Repository: aardvark-platform/aardvark.base Branch: master Commit: 011bd5bb9187 Files: 804 Total size: 41.1 MB Directory structure: gitextract_19g_u3m2/ ├── .claude/ │ └── CLAUDE.md ├── .config/ │ └── dotnet-tools.json ├── .github/ │ └── workflows/ │ ├── build.yml │ ├── docs-check.yml │ └── publish.yml ├── .gitignore ├── .vscode/ │ ├── settings.json │ └── tasks.json ├── AGENTS.md ├── LICENSE ├── PACKAGES.md ├── README.md ├── RELEASE_NOTES.md ├── ai/ │ ├── ALGORITHMS.md │ ├── COLLECTIONS.md │ ├── DOC_ACCURACY_AUDIT.md │ ├── FSHARP_INTEROP.md │ ├── INCREMENTAL.md │ ├── PIXIMAGE.md │ ├── PRIMITIVE_TYPES.md │ ├── README.md │ ├── RECIPE_AI_FRIENDLINESS.md │ ├── SEMANTICS_GEOMETRY_CORE.md │ ├── SEMANTICS_LINEAR_ALGEBRA.md │ ├── SERIALIZATION.md │ ├── SYMBOL_INDEX.md │ ├── TENSORS.md │ └── UTILITIES.md ├── build.cmd ├── build.sh ├── check-docs.cmd ├── check-docs.sh ├── generate.cmd ├── generate.sh ├── global.json ├── paket.dependencies ├── src/ │ ├── Aardvark.Base/ │ │ ├── Aardvark.Base.csproj │ │ ├── AlgoDat/ │ │ │ ├── AdaBoost.cs │ │ │ ├── ConcurrentHashSet.cs │ │ │ ├── ExtendedCore/ │ │ │ │ ├── BitHelpers.cs │ │ │ │ └── SortedSetExt.cs │ │ │ ├── INode.cs │ │ │ ├── LruCache.cs │ │ │ ├── Meta.cs │ │ │ ├── MinimumSpanningTree.cs │ │ │ ├── SalesmanOfDeath.cs │ │ │ ├── ShortestPath.cs │ │ │ └── Span.cs │ │ ├── Delegates/ │ │ │ ├── Delegates.cs │ │ │ ├── Delegates_auto.cs │ │ │ ├── Delegates_template.cs │ │ │ └── HigherOrderFunctions.cs │ │ ├── Extensions/ │ │ │ ├── ArrayExtensions.cs │ │ │ ├── CastExtensions.cs │ │ │ ├── DagExtensions.cs │ │ │ ├── DateTimeExtensions.cs │ │ │ ├── DictionaryExtensions.cs │ │ │ ├── EnumHelpers.cs │ │ │ ├── EventHandlerExtensions.cs │ │ │ ├── FuncActionExtensions.cs │ │ │ ├── FuncActionExtensions_auto.cs │ │ │ ├── FuncActionExtensions_template.cs │ │ │ ├── HigherOrderFunctions.cs │ │ │ ├── ICollectionExtensions.cs │ │ │ ├── IEnumerableExtensions.cs │ │ │ ├── IListExtensions.cs │ │ │ ├── IsExternalInit.cs │ │ │ ├── ListExtensions.cs │ │ │ ├── NonGenericArray.cs │ │ │ ├── SequenceExtensions_auto.cs │ │ │ ├── SequenceExtensions_template.cs │ │ │ ├── StreamExtensions.cs │ │ │ ├── StringExtensions.cs │ │ │ ├── Structs.cs │ │ │ ├── SubRange.cs │ │ │ ├── SystemDrawingExtensions.cs │ │ │ ├── TupleExtensions.cs │ │ │ ├── TypeExtensions.cs │ │ │ └── VariousExtensions.cs │ │ ├── Geodesy/ │ │ │ ├── GeoConsts.cs │ │ │ └── GeoConversion.cs │ │ ├── Geometry/ │ │ │ ├── Algorithms_auto.cs │ │ │ ├── Algorithms_template.cs │ │ │ ├── BbTree.cs │ │ │ ├── ClippingFunctions_auto.cs │ │ │ ├── ClippingFunctions_template.cs │ │ │ ├── Interfaces/ │ │ │ │ ├── IBoundingBox_auto.cs │ │ │ │ ├── IBoundingBox_template.cs │ │ │ │ ├── IBoundingCircle.cs │ │ │ │ ├── IBoundingSphere.cs │ │ │ │ ├── IImmutablePolygon.cs │ │ │ │ └── IPolygon.cs │ │ │ ├── IntersectionTests_auto.cs │ │ │ ├── IntersectionTests_template.cs │ │ │ ├── Relations/ │ │ │ │ ├── LinearCombination_auto.cs │ │ │ │ ├── LinearCombination_template.cs │ │ │ │ ├── Orthogonality_auto.cs │ │ │ │ ├── Orthogonality_template.cs │ │ │ │ ├── Parallelism_auto.cs │ │ │ │ ├── Parallelism_template.cs │ │ │ │ ├── SubPrimitives_auto.cs │ │ │ │ └── SubPrimitives_template.cs │ │ │ ├── SpecialPoints_auto.cs │ │ │ ├── SpecialPoints_template.cs │ │ │ └── Types/ │ │ │ ├── Capsule/ │ │ │ │ ├── Capsule3_auto.cs │ │ │ │ └── Capsule3_template.cs │ │ │ ├── Circle/ │ │ │ │ ├── Circle2_auto.cs │ │ │ │ ├── Circle2_template.cs │ │ │ │ ├── Circle3_auto.cs │ │ │ │ └── Circle3_template.cs │ │ │ ├── Cone/ │ │ │ │ ├── Cone3_auto.cs │ │ │ │ ├── Cone3_template.cs │ │ │ │ ├── Conic2_auto.cs │ │ │ │ └── Conic2_template.cs │ │ │ ├── Cylinder/ │ │ │ │ ├── Cylinder3_auto.cs │ │ │ │ └── Cylinder3_template.cs │ │ │ ├── Ellipse/ │ │ │ │ ├── Ellipse2_auto.cs │ │ │ │ ├── Ellipse2_template.cs │ │ │ │ ├── Ellipse3_auto.cs │ │ │ │ ├── Ellipse3_template.cs │ │ │ │ ├── Ellipse_auto.cs │ │ │ │ └── Ellipse_template.cs │ │ │ ├── Geometry1i.cs │ │ │ ├── Geometry1i_auto.cs │ │ │ ├── Geometry1i_template.cs │ │ │ ├── Geometry_auto.cs │ │ │ ├── Geometry_template.cs │ │ │ ├── Hull/ │ │ │ │ ├── Hull2_auto.cs │ │ │ │ ├── Hull2_template.cs │ │ │ │ ├── Hull3_auto.cs │ │ │ │ └── Hull3_template.cs │ │ │ ├── Line/ │ │ │ │ ├── Line2_auto.cs │ │ │ │ ├── Line2_template.cs │ │ │ │ ├── Line3_auto.cs │ │ │ │ └── Line3_template.cs │ │ │ ├── Line1iPoint.cs │ │ │ ├── Plane/ │ │ │ │ ├── Plane2_auto.cs │ │ │ │ ├── Plane2_template.cs │ │ │ │ ├── Plane3_auto.cs │ │ │ │ └── Plane3_template.cs │ │ │ ├── Polygon/ │ │ │ │ ├── IImmutablePolygonExtensions_auto.cs │ │ │ │ ├── IImmutablePolygonExtensions_template.cs │ │ │ │ ├── ImmutablePolygon.cs │ │ │ │ ├── Polygon2_auto.cs │ │ │ │ ├── Polygon2_template.cs │ │ │ │ ├── Polygon3_auto.cs │ │ │ │ ├── Polygon3_template.cs │ │ │ │ ├── PolygonExtensions_auto.cs │ │ │ │ └── PolygonExtensions_template.cs │ │ │ ├── Quad/ │ │ │ │ ├── Quad2_auto.cs │ │ │ │ ├── Quad2_template.cs │ │ │ │ ├── Quad3_auto.cs │ │ │ │ └── Quad3_template.cs │ │ │ ├── Quadric/ │ │ │ │ ├── Quadric_auto.cs │ │ │ │ └── Quadric_template.cs │ │ │ ├── Ray/ │ │ │ │ ├── Ray2_auto.cs │ │ │ │ ├── Ray2_template.cs │ │ │ │ ├── Ray3_auto.cs │ │ │ │ └── Ray3_template.cs │ │ │ ├── Sphere/ │ │ │ │ ├── Sphere3_auto.cs │ │ │ │ └── Sphere3_template.cs │ │ │ ├── Torus/ │ │ │ │ ├── Torus3_auto.cs │ │ │ │ └── Torus3_template.cs │ │ │ └── Triangle/ │ │ │ ├── Triangle2_auto.cs │ │ │ ├── Triangle2_template.cs │ │ │ ├── Triangle3_auto.cs │ │ │ └── Triangle3_template.cs │ │ ├── Hashing/ │ │ │ └── HashCode.cs │ │ ├── Introspection/ │ │ │ ├── Aardvark.cs │ │ │ ├── CachingProperties.cs │ │ │ ├── Introspection.cs │ │ │ ├── IntrospectionProperties.cs │ │ │ ├── Native.cs │ │ │ ├── Platform/ │ │ │ │ ├── Dl.cs │ │ │ │ ├── Kernel32.cs │ │ │ │ └── LdConfig.cs │ │ │ ├── Plugins.cs │ │ │ ├── RegexPatterns.cs │ │ │ └── Utilities.cs │ │ ├── Json/ │ │ │ └── JsonConverters.cs │ │ ├── Math/ │ │ │ ├── Base/ │ │ │ │ ├── Adler32.cs │ │ │ │ ├── AliasTable_auto.cs │ │ │ │ ├── AliasTable_template.cs │ │ │ │ ├── Complex_auto.cs │ │ │ │ ├── Complex_template.cs │ │ │ │ ├── Constant.cs │ │ │ │ ├── Conversion.cs │ │ │ │ ├── DistributionFunction.cs │ │ │ │ ├── Fraction.cs │ │ │ │ ├── Fun.cs │ │ │ │ ├── Fun_auto.cs │ │ │ │ ├── Fun_template.cs │ │ │ │ ├── Half.cs │ │ │ │ ├── MedianWindow.cs │ │ │ │ ├── PhysicsConsts.cs │ │ │ │ ├── Quaternion_auto.cs │ │ │ │ ├── Quaternion_template.cs │ │ │ │ ├── SampleGrid2d.cs │ │ │ │ ├── Statistics.cs │ │ │ │ └── WeightedIndex.cs │ │ │ ├── Colors/ │ │ │ │ ├── Color.cs │ │ │ │ ├── Color_auto.cs │ │ │ │ ├── Color_template.cs │ │ │ │ └── Spectrum.cs │ │ │ ├── Curves/ │ │ │ │ └── Curves.cs │ │ │ ├── Interfaces/ │ │ │ │ ├── IMatrix.cs │ │ │ │ ├── IOpacity.cs │ │ │ │ ├── IRGB.cs │ │ │ │ ├── IRange.cs │ │ │ │ ├── ISize_auto.cs │ │ │ │ ├── ISize_template.cs │ │ │ │ ├── ITensor.cs │ │ │ │ ├── IValidity.cs │ │ │ │ ├── IVector.cs │ │ │ │ └── IVolume.cs │ │ │ ├── Interfaces.cs │ │ │ ├── Interpolation/ │ │ │ │ ├── Interpolation.cs │ │ │ │ └── Mapping.cs │ │ │ ├── LuFactorization.cs │ │ │ ├── Numerics/ │ │ │ │ ├── CovarianceMatrix.cs │ │ │ │ └── Polynomial.cs │ │ │ ├── QrFactorization.cs │ │ │ ├── RangesBoxes/ │ │ │ │ ├── Box.cs │ │ │ │ ├── Box_auto.cs │ │ │ │ ├── Box_template.cs │ │ │ │ ├── Cell.cs │ │ │ │ ├── Cell2d.cs │ │ │ │ ├── OrientedBox_auto.cs │ │ │ │ └── OrientedBox_template.cs │ │ │ ├── Trafos/ │ │ │ │ ├── Affine_auto.cs │ │ │ │ ├── Affine_template.cs │ │ │ │ ├── CoordTransforms.cs │ │ │ │ ├── CoordinateSystem.cs │ │ │ │ ├── Euclidean_auto.cs │ │ │ │ ├── Euclidean_template.cs │ │ │ │ ├── M33_auto.cs │ │ │ │ ├── M33_template.cs │ │ │ │ ├── M44_auto.cs │ │ │ │ ├── M44_template.cs │ │ │ │ ├── MatrixArrayExtensions.cs │ │ │ │ ├── Matrix_auto.cs │ │ │ │ ├── Matrix_template.cs │ │ │ │ ├── Rot2_auto.cs │ │ │ │ ├── Rot2_template.cs │ │ │ │ ├── Rot3_auto.cs │ │ │ │ ├── Rot3_template.cs │ │ │ │ ├── Scale_auto.cs │ │ │ │ ├── Scale_template.cs │ │ │ │ ├── Shift_auto.cs │ │ │ │ ├── Shift_template.cs │ │ │ │ ├── Similarity_auto.cs │ │ │ │ ├── Similarity_template.cs │ │ │ │ ├── Trafo_auto.cs │ │ │ │ └── Trafo_template.cs │ │ │ └── Vectors/ │ │ │ ├── HashCode.cs │ │ │ ├── V3fCoder.cs │ │ │ ├── VectorArrayExtensions.cs │ │ │ ├── VectorIEnumerableExtensions_auto.cs │ │ │ ├── VectorIEnumerableExtensions_template.cs │ │ │ ├── VectorTypeConverter_auto.cs │ │ │ ├── VectorTypeConverter_template.cs │ │ │ ├── Vector_auto.cs │ │ │ └── Vector_template.cs │ │ ├── Random/ │ │ │ ├── ForcedRandomSeries.cs │ │ │ ├── HaltonRandomSeries.cs │ │ │ ├── IRandomDistribution.cs │ │ │ ├── IRandomSeries.cs │ │ │ ├── IRandomUniform.cs │ │ │ ├── PerlinNoise.cs │ │ │ ├── Prime.cs │ │ │ ├── PseudoRandomSeries.cs │ │ │ ├── Quasi.cs │ │ │ ├── RandomDistributions.cs │ │ │ ├── RandomIEnumerableExtensions.cs │ │ │ ├── RandomSample.cs │ │ │ └── RandomSystem.cs │ │ ├── Reporting/ │ │ │ ├── FilterLogTarget.cs │ │ │ ├── IJobReporter.cs │ │ │ ├── ILogTarget.cs │ │ │ ├── IReportable.cs │ │ │ ├── IReporter.cs │ │ │ ├── JobReporter.cs │ │ │ ├── LogMsg.cs │ │ │ ├── MultiLogTarget.cs │ │ │ ├── NullReporter.cs │ │ │ ├── PerThreadJobReporter.cs │ │ │ ├── PerThreadLogTarget.cs │ │ │ ├── Report.cs │ │ │ ├── ReportJob.cs │ │ │ ├── Skipper.cs │ │ │ ├── TestInfo.cs │ │ │ └── TextLogTarget.cs │ │ ├── Sorting/ │ │ │ ├── ArrayExtensions.cs │ │ │ ├── IEnumerableExtensions.cs │ │ │ ├── ListExtensions.cs │ │ │ ├── Sorting_auto.cs │ │ │ └── Sorting_template.cs │ │ ├── Symbol/ │ │ │ ├── Dict_auto.cs │ │ │ ├── Dict_template.cs │ │ │ ├── Dicts.cs │ │ │ ├── IDict.cs │ │ │ ├── SymMapBase.cs │ │ │ ├── SymMapBaseTraversal.cs │ │ │ └── Symbol.cs │ │ ├── Text/ │ │ │ ├── Text.cs │ │ │ └── TextParser.cs │ │ ├── Tup/ │ │ │ ├── Tuples_auto.cs │ │ │ └── Tuples_template.cs │ │ ├── paket.references │ │ └── paket.template │ ├── Aardvark.Base.Essentials/ │ │ ├── Aardvark.Base.Essentials.csproj │ │ ├── Camera/ │ │ │ ├── CameraProjectionOrtho.cs │ │ │ ├── CameraProjectionPerspective.cs │ │ │ ├── CameraViewRaw.cs │ │ │ ├── CameraViewWithSky.cs │ │ │ ├── ICameraProjection.cs │ │ │ ├── ICameraProjectionExtensions.cs │ │ │ ├── ICameraView.cs │ │ │ ├── ICameraViewExtensions.cs │ │ │ ├── IRenderView.cs │ │ │ └── IRenderViewExtensions.cs │ │ ├── Editing/ │ │ │ ├── BehaviorDragAbsolute.cs │ │ │ ├── BehaviorDragRelative.cs │ │ │ ├── IBehavior.cs │ │ │ ├── IBehaviorDeletable.cs │ │ │ ├── IBehaviorPosition2d.cs │ │ │ ├── IBehaviorSplittableEdge2d.cs │ │ │ ├── IBehaviorTransform2d.cs │ │ │ ├── IEditableEdge2d.cs │ │ │ ├── IEditableFace2d.cs │ │ │ ├── IEditableSequence.cs │ │ │ └── IEditableVertex2d.cs │ │ ├── NormalizedDeviceCoordinates.cs │ │ ├── PixelPosition.cs │ │ ├── Screenshot.cs │ │ ├── System/ │ │ │ ├── Awaitable.cs │ │ │ ├── Clock.cs │ │ │ ├── Disposable.cs │ │ │ ├── EventSource.cs │ │ │ ├── EventSourceExtensions.cs │ │ │ ├── EventSourceInterfaces.cs │ │ │ ├── EventSourceSpecials.cs │ │ │ ├── FilteredEventSource.cs │ │ │ ├── IAwaitable.cs │ │ │ ├── Reactive.cs │ │ │ ├── Time.cs │ │ │ └── WithCancellationExtension.cs │ │ ├── paket.references │ │ └── paket.template │ ├── Aardvark.Base.FSharp/ │ │ ├── Aardvark.Base.FSharp.fsproj │ │ ├── Ag.fs │ │ ├── Algorithms/ │ │ │ └── PolygonSimplification.fs │ │ ├── Color/ │ │ │ ├── ColorBrewer.fs │ │ │ ├── ColorBrewerSchemes.fs │ │ │ └── ColorBrewerSchemes.fsx │ │ ├── Datastructures/ │ │ │ ├── Geometry/ │ │ │ │ ├── Boundable.fs │ │ │ │ ├── Bvh.fs │ │ │ │ └── KdTree.fs │ │ │ ├── Immutable/ │ │ │ │ ├── FingerTree.fs │ │ │ │ ├── Graph.fs │ │ │ │ ├── MapExt.fs │ │ │ │ ├── RangeSet_auto.fs │ │ │ │ ├── RangeSet_template.fs │ │ │ │ └── SetDelta.fs │ │ │ └── Mutable/ │ │ │ ├── AVL.fs │ │ │ ├── ConcurrentHashQueue.fs │ │ │ ├── FixedSizeArray.fs │ │ │ ├── OrderMaintenance.fs │ │ │ ├── OrderMaintenanceTrie.fs │ │ │ ├── ReferenceCountingSet.fs │ │ │ ├── SkipList.fs │ │ │ └── StableSet.fs │ │ ├── Math/ │ │ │ ├── AverageWindow.fs │ │ │ ├── Converters.fs │ │ │ ├── Math.fs │ │ │ ├── Matrix.fs │ │ │ ├── SVDM33f.fs │ │ │ └── Vectors.fs │ │ ├── Native/ │ │ │ ├── BlobStore.fs │ │ │ ├── FileTable.fs │ │ │ ├── Manager.fs │ │ │ ├── Memory.fs │ │ │ ├── Pointer.fs │ │ │ └── Store.fs │ │ ├── Reflection/ │ │ │ ├── Formatf.fs │ │ │ ├── FunctionReflection.fs │ │ │ ├── IL.fs │ │ │ ├── Multimethod.fs │ │ │ ├── Quotations.fs │ │ │ ├── ReflectionExtensions.fs │ │ │ ├── TypeBuilder.fs │ │ │ ├── TypeInfo.fs │ │ │ ├── TypeMeta_auto.fs │ │ │ ├── TypeMeta_template.fs │ │ │ └── UnmanagedFunctions.fs │ │ ├── Runtime/ │ │ │ ├── Assembler.fs │ │ │ ├── Caches.fs │ │ │ ├── CustomSchedulers.fs │ │ │ ├── DynamicLinker.fs │ │ │ ├── Fragments.fs │ │ │ ├── NativeMemory.fs │ │ │ └── WeakTable.fs │ │ ├── Utilities/ │ │ │ ├── IO.fs │ │ │ ├── Interop/ │ │ │ │ ├── ArraySegment.fs │ │ │ │ ├── CSharpList.fs │ │ │ │ ├── Dictionary.fs │ │ │ │ ├── FSLibExtensions.fs │ │ │ │ ├── HashSet.fs │ │ │ │ ├── SortedSet.fs │ │ │ │ ├── String.fs │ │ │ │ └── Symbol.fs │ │ │ ├── Lens.fs │ │ │ ├── Logging.fs │ │ │ ├── Measures.fs │ │ │ ├── Monads.fs │ │ │ ├── Monoid.fs │ │ │ ├── Native.fs │ │ │ ├── Pickler/ │ │ │ │ ├── AdaptivePicklers.fs │ │ │ │ └── FsPicklerExtensions.fs │ │ │ ├── PrimitiveValueConverter.fs │ │ │ ├── Threading.fs │ │ │ └── Weak.fs │ │ ├── __project.fsx │ │ ├── paket.references │ │ └── paket.template │ ├── Aardvark.Base.Fonts/ │ │ ├── Aardvark.Base.Fonts.fsproj │ │ ├── BvhInternal.fs │ │ ├── Font.fs │ │ ├── FontResolver.fs │ │ ├── Path.fs │ │ ├── PathSegment.fs │ │ ├── PathTessellator.fs │ │ ├── paket.references │ │ └── paket.template │ ├── Aardvark.Base.IO/ │ │ ├── Aardvark.Base.IO.csproj │ │ ├── Annotations.cs │ │ ├── BaseCoder.cs │ │ ├── BinaryReadingCoder.cs │ │ ├── BinaryReadingCoder_auto.cs │ │ ├── BinaryReadingCoder_template.cs │ │ ├── BinaryWritingCoder.cs │ │ ├── BinaryWritingCoder_auto.cs │ │ ├── BinaryWritingCoder_template.cs │ │ ├── ChunkedMemoryStream.cs │ │ ├── CodingExtensions.cs │ │ ├── Converter.cs │ │ ├── FastObjectFactory.cs │ │ ├── FieldCoderExtensions.cs │ │ ├── GzipUtils.cs │ │ ├── IAwakeable.cs │ │ ├── ICoder.cs │ │ ├── ICoder_auto.cs │ │ ├── ICoder_template.cs │ │ ├── IFieldCodeable.cs │ │ ├── ITypedMap.cs │ │ ├── NetworkOrderBinaryReader.cs │ │ ├── NetworkOrderBinaryWriter.cs │ │ ├── RegisterTypeInfoAttribute.cs │ │ ├── StreamCodeReader.cs │ │ ├── StreamCodeReader_auto.cs │ │ ├── StreamCodeReader_template.cs │ │ ├── StreamCodeWriter.cs │ │ ├── StreamCodeWriter_auto.cs │ │ ├── StreamCodeWriter_template.cs │ │ ├── StreamWriter2.cs │ │ ├── SymMap.cs │ │ ├── TypeCoder.cs │ │ ├── TypeCoder_auto.cs │ │ ├── TypeCoder_template.cs │ │ ├── TypeExtensions.cs │ │ ├── TypeInfo.cs │ │ ├── TypeInfoVersion.cs │ │ ├── UberStream.cs │ │ ├── WorkDir.cs │ │ ├── XmlParser.cs │ │ ├── XmlReadingCoder.cs │ │ ├── XmlReadingCoder_auto.cs │ │ ├── XmlReadingCoder_template.cs │ │ ├── XmlWritingCoder.cs │ │ ├── XmlWritingCoder_auto.cs │ │ ├── XmlWritingCoder_template.cs │ │ ├── ZipFileContainer.cs │ │ ├── ZipFileHeader.cs │ │ ├── paket.references │ │ └── paket.template │ ├── Aardvark.Base.Incremental/ │ │ ├── Aardvark.Base.Incremental.fsproj │ │ ├── AdaptiveFunc/ │ │ │ └── AdaptiveFunc.fs │ │ ├── AdaptiveStream/ │ │ │ ├── AdaptiveStream.fs │ │ │ └── AdaptiveStreamCore.fs │ │ ├── AgInterop.fs │ │ ├── Builders.fs │ │ ├── ChangeTracker.fs │ │ ├── IncrementalBvh.fs │ │ ├── Proc/ │ │ │ ├── Proc.fs │ │ │ ├── ProcList.fs │ │ │ └── ThreadPool.fs │ │ ├── Scripts/ │ │ │ ├── load-project.fsx │ │ │ └── load-references.fsx │ │ ├── paket.references │ │ └── paket.template │ ├── Aardvark.Base.Runtime/ │ │ ├── Aardvark.Base.Runtime.fsproj │ │ ├── Coder/ │ │ │ ├── Code.fs │ │ │ ├── Core.fs │ │ │ ├── State.fs │ │ │ ├── Utilities.fs │ │ │ └── ValueCoders.fs │ │ ├── paket.references │ │ └── paket.template │ ├── Aardvark.Base.Telemetry/ │ │ ├── Aardvark.Base.Telemetry.csproj │ │ ├── Debug.cs │ │ ├── Environment.cs │ │ ├── HardwareThread.cs │ │ ├── IProbe.cs │ │ ├── Probes.cs │ │ ├── Registry.cs │ │ ├── TelemetryExtensions.cs │ │ ├── TimingStats.cs │ │ ├── Views.cs │ │ ├── paket.references │ │ └── paket.template │ ├── Aardvark.Base.Tensors/ │ │ ├── Aardvark.Base.Tensors.fsproj │ │ ├── Algorithms/ │ │ │ ├── Generator.fsx │ │ │ ├── QR.fs │ │ │ ├── SVD.fs │ │ │ └── Solver.fs │ │ ├── Extensions/ │ │ │ ├── TensorMath.fs │ │ │ ├── TensorSlicing.fs │ │ │ ├── TensorUtilitiesGenerated.fs │ │ │ └── TensorUtilitiesGenerator.fsx │ │ ├── Native/ │ │ │ ├── NativeTensorExtensions.fs │ │ │ ├── NativeTensorGenerated.fs │ │ │ └── NativeTensorGenerator.fsx │ │ ├── PixImage/ │ │ │ ├── ImageTrafo.fs │ │ │ ├── PixCube.fs │ │ │ └── PixImageErrorMetric.fs │ │ ├── paket.references │ │ └── paket.template │ ├── Aardvark.Base.Tensors.CSharp/ │ │ ├── Aardvark.Base.Tensors.CSharp.csproj │ │ ├── Algorithms/ │ │ │ ├── LuFactorization.cs │ │ │ └── QrFactorization.cs │ │ ├── PixImage/ │ │ │ ├── EdgeFilter.cs │ │ │ ├── IPix.cs │ │ │ ├── ImageLoadException.cs │ │ │ ├── PixCube.cs │ │ │ ├── PixImage.cs │ │ │ ├── PixImageCreators.cs │ │ │ ├── PixImageExtensions.cs │ │ │ ├── PixImageMipMap.cs │ │ │ ├── PixLoader.cs │ │ │ ├── PixProcessor.cs │ │ │ └── PixVolume.cs │ │ ├── Tensor.cs │ │ ├── TensorExtensions.cs │ │ ├── TensorExtensions_auto.cs │ │ ├── TensorExtensions_template.cs │ │ ├── TensorMathExt_auto.cs │ │ ├── TensorMathExt_template.cs │ │ ├── Tensor_auto.cs │ │ ├── Tensor_template.cs │ │ ├── Tensors/ │ │ │ ├── Accessors.cs │ │ │ ├── Accessors_auto.cs │ │ │ ├── Accessors_template.cs │ │ │ ├── ArrayExtensions.cs │ │ │ ├── FilterKernel.cs │ │ │ ├── ImageBorder.cs │ │ │ ├── ImageTensors.cs │ │ │ ├── Interfaces.cs │ │ │ ├── Parallel.cs │ │ │ └── Tools.cs │ │ ├── Utilities/ │ │ │ ├── Polygon2dExtensions.cs │ │ │ └── SpectrumExtensions.cs │ │ └── paket.references │ ├── Aardvark.Geometry/ │ │ ├── Aardvark.Geometry.fsproj │ │ ├── Bvh.fs │ │ ├── EllipsoidRegression.fs │ │ ├── LinearRegression.fs │ │ ├── PolyRegion2d.fs │ │ ├── Region3d.fs │ │ ├── TexturePacking.fs │ │ ├── paket.references │ │ └── paket.template │ ├── Aardvark.sln │ ├── CodeGenerator/ │ │ ├── CodeGenerator.csproj │ │ ├── CompilerServices.cs │ │ ├── InternalsVisibleTo.cs │ │ ├── Program.cs │ │ ├── README.md │ │ ├── TemplateProcessor.cs │ │ ├── app.config │ │ └── paket.references │ ├── Demo/ │ │ ├── CoreTest/ │ │ │ ├── CoreTest.fsproj │ │ │ ├── Program.fs │ │ │ └── paket.references │ │ ├── ExamplesCSharp/ │ │ │ ├── ExamplesCSharp.csproj │ │ │ ├── Program.cs │ │ │ └── paket.references │ │ ├── IncrementalDemo.CSharp/ │ │ │ ├── IncrementalDemo.CSharp.csproj │ │ │ ├── Program.cs │ │ │ └── paket.references │ │ ├── PixImageDemo/ │ │ │ ├── PixImageDemo.csproj │ │ │ ├── Program.cs │ │ │ └── paket.references │ │ ├── RandomSampleDemo/ │ │ │ ├── Program.cs │ │ │ ├── RandomSampleDemo.csproj │ │ │ └── paket.references │ │ ├── Scratch/ │ │ │ ├── Program.fs │ │ │ ├── Scratch.fsproj │ │ │ ├── Store.fs │ │ │ └── paket.references │ │ └── Sketch/ │ │ ├── App.config │ │ ├── FingerTree.fsx │ │ ├── FutureList.fsx │ │ ├── Lazy.fsx │ │ ├── Observable.fsx │ │ ├── Program.fs │ │ ├── Rampa.fsx │ │ ├── Sketch.fsproj │ │ ├── Sketch.sln │ │ ├── UndoRedo.fsx │ │ ├── Yampa.fsx │ │ ├── adventure.txt │ │ └── paket_.references │ └── Tests/ │ ├── Aardvark.Base.Benchmarks/ │ │ ├── Aardvark.Base.Benchmarks.csproj │ │ ├── CodeGenTest.cs │ │ ├── ColorConversion.cs │ │ ├── ConstantsBenchmark.cs │ │ ├── Enumerators.cs │ │ ├── Geometry/ │ │ │ ├── PolygonTransform.cs │ │ │ ├── RayHitTest.cs │ │ │ └── SolidAngle.cs │ │ ├── HashCodeCombine.cs │ │ ├── Hashes.cs │ │ ├── Indexers_auto.cs │ │ ├── Indexers_template.cs │ │ ├── Lazy.cs │ │ ├── Math/ │ │ │ ├── AngleBetween_auto.cs │ │ │ ├── AngleBetween_template.cs │ │ │ ├── DistanceRot3_auto.cs │ │ │ ├── DistanceRot3_template.cs │ │ │ ├── DistanceToLine.cs │ │ │ ├── FractTest.cs │ │ │ ├── IntegerPower_auto.cs │ │ │ ├── IntegerPower_template.cs │ │ │ ├── Log2Int.cs │ │ │ ├── PowerOfTwo_auto.cs │ │ │ ├── PowerOfTwo_template.cs │ │ │ ├── Rot3GetEuler_auto.cs │ │ │ ├── Rot3GetEuler_template.cs │ │ │ ├── Rot3dTransform.cs │ │ │ ├── RotateInto_auto.cs │ │ │ ├── RotateInto_template.cs │ │ │ ├── Tensors/ │ │ │ │ ├── MatrixMinor.cs │ │ │ │ ├── MatrixMultiply.cs │ │ │ │ ├── MatrixOrthogonalize_auto.cs │ │ │ │ ├── MatrixOrthogonalize_template.cs │ │ │ │ ├── MatrixSampling.cs │ │ │ │ └── TensorMathBenchmark.cs │ │ │ ├── Transform.cs │ │ │ └── VectorLength.cs │ │ ├── Program.cs │ │ ├── StaticConstants.cs │ │ ├── StreamWriterReader.cs │ │ ├── TelemetryProbesBenchmark.cs │ │ └── paket.references │ ├── Aardvark.Base.FSharp.Benchmarks/ │ │ ├── Aardvark.Base.FSharp.Benchmarks.fsproj │ │ ├── ActivePatterns.fs │ │ ├── ArrayChooseBench.fs │ │ ├── BvhIntersectBench.fs │ │ ├── DynamicDispatchBench.fs │ │ ├── NullCheckBench.fs │ │ ├── Program.fs │ │ ├── ReferenceCountingSetBench.fs │ │ ├── TensorMathBench.fs │ │ ├── TensorUtilitiesBench.fs │ │ ├── Tuples_auto.fs │ │ ├── Tuples_template.fs │ │ ├── TypePatternsBench.fs │ │ └── paket.references │ ├── Aardvark.Base.FSharp.Tests/ │ │ ├── Aardvark.Base.FSharp.Tests.fsproj │ │ ├── CachesTest.fs │ │ ├── ControlTests.fs │ │ ├── Datastructures/ │ │ │ ├── FSharpExtensionTests.fs │ │ │ ├── MapExt.fs │ │ │ ├── OrderMaintenanceTrie.fs │ │ │ ├── RangeSetTests.fs │ │ │ └── SortedSetExt.fs │ │ ├── EnumTests.fs │ │ ├── GeometryValueOptionTests.fs │ │ ├── HMap.fs │ │ ├── Math/ │ │ │ ├── MathTests.fs │ │ │ ├── SVDTests.fs │ │ │ └── TrafoTests.fs │ │ ├── NativeMemory.fs │ │ ├── NullCoalesceTests.fs │ │ ├── PinnedValueTests.fs │ │ ├── Program.fs │ │ ├── PureAgTests.fs │ │ ├── SizeOfTests.fs │ │ ├── Tensors/ │ │ │ ├── PixTests.fs │ │ │ ├── TensorMathTests.fs │ │ │ └── TensorTests.fs │ │ ├── TypeMetaTests.fs │ │ └── paket.references │ ├── Aardvark.Base.Fonts.Tests/ │ │ ├── Aardvark.Base.Fonts.Tests.fsproj │ │ ├── Common.fs │ │ ├── Loading.fs │ │ ├── PathSegment.fs │ │ ├── Program.fs │ │ ├── paket.references │ │ └── test.runsettings │ ├── Aardvark.Base.Incremental.Tests/ │ │ ├── AListTests.fs │ │ ├── AListTestsNew.fs │ │ ├── AMapTests.fs │ │ ├── ASetFoldTest.csv │ │ ├── ASetPerformance.fs │ │ ├── ASetPerformanceTests.fs │ │ ├── ASetTests.fs │ │ ├── Aardvark.Base.Incremental.Tests.fsproj │ │ ├── AgTests.fs │ │ ├── ModTests.fs │ │ ├── Mutables.fs │ │ ├── Performance.fs │ │ ├── SizeOfVariousAdaptiveObjects.fs │ │ ├── UndoRedo.fs │ │ └── paket.references │ ├── Aardvark.Base.Runtime.Tests/ │ │ ├── Aardvark.Base.Runtime.Tests.fsproj │ │ ├── CoderTests.fs │ │ ├── ReflectionTests.fs │ │ └── paket.references │ ├── Aardvark.Base.Tests/ │ │ ├── Aardvark.Base.Tests.csproj │ │ ├── AlgoDat/ │ │ │ ├── DictTests.cs │ │ │ ├── HigherOrderFunctionsTests.cs │ │ │ └── SortingTests.cs │ │ ├── CodeGenerator/ │ │ │ └── CodeGeneratorTests.cs │ │ ├── Extensions/ │ │ │ ├── Arrays.cs │ │ │ ├── DateTime.cs │ │ │ ├── Enumerable.cs │ │ │ ├── Hashes.cs │ │ │ ├── ListHeapTests.cs │ │ │ ├── Lists.cs │ │ │ ├── StreamTests.cs │ │ │ ├── Strings.cs │ │ │ └── TaskWithCancellationTests.cs │ │ ├── Geometry/ │ │ │ ├── Circle2dTests.cs │ │ │ ├── Hull2dTests.cs │ │ │ ├── Hull3dTests.cs │ │ │ ├── IntersectionTestsTests.cs │ │ │ ├── LineDistance.cs │ │ │ ├── Plane3dTests.cs │ │ │ └── PolygonClipping.cs │ │ ├── IO/ │ │ │ └── UberStreamTests.cs │ │ ├── Images/ │ │ │ ├── PixImageTests.cs │ │ │ ├── PixSaveParamsTests.cs │ │ │ ├── PixVolumeTests.cs │ │ │ └── SystemDrawingTests.cs │ │ ├── Json/ │ │ │ └── SystemTextJsonTests.cs │ │ ├── Math/ │ │ │ ├── AliasTable.cs │ │ │ ├── ColorTests.cs │ │ │ ├── ComplexTests.cs │ │ │ ├── Distributions.cs │ │ │ ├── FunTests.cs │ │ │ ├── HalfTests.cs │ │ │ ├── PolynomialTests.cs │ │ │ └── QuaternionTests.cs │ │ ├── Plane/ │ │ │ └── PlaneTest.cs │ │ ├── Program.cs │ │ ├── Random/ │ │ │ ├── RandomIEnumerableExtensionsTests.cs │ │ │ └── RandomSystemTests.cs │ │ ├── RangesBoxes/ │ │ │ ├── BoxTests.cs │ │ │ ├── Cell2dTests.cs │ │ │ └── CellTests.cs │ │ ├── Reporting/ │ │ │ └── ReportingTests.cs │ │ ├── System/ │ │ │ └── EventSourceSlimTests.cs │ │ ├── Telemetry/ │ │ │ └── TelemetryTests.cs │ │ ├── Tensors/ │ │ │ └── TensorMatrixTests.cs │ │ ├── TestSuite/ │ │ │ └── TestSuite.cs │ │ ├── Trafos/ │ │ │ ├── AffineTests.cs │ │ │ ├── EuclideanTests.cs │ │ │ ├── MatrixTests.cs │ │ │ ├── Rot2dTests.cs │ │ │ ├── Rot3dTests.cs │ │ │ ├── Scale3dTests.cs │ │ │ ├── Shift3dTests.cs │ │ │ ├── SimilarityTests.cs │ │ │ ├── TrafoTesting.cs │ │ │ └── TrafoTests.cs │ │ ├── Vectors/ │ │ │ ├── V3fCoderTests.cs │ │ │ └── VectorTests.cs │ │ └── paket.references │ └── Aardvark.Geometry.Tests/ │ ├── Aardvark.Geometry.Tests.fsproj │ ├── PolyRegion2dTests.fs │ ├── Program.fs │ ├── Regression.fs │ ├── TexturePacking.fs │ └── paket.references ├── test.cmd ├── test.sh └── tools/ ├── DocsChecker/ │ ├── DocsAnalyzer.cs │ ├── DocsChecker.csproj │ ├── DocsRules.cs │ ├── Program.cs │ └── Properties/ │ └── AssemblyInfo.cs └── DocsChecker.Tests/ ├── DocsAnalyzerTests.cs └── DocsChecker.Tests.csproj ================================================ FILE CONTENTS ================================================ ================================================ FILE: .claude/CLAUDE.md ================================================ # AI Documentation Read `ai/README.md` for indexed reference docs on types, algorithms, and utilities. ================================================ FILE: .config/dotnet-tools.json ================================================ { "version": 1, "isRoot": true, "tools": { "paket": { "version": "10.0.0-alpha011", "commands": [ "paket" ], "rollForward": false }, "aardpack": { "version": "2.0.7", "commands": [ "aardpack" ], "rollForward": false } } } ================================================ FILE: .github/workflows/build.yml ================================================ name: Build on: push: paths-ignore: - 'README.md' - 'docs/**' pull_request: paths-ignore: - 'README.md' - 'docs/**' jobs: codegen-check: runs-on: windows-latest steps: - uses: actions/checkout@v4 - name: Setup .NET uses: actions/setup-dotnet@v4 with: global-json-file: global.json - name: Cache Paket uses: actions/cache@v4 with: path: | ~/.nuget/packages paket-files key: ${{ runner.os }}-paket-${{ hashFiles('paket.lock') }} restore-keys: | ${{ runner.os }}-paket- - name: Restore shell: cmd run: .\build.cmd restore - name: Run forced code generation shell: cmd run: .\generate.cmd --force - name: Fail on generated diffs shell: pwsh run: | git diff --quiet -- src if ($LASTEXITCODE -ne 0) { Write-Host "Generated files are out of date:" git diff --name-only -- src exit 1 } build: needs: codegen-check runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] include: - os: ubuntu-latest run-build: bash ./build.sh - os: windows-latest run-build: .\build.cmd - os: macos-latest run-build: bash ./build.sh steps: - uses: actions/checkout@v4 - name: Setup .NET uses: actions/setup-dotnet@v4 with: global-json-file: global.json - name: Cache Paket uses: actions/cache@v4 with: path: | ~/.nuget/packages paket-files key: ${{ runner.os }}-paket-${{ hashFiles('paket.lock') }} restore-keys: | ${{ runner.os }}-paket- - name: Build run: ${{ matrix.run-build }} ================================================ FILE: .github/workflows/docs-check.yml ================================================ name: Docs Check on: push: pull_request: jobs: docs-check: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] steps: - uses: actions/checkout@v4 - name: Setup .NET uses: actions/setup-dotnet@v4 with: global-json-file: global.json - name: Run docs checker (Unix) if: runner.os != 'Windows' run: bash ./check-docs.sh - name: Run docs checker (Windows) if: runner.os == 'Windows' shell: cmd run: .\check-docs.cmd ================================================ FILE: .github/workflows/publish.yml ================================================ name: Publish on: push: branches: - master - v53 paths: - RELEASE_NOTES.md - .github/workflows/publish.yml jobs: release-check: name: Check release version runs-on: windows-latest permissions: contents: read outputs: should_publish: ${{ steps.compare.outputs.should_publish }} release_notes_version: ${{ steps.compare.outputs.release_notes_version }} latest_release_version: ${{ steps.compare.outputs.latest_release_version }} steps: - name: Checkout uses: actions/checkout@v4 - name: Install Dotnet uses: actions/setup-dotnet@v4 with: global-json-file: global.json - name: Restore Tools run: dotnet tool restore - name: Compare release versions id: compare shell: pwsh env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | function Normalize-Version([string] $Version) { if ([string]::IsNullOrWhiteSpace($Version)) { return "" } return $Version.Trim() -replace '^[vV]', '' } $parseOutput = & dotnet aardpack --parse-only if ($LASTEXITCODE -ne 0) { throw "dotnet aardpack --parse-only failed with exit code $LASTEXITCODE." } $releaseNotesVersion = ($parseOutput | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -Last 1).Trim() if ([string]::IsNullOrWhiteSpace($releaseNotesVersion)) { throw "dotnet aardpack --parse-only did not return a release notes version." } $headers = @{ Authorization = "Bearer $env:GITHUB_TOKEN" Accept = "application/vnd.github+json" "X-GitHub-Api-Version" = "2022-11-28" "User-Agent" = "github-actions" } $latestReleaseVersion = "" $shouldPublish = "true" try { $latestRelease = Invoke-RestMethod ` -Uri "https://api.github.com/repos/${{ github.repository }}/releases/latest" ` -Headers $headers $latestReleaseVersion = [string] $latestRelease.tag_name if ((Normalize-Version $releaseNotesVersion) -eq (Normalize-Version $latestReleaseVersion)) { $shouldPublish = "false" } } catch { $statusCode = $_.Exception.Response.StatusCode.value__ if ($statusCode -eq 404) { Write-Host "No latest GitHub release found. Continuing publish workflow." } else { throw } } "release_notes_version=$releaseNotesVersion" >> $env:GITHUB_OUTPUT "latest_release_version=$latestReleaseVersion" >> $env:GITHUB_OUTPUT "should_publish=$shouldPublish" >> $env:GITHUB_OUTPUT "## Publish release check" >> $env:GITHUB_STEP_SUMMARY "" >> $env:GITHUB_STEP_SUMMARY "- Release notes version: ``$releaseNotesVersion``" >> $env:GITHUB_STEP_SUMMARY "- Latest GitHub release: ``$latestReleaseVersion``" >> $env:GITHUB_STEP_SUMMARY "- Should publish: ``$shouldPublish``" >> $env:GITHUB_STEP_SUMMARY pack: name: Package needs: release-check if: needs.release-check.outputs.should_publish == 'true' runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Install Dotnet uses: actions/setup-dotnet@v4 with: global-json-file: global.json - name: Restore Tools run: dotnet tool restore - name: Restore run: dotnet paket restore - name: Run forced code generation shell: cmd run: .\generate.cmd --force - name: Fail on generated diffs shell: pwsh run: | git diff --quiet -- src if ($LASTEXITCODE -ne 0) { Write-Host "Generated files are out of date:" git diff --name-only -- src exit 1 } - name: Build shell: cmd run: dotnet build -c Release src\Aardvark.sln - name: Test run: dotnet test src\Aardvark.sln -c Release --no-build --nologo --logger:"console;verbosity=normal" - name: Pack env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: dotnet aardpack src\Aardvark.sln --notag --skip-build - name: Upload Packages uses: actions/upload-artifact@v4 with: name: packages path: bin\pack - name: GitHub Packages env: NUGET_KEY: ${{ secrets.GITHUB_TOKEN }} shell: cmd run: dotnet nuget push "bin\pack\*.nupkg" -k %NUGET_KEY% -s "https://nuget.pkg.github.com/aardvark-platform/index.json" --skip-duplicate - name: NuGet env: NUGET_KEY: ${{ secrets.NUGET_KEY }} shell: cmd run: dotnet nuget push "bin\pack\*.nupkg" -k %NUGET_KEY% -s "https://api.nuget.org/v3/index.json" --skip-duplicate ================================================ FILE: .gitignore ================================================ **/.DS_Store /.paket/paket.exe /src/Aardvark.Base/obj /src/*.suo /src/*.userprefs /bin/net40 /bin/net45 /packages/* !/packages/*.config *.nupkg obj /src/Aardvark.sln.ide *.swp bin *.*~ /buildLog.log /src/.vs tmp /docs !/docs/ !/docs/CONTRIBUTING.md !/docs/INTEROP.md !/docs/TROUBLESHOOTING.md /src/Aardvark.Base/Images/TensorExtensions_generator.cs /src/Demo/Sketch/.vs/Sketch/v14/*.suo /TestResult.xml /.fake /paket-files /tests.out /*.log /src/Aardvark.Base/Tensors/TensorMathExt_generator.cs **/*.csproj.user **/*_generator.cs /.paket *.fsproj.user Aardvark.log /build.fsx.lock .ionide /.vs .idea .boss/ src/Aardvark.sln.DotSettings.user .claude/settings.local.json ================================================ FILE: .vscode/settings.json ================================================ { "dotnet-test-explorer.testProjectPath": "src/Aardvark.sln", "files.exclude": { "**/.git": true, "**/.svn": true, "**/.hg": true, "**/CVS": true, "**/.DS_Store": true, "**/Thumbs.db": true, ".paket": true, ".ionide": true, "packages": true, "paket-files": true, "**/obj/": true } } ================================================ FILE: .vscode/tasks.json ================================================ { // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "2.0.0", "tasks": [ { "label": "restore-tools", "command": "dotnet", "type": "shell", "args": [ "tool", "restore" ], "group": "build", "runOptions": { "runOn": "folderOpen" }, "presentation": { "echo": false, "reveal": "never", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": false, "close": true } }, { "label": "restore", "command": "dotnet", "type": "shell", "args": [ "paket", "restore" ], "group": "build" }, { "label": "codegen", "command": "dotnet", "type": "shell", "args": [ "run", "--project", "src/CodeGenerator/CodeGenerator.csproj" ], "group": "build" }, { "label": "build", "command": "dotnet", "type": "shell", "args": [ "build", "src/Aardvark.sln", // Ask dotnet build to generate full paths for file names. "/property:GenerateFullPaths=true", // Do not generate summary otherwise it leads to duplicate errors in Problems panel "/consoleloggerparameters:NoSummary" ], "group": "build", "presentation": { "reveal": "silent" }, "problemMatcher": "$msCompile" }, { "label": "install", "command": "dotnet", "type": "shell", "args": [ "paket", "install" ], "group": "build", "presentation": { "reveal": "always" }, "problemMatcher": "$msCompile" }, { "label": "clean", "command": "dotnet", "type": "shell", "args": [ "clean", "src/Aardvark.sln" ], "group": "build", "presentation": { "reveal": "always" } } ] } ================================================ FILE: AGENTS.md ================================================ # AI Agent Guide Repository-specific rules and verified operational facts for coding agents. Primary AI reference index: `ai/README.md` ## Supported Commands Use these commands for restore/build/test/codegen: | Task | Command | Notes | |------|---------|-------| | Restore only | `./build.sh restore` or `.\build.cmd restore` | Restores dotnet tools + paket packages, auto-repairing missing Paket targets with `dotnet paket install`, and returns a nonzero exit code on the first failure | | Build all | `./build.sh` or `.\build.cmd` | Builds `src/Aardvark.sln` and stops on the first failing step | | Build one project | `dotnet build src/Aardvark.Base/Aardvark.Base.csproj -c Debug` | Use explicit project path | | Test all | `./test.sh` or `.\test.cmd` | Runs the five maintained test projects, stopping on the first failing step; excludes benchmark projects and the deprecated incremental test project | | Test one project | `dotnet test src/Tests/Aardvark.Base.Tests/Aardvark.Base.Tests.csproj -c Debug` | Prefer this over whole-solution test | | Test with filter | `dotnet test src/Tests/Aardvark.Base.Tests/Aardvark.Base.Tests.csproj --filter "FullyQualifiedName~Vector"` | Works with NUnit adapter; use a concrete test project | | Codegen | `./generate.sh` or `.\generate.cmd` | Required after template changes | | Check docs drift | `./check-docs.sh` or `.\check-docs.cmd` | Validates docs against source anchors and anti-drift rules | ## Dependency Management (Paket) This repo uses Paket, not `dotnet add package`. | Task | Command | |------|---------| | Add package | `dotnet paket add --project ` | | Update group | `dotnet paket update --group Main` | | Re-resolve lock | `dotnet paket install` | | Restore packages | `dotnet paket restore` | Rules: - Never edit `paket.lock` manually - Never use `dotnet add package` in this repo - Change constraints in `paket.dependencies`, then regenerate lock with Paket - Top-level `build.*` / `test.*` scripts auto-run `dotnet paket install` when `.paket/Paket.Restore.targets` is missing; otherwise they use `dotnet paket restore` - Top-level `build.*` / `test.*` scripts now stop immediately on the first failing restore/build/test command and return that nonzero exit code ## Release Notes When a change needs release notes: - `aardvark.build` reads the first `### ` section as the current package version - unreleased notes may appear above that first version section as plain text or bullet points - do not add a markdown heading such as `### Preliminary` above the first version section - do not append new notes inside an older released version block - if you add pending/preliminary notes, place them above the first version section instead of inside the previous released block ## File Ownership by Change Type | Change Type | Files to Modify | Files to Avoid | |-------------|-----------------|----------------| | Add C# feature | `src/Aardvark.Base/**/*.cs`, `src/Aardvark.Base.IO/**/*.cs`, `src/Aardvark.Base.Essentials/**/*.cs` | `*_auto.cs`, `*_template.cs` unless you are updating generation templates intentionally | | Add F# feature | `src/Aardvark.Base.FSharp/**/*.fs`, `src/Aardvark.Base.Incremental/**/*.fs`, `src/Aardvark.Base.Tensors/**/*.fs`, `src/Aardvark.Geometry/**/*.fs`, `src/Aardvark.Base.Runtime/**/*.fs`, `src/Aardvark.Base.Fonts/**/*.fs` | Generated `*_auto.fs` unless template-driven change | | Add tests | `src/Tests/**/*Tests.cs`, `src/Tests/**/*Tests.fs` | Unrelated production modules | | Fix bug | Smallest relevant source area + regression test | Broad refactors without tests | | Update dependencies | `paket.dependencies` (+ Paket-generated lock update) | Manual lock edits | ## Cross-Language Reality (Important) Do not assume strict one-way C#/F# dependency rules here. This solution intentionally mixes languages: - F# projects reference C# projects - Some C# projects also reference F# projects (for example `Aardvark.Base.IO` references `Aardvark.Base.Tensors.fsproj`) Guideline for agents: - Preserve existing dependency direction used by neighboring projects - If introducing a new reference, check existing project patterns first - Avoid creating dependency cycles ## Framework, SDK, and Project Matrix - SDK pin: `.NET SDK 8.0.0` with `rollForward: latestFeature` (see `global.json`) - Not all projects target the same framework Current project reality: - Mixed `net8.0;netstandard2.0`: `Aardvark.Base`, `Aardvark.Base.FSharp`, `Aardvark.Base.IO` - `netstandard2.0` only: `Aardvark.Base.Essentials`, `Aardvark.Base.Telemetry`, `Aardvark.Base.Tensors`, `Aardvark.Base.Tensors.CSharp`, `Aardvark.Base.Runtime`, `Aardvark.Base.Fonts`, `Aardvark.Geometry` - `net8.0` test/demo projects: most projects in `src/Tests` and `src/Demo` - Deprecated legacy test project: `src/Tests/Aardvark.Base.Incremental.Tests/Aardvark.Base.Incremental.Tests.fsproj` still targets `netcoreapp3.0`, is intentionally excluded from `src/Aardvark.sln` and the standard `test.sh` / `test.cmd` path, and is tracked for removal-or-migration in GitHub issue `#94` - C# language version is not uniform (`12.0` in `Aardvark.Base`, `10.0` in some other C# projects) ## Common Failure Modes | Symptom | Cause | Fix | |---------|-------|-----| | `dotnet paket restore` fails | Paket/tool state mismatch | `dotnet tool restore` then `dotnet paket restore`; if `.paket/Paket.Restore.targets` is missing or scripts are not being used, run `dotnet paket install` | | Compile errors in generated files | Template/output out of sync | Run `./generate.sh` or `.\generate.cmd` | | Build fails due framework mismatch | Running old SDK/runtime | Install .NET 8 SDK; verify `dotnet --info` and `global.json` | | Test filter returns zero tests | Wrong filter syntax | Use `FullyQualifiedName~...` pattern | | Docs check fails | Broken links, stale examples, missing anchors, mojibake | Run `./check-docs.sh` or `.\check-docs.cmd` and fix the reported file/pattern | | Rendering namespace not found | Wrong package assumption | `Aardvark.Rendering` comes from downstream package, not this repo | ## Project Structure ```text src/ |- Aardvark.Base/ (core C# math/geometry/types) |- Aardvark.Base.Essentials/ (additional C# utilities) |- Aardvark.Base.IO/ (I/O and image codecs; C#) |- Aardvark.Base.Telemetry/ (telemetry probes; C#) |- Aardvark.Base.Tensors.CSharp/ (C# tensor/piximage layer) |- Aardvark.Base.FSharp/ (F# functional extensions) |- Aardvark.Base.Incremental/ (adaptive system; F#) |- Aardvark.Base.Tensors/ (tensor features; F#) |- Aardvark.Base.Runtime/ (runtime helpers; F#) |- Aardvark.Base.Fonts/ (font/text support; F#) |- Aardvark.Geometry/ (geometry algorithms; F#) |- Tests/ (C# + F# test projects) |- Demo/ (sample apps) |- CodeGenerator/ (template/code generation tooling) ``` ## AI Reference Docs See `ai/README.md` for task-based lookup across: - primitive math/geometry types - linear algebra semantics (layout/interoperability) - geometry semantics (transform conventions) - piximage/tensor APIs - algorithms and collections - serialization - utilities - F# interop - incremental/adaptive system ## Agent Workflow Tips 1. Read only the doc needed for your task, not all docs 2. Verify API names with `rg` before using examples from docs 3. Prefer local source as the final truth if docs and code disagree 4. Run focused tests for touched modules before broad test runs 5. When changing templates, regenerate before building 6. When changing docs, run `./check-docs.sh` or `.\check-docs.cmd` --- Last updated: 2026-02-26 ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Aardvark Platform Copyright (C) 2006-2019 Aardvark Platform Team https://aardvark.graphics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: PACKAGES.md ================================================ # Approach Stable packages will be pushed to nuget by the maintainers. # Developer packages Community packages go to github, for this register your github token using: `paket config add-token https://nuget.pkg.github.com/aardvark-platform ` use build pushgithub ================================================ FILE: README.md ================================================ # Aardvark.Base [![Build](https://github.com/aardvark-platform/aardvark.base/actions/workflows/build.yml/badge.svg)](https://github.com/aardvark-platform/aardvark.base/actions/workflows/build.yml) [![Publish](https://github.com/aardvark-platform/aardvark.base/actions/workflows/publish.yml/badge.svg)](https://github.com/aardvark-platform/aardvark.base/actions/workflows/publish.yml) [![License](https://img.shields.io/github/license/aardvark-platform/aardvark.base.svg?label=License)](https://github.com/aardvark-platform/aardvark.base/blob/master/LICENSE) [![NuGet](https://img.shields.io/nuget/v/Aardvark.Base.svg)](https://www.nuget.org/packages/Aardvark.Base/) High-performance .NET foundation for visual computing, real-time graphics and geometry processing. Cross-platform (Windows/Linux/macOS), targets .NET Standard 2.0 and .NET 8.0. Foundation of the [Aardvark Platform](https://github.com/aardvark-platform) ecosystem, powering advanced libraries for rendering (Aardvark.Rendering), UI (Aardvark.Media), VR/AR applications, and scientific visualization. ## Core Components **Mathematics & Geometry** - Vectors, matrices, quaternions, transformations (2D/3D/4D) - Ranges, boxes, spheres, planes, rays, frustums - Polygons, meshes, BVH acceleration structures - Linear/ellipsoid regression, geometric algorithms **Image Processing** - PixImage with full tensor capabilities - Format support: JPEG, PNG, TIFF, EXR, WebP, DDS - Mipmaps, cube maps, volume textures - Hardware-accelerated scaling and transformations **Data Structures & Algorithms** - Incremental/reactive programming primitives - Efficient collections (IntDict, SymbolDict, MapExt) - Spatial indexing (KdTree, BVH) - Fast serialization/deserialization ## Quick Start ```csharp using Aardvark.Base; // Vectors and matrices var v = new V3d(1, 2, 3); var m = M44d.RotationX(45.0.RadiansFromDegrees()); var transformed = m.TransformPos(v); // Image processing var image = PixImage.Load("image.jpg"); var scaled = image.Scaled(0.5); scaled.Save("output.png"); // Geometry var box = new Box3d(V3d.Zero, V3d.One); var ray = new Ray3d(V3d.Zero, V3d.XAxis); var hit = ray.Intersects(box, out double t); ``` ## Installation ``` dotnet add package Aardvark.Base dotnet add package Aardvark.Base.FSharp # F# extensions ``` ## Resources - [Gallery](https://github.com/aardvark-platform/aardvark.docs/wiki/Gallery) - [Packages & Repositories](https://github.com/aardvark-platform/aardvark.docs/wiki/Packages-and-Repositories) - [Documentation](https://github.com/aardvark-platform/aardvark.base/wiki) - [API Reference](https://aardvarkians.com/) - [Platform Overview](https://github.com/aardvark-platform/aardvark.docs/wiki) - [Discord Community](https://discord.gg/UyecnhM) - [AI Reference](./ai/) - Technical docs for AI coding assistants ## License [Apache 2.0](LICENSE) ================================================ FILE: RELEASE_NOTES.md ================================================ - [IO] Hardened `UberStream` constructor and read/write argument validation - [Base] Made `EnumerableEx.AllDistinct` and `AllEqual` enumerate inputs only once - [PixImage] Fixed save-parameter validation messages to report numeric values without a leading dollar sign - [Base] Hardened `Stream.ReadBytes` argument validation before reading - [Random] Fixed `TakeRandomly` to reject NaN probabilities - [Base] Fixed `SingleValueSymbolDict` value-only construction and shared-value setter/add behavior - [Essentials] Fixed `EventSourceSlim` next-value awaitables and non-generic `IEvent` members - [Base] Completed `SingleEntryDict` lookup, removal, and re-add behavior - [Geometry] Fixed `Plane3.Project` array-slice validation for ranges ending at the array length - [Base] Fixed `EnumerableEx.SelectToList` overloads for arrays and lists - [Base] Fixed `StringFun.Plural` for empty and one-character words - [Base] Fixed `ListFun.Map3` to truncate to the shortest input list when the third list is shortest - [Base] Hardened `Adler32` input validation for null inputs and invalid array ranges - [Random] Fixed `RandomSystem` boundary handling for inclusive integer and open/closed floating-point samples - [Geometry] Implemented `Quad2.Contains(...)` overloads for lines, triangles, quads, and circles - [FSharp] Fixed null-argument validation for custom `Seq` helpers - [FSharp] Fixed `Seq.foldi` to pass the correct element index - [Essentials] Fixed `Task.WithCancellation` for already-canceled tokens ### 5.3.23 - [CI] Added a publish workflow early exit when release notes already match the latest GitHub Release ### 5.3.22 - [Telemetry] Fixed `WallClockTimer` timer disposal so repeated `Dispose` calls do not corrupt timer state - [Introspection] Fixed native library loading on Windows using netstandard2.0 (https://github.com/aardvark-platform/aardvark.base/issues/86) - [Base] Fixed `Dict.Contains(key, value)` for collided entries in hash buckets - [Base] Fixed reentrant `Dict.GetOrCreate` - [Base] Fixed linear polynomial real roots - [Base] Fixed special dict setter behavior - [Base] Added fast values enumerator API for dict types - [PixImage] Improved reporting of inner exceptions thrown by loaders and processors - [FSharp] Added `Array.chooseV` and `Array.chooseiV` - [FSharp] Added `Array.zipV` and `Array.unzipV` - [FSharp] Fixed null-input handling for custom array ValueOption helpers - [FSharp] Added intersection methods using `ValueOption` for `BvhTree` and `KdTree` ### 5.3.21 - [Base] Simplified computation of Constant.MachineEpsilon - [FSharp] Fixed MapExt.choose2 and MapExt.map2 ### 5.3.20 - [Base] Improved native library loading and symlink creation - [FSharp] Added utilities for copying streams - [Fonts] Added Font.LoadFromAssembly for loading embedded fonts - [Fonts] Improved error reporting by font resolver - [Fonts] Added missing Symbola font - [Fonts] Implemented font resolver for Linux - [Base] Added hashing extensions for typed arrays in NET Standard 2.0 to improve binary compatibility with .NET 8 build. ### 5.3.19 - [Color] Added missing over- and underflow checks - [PixCube] Added null- and length checks for input arrays - [PixCube] Added IsEmpty ### 5.3.18 - Added ReadOnlySpan overloads for Cell, Cell2d, and range types - [Tensors] Added and improved XML documentation - [Tensors] Added PixImage and PixVolume constructors for data arrays - [Color] Added over- and underflow checks for integer-based arithmetic operators - [Color] Deprecated addition and subtraction of different types - [Color] Deprecated integer-based multiplication and division - [FSharpMath] Added min, max overloads for uint vectors - [Introspection] Added overloads for unpacking native dependencies for a specific platform ### 5.3.17 - [FSharp] Added non-generic isNull and notNull - [FSharp] Added generic inc and dec - [FSharp] Fixed generic constraint of NativePtr.stackUseArr ### 5.3.16 - Fixed Cell.XYZ bug and improved doc comments - [FSharp] Added PinnedValue and PinnedValue<'T> utility for pinning values and arrays with IDisposable semantics - [FSharp] Added explicit type parameters to NativePtr functions - [PixImage] Improved error messages regarding image loaders ### 5.3.15 - [Geometry] fixed GetPlane/GetTrafo for LinearRegression2d - [Math] Added Fun.IsPowerOfTwo, Fun.NextPowerOfTwo, Fun.PrevPowerOfTwo overloads for uint32 and uint64 ### 5.3.14 - [FSharp] Added workaround for compiler-related bug in NativePtr.pin, pinArr, and pinArri (https://github.com/dotnet/fsharp/issues/18689) - [FSharp] Added tryLastV for Seq, List, and Array ### 5.3.13 - [FSharp] Added null-coalesing operator ||? - [FSharp] Added Seq.asArray - [FSharp] Added IDictionary and IReadOnlyDictionary interfaces for MapExt - [FSharp] Added tryFindV, tryPickV, pickV, tryHeadV for Seq, List, and Array - [Base] Added IDictionary and IReadOnlyDictionary interfaces for Dict, IntDict, SymbolDict, DictIEq - [Base] Added ContainsValue() for Dict types - [Ag] Use ValueOption internally and added overloads for public API returning ValueOption ### 5.3.12 - Fixed regression in range constructors ### 5.3.11 - Fixed range constructors for empty and null arrays and sequences - Added GrayAlpha pixel format constants - Added ToString() override for PixFormat - Added PixFileFormat.Webp and PixWebpSaveParams - Added more known image file extensions - Added PixTiffSaveParams for choosing the compression scheme when saving TIFF images - Added PixExrSaveParams for choosing the compression scheme when saving EXR images ### 5.3.10 - [IO] Added SymMap constructor overload ### 5.3.9 - [Base] Added AliasTable - [Base] Added Triangle.Distance - [Base] Added Triangle.SolidAngle - [FSharp] Added NativePtr.stackUseArr - [FSharp] Added Map.tryFindV - [FSharp] Added Map.ofSeqWithDuplicates - [FSharp] Added choosei, collecti for Seq, List, Array - [FSharp] Added assignment operators - [FSharp] Added Type.CLRSize extension property - [Introspection] Made native library loading more robust - [Introspection] Fixed issue with plugin cache invalidation - [Report] Using Stopwatch.GetTimestamp() instead of Stopwatch instance in ReportJob ### 5.3.8 - [FSharp] Added stableSum and stableSumBy for List, Array, and Seq - added basic BbTree implementation without operations ### 5.3.7 - Marked quaternion to matrix conversion obsolete as it is misleading - Added conversions between ranges and 2D vectors - Added Lerp and InvLerp for integer ranges and boxes - Unified native dependency unpacking and added Aardvark.UnpackAndListNativeDependencies ### 5.3.6 - Updated System.Text.Json dependency (CVE-2024-43485) - Added angle conversion utilities for ranges - Added Ray3.Transformed overloads - Added Ray3.Normalized - Added Vec.AngleBetweenSigned for 2D vectors - Added Fun.WrapToPi - Added 2D ray-circle intersection methods ### 5.3.5 - [Base] added IsEmpty/IsEmptyOrNull overloads for Array/ICollection with efficient implementation - [Base] added FindValue and FindNeighboursV to SortedSet - [FSharp] changed MemoryManager/FreeList to use value tuples/options and use new SortedSet methods - [FSharp] added Path.normalizeDirectorySeparators - [FSharp] fixed Path.withTrailingSlash and Path.withoutTrailingSlash to consider Path.AltDirectorySeparatorChar ### 5.3.4 - [FSharp] Moved pin utilities to modules; added pinArri, temp - Prevent multiple invocations of Aardvark.Init - Added new PixProcessor API for plugin-based scaling, rotating and remapping of images (replaces PixImage.SetScaledFun et al.) ### 5.3.3 - Optimized ReferenceCountingSet (struct enumerator, internal struct tuples) - Restored MD5 hashing extensions (fixes: https://github.com/aardvark-platform/aardvark.base/issues/72) - [Introspection] Native libraries are now unpacked to the default Aardvark cache directory with subfolders for each platform (fixes: https://github.com/aardvark-platform/aardvark.base/issues/81). - [Introspection] Improved support for single file deployment. Fixed plugin loading and caching (fixes: https://github.com/aardvark-platform/aardvark.base/issues/65). - [Introspection] Made assembly loading more robust for NET 8. If an assembly cannot be resolved the entry path is checked for the assembly file, making it possible to load assemblies by name that are not runtime or compilation dependencies (see also: https://github.com/Particular/Workshop/issues/64). - [FSharp] Added RequireQualifiedAccess attribute to ProcListValue - [FSharp] Added RequireQualifiedAccess attribute to Tree - [FSharp] Added pin, pinArr, and NativePtr.Address - Added Stream.ReadBytes extension ### 5.3.2 - [FSharp] Revert LookupTable utilities to use lists instead of seq ### 5.3.1 - [FSharp] Added Stream.readAllBytes - [FSharp] Added Path.withTrailingSlash and withoutTrailingSlash - [FSharp] Added approximateEquals - [FSharp] Reworked LookupTable utilities - [FSharp] Optimized and reworked type patterns - [FSharp] Imported PrimitiveValueConverter from Aardvark.Rendering ### 5.3.0 - https://github.com/aardvark-platform/aardvark.base/wiki/Aardvark-5.3-changelog ### 5.3.0-prerelease0005 - Reintroduced `IPixImage` as `IPix` - Renamed `PixImageCube` to `PixCube` ### 5.3.0-prerelease0004 - Fixed PixImage/Volume conversion with redundant channels - Added Width, Height, and Depth properties for PixImage and PixVolume ### 5.3.0-prerelease0003 - Restored Error<'T> - [PixImageMipMap] Re-added PixFormat and reverted rename of ImageArray field - [PixImageMipMap] Renamed Count to LevelCount - [PixImageCube] Reverted rename of MipMapArray field - [PixLoader] Added CanEncode and CanDecode - Made Array and Data of PixImage and PixVolume consistent with tensors ### 5.3.0-prerelease0002 - Removed Result<'T> alias - [FSharpMath] Fixed conflicts in SRTP member names with .NET - [Color] Added Fun.Lerp overloads with vector parameter ### 5.3.0-prerelease0001 - Initial prerelease ### 5.2.32 - Fixed Type.GetCLRSize for structs - Use .NET functions for Array.Copy and Set - Fixed Array CopyTo extension overloads for copying between an array and native memory - Changed SymMapBaseCollectionTraversal.Collect typeName argument to Symbol - Added ToBase64 extensions with span - Added generic Compute**Hash overloads (avoiding GetCLRSize) - Added AsCastSpan extension ### 5.2.31 * fixed Hash Computations for non-primitive types * added `AsByteSpan` extension method for System.Array/string in >=net6.0 ### 5.2.30 * removed UnsafeCoerce usages and several other net6.0+ fixes ### 5.2.29 * Fixed color parsing to be independent of the current culture (regression in 5.2.27) * Added more value variants for Dictionary, Dict, and SymbolDict functions ### 5.2.28 * Added Brewer color schemes * Added String.replace * Added IDictionary.TryPop overload with output argument ### 5.2.27 * Improved and fixed RangeSet implementation * Added utilities for ValueOption * Added more ArraySegment utilities * [Text] Fixed NestedBracketSplitCount * [Color] Fixed overflow issue in C4ui constructors * [Color] Improved color parsing, now supports hexadecimal color strings * [PixImage] Fixed file handle leak in Windows Media loader * [MapExt] Added value variants of some operations ### 5.2.26 * LinearRegression3d: made fields public * Added getLines, normalizeLineEndings, withLineNumbers in String module * Fixed FGetValueOrDefault dictionary extension * Added value variants for Dict functions * Added F# ArraySegment utilities * [Introspection] Tidied up exception reporting ### 5.2.25 * Fixed issue with PixImageMipMap loading * Improved exception message of EnumHelpers methods * [Introspection] Use XML serialization for plugin cache * Replaced netcoreapp3.1 target with net6.0 ### 5.2.24 * fixed and optimized Cell.Contains * update Aardvark.Build to 1.0.19 ### 5.2.23 * Fixed build for VS 2019 / .NET 6 ### 5.2.22 * Fixed RandomSample.Lambertian internal calculation precision * Added float bits method overloads for unsigned vectors * Use reflection-based PixImageMipMap creation * [TypeInfo] Added color-related types and patterns * [Trafo] Implemented infinite far plane for perspective projection * [Trafo] Added reversed perspective projection variants * [Introspection] Increased verbosity level of custom attribute error ### 5.2.21 * Made non-generic PixImage creation more flexible and robust * Added NativePtr.Item and NativePtr.Value * Added Buffer.MemoryCopy overloads with nativeint arguments ### 5.2.20 * [Base] added float overloads to RandomSample methods * [Base] changed array memory copies to use Buffer.MemoryCopy * [PixImage] respect channel order in format and type conversion * [PixImage] improved support for dual-channel images * [PixImage] fixed and improved format conversion * [Tensors] added simple accessors for Gray and BW * [Vrml] added support for gzip compressed files * [Vrml] allow registration of custom field parsers * [Vrml] improved robustness in case of unknown field tokens ### 5.2.19 * Added IPixMipmapLoader for loading images with mipmap chains * Marked some exotic image loading functions obsolete ### 5.2.18 * made introspection attribute querying more robust ### 5.2.17 * JSON support - add missing Range1* types - handling of special float values (NaN, +Inf, -Inf) * Add Vec.w * Update Aardvark.Build ### 5.2.16 * support System.Text.Json for primitive types (vectors, matrices, boxes, transforms, geometric primitives, ...) ### 5.2.15 * Added File.writeAll* variants that create parent directories * [IO] Added logging output in case there is a stream position mismatch * [PixImage] Print path when loading from file stream ### 5.2.14 * Updated to ImageSharp 2.1 * Implemented default PixImage scaling function * Configurable PixImage functions throw proper exceptions * Added float16 support for PixImageMipMap * [Introspection] changed logging message when using CustomEntryAssembly from warning to normal ### 5.2.13 * Added uint32 vector types (V2ui, V3ui, V4ui) * Added Disposable.empty * Inlined color conversion methods, deprecating lambdas * Implemented color conversions for Float16 * [Patterns] Added 2x3 matrices ### 5.2.12 * Added Fun.PowerOfTwo for int32 vectors * [FSharpMath] Added exp2, step, and linearstep * [Patterns] Added missing vector and matrix types * Added Fun.Step and Fun.Linearstep ### 5.2.11 * [Ag] Removed compiler message ### 5.2.10 * fixed VRML transformations (missing normalization) ### 5.2.9 * Executable memory tools are now obsolete (use Aardvark.Assembler nuget package instead) ### 5.2.8 * revert obsolete AMD64 assembler to original behaviour ### 5.2.7 * fixed AMD64 assembler Begin/End (saving callee saved registers) ### 5.2.6 - [PixImage.SystemDrawing] removed System.Drawing.Common upper version constraint - [IO] BinaryReadingCoder: patch object reference after converter/proxy conversion (#77) ### 5.2.5 - Ported System.Drawing bitmap extensions to new PixLoader API (renamed to Aardvark.PixImage.SystemDrawing) - Added Aardvark.PixImage.WindowsMedia - Added Trafo.(Inv)TransformPosProj(Full) - Added constructors and comments for tensor info structs ### 5.2.4 - Added new API for PixImage loading and saving - Added PixImage.meanSquaredError and PixImage.peakSignalToNoiseRatio - Moved System.Drawing primitives extensions to Aardvark.Base.SystemDrawingInterop ### 5.2.3 - Added transform methods for Trafo types - Added float32 overload for WeightedSum - Fixed Plane3d.Transformed methods - Added remainder operator for vector types - Made Col.FormatDefaultOf more flexible - [Report] Create directory for log file if it does not exist - Added RangeSet64 ### 5.2.2 - [ImageSharp] Implemented proper per row processing ### 5.2.1 - [ImageSharp] Switched to contiguous image buffers ### 5.2.0 - https://github.com/aardvark-platform/aardvark.docs/wiki/Aardvark-5.2-changelog ### 5.1.27 - added Transformed method for MatrixInfo and VolumeInfo - fixed ldconfig regex for entries with ABI ### 5.1.26 - added PixImage and PixVolume related extensions to native tensors - added PolyRegion2d.Overlaps(Box2d) - fixed byte color indexing - removed unnecessary DevILSharp references - added Map.unionMany - fixed Ceres native unpack - workaround for loading native IPP dependencies ### 5.1.25 - another SHA1 truncate ### 5.1.24 - "simulated" MD5 via truncated SHA1 (please don't hit me security bubble) ### 5.1.23 - switched MD5 to SHA1 ### 5.1.22 - updated to FSharp.Core >= 5.0.0 ### 5.1.21 - [Report] workaround for getting/setting Console.ForegroundColor when not available. added `NoTarget` to Report for disabling ### 5.1.20 - add Cell.GetCommonRoot(...) and corresponding constructor overloads; same for Cell2d ### 5.1.19 - fixed cell-from-box constructor for boxes with Max including 0.0 - Relax asserts in matrix and rot methods and constructors ### 5.1.18 - cleaned up and fixed cell construction from boxes ### 5.1.17 - Add Fun.Log2CeilingInt - Fix power of two edge cases in Cell and Cell2d ### 5.1.16 - updated build script - fixed PixImage.CreateRaw loader fallback - fixed default AssemblyFilter - fixed Introspection ignoring GLSLangSharp - unbreak Cell to work with fixed Log2Int (same for Cell2d) ### 5.1.15 - added functions for computing mipmap level count and size - added support for signed integer PixImages - changed default introspection cache location to LocalApplicationData - fixed Log2Int - fixed missing FileStream Dispose in Vrml97 parser ### 5.1.14 - fixed Introspection caching ### 5.1.13 - added Plane2d.Intersects overload that was removed accidentally ### 5.1.12 - added missing XmlIgnore attribute to vector swizzles - added ValuesWithKeyEnumerator to Dicts - preparations for .net 5 single file deployment - added missing finite checks to vectors and matrices - added vector variants for Fun.FloatToBits and Fun.FloatFromBits - fixed Box2d - Line2d intersection test - fixed Plane2d - Ray2d intersection test - fixed polygon extensions ### 5.1.11 - added some IAssemblerStream methods (AddInt, MulInt, etc.) ### 5.1.10 - fixed mscorlib recursive resource lookup (#61) - added Constant initialization (#59) ### 5.1.9 - removed System.Reactive depdendency - raised FSharp.Core version to >= 4.7.0 ### 5.1.8 - added polygon transformataions (#57) - prioritization of custom images loaders: considering last registered first - consistency and completeness of Ray3d.Hits overloads - changed Ray3d.Hits default range to [0, double.MaxValue] ### 5.1.6 - fixed Fun.Frac for tiny negative numbers - added invLerp to FSharpMath ### 5.1.5 - devil loader functions are now public ### 5.1.4 - updated to FSharp.Data.Adaptive 1.2 - added IEquatable to math types - added Array.binarySearch ### 5.1.3 - udpated build script ### 5.1.2 - testing - new package mechanism ### 5.1.1 - switched to FSharp.Data.Adaptive 1.1 ================================================ FILE: ai/ALGORITHMS.md ================================================ # Aardvark.Base Algorithms Reference Source-verified map of key algorithm types and entry points. ## ShortestPath `ShortestPath` implements `IShortestPath` and runs asynchronous shortest-path computation. Key methods: - `CalculateShortestPaths(T seed)` - `CalculateShortestPathsByIndex(int seedIndex)` - `GetMinimalPath(T target)` - `GetMinimalPathByIndex(int targetIndex)` - `Cancel()` Constructors: ```csharp new ShortestPath(List nodes, List<(int,int)> edges, Func getCost); new ShortestPath(T[] nodes, List[] neighbors, Func getCost); ``` ## BbTree Bounding-box hierarchy in `Geometry/BbTree.cs`. Constructor: ```csharp new BbTree(Box3d[] boundingBoxes, BbTree.BuildFlags flags = BbTree.BuildFlags.Default, int[] countArray = null); ``` Useful members: - `NodeCount` - `Box3d` - `IndexArray` - `LeafArray` - `LeftBoxArray` - `RightBoxArray` - `GetLeft(i)`, `GetRight(i)` `BbTreeHit` contains `NodeIndex` and `RayT`. ## Linear Algebra Numerics Available in `Math/LuFactorization.cs` and `Math/QrFactorization.cs`: - `LuFactorize` - `LuSolve` - `LuInverse` - `QrFactorize` `LuFactorize` is in-place. ## Probability Sampling ### Alias tables Types: - `AliasTableF` - `AliasTableD` Construction/update: ```csharp var t = new AliasTableD(pdf, 1.0 / pdf.Sum()); t.Update(newPdf, 1.0 / newPdf.Sum()); int index = t.Sample(rnd.UniformDouble()); ``` `FromPdf` / `FromNormalizedPdf` exist as instance methods on the class. ### DistributionFunction `DistributionFunction` provides CDF-based sampling: ```csharp var d = new DistributionFunction(pdf); int i = d.Sample(rnd); int j = DistributionFunction.SampleCDF(d.CDF, rnd.UniformDouble()); ``` ## Polynomial `Polynomial` is in `Math/Numerics/Polynomial.cs` (not `Math/Base`). Examples: - `coeff.Evaluate(x)` - `coeff.Derivative()` - `Polynomial.RealRootsOfNormed(...)` ## Source Anchors - `src/Aardvark.Base/AlgoDat/ShortestPath.cs` - `src/Aardvark.Base/Geometry/BbTree.cs` - `src/Aardvark.Base/Math/LuFactorization.cs` - `src/Aardvark.Base/Math/QrFactorization.cs` - `src/Aardvark.Base/Math/Base/AliasTable_auto.cs` - `src/Aardvark.Base/Math/Base/DistributionFunction.cs` - `src/Aardvark.Base/Math/Numerics/Polynomial.cs` ================================================ FILE: ai/COLLECTIONS.md ================================================ # Aardvark.Base Collections Reference Source-verified reference for custom collection and symbol infrastructure. ## Symbol and TypedSymbol `Symbol` is interned and integer-backed. ```csharp Symbol s0 = Symbol.Create("name"); Symbol s1 = "name"; // implicit conversion Symbol s2 = Symbol.Create(Guid.NewGuid()); Symbol empty = Symbol.Empty; Symbol neg = -s0; // negative key variant ``` Important members: - `Id` - `IsEmpty` / `IsNotEmpty` - `IsPositive` / `IsNegative` - `ToGuid()` `TypedSymbol` provides compile-time value type pairing for typed dictionary access. ## Dict Family Main types in `Symbol/Dict_auto.cs`: - `Dict` - `DictSet` - `SymbolDict` - `SymbolSet` Common helpers: - `GetOrCreate(...)` - `TryRemove(...)` - `ValuesWithKey(...)` `SymbolDict` also has typed overloads: - `Add(TypedSymbol key, TType value)` - `Get(TypedSymbol key)` - `TryGetValue(TypedSymbol key, out TType value)` ## LruCache `LruCache` is synchronized and capacity-driven. Constructors: ```csharp new LruCache(capacity); new LruCache(capacity, sizeFun, readFun, deleteAct); ``` Key operations: - indexer `cache[key]` (auto-load with `readFun`) - `GetOrAdd(...)` - `TryRemove(...)` - `Remove(...)` - mutable `Capacity` (can trigger eviction) ## ConcurrentHashSet Defined in namespace `System.Collections.Concurrent`. Core operations: ```csharp set.Add(item); set.Remove(item); // no TryRemove API on this type set.Contains(item); set.Clear(); set.UnionWith(other); ``` ## SingleEntryDict `SingleEntryDict` exists in `Symbol/Dicts.cs` and is optimized for one optional key/value entry. It supports normal `IDict` lookup, removal, and re-adding the configured key after removal. ## Source Anchors - `src/Aardvark.Base/Symbol/Symbol.cs` - `src/Aardvark.Base/Symbol/Dict_auto.cs` - `src/Aardvark.Base/Symbol/Dicts.cs` - `src/Aardvark.Base/Symbol/IDict.cs` - `src/Aardvark.Base/AlgoDat/LruCache.cs` - `src/Aardvark.Base/AlgoDat/ConcurrentHashSet.cs` ================================================ FILE: ai/DOC_ACCURACY_AUDIT.md ================================================ # AI Docs Accuracy Audit Audit baseline for coding-agent docs in this repository. ## Last Audit - Date: 2026-02-26 - Scope: `AGENTS.md`, `ai/*.md`, `docs/*.md`, selected source anchors ## Verified Corrections in This Audit 1. Added task-split docs for semantic depth: - `ai/SEMANTICS_LINEAR_ALGEBRA.md` - `ai/SEMANTICS_GEOMETRY_CORE.md` 2. Added symbol-first discovery index: - `ai/SYMBOL_INDEX.md` 3. Rewrote inaccurate AI topic docs: - `ai/UTILITIES.md` - `ai/COLLECTIONS.md` - `ai/ALGORITHMS.md` - `ai/PIXIMAGE.md` - `ai/TENSORS.md` 4. Corrected user-facing docs that had stale command guidance: - `docs/CONTRIBUTING.md` - `docs/INTEROP.md` - `docs/TROUBLESHOOTING.md` 5. Added drift tooling: - `tools/DocsChecker/*` - `check-docs.sh` - `check-docs.cmd` - `.github/workflows/docs-check.yml` ## Known High-Risk Drift Areas - Generated code APIs (`*_auto.cs`, `*_auto.fs`) - Cross-language dependencies between C# and F# projects - Matrix/transform semantics and interop assumptions - Pix/tensor APIs where historical examples often reference removed overloads ## Maintenance Rule If a PR changes public API behavior or key semantics: 1. Update the relevant doc in `ai/` or `docs/`. 2. Run docs checker (`./check-docs.sh` or `.\check-docs.cmd`). 3. Keep source anchors in sync with actual file locations/symbol names. ## Rules Touched In This Iteration Docs checker hardening added: 1. Expanded required file coverage to additional AI topic docs. 2. Expanded forbidden/required pattern checks for common stale examples. 3. Expanded source-anchor coverage across primitives, tensors/pix, telemetry/random, collections, and algorithms. 4. Added fixture-based checker tests (`tools/DocsChecker.Tests`). 5. Enabled Linux + Windows hard-fail docs-check workflow matrix. ================================================ FILE: ai/FSHARP_INTEROP.md ================================================ # Aardvark.Base F# Interop Reference AI-targeted reference for using Aardvark.Base types from F#. Covers modules, extension functions, and idiomatic patterns. --- ## Namespace and Module Structure ### Common Open Statements ```fsharp open Aardvark.Base // Core types: V3d, M44d, Box3d, etc. open Aardvark.Base.Sorting // Sorting extension methods ``` ### Module Hierarchy | Namespace | Contents | |-----------|----------| | `Aardvark.Base` | All primitive types + F# modules | | `Aardvark.Base.Sorting` | Array sorting extensions | --- ## Vec Module Functional wrappers for vector operations. Works with any vector type (V2d, V3f, V4i, etc.). ```fsharp open Aardvark.Base // Dot product let d = Vec.dot V3d.XAxis V3d.YAxis // 0.0 // Cross product (3D only) let c = Vec.cross V3d.XAxis V3d.YAxis // V3d.ZAxis // Length and normalization let len = Vec.length V3d.One // sqrt(3) let lenSq = Vec.lengthSquared V3d.One // 3.0 let unit = Vec.normalize V3d.One // unit vector // Distance let dist = Vec.distance V3d.Zero V3d.One let distSq = Vec.distanceSquared V3d.Zero V3d.One // Swizzles let x = Vec.x v3d let xy = Vec.xy v3d // V2d let xyz = Vec.xyz v4d // V3d // Reflection/refraction let refl = Vec.reflect normal incident let refr = Vec.refract eta normal incident // Component-wise comparisons Vec.anySmaller V3d.One V3d.Zero // false Vec.allGreater V3d.One V3d.Zero // true Vec.anyEqual v1 v2 Vec.allDifferent v1 v2 ``` --- ## Mat Module Functional wrappers for matrix operations. ```fsharp open Aardvark.Base // Transpose, determinant, inverse let mt = Mat.transpose M33d.Identity let d = Mat.det M22d.Identity let inv = Mat.inverse M33d.Identity // Transform vectors let v4 = Mat.transform M44d.Identity V4d.One let pos = Mat.transformPos M44d.Identity V3d.One // w=1 let dir = Mat.transformDir M44d.Identity V3d.One // w=0 let proj = Mat.transformPosProj M44d.Identity V3d.One // with perspective divide // Component-wise comparisons Mat.anyEqual m1 m2 Mat.allSmaller m1 m2 ``` --- ## Trafo Module Functional wrappers for transformation types. ```fsharp open Aardvark.Base let t = Trafo3d.Translation(V3d(1, 2, 3)) // Access matrices let fwd = Trafo.forward t // M44d forward matrix let bwd = Trafo.backward t // M44d inverse matrix // Invert let inv = Trafo.inverse t // Compose and transform let pos = V3d.Zero |> Mat.transformPos (t |> Trafo.forward) ``` --- ## Lens System Functional lenses for immutable state updates. Used extensively with Adaptify-generated models. ### Lens Type ```fsharp type Lens<'s, 'a> = abstract Get : 's -> 'a abstract Set : 's * 'a -> 's abstract Update : 's * ('a -> 'a) -> 's ``` ### Operators | Operator | Signature | Description | |----------|-----------|-------------| | `\|.` | `Lens<'s,'a> -> Lens<'a,'b> -> Lens<'s,'b>` | Compose lenses | | `\|?` | `Lens<'s, Option<'a>> -> 'a -> Lens<'s,'a>` | Default for None | ### Usage ```fsharp open Aardvark.Base // Adaptify generates lenses like Model.position_ // Compose with |. operator let nestedLens = Model.inner_ |. Inner.value_ // Get value let v = nestedLens.Get model // Set value let model' = nestedLens.Set(model, newValue) // Update value let model'' = nestedLens.Update(model, fun v -> v + 1) ``` ### Predefined Lenses ```fsharp // Set membership lens Set.Lens.contains "item" // Lens, bool> // Map item lens Map.Lens.item "key" // Lens, Option<'v>> // List item lens List.Lens.item 0 // Lens, Option<'a>> ``` --- ## Color Module (ColorBrewer) Color scheme generation for data visualization. ```fsharp open Aardvark.Base // Get sequential color scheme let colors = ColorBrewer.getColors ColorBrewer.SchemeType.Sequential "Blues" 5 // Available scheme types ColorBrewer.SchemeType.Sequential // Light to dark ColorBrewer.SchemeType.Diverging // Two-ended ColorBrewer.SchemeType.Qualitative // Distinct categories ``` --- ## Interop Modules F# extensions for .NET collections. ### Dictionary Extensions ```fsharp open Aardvark.Base let dict = System.Collections.Generic.Dictionary() // F#-style access dict.["key"] <- 42 let v = dict.["key"] // TryFind returns Option match dict.TryFind "key" with | Some v -> ... | None -> ... ``` ### HashSet Extensions ```fsharp open Aardvark.Base let set = System.Collections.Generic.HashSet() // Set operations return new sets let union = set.Union otherSet let inter = set.Intersect otherSet ``` --- ## Memory and Native Utilities ### MicroTime (High-Resolution Timing) ```fsharp open Aardvark.Base let start = MicroTime.Now // ... work ... let elapsed = MicroTime.Now - start printfn "Elapsed: %A" elapsed ``` ### Mem (Memory Sizes) ```fsharp open Aardvark.Base let size = Mem.mebibytes 512L printfn "%d bytes" size.Bytes ``` --- ## Common Patterns ### Pipeline with Transformations ```fsharp let result = V3d.Zero |> Mat.transformPos (Trafo3d.Translation(V3d.One) |> Trafo.forward) |> Mat.transformDir (Trafo3d.RotationZ(Constant.Pi) |> Trafo.forward) ``` ### Lens-Based State Updates ```fsharp // Update nested model immutably let model' = model |> (Model.camera_ |. Camera.position_).Set(V3d(0, 0, 10)) |> (Model.camera_ |. Camera.target_).Set(V3d.Zero) ``` ### Vector Comparisons in Conditionals ```fsharp if Vec.allSmaller point boxMax && Vec.allGreater point boxMin then // point is inside box () ``` --- ## Gotchas 1. **Module Suffix Convention**: F# modules like `Vec`, `Mat`, `Trafo` use `CompilationRepresentationFlags.ModuleSuffix` to avoid name collisions with types. Don't confuse `Vec` (module) with `V3d` (type) 2. **Inline Functions**: Most `Vec` and `Mat` functions are `inline` with SRTP constraints. This means they work on any type with matching static members, but error messages can be cryptic if types don't match 3. **Lens Composition Order**: `outer |. inner` reads left-to-right (outer first, then inner). This is opposite to function composition `>>`. Think of `|.` as "then focus on" 4. **Option Lenses**: `Map.Lens.item` returns `Lens<_, Option<_>>`. Use `|?` operator to provide a default, or handle `None` explicitly --- ## See Also - [PRIMITIVE_TYPES.md](PRIMITIVE_TYPES.md) - C# API reference for V3d, M44d, Trafo3d (same types, method syntax) - [COLLECTIONS.md](COLLECTIONS.md) - Symbol and SymbolDict (usable from F# with same API) - [ALGORITHMS.md](ALGORITHMS.md) - Graph and spatial algorithms callable from F# ================================================ FILE: ai/INCREMENTAL.md ================================================ # Incremental/Adaptive System Reactive computation with automatic dependency tracking. Values form a DAG; changes propagate lazily through dependencies. ## Architecture Built on **FSharp.Data.Adaptive** (external NuGet package). Aardvark.Base.Incremental adds: - `afun` - adaptive functions - `astate` - stateful adaptive computations - `Controller` - UI-like state with previous-value tracking - `astream` - event streams with history (experimental) - `Proc` - cancellable continuations Namespace: `FSharp.Data.Adaptive` (core types from external package) ## Core Types ### Adaptive Values | Type | Description | |------|-------------| | `aval<'a>` / `IAdaptiveValue` | Read-only adaptive value | | `cval<'a>` / `ChangeableValue` | Mutable adaptive value (source) | ```fsharp // F# let counter = cval 0 let doubled = counter |> AVal.map ((*) 2) let value = AVal.force doubled // 0 ``` ```csharp // C# var counter = new ChangeableValue(0); var doubled = counter.Map(x => x * 2); int value = doubled.GetValue(); // 0 ``` ### Adaptive Collections | Type | C# Type | Delta Type | |------|---------|------------| | `aset<'a>` | `ChangeableHashSet` | `HashSetDelta` | | `amap<'k,'v>` | `ChangeableHashMap` | `HashMapDelta` | | `alist<'a>` | `ChangeableIndexList` | `IndexListDelta` | Collections track changes via delta objects. Use readers to get incremental updates. ```csharp // C# var set = new ChangeableHashSet(new[] { 1, 2, 3 }); var filtered = set.Filter(x => x > 1); var reader = filtered.GetReader(); // Get deltas since last read var deltas = reader.GetChanges(AdaptiveToken.Top); foreach (var d in deltas) { if (d.Count > 0) Console.WriteLine($"add {d.Value}"); else Console.WriteLine($"rem {d.Value}"); } ``` ## Transactions Mutations must occur inside transactions. Changes batch until transaction ends. ```fsharp // F# transact (fun () -> counter.Value <- 1 counter.Value <- 2 // only final value propagates ) ``` ```csharp // C# using (Adaptive.Transact) { counter.Value = 1; counter.Value = 2; // only final value propagates } ``` ### AdaptiveToken Tracks evaluation context and dependencies. Use `AdaptiveToken.Top` for top-level reads. ```fsharp let value = myAVal.GetValue(AdaptiveToken.Top) ``` ```csharp var value = myAVal.GetValue(AdaptiveToken.Top); ``` ## F# Operators From `FSharp.Data.Adaptive.Operators`: | Operator | Description | Example | |----------|-------------|---------| | `%+` | Adaptive add | `a %+ b` | | `%-` | Adaptive subtract | `a %- b` | | `%*` | Adaptive multiply | `a %* b` | | `%/` | Adaptive divide | `a %/ b` | | `%&&` | Adaptive AND | `a %&& b` | | `%||` | Adaptive OR | `a %|| b` | | `%?` / `%.` | Conditional | `cond %? trueVal %. falseVal` | | `!!` | Force value | `!!aval` | | `~~` | Make constant | `~~42` | ```fsharp open FSharp.Data.Adaptive.Operators let a = cval 10 let b = cval 20 let sum = a %+ b // aval = 30 let forced = !!sum // int = 30 let const = ~~100 // aval (constant) ``` ## Adaptive Functions (afun) Functions that depend on adaptive values. Re-evaluated when dependencies change. ```fsharp type afun<'a, 'b> // IAdaptiveFunc in C# ``` ### AFun Module | Function | Description | |----------|-------------| | `AFun.create f` | Wrap pure function | | `AFun.constant v` | Always return v | | `AFun.bind f m` | Bind aval to afun | | `AFun.compose g f` | Compose: f then g | | `AFun.apply v f` | Apply afun to aval | | `AFun.run v f` | Run afun with constant input | ```fsharp // Builder syntax let myFunc = afun { let! scale = scaleAVal return fun x -> x * scale } // Composition let combined = f >>. g // f then g let combined = g <<. f // same as above ``` ### Integration ```fsharp let result : aval<'b> = AFun.apply inputAVal myFunc ``` ## Adaptive State (astate) Stateful computations that thread state through evaluation. ```fsharp type astate<'s, 'a> = { runState: afun<'s, 's * 'a> } ``` ### AState Module | Function | Description | |----------|-------------| | `AState.create v` | Return value, preserve state | | `AState.map f m` | Transform result | | `AState.bind f m` | Sequence computations | | `AState.getState` | Get current state | | `AState.putState s` | Replace state | | `AState.modifyState f` | Transform state | ```fsharp let computation = astate { let! current = AState.getState do! AState.modifyState ((+) 1) return current } ``` ### Controller Pattern Tracks previous values across evaluations. Used for UI-like delta computation. ```fsharp type Controller<'a> = astate ``` | Function | Description | |----------|-------------| | `withLast aval` | Get `(previous, current)` tuple | | `pre aval` | Get previous value | | `differentiate aval` | Get `current - previous` | ```fsharp let deltaController = controller { let! (prev, curr) = withLast positionAVal return curr - prev // movement delta } let myFunc : afun<'a, 'b> = controller.Run(deltaController) ``` ## Adaptive Streams (astream) Event streams with timestamped history. **Experimental** - namespace: `Aardvark.Base.Incremental.Experimental` ```fsharp type astream<'a> // IAdaptiveStream in C# type EventHistory<'a> = | Cancel | Faulted of Exception | History of list ``` ### IStreamReader ```fsharp type IStreamReader<'a> = inherit IDisposable inherit IAdaptiveObject abstract GetHistory : IAdaptiveObject -> EventHistory<'a> abstract SubscribeOnEvaluate : (EventHistory<'a> -> unit) -> IDisposable ``` ### EventHistory Module | Function | Description | |----------|-------------| | `EventHistory.empty` | Empty history | | `EventHistory.map f h` | Transform events | | `EventHistory.choose f h` | Filter/transform | | `EventHistory.filter f h` | Filter events | | `EventHistory.union l r` | Merge histories | | `EventHistory.concat hs` | Concatenate list | ## Proc (Cancellable Continuations) Continuation-based async with cancellation support. ```fsharp type Proc<'a, 'r> type ProcResult<'a> = | Value of 'a | Cancelled | Faulted of exn ``` ### Creating Procs | Method | Description | |--------|-------------| | `Proc.Create v` | Immediate value | | `Proc.Await task` | Await Task | | `Proc.Await async` | Await Async | | `Proc.Await sem` | Await SemaphoreSlim | | `Proc.Sleep ms` | Delay | ### Running Procs | Method | Description | |--------|-------------| | `Proc.RunSynchronously(p, ?ct)` | Block until complete | | `Proc.StartAsTask(p, ?ct)` | Return Task | | `Proc.Start(p, ?ct)` | Fire and forget | ### Builder Syntax ```fsharp let download url = proc { let! response = httpClient.GetAsync(url) let! content = response.Content.ReadAsStringAsync() return content } // Run with cancellation use cts = new CancellationTokenSource() let result = Proc.RunSynchronously(download "http://...", cts.Token) match result with | Value content -> printfn "Got: %s" content | Cancelled -> printfn "Cancelled" | Faulted e -> printfn "Error: %A" e ``` ## ChangeTracker Detect value changes with memoization. Used internally by afun/astate. ```fsharp // Default equality let hasChanged = ChangeTracker.track if hasChanged newValue then // value changed since last call // Custom equality let hasChanged = ChangeTracker.trackCustom (Some myEqualityFn) ``` ## Common Patterns ### Reactive Collection Processing ```csharp var items = new ChangeableHashSet(); var processed = items .Filter(x => x.IsActive) .Map(x => ProcessItem(x)); var reader = processed.GetReader(); // On each frame/update: var changes = reader.GetChanges(AdaptiveToken.Top); ApplyChanges(changes); ``` ### Nested Collections (SelectMany) ```csharp var outer = new ChangeableHashSet>(); var flattened = outer.SelectMany(x => x); // flattened updates when outer or any inner set changes ``` ### Constant Optimization ```fsharp // Check if value is constant (never changes) if myAVal.IsConstant then // Can cache result permanently ``` ## Gotchas 1. **Always use transactions** - mutations outside `transact`/`Adaptive.Transact` throw 2. **Force outside transactions** - calling `GetValue`/`AVal.force` inside transact can cause reentrancy issues 3. **Dispose readers** - `IStreamReader` and collection readers hold references; dispose when done 4. **astream is experimental** - namespace is `Aardvark.Base.Incremental.Experimental`, API may change 5. **Proc vs Async** - Proc is simpler continuation-based; use for UI/rendering pipelines, Async for I/O 6. **Controller state** - `ControllerState` tracks pulled values between evaluations; initialize via `controller.Run` ## See Also - [FSHARP_INTEROP.md](FSHARP_INTEROP.md) - F# modules and functional patterns - FSharp.Data.Adaptive documentation: https://fsprojects.github.io/FSharp.Data.Adaptive/ ================================================ FILE: ai/PIXIMAGE.md ================================================ # Aardvark.Base Pix/Image Reference Source-verified orientation for `PixImage`, `PixVolume`, and related types. ## Core Types - `PixImage` / `PixImage` - `PixVolume` / `PixVolume` - `PixCube` - `PixImageMipMap` - `PixFormat` - `PixFileFormat` - `PixProcessorCaps` ## Loading and Info Static load methods are on non-generic `PixImage`: ```csharp PixImage img = PixImage.Load("a.png"); PixImage img2 = PixImage.Load(stream); PixImage raw = PixImage.LoadRaw("a.png"); PixImageInfo info = PixImage.GetInfoFromFile("a.png"); ``` Typed load is via constructor: ```csharp var typed = new PixImage("a.png"); ``` No static `PixImage.Load(...)` API exists. ## Saving ```csharp img.Save("out.png"); img.Save("out.jpg", new PixJpegSaveParams(90)); img.Save(stream, PixFileFormat.Png); img.SaveAsJpeg("out.jpg", 90); img.SaveAsPng("out.png", 6); ``` ## Processing and Conversion Common `PixImage` methods: - `Resized(...)` - `Scaled(...)` - `Rotated(...)` - `SubImage(...)` (view on shared storage) - `ToPixImage()` - `ToFormat(Col.Format)` - `ToImageLayout()` - `GetChannel(long)` / `GetChannel(Col.Channel)` `SubImage(...)` returns a view; edits affect shared data. ## Loaders and Processors Loader hooks: ```csharp PixImage.SetLoader(loader, priority); PixImage.AddLoader(loader); ``` Processor lookup: ```csharp var p = PixImage.GetProcessors(PixProcessorCaps.Scale); ``` `PixProcessorCaps` values: - `None` - `Scale` - `Rotate` - `Remap` - `All` ## PixFormat and File Formats `PixFormat` is defined in `Aardvark.Base` (`Color.cs`) as `(Type, Col.Format)`. Common predefined values: - `PixFormat.ByteGray` - `PixFormat.ByteRGB` - `PixFormat.ByteRGBA` - `PixFormat.FloatGray` - `PixFormat.FloatRGB` `PixFileFormat` enum is in `PixImage.cs` and contains formats such as `Png`, `Jpeg`, `Bmp`, `Tiff`, `Exr`, `Webp`, and others. ## Mipmaps and Cubemaps `PixImageMipMap`: - `Load(string|Stream, IPixLoader?)` - `Create(baseImage, interpolation, maxCount, powerOfTwo)` - `LevelCount` `PixCube`: - six `PixImageMipMap` faces addressed by `CubeSide` ## Source Anchors - `src/Aardvark.Base.Tensors.CSharp/PixImage/PixImage.cs` - `src/Aardvark.Base.Tensors.CSharp/PixImage/PixVolume.cs` - `src/Aardvark.Base.Tensors.CSharp/PixImage/PixCube.cs` - `src/Aardvark.Base.Tensors.CSharp/PixImage/PixImageMipMap.cs` - `src/Aardvark.Base.Tensors.CSharp/PixImage/PixProcessor.cs` - `src/Aardvark.Base/Math/Colors/Color.cs` ================================================ FILE: ai/PRIMITIVE_TYPES.md ================================================ # Aardvark.Base Primitive Types Reference Fast orientation for core math and geometry types in `Aardvark.Base`. Use this with: - `SEMANTICS_LINEAR_ALGEBRA.md` for matrix/vector layout and interop details - `SEMANTICS_GEOMETRY_CORE.md` for geometry conventions and transform semantics ## Naming Convention Pattern: `{TypeName}{Dimension}{Suffix}` | Suffix | Meaning | |--------|---------| | `i` | `int` | | `l` | `long` | | `f` | `float` | | `d` | `double` | | `b` | `byte` | Examples: - `V3d` = 3D vector (`double`) - `M44f` = 4x4 matrix (`float`) - `Box3d` = 3D axis-aligned box (`double`) ## Important Reality - Core vector/matrix structs are mutable value types (`struct`), not uniformly `readonly struct`. - For matrix/vector math in 3D, prefer explicit methods (`TransformPos`, `TransformDir`) over ambiguous shorthand. ## Vector Families Common families: - `V2*`, `V3*`, `V4*` - integer and floating-point variants (`i`, `l`, `f`, `d`) Typical APIs: ```csharp var a = new V3d(1, 2, 3); var b = new V3d(4, 5, 6); var dot = V3d.Dot(a, b); var cross = V3d.Cross(a, b); var dist = V3d.Distance(a, b); var unit = a.Normalized; ``` ## Matrix Families Common families: - `M22*`, `M23*`, `M33*`, `M34*`, `M44*` ### M44d Construction (Verified) ```csharp var t = M44d.Translation(new V3d(1, 2, 3)); var s = M44d.Scale(new V3d(2, 2, 2)); var r = M44d.RotationZ(0.5); var fromRows = M44d.FromRows( new V4d(1, 0, 0, 0), new V4d(0, 1, 0, 0), new V4d(0, 0, 1, 0), new V4d(0, 0, 0, 1) ); var rot = Rot3d.RotationZ(0.5); var rotAsMatrix = (M44d)rot; ``` ### M44d Operations (Verified) ```csharp var m = M44d.Translation(new V3d(1, 2, 3)); var p = m.TransformPos(new V3d(5, 6, 7)); // includes translation var d = m.TransformDir(new V3d(0, 1, 0)); // ignores translation var h = m * new V4d(5, 6, 7, 1); // valid homogeneous multiply ``` Notes: - `M44d * V4d` and `V4d * M44d` are defined. - `M44d * V3d` is not defined. - `M44d.Transform(V3d)` is not a supported API; use `TransformPos`/`TransformDir`. ## Transformation Types 3D families: - `Rot3*`, `Shift3*`, `Scale3*`, `Euclidean3*`, `Similarity3*`, `Affine3*`, `Trafo3*` Typical `Trafo3d` usage: ```csharp var trafo = Trafo3d.Translation(new V3d(1, 0, 0)) * Trafo3d.Scale(2.0); var fwd = trafo.Forward; // M44d var bwd = trafo.Backward; // M44d inverse var p = trafo.TransformPos(new V3d(1, 2, 3)); ``` ## Geometry Core Families Common primitives: - `Box2*`, `Box3*` - `Ray2*`, `Ray3*` - `Plane2*`, `Plane3*` - `Sphere3*`, `Circle2*`, `Circle3*` - `Triangle2*`, `Triangle3*` - `Hull2*`, `Hull3*` Typical APIs: ```csharp var box = new Box3d(V3d.Zero, V3d.One); var ray = new Ray3d(V3d.Zero, V3d.XAxis); var contains = box.Contains(new V3d(0.5, 0.5, 0.5)); var hit = ray.Hits(box, out double t); ``` ## Gotchas 1. Matrix convention details (layout, multiplication side, interop) are critical for performance and correctness: use `SEMANTICS_LINEAR_ALGEBRA.md`. 2. `TransformPos` vs `TransformDir` matters for translation handling. 3. Subtle precision loss exists when converting from `d` variants to `f` variants. ## Source Anchors - `src/Aardvark.Base/Math/Vectors/Vector_auto.cs` (`V3d`) - `src/Aardvark.Base/Math/Trafos/Matrix_auto.cs` (`M44d`, transforms, operators) - `src/Aardvark.Base/Math/Trafos/Rot3_auto.cs` (`Rot3d` to `M44d` cast) - `src/Aardvark.Base/Math/RangesBoxes/Box_auto.cs` (`Box3d`) - `src/Aardvark.Base/Geometry/Types/Ray/Ray3_auto.cs` (`Ray3d` hit methods) ================================================ FILE: ai/README.md ================================================ # Aardvark.Base AI Reference Task-first docs for coding agents. Goal: open one focused document, not the whole `ai/` folder. ## Fast Path 1. Find symbols in [SYMBOL_INDEX.md](SYMBOL_INDEX.md). 2. Open one task doc from the table below. 3. Verify critical names in source with `rg`. ## Task Docs | Need | Read | |------|------| | Primitive math and geometry types | [PRIMITIVE_TYPES.md](PRIMITIVE_TYPES.md) | | Matrix/vector layout and interop semantics | [SEMANTICS_LINEAR_ALGEBRA.md](SEMANTICS_LINEAR_ALGEBRA.md) | | Geometry and transform semantics | [SEMANTICS_GEOMETRY_CORE.md](SEMANTICS_GEOMETRY_CORE.md) | | Images, volumes, loaders, processors | [PIXIMAGE.md](PIXIMAGE.md) | | Tensor containers, views, strides | [TENSORS.md](TENSORS.md) | | Graph/spatial/numeric algorithms | [ALGORITHMS.md](ALGORITHMS.md) | | Symbols, dicts, caches, concurrent set | [COLLECTIONS.md](COLLECTIONS.md) | | Logging, telemetry, random, geodesy | [UTILITIES.md](UTILITIES.md) | | Serialization/coder APIs | [SERIALIZATION.md](SERIALIZATION.md) | | F# wrappers and idioms | [FSHARP_INTEROP.md](FSHARP_INTEROP.md) | | Incremental/adaptive system | [INCREMENTAL.md](INCREMENTAL.md) | ## Meta Docs | Need | Read | |------|------| | Symbol-to-doc lookup | [SYMBOL_INDEX.md](SYMBOL_INDEX.md) | | Drift and accuracy audit log | [DOC_ACCURACY_AUDIT.md](DOC_ACCURACY_AUDIT.md) | | AI-friendliness recipe for other repos | [RECIPE_AI_FRIENDLINESS.md](RECIPE_AI_FRIENDLINESS.md) | ## Accuracy Contract - Docs are orientation, source is truth. - If a method/type matters, verify with `rg` before coding. - If docs and code differ, fix docs in the same change. - Prefer examples that reflect current scripts and project targets. --- Last verified against repository state: 2026-02-26 ================================================ FILE: ai/RECIPE_AI_FRIENDLINESS.md ================================================ # Recipe: Making a Repository AI-Friendly Step-by-step guide for Claude instances to add AI-optimized documentation to similar codebases. --- ## Overview This recipe transforms a typical .NET/F# repository into one that AI coding assistants can navigate and modify efficiently. The pattern was extracted from commits that added ~3300 lines of targeted documentation to Aardvark.Base. **Time estimate**: 2-4 hours for a medium codebase (50-200 source files). --- ## Step 1: Add `.editorconfig` Consistent formatting reduces diff noise and prevents AI-generated code from introducing style conflicts. ```ini root = true [*] charset = utf-8 insert_final_newline = true trim_trailing_whitespace = true end_of_line = lf [*.{cs,fs,fsx,fsi}] indent_style = space indent_size = 4 [*.{csproj,fsproj,props,targets,sln}] indent_style = space indent_size = 2 [*.{json,yml,yaml,xml}] indent_style = space indent_size = 2 [*.md] trim_trailing_whitespace = false [*.sh] end_of_line = lf [*.cmd] end_of_line = crlf ``` --- ## Step 2: Add `.gitattributes` Cross-platform line endings prevent spurious diffs when AI generates code on different OSes. ``` * text=auto # Source code *.cs text eol=lf *.fs text eol=lf *.fsx text eol=lf *.fsi text eol=lf # Build files *.csproj text eol=lf *.fsproj text eol=lf *.sln text eol=lf *.props text eol=lf *.targets text eol=lf # Config *.json text eol=lf *.yml text eol=lf *.yaml text eol=lf # Docs *.md text eol=lf *.txt text eol=lf # Scripts *.sh text eol=lf *.cmd text eol=crlf *.bat text eol=crlf # Binary *.png binary *.jpg binary *.dll binary *.exe binary *.pdb binary *.nupkg binary *.zip binary ``` --- ## Step 3: Create `AGENTS.md` at Repo Root This is the entry point for AI agents. Include: 1. **Link to detailed docs** (if any) 2. **Supported commands table** (build, test, restore) 3. **Dependency management rules** (npm, pip, NuGet, Paket, etc.) 4. **File ownership by change type** 5. **Framework/SDK constraints** 6. **Common failure modes with fixes** 7. **Project structure overview** 8. **Tips for AI agents** 9. **Release notes placement rule** when the repo keeps unreleased notes above versioned sections ### Template ```markdown # AI Agent Guide This repository has AI-targeted reference documentation in `ai/README.md`. ## Supported Commands | Task | Command | Notes | |------|---------|-------| | Restore | `./build.sh restore` or `.\build.cmd restore` | Restores tools + packages | | Build | `./build.sh` or `.\build.cmd` | Builds entire solution | | Test | `./test.sh` or `.\test.cmd` | Runs the real test projects; excludes benchmark projects | | Build one | `dotnet build src/Foo/Foo.csproj` | Single project | ## Dependency Management | Task | Command | |------|---------| | Add package | `` | | Update | `` | **Rules:** - ## File Ownership by Change Type | Change Type | Files to Modify | Files to NOT Touch | |-------------|-----------------|-------------------| | Add feature | `src/**/*.cs` | `*_auto.cs` (generated) | | Add test | `tests/**/*Tests.cs` | Source files, other tests | | Fix bug | Relevant source + test | Unrelated modules | ## Framework & SDK Rules - **.NET Version**: X.Y (see `global.json`) - **Target Frameworks**: netstandard2.0, net8.0 - **LangVersion**: 12 ## Common Failure Modes & Fixes | Symptom | Cause | Fix | |---------|-------|-----| | Package restore fails | Outdated lock file | `` | | SDK not found | Wrong .NET version | Install .NET X.Y | ## Project Structure ``` src/ ├── Core/ # Main library ├── Extensions/ # Optional modules └── Tests/ # Test projects ``` ## Tips for AI Agents 1. Read only what you need; each doc is self-contained 2. Check the "Gotchas" section before writing code 3. If the repo has `RELEASE_NOTES.md`, say where unreleased notes belong. ### Release Notes Placement If the repository keeps unreleased notes separately from numbered releases: - tell agents whether tooling reads the first `### ` section as the current version - if plain pending notes above the first version are allowed, say that explicitly - explicitly forbid adding a markdown heading such as `### Preliminary` above that first version section when tooling would treat it as structural - explicitly forbid adding new notes inside the previous released version block - if pending notes belong above the first version, say that directly instead of telling agents to write into the previous released block 3. Run tests after changes 4. Use provided build scripts ``` --- ## Step 4: Create `ai/README.md` Index This is a compact index so the AI knows which doc to read for each task. ### Template ```markdown # AI Reference Index for AI coding assistants. Read only the doc you need. ## By Task | Task | Document | Size | |------|----------|------| | Core types, APIs | CORE.md | ~10 KB | | Data structures | DATA_STRUCTURES.md | ~8 KB | | Algorithms | ALGORITHMS.md | ~8 KB | | Serialization | SERIALIZATION.md | ~7 KB | | Configuration | CONFIG.md | ~5 KB | ## By Type - `FooClass`, `BarStruct` → CORE.md - `MyCollection` → DATA_STRUCTURES.md ``` **Key rules:** - Include approximate file sizes (AI can estimate reading cost) - Group by task AND by type name - Keep it under 50 lines --- ## Step 5: Create Topic-Specific Reference Docs in `ai/` Each doc covers one topic. Target 6-12 KB per doc (500-1000 lines). ### Document Structure ```markdown # Reference AI-targeted reference for . --- ## ### | Type | Properties | Notes | |------|------------|-------| | Foo | Bar, Baz | Description | ### Usage ``` // Example code ``` --- ## ... --- ## Usage Patterns ### Pattern Name ``` // Complete working example ``` --- ## Gotchas 1. **Gotcha Title**: Explanation of the trap and how to avoid it 2. **Another Gotcha**: ... --- ## See Also - [OTHER_DOC.md](OTHER_DOC.md) - Why this is related ``` ### Formatting Rules 1. **Tables over prose** - Types, properties, commands in tables 2. **Code examples** - Complete, copy-paste-ready 3. **Gotchas section** - Common mistakes (3-5 items) 4. **See Also** - Cross-references to related docs 5. **No fluff** - Skip introductions, motivation, history ### Step 5b: F# Considerations If your repo has F# code alongside C#: 1. **Document `open` statements** - F# uses `open Namespace` instead of `using`. List common opens and what they provide 2. **Cover F# modules** - F# modules (like `Vec`, `Mat`) wrap C# static methods. Document these separately from the C# API 3. **Note function conventions**: - F# prefers curried functions: `transformPos matrix point` - C# uses tupled: `TransformPos(matrix, point)` - Document both forms if available 4. **Dual-language examples** - For key operations, show both: ```csharp // C# var result = V3d.Cross(a, b); ``` ```fsharp // F# let result = Vec.cross a b ``` 5. **Document lenses** - If using Adaptify or similar, document the lens system and composition operators --- ## Step 6: Add `.claude/CLAUDE.md` Pointer Minimal file that tells Claude Code where to find docs. ```markdown # AI Documentation Read `ai/README.md` for indexed reference docs. ``` --- ## Step 7: Document Complex Build Systems If your repo has code generation, custom build steps, or unusual tooling, create a README in that component's directory. ### Template for Code Generators ```markdown # ## Purpose ## How to Run ```bash ./generate.sh # Unix .\generate.cmd # Windows ``` ## When to Run Run after modifying any `*_template.*` file. ## Input Files `*_template.cs` files containing: - ## Output Files `*_auto.cs` files that are: - AUTO GENERATED - DO NOT EDIT - ## Generated Files Summary | Template | Output | Purpose | |----------|--------|---------| | Foo_template.cs | Foo_auto.cs | Generates type variants | ``` --- ## Step 8: Improve CI Configuration AI agents benefit from CI that: - Uses caching (faster feedback loop) - Sets `fail-fast: false` (see all failures, not just first) - Has correct path-ignore globs ### GitHub Actions Example ```yaml name: Build on: push: paths-ignore: - 'README.md' - 'docs/**' pull_request: paths-ignore: - 'README.md' - 'docs/**' jobs: build: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] steps: - uses: actions/checkout@v4 - name: Setup .NET uses: actions/setup-dotnet@v4 with: global-json-file: global.json - name: Cache packages uses: actions/cache@v4 with: path: | ~/.nuget/packages key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }} - name: Build run: ``` --- ## Checklist Before considering the repository AI-friendly, verify: - [ ] `.editorconfig` exists with language-specific rules - [ ] `.gitattributes` handles line endings and binary files - [ ] `AGENTS.md` at root with commands, rules, structure - [ ] `ai/README.md` index with task-based lookup - [ ] `ai/*.md` docs for each major topic (3-10 docs typical) - [ ] `.claude/CLAUDE.md` points to ai/README.md - [ ] Build system READMEs for code generators or unusual tooling - [ ] CI uses caching and fail-fast: false - [ ] All `ai/*.md` docs have Gotchas and See Also sections - [ ] All `ai/*.md` docs are 6-12 KB (not too long to read, not too short to be useful) --- ## Anti-Patterns to Avoid 1. **Walls of prose** - AI skims; tables and code are better 2. **Incomplete examples** - Every code block should work if pasted 3. **Missing gotchas** - The mistakes AI makes repeatedly belong here 4. **Giant monolithic docs** - Split by topic; 6-12 KB per file 5. **Stale docs** - Update when behavior changes; delete obsolete content 6. **Documenting the obvious** - Skip "what is a vector"; focus on API specifics 7. **Duplicating source comments** - Reference docs should add value beyond inline docs --- ## Maintenance When making changes to the codebase: 1. **New types/APIs**: Update relevant `ai/*.md` doc 2. **New failure mode**: Add to AGENTS.md failure table 3. **New build step**: Add to AGENTS.md commands table 4. **Breaking change**: Update Gotchas section 5. **Removing feature**: Delete from docs (don't leave stale references) --- *Last updated: December 2025* ================================================ FILE: ai/SEMANTICS_GEOMETRY_CORE.md ================================================ # Aardvark.Base Geometry Semantics Use this for transform correctness questions in geometry code. ## Transform Semantics For `M44d` and `Trafo3d`: - `TransformPos` treats input as point (`w=1`) - `TransformDir` treats input as direction (`w=0`) - `TransformPosProj` performs perspective division Use the right method for normals/vectors/points. Most correctness bugs come from mixing them. ## Trafo3d Forward/Backward `Trafo3d` stores both matrices: - `Forward`: model -> transformed space - `Backward`: inverse transform `InvTransformPos` and related methods use `Backward`. ## Trafo3d Multiplication Order `Trafo3d` composition is backward relative to raw matrix multiplication for natural postfix usage. ```csharp var combined = t0 * t1; // not equivalent to new Trafo3d(t0.Forward * t1.Forward, ...) ``` For ambiguity-sensitive code, inspect resulting `Forward` explicitly. ## Matrix and Geometry Interop When crossing APIs that use transposed conventions, use: - `m.Transposed` - `m.TransposedTransformPos(...)` - `m.TransposedTransformDir(...)` Do not assume identical handedness or memory/algebra conventions across systems. ## Geodesy Units (Geo) `Geo.XyzFromLonLatHeight` and `Geo.LonLatHeightFromXyz` use: - longitude/latitude in degrees - height in meters - ellipsoid from `GeoEllipsoid` (`Wgs84`, `Grs80`, `Bessel1841`, ...) ## Source Anchors - `src/Aardvark.Base/Math/Trafos/Matrix_auto.cs` (`TransformPos`, `TransformDir`, transposed variants) - `src/Aardvark.Base/Math/Trafos/Trafo_auto.cs` (`Trafo3d`, `Forward`, `Backward`, operator `*`) - `src/Aardvark.Base/Geodesy/GeoConversion.cs` (`XyzFromLonLatHeight`, `LonLatHeightFromXyz`) - `src/Aardvark.Base/Geodesy/GeoConsts.cs` (`GeoEllipsoid`) ================================================ FILE: ai/SEMANTICS_LINEAR_ALGEBRA.md ================================================ # Aardvark.Base Linear Algebra Semantics Use this when matrix/vector layout and interop correctness matter. ## M44d Convention (Verified) `M44d` fields are named by row/column: `Mrc`. - `M00..M03` = row 0 - `M10..M13` = row 1 - `M20..M23` = row 2 - `M30..M33` = row 3 `double[]` export order is row-major: ```csharp var a = (double[])m; // a = [M00, M01, M02, M03, M10, ... , M33] ``` ## Multiplication Semantics `M44d` supports both: - `m * v` where `v` is a column vector - `v * m` where `v` is a row vector Column-vector form (`m * v`) is the canonical transform style for `TransformPos`/`TransformDir`. ```csharp V4d c = m * v; V4d r = v * m; ``` ## Point vs Direction For `M44d`: - `TransformDir(v)` ignores translation (`w = 0`) - `TransformPos(p)` applies translation (`w = 1`) - translation lives in `M03/M13/M23` ## Direct Answer: Row-Major or Column-Major? Both concerns exist, but they are different: - In-memory field/array layout is row-major. - Algebra supports column-vector and row-vector multiplication operators. If your external system is column-major memory, conversion is required at the boundary. ## Efficient Layout Conversion ### Row-major array -> M44d ```csharp var m = new M44d(rowMajor16); ``` ### Column-major array -> M44d ```csharp var m = M44d.FromCols( new V4d(cm[0], cm[1], cm[2], cm[3]), new V4d(cm[4], cm[5], cm[6], cm[7]), new V4d(cm[8], cm[9], cm[10], cm[11]), new V4d(cm[12], cm[13], cm[14], cm[15]) ); ``` ### M44d -> column-major array ```csharp var cm = new[] { m.M00, m.M10, m.M20, m.M30, m.M01, m.M11, m.M21, m.M31, m.M02, m.M12, m.M22, m.M32, m.M03, m.M13, m.M23, m.M33 }; ``` ### Opposite algebra convention If the other side interprets transforms with opposite multiplication side, transpose at the boundary: ```csharp var boundaryMatrix = m.Transposed; ``` For one-off transforms, use `TransposedTransformDir` / `TransposedTransformPos` to avoid manual transpose logic. ## Trafo3d Composition Note `Trafo3d` multiplication order is intentionally reversed relative to raw `M44d` multiplication: ```csharp var t = t0 * t1; // forward = t1.Forward * t0.Forward ``` This is documented in `Trafo_auto.cs` and affects composition assumptions. ## Source Anchors - `src/Aardvark.Base/Math/Trafos/Matrix_auto.cs` (`M44d`, `FromRows`, `FromCols`, `operator*`, `TransformPos`, `TransposedTransformPos`) - `src/Aardvark.Base/Math/Trafos/Trafo_auto.cs` (`Trafo3d` operator `*` composition semantics) ================================================ FILE: ai/SERIALIZATION.md ================================================ # Aardvark.Base Serialization Reference AI-targeted reference for the ICoder serialization system - bidirectional read/write abstraction. --- ## ICoder Pattern The ICoder interface provides a unified API for both reading and writing. The same code handles both directions. ```csharp public partial interface ICoder { bool IsReading { get; } bool IsWriting { get; } int CoderVersion { get; } int MemoryVersion { get; } int StreamVersion { get; } void Code(ref object obj); void CodeT(ref T obj); // ... type-specific methods } ``` ### Key Insight Same method signature for read and write: - **Writing**: reads value from `ref` parameter, writes to stream - **Reading**: reads from stream, assigns to `ref` parameter ```csharp // This code works for BOTH reading and writing public void Serialize(ICoder coder) { coder.CodeInt32(ref _x); coder.CodeString(ref _name); coder.CodeV3d(ref _position); } ``` --- ## Implementations ### BinaryWritingCoder Writes objects to binary stream. ```csharp using (var coder = new BinaryWritingCoder(stream)) { object data = myObject; coder.Code(ref data); } ``` ### BinaryReadingCoder Reads objects from binary stream. ```csharp using (var coder = new BinaryReadingCoder(stream)) { object data = null; coder.Code(ref data); var myObject = (MyType)data; } ``` --- ## Type-Specific Methods ### Primitive Types ```csharp void CodeBool(ref bool value); void CodeByte(ref byte value); void CodeSByte(ref sbyte value); void CodeInt16(ref short value); void CodeUInt16(ref ushort value); void CodeInt32(ref int value); void CodeUInt32(ref uint value); void CodeInt64(ref long value); void CodeUInt64(ref ulong value); void CodeFloat(ref float value); void CodeDouble(ref double value); void CodeChar(ref char value); void CodeString(ref string value); void CodeGuid(ref Guid value); void CodeType(ref Type value); void CodeSymbol(ref Symbol value); ``` ### Aardvark Types ```csharp // Vectors void CodeV2i(ref V2i value); void CodeV2f(ref V2f value); void CodeV2d(ref V2d value); void CodeV3i(ref V3i value); void CodeV3f(ref V3f value); void CodeV3d(ref V3d value); void CodeV4i(ref V4i value); void CodeV4f(ref V4f value); void CodeV4d(ref V4d value); // Matrices void CodeM22f(ref M22f value); void CodeM33f(ref M33f value); void CodeM44f(ref M44f value); void CodeM22d(ref M22d value); void CodeM33d(ref M33d value); void CodeM44d(ref M44d value); // Transformations void CodeTrafo2f(ref Trafo2f value); void CodeTrafo3f(ref Trafo3f value); void CodeTrafo2d(ref Trafo2d value); void CodeTrafo3d(ref Trafo3d value); // Colors void CodeC3b(ref C3b value); void CodeC4b(ref C4b value); void CodeC3f(ref C3f value); void CodeC4f(ref C4f value); // Geometric void CodeBox2i(ref Box2i value); void CodeBox3i(ref Box3i value); void CodeBox2f(ref Box2f value); void CodeBox3f(ref Box3f value); void CodeBox2d(ref Box2d value); void CodeBox3d(ref Box3d value); ``` ### Collections ```csharp void CodeT(ref T obj); void CodeTArray(ref T[] array); void CodeList_of_T_(ref List list); void CodeHashSet_of_T_(ref HashSet set); void Code(Type t, ref Array array); void Code(Type t, ref IList list); void Code(Type t, ref IDictionary dict); ``` ### Tensors ```csharp void Code(Type t, ref IArrayVector vector); void Code(Type t, ref IArrayMatrix matrix); void Code(Type t, ref IArrayVolume volume); void Code(Type t, ref IArrayTensor4 tensor4); void Code(Type t, ref IArrayTensorN tensor); ``` ### Struct Arrays ```csharp void CodeStructArray(ref T[] a) where T : struct; void CodeStructList(ref List l) where T : struct; ``` --- ## Extended Interfaces ### IReadingCoder ```csharp public interface IReadingCoder : ICoder { // Code count with creation function int CodeCount(ref T value, Func creator) where T : class; } ``` ### IWritingCoder ```csharp public interface IWritingCoder : ICoder { // Code count with counting function int CodeCount(ref T value, Func counter) where T : class; } ``` --- ## Version Handling ICoder supports versioned serialization: ```csharp coder.MemoryVersion // current in-memory format version coder.StreamVersion // version in the stream being read coder.CoderVersion // coder implementation version ``` Use for backward compatibility: ```csharp public void Serialize(ICoder coder) { coder.CodeInt32(ref _x); if (coder.StreamVersion >= 2) { coder.CodeString(ref _newField); } else if (coder.IsReading) { _newField = "default"; // provide default for old data } } ``` --- ## TypeInfo Registration Register custom types for polymorphic serialization: ```csharp coder.Add(new TypeInfo[] { new TypeInfo(typeof(MyType), "MyType", /* version */ 1), // ... }); coder.Del(typeInfoArray); // remove registration ``` --- ## Usage Patterns ### Basic Serialization ```csharp // Write using (var stream = File.Create("data.bin")) using (var coder = new BinaryWritingCoder(stream)) { var position = new V3d(1, 2, 3); var name = "test"; coder.CodeV3d(ref position); coder.CodeString(ref name); } // Read using (var stream = File.OpenRead("data.bin")) using (var coder = new BinaryReadingCoder(stream)) { var position = default(V3d); var name = default(string); coder.CodeV3d(ref position); coder.CodeString(ref name); } ``` ### Unified Read/Write Method ```csharp public class MyData { private V3d _position; private string _name; private List _values; public void Code(ICoder coder) { coder.CodeV3d(ref _position); coder.CodeString(ref _name); coder.CodeList_of_T_(ref _values); } } // Write myData.Code(writingCoder); // Read myData.Code(readingCoder); ``` ### Conditional Coding ```csharp public void Code(ICoder coder) { coder.CodeInt32(ref _count); if (coder.IsWriting && _data != null) { coder.CodeTArray(ref _data); } else if (coder.IsReading) { _data = new float[_count]; coder.CodeTArray(ref _data); } } ``` --- ## Special Methods ### Symbol Variants ```csharp // Symbol known to be from a GUID void CodeGuidSymbol(ref Symbol v); // Symbol known to be positive (has string representation) void CodePositiveSymbol(ref Symbol v); ``` ### Set Types ```csharp void CodeIntSet(ref IntSet v); void CodeSymbolSet(ref SymbolSet v); ``` ### Enum Coding ```csharp void CodeEnum(Type t, ref object value); ``` --- ## Gotchas 1. **Unidirectional Reference Pattern**: The `ref` parameter pattern is elegant but *confusing* for debugging. Read-mode passes `null` into `ref`, write-mode reads from the ref. Always verify `IsReading`/`IsWriting` in conditional logic 2. **Version Mismatch Silent Failures**: If code reads a newer format than `StreamVersion`, old fields stay at default values without warning. Use version guards explicitly; don't assume forward compatibility 3. **Polymorphic Type Registration**: Polymorphic serialization requires exact `TypeInfo` registration. Missing a subclass? It silently serializes as the base type, causing silent data loss on read --- ## See Also - [PRIMITIVE_TYPES.md](PRIMITIVE_TYPES.md) - All primitives (V3d, M44d, Trafo3d) have `CodeXxx` methods - [TENSORS.md](TENSORS.md) - N-dimensional tensors serialize via `Code(Type t, ref IArrayVolume volume)` - [PIXIMAGE.md](PIXIMAGE.md) - `PixImage` serialization for binary save/load workflows - [COLLECTIONS.md](COLLECTIONS.md) - `Symbol`, `SymbolDict`, `LruCache` serialization patterns ================================================ FILE: ai/SYMBOL_INDEX.md ================================================ # Aardvark.Base Symbol Index Quick symbol-to-doc map for incremental discovery. ## Core Math / Geometry | Symbol | Primary Doc | |--------|-------------| | `V2d`, `V3d`, `V4d` | [PRIMITIVE_TYPES.md](PRIMITIVE_TYPES.md) | | `M22d..M44d` | [PRIMITIVE_TYPES.md](PRIMITIVE_TYPES.md) | | `Rot3d`, `Trafo3d` | [PRIMITIVE_TYPES.md](PRIMITIVE_TYPES.md) | | `M44d` layout/interoperability | [SEMANTICS_LINEAR_ALGEBRA.md](SEMANTICS_LINEAR_ALGEBRA.md) | | Transform semantics (`TransformPos`, `TransformDir`) | [SEMANTICS_GEOMETRY_CORE.md](SEMANTICS_GEOMETRY_CORE.md) | | `Box3d`, `Ray3d`, `Plane3d` | [PRIMITIVE_TYPES.md](PRIMITIVE_TYPES.md) | ## Images / Tensors | Symbol | Primary Doc | |--------|-------------| | `PixImage`, `PixImage` | [PIXIMAGE.md](PIXIMAGE.md) | | `PixVolume`, `PixVolume` | [PIXIMAGE.md](PIXIMAGE.md) | | `PixCube`, `PixImageMipMap` | [PIXIMAGE.md](PIXIMAGE.md) | | `PixFormat`, `PixFileFormat`, `PixProcessorCaps` | [PIXIMAGE.md](PIXIMAGE.md) | | `Vector`, `Matrix`, `Volume`, `Tensor4` | [TENSORS.md](TENSORS.md) | | `MatrixInfo`, `VolumeInfo`, `Tensor4Info` | [TENSORS.md](TENSORS.md) | ## Algorithms / Numerics | Symbol | Primary Doc | |--------|-------------| | `ShortestPath` | [ALGORITHMS.md](ALGORITHMS.md) | | `BbTree` | [ALGORITHMS.md](ALGORITHMS.md) | | `AliasTableF`, `AliasTableD` | [ALGORITHMS.md](ALGORITHMS.md) | | `DistributionFunction` | [ALGORITHMS.md](ALGORITHMS.md) | | `Polynomial` | [ALGORITHMS.md](ALGORITHMS.md) | | `LuFactorize`, `LuSolve`, `QrFactorize` | [ALGORITHMS.md](ALGORITHMS.md) | ## Collections / Infrastructure | Symbol | Primary Doc | |--------|-------------| | `Symbol`, `TypedSymbol` | [COLLECTIONS.md](COLLECTIONS.md) | | `Dict`, `SymbolDict`, `SymbolSet` | [COLLECTIONS.md](COLLECTIONS.md) | | `LruCache` | [COLLECTIONS.md](COLLECTIONS.md) | | `ConcurrentHashSet` | [COLLECTIONS.md](COLLECTIONS.md) | | `Report` | [UTILITIES.md](UTILITIES.md) | | `Telemetry` | [UTILITIES.md](UTILITIES.md) | | `RandomSystem`, `RandomSample`, `HaltonRandomSeries` | [UTILITIES.md](UTILITIES.md) | | `Geo`, `GeoEllipsoid` | [UTILITIES.md](UTILITIES.md) | ## F# / Incremental | Symbol | Primary Doc | |--------|-------------| | `Vec`, `Mat`, `Trafo`, `Lens` | [FSHARP_INTEROP.md](FSHARP_INTEROP.md) | | `aval`, `cval`, `aset`, `amap`, `alist` | [INCREMENTAL.md](INCREMENTAL.md) | ## Verification Tip After landing on a doc, validate exact API names in source: ```bash rg "SymbolName" src ``` ================================================ FILE: ai/TENSORS.md ================================================ # Aardvark.Base Tensor Types Reference Source-verified reference for stride-based tensor containers. ## Core Model Indexing is stride-based: ``` index = Origin + x * DX + y * DY + z * DZ + ... ``` Metadata structs: - `VectorInfo` - `MatrixInfo` - `VolumeInfo` - `Tensor4Info` Data containers: - `Vector` - `Matrix` - `Volume` - `Tensor4` These are `struct` types in generated `Tensor_auto.cs`. ## Default Dense Layouts `MatrixInfo(size)` defaults to: - `DX = 1` - `DY = SX` Image layouts (`ImageTensors.cs`): - Matrix: `DX = 1`, `DY = SX` - Volume: `DZ = 1`, `DX = SZ`, `DY = SX * DX` - Tensor4: `DW = 1`, `DX = SW`, `DY = SX * DX`, `DZ = SY * DY` ## Views vs Copies Subview methods return views on shared data: - `SubMatrix(...)`, `SubMatrixWindow(...)` - `SubVolume(...)`, `SubVolumeWindow(...)` - `SubTensor4(...)`, `SubTensor4Window(...)` `Transposed` is a stride/view transform, not deep copy. Use `Copy()` or `CopyWindow()` when you need independent storage. ## Matrix Convenience Methods On `Matrix`: - `Row(y)` and `Col(x)` (return `Vector`) - `Transposed` - `SetByCoord(...)` - `Foreach...` variants for iteration ## Image Layout Helpers In `Tensors/ImageTensors.cs`: - `HasImageLayout(...)` - `CreateImageVolume(...)` - `CreateImageTensor4(...)` - `ToImage(...)` / `ToImageWindow(...)` - `CopyToImage(...)` / `CopyToImageWindow(...)` These are important for high-performance pix/tensor interoperability. ## Source Anchors - `src/Aardvark.Base.Tensors.CSharp/Tensor_auto.cs` - `src/Aardvark.Base.Tensors.CSharp/Tensors/ImageTensors.cs` ================================================ FILE: ai/UTILITIES.md ================================================ # Aardvark.Base Utilities Reference Source-verified orientation for reporting, telemetry, random, traversal, and geodesy APIs. ## Report `Report` is global process state. Common methods: ```csharp Report.Line("msg"); Report.Warn("msg"); Report.Debug("msg"); Report.Trace("msg"); Report.Error("msg"); Report.Fatal("msg"); Report.BeginTimed("load"); // ... Report.End(); Report.Progress(0.5); Report.ProgressDelta(0.1); ``` Key settings: ```csharp Report.Verbosity = 2; Report.MultiThreaded = true; Report.ThrowOnError = false; ``` ## Telemetry Core probe types: - `Telemetry.Counter` - `Telemetry.StopWatchTime` - `Telemetry.WallClockTime` - `Telemetry.CpuTime` Registration: ```csharp var c = new Telemetry.Counter(); Telemetry.Register("Frames", c); Telemetry.Register("Frames/s", c.RatePerSecond()); ``` Reset API: ```csharp Telemetry.ResetTelemetrySystem(); ``` ## Random `RandomSystem` implements `IRandomUniform`. ```csharp var rnd = new RandomSystem(1); int raw = rnd.UniformInt(); int bounded = rnd.UniformInt(100); // extension method on IRandomUniform double u = rnd.UniformDouble(); ``` Geometric sampling: ```csharp var dir = RandomSample.Spherical(rnd, 0); var hemi = RandomSample.Lambertian(V3d.ZAxis, rnd, 0); var disk = RandomSample.Disk(rnd, 0); ``` Low-discrepancy: ```csharp var halton = new HaltonRandomSeries(2, rnd); double q = Quasi.QuasiHaltonWithIndex(2, 0.123); ``` ## INode Traversal `INode` extensions: - `DepthFirst()` - `BreadthFirst()` - `NodesAtDepth(depth)` - `DescendentsAndSelf()` and `Descendents()` (spelling in code is `Descendents`) ## Geodesy Main conversions: ```csharp var xyz = Geo.XyzFromLonLatHeight(new V3d(lonDeg, latDeg, hMeters), GeoEllipsoid.Wgs84); var llh = Geo.LonLatHeightFromXyz(xyz, GeoEllipsoid.Wgs84); ``` `GeoEllipsoid` presets include `Wgs84`, `Grs80`, `Bessel1841`. ## Constants `Constant` exposes machine-epsilon/tiny/parseable min/max style values. Mathematical constants are on non-generic classes: - `Constant.Pi`, `Constant.E` - `ConstantF.Pi`, `ConstantF.E` ## Source Anchors - `src/Aardvark.Base/Reporting/Report.cs` - `src/Aardvark.Base.Telemetry/Probes.cs` - `src/Aardvark.Base.Telemetry/Registry.cs` - `src/Aardvark.Base.Telemetry/IProbe.cs` - `src/Aardvark.Base.Telemetry/TelemetryExtensions.cs` - `src/Aardvark.Base/Random/RandomSystem.cs` - `src/Aardvark.Base/Random/IRandomUniform.cs` - `src/Aardvark.Base/Random/RandomSample.cs` - `src/Aardvark.Base/Random/HaltonRandomSeries.cs` - `src/Aardvark.Base/Random/Quasi.cs` - `src/Aardvark.Base/AlgoDat/INode.cs` - `src/Aardvark.Base/Geodesy/GeoConversion.cs` - `src/Aardvark.Base/Geodesy/GeoConsts.cs` - `src/Aardvark.Base/Math/Base/Constant.cs` ================================================ FILE: build.cmd ================================================ @echo off dotnet tool restore IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% REM `dotnet paket restore` alone does not recreate Paket.Restore.targets if it is missing. IF NOT EXIST ".paket\Paket.Restore.targets" ( dotnet paket install IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% ) ELSE ( dotnet paket restore IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% ) IF "%1"=="restore" exit /B dotnet build src\Aardvark.sln IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% ================================================ FILE: build.sh ================================================ #!/bin/bash set -eu mode="${1-}" dotnet tool restore # `dotnet paket restore` alone does not recreate Paket.Restore.targets if it is missing. if [ ! -f ".paket/Paket.Restore.targets" ]; then dotnet paket install else dotnet paket restore fi if [ "$mode" = "restore" ]; then exit 0 fi dotnet build src/Aardvark.sln ================================================ FILE: check-docs.cmd ================================================ @echo off dotnet run --project tools\DocsChecker\DocsChecker.csproj -c Release ================================================ FILE: check-docs.sh ================================================ #!/bin/bash set -euo pipefail dotnet run --project tools/DocsChecker/DocsChecker.csproj -c Release ================================================ FILE: generate.cmd ================================================ @echo off dotnet build src\CodeGenerator\CodeGenerator.csproj dotnet bin\Debug\net8.0\CodeGenerator.dll %* ================================================ FILE: generate.sh ================================================ #! /bin/sh dotnet build src/CodeGenerator/CodeGenerator.csproj dotnet bin/Debug/net8.0/CodeGenerator.dll "$@" ================================================ FILE: global.json ================================================ { "sdk": { "version": "8.0.0", "rollForward": "latestFeature", "allowPrerelease": false } } ================================================ FILE: paket.dependencies ================================================ framework: netstandard2.0, net8.0 storage: none source https://api.nuget.org/v3/index.json nuget Aardvark.Build ~> 2.0.7 nuget FSharp.Core >= 8.0.300 lowest_matching: true nuget System.Collections.Immutable >= 8.0.0 lowest_matching: true nuget System.Reflection.Metadata >= 8.0.0 lowest_matching: true nuget System.Text.Json >= 8.0.5 lowest_matching: true nuget System.Dynamic.Runtime ~> 4.3.0 nuget Aardvark.Base.TypeProviders ~> 4.5.15 nuget FSharp.Data.Adaptive ~> 1.2.0 nuget CSharp.Data.Adaptive ~> 1.2.0 nuget Unofficial.LibTessDotNet ~> 2.0.2 nuget FsPickler ~> 5.3.2 nuget FsPickler.Json ~> 5.3.2 nuget Unofficial.Typography ~> 0.1.0 nuget FuzzySharp ~> 2.0.2 nuget SingleFileExtractor.Core ~> 2.2.1 group CodeGenerator framework net8.0 storage: none source https://api.nuget.org/v3/index.json nuget Microsoft.NETFramework.ReferenceAssemblies = 1.0.0 nuget Microsoft.CodeAnalysis.CSharp ~> 4.1.0 group Demo framework net8.0 storage: none source https://api.nuget.org/v3/index.json nuget System.Reactive ~> 6.0.0 nuget CSharp.Data.Adaptive ~> 1.2.0 group Test framework: net8.0 storage: none source https://api.nuget.org/v3/index.json nuget NUnit ~> 3.14.0 nuget FsUnit ~> 5.6.1 nuget FsCheck ~> 2.16.6 nuget FsCheck.NUnit ~> 2.16.6 nuget NUnit3TestAdapter ~> 4.5.0 nuget Microsoft.NET.Test.Sdk ~> 17.9.0 nuget Expecto ~> 10.2.1 nuget Expecto.FsCheck ~> 10.2.1 nuget YoloDev.Expecto.TestSdk ~> 0.14.3 nuget BenchmarkDotNet ~> 0.13.12 ================================================ FILE: src/Aardvark.Base/Aardvark.Base.csproj ================================================ net8.0;netstandard2.0 12.0 true ..\..\bin\Debug 1701;1702;1705;1591 true ..\..\bin\Release 1701;1702;1705;1591 true ================================================ FILE: src/Aardvark.Base/AlgoDat/AdaBoost.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace Aardvark.Base { /// /// Adaptive boosting creates a strong binary classifier /// out of an ensemble of weak classifiers. /// public static class AdaBoost { /// /// Creates a strong binary classifier out of an ensemble of weak classifiers. /// /// Type of items to be classified. /// Training set. /// Correct classification of training set. /// /// Returns a new weak classifier for given weighted items. /// (double[] weights, T[] items, bool[] groundTruth) => T => bool. /// /// Maximium number of weak classifiers to combine. /// Optional callback for each learning iteration. /// If onIteration returns true, then learning is stopped. /// Default is 0.0, which means that the /// maximum number of iterations will be performed. /// A strong classifier for Ts based on a weighted majority vote of /// weak classifiers. public static Func Train( T[] items, bool[] groundTruth, Func> getNextWeakClassifier, int iterations, Func, bool> onIteration = null, double stopIfWeakClassifierHasLessImportanceThan = 0.0 ) { var count = items.Length; var ws = new double[count].Set(1.0 / count); var classifiers = new List>(); var alphas = new List(); while (iterations-- > 0) { try { // get next weak classifier (based on examples and weights) var classifier = getNextWeakClassifier(ws, items, groundTruth); // predict values with new classifier var predictions = items.Select(x => classifier(x)).ToArray(); // compare predictions to reality (and compute error rate e) double e = 0.0; for (var j = 0; j < count; j++) { e += ws[j] * (predictions[j] == groundTruth[j] ? 0 : 1); } if (Math.Abs(0.5 - e) < 0.02) { iterations++; continue; } if (e == 0.0) // we found a perfect classifier { classifiers.Clear(); classifiers.Add(classifier); alphas.Clear(); alphas.Add(1.0); break; } // compute importance for this classifier // (higher error rate gives less importance) var alpha = 0.5 * Math.Log((1 - e) / e); if (Math.Abs(alpha) < stopIfWeakClassifierHasLessImportanceThan) break; // increase weights of incorrectly classified examples, and // decrease weights of correctly classified examples var up = Math.Exp(alpha); var down = Math.Exp(-alpha); for (var j = 0; j < count; j++) { ws[j] *= (predictions[j] == groundTruth[j]) ? down : up; } var wnormf = 1.0 / ws.Sum(); // normalization factor for weights for (var j = 0; j < count; j++) ws[j] *= wnormf; // add classifier and its importance to list classifiers.Add(classifier); alphas.Add(alpha); // optional callback if (onIteration != null) { var c = new Classifier( Enumerable.Range(0, ws.Length).Select(i => new WeightedExample(ws[i], items[i])), Enumerable.Range(0, alphas.Count).Select(i => new WeakClassifier(alphas[i], classifiers[i])) ); if (onIteration(c.Classify)) { break; } } } catch /*(Exception e)*/ { Report.Warn("AdaBoost.Train"); } } // create strong classifier from weak classifiers return new Classifier( Enumerable.Range(0, ws.Length).Select(i => new WeightedExample(ws[i], items[i])), Enumerable.Range(0, alphas.Count).Select(i => new WeakClassifier(alphas[i], classifiers[i])) ).Classify; } private readonly struct Classifier { private readonly WeakClassifier[] m_weakClassifiers; public Classifier( IEnumerable> examples, IEnumerable> weakClassifiers ) { m_weakClassifiers = weakClassifiers.ToArray(); } public bool Classify(T x) => SumAlphaWeightedWeakClassifiers(x) > 0.0; /// /// Computes propability of positive classification given x. /// public double P(T x) => 1.0 / (1.0 + Math.Exp(-2.0 * SumAlphaWeightedWeakClassifiers(x))); private double SumAlphaWeightedWeakClassifiers(T x) => m_weakClassifiers.Sum(c => c.Alpha * (c.Classifier(x) ? +1 : -1)); } private readonly struct WeightedExample { public readonly double Weight; public readonly T Example; public WeightedExample(double weight, T example) { Weight = weight; Example = example; } } private readonly struct WeakClassifier { public readonly double Alpha; public readonly Func Classifier; public WeakClassifier(double alpha, Func classifier) { Alpha = alpha; Classifier = classifier ?? throw new ArgumentNullException("classifier"); } } } } ================================================ FILE: src/Aardvark.Base/AlgoDat/ConcurrentHashSet.cs ================================================ using System.Collections.Generic; using System.Linq; namespace System.Collections.Concurrent { /// /// Represents a thread-safe collection that can be accessed by multiple threads concurrently. /// public class ConcurrentHashSet : IEnumerable, ICollection { //int does not waste too much memory and might be used for reference-counting //or similar features. TODO: investigate if this is faster using reference types. private readonly ConcurrentDictionary m_entries; #region Constructors public ConcurrentHashSet() { m_entries = new ConcurrentDictionary(); } public ConcurrentHashSet(int concurrencyLevel, int capacity) { m_entries = new ConcurrentDictionary(concurrencyLevel, capacity); } public ConcurrentHashSet(IEqualityComparer comparer) { m_entries = new ConcurrentDictionary(comparer); } public ConcurrentHashSet(IEnumerable collection) { m_entries = new ConcurrentDictionary(collection.Select(e => new KeyValuePair(e, 1))); } public ConcurrentHashSet(IEnumerable collection, IEqualityComparer comparer) { m_entries = new ConcurrentDictionary(collection.Select(e => new KeyValuePair(e, 1)), comparer); } #endregion #region Properties public int Count => m_entries.Count; #endregion #region Methods public void Clear() => m_entries.Clear(); public bool Add(T item) => m_entries.TryAdd(item, 1); public bool Remove(T item) => m_entries.TryRemove(item, out int dummy); public void UnionWith(IEnumerable other) { foreach (var e in other) Add(e); } #endregion #region IEnumerable Members public Enumerator GetEnumerator() => new Enumerator(this); IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); #endregion #region ICollection Members public bool Contains(T item) => m_entries.ContainsKey(item); public void CopyTo(T[] array, int arrayIndex) => m_entries.Keys.CopyTo(array, arrayIndex); public bool IsReadOnly => false; void ICollection.Add(T item) => Add(item); #endregion public readonly struct Enumerator : IEnumerator, System.Collections.IEnumerator { private readonly IEnumerator> m_enumerator; internal Enumerator(ConcurrentHashSet set) { m_enumerator = set.m_entries.GetEnumerator(); } public T Current => m_enumerator.Current.Key; public void Dispose() => m_enumerator.Dispose(); object IEnumerator.Current => ((IEnumerator)m_enumerator).Current; public bool MoveNext() => m_enumerator.MoveNext(); public void Reset() => m_enumerator.Reset(); } } } ================================================ FILE: src/Aardvark.Base/AlgoDat/ExtendedCore/BitHelpers.cs ================================================ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Collections; using System.Text; namespace Aardvark.Base { /// /// ABOUT: /// Helps with operations that rely on bit marking to indicate whether an item in the /// collection should be added, removed, visited already, etc. /// /// BitHelper doesn't allocate the array; you must pass in an array or ints allocated on the /// stack or heap. ToIntArrayLength() tells you the int array size you must allocate. /// /// USAGE: /// Suppose you need to represent a bit array of length (i.e. logical bit array length) /// BIT_ARRAY_LENGTH. Then this is the suggested way to instantiate BitHelper: /// *************************************************************************** /// int intArrayLength = BitHelper.ToIntArrayLength(BIT_ARRAY_LENGTH); /// BitHelper bitHelper; /// if (intArrayLength less than stack alloc threshold) /// int* m_arrayPtr = stackalloc int[intArrayLength]; /// bitHelper = new BitHelper(m_arrayPtr, intArrayLength); /// else /// int[] m_arrayPtr = new int[intArrayLength]; /// bitHelper = new BitHelper(m_arrayPtr, intArrayLength); /// *************************************************************************** /// /// IMPORTANT: /// The second ctor args, length, should be specified as the length of the int array, not /// the logical bit array. Because length is used for bounds checking into the int array, /// it's especially important to get this correct for the stackalloc version. See the code /// samples above; this is the value gotten from ToIntArrayLength(). /// /// The length ctor argument is the only exception; for other methods -- MarkBit and /// IsMarked -- pass in values as indices into the logical bit array, and it will be mapped /// to the position within the array of ints. /// /// FUTURE OPTIMIZATIONS: /// A method such as FindFirstMarked/Unmarked Bit would be useful for callers that operate /// on a bit array and then need to loop over it. In particular, if it avoided visiting /// every bit, it would allow good perf improvements when the bit array is sparse. /// unsafe internal sealed class BitHelperExt { // should not be serialized private const byte MarkedBitFlag = 1; private const byte IntSize = 32; // m_length of underlying int array (not logical bit array) private readonly int _length; // ptr to stack alloc'd array of ints private readonly int* _arrayPtr; // array of ints private readonly int[] _array; // whether to operate on stack alloc'd or heap alloc'd array private readonly bool _useStackAlloc; /// /// Instantiates a BitHelper with a heap alloc'd array of ints /// /// int array to hold bits /// length of int array internal BitHelperExt(int* bitArrayPtr, int length) { _arrayPtr = bitArrayPtr; _length = length; _useStackAlloc = true; } /// /// Instantiates a BitHelper with a heap alloc'd array of ints /// /// int array to hold bits /// length of int array internal BitHelperExt(int[] bitArray, int length) { _array = bitArray; _length = length; } /// /// Mark bit at specified position /// /// internal void MarkBit(int bitPosition) { int bitArrayIndex = bitPosition / IntSize; if (bitArrayIndex < _length && bitArrayIndex >= 0) { int flag = (MarkedBitFlag << (bitPosition % IntSize)); if (_useStackAlloc) { _arrayPtr[bitArrayIndex] |= flag; } else { _array[bitArrayIndex] |= flag; } } } /// /// Is bit at specified position marked? /// /// /// internal bool IsMarked(int bitPosition) { int bitArrayIndex = bitPosition / IntSize; if (bitArrayIndex < _length && bitArrayIndex >= 0) { int flag = (MarkedBitFlag << (bitPosition % IntSize)); if (_useStackAlloc) { return ((_arrayPtr[bitArrayIndex] & flag) != 0); } else { return ((_array[bitArrayIndex] & flag) != 0); } } return false; } /// /// How many ints must be allocated to represent n bits. Returns (n+31)/32, but /// avoids overflow /// /// /// internal static int ToIntArrayLength(int n) { return n > 0 ? ((n - 1) / IntSize + 1) : 0; } } } ================================================ FILE: src/Aardvark.Base/AlgoDat/ExtendedCore/SortedSetExt.cs ================================================ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. /*============================================================ ** ** ** Purpose: A generic sorted set. ** ** This is a copy of SortedSet extending it with neighbourhood information ===========================================================*/ using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Aardvark.Base { // // A binary search tree is a red-black tree if it satifies the following red-black properties: // 1. Every node is either red or black // 2. Every leaf (nil node) is black // 3. If a node is red, the both its children are black // 4. Every simple path from a node to a descendant leaf contains the same number of black nodes // // The basic idea of red-black tree is to represent 2-3-4 trees as standard BSTs but to add one extra bit of information // per node to encode 3-nodes and 4-nodes. // 4-nodes will be represented as: B // R R // 3 -node will be represented as: B or B // R B B R // // For a detailed description of the algorithm, take a look at "Algorithm" by Rebert Sedgewick. // internal delegate bool TreeWalkPredicate(SortedSetExt.Node node); internal enum TreeRotation { LeftRotation = 1, RightRotation = 2, RightLeftRotation = 3, LeftRightRotation = 4, } public class Optional { public bool HasValue; public T Value; private Optional() { HasValue = false; Value = default(T); } public Optional(T value) { HasValue = true; Value = value; } public static Optional None = new Optional(); } [DebuggerDisplay("Count = {Count}")] public class SortedSetExt : ISet, ICollection, ICollection, IReadOnlyCollection { #region local variables/constants private Node _root; private readonly IComparer _comparer; private int _count; private int _version; private Object _syncRoot; internal const int StackAllocThreshold = 100; #endregion #region Constructors public SortedSetExt() { _comparer = Comparer.Default; } public SortedSetExt(IComparer comparer) { if (comparer == null) { _comparer = Comparer.Default; } else { _comparer = comparer; } } public SortedSetExt(IEnumerable collection) : this(collection, Comparer.Default) { } public SortedSetExt(IEnumerable collection, IComparer comparer) : this(comparer) { if (collection == null) { throw new ArgumentNullException("collection"); } // these are explicit type checks in the mould of HashSet. It would have worked better // with something like an ISorted (we could make this work for SortedList.Keys etc) SortedSetExt baseSortedSet = collection as SortedSetExt; SortedSetExt baseTreeSubSet = collection as TreeSubSet; if (baseSortedSet != null && baseTreeSubSet == null && AreComparersEqual(this, baseSortedSet)) { //breadth first traversal to recreate nodes if (baseSortedSet.Count == 0) { return; } //pre order way to replicate nodes Stack theirStack = new Stack.Node>(2 * log2(baseSortedSet.Count) + 2); Stack myStack = new Stack.Node>(2 * log2(baseSortedSet.Count) + 2); Node theirCurrent = baseSortedSet._root; Node myCurrent = (theirCurrent != null ? new SortedSetExt.Node(theirCurrent.Item, theirCurrent.IsRed) : null); _root = myCurrent; while (theirCurrent != null) { theirStack.Push(theirCurrent); myStack.Push(myCurrent); myCurrent.Left = (theirCurrent.Left != null ? new SortedSetExt.Node(theirCurrent.Left.Item, theirCurrent.Left.IsRed) : null); theirCurrent = theirCurrent.Left; myCurrent = myCurrent.Left; } while (theirStack.Count != 0) { theirCurrent = theirStack.Pop(); myCurrent = myStack.Pop(); Node theirRight = theirCurrent.Right; Node myRight = null; if (theirRight != null) { myRight = new SortedSetExt.Node(theirRight.Item, theirRight.IsRed); } myCurrent.Right = myRight; while (theirRight != null) { theirStack.Push(theirRight); myStack.Push(myRight); myRight.Left = (theirRight.Left != null ? new SortedSetExt.Node(theirRight.Left.Item, theirRight.Left.IsRed) : null); theirRight = theirRight.Left; myRight = myRight.Left; } } _count = baseSortedSet._count; } else { T[] els = collection.ToArray(); int count = els.Length; if (count > 0) { Array.Sort(els, 0, count, _comparer); int index = 1; for (int i = 1; i < count; i++) { if (comparer.Compare(els[i], els[i - 1]) != 0) { els[index++] = els[i]; } } count = index; _root = ConstructRootFromSortedArray(els, 0, count - 1, null); _count = count; } } } #endregion #region Bulk Operation Helpers private void AddAllElements(IEnumerable collection) { foreach (T item in collection) { if (!this.Contains(item)) Add(item); } } private void RemoveAllElements(IEnumerable collection) { T min = this.Min; T max = this.Max; foreach (T item in collection) { if (!(_comparer.Compare(item, min) < 0 || _comparer.Compare(item, max) > 0) && this.Contains(item)) this.Remove(item); } } private bool ContainsAllElements(IEnumerable collection) { foreach (T item in collection) { if (!this.Contains(item)) { return false; } } return true; } // // Do a in order walk on tree and calls the delegate for each node. // If the action delegate returns false, stop the walk. // // Return true if the entire tree has been walked. // Otherwise returns false. // internal bool InOrderTreeWalk(TreeWalkPredicate action) { return InOrderTreeWalk(action, false); } // Allows for the change in traversal direction. Reverse visits nodes in descending order internal virtual bool InOrderTreeWalk(TreeWalkPredicate action, bool reverse) { if (_root == null) { return true; } // The maximum height of a red-black tree is 2*lg(n+1). // See page 264 of "Introduction to algorithms" by Thomas H. Cormen // note: this should be logbase2, but since the stack grows itself, we // don't want the extra cost Stack stack = new Stack(2 * (int)(SortedSetExt.log2(Count + 1))); Node current = _root; while (current != null) { stack.Push(current); current = (reverse ? current.Right : current.Left); } while (stack.Count != 0) { current = stack.Pop(); if (!action(current)) { return false; } Node node = (reverse ? current.Left : current.Right); while (node != null) { stack.Push(node); node = (reverse ? node.Right : node.Left); } } return true; } // // Do a left to right breadth first walk on tree and // calls the delegate for each node. // If the action delegate returns false, stop the walk. // // Return true if the entire tree has been walked. // Otherwise returns false. // internal virtual bool BreadthFirstTreeWalk(TreeWalkPredicate action) { if (_root == null) { return true; } Queue processQueue = new Queue(); processQueue.Enqueue(_root); Node current; while (processQueue.Count != 0) { current = processQueue.Dequeue(); if (!action(current)) { return false; } if (current.Left != null) { processQueue.Enqueue(current.Left); } if (current.Right != null) { processQueue.Enqueue(current.Right); } } return true; } #endregion #region Properties public int Count { get { VersionCheck(); return _count; } } public IComparer Comparer { get { return _comparer; } } bool ICollection.IsReadOnly { get { return false; } } bool ICollection.IsSynchronized { get { return false; } } object ICollection.SyncRoot { get { if (_syncRoot == null) { System.Threading.Interlocked.CompareExchange(ref _syncRoot, new Object(), null); } return _syncRoot; } } #endregion #region Subclass helpers //virtual function for subclass that needs to update count internal virtual void VersionCheck() { } //virtual function for subclass that needs to do range checks internal virtual bool IsWithinRange(T item) { return true; } #endregion #region ICollection Members /// /// Add the value ITEM to the tree, returns true if added, false if duplicate /// /// item to be added public bool Add(T item) { return AddIfNotPresent(item); } void ICollection.Add(T item) { AddIfNotPresent(item); } /// /// Adds ITEM to the tree if not already present. Returns TRUE if value was successfully added /// or FALSE if it is a duplicate /// internal virtual bool AddIfNotPresent(T item) { if (_root == null) { // empty tree _root = new Node(item, false); _count = 1; _version++; return true; } // // Search for a node at bottom to insert the new node. // If we can guanratee the node we found is not a 4-node, it would be easy to do insertion. // We split 4-nodes along the search path. // Node current = _root; Node parent = null; Node grandParent = null; Node greatGrandParent = null; //even if we don't actually add to the set, we may be altering its structure (by doing rotations //and such). so update version to disable any enumerators/subsets working on it _version++; int order = 0; while (current != null) { order = _comparer.Compare(item, current.Item); if (order == 0) { // We could have changed root node to red during the search process. // We need to set it to black before we return. _root.IsRed = false; return false; } // split a 4-node into two 2-nodes if (Is4Node(current)) { Split4Node(current); // We could have introduced two consecutive red nodes after split. Fix that by rotation. if (IsRed(parent)) { InsertionBalance(current, ref parent, grandParent, greatGrandParent); } } greatGrandParent = grandParent; grandParent = parent; parent = current; current = (order < 0) ? current.Left : current.Right; } Debug.Assert(parent != null, "Parent node cannot be null here!"); // ready to insert the new node Node node = new Node(item); if (order > 0) { parent.Right = node; } else { parent.Left = node; } // the new node will be red, so we will need to adjust the colors if parent node is also red if (parent.IsRed) { InsertionBalance(node, ref parent, grandParent, greatGrandParent); } // Root node is always black _root.IsRed = false; ++_count; return true; } /// /// Remove the T ITEM from this SortedSet. Returns true if successfully removed. /// /// /// public bool Remove(T item) { return this.DoRemove(item); // hack so it can be made non-virtual } internal virtual bool DoRemove(T item) { if (_root == null) { return false; } // Search for a node and then find its succesor. // Then copy the item from the succesor to the matching node and delete the successor. // If a node doesn't have a successor, we can replace it with its left child (if not empty.) // or delete the matching node. // // In top-down implementation, it is important to make sure the node to be deleted is not a 2-node. // Following code will make sure the node on the path is not a 2 Node. //even if we don't actually remove from the set, we may be altering its structure (by doing rotations //and such). so update version to disable any enumerators/subsets working on it _version++; Node current = _root; Node parent = null; Node grandParent = null; Node match = null; Node parentOfMatch = null; bool foundMatch = false; while (current != null) { if (Is2Node(current)) { // fix up 2-Node if (parent == null) { // current is root. Mark it as red current.IsRed = true; } else { Node sibling = GetSibling(current, parent); if (sibling.IsRed) { // If parent is a 3-node, flip the orientation of the red link. // We can acheive this by a single rotation // This case is converted to one of other cased below. Debug.Assert(!parent.IsRed, "parent must be a black node!"); if (parent.Right == sibling) { RotateLeft(parent); } else { RotateRight(parent); } parent.IsRed = true; sibling.IsRed = false; // parent's color // sibling becomes child of grandParent or root after rotation. Update link from grandParent or root ReplaceChildOfNodeOrRoot(grandParent, parent, sibling); // sibling will become grandParent of current node grandParent = sibling; if (parent == match) { parentOfMatch = sibling; } // update sibling, this is necessary for following processing sibling = (parent.Left == current) ? parent.Right : parent.Left; } Debug.Assert(sibling != null || sibling.IsRed == false, "sibling must not be null and it must be black!"); if (Is2Node(sibling)) { Merge2Nodes(parent, current, sibling); } else { // current is a 2-node and sibling is either a 3-node or a 4-node. // We can change the color of current to red by some rotation. TreeRotation rotation = RotationNeeded(parent, current, sibling); Node newGrandParent = null; switch (rotation) { case TreeRotation.RightRotation: Debug.Assert(parent.Left == sibling, "sibling must be left child of parent!"); Debug.Assert(sibling.Left.IsRed, "Left child of sibling must be red!"); sibling.Left.IsRed = false; newGrandParent = RotateRight(parent); break; case TreeRotation.LeftRotation: Debug.Assert(parent.Right == sibling, "sibling must be left child of parent!"); Debug.Assert(sibling.Right.IsRed, "Right child of sibling must be red!"); sibling.Right.IsRed = false; newGrandParent = RotateLeft(parent); break; case TreeRotation.RightLeftRotation: Debug.Assert(parent.Right == sibling, "sibling must be left child of parent!"); Debug.Assert(sibling.Left.IsRed, "Left child of sibling must be red!"); newGrandParent = RotateRightLeft(parent); break; case TreeRotation.LeftRightRotation: Debug.Assert(parent.Left == sibling, "sibling must be left child of parent!"); Debug.Assert(sibling.Right.IsRed, "Right child of sibling must be red!"); newGrandParent = RotateLeftRight(parent); break; } newGrandParent.IsRed = parent.IsRed; parent.IsRed = false; current.IsRed = true; ReplaceChildOfNodeOrRoot(grandParent, parent, newGrandParent); if (parent == match) { parentOfMatch = newGrandParent; } grandParent = newGrandParent; } } } // we don't need to compare any more once we found the match int order = foundMatch ? -1 : _comparer.Compare(item, current.Item); if (order == 0) { // save the matching node foundMatch = true; match = current; parentOfMatch = parent; } grandParent = parent; parent = current; if (order < 0) { current = current.Left; } else { current = current.Right; // continue the search in right sub tree after we find a match } } // move successor to the matching node position and replace links if (match != null) { ReplaceNode(match, parentOfMatch, parent, grandParent); --_count; } if (_root != null) { _root.IsRed = false; } return foundMatch; } public virtual void Clear() { _root = null; _count = 0; ++_version; } public virtual bool Contains(T item) { return FindNode(item) != null; } public void CopyTo(T[] array) { CopyTo(array, 0, Count); } public void CopyTo(T[] array, int index) { CopyTo(array, index, Count); } public void CopyTo(T[] array, int index, int count) { if (array == null) { throw new ArgumentNullException("array"); } if (index < 0) { throw new ArgumentOutOfRangeException("index"); } if (count < 0) { throw new ArgumentOutOfRangeException("count", "SR.ArgumentOutOfRange_NeedNonNegNum"); } // will array, starting at arrayIndex, be able to hold elements? Note: not // checking arrayIndex >= array.Length (consistency with list of allowing // count of 0; subsequent check takes care of the rest) if (index > array.Length || count > array.Length - index) { throw new ArgumentException("SR.Arg_ArrayPlusOffTooSmall"); } //upper bound count += index; InOrderTreeWalk(delegate (Node node) { if (index >= count) { return false; } else { array[index++] = node.Item; return true; } }); } void ICollection.CopyTo(Array array, int index) { if (array == null) { throw new ArgumentNullException("array"); } if (array.Rank != 1) { throw new ArgumentException("SR.Arg_RankMultiDimNotSupported"); } if (array.GetLowerBound(0) != 0) { throw new ArgumentException("SR.Arg_NonZeroLowerBound"); } if (index < 0) { throw new ArgumentOutOfRangeException("arrayIndex", "SR.ArgumentOutOfRange_NeedNonNegNum"); } if (array.Length - index < Count) { throw new ArgumentException("SR.Arg_ArrayPlusOffTooSmall"); } T[] tarray = array as T[]; if (tarray != null) { CopyTo(tarray, index); } else { object[] objects = array as object[]; if (objects == null) { throw new ArgumentException("SR.Argument_InvalidArrayType"); } try { InOrderTreeWalk(delegate (Node node) { objects[index++] = node.Item; return true; }); } catch (ArrayTypeMismatchException) { throw new ArgumentException("SR.Argument_InvalidArrayType"); } } } #endregion #region IEnumerable members public Enumerator GetEnumerator() { return new Enumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region Tree Specific Operations private static Node GetSibling(Node node, Node parent) { if (parent.Left == node) { return parent.Right; } return parent.Left; } // After calling InsertionBalance, we need to make sure current and parent up-to-date. // It doesn't matter if we keep grandParent and greatGrantParent up-to-date // because we won't need to split again in the next node. // By the time we need to split again, everything will be correctly set. // private void InsertionBalance(Node current, ref Node parent, Node grandParent, Node greatGrandParent) { Debug.Assert(grandParent != null, "Grand parent cannot be null here!"); bool parentIsOnRight = (grandParent.Right == parent); bool currentIsOnRight = (parent.Right == current); Node newChildOfGreatGrandParent; if (parentIsOnRight == currentIsOnRight) { // same orientation, single rotation newChildOfGreatGrandParent = currentIsOnRight ? RotateLeft(grandParent) : RotateRight(grandParent); } else { // different orientaton, double rotation newChildOfGreatGrandParent = currentIsOnRight ? RotateLeftRight(grandParent) : RotateRightLeft(grandParent); // current node now becomes the child of greatgrandparent parent = greatGrandParent; } // grand parent will become a child of either parent of current. grandParent.IsRed = true; newChildOfGreatGrandParent.IsRed = false; ReplaceChildOfNodeOrRoot(greatGrandParent, grandParent, newChildOfGreatGrandParent); } private static bool Is2Node(Node node) { Debug.Assert(node != null, "node cannot be null!"); return IsBlack(node) && IsNullOrBlack(node.Left) && IsNullOrBlack(node.Right); } private static bool Is4Node(Node node) { return IsRed(node.Left) && IsRed(node.Right); } private static bool IsBlack(Node node) { return (node != null && !node.IsRed); } private static bool IsNullOrBlack(Node node) { return (node == null || !node.IsRed); } private static bool IsRed(Node node) { return (node != null && node.IsRed); } private static void Merge2Nodes(Node parent, Node child1, Node child2) { Debug.Assert(IsRed(parent), "parent must be be red"); // combing two 2-nodes into a 4-node parent.IsRed = false; child1.IsRed = true; child2.IsRed = true; } // Replace the child of a parent node. // If the parent node is null, replace the root. private void ReplaceChildOfNodeOrRoot(Node parent, Node child, Node newChild) { if (parent != null) { if (parent.Left == child) { parent.Left = newChild; } else { parent.Right = newChild; } } else { _root = newChild; } } // Replace the matching node with its succesor. private void ReplaceNode(Node match, Node parentOfMatch, Node succesor, Node parentOfSuccesor) { if (succesor == match) { // this node has no successor, should only happen if right child of matching node is null. Debug.Assert(match.Right == null, "Right child must be null!"); succesor = match.Left; } else { Debug.Assert(parentOfSuccesor != null, "parent of successor cannot be null!"); Debug.Assert(succesor.Left == null, "Left child of succesor must be null!"); Debug.Assert((succesor.Right == null && succesor.IsRed) || (succesor.Right.IsRed && !succesor.IsRed), "Succesor must be in valid state"); if (succesor.Right != null) { succesor.Right.IsRed = false; } if (parentOfSuccesor != match) { // detach succesor from its parent and set its right child parentOfSuccesor.Left = succesor.Right; succesor.Right = match.Right; } succesor.Left = match.Left; } if (succesor != null) { succesor.IsRed = match.IsRed; } ReplaceChildOfNodeOrRoot(parentOfMatch, match, succesor); } internal virtual Node FindNode(T item) { Node current = _root; while (current != null) { int order = _comparer.Compare(item, current.Item); if (order == 0) { return current; } else { current = (order < 0) ? current.Left : current.Right; } } return null; } internal virtual (Node, Node, Node) FindNeighbours(T item) { Node current = _root; Node left = null; Node right = null; Node self = null; while (current != null) { int order = _comparer.Compare(item, current.Item); if (order != 0) { if (order > 0) { left = current; current = current.Right; } else { right = current; current = current.Left; } } else { self = current; if (current.Left != null) { left = current.Left; while (left.Right != null) left = left.Right; } if (current.Right != null) { right = current.Right; while (right.Left != null) right = right.Left; } break; } } return (left, self, right); } //used for bithelpers. Note that this implementation is completely different //from the Subset's. The two should not be mixed. This indexes as if the tree were an array. //http://en.wikipedia.org/wiki/Binary_Tree#Methods_for_storing_binary_trees internal virtual int InternalIndexOf(T item) { Node current = _root; int count = 0; while (current != null) { int order = _comparer.Compare(item, current.Item); if (order == 0) { return count; } else { current = (order < 0) ? current.Left : current.Right; count = (order < 0) ? (2 * count + 1) : (2 * count + 2); } } return -1; } internal Node FindRange(T from, T to) { return FindRange(from, to, true, true); } internal Node FindRange(T from, T to, bool lowerBoundActive, bool upperBoundActive) { Node current = _root; while (current != null) { if (lowerBoundActive && _comparer.Compare(from, current.Item) > 0) { current = current.Right; } else { if (upperBoundActive && _comparer.Compare(to, current.Item) < 0) { current = current.Left; } else { return current; } } } return null; } internal void UpdateVersion() { ++_version; } private static Node RotateLeft(Node node) { Node x = node.Right; node.Right = x.Left; x.Left = node; return x; } private static Node RotateLeftRight(Node node) { Node child = node.Left; Node grandChild = child.Right; node.Left = grandChild.Right; grandChild.Right = node; child.Right = grandChild.Left; grandChild.Left = child; return grandChild; } private static Node RotateRight(Node node) { Node x = node.Left; node.Left = x.Right; x.Right = node; return x; } private static Node RotateRightLeft(Node node) { Node child = node.Right; Node grandChild = child.Left; node.Right = grandChild.Left; grandChild.Left = node; child.Left = grandChild.Right; grandChild.Right = child; return grandChild; } /// /// Testing counter that can track rotations /// private static TreeRotation RotationNeeded(Node parent, Node current, Node sibling) { Debug.Assert(IsRed(sibling.Left) || IsRed(sibling.Right), "sibling must have at least one red child"); if (IsRed(sibling.Left)) { if (parent.Left == current) { return TreeRotation.RightLeftRotation; } return TreeRotation.RightRotation; } else { if (parent.Left == current) { return TreeRotation.LeftRotation; } return TreeRotation.LeftRightRotation; } } /// /// Decides whether these sets are the same, given the comparer. If the EC's are the same, we can /// just use SetEquals, but if they aren't then we have to manually check with the given comparer /// internal static bool SortedSetEquals(SortedSetExt set1, SortedSetExt set2, IComparer comparer) { // handle null cases first if (set1 == null) { return (set2 == null); } else if (set2 == null) { // set1 != null return false; } if (AreComparersEqual(set1, set2)) { if (set1.Count != set2.Count) return false; return set1.SetEquals(set2); } else { bool found = false; foreach (T item1 in set1) { found = false; foreach (T item2 in set2) { if (comparer.Compare(item1, item2) == 0) { found = true; break; } } if (!found) return false; } return true; } } //This is a little frustrating because we can't support more sorted structures private static bool AreComparersEqual(SortedSetExt set1, SortedSetExt set2) { return set1.Comparer.Equals(set2.Comparer); } private static void Split4Node(Node node) { node.IsRed = true; node.Left.IsRed = false; node.Right.IsRed = false; } /// /// Copies this to an array. Used for DebugView /// /// internal T[] ToArray() { T[] newArray = new T[Count]; CopyTo(newArray); return newArray; } #endregion #region ISet Members /// /// Transform this set into its union with the IEnumerable OTHER ///Attempts to insert each element and rejects it if it exists. /// NOTE: The caller object is important as UnionWith uses the Comparator ///associated with THIS to check equality /// Throws ArgumentNullException if OTHER is null /// /// public void UnionWith(IEnumerable other) { if (other == null) { throw new ArgumentNullException("other"); } SortedSetExt s = other as SortedSetExt; TreeSubSet t = this as TreeSubSet; if (t != null) VersionCheck(); if (s != null && t == null && _count == 0) { SortedSetExt dummy = new SortedSetExt(s, _comparer); _root = dummy._root; _count = dummy._count; _version++; return; } if (s != null && t == null && AreComparersEqual(this, s) && (s.Count > this.Count / 2)) { //this actually hurts if N is much greater than M the /2 is arbitrary //first do a merge sort to an array. T[] merged = new T[s.Count + this.Count]; int c = 0; Enumerator mine = this.GetEnumerator(); Enumerator theirs = s.GetEnumerator(); bool mineEnded = !mine.MoveNext(), theirsEnded = !theirs.MoveNext(); while (!mineEnded && !theirsEnded) { int comp = Comparer.Compare(mine.Current, theirs.Current); if (comp < 0) { merged[c++] = mine.Current; mineEnded = !mine.MoveNext(); } else if (comp == 0) { merged[c++] = theirs.Current; mineEnded = !mine.MoveNext(); theirsEnded = !theirs.MoveNext(); } else { merged[c++] = theirs.Current; theirsEnded = !theirs.MoveNext(); } } if (!mineEnded || !theirsEnded) { Enumerator remaining = (mineEnded ? theirs : mine); do { merged[c++] = remaining.Current; } while (remaining.MoveNext()); } //now merged has all c elements //safe to gc the root, we have all the elements _root = null; _root = SortedSetExt.ConstructRootFromSortedArray(merged, 0, c - 1, null); _count = c; _version++; } else { AddAllElements(other); } } private static Node ConstructRootFromSortedArray(T[] arr, int startIndex, int endIndex, Node redNode) { //what does this do? //you're given a sorted array... say 1 2 3 4 5 6 //2 cases: // If there are odd # of elements, pick the middle element (in this case 4), and compute // its left and right branches // If there are even # of elements, pick the left middle element, save the right middle element // and call the function on the rest // 1 2 3 4 5 6 -> pick 3, save 4 and call the fn on 1,2 and 5,6 // now add 4 as a red node to the lowest element on the right branch // 3 3 // 1 5 -> 1 5 // 2 6 2 4 6 // As we're adding to the leftmost of the right branch, nesting will not hurt the red-black properties // Leaf nodes are red if they have no sibling (if there are 2 nodes or if a node trickles // down to the bottom //the iterative way to do this ends up wasting more space than it saves in stack frames (at //least in what i tried) //so we're doing this recursively //base cases are described below int size = endIndex - startIndex + 1; if (size == 0) { return null; } Node root = null; if (size == 1) { root = new Node(arr[startIndex], false); if (redNode != null) { root.Left = redNode; } } else if (size == 2) { root = new Node(arr[startIndex], false); root.Right = new Node(arr[endIndex], false); root.Right.IsRed = true; if (redNode != null) { root.Left = redNode; } } else if (size == 3) { root = new Node(arr[startIndex + 1], false); root.Left = new Node(arr[startIndex], false); root.Right = new Node(arr[endIndex], false); if (redNode != null) { root.Left.Left = redNode; } } else { int midpt = ((startIndex + endIndex) / 2); root = new Node(arr[midpt], false); root.Left = ConstructRootFromSortedArray(arr, startIndex, midpt - 1, redNode); if (size % 2 == 0) { root.Right = ConstructRootFromSortedArray(arr, midpt + 2, endIndex, new Node(arr[midpt + 1], true)); } else { root.Right = ConstructRootFromSortedArray(arr, midpt + 1, endIndex, null); } } return root; } /// /// Transform this set into its intersection with the IEnumerable OTHER /// NOTE: The caller object is important as IntersectionWith uses the /// comparator associated with THIS to check equality /// Throws ArgumentNullException if OTHER is null /// /// public virtual void IntersectWith(IEnumerable other) { if (other == null) { throw new ArgumentNullException("other"); } if (Count == 0) return; //HashSet optimizations can't be done until equality comparers and comparers are related //Technically, this would work as well with an ISorted SortedSetExt s = other as SortedSetExt; TreeSubSet t = this as TreeSubSet; if (t != null) VersionCheck(); //only let this happen if i am also a SortedSet, not a SubSet if (s != null && t == null && AreComparersEqual(this, s)) { //first do a merge sort to an array. T[] merged = new T[this.Count]; int c = 0; Enumerator mine = this.GetEnumerator(); Enumerator theirs = s.GetEnumerator(); bool mineEnded = !mine.MoveNext(), theirsEnded = !theirs.MoveNext(); T max = Max; T min = Min; while (!mineEnded && !theirsEnded && Comparer.Compare(theirs.Current, max) <= 0) { int comp = Comparer.Compare(mine.Current, theirs.Current); if (comp < 0) { mineEnded = !mine.MoveNext(); } else if (comp == 0) { merged[c++] = theirs.Current; mineEnded = !mine.MoveNext(); theirsEnded = !theirs.MoveNext(); } else { theirsEnded = !theirs.MoveNext(); } } //now merged has all c elements //safe to gc the root, we have all the elements _root = null; _root = SortedSetExt.ConstructRootFromSortedArray(merged, 0, c - 1, null); _count = c; _version++; } else { IntersectWithEnumerable(other); } } internal virtual void IntersectWithEnumerable(IEnumerable other) { //TODO: Perhaps a more space-conservative way to do this List toSave = new List(this.Count); foreach (T item in other) { if (this.Contains(item)) { toSave.Add(item); this.Remove(item); } } this.Clear(); AddAllElements(toSave); } /// /// Transform this set into its complement with the IEnumerable OTHER /// NOTE: The caller object is important as ExceptWith uses the /// comparator associated with THIS to check equality /// Throws ArgumentNullException if OTHER is null /// /// public void ExceptWith(IEnumerable other) { if (other == null) { throw new ArgumentNullException("other"); } if (_count == 0) return; if (other == this) { this.Clear(); return; } SortedSetExt asSorted = other as SortedSetExt; if (asSorted != null && AreComparersEqual(this, asSorted)) { //outside range, no point doing anything if (!(_comparer.Compare(asSorted.Max, this.Min) < 0 || _comparer.Compare(asSorted.Min, this.Max) > 0)) { T min = this.Min; T max = this.Max; foreach (T item in other) { if (_comparer.Compare(item, min) < 0) continue; if (_comparer.Compare(item, max) > 0) break; Remove(item); } } } else { RemoveAllElements(other); } } /// /// Transform this set so it contains elements in THIS or OTHER but not both /// NOTE: The caller object is important as SymmetricExceptWith uses the /// comparator associated with THIS to check equality /// Throws ArgumentNullException if OTHER is null /// /// public void SymmetricExceptWith(IEnumerable other) { if (other == null) { throw new ArgumentNullException("other"); } if (this.Count == 0) { this.UnionWith(other); return; } if (other == this) { this.Clear(); return; } SortedSetExt asSorted = other as SortedSetExt; if (asSorted != null && AreComparersEqual(this, asSorted)) { SymmetricExceptWithSameEC(asSorted); } else { //need perf improvement on this T[] elements = (new List(other)).ToArray(); Array.Sort(elements, this.Comparer); SymmetricExceptWithSameEC(elements); } } //OTHER must be a set internal void SymmetricExceptWithSameEC(ISet other) { foreach (T item in other) { //yes, it is classier to say //if (!this.Remove(item))this.Add(item); //but this ends up saving on rotations if (this.Contains(item)) { this.Remove(item); } else { this.Add(item); } } } //OTHER must be a sorted array internal void SymmetricExceptWithSameEC(T[] other) { if (other.Length == 0) { return; } T last = other[0]; for (int i = 0; i < other.Length; i++) { while (i < other.Length && i != 0 && _comparer.Compare(other[i], last) == 0) i++; if (i >= other.Length) break; if (this.Contains(other[i])) { this.Remove(other[i]); } else { this.Add(other[i]); } last = other[i]; } } /// /// Checks whether this Tree is a subset of the IEnumerable other /// /// /// public bool IsSubsetOf(IEnumerable other) { if (other == null) { throw new ArgumentNullException("other"); } if (Count == 0) return true; SortedSetExt asSorted = other as SortedSetExt; if (asSorted != null && AreComparersEqual(this, asSorted)) { if (this.Count > asSorted.Count) return false; return IsSubsetOfSortedSetWithSameEC(asSorted); } else { //worst case: mark every element in my set and see if i've counted all //O(MlogN) ElementCount result = CheckUniqueAndUnfoundElements(other, false); return (result.uniqueCount == Count && result.unfoundCount >= 0); } } private bool IsSubsetOfSortedSetWithSameEC(SortedSetExt asSorted) { SortedSetExt prunedOther = asSorted.GetViewBetween(this.Min, this.Max); foreach (T item in this) { if (!prunedOther.Contains(item)) return false; } return true; } /// /// Checks whether this Tree is a proper subset of the IEnumerable other /// /// /// public bool IsProperSubsetOf(IEnumerable other) { if (other == null) { throw new ArgumentNullException("other"); } if ((other as ICollection) != null) { if (Count == 0) return (other as ICollection).Count > 0; } //another for sorted sets with the same comparer SortedSetExt asSorted = other as SortedSetExt; if (asSorted != null && AreComparersEqual(this, asSorted)) { if (this.Count >= asSorted.Count) return false; return IsSubsetOfSortedSetWithSameEC(asSorted); } //worst case: mark every element in my set and see if i've counted all //O(MlogN). ElementCount result = CheckUniqueAndUnfoundElements(other, false); return (result.uniqueCount == Count && result.unfoundCount > 0); } /// /// Checks whether this Tree is a super set of the IEnumerable other /// /// /// public bool IsSupersetOf(IEnumerable other) { if (other == null) { throw new ArgumentNullException("other"); } if ((other as ICollection) != null && (other as ICollection).Count == 0) return true; //do it one way for HashSets //another for sorted sets with the same comparer SortedSetExt asSorted = other as SortedSetExt; if (asSorted != null && AreComparersEqual(this, asSorted)) { if (this.Count < asSorted.Count) return false; SortedSetExt pruned = GetViewBetween(asSorted.Min, asSorted.Max); foreach (T item in asSorted) { if (!pruned.Contains(item)) return false; } return true; } //and a third for everything else return ContainsAllElements(other); } /// /// Checks whether this Tree is a proper super set of the IEnumerable other /// /// /// public bool IsProperSupersetOf(IEnumerable other) { if (other == null) { throw new ArgumentNullException("other"); } if (Count == 0) return false; if ((other as ICollection) != null && (other as ICollection).Count == 0) return true; //another way for sorted sets SortedSetExt asSorted = other as SortedSetExt; if (asSorted != null && AreComparersEqual(asSorted, this)) { if (asSorted.Count >= this.Count) return false; SortedSetExt pruned = GetViewBetween(asSorted.Min, asSorted.Max); foreach (T item in asSorted) { if (!pruned.Contains(item)) return false; } return true; } //worst case: mark every element in my set and see if i've counted all //O(MlogN) //slight optimization, put it into a HashSet and then check can do it in O(N+M) //but slower in better cases + wastes space ElementCount result = CheckUniqueAndUnfoundElements(other, true); return (result.uniqueCount < Count && result.unfoundCount == 0); } /// /// Checks whether this Tree has all elements in common with IEnumerable other /// /// /// public bool SetEquals(IEnumerable other) { if (other == null) { throw new ArgumentNullException("other"); } SortedSetExt asSorted = other as SortedSetExt; if (asSorted != null && AreComparersEqual(this, asSorted)) { IEnumerator mine = this.GetEnumerator(); IEnumerator theirs = asSorted.GetEnumerator(); bool mineEnded = !mine.MoveNext(); bool theirsEnded = !theirs.MoveNext(); while (!mineEnded && !theirsEnded) { if (Comparer.Compare(mine.Current, theirs.Current) != 0) { return false; } mineEnded = !mine.MoveNext(); theirsEnded = !theirs.MoveNext(); } return mineEnded && theirsEnded; } //worst case: mark every element in my set and see if i've counted all //O(N) by size of other ElementCount result = CheckUniqueAndUnfoundElements(other, true); return (result.uniqueCount == Count && result.unfoundCount == 0); } /// /// Checks whether this Tree has any elements in common with IEnumerable other /// /// /// public bool Overlaps(IEnumerable other) { if (other == null) { throw new ArgumentNullException("other"); } if (this.Count == 0) return false; if ((other as ICollection != null) && (other as ICollection).Count == 0) return false; SortedSetExt asSorted = other as SortedSetExt; if (asSorted != null && AreComparersEqual(this, asSorted) && (_comparer.Compare(Min, asSorted.Max) > 0 || _comparer.Compare(Max, asSorted.Min) < 0)) { return false; } foreach (T item in other) { if (this.Contains(item)) { return true; } } return false; } /// /// This works similar to HashSet's CheckUniqueAndUnfound (description below), except that the bit /// array maps differently than in the HashSet. We can only use this for the bulk boolean checks. /// /// Determines counts that can be used to determine equality, subset, and superset. This /// is only used when other is an IEnumerable and not a HashSet. If other is a HashSet /// these properties can be checked faster without use of marking because we can assume /// other has no duplicates. /// /// The following count checks are performed by callers: /// 1. Equals: checks if unfoundCount = 0 and uniqueFoundCount = Count; i.e. everything /// in other is in this and everything in this is in other /// 2. Subset: checks if unfoundCount >= 0 and uniqueFoundCount = Count; i.e. other may /// have elements not in this and everything in this is in other /// 3. Proper subset: checks if unfoundCount > 0 and uniqueFoundCount = Count; i.e /// other must have at least one element not in this and everything in this is in other /// 4. Proper superset: checks if unfound count = 0 and uniqueFoundCount strictly less /// than Count; i.e. everything in other was in this and this had at least one element /// not contained in other. /// /// An earlier implementation used delegates to perform these checks rather than returning /// an ElementCount struct; however this was changed due to the perf overhead of delegates. /// /// /// Allows us to finish faster for equals and proper superset /// because unfoundCount must be 0. /// // // // // // // private unsafe ElementCount CheckUniqueAndUnfoundElements(IEnumerable other, bool returnIfUnfound) { ElementCount result; // need special case in case this has no elements. if (Count == 0) { int numElementsInOther = 0; foreach (T item in other) { numElementsInOther++; // break right away, all we want to know is whether other has 0 or 1 elements break; } result.uniqueCount = 0; result.unfoundCount = numElementsInOther; return result; } int originalLastIndex = Count; int intArrayLength = BitHelperExt.ToIntArrayLength(originalLastIndex); BitHelperExt bitHelper; if (intArrayLength <= StackAllocThreshold) { int* bitArrayPtr = stackalloc int[intArrayLength]; bitHelper = new BitHelperExt(bitArrayPtr, intArrayLength); } else { int[] bitArray = new int[intArrayLength]; bitHelper = new BitHelperExt(bitArray, intArrayLength); } // count of items in other not found in this int unfoundCount = 0; // count of unique items in other found in this int uniqueFoundCount = 0; foreach (T item in other) { int index = InternalIndexOf(item); if (index >= 0) { if (!bitHelper.IsMarked(index)) { // item hasn't been seen yet bitHelper.MarkBit(index); uniqueFoundCount++; } } else { unfoundCount++; if (returnIfUnfound) { break; } } } result.uniqueCount = uniqueFoundCount; result.unfoundCount = unfoundCount; return result; } public int RemoveWhere(Predicate match) { if (match == null) { throw new ArgumentNullException("match"); } List matches = new List(this.Count); BreadthFirstTreeWalk(delegate (Node n) { if (match(n.Item)) { matches.Add(n.Item); } return true; }); // reverse breadth first to (try to) incur low cost int actuallyRemoved = 0; for (int i = matches.Count - 1; i >= 0; i--) { if (this.Remove(matches[i])) { actuallyRemoved++; } } return actuallyRemoved; } #endregion #region ISorted Members public T Min { get { T ret = default(T); InOrderTreeWalk(delegate (SortedSetExt.Node n) { ret = n.Item; return false; }); return ret; } } public T Max { get { T ret = default(T); InOrderTreeWalk(delegate (SortedSetExt.Node n) { ret = n.Item; return false; }, true); return ret; } } public IEnumerable Reverse() { Enumerator e = new Enumerator(this, true); while (e.MoveNext()) { yield return e.Current; } } /// /// Returns a subset of this tree ranging from values lBound to uBound /// Any changes made to the subset reflect in the actual tree /// /// Lowest Value allowed in the subset /// Highest Value allowed in the subset public virtual SortedSetExt GetViewBetween(T lowerValue, T upperValue) { if (Comparer.Compare(lowerValue, upperValue) > 0) { throw new ArgumentException("lowerBound is greater than upperBound"); } return new TreeSubSet(this, lowerValue, upperValue, true, true); } public bool TryFindGreater(T lowerValue, out T result) { var tup = FindNeighbours(lowerValue); if (tup.Item3 != null) { result = tup.Item3.Item; return true; } else { result = default(T); return false; } } public bool TryFindSmaller(T upperValue, out T result) { var tup = FindNeighbours(upperValue); if (tup.Item1 != null) { result = tup.Item1.Item; return true; } else { result = default(T); return false; } } public void FindNeighbours(T value, out Optional lower, out Optional self, out Optional upper) { var tup = FindNeighbours(value); if (tup.Item1 != null) lower = new Optional(tup.Item1.Item); else lower = Optional.None; if (tup.Item2 != null) self = new Optional(tup.Item2.Item); else self = Optional.None; if (tup.Item3 != null) upper = new Optional(tup.Item3.Item); else upper = Optional.None; } /// /// Find the neighbours of the given value /// returns (hasLower, hasValue, hasUpper) and the corresponding values in the out p /// public (bool, bool, bool) FindNeighboursV(T value, out T lower, out T self, out T upper) { var (l, s, u) = FindNeighbours(value); lower = l != null ? l.Item : default; self = s != null ? s.Item : default; upper = u != null ? u.Item : default; return (l != null, s != null, u != null); } /// /// Checks if the value is present in the set and returns the value (might be different to the value passed in when using custom IComparer) /// public bool FindValue(T value, out T result) { var val = FindNode(value); result = val != null ? val.Item : default; return val != null; } #if DEBUG /// /// debug status to be checked whenever any operation is called /// /// internal virtual bool versionUpToDate() { return true; } #endif /// /// This class represents a subset view into the tree. Any changes to this view /// are reflected in the actual tree. Uses the Comparator of the underlying tree. /// internal sealed class TreeSubSet : SortedSetExt { private readonly SortedSetExt _underlying; private readonly T _min, _max; //these exist for unbounded collections //for instance, you could allow this subset to be defined for i>10. The set will throw if //anything <=10 is added, but there is no upperbound. These features Head(), Tail(), were punted //in the spec, and are not available, but the framework is there to make them available at some point. private readonly bool _lBoundActive, _uBoundActive; //used to see if the count is out of date #if DEBUG internal override bool versionUpToDate() { return (_version == _underlying._version); } #endif public TreeSubSet(SortedSetExt Underlying, T Min, T Max, bool lowerBoundActive, bool upperBoundActive) : base(Underlying.Comparer) { _underlying = Underlying; _min = Min; _max = Max; _lBoundActive = lowerBoundActive; _uBoundActive = upperBoundActive; _root = _underlying.FindRange(_min, _max, _lBoundActive, _uBoundActive); // root is first element within range _count = 0; _version = -1; VersionCheckImpl(); } /// /// Additions to this tree need to be added to the underlying tree as well /// internal override bool AddIfNotPresent(T item) { if (!IsWithinRange(item)) { throw new ArgumentOutOfRangeException("collection"); } bool ret = _underlying.AddIfNotPresent(item); VersionCheck(); #if DEBUG Debug.Assert(this.versionUpToDate() && _root == _underlying.FindRange(_min, _max)); #endif return ret; } public override bool Contains(T item) { VersionCheck(); #if DEBUG Debug.Assert(this.versionUpToDate() && _root == _underlying.FindRange(_min, _max)); #endif return base.Contains(item); } internal override bool DoRemove(T item) { // todo: uppercase this and others if (!IsWithinRange(item)) { return false; } bool ret = _underlying.Remove(item); VersionCheck(); #if DEBUG Debug.Assert(this.versionUpToDate() && _root == _underlying.FindRange(_min, _max)); #endif return ret; } public override void Clear() { if (_count == 0) { return; } List toRemove = new List(); BreadthFirstTreeWalk(delegate (Node n) { toRemove.Add(n.Item); return true; }); while (toRemove.Count != 0) { _underlying.Remove(toRemove[toRemove.Count - 1]); toRemove.RemoveAt(toRemove.Count - 1); } _root = null; _count = 0; _version = _underlying._version; } internal override bool IsWithinRange(T item) { int comp = (_lBoundActive ? Comparer.Compare(_min, item) : -1); if (comp > 0) { return false; } comp = (_uBoundActive ? Comparer.Compare(_max, item) : 1); if (comp < 0) { return false; } return true; } internal override bool InOrderTreeWalk(TreeWalkPredicate action, Boolean reverse) { VersionCheck(); if (_root == null) { return true; } // The maximum height of a red-black tree is 2*lg(n+1). // See page 264 of "Introduction to algorithms" by Thomas H. Cormen Stack stack = new Stack(2 * (int)SortedSetExt.log2(_count + 1)); //this is not exactly right if count is out of date, but the stack can grow Node current = _root; while (current != null) { if (IsWithinRange(current.Item)) { stack.Push(current); current = (reverse ? current.Right : current.Left); } else if (_lBoundActive && Comparer.Compare(_min, current.Item) > 0) { current = current.Right; } else { current = current.Left; } } while (stack.Count != 0) { current = stack.Pop(); if (!action(current)) { return false; } Node node = (reverse ? current.Left : current.Right); while (node != null) { if (IsWithinRange(node.Item)) { stack.Push(node); node = (reverse ? node.Right : node.Left); } else if (_lBoundActive && Comparer.Compare(_min, node.Item) > 0) { node = node.Right; } else { node = node.Left; } } } return true; } internal override bool BreadthFirstTreeWalk(TreeWalkPredicate action) { VersionCheck(); if (_root == null) { return true; } Queue processQueue = new Queue(); processQueue.Enqueue(_root); Node current; while (processQueue.Count != 0) { current = processQueue.Dequeue(); if (IsWithinRange(current.Item) && !action(current)) { return false; } if (current.Left != null && (!_lBoundActive || Comparer.Compare(_min, current.Item) < 0)) { processQueue.Enqueue(current.Left); } if (current.Right != null && (!_uBoundActive || Comparer.Compare(_max, current.Item) > 0)) { processQueue.Enqueue(current.Right); } } return true; } internal override SortedSetExt.Node FindNode(T item) { if (!IsWithinRange(item)) { return null; } VersionCheck(); #if DEBUG Debug.Assert(this.versionUpToDate() && _root == _underlying.FindRange(_min, _max)); #endif return base.FindNode(item); } //this does indexing in an inefficient way compared to the actual sortedset, but it saves a //lot of space internal override int InternalIndexOf(T item) { int count = -1; foreach (T i in this) { count++; if (Comparer.Compare(item, i) == 0) return count; } #if DEBUG Debug.Assert(this.versionUpToDate() && _root == _underlying.FindRange(_min, _max)); #endif return -1; } /// /// checks whether this subset is out of date. updates if necessary. /// internal override void VersionCheck() { VersionCheckImpl(); } private void VersionCheckImpl() { Debug.Assert(_underlying != null, "Underlying set no longer exists"); if (_version != _underlying._version) { _root = _underlying.FindRange(_min, _max, _lBoundActive, _uBoundActive); _version = _underlying._version; _count = 0; InOrderTreeWalk(delegate (Node n) { _count++; return true; }); } } //This passes functionality down to the underlying tree, clipping edges if necessary //There's nothing gained by having a nested subset. May as well draw it from the base //Cannot increase the bounds of the subset, can only decrease it public override SortedSetExt GetViewBetween(T lowerValue, T upperValue) { if (_lBoundActive && Comparer.Compare(_min, lowerValue) > 0) { //lBound = min; throw new ArgumentOutOfRangeException("lowerValue"); } if (_uBoundActive && Comparer.Compare(_max, upperValue) < 0) { //uBound = max; throw new ArgumentOutOfRangeException("upperValue"); } TreeSubSet ret = (TreeSubSet)_underlying.GetViewBetween(lowerValue, upperValue); return ret; } internal override void IntersectWithEnumerable(IEnumerable other) { List toSave = new List(this.Count); foreach (T item in other) { if (this.Contains(item)) { toSave.Add(item); this.Remove(item); } } this.Clear(); this.AddAllElements(toSave); #if DEBUG Debug.Assert(this.versionUpToDate() && _root == _underlying.FindRange(_min, _max)); #endif } } #endregion #region Helper Classes internal sealed class Node { public bool IsRed; public T Item; public Node Left; public Node Right; public Node(T item) { // The default color will be red, we never need to create a black node directly. this.Item = item; IsRed = true; } public Node(T item, bool isRed) { // The default color will be red, we never need to create a black node directly. this.Item = item; this.IsRed = isRed; } } [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", Justification = "not an expected scenario")] public struct Enumerator : IEnumerator, IEnumerator { private readonly SortedSetExt _tree; private readonly int _version; private readonly Stack.Node> _stack; private SortedSetExt.Node _current; //private static SortedSetExt.Node s_dummyNode = new SortedSetExt.Node(default(T)); private readonly bool _reverse; internal Enumerator(SortedSetExt set) { _tree = set; //this is a hack to make sure that the underlying subset has not been changed since //TODO: more elegant way to ensure failfast on concurrency failures _tree.VersionCheck(); _version = _tree._version; // 2lg(n + 1) is the maximum height _stack = new Stack.Node>(2 * (int)SortedSetExt.log2(set.Count + 1)); _current = null; _reverse = false; Intialize(); } internal Enumerator(SortedSetExt set, bool reverse) { _tree = set; //this is a hack to make sure that the underlying subset has not been changed since //TODO: more elegant way to ensure failfast on concurrency failures _tree.VersionCheck(); _version = _tree._version; // 2lg(n + 1) is the maximum height _stack = new Stack.Node>(2 * (int)SortedSetExt.log2(set.Count + 1)); _current = null; _reverse = reverse; Intialize(); } private void Intialize() { _current = null; SortedSetExt.Node node = _tree._root; Node next = null, other = null; while (node != null) { next = (_reverse ? node.Right : node.Left); other = (_reverse ? node.Left : node.Right); if (_tree.IsWithinRange(node.Item)) { _stack.Push(node); node = next; } else if (next == null || !_tree.IsWithinRange(next.Item)) { node = other; } else { node = next; } } } public bool MoveNext() { //this is a hack to make sure that the underlying subset has not been changed since //TODO: more elegant way to ensure failfast on concurrency failures _tree.VersionCheck(); if (_version != _tree._version) { throw new InvalidOperationException("SR.InvalidOperation_EnumFailedVersion"); } if (_stack.Count == 0) { _current = null; return false; } _current = _stack.Pop(); SortedSetExt.Node node = (_reverse ? _current.Left : _current.Right); Node next = null, other = null; while (node != null) { next = (_reverse ? node.Right : node.Left); other = (_reverse ? node.Left : node.Right); if (_tree.IsWithinRange(node.Item)) { _stack.Push(node); node = next; } else if (other == null || !_tree.IsWithinRange(other.Item)) { node = next; } else { node = other; } } return true; } public readonly void Dispose() { } public readonly T Current { get { if (_current != null) { return _current.Item; } return default(T); } } readonly object IEnumerator.Current { get { if (_current == null) { throw new InvalidOperationException("SR.InvalidOperation_EnumOpCantHappen"); } return _current.Item; } } internal readonly bool NotStartedOrEnded { get { return _current == null; } } internal void Reset() { if (_version != _tree._version) { throw new InvalidOperationException("SR.InvalidOperation_EnumFailedVersion"); } _stack.Clear(); Intialize(); } void IEnumerator.Reset() { Reset(); } } internal struct ElementCount { internal int uniqueCount; internal int unfoundCount; } #endregion #region misc // used for set checking operations (using enumerables) that rely on counting private static int log2(int value) { //Contract.Requires(value>0) int c = 0; while (value > 0) { c++; value >>= 1; } return c; } #endregion } /// /// A class that generates an IEqualityComparer for this SortedSet. Requires that the definition of /// equality defined by the IComparer for this SortedSet be consistent with the default IEqualityComparer /// for the type T. If not, such an IEqualityComparer should be provided through the constructor. /// internal sealed class SortedSetEqualityComparer : IEqualityComparer> { private readonly IComparer _comparer; private readonly IEqualityComparer _eqComparer; public SortedSetEqualityComparer() : this(null, null) { } public SortedSetEqualityComparer(IComparer comparer) : this(comparer, null) { } public SortedSetEqualityComparer(IEqualityComparer memberEqualityComparer) : this(null, memberEqualityComparer) { } /// /// Create a new SetEqualityComparer, given a comparer for member order and another for member equality (these /// must be consistent in their definition of equality) /// public SortedSetEqualityComparer(IComparer comparer, IEqualityComparer memberEqualityComparer) { if (comparer == null) _comparer = Comparer.Default; else _comparer = comparer; if (memberEqualityComparer == null) _eqComparer = EqualityComparer.Default; else _eqComparer = memberEqualityComparer; } // using comparer to keep equals properties in tact; don't want to choose one of the comparers public bool Equals(SortedSetExt x, SortedSetExt y) { return SortedSetExt.SortedSetEquals(x, y, _comparer); } //IMPORTANT: this part uses the fact that GetHashCode() is consistent with the notion of equality in //the set public int GetHashCode(SortedSetExt obj) { int hashCode = 0; if (obj != null) { foreach (T t in obj) { hashCode = hashCode ^ (_eqComparer.GetHashCode(t) & 0x7FFFFFFF); } } // else returns hashcode of 0 for null HashSets return hashCode; } // Equals method for the comparer itself. public override bool Equals(Object obj) { SortedSetEqualityComparer comparer = obj as SortedSetEqualityComparer; if (comparer == null) { return false; } return (_comparer == comparer._comparer); } public override int GetHashCode() { return _comparer.GetHashCode() ^ _eqComparer.GetHashCode(); } } } ================================================ FILE: src/Aardvark.Base/AlgoDat/INode.cs ================================================ using Aardvark.Base; using System; using System.Collections.Generic; using System.Linq; namespace Aardvark.VRVis { /// /// A simple hierarchical node interface without any /// notion of a traversal state. /// public interface INode { IEnumerable SubNodes { get; } } /// /// Immediately supply some basic traversal functionality. /// public static class INodeExtensions { public static int ComputeDepth(this INode self) { var subNodes = self.SubNodes; if (subNodes.Count() == 0) return 0; return 1 + subNodes.Max(x => x.ComputeDepth()); } public static IEnumerable NodesAtDepth(this INode self, int depth) where T : class { return from node in self.NodesAtDepth(depth) where node is T select node as T; } /// /// Returns all nodes of a graph that are at the same depth as a flat /// sequence. /// public static IEnumerable NodesAtDepth(this INode self, int depth) { if (depth < 0) return Enumerable.Empty(); if (depth == 0) return self.IntoIEnumerable(); var subNodes = self.SubNodes; if (depth == 1) return subNodes; return from sn in subNodes from n in sn.NodesAtDepth(depth - 1) select n; } /// /// Enumerates all nodes of this scene graph in depth first order. /// public static IEnumerable DepthFirst(this INode self) { if (self == null) return Array.Empty(); return self.DepthFirst(n => n.SubNodes); } /// /// Enumerates all nodes of type T of this scene graph in depth /// first order. /// public static IEnumerable DepthFirst(this INode self) where T : class { if (self == null) return Enumerable.Empty(); return from node in self.DepthFirst() where node is T select node as T; } /// /// Enumerates all nodes of this scene graph in breadth first order. /// public static IEnumerable BreadthFirst(this INode self) { if (self == null) return Enumerable.Empty(); return self.BreadthFirst(n => n.SubNodes); } /// /// Enumerates all nodes of type T of this scene graph in breadth /// first order. /// public static IEnumerable BreadthFirst(this INode self) where T : class { if (self == null) return Enumerable.Empty(); return from node in self.BreadthFirst() where node is T select node as T; } /// /// Enumerates descendent nodes including the node itself (uses Depth-First traversal order) /// public static IEnumerable DescendentsAndSelf(this T node) where T : class, INode { return node.DepthFirst(); } /// /// Enumerates all descendent nodes (uses Depth-First traversal order and skips first) /// public static IEnumerable Descendents(this T node) where T : class, INode { return node.DepthFirst().Skip(1); } } } ================================================ FILE: src/Aardvark.Base/AlgoDat/LruCache.cs ================================================ using System; using System.Collections.Generic; namespace Aardvark.Base { /// /// A least-recently-used cache, with specifyable capacity and per-item size-, read-, and delete /// function. The indexer is used to access items. Capacity can be changed on the fly. All /// operations are synchronized for use in multi-threaded applications. /// public class LruCache { private class Entry { public long Time; public long Size; public int Index; public TKey Key; public TValue Value; public Action DeleteAct; } private readonly object m_lock; private readonly Dict m_cache; private readonly List m_heap; private readonly Func m_sizeFun; private readonly Func m_readFun; private readonly Action m_deleteAct; private long m_capacity; private long m_time; private long m_size; /// /// Creates an LruCache with the specified capacity, per-item (Key) size function, /// per-item (Key) read function, and per-item (key/value) delete action. /// The indexer is used to access items. Capacity can be changed on the fly. All /// operations are synchronized for use in multi-threaded applications. /// public LruCache( long capacity, Func sizeFun, Func readFun, Action deleteAct = null ) { m_lock = new object(); m_cache = new Dict(); m_heap = new List(); m_sizeFun = sizeFun; m_readFun = readFun; m_deleteAct = deleteAct; m_capacity = capacity; m_time = 0; m_size = 0; } public LruCache( long capacity ) { m_lock = new object(); m_cache = new Dict(); m_heap = new List(); m_sizeFun = null; m_readFun = null; m_deleteAct = null; m_capacity = capacity; m_time = 0; m_size = 0; } public long Capacity { get { return m_capacity; } set { lock (m_lock) { m_capacity = value; Shrink(m_size); } } } private void Shrink(long size) { while (size > m_capacity) { var removeKey = Dequeue(m_heap).Key; if (m_cache.TryRemove(removeKey, out Entry entry)) { m_deleteAct?.Invoke(removeKey, entry.Value); entry.DeleteAct?.Invoke(); size -= entry.Size; } else throw new InvalidOperationException("tried to remove an item that is not in the cache"); // this should never ever happen! } m_size = size; } /// /// Accessing items in the cache. If an item is not encountred in the cache, /// it is read using the read function that was specified on cache creation. /// public TValue this [TKey key] { get { Entry entry; lock (m_lock) { if (m_cache.TryGetValue(key, out entry)) { entry.Time = ++m_time; Sink(m_heap, entry.Index); } else { var size = m_sizeFun(key); Shrink(m_size + size); entry = new Entry { Time = ++m_time, Size = size, Key = key, Value = m_readFun(key) }; m_cache[key] = entry; Enqueue(m_heap, entry); } } return entry.Value; } } public TValue GetOrAdd(TKey key, long size, Func valueFun, Action deleteAct = null) { lock (m_lock) { if (m_cache.TryGetValue(key, out Entry entry)) { entry.Time = ++m_time; Sink(m_heap, entry.Index); } else { Shrink(m_size + size); entry = new Entry { Time = ++m_time, Size = size, Key = key, Value = valueFun(), DeleteAct = deleteAct, }; m_cache[key] = entry; Enqueue(m_heap, entry); } return entry.Value; } } /// /// Remove the entry with the supplied key from the hash. /// Returns true on success and puts the value of the /// entry into the out parameter. /// public bool TryRemove(TKey key, out TValue value) { lock (m_lock) { if (m_cache.TryRemove(key, out Entry entry)) { m_size -= entry.Size; RemoveAt(m_heap, entry.Index); if (m_deleteAct != null) m_deleteAct(key, entry.Value); value = entry.Value; return true; } value = default; return false; } } /// /// Remove the entry with the supplied key from the hash. /// Returns true on success. /// public bool Remove(TKey key) { lock (m_lock) { if (m_cache.TryRemove(key, out Entry entry)) { m_size -= entry.Size; RemoveAt(m_heap, entry.Index); m_deleteAct?.Invoke(key, entry.Value); entry.DeleteAct?.Invoke(); return true; } return false; } } /// /// Reomves an arbitrary element from the heap, and maintains the heap /// conditions. /// private static void RemoveAt(List heap, int index) { var count = heap.Count; if (count == 1) { heap.Clear(); return; } var element = heap[--count]; heap.RemoveAt(count); if (index == count) return; int i = index; while (i > 0) { int i2 = (i - 1) / 2; if (element.Time > heap[i2].Time) break; heap[i] = heap[i2]; heap[i].Index = i; i = i2; } if (i == index) { int i1 = 2 * i + 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && heap[i1].Time > heap[i2].Time) ? i2 : i1; // smaller child if (heap[ni].Time > element.Time) break; heap[i] = heap[ni]; heap[i].Index = i; i = ni; i1 = 2 * i + 1; } } heap[i] = element; heap[i].Index = i; } private static void Enqueue(List heap, Entry entry) { int i = heap.Count; heap.Add(entry); entry.Index = i; while (i > 0) { int i2 = (i - 1) / 2; if (entry.Time > heap[i2].Time) break; heap[i] = heap[i2]; heap[i].Index = i; i = i2; } heap[i] = entry; heap[i].Index = i; } /// /// Removes and returns the item at the top of the heap (i.e. the /// 0th position of the list). /// private static Entry Dequeue(List heap) { var result = heap[0]; var count = heap.Count; if (count == 1) { heap.Clear(); return result; } var entry = heap[--count]; heap.RemoveAt(count); int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && heap[i1].Time > heap[i2].Time) ? i2 : i1; // smaller child if (heap[ni].Time > entry.Time) break; heap[i] = heap[ni]; heap[i].Index = i; // track index i = ni; i1 = 2 * i + 1; } heap[i] = entry; heap[i].Index = i; // track index return result; } /// /// Sinks an item. /// private static void Sink(List heap, int i) { var count = heap.Count; var entry = heap[i]; int i1 = 2 * i + 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && heap[i1].Time > heap[i2].Time) ? i2 : i1; // smaller child if (heap[ni].Time > entry.Time) break; heap[i] = heap[ni]; heap[i].Index = i; // track index i = ni; i1 = 2 * i + 1; } heap[i] = entry; heap[i].Index = i; // track index } } } ================================================ FILE: src/Aardvark.Base/AlgoDat/Meta.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Aardvark.Base { public static class Meta { #region MetaTypes public class SimpleType { public string Name { get; set; } public string Char { get; set; } public string Read { get; set; } public string Caps { get; set; } public bool IsInteger { get; set; } public bool IsReal { get; set; } public bool IsCharOrString { get; set; } private string m_fsharpName; public string FSharpName { get => m_fsharpName ?? Name; set => m_fsharpName = value; } public SimpleType() { } public SimpleType(string name) { Name = name; Char = null; Read = null; } } public class TensorType : SimpleType { public SimpleType FieldType { get; set; } public TensorType(string name) : base(name) { Read = "Read" + name; } } public class GenericTensorType : SimpleType { public SimpleType DataType { get; set; } public SimpleType ViewType { get; set; } public SimpleType IndexType { get; set; } public SimpleType IntIndexType { get; set; } public int Dim { get; set; } public GenericTensorType(string name) : base(name) { } } public class VecType : TensorType { public int Len { get; set; } public string[] Fields { get; set; } public VecType(string name) : base(name) { } } public struct MatDims { public int Rows; public int Cols; public MatDims(int rows, int cols) { Rows = rows; Cols = cols; } } public class MatType : TensorType { public int Rows { get; set; } public int Cols { get; set; } public MatDims Dims { get { return new MatDims(Rows, Cols); } } public MatType(string name) : base(name) { } } public class TrafoType : SimpleType { public SimpleType MatType { get; set; } public TrafoType(string name) : base(name) { Read = "Read" + name; } } public class RangeType : SimpleType { public SimpleType LimitType { get; set; } public RangeType(string name) : base(name) { Read = "Read" + name; } } public class ColorType : TensorType { public int Len { get; set; } public string[] Channels { get; set; } public string[] Fields { get; set; } public bool HasAlpha { get; set; } public string MinValue { get; set; } public string MaxValue { get; set; } public ColorType(string name) : base(name) { } } #endregion public static readonly SimpleType BoolType = new SimpleType() { Name = "bool", Caps = "Bool", Read = "ReadBoolean", }; public static readonly SimpleType ByteType = new SimpleType() { Name = "byte", Caps = "Byte", Char = "b", Read = "ReadByte", FSharpName = "uint8", IsInteger = true, }; public static readonly SimpleType SByteType = new SimpleType() { Name = "sbyte", Caps = "SByte", Char = "sb", Read = "ReadSByte", FSharpName = "int8", IsInteger = true, }; public static readonly SimpleType ShortType = new SimpleType() { Name = "short", Caps = "Short", Char = "s", Read = "ReadInt16", FSharpName = "int16", IsInteger = true, }; public static readonly SimpleType UShortType = new SimpleType() { Name = "ushort", Caps = "UShort", Char = "us", Read = "ReadUInt16", FSharpName = "uint16", IsInteger = true, }; public static readonly SimpleType IntType = new SimpleType() { Name = "int", Caps = "Int", Char = "i", Read = "ReadInt32", FSharpName = "int32", IsInteger = true, }; public static readonly SimpleType UIntType = new SimpleType() { Name = "uint", Caps = "UInt", Char = "ui", Read = "ReadUInt32", FSharpName = "uint32", IsInteger = true, }; public static readonly SimpleType LongType = new SimpleType() { Name = "long", Caps = "Long", Char = "l", Read = "ReadInt64", FSharpName = "int64", IsInteger = true, }; public static readonly SimpleType ULongType = new SimpleType() { Name = "ulong", Caps = "ULong", Char = "ul", Read = "ReadUInt64", FSharpName = "uint64", IsInteger = true, }; public static readonly SimpleType HalfType = new SimpleType() { Name = "Half", Caps = "Half", Char = "h", Read = "ReadHalf", FSharpName = "float16", IsReal = true, }; public static readonly SimpleType FloatType = new SimpleType() { Name = "float", Caps = "Float", Char = "f", Read = "ReadSingle", FSharpName = "float32", IsReal = true, }; public static readonly SimpleType DoubleType = new SimpleType() { Name = "double", Caps = "Double", Char = "d", Read = "ReadDouble", FSharpName = "float", IsReal = true, }; public static readonly SimpleType DecimalType = new SimpleType() { Name = "decimal", Caps = "Decimal", Read = "ReadDecimal", }; public static readonly SimpleType CharType = new SimpleType() { Name = "Char", Read = "ReadChar", FSharpName = "char", IsCharOrString = true, }; public static readonly SimpleType StringType = new SimpleType() { Name = "String", Read = "ReadString", FSharpName = "string", IsCharOrString = true, }; public static readonly SimpleType TypeType = new SimpleType() { Name = "Type", Read = "ReadType", }; public static readonly SimpleType GuidType = new SimpleType() { Name = "Guid", Read = "ReadGuid", }; public static readonly SimpleType FractionType = new SimpleType() { Name = "Fraction", Read = "ReadFraction", }; public static readonly SimpleType DateTimeType = new SimpleType() { Name = "DateTime", }; public static readonly SimpleType TimeSpanType = new SimpleType() { Name = "TimeSpan", }; public static readonly SimpleType[] TextTypes = new[] { CharType, StringType, }; public static readonly SimpleType[] SystemTypes = new[] { CharType, StringType, TypeType, GuidType, }; public static readonly SimpleType[] TimeTypes = new[] { DateTimeType, TimeSpanType, }; public static readonly SimpleType Euclidean3fType = new SimpleType() { Name = "Euclidean3f", Read = "ReadEuclidean3f", }; public static readonly SimpleType Euclidean3dType = new SimpleType() { Name = "Euclidean3d", Read = "ReadEuclidean3d", }; public static readonly SimpleType Rot2fType = new SimpleType() { Name = "Rot2f", Read = "ReadRot2f", }; public static readonly SimpleType Rot2dType = new SimpleType() { Name = "Rot2d", Read = "ReadRot2d", }; public static readonly SimpleType Rot3fType = new SimpleType() { Name = "Rot3f", Read = "ReadRot3f", }; public static readonly SimpleType Rot3dType = new SimpleType() { Name = "Rot3d", Read = "ReadRot3d", }; public static readonly SimpleType Scale3fType = new SimpleType() { Name = "Scale3f", Read = "ReadScale3f", }; public static readonly SimpleType Scale3dType = new SimpleType() { Name = "Scale3d", Read = "ReadScale3d", }; public static readonly SimpleType Shift3fType = new SimpleType() { Name = "Shift3f", Read = "ReadShift3f", }; public static readonly SimpleType Shift3dType = new SimpleType() { Name = "Shift3d", Read = "ReadShift3d", }; public static readonly SimpleType Trafo2fType = new SimpleType() { Name = "Trafo2f", Read = "ReadTrafo2f", }; public static readonly SimpleType Trafo2dType = new SimpleType() { Name = "Trafo2d", Read = "ReadTrafo2d", }; public static readonly SimpleType Trafo3fType = new SimpleType() { Name = "Trafo3f", Read = "ReadTrafo3f", }; public static readonly SimpleType Trafo3dType = new SimpleType() { Name = "Trafo3d", Read = "ReadTrafo3d", }; public static readonly SimpleType[] IntegerTypes = new SimpleType[] { ByteType, SByteType, ShortType, UShortType, IntType, UIntType, LongType, ULongType, }; public static readonly SimpleType[] IndexTypes = new SimpleType[] { IntType, LongType, }; public static readonly SimpleType[] RealTypes = new SimpleType[] { FloatType, DoubleType, }; public static readonly SimpleType[] SignedTypes = new SimpleType[] { SByteType, ShortType, IntType, LongType, FloatType, DoubleType, DecimalType, }; public static readonly SimpleType[] UnsignedTypes = new SimpleType[] { ByteType, UShortType, UIntType, ULongType, }; public static readonly SimpleType[] FloatRepresentableTypes = new SimpleType[] { ByteType, SByteType, ShortType, UShortType, FloatType }; public static readonly SimpleType[] DoubleRepresentableTypes = new SimpleType[] { ByteType, SByteType, ShortType, UShortType, IntType, UIntType, FloatType, DoubleType }; public static readonly Dictionary RealRepresentableTypes = new Dictionary() { { FloatType, FloatRepresentableTypes }, { DoubleType, DoubleRepresentableTypes } }; public static readonly SimpleType[] TrafoTypes = new SimpleType[] { Euclidean3fType, Euclidean3dType, Rot2fType, Rot2dType, Rot3fType, Rot3dType, Scale3fType, Scale3dType, Shift3fType, Shift3dType, Trafo2fType, Trafo2dType, Trafo3fType, Trafo3dType, }; public static readonly string[] VecFields = new string[] { "X", "Y", "Z", "W", }; public static readonly string[] VecArgs = new string[] { "x", "y", "z", "w", }; public static readonly SimpleType[] VecFieldTypes = new SimpleType[] { IntType, UIntType, LongType, FloatType, DoubleType, }; public static readonly SimpleType[] SignedVecFieldTypes = VecFieldTypes.Where(t => !UnsignedTypes.Contains(t)).ToArray(); public static readonly SimpleType[] MatFieldTypes = SignedVecFieldTypes; public static readonly string[] ColorFields = new string[] { "R", "G", "B", "A", }; public static readonly string[] ColorArgs = new string[] { "r", "g", "b", "a", }; public static readonly SimpleType[] ColorFieldTypes = new SimpleType[] { ByteType, UShortType, UIntType, FloatType, DoubleType }; public static readonly SimpleType[] ColorConvertibleTypes = new SimpleType[] { ByteType, UShortType, UIntType, HalfType, FloatType, DoubleType }; public static readonly Dictionary ColorConvertibleTypeMinValue = new Dictionary() { { ByteType, "0" }, { UShortType, "0" }, { UIntType, "0" }, { HalfType, "Half.Zero" }, { FloatType, "0.0f" }, { DoubleType, "0" }, }; public static readonly Dictionary ColorConvertibleTypeMaxValue = new Dictionary() { { ByteType, "255" }, { UShortType, "65535" }, { UIntType, "UInt32.MaxValue" }, { HalfType, "Half.One" }, { FloatType, "1.0f" }, { DoubleType, "1.0" } }; public static readonly int[] VecTypeDimensions = new[] { 2, 3, 4 }; private static readonly Dictionary[] VecTypeMapArray; public static readonly VecType[] VecTypes; public static readonly VecType[] SignedVecTypes; public static VecType VecTypeOf(int dimensions, SimpleType fieldType) { return VecTypeMapArray[dimensions][fieldType]; } public static VecType TryGetVecTypeOf(int dimensions, SimpleType fieldType) { if (dimensions >= 0 && dimensions < VecTypeMapArray.Length) { if (VecTypeMapArray[dimensions].TryGetValue(fieldType, out var result)) return result; } return null; } public static readonly MatDims[] MatTypeDimensions = new[] { new MatDims(2, 2), new MatDims(2, 3), new MatDims(3, 3), new MatDims(3, 4), new MatDims(4, 4), }; private static readonly Dictionary[,] MatTypeMapArray; public static MatType MatTypeOf(int rows, int cols, SimpleType fieldType) { return MatTypeMapArray[rows, cols][fieldType]; } public static readonly MatType[] MatTypes; public static readonly RangeType[] RangeTypes; public static readonly RangeType[] BoxTypes; public static readonly RangeType[] RangeAndBoxTypes; public static readonly int[] ColorTypeDimensions = new[] { 3, 4 }; private static readonly Dictionary[] ColorTypeMapArray; public static readonly ColorType[] ColorTypes; public static ColorType ColorTypeOf(int dim, SimpleType fieldType) { return ColorTypeMapArray[dim][fieldType]; } public static readonly SimpleType[] NumericTypes; public static readonly SimpleType[] BuiltInTypes; public static readonly SimpleType[] StandardNumericTypes; public static readonly SimpleType[] BuiltInNumericTypes; public static readonly SimpleType[] ComparableTypes; private static readonly Dictionary ComputationTypeMap = new Dictionary() { { ByteType, DoubleType }, { UIntType, DoubleType}, { UShortType, DoubleType}, { IntType, DoubleType }, { LongType, DoubleType }, }; public static SimpleType ComputationTypeOf(SimpleType type) { SimpleType computationType; if (ComputationTypeMap.TryGetValue(type, out computationType)) return computationType; return type; } private static readonly Dictionary HighPrecisionTypeMap = new Dictionary() { { ByteType, IntType }, { UShortType, IntType }, { UIntType, LongType }, { IntType, LongType }, { FloatType, DoubleType }, }; public static SimpleType HighPrecisionTypeOf(SimpleType type) { SimpleType result; if (HighPrecisionTypeMap.TryGetValue(type, out result)) return result; return type; } private static readonly Dictionary SummationTypeMap = new Dictionary() { { ByteType, IntType }, { SByteType, IntType }, { ShortType, LongType }, { UShortType, LongType }, { IntType, LongType }, { UIntType, LongType }, { FloatType, DoubleType }, { DoubleType, DoubleType }, }; public static SimpleType SummationTypeOf(SimpleType type) { SimpleType summationType; if (SummationTypeMap.TryGetValue(type, out summationType)) return summationType; return type; } public static readonly SimpleType[] StructTypes; public static readonly SimpleType TViewType = new SimpleType("Tv"); public static readonly SimpleType TDataType = new SimpleType("Td"); public static readonly GenericTensorType VectorType; public static readonly GenericTensorType VectorWithViewType; public static readonly GenericTensorType MatrixType; public static readonly GenericTensorType MatrixWithViewType; public static readonly GenericTensorType VolumeType; public static readonly GenericTensorType VolumeWithViewType; public static readonly GenericTensorType Tensor4Type; public static readonly GenericTensorType Tensor4WithViewType; public static readonly GenericTensorType[] GenericTensorTypes; public static readonly SimpleType[] DirectlyCodeableBuiltinTypes; public static readonly SimpleType[] DirectlyCodeableTypes; private static readonly Dictionary s_typeNameSeparatorMap = new Dictionary { { " ", "" }, { "[]", "Array" }, { "[,]", "Array2d" }, { "[,,]", "Array3d" }, { "<", "_of_" }, { ",", "_" }, { ">", "_" }, }; private static readonly Dictionary s_typeNameIdentifierMap = new Dictionary(); public static string GetXmlTypeName(string typeName) { typeName = typeName.ReplaceIdentifiers(s_typeNameIdentifierMap); foreach (var kvp in s_typeNameSeparatorMap) typeName = typeName.Replace(kvp.Key, kvp.Value); return typeName; } static Meta() { #region VecTypes var vectorTypes = new List(); VecTypeMapArray = new Dictionary[5]; foreach (var n in VecTypeDimensions) { var typeMap = new Dictionary(); foreach (var ft in VecFieldTypes) { var t = new VecType("V" + n + ft.Char) { Len = n, FieldType = ft, Fields = VecFields.Take(n).ToArray(), }; typeMap[ft] = t; vectorTypes.Add(t); } VecTypeMapArray[n] = typeMap; } VecTypes = vectorTypes.ToArray(); SignedVecTypes = vectorTypes.Where(t => !UnsignedTypes.Contains(t.FieldType)).ToArray(); #endregion #region MatTypes var matrixTypes = new List(); MatTypeMapArray = new Dictionary[5, 5]; foreach (var dim in MatTypeDimensions) { var typeMap = new Dictionary(); foreach (var ft in MatFieldTypes) { var t = new MatType("M" + dim.Rows + dim.Cols + ft.Char) { Rows = dim.Rows, Cols = dim.Cols, FieldType = ft }; typeMap[ft] = t; matrixTypes.Add(t); } MatTypeMapArray[dim.Rows, dim.Cols] = typeMap; } MatTypes = matrixTypes.ToArray(); #endregion VectorType = new GenericTensorType("Vector") { DataType = TDataType, ViewType = TDataType, Dim = 1, IndexType = LongType, IntIndexType = IntType, }; VectorWithViewType = new GenericTensorType("Vector") { DataType = TDataType, ViewType = TViewType, Dim = 1, IndexType = LongType, IntIndexType = IntType, }; MatrixType = new GenericTensorType("Matrix") { DataType = TDataType, ViewType = TDataType, Dim = 2, IndexType = VecTypeOf(2, LongType), IntIndexType = VecTypeOf(2, IntType), }; MatrixWithViewType = new GenericTensorType("Matrix") { DataType = TDataType, ViewType = TViewType, Dim = 2, IndexType = VecTypeOf(2, LongType), IntIndexType = VecTypeOf(2, IntType), }; VolumeType = new GenericTensorType("Volume") { DataType = TDataType, ViewType = TDataType, Dim = 3, IndexType = VecTypeOf(3, LongType), IntIndexType = VecTypeOf(3, IntType), }; VolumeWithViewType = new GenericTensorType("Volume") { DataType = TDataType, ViewType = TViewType, Dim = 3, IndexType = VecTypeOf(3, LongType), IntIndexType = VecTypeOf(3, IntType), }; Tensor4Type = new GenericTensorType("Tensor4") { DataType = TDataType, ViewType = TDataType, Dim = 4, IndexType = VecTypeOf(4, LongType), IntIndexType = VecTypeOf(4, IntType), }; Tensor4WithViewType = new GenericTensorType("Tensor4") { DataType = TDataType, ViewType = TViewType, Dim = 4, IndexType = VecTypeOf(4, LongType), IntIndexType = VecTypeOf(4, IntType), }; GenericTensorTypes = new GenericTensorType[] { VectorType, VectorWithViewType, MatrixType, MatrixWithViewType, VolumeType, VolumeWithViewType, Tensor4Type, Tensor4WithViewType, }; RangeTypes = GenerateRangeTypes().ToArray(); BoxTypes = GenerateBoxTypes().ToArray(); RangeAndBoxTypes = RangeTypes.Concat(BoxTypes).ToArray(); #region ColorTypes var colorTypes = new List(); ColorTypeMapArray = new Dictionary[5]; foreach (var n in ColorTypeDimensions) { var typeMap = new Dictionary(); foreach (var ft in ColorFieldTypes) { var t = new ColorType("C" + n + ft.Char) { Len = n, FieldType = ft, Fields = ColorFields.Take(n).ToArray(), Channels = ColorFields.Take(3).ToArray(), HasAlpha = n == 4, MinValue = ColorConvertibleTypeMinValue[ft], MaxValue = ColorConvertibleTypeMaxValue[ft], }; typeMap[ft] = t; colorTypes.Add(t); } ColorTypeMapArray[n] = typeMap; } ColorTypes = colorTypes.ToArray(); #endregion DirectlyCodeableBuiltinTypes = IntegerTypes.Concat(RealTypes).ToArray(); BuiltInTypes = BoolType.IntoArray() .Concat(DirectlyCodeableBuiltinTypes) .ToArray(); StandardNumericTypes = IntegerTypes .Concat(RealTypes) .ToArray(); foreach (var t in StandardNumericTypes) s_typeNameIdentifierMap[t.Name] = t.Caps; foreach (var t in TextTypes) s_typeNameIdentifierMap[t.Name.ToLower()] = t.Name; s_typeNameIdentifierMap[BoolType.Name] = BoolType.Caps; BuiltInNumericTypes = StandardNumericTypes .Concat(DecimalType.IntoArray()) .ToArray(); NumericTypes = StandardNumericTypes .Concat(FractionType.IntoArray()) .ToArray(); ComparableTypes = StandardNumericTypes .Concat(DecimalType.IntoArray()) .Concat(FractionType.IntoArray()) .Concat(TimeTypes) .ToArray(); StructTypes = BuiltInTypes .Concat(FractionType.IntoArray()) .Concat(SystemTypes) .Concat(VecTypes) .Concat(MatTypes) .Concat(ColorTypes) .Concat(RangeAndBoxTypes) .Concat(TrafoTypes) .ToArray(); DirectlyCodeableTypes = DirectlyCodeableBuiltinTypes .Concat(FractionType.IntoArray()) .Concat(SignedVecTypes) // TODO: Also support unsigned (breaking change in interface) .Concat(MatTypes) .Concat(ColorTypes) .Concat(RangeAndBoxTypes) .Concat(TrafoTypes) .ToArray(); } private static IEnumerable GenerateRangeTypes() { foreach (var t in IntegerTypes.Concat(RealTypes)) yield return new RangeType("Range1" + t.Char) { LimitType = t }; } private static IEnumerable GenerateBoxTypes() { foreach (var vt in SignedVecTypes) if (vt.Len < 4) yield return new RangeType("Box" + vt.Len + vt.FieldType.Char) { LimitType = vt }; } public static readonly SimpleType Circle2dType = new SimpleType() { Name = "Circle2d" }; public static readonly SimpleType Line2dType = new SimpleType() { Name = "Line2d" }; public static readonly SimpleType Line3dType = new SimpleType() { Name = "Line3d" }; public static readonly SimpleType Plane2dType = new SimpleType() { Name = "Plane2d" }; public static readonly SimpleType Plane3dType = new SimpleType() { Name = "Plane3d" }; public static readonly SimpleType PlaneWithPoint3dType = new SimpleType() { Name = "PlaneWithPoint3d" }; public static readonly SimpleType Quad2dType = new SimpleType() { Name = "Quad2d" }; public static readonly SimpleType Quad3dType = new SimpleType() { Name = "Quad3d" }; public static readonly SimpleType Ray2dType = new SimpleType() { Name = "Ray2d" }; public static readonly SimpleType Ray3dType = new SimpleType() { Name = "Ray3d" }; public static readonly SimpleType Sphere3dType = new SimpleType() { Name = "Sphere3d" }; public static readonly SimpleType Triangle2dType = new SimpleType() { Name = "Triangle2d" }; public static readonly SimpleType Triangle3dType = new SimpleType() { Name = "Triangle3d" }; public static readonly SimpleType Circle2fType = new SimpleType() { Name = "Circle2f" }; public static readonly SimpleType Line2fType = new SimpleType() { Name = "Line2f" }; public static readonly SimpleType Line3fType = new SimpleType() { Name = "Line3f" }; public static readonly SimpleType Plane2fType = new SimpleType() { Name = "Plane2f" }; public static readonly SimpleType Plane3fType = new SimpleType() { Name = "Plane3f" }; public static readonly SimpleType PlaneWithPoint3fType = new SimpleType() { Name = "PlaneWithPoint3f" }; public static readonly SimpleType Quad2fType = new SimpleType() { Name = "Quad2f" }; public static readonly SimpleType Quad3fType = new SimpleType() { Name = "Quad3f" }; public static readonly SimpleType Ray2fType = new SimpleType() { Name = "Ray2f" }; public static readonly SimpleType Ray3fType = new SimpleType() { Name = "Ray3f" }; public static readonly SimpleType Sphere3fType = new SimpleType() { Name = "Sphere3f" }; public static readonly SimpleType Triangle2fType = new SimpleType() { Name = "Triangle2f" }; public static readonly SimpleType Triangle3fType = new SimpleType() { Name = "Triangle3f" }; /// /// All geometry types that need to be serialized. /// public static readonly SimpleType[] GeometryTypes = new SimpleType[] { Circle2dType, Line2dType, Line3dType, Plane2dType, Plane3dType, PlaneWithPoint3dType, Quad2dType, Quad3dType, Ray2dType, Ray3dType, Sphere3dType, Triangle2dType, Triangle3dType, Circle2fType, Line2fType, Line3fType, Plane2fType, Plane3fType, PlaneWithPoint3fType, Quad2fType, Quad3fType, Ray2fType, Ray3fType, Sphere3fType, Triangle2fType, Triangle3fType }; #region Fun related // Instead of manually copy pasting methods defined in the Fun class to work // elementwise with vectors and matrices, we simply define the methods we are interested in here. // It's a bit verbose since we require a lot of meta information, but much easier and less error-prone than // manually copy pasting the code. public class ElementwiseFun { public enum ParamType { Scalar, Tensor, } public class Parameter { public string Name { get; set; } public ParamType Type { get; set; } // Parameters can specify an element type // If null, it is generic and takes the element type of the current type // E.g. for V2i -> int public SimpleType ElementType { get; set; } public Parameter(string name, ParamType t, SimpleType et) { Name = name; Type = t; ElementType = et; } } public string Name { get; set; } // Element type of the result, if null it takes the element type of the current class // E.g. for V2i -> int public SimpleType ReturnType { get; set; } public Parameter[] Parameters { get; set; } public bool IsExtension { get; set; } public bool HasVarArgs { get; set; } public bool EditorBrowsable { get; set; } public bool Obsolete { get; set; } // Only valid for the given element types public SimpleType[] Domain { get; set; } public ElementwiseFun(string name, SimpleType returnType, bool extension, bool varArgs, SimpleType[] domain, bool editorBrowsable, bool obsolete, params Parameter[] parameters) { Name = name; ReturnType = returnType; Parameters = parameters; IsExtension = extension; HasVarArgs = varArgs; Domain = domain; EditorBrowsable = editorBrowsable; Obsolete = obsolete; } } public static bool IsScalar(this ElementwiseFun.Parameter p) { return p.Type == ElementwiseFun.ParamType.Scalar; } public static bool IsTensor(this ElementwiseFun.Parameter p) { return p.Type == ElementwiseFun.ParamType.Tensor; } private static ElementwiseFun.Parameter Scalar(string name, SimpleType t = null) { return new ElementwiseFun.Parameter(name, ElementwiseFun.ParamType.Scalar, t); } private static ElementwiseFun.Parameter Tensor(string name, SimpleType t = null) { return new ElementwiseFun.Parameter(name, ElementwiseFun.ParamType.Tensor, t); } private static ElementwiseFun.Parameter Other(string name, string typeName) { return new ElementwiseFun.Parameter(name, ElementwiseFun.ParamType.Scalar, new SimpleType(typeName)); } private static ElementwiseFun Method(string name, SimpleType returnType, SimpleType[] domain, params ElementwiseFun.Parameter[] parameters) { return new ElementwiseFun(name, returnType, true, false, domain, true, false, parameters); } private static ElementwiseFun MethodVarArgs(string name, SimpleType returnType, SimpleType[] domain, params ElementwiseFun.Parameter[] parameters) { return new ElementwiseFun(name, returnType, true, true, domain, true, false, parameters); } private static ElementwiseFun MethodHidden(string name, SimpleType returnType, SimpleType[] domain, params ElementwiseFun.Parameter[] parameters) { return new ElementwiseFun(name, returnType, true, false, domain, false, false, parameters); } private static ElementwiseFun MethodObsolete(string name, SimpleType returnType, SimpleType[] domain, params ElementwiseFun.Parameter[] parameters) { return new ElementwiseFun(name, returnType, true, false, domain, false, true, parameters); } private static ElementwiseFun Method(string name, SimpleType[] domain, params ElementwiseFun.Parameter[] parameters) { return Method(name, null, domain, parameters); } private static ElementwiseFun MethodVarArgs(string name, SimpleType[] domain, params ElementwiseFun.Parameter[] parameters) { return MethodVarArgs(name, null, domain, parameters); } private static ElementwiseFun MethodHidden(string name, SimpleType[] domain, params ElementwiseFun.Parameter[] parameters) { return new ElementwiseFun(name, null, true, false, domain, false, false, parameters); } private static ElementwiseFun MethodObsolete(string name, SimpleType[] domain, params ElementwiseFun.Parameter[] parameters) { return new ElementwiseFun(name, null, true, false, domain, false, true, parameters); } private static ElementwiseFun Method(string name, bool isExtension, SimpleType[] domain, params ElementwiseFun.Parameter[] parameters) { return new ElementwiseFun(name, null, isExtension, false, domain, true, false, parameters); } private static ElementwiseFun Method(string name, SimpleType returnType, params ElementwiseFun.Parameter[] parameters) { return new ElementwiseFun(name, returnType, true, false, VecFieldTypes, true, false, parameters); } private static ElementwiseFun Method(string name, params ElementwiseFun.Parameter[] parameters) { return Method(name, VecFieldTypes, parameters); } private static ElementwiseFun MethodVarArgs(string name, params ElementwiseFun.Parameter[] parameters) { return MethodVarArgs(name, VecFieldTypes, parameters); } private static Dictionary getElementwiseFuns() { var dict = new Dictionary(); void Add(string category, params ElementwiseFun[] funs) { dict.Add(category, funs); } SimpleType[] Domain(params SimpleType[] types) => types; SimpleType[] AllExcept(params SimpleType[] types) => types.FoldLeft(VecFieldTypes, (arr, t) => arr.WithRemoved(t)); SimpleType[] OnlyReal() => Domain(FloatType, DoubleType); SimpleType[] NotReal() => AllExcept(FloatType, DoubleType); SimpleType[] OnlySigned() => AllExcept(UIntType, ULongType); #region Min and Max Add( "Min and Max", Method("Min", Tensor("a"), Tensor("b")), Method("Min", Tensor("a"), Scalar("b")), Method("Min", Scalar("a"), Tensor("b")), Method("Max", Tensor("a"), Tensor("b")), Method("Max", Tensor("a"), Scalar("b")), Method("Max", Scalar("a"), Tensor("b")), Method("Min", Tensor("a"), Tensor("b"), Tensor("c")), Method("Max", Tensor("a"), Tensor("b"), Tensor("c")), Method("Min", Tensor("a"), Tensor("b"), Tensor("c"), Tensor("d")), Method("Max", Tensor("a"), Tensor("b"), Tensor("c"), Tensor("d")), MethodVarArgs("Min", Tensor("x"), Tensor("values")), MethodVarArgs("Max", Tensor("x"), Tensor("values")) ); #endregion #region Abs Add("Abs", Method("Abs", OnlySigned(), Tensor("x")) ); #endregion #region Rounding Add("Rounding", Method("Floor", RealTypes, Tensor("x")), Method("Ceiling", RealTypes, Tensor("x")), Method("Round", RealTypes, Tensor("x")), Method("Round", RealTypes, Tensor("x"), Other("mode", "MidpointRounding")), Method("Round", RealTypes, Tensor("x"), Other("digits", "int")), Method("Round", RealTypes, Tensor("x"), Other("digits", "int"), Other("mode", "MidpointRounding")), Method("Truncate", RealTypes, Tensor("x")) ); #endregion #region Frac Add("Frac", Method("Frac", RealTypes, Tensor("x"))); #endregion #region Clamping Add("Clamping", Method("Clamp", Tensor("x"), Tensor("a"), Tensor("b")), Method("Clamp", Tensor("x"), Scalar("a"), Scalar("b")), Method("ClampExcl", NotReal(), Tensor("x"), Tensor("a"), Tensor("b")), Method("ClampExcl", NotReal(), Tensor("x"), Scalar("a"), Scalar("b")), Method("ClampWrap", Tensor("x"), Tensor("a"), Tensor("b")), Method("ClampWrap", Tensor("x"), Scalar("a"), Scalar("b")), Method("Saturate", Tensor("x")) ); #endregion #region MapToUnitInterval Add("MapToUnitInterval", Method("MapToUnitInterval", RealTypes, Tensor("t"), Tensor("tMax"), Scalar("repeat", BoolType), Scalar("mirror", BoolType)), Method("MapToUnitInterval", RealTypes, Tensor("t"), Tensor("tMax"), Scalar("repeat", BoolType)), Method("MapToUnitInterval", RealTypes, Tensor("t"), Tensor("tMax")), Method("MapToUnitInterval", RealTypes, Tensor("t"), Tensor("tMin"), Tensor("tMax")) ); #endregion #region Sign Add("Sign", Method("Sign", IntType, OnlySigned(), Tensor("x")), Method("Signumi", IntType, OnlySigned(), Tensor("x")), Method("Signum", OnlySigned(), Tensor("x")) ); #endregion #region Multiply-Add Add("Multiply-Add", Method("MultiplyAdd", false, AllExcept(), Tensor("x"), Tensor("y"), Tensor("z")), Method("MultiplyAdd", false, AllExcept(), Tensor("x"), Scalar("y"), Tensor("z")), Method("MultiplyAdd", false, AllExcept(), Scalar("x"), Tensor("y"), Tensor("z")) ); #endregion #region Copy sign Add("Copy sign", Method("CopySign", false, RealTypes, Tensor("value"), Tensor("sign")), Method("CopySign", false, RealTypes, Scalar("value"), Tensor("sign")), Method("CopySign", false, RealTypes, Tensor("value"), Scalar("sign")) ); #endregion #region Roots Add("Roots", Method("Sqrt", RealTypes, Tensor("x")), Method("Sqrt", DoubleType, NotReal(), Tensor("x")), Method("Cbrt", RealTypes, Tensor("x")), Method("Cbrt", DoubleType, NotReal(), Tensor("x")) ); #endregion #region Square Add("Square", Method("Square", Tensor("x")) ); #endregion #region Power Add("Power", Method("Pown", NotReal(), Tensor("x"), Tensor("y")), Method("Pown", NotReal(), Tensor("x"), Scalar("y")), Method("Pown", NotReal(), Scalar("x"), Tensor("y")), Method("Pown", AllExcept(IntType), Tensor("x"), Tensor("y", IntType)), Method("Pown", AllExcept(IntType), Tensor("x"), Scalar("y", IntType)), Method("Pown", AllExcept(IntType), Scalar("x"), Tensor("y", IntType)), Method("Pow", OnlyReal(), Tensor("x"), Tensor("y")), Method("Pow", OnlyReal(), Tensor("x"), Scalar("y")), Method("Pow", OnlyReal(), Scalar("x"), Tensor("y")), Method("Pow", FloatType, NotReal(), Tensor("x"), Tensor("y", FloatType)), Method("Pow", FloatType, NotReal(), Tensor("x"), Scalar("y", FloatType)), Method("Pow", FloatType, NotReal(), Scalar("x"), Tensor("y", FloatType)), Method("Pow", DoubleType, NotReal(), Tensor("x"), Tensor("y", DoubleType)), Method("Pow", DoubleType, NotReal(), Tensor("x"), Scalar("y", DoubleType)), Method("Pow", DoubleType, NotReal(), Scalar("x"), Tensor("y", DoubleType)), MethodHidden("Power", OnlyReal(), Tensor("x"), Tensor("y")), MethodHidden("Power", OnlyReal(), Tensor("x"), Scalar("y")), MethodHidden("Power", OnlyReal(), Scalar("x"), Tensor("y")), MethodHidden("Power", FloatType, NotReal(), Tensor("x"), Tensor("y", FloatType)), MethodHidden("Power", FloatType, NotReal(), Tensor("x"), Scalar("y", FloatType)), MethodHidden("Power", FloatType, NotReal(), Scalar("x"), Tensor("y", FloatType)), MethodHidden("Power", DoubleType, NotReal(), Tensor("x"), Tensor("y", DoubleType)), MethodHidden("Power", DoubleType, NotReal(), Tensor("x"), Scalar("y", DoubleType)), MethodHidden("Power", DoubleType, NotReal(), Scalar("x"), Tensor("y", DoubleType)) ); #endregion #region Exp and Log Add("Exp and Log", Method("Exp", RealTypes, Tensor("x")), Method("Exp", DoubleType, NotReal(), Tensor("x")), Method("Log", RealTypes, Tensor("x")), Method("Log", DoubleType, NotReal(), Tensor("x")), Method("Log2", RealTypes, Tensor("x")), Method("Log2", DoubleType, NotReal(), Tensor("x")), Method("Log2Int", IntType, Tensor("x")), Method("Log10", RealTypes, Tensor("x")), Method("Log10", DoubleType, NotReal(), Tensor("x")), Method("Log", RealTypes, Tensor("x"), Scalar("basis")), Method("Log", DoubleType, NotReal(), Tensor("x"), Scalar("basis", DoubleType)) ); #endregion #region ModP Add("ModP", Method("ModP", OnlySigned(), Tensor("a"), Tensor("b"))); #endregion #region Power of Two Add("Power of Two", Method("PowerOfTwo", Domain(LongType, FloatType, DoubleType), Tensor("x")), Method("PowerOfTwo", LongType, Domain(IntType), Tensor("x")), Method("NextPowerOfTwo", Domain(IntType, LongType), Tensor("x")), Method("PrevPowerOfTwo", Domain(IntType, LongType), Tensor("x")) ); #endregion #region Trigonometry Add("Trigonometry", Method("Sin", RealTypes, Tensor("x")), Method("Cos", RealTypes, Tensor("x")), Method("Tan", RealTypes, Tensor("x")), Method("Asin", RealTypes, Tensor("x")), Method("AsinClamped", RealTypes, Tensor("x")), Method("Acos", RealTypes, Tensor("x")), Method("AcosClamped", RealTypes, Tensor("x")), Method("Atan", RealTypes, Tensor("x")), Method("Atan2", false, RealTypes, Tensor("y"), Tensor("x")), Method("FastAtan2", false, RealTypes, Tensor("y"), Tensor("x")), Method("Sinh", RealTypes, Tensor("x")), Method("Cosh", RealTypes, Tensor("x")), Method("Tanh", RealTypes, Tensor("x")), Method("Asinh", RealTypes, Tensor("x")), Method("Acosh", RealTypes, Tensor("x")), Method("Atanh", RealTypes, Tensor("x")) ); #endregion #region Step functions Add("Step functions", Method("Step", Tensor("x"), Tensor("edge")), Method("Step", Tensor("x"), Scalar("edge")), Method("Linearstep", RealTypes, Tensor("x"), Tensor("edge0"), Tensor("edge1")), Method("Linearstep", RealTypes, Tensor("x"), Scalar("edge0"), Scalar("edge1")), Method("Smoothstep", RealTypes, Tensor("x"), Tensor("edge0"), Tensor("edge1")), Method("Smoothstep", RealTypes, Tensor("x"), Scalar("edge0"), Scalar("edge1")) ); #endregion #region Interpolation Add("Interpolation", Method("Lerp", AllExcept(DoubleType), Scalar("t", FloatType), Tensor("a"), Tensor("b")), Method("Lerp", AllExcept(DoubleType), Tensor("t", FloatType), Tensor("a"), Tensor("b")), Method("Lerp", AllExcept(FloatType), Scalar("t", DoubleType), Tensor("a"), Tensor("b")), Method("Lerp", AllExcept(FloatType), Tensor("t", DoubleType), Tensor("a"), Tensor("b")), Method("InvLerp", Domain(FloatType), Tensor("y"), Tensor("a"), Tensor("b")), Method("InvLerp", DoubleType, AllExcept(FloatType), Tensor("y"), Tensor("a"), Tensor("b")) ); #endregion #region Common Divisor and Multiple Add("Common Divisor and Multiple", Method("GreatestCommonDivisor", Domain(IntType, LongType, UIntType, ULongType), Tensor("a"), Tensor("b")), Method("LeastCommonMultiple", Domain(IntType, LongType, UIntType, ULongType), Tensor("a"), Tensor("b")) ); #endregion #region Floating point bits Add("Floating point bits", Method("FloatToBits", IntType, Domain(FloatType), Tensor("x")), Method("FloatToUnsignedBits", UIntType, Domain(FloatType), Tensor("x")), Method("FloatFromBits", FloatType, Domain(IntType), Tensor("x")), Method("FloatFromUnsignedBits", FloatType, Domain(UIntType), Tensor("x")), Method("FloatToBits", LongType, Domain(DoubleType), Tensor("x")), Method("FloatFromBits", DoubleType, Domain(LongType), Tensor("x")) ); #endregion return dict; } public static readonly Dictionary ElementwiseFuns = getElementwiseFuns(); #endregion } } ================================================ FILE: src/Aardvark.Base/AlgoDat/MinimumSpanningTree.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Aardvark.Base { public static class MinimumSpanningTree { /// /// Creates a minimum spanning tree from a set of weighted edges. /// The input are edges ((TVertex, TVertex), TWeight) of a graph. /// The output are a subset of these edges which form a minimum spanning tree. /// The type of the weight (TWeight) needs to be IComparable. /// public static IEnumerable<((TVertex, TVertex), TWeight)> Create( IEnumerable<((TVertex, TVertex), TWeight)> edges ) where TWeight : IComparable { if (edges is null) throw new ArgumentNullException(nameof(edges)); Report.BeginTimed("create vertex set"); var vertexSet = new HashSet(edges.SelectMany(e => e.Item1)); Report.End(); if (vertexSet.Count < 2) yield break; //compare function int compare(KeyValuePair kvp0, KeyValuePair kvp1) => kvp0.Key.CompareTo(kvp1.Key); // init per-vertex edge priority queues Report.BeginTimed("init per-vertex edge priority queues"); var v2es = new Dictionary>>(); vertexSet.ForEach(v => v2es[v] = new List>()); foreach (var e in edges) { v2es[e.Item1.Item1].HeapEnqueue(compare, new KeyValuePair(e.Item2, e.Item1.Item2)); v2es[e.Item1.Item2].HeapEnqueue(compare, new KeyValuePair(e.Item2, e.Item1.Item1)); } Report.End(); // mst var mst = new HashSet(); void move(TVertex v) { vertexSet.Remove(v); mst.Add(v); } // build minimum spanning tree using Prim's algorithm Report.BeginTimed("build mst"); move(vertexSet.First()); while (vertexSet.Count > 0) { var candidateQueues = mst .Where(v => v2es.ContainsKey(v)) .Select(v => (v, v2es[v])).Where(q => !q.Item2.IsEmptyOrNull()) ; foreach (var q in candidateQueues) { while (!q.Item2.IsEmptyOrNull() && mst.Contains(q.Item2[0].Value)) q.Item2.HeapDequeue(compare); if (q.Item2.IsEmptyOrNull()) v2es.Remove(q.Item1); } var best = candidateQueues .Select(q => (q.Item1, q.Item2[0])) .Min((a, b) => a.Item2.Key.CompareTo(b.Item2.Key) < 0) ; v2es[best.Item1].HeapDequeue(compare); move(best.Item2.Value); yield return ((best.Item1, best.Item2.Value), best.Item2.Key); } Report.End(); } } public static class MinimumSpanningTreeTest { public static void Test() { var r = new Random(); var es = from a in Enumerable.Range(1, 1000) from b in Enumerable.Range(a + 1, 1000 - a - 1) let w = r.NextDouble() + 1 select ((a, b), w) ; Report.Line("number of edges: {0}", es.Count()); /* unused variable error under mono: var edges = new Tup<(string ,string), int>[] { (("A", "B"), 7), (("A", "D"), 5), (("D", "B"), 9), (("B", "C"), 8), (("B", "E"), 7), (("C", "E"), 5), (("E", "D"), 15), (("F", "D"), 6), (("E", "F"), 8), (("F", "G"), 11), (("E", "G"), 9), }; */ Report.BeginTimed("building mst"); var mst = MinimumSpanningTree.Create(es).ToArray(); Report.End(); Report.Line("#edges in mst: {0}", mst.Length); } } } ================================================ FILE: src/Aardvark.Base/AlgoDat/SalesmanOfDeath.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace Aardvark.Base { public readonly struct SymmetricMatrix { private readonly T[] m_data; private readonly long m_size; #region Constructors public SymmetricMatrix(long size) { m_size = size; m_data = new T[size * (size + 1) / 2]; } #endregion #region Properties private long GetIndex(long x, long y) { if (y > x) return x * (m_size + 1) - (x * (x + 1)) / 2 + y - x; else return y * (m_size + 1) - (y * (y + 1)) / 2 + x - y; } private V2l GetCoord(long index) { long r, c; r = (int)(0.5 * (-System.Math.Sqrt(-8 * index + 4 * m_size * m_size + 4 * m_size + 1) + 2 * m_size + 1)); if (r == 0) c = index; else c = r + index % (r * (m_size + 1) - (r * (r + 1)) / 2); return new V2l(c, r); } public T this[long index] { get { return m_data[index]; } set { m_data[index] = value; } } public T this[long row, long col] { get { return m_data[GetIndex(col, row)]; } set { m_data[GetIndex(col, row)] = value; } } public T this[V2l vec] { get { return m_data[GetIndex(vec.X, vec.Y)]; } set { m_data[GetIndex(vec.X, vec.Y)] = value; } } public V2l Size => new V2l(m_size, m_size); #endregion #region Methods public void ForeachCoord(Action action) { V2l current = V2l.Zero; for (long i = 0; i < m_data.Length; i++) { action(current); current.X++; if (current.X >= m_size) { current.Y++; current.X = current.Y; } } } public void ForeachCoord(Action action) { V2l current = V2l.Zero; for (long i = 0; i < m_data.Length; i++) { action(current.X, current.Y); current.X++; if (current.X >= m_size) { current.Y++; current.X = current.Y; } } } public void ForeachIndex(Action action) { for (long i = 0; i < m_data.Length; i++) action(i); } public void ForeachXYIndex(Action action) { V2l current = V2l.Zero; for (long i = 0; i < m_data.Length; i++) { action(current.X, current.Y, i); current.X++; if (current.X >= m_size) { current.Y++; current.X = current.Y; } } } public void ForeachY(int x, Action action) { long index = GetIndex(x, 0); V2l vec = new V2l(x, 0); for (vec.Y = 0; vec.Y <= x; vec.Y++) { action(index, vec); index += (m_size - vec.Y - 1); } } public void ForeachX(int y, Action action) { long index = GetIndex(y, y); V2l vec = new V2l(y, y); for (vec.X = y; vec.X < m_size; vec.X++) { action(index, vec); index++; } } public void SetByIndex(Func setter) { for (long i = 0; i < m_data.Length; i++) m_data[i] = setter(i); } public void SetByCoord(Func setter) { V2l current = V2l.Zero; for (long i = 0; i < m_data.Length; i++) { m_data[i] = setter(current); current.X++; if (current.X >= m_size) { current.Y++; current.X = current.Y; } } } public void SetByCoord(Func setter) { V2l current = V2l.Zero; for (long i = 0; i < m_data.Length; i++) { m_data[i] = setter(current.X, current.Y); current.X++; if (current.X >= m_size) { current.Y++; current.X = current.Y; } } } #endregion } public abstract class AbstractGraph where TCost : struct, IComparable { protected List m_nodes; protected Tree m_minimumSpanningTree; #region Reference-Structures/Classes public readonly struct Edge : IComparable { private readonly AbstractGraph m_graph; public readonly int Index0; public readonly int Index1; #region Constructors internal Edge(AbstractGraph graph, int i0, int i1) { if (i0 == i1) throw new ArgumentException("Degenerated Edges are not posible"); m_graph = graph; if (i0 < i1) { Index0 = i0; Index1 = i1; } else { Index0 = i1; Index1 = i0; } } #endregion #region Properties public TVertex Node0 => m_graph.m_nodes[Index0]; public TVertex Node1 => m_graph.m_nodes[Index1]; public TCost Cost => m_graph.GetCost(Index0, Index1); #endregion #region Overrides public override int GetHashCode() => m_graph.GetHashCode() ^ ((Index0.GetHashCode() << 12) ^ Index1.GetHashCode()); public override bool Equals(object obj) { if (obj is Edge e) { if (!e.m_graph.Equals(m_graph)) return false; else return Index0 == e.Index0 && Index1 == e.Index1; } else return false; } public override string ToString() => string.Format("[{0},{1}]", Index0, Index1); #endregion #region IComparable Members public int CompareTo(Edge other) => Cost.CompareTo(other.Cost); #endregion } protected class UnionFind { private readonly List m_nodes; private readonly int[] m_parent; #region Constructors internal UnionFind(List nodes) { m_nodes = nodes; m_parent = new int[m_nodes.Count].SetByIndex(i => i); } #endregion #region Methods private int FindRoot(int n) { int p = m_parent[n]; if (p != n) { p = FindRoot(p); m_parent[n] = p; return p; } else { return n; } } public bool Add(int n0, int n1) { int p0 = FindRoot(n0); int p1 = FindRoot(n1); if (p0 != p1) { m_parent[p0] = p1; return true; } else return false; } #endregion } public class Tree { private readonly AbstractGraph m_graph; private readonly List> m_edges; private int m_edgeCount; private readonly bool[] m_visited; #region Constructors internal Tree(AbstractGraph graph) { m_graph = graph; m_edges = new List>(m_graph.m_nodes.Count); for (int i = 0; i < m_graph.m_nodes.Count; i++) { m_edges.Add(new Tup(-1, -1)); } m_visited = new bool[m_graph.m_nodes.Count].SetByIndex(i => false); m_edgeCount = 0; } #endregion #region Edges private void AddHalfEdge(Edge e, int l, int r) { int index = l; var tup = m_edges[index]; if (tup.E0 < 0) { tup.E0 = r; m_edges[index] = tup; } else { while (tup.E1 >= 0) { index = tup.E1; tup = m_edges[index]; } tup.E1 = m_edges.Count; m_edges[index] = tup; m_edges.Add(new Tup(r, -1)); } } internal void AddEdge(Edge edge) { AddHalfEdge(edge, edge.Index0, edge.Index1); AddHalfEdge(edge, edge.Index1, edge.Index0); m_edgeCount++; } #endregion #region Traversals private void TraverseAux(int n, Action nodeAction, Action edgeAction) { if (m_visited[n]) return; m_visited[n] = true; nodeAction(m_graph.m_nodes[n]); var tup = m_edges[n]; if (tup.E0 < 0) return; int edgeIndex = n; edgeAction(new Edge(m_graph, n, tup.E0)); TraverseAux(tup.E0, nodeAction, edgeAction); while (tup.E1 >= 0) { edgeIndex = tup.E1; tup = m_edges[edgeIndex]; edgeAction(new Edge(m_graph, n, tup.E0)); TraverseAux(tup.E0, nodeAction, edgeAction); } } public void Traverse(Action nodeAction, Action edgeAction) { m_visited.SetByIndex(i => false); TraverseAux(0, nodeAction, edgeAction); } private void TraverseEulerAux(int n, Action action) { if (m_visited[n]) return; m_visited[n] = true; int nodeIndex = n; action(nodeIndex);//m_graph.m_nodes[n]); var tup = m_edges[n]; if (tup.E0 < 0) return; TraverseEulerAux(tup.E0, action); action(nodeIndex);//m_graph.m_nodes[n]); while (tup.E1 >= 0) { n = tup.E1; tup = m_edges[n]; TraverseEulerAux(tup.E0, action); action(nodeIndex);//m_graph.m_nodes[n]); } } public void TraverseEuler(Action action) { m_visited.SetByIndex(i => false); TraverseEulerAux(0, action); } #endregion #region Properties public int VertexCount => m_graph.VertexCount; public int EdgeCount => m_edgeCount; public TCost Cost => GetCost(GraphHelpers.Add, default(TCost)); public TAccumulate GetCost(Func addition, TAccumulate seed) { var sum = seed; Traverse(node => { }, edge => sum = addition(sum, edge.Cost)); return sum; } #endregion } public class Tour { private readonly AbstractGraph m_graph; private readonly int[] m_permutation; private bool m_2optImproved; private readonly bool m_circular; #region Constructors internal Tour(AbstractGraph graph, int[] permutation, bool circular = true) { m_circular = circular; m_graph = graph; m_permutation = permutation; m_2optImproved = circular ? false : true; } #endregion #region Methods public bool Improve(int iterations = 1) { if (iterations < 0) iterations = int.MaxValue; int steps = 0; if (!m_2optImproved) { do { if (m_graph.Improve2Opt(m_permutation, GraphHelpers.Add) == 0) m_2optImproved = true; else steps++; } while (steps < iterations && !m_2optImproved); } return steps != 0; } public void Improve3Opt(int iterations) { for (int i = 0; i < iterations; i++) { m_graph.Improve3Opt(m_permutation, GraphHelpers.Add); } } #endregion #region Properties public IEnumerable Vertices { get { foreach (var i in m_permutation) yield return m_graph.m_nodes[i]; } } public IEnumerable Edges { get { int count = m_permutation.Length; for (int i = 0; i < (m_circular ? count : count - 1); i++) { yield return new Edge(m_graph, m_permutation[i], m_permutation[(i + 1) % count]); } } } public TAccumulate GetCost(Func addition, TAccumulate seed) { var sum = seed; foreach (var e in Edges) { sum = addition(sum, e.Cost); } return sum; } public TCost Cost => GetCost(GraphHelpers.Add, default(TCost)); public int Count => m_permutation.Length; public int[] Permutation => m_permutation; public TVertex this[int index] => m_graph.m_nodes[m_permutation[index]]; #endregion #region Overrides public override string ToString() { var e = Vertices.GetEnumerator(); if (!e.MoveNext()) return "[]"; string res = e.Current.ToString(); while (e.MoveNext()) { res += string.Format(", {0}", e.Current.ToString()); } return string.Format("[{0}]", res); } #endregion } public readonly struct Vertex { private readonly AbstractGraph m_graph; private readonly int m_index; #region Constructors internal Vertex(AbstractGraph graph, int index) { m_graph = graph; m_index = index; } #endregion #region Properties public TVertex Value => m_graph.m_nodes[m_index]; public int Index => m_index; #endregion #region Overrides public override string ToString() => string.Format("[{0}: {1}]", m_index, Value); public override int GetHashCode() => m_graph.GetHashCode() ^ m_index.GetHashCode(); public override bool Equals(object obj) { if (obj is Vertex v) { return v.m_graph.Equals(m_graph) && v.m_index == m_index; } else return false; } #endregion } #endregion #region Abstract Members public abstract int EdgeCount { get; } public abstract TCost GetCost(int n0, int n1); public abstract IEnumerable Edges { get; } public abstract Tree MinimumSpanningTree { get; } #endregion #region Properties public int VertexCount => m_nodes.Count; #endregion public Vertex GetVertex(int index) => new Vertex(this, index); public IEnumerable GetVertices(TVertex value) { int index = 0; foreach (var v in m_nodes) { if (v.Equals(value)) yield return new Vertex(this, index); index++; } } #region TSP-Solver protected int Improve2Opt(int[] tour, Func add) { int steps = 0; int count = tour.Length; for (int i = 0; i < count; i++) { for (int j = i + 2; j < count; j++) { int l0 = i % count; int l1 = (i + 1) % count; int r0 = j % count; int r1 = (j + 1) % count; var wOld = add(GetCost(tour[l0], tour[l1]), GetCost(tour[r0], tour[r1])); var wNew = add(GetCost(tour[l0], tour[r0]), GetCost(tour[r1], tour[l1])); if (wNew.CompareTo(wOld) < 0) { int temp; //reverse l1 to r0 while (r0 > l1) { temp = tour[r0]; tour[r0] = tour[l1]; tour[l1] = temp; l1++; r0--; } steps++; } } } return steps; } protected int Improve3Opt(int[] tour, Func add) { int improvements = 0; int count = tour.Length; for (int i = 0; i < count; i++) { int i0 = tour[i]; int i1 = tour[(i + 1) % count]; for (int j = i + 2; j < count; j++) { int i2 = tour[j]; int i3 = tour[(j + 1) % count]; for (int k = j + 2; k < count; k++) { int i4 = tour[k]; int i5 = tour[(k + 1) % count]; //Initial: //01 23 45 //New: //0: 02 13 45 (already tested with 2-opt) //1: 02 14 35 Reverse: [2:1], [4:3] //2: 03 41 25 Reverse: nothing //3: 03 42 15 Reverse: [2:1] //4: 04 31 25 Reverse: [4:3] //5: 04 32 15 Reverse: [4:3], [2:1] int alternativeIndex = -1; var min = add(add(GetCost(i0, i1), GetCost(i2, i3)), GetCost(i4, i5)); //02 14 35 Reverse: [2:1], [4:3] var alternativeCost = add(add(GetCost(i0, i2), GetCost(i1, i4)), GetCost(i3, i5)); if (alternativeCost.CompareTo(min) < 0) { min = alternativeCost; alternativeIndex = 1; } //03 41 25 Reverse: nothing alternativeCost = add(add(GetCost(i0, i3), GetCost(i4, i1)), GetCost(i2, i5)); if (alternativeCost.CompareTo(min) < 0) { min = alternativeCost; alternativeIndex = 2; } //03 42 15 Reverse: [2:1] alternativeCost = add(add(GetCost(i0, i3), GetCost(i4, i2)), GetCost(i1, i5)); if (alternativeCost.CompareTo(min) < 0) { min = alternativeCost; alternativeIndex = 3; } //04 31 25 Reverse: [4:3] alternativeCost = add(add(GetCost(i0, i4), GetCost(i3, i1)), GetCost(i2, i5)); if (alternativeCost.CompareTo(min) < 0) { min = alternativeCost; alternativeIndex = 4; } //04 32 15 Reverse: [4:3], [2:1] alternativeCost = add(add(GetCost(i0, i4), GetCost(i3, i2)), GetCost(i1, i5)); if (alternativeCost.CompareTo(min) < 0) { min = alternativeCost; alternativeIndex = 5; } if (alternativeIndex > 0) { if (alternativeIndex == 1) { //1: 02 14 35 Reverse: [2:1], [4:3] } } } } } return improvements; } #endregion #region Shortest Path private TR NearestNode(IEnumerable nodes, Func comparable, Func result) where TI : IComparable { var e = nodes.GetEnumerator(); if (!e.MoveNext()) throw new IndexOutOfRangeException(); var min = e.Current; var comparableMin = comparable(min); while (e.MoveNext()) { var comparableTemp = comparable(e.Current); if (comparableTemp.CompareTo(comparableMin) < 0) { min = e.Current; comparableMin = comparableTemp; } } return result(min); } public Tour ShortestPath(int start, int end) { var parent = new int[m_nodes.Count].Set(-1); var nodes = new HashSet(); var distances = new TCost[m_nodes.Count]; for (int i = 0; i < m_nodes.Count; i++) { if (i != start) { distances[i] = GetCost(start, i); parent[i] = start; } else distances[i] = default(TCost); } for (int i = 0; i < m_nodes.Count; i++) { nodes.Add(i); } while (nodes.Count > 0) { int u = NearestNode(nodes, n => distances[n], n => n); nodes.Remove(u); foreach (var v in nodes) { //u,v var alternative = GraphHelpers.Add(distances[u], GetCost(u, v)); if (alternative.CompareTo(distances[v]) < 0) { distances[v] = alternative; parent[v] = u; } } } var path = new List { end }; var current = end; while (parent[current] >= 0) { current = parent[current]; path.Insert(0, current); } return new Tour(this, path.ToArray(), false); } #endregion } public class DenseGraph : AbstractGraph where TCost : struct, IComparable { private SymmetricMatrix m_costs; #region Constructors public DenseGraph(IEnumerable nodes, Func weightFun) { m_nodes = nodes.ToList(); BuildWeights(weightFun); } public DenseGraph(IEnumerable nodes, Func weightFun) { m_nodes = nodes.ToList(); BuildWeights(weightFun); } #endregion #region Methods public void BuildWeights(Func weightFun) { m_costs = new SymmetricMatrix(m_nodes.Count); m_costs.SetByCoord((x, y) => { return weightFun(m_nodes[(int)x], m_nodes[(int)y]); }); m_minimumSpanningTree = null; } public void BuildWeights(Func weightFun) { m_costs = new SymmetricMatrix(m_nodes.Count); m_costs.SetByCoord((x, y) => { return weightFun((int)x, m_nodes[(int)x], (int)y, m_nodes[(int)y]); }); m_minimumSpanningTree = null; } #endregion #region Properties public override IEnumerable Edges { get { for (int x = 1; x < m_nodes.Count; x++) { for (int y = 0; y < x; y++) { yield return new Edge(this, y, x); } } } } public override int EdgeCount => m_nodes.Count * (m_nodes.Count - 1) / 2; /// /// Returns the minimum-spanning-tree for the Graph /// If no Tree has been built before builds it using Prim's algorithm (which is faster than Kruskal's algorithm on dense Graphs) /// public override Tree MinimumSpanningTree { get { if (m_minimumSpanningTree == null) m_minimumSpanningTree = BuildMinimumSpanningTreePrim(); return m_minimumSpanningTree; } } #endregion #region Minimum-Spanning-Tree /// /// Builds the minimum-spanning tree using Kruskal's algorithm in O(|E|*log|E|) /// where |E| is the number of Edges /// and |V| the number of vertices (nodes) in the Graph /// /// private Tree BuildMinimumSpanningTreeKruskal() { int N = m_nodes.Count; var unionFind = new UnionFind(m_nodes); //O(|V|) Func cmp = (a, b) => a.CompareTo(b); var heap = new List(EdgeCount); foreach (var e in Edges) heap.HeapEnqueue(cmp, e); var tree = new Tree(this); long i = 0; //O(|E|*log|E|) while (tree.EdgeCount < N - 1) { var edge = heap.HeapDequeue(cmp); i++; //O(1) amortized if (unionFind.Add(edge.Index0, edge.Index1)) { //O(1) tree.AddEdge(edge); } } //O(|V| + |E|*log|E|) return tree; } /// /// Builds the minimum-spanning-tree using Prim's algorithm in O(|V|^2) /// where |V| is the number of vertices (nodes) in the Graph /// /// public Tree BuildMinimumSpanningTreePrim() { int node = 0; bool[] visited = new bool[m_nodes.Count].Set(false); Tree tree = new Tree(this); while (tree.EdgeCount < m_nodes.Count - 1) { visited[node] = true; int next = FindClosestUnvisited(node, visited); tree.AddEdge(new Edge(this, node, next)); node = next; } return tree; } private int FindClosestUnvisited(int node, bool[] visited) { int N = m_nodes.Count; long nearest = -1; TCost min = default(TCost); m_costs.ForeachX(node, (i, p) => { if (node != p.X && !visited[p.X]) { var w = m_costs[i]; if (nearest < 0 || w.CompareTo(min) < 0) { min = w; nearest = p.X; } } }); m_costs.ForeachY(node, (i, p) => { if (node != p.Y && !visited[p.Y]) { var w = m_costs[i]; if (nearest < 0 || w.CompareTo(min) < 0) { min = w; nearest = p.Y; } } }); return (int)nearest; } #endregion #region TSP-Solver public Tour SolveTSP() { int index = 0; var perm = new int[m_nodes.Count]; var visited = new bool[m_nodes.Count].SetByIndex(i => false); MinimumSpanningTree.TraverseEuler(ni => { if (!visited[ni]) { visited[ni] = true; perm[index] = ni; index++; } }); return new Tour(this, perm); } public override TCost GetCost(int n0, int n1) { if (n0 < n1) return m_costs[n0, n1]; else return m_costs[n1, n0]; } #endregion } internal static class GraphHelpers { private static readonly Dictionary> m_additions = new Dictionary>() { {typeof(int), (a,b) => (int)a + (int)b}, {typeof(uint), (a,b) => (uint)a + (uint)b}, {typeof(long), (a,b) => (long)a + (long)b}, {typeof(float), (a,b) => (float)a + (float)b}, {typeof(double), (a,b) => (double)a + (double)b}, {typeof(byte), (a,b) => (byte)a + (byte)b}, {typeof(short), (a,b) => (short)a + (short)b}, {typeof(ushort), (a,b) => (ushort)a + (ushort)b}, }; public static TWeight Add(TWeight v0, TWeight v1) { return (TWeight)m_additions[typeof(TWeight)](v0, v1); } } } ================================================ FILE: src/Aardvark.Base/AlgoDat/ShortestPath.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace Aardvark.Base { public interface IShortestPath { void Cancel(); void CalculateShortestPaths(T pos); void CalculateShortestPathsByIndex(int posIdx); List GetMinimalPath(T pos); List GetMinimalPathByIndex(int posIdx); } public class ShortestPath : IShortestPath { private readonly List m_nodes; private readonly List[] m_neighbors; private readonly Func m_getCostFunc; private bool[] m_expanded; private int[] m_pointers; private bool m_cancelTask = false; private int m_seedId; private Task m_task = null; private CancellationTokenSource m_cancellationToken; public ShortestPath(List nodes, List<(int, int)> edges, Func getCostFunc) { m_nodes = nodes; m_neighbors = new List[nodes.Count]; for(int i = 0; i(); foreach (var e in edges) { m_neighbors[e.Item1].Add(e.Item2); m_neighbors[e.Item2].Add(e.Item1); } m_getCostFunc = getCostFunc; m_expanded = new bool[nodes.Count]; } public ShortestPath(T[] nodes, List[] neighbors, Func getCostFunc) { m_nodes = nodes.ToList(); m_neighbors = neighbors; m_getCostFunc = getCostFunc; m_expanded = new bool[nodes.Length]; } public void Cancel() { if (m_task != null && !(m_task.IsCanceled || m_task.IsCompleted)) { m_cancelTask = true; if (m_cancellationToken != null) m_cancellationToken.Cancel(); m_task.Wait(); } m_task = null; m_cancelTask = false; } public void CalculateShortestPaths(T seed) { //Cancel(); if (m_cancellationToken != null) m_cancellationToken.Cancel(); m_cancellationToken = new CancellationTokenSource(); m_task = Task.Factory.StartNew(delegate { Calculate(seed); }, m_cancellationToken); } public void CalculateShortestPathsByIndex(int index) { //Cancel(); if (m_cancellationToken != null) m_cancellationToken.Cancel(); m_cancellationToken = new CancellationTokenSource(); m_task = Task.Factory.StartNew(delegate { CalculateByIndex(index); }, m_cancellationToken); } private void Calculate(T seed) { CalculateByIndex(m_nodes.IndexOf(seed)); } private void CalculateByIndex(int index) { Report.BeginTimed("Shortest paths calculation"); m_seedId = index; var activePixels = new FibonacciHeap(); var inActiveList = new Dictionary.Node>(); inActiveList[m_seedId] = activePixels.Insert(0, m_seedId); var totalCost = new float[m_nodes.Count].Set(float.MaxValue); m_expanded = new bool[m_nodes.Count]; m_pointers = new int[m_nodes.Count].Set(m_seedId); totalCost[m_seedId] = 0; while (!activePixels.IsEmpty()) { if (m_cancelTask) { Report.End("Canceled Dijkstra"); return; } var q = activePixels.DeleteMin(); inActiveList.Remove(q); m_expanded[q] = true; var totalCostQ = totalCost[q]; foreach (var r in m_neighbors[q]) { if (m_expanded[r]) continue; var gtemp = totalCostQ + m_getCostFunc(m_nodes[q], m_nodes[r]); var isActive = inActiveList.ContainsKey(r); if (!isActive || gtemp < totalCost[r]) { if (isActive) activePixels.DecreaseKey(inActiveList[r], gtemp); else inActiveList[r] = activePixels.Insert(gtemp, r); totalCost[r] = gtemp; m_pointers[r] = q; } } } Report.End(); } public List GetMinimalPathByIndex(int endIndex) { var contour = new List(); var id = endIndex; var end = m_nodes[id]; var seed = m_nodes[m_seedId]; if (!m_expanded[id]) return new List() { end, seed }; while (id != m_seedId) { contour.Add(m_nodes[id]); id = m_pointers[id]; } return contour; } public List GetMinimalPath(T end) { var id = m_nodes.IndexOf(end); return GetMinimalPathByIndex(id); } } class FibonacciHeap { public class Node { private readonly T _item; private Node _parent; private Node _left; private Node _right; private Node _child; private float _key = 0; private int _degree = 0; private bool _marked = false; public Node(float key, T item) { _key = key; _item = item; _left = this; _right = this; } public T Value => _item; public Node Right { get { return _right; } set { _right = value; value._left = this; } } public Node Left { get { return _left; } set { _left = value; value._right = this; } } public Node Parent =>_parent; public Node Child => _child; public void AddChild(Node node) { _degree++; node._parent = this; if (_child == null) _child = node; else _child.InsertOneBefore(node); } public void RemoveChild(Node node) { if (_child != null) { if (_degree == 1) { _child = null; _degree = 0; node._parent = null; } else { if (_child == node) _child = _child.Left; node.Isolate(); _degree--; node._parent = null; } } } public void RemoveAllChildren() { if (_child != null) { foreach (var child in _child.AllSiblings) child._parent = null; _degree = 0; _child = null; } } public void InsertOneBefore(Node node) { var right = Right; Right = node; right.Left = node; } public void InsertGroupBefore(Node node) { var start = node; var end = start.Left; var right = Right; Right = start; right.Left = end; } public void Isolate() { var left = Left; var right = Right; left.Right = right; Left = this; } public float Key { get { return _key; } set { _key = value; } } public int Degree => _degree; public bool Marked { get { return _marked; } set { _marked = value; } } public IEnumerable GetAllChildren() { if (_child == null) return Enumerable.Empty(); return _child.AllSiblings; } public IEnumerable AllSiblings { get { var node = this; do { yield return node; node = node.Right; } while (node != this); } } public bool HasNoSiblings() => _left == this; public bool HasMaxOneSibling() => _left._left == this; } private Node _min; private int _n = 0; public void Insert(Node node) { if (_min == null) { _min = node; } else { _min.InsertOneBefore(node); if (node.Key < _min.Key) _min = node; } _n++; } public Node Insert(float key, T item) { var node = new Node(key, item); Insert(node); return node; } public T GetMin() => _min.Value; public T DeleteMin() { var min = _min; if (_min != null) { if (_min.HasNoSiblings() && _min.Degree == 0) { _min = null; } else { if (_min.Degree > 0) { var child = _min.Child; _min.RemoveAllChildren(); if (!_min.HasNoSiblings()) { _min.InsertGroupBefore(child); _min.Isolate(); } _min = child; } else { var left = _min.Left; _min.Isolate(); _min = left; } Consolidate(); } _n--; } return min.Value; } /*private static Node FindMinSibling(Node node) { var minNode = node; foreach (var n in node.AllSiblings) { if (n.Key < minNode.Key) { minNode = n; } } return minNode; }*/ public void Delete(Node node) { DecreaseKey(node, int.MinValue); DeleteMin(); } public void DecreaseKey(Node node, float newKey) { node.Key = newKey; if (node.Parent == null) { if (newKey < _min.Key) _min = node; } else if (node.Key < node.Parent.Key) { var parent = node.Parent; parent.RemoveChild(node); _min.InsertOneBefore(node); if (!parent.Marked) parent.Marked = true; else { while (parent.Parent != null && parent.Marked) { var pparent = parent.Parent; pparent.RemoveChild(parent); _min.InsertOneBefore(parent); parent.Marked = false; parent = pparent; } } } } public bool IsEmpty() => _min == null; private void Consolidate() { if (_min == null) return; var lookup = new Node[2 * (int)(_n.Log() + 1)]; var last = _min; var current = _min; var newMin = _min; bool stop = false; do { var next = current.Right; while (lookup[current.Degree] != null) { var right = current.Right; var first = current; var second = lookup[current.Degree]; if (second == right && right.Right != first) right = right.Right; lookup[current.Degree] = null; if (second.Key < first.Key) Fun.Swap(ref first, ref second); second.Isolate(); first.AddChild(second); current = first; if (newMin.Key > first.Key || second == newMin) newMin = first; if (second == last) stop = true; } lookup[current.Degree] = current; current = next; } while (current != last && !stop); _min = newMin; } } } ================================================ FILE: src/Aardvark.Base/AlgoDat/Span.cs ================================================ using System; namespace Aardvark.Base { public static class SpanPinning { /// /// Pins a span and performs the given action with the resulting pointer. /// This method is required due to missing support for pinning spans in F#. /// /// The span to pin. /// The action to perform. /// The result of the action. public unsafe static Result Pin(Span span, Func action) where T : unmanaged { fixed (T* ptr = span) { return action((IntPtr)ptr); } } } } ================================================ FILE: src/Aardvark.Base/Delegates/Delegates.cs ================================================ using System; namespace Aardvark.Base { public delegate void ActionValRef(T0 a0, ref T1 a1); public delegate void ActionRefValVal(ref T0 a0, T1 a1, T2 a2); public static class LambdaApplicationExtensions { public static bool ApplyByType( this T obj, Action proc0) where T0 : class { if (obj is T0 a0) { proc0(a0); return true; } return false; } public static void ApplyByTypeStrict( this T obj, Action proc0) where T0 : class { if (obj is T0 a0) { proc0(a0); return; } throw new ArgumentException(); } public static bool ApplyByType( this T obj, Action proc0, Action proc1) where T0 : class where T1 : class { if (obj is T0 a0) { proc0(a0); return true; } if (obj is T1 a1) { proc1(a1); return true; } return false; } public static void ApplyByTypeStrict( this T obj, Action proc0, Action proc1) where T0 : class where T1 : class { if (obj is T0 a0) { proc0(a0); return; } if (obj is T1 a1) { proc1(a1); return; } throw new ArgumentException(); } public static Tr ApplyByTypeStrict( this T obj, Func fun0) where T0 : class { if (obj is T0 a0) return fun0(a0); throw new ArgumentException(); } public static Tr ApplyByTypeStrict( this T obj, Func fun0, Func fun1) where T0 : class where T1 : class { if (obj is T0 a0) return fun0(a0); if (obj is T1 a1) return fun1(a1); throw new ArgumentException(); } } } ================================================ FILE: src/Aardvark.Base/Delegates/Delegates_auto.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region RefFunc public delegate TRes RefFunc (ref T0 a0); public delegate TRes RefFunc (ref T0 a0, ref T1 a1); public delegate TRes RefFunc (ref T0 a0, ref T1 a1, ref T2 a2); public delegate TRes RefFunc (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3); public delegate TRes RefFunc (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4); public delegate TRes RefFunc (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5); public delegate TRes RefFunc (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6); public delegate TRes RefFunc (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7); public delegate TRes RefFunc (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8); public delegate TRes RefFunc (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9); public delegate TRes RefFunc (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10); public delegate TRes RefFunc (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11); public delegate TRes RefFunc (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12); public delegate TRes RefFunc (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13); public delegate TRes RefFunc (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14); public delegate TRes RefFunc (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14, ref T15 a15); #endregion #region FuncOut public delegate TRes FuncOut1 (out T0 a0); public delegate TRes FuncOut1 (T0 a0, out T1 a1); public delegate TRes FuncOut1 (T0 a0, T1 a1, out T2 a2); public delegate TRes FuncOut1 (T0 a0, T1 a1, T2 a2, out T3 a3); public delegate TRes FuncOut1 (T0 a0, T1 a1, T2 a2, T3 a3, out T4 a4); public delegate TRes FuncOut1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, out T5 a5); public delegate TRes FuncOut1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, out T6 a6); public delegate TRes FuncOut1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, out T7 a7); public delegate TRes FuncOut1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, out T8 a8); public delegate TRes FuncOut1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, out T9 a9); public delegate TRes FuncOut1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, out T10 a10); public delegate TRes FuncOut1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, out T11 a11); public delegate TRes FuncOut1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, out T12 a12); public delegate TRes FuncOut1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, out T13 a13); public delegate TRes FuncOut1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, T13 a13, out T14 a14); public delegate TRes FuncOut1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, T13 a13, T14 a14, out T15 a15); public delegate TRes FuncOut2 (out T0 a0, out T1 a1); public delegate TRes FuncOut2 (T0 a0, out T1 a1, out T2 a2); public delegate TRes FuncOut2 (T0 a0, T1 a1, out T2 a2, out T3 a3); public delegate TRes FuncOut2 (T0 a0, T1 a1, T2 a2, out T3 a3, out T4 a4); public delegate TRes FuncOut2 (T0 a0, T1 a1, T2 a2, T3 a3, out T4 a4, out T5 a5); public delegate TRes FuncOut2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, out T5 a5, out T6 a6); public delegate TRes FuncOut2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, out T6 a6, out T7 a7); public delegate TRes FuncOut2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, out T7 a7, out T8 a8); public delegate TRes FuncOut2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, out T8 a8, out T9 a9); public delegate TRes FuncOut2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, out T9 a9, out T10 a10); public delegate TRes FuncOut2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, out T10 a10, out T11 a11); public delegate TRes FuncOut2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, out T11 a11, out T12 a12); public delegate TRes FuncOut2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, out T12 a12, out T13 a13); public delegate TRes FuncOut2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, out T13 a13, out T14 a14); public delegate TRes FuncOut2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, T13 a13, out T14 a14, out T15 a15); public delegate TRes FuncOut3 (out T0 a0, out T1 a1, out T2 a2); public delegate TRes FuncOut3 (T0 a0, out T1 a1, out T2 a2, out T3 a3); public delegate TRes FuncOut3 (T0 a0, T1 a1, out T2 a2, out T3 a3, out T4 a4); public delegate TRes FuncOut3 (T0 a0, T1 a1, T2 a2, out T3 a3, out T4 a4, out T5 a5); public delegate TRes FuncOut3 (T0 a0, T1 a1, T2 a2, T3 a3, out T4 a4, out T5 a5, out T6 a6); public delegate TRes FuncOut3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, out T5 a5, out T6 a6, out T7 a7); public delegate TRes FuncOut3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, out T6 a6, out T7 a7, out T8 a8); public delegate TRes FuncOut3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, out T7 a7, out T8 a8, out T9 a9); public delegate TRes FuncOut3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, out T8 a8, out T9 a9, out T10 a10); public delegate TRes FuncOut3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, out T9 a9, out T10 a10, out T11 a11); public delegate TRes FuncOut3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, out T10 a10, out T11 a11, out T12 a12); public delegate TRes FuncOut3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, out T11 a11, out T12 a12, out T13 a13); public delegate TRes FuncOut3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, out T12 a12, out T13 a13, out T14 a14); public delegate TRes FuncOut3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, out T13 a13, out T14 a14, out T15 a15); public delegate TRes FuncOut4 (out T0 a0, out T1 a1, out T2 a2, out T3 a3); public delegate TRes FuncOut4 (T0 a0, out T1 a1, out T2 a2, out T3 a3, out T4 a4); public delegate TRes FuncOut4 (T0 a0, T1 a1, out T2 a2, out T3 a3, out T4 a4, out T5 a5); public delegate TRes FuncOut4 (T0 a0, T1 a1, T2 a2, out T3 a3, out T4 a4, out T5 a5, out T6 a6); public delegate TRes FuncOut4 (T0 a0, T1 a1, T2 a2, T3 a3, out T4 a4, out T5 a5, out T6 a6, out T7 a7); public delegate TRes FuncOut4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, out T5 a5, out T6 a6, out T7 a7, out T8 a8); public delegate TRes FuncOut4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, out T6 a6, out T7 a7, out T8 a8, out T9 a9); public delegate TRes FuncOut4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, out T7 a7, out T8 a8, out T9 a9, out T10 a10); public delegate TRes FuncOut4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, out T8 a8, out T9 a9, out T10 a10, out T11 a11); public delegate TRes FuncOut4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, out T9 a9, out T10 a10, out T11 a11, out T12 a12); public delegate TRes FuncOut4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, out T10 a10, out T11 a11, out T12 a12, out T13 a13); public delegate TRes FuncOut4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, out T11 a11, out T12 a12, out T13 a13, out T14 a14); public delegate TRes FuncOut4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, out T12 a12, out T13 a13, out T14 a14, out T15 a15); public delegate TRes FuncOut5 (out T0 a0, out T1 a1, out T2 a2, out T3 a3, out T4 a4); public delegate TRes FuncOut5 (T0 a0, out T1 a1, out T2 a2, out T3 a3, out T4 a4, out T5 a5); public delegate TRes FuncOut5 (T0 a0, T1 a1, out T2 a2, out T3 a3, out T4 a4, out T5 a5, out T6 a6); public delegate TRes FuncOut5 (T0 a0, T1 a1, T2 a2, out T3 a3, out T4 a4, out T5 a5, out T6 a6, out T7 a7); public delegate TRes FuncOut5 (T0 a0, T1 a1, T2 a2, T3 a3, out T4 a4, out T5 a5, out T6 a6, out T7 a7, out T8 a8); public delegate TRes FuncOut5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, out T5 a5, out T6 a6, out T7 a7, out T8 a8, out T9 a9); public delegate TRes FuncOut5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, out T6 a6, out T7 a7, out T8 a8, out T9 a9, out T10 a10); public delegate TRes FuncOut5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, out T7 a7, out T8 a8, out T9 a9, out T10 a10, out T11 a11); public delegate TRes FuncOut5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, out T8 a8, out T9 a9, out T10 a10, out T11 a11, out T12 a12); public delegate TRes FuncOut5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, out T9 a9, out T10 a10, out T11 a11, out T12 a12, out T13 a13); public delegate TRes FuncOut5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, out T10 a10, out T11 a11, out T12 a12, out T13 a13, out T14 a14); public delegate TRes FuncOut5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, out T11 a11, out T12 a12, out T13 a13, out T14 a14, out T15 a15); public delegate TRes FuncOut6 (out T0 a0, out T1 a1, out T2 a2, out T3 a3, out T4 a4, out T5 a5); public delegate TRes FuncOut6 (T0 a0, out T1 a1, out T2 a2, out T3 a3, out T4 a4, out T5 a5, out T6 a6); public delegate TRes FuncOut6 (T0 a0, T1 a1, out T2 a2, out T3 a3, out T4 a4, out T5 a5, out T6 a6, out T7 a7); public delegate TRes FuncOut6 (T0 a0, T1 a1, T2 a2, out T3 a3, out T4 a4, out T5 a5, out T6 a6, out T7 a7, out T8 a8); public delegate TRes FuncOut6 (T0 a0, T1 a1, T2 a2, T3 a3, out T4 a4, out T5 a5, out T6 a6, out T7 a7, out T8 a8, out T9 a9); public delegate TRes FuncOut6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, out T5 a5, out T6 a6, out T7 a7, out T8 a8, out T9 a9, out T10 a10); public delegate TRes FuncOut6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, out T6 a6, out T7 a7, out T8 a8, out T9 a9, out T10 a10, out T11 a11); public delegate TRes FuncOut6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, out T7 a7, out T8 a8, out T9 a9, out T10 a10, out T11 a11, out T12 a12); public delegate TRes FuncOut6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, out T8 a8, out T9 a9, out T10 a10, out T11 a11, out T12 a12, out T13 a13); public delegate TRes FuncOut6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, out T9 a9, out T10 a10, out T11 a11, out T12 a12, out T13 a13, out T14 a14); public delegate TRes FuncOut6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, out T10 a10, out T11 a11, out T12 a12, out T13 a13, out T14 a14, out T15 a15); public delegate TRes FuncOut7 (out T0 a0, out T1 a1, out T2 a2, out T3 a3, out T4 a4, out T5 a5, out T6 a6); public delegate TRes FuncOut7 (T0 a0, out T1 a1, out T2 a2, out T3 a3, out T4 a4, out T5 a5, out T6 a6, out T7 a7); public delegate TRes FuncOut7 (T0 a0, T1 a1, out T2 a2, out T3 a3, out T4 a4, out T5 a5, out T6 a6, out T7 a7, out T8 a8); public delegate TRes FuncOut7 (T0 a0, T1 a1, T2 a2, out T3 a3, out T4 a4, out T5 a5, out T6 a6, out T7 a7, out T8 a8, out T9 a9); public delegate TRes FuncOut7 (T0 a0, T1 a1, T2 a2, T3 a3, out T4 a4, out T5 a5, out T6 a6, out T7 a7, out T8 a8, out T9 a9, out T10 a10); public delegate TRes FuncOut7 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, out T5 a5, out T6 a6, out T7 a7, out T8 a8, out T9 a9, out T10 a10, out T11 a11); public delegate TRes FuncOut7 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, out T6 a6, out T7 a7, out T8 a8, out T9 a9, out T10 a10, out T11 a11, out T12 a12); public delegate TRes FuncOut7 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, out T7 a7, out T8 a8, out T9 a9, out T10 a10, out T11 a11, out T12 a12, out T13 a13); public delegate TRes FuncOut7 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, out T8 a8, out T9 a9, out T10 a10, out T11 a11, out T12 a12, out T13 a13, out T14 a14); public delegate TRes FuncOut7 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, out T9 a9, out T10 a10, out T11 a11, out T12 a12, out T13 a13, out T14 a14, out T15 a15); public delegate TRes FuncOut8 (out T0 a0, out T1 a1, out T2 a2, out T3 a3, out T4 a4, out T5 a5, out T6 a6, out T7 a7); public delegate TRes FuncOut8 (T0 a0, out T1 a1, out T2 a2, out T3 a3, out T4 a4, out T5 a5, out T6 a6, out T7 a7, out T8 a8); public delegate TRes FuncOut8 (T0 a0, T1 a1, out T2 a2, out T3 a3, out T4 a4, out T5 a5, out T6 a6, out T7 a7, out T8 a8, out T9 a9); public delegate TRes FuncOut8 (T0 a0, T1 a1, T2 a2, out T3 a3, out T4 a4, out T5 a5, out T6 a6, out T7 a7, out T8 a8, out T9 a9, out T10 a10); public delegate TRes FuncOut8 (T0 a0, T1 a1, T2 a2, T3 a3, out T4 a4, out T5 a5, out T6 a6, out T7 a7, out T8 a8, out T9 a9, out T10 a10, out T11 a11); public delegate TRes FuncOut8 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, out T5 a5, out T6 a6, out T7 a7, out T8 a8, out T9 a9, out T10 a10, out T11 a11, out T12 a12); public delegate TRes FuncOut8 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, out T6 a6, out T7 a7, out T8 a8, out T9 a9, out T10 a10, out T11 a11, out T12 a12, out T13 a13); public delegate TRes FuncOut8 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, out T7 a7, out T8 a8, out T9 a9, out T10 a10, out T11 a11, out T12 a12, out T13 a13, out T14 a14); public delegate TRes FuncOut8 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, out T8 a8, out T9 a9, out T10 a10, out T11 a11, out T12 a12, out T13 a13, out T14 a14, out T15 a15); #endregion #region FuncRef public delegate TRes FuncRef1 (ref T0 a0); public delegate TRes FuncRef1 (T0 a0, ref T1 a1); public delegate TRes FuncRef1 (T0 a0, T1 a1, ref T2 a2); public delegate TRes FuncRef1 (T0 a0, T1 a1, T2 a2, ref T3 a3); public delegate TRes FuncRef1 (T0 a0, T1 a1, T2 a2, T3 a3, ref T4 a4); public delegate TRes FuncRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, ref T5 a5); public delegate TRes FuncRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, ref T6 a6); public delegate TRes FuncRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, ref T7 a7); public delegate TRes FuncRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, ref T8 a8); public delegate TRes FuncRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, ref T9 a9); public delegate TRes FuncRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, ref T10 a10); public delegate TRes FuncRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, ref T11 a11); public delegate TRes FuncRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, ref T12 a12); public delegate TRes FuncRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, ref T13 a13); public delegate TRes FuncRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, T13 a13, ref T14 a14); public delegate TRes FuncRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, T13 a13, T14 a14, ref T15 a15); public delegate TRes FuncRef2 (ref T0 a0, ref T1 a1); public delegate TRes FuncRef2 (T0 a0, ref T1 a1, ref T2 a2); public delegate TRes FuncRef2 (T0 a0, T1 a1, ref T2 a2, ref T3 a3); public delegate TRes FuncRef2 (T0 a0, T1 a1, T2 a2, ref T3 a3, ref T4 a4); public delegate TRes FuncRef2 (T0 a0, T1 a1, T2 a2, T3 a3, ref T4 a4, ref T5 a5); public delegate TRes FuncRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, ref T5 a5, ref T6 a6); public delegate TRes FuncRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, ref T6 a6, ref T7 a7); public delegate TRes FuncRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, ref T7 a7, ref T8 a8); public delegate TRes FuncRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, ref T8 a8, ref T9 a9); public delegate TRes FuncRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, ref T9 a9, ref T10 a10); public delegate TRes FuncRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, ref T10 a10, ref T11 a11); public delegate TRes FuncRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, ref T11 a11, ref T12 a12); public delegate TRes FuncRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, ref T12 a12, ref T13 a13); public delegate TRes FuncRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, ref T13 a13, ref T14 a14); public delegate TRes FuncRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, T13 a13, ref T14 a14, ref T15 a15); public delegate TRes FuncRef3 (ref T0 a0, ref T1 a1, ref T2 a2); public delegate TRes FuncRef3 (T0 a0, ref T1 a1, ref T2 a2, ref T3 a3); public delegate TRes FuncRef3 (T0 a0, T1 a1, ref T2 a2, ref T3 a3, ref T4 a4); public delegate TRes FuncRef3 (T0 a0, T1 a1, T2 a2, ref T3 a3, ref T4 a4, ref T5 a5); public delegate TRes FuncRef3 (T0 a0, T1 a1, T2 a2, T3 a3, ref T4 a4, ref T5 a5, ref T6 a6); public delegate TRes FuncRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, ref T5 a5, ref T6 a6, ref T7 a7); public delegate TRes FuncRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, ref T6 a6, ref T7 a7, ref T8 a8); public delegate TRes FuncRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, ref T7 a7, ref T8 a8, ref T9 a9); public delegate TRes FuncRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, ref T8 a8, ref T9 a9, ref T10 a10); public delegate TRes FuncRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, ref T9 a9, ref T10 a10, ref T11 a11); public delegate TRes FuncRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, ref T10 a10, ref T11 a11, ref T12 a12); public delegate TRes FuncRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, ref T11 a11, ref T12 a12, ref T13 a13); public delegate TRes FuncRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, ref T12 a12, ref T13 a13, ref T14 a14); public delegate TRes FuncRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, ref T13 a13, ref T14 a14, ref T15 a15); public delegate TRes FuncRef4 (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3); public delegate TRes FuncRef4 (T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4); public delegate TRes FuncRef4 (T0 a0, T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5); public delegate TRes FuncRef4 (T0 a0, T1 a1, T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6); public delegate TRes FuncRef4 (T0 a0, T1 a1, T2 a2, T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7); public delegate TRes FuncRef4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8); public delegate TRes FuncRef4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9); public delegate TRes FuncRef4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10); public delegate TRes FuncRef4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11); public delegate TRes FuncRef4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12); public delegate TRes FuncRef4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13); public delegate TRes FuncRef4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14); public delegate TRes FuncRef4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, ref T12 a12, ref T13 a13, ref T14 a14, ref T15 a15); public delegate TRes FuncRef5 (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4); public delegate TRes FuncRef5 (T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5); public delegate TRes FuncRef5 (T0 a0, T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6); public delegate TRes FuncRef5 (T0 a0, T1 a1, T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7); public delegate TRes FuncRef5 (T0 a0, T1 a1, T2 a2, T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8); public delegate TRes FuncRef5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9); public delegate TRes FuncRef5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10); public delegate TRes FuncRef5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11); public delegate TRes FuncRef5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12); public delegate TRes FuncRef5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13); public delegate TRes FuncRef5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14); public delegate TRes FuncRef5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14, ref T15 a15); public delegate TRes FuncRef6 (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5); public delegate TRes FuncRef6 (T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6); public delegate TRes FuncRef6 (T0 a0, T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7); public delegate TRes FuncRef6 (T0 a0, T1 a1, T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8); public delegate TRes FuncRef6 (T0 a0, T1 a1, T2 a2, T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9); public delegate TRes FuncRef6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10); public delegate TRes FuncRef6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11); public delegate TRes FuncRef6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12); public delegate TRes FuncRef6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13); public delegate TRes FuncRef6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14); public delegate TRes FuncRef6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14, ref T15 a15); public delegate TRes FuncRef7 (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6); public delegate TRes FuncRef7 (T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7); public delegate TRes FuncRef7 (T0 a0, T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8); public delegate TRes FuncRef7 (T0 a0, T1 a1, T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9); public delegate TRes FuncRef7 (T0 a0, T1 a1, T2 a2, T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10); public delegate TRes FuncRef7 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11); public delegate TRes FuncRef7 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12); public delegate TRes FuncRef7 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13); public delegate TRes FuncRef7 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14); public delegate TRes FuncRef7 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14, ref T15 a15); public delegate TRes FuncRef8 (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7); public delegate TRes FuncRef8 (T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8); public delegate TRes FuncRef8 (T0 a0, T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9); public delegate TRes FuncRef8 (T0 a0, T1 a1, T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10); public delegate TRes FuncRef8 (T0 a0, T1 a1, T2 a2, T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11); public delegate TRes FuncRef8 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12); public delegate TRes FuncRef8 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13); public delegate TRes FuncRef8 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14); public delegate TRes FuncRef8 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14, ref T15 a15); #endregion #region Recursive public delegate Func Recursive (Recursive r); public delegate Func Recursive (Recursive r); public delegate Func Recursive (Recursive r); public delegate Func Recursive (Recursive r); #endregion #region RefAction public delegate void RefAction (ref T0 a0); public delegate void RefAction (ref T0 a0, ref T1 a1); public delegate void RefAction (ref T0 a0, ref T1 a1, ref T2 a2); public delegate void RefAction (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3); public delegate void RefAction (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4); public delegate void RefAction (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5); public delegate void RefAction (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6); public delegate void RefAction (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7); public delegate void RefAction (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8); public delegate void RefAction (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9); public delegate void RefAction (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10); public delegate void RefAction (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11); public delegate void RefAction (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12); public delegate void RefAction (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13); public delegate void RefAction (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14); public delegate void RefAction (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14, ref T15 a15); #endregion #region ActionRef public delegate void ActionRef1 (ref T0 a0); public delegate void ActionRef1 (T0 a0, ref T1 a1); public delegate void ActionRef1 (T0 a0, T1 a1, ref T2 a2); public delegate void ActionRef1 (T0 a0, T1 a1, T2 a2, ref T3 a3); public delegate void ActionRef1 (T0 a0, T1 a1, T2 a2, T3 a3, ref T4 a4); public delegate void ActionRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, ref T5 a5); public delegate void ActionRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, ref T6 a6); public delegate void ActionRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, ref T7 a7); public delegate void ActionRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, ref T8 a8); public delegate void ActionRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, ref T9 a9); public delegate void ActionRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, ref T10 a10); public delegate void ActionRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, ref T11 a11); public delegate void ActionRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, ref T12 a12); public delegate void ActionRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, ref T13 a13); public delegate void ActionRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, T13 a13, ref T14 a14); public delegate void ActionRef1 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, T13 a13, T14 a14, ref T15 a15); public delegate void ActionRef2 (ref T0 a0, ref T1 a1); public delegate void ActionRef2 (T0 a0, ref T1 a1, ref T2 a2); public delegate void ActionRef2 (T0 a0, T1 a1, ref T2 a2, ref T3 a3); public delegate void ActionRef2 (T0 a0, T1 a1, T2 a2, ref T3 a3, ref T4 a4); public delegate void ActionRef2 (T0 a0, T1 a1, T2 a2, T3 a3, ref T4 a4, ref T5 a5); public delegate void ActionRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, ref T5 a5, ref T6 a6); public delegate void ActionRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, ref T6 a6, ref T7 a7); public delegate void ActionRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, ref T7 a7, ref T8 a8); public delegate void ActionRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, ref T8 a8, ref T9 a9); public delegate void ActionRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, ref T9 a9, ref T10 a10); public delegate void ActionRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, ref T10 a10, ref T11 a11); public delegate void ActionRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, ref T11 a11, ref T12 a12); public delegate void ActionRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, ref T12 a12, ref T13 a13); public delegate void ActionRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, ref T13 a13, ref T14 a14); public delegate void ActionRef2 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, T13 a13, ref T14 a14, ref T15 a15); public delegate void ActionRef3 (ref T0 a0, ref T1 a1, ref T2 a2); public delegate void ActionRef3 (T0 a0, ref T1 a1, ref T2 a2, ref T3 a3); public delegate void ActionRef3 (T0 a0, T1 a1, ref T2 a2, ref T3 a3, ref T4 a4); public delegate void ActionRef3 (T0 a0, T1 a1, T2 a2, ref T3 a3, ref T4 a4, ref T5 a5); public delegate void ActionRef3 (T0 a0, T1 a1, T2 a2, T3 a3, ref T4 a4, ref T5 a5, ref T6 a6); public delegate void ActionRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, ref T5 a5, ref T6 a6, ref T7 a7); public delegate void ActionRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, ref T6 a6, ref T7 a7, ref T8 a8); public delegate void ActionRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, ref T7 a7, ref T8 a8, ref T9 a9); public delegate void ActionRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, ref T8 a8, ref T9 a9, ref T10 a10); public delegate void ActionRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, ref T9 a9, ref T10 a10, ref T11 a11); public delegate void ActionRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, ref T10 a10, ref T11 a11, ref T12 a12); public delegate void ActionRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, ref T11 a11, ref T12 a12, ref T13 a13); public delegate void ActionRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, ref T12 a12, ref T13 a13, ref T14 a14); public delegate void ActionRef3 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, T12 a12, ref T13 a13, ref T14 a14, ref T15 a15); public delegate void ActionRef4 (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3); public delegate void ActionRef4 (T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4); public delegate void ActionRef4 (T0 a0, T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5); public delegate void ActionRef4 (T0 a0, T1 a1, T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6); public delegate void ActionRef4 (T0 a0, T1 a1, T2 a2, T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7); public delegate void ActionRef4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8); public delegate void ActionRef4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9); public delegate void ActionRef4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10); public delegate void ActionRef4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11); public delegate void ActionRef4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12); public delegate void ActionRef4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13); public delegate void ActionRef4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14); public delegate void ActionRef4 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, T11 a11, ref T12 a12, ref T13 a13, ref T14 a14, ref T15 a15); public delegate void ActionRef5 (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4); public delegate void ActionRef5 (T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5); public delegate void ActionRef5 (T0 a0, T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6); public delegate void ActionRef5 (T0 a0, T1 a1, T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7); public delegate void ActionRef5 (T0 a0, T1 a1, T2 a2, T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8); public delegate void ActionRef5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9); public delegate void ActionRef5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10); public delegate void ActionRef5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11); public delegate void ActionRef5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12); public delegate void ActionRef5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13); public delegate void ActionRef5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14); public delegate void ActionRef5 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14, ref T15 a15); public delegate void ActionRef6 (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5); public delegate void ActionRef6 (T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6); public delegate void ActionRef6 (T0 a0, T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7); public delegate void ActionRef6 (T0 a0, T1 a1, T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8); public delegate void ActionRef6 (T0 a0, T1 a1, T2 a2, T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9); public delegate void ActionRef6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10); public delegate void ActionRef6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11); public delegate void ActionRef6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12); public delegate void ActionRef6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13); public delegate void ActionRef6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14); public delegate void ActionRef6 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14, ref T15 a15); public delegate void ActionRef7 (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6); public delegate void ActionRef7 (T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7); public delegate void ActionRef7 (T0 a0, T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8); public delegate void ActionRef7 (T0 a0, T1 a1, T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9); public delegate void ActionRef7 (T0 a0, T1 a1, T2 a2, T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10); public delegate void ActionRef7 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11); public delegate void ActionRef7 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12); public delegate void ActionRef7 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13); public delegate void ActionRef7 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14); public delegate void ActionRef7 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14, ref T15 a15); public delegate void ActionRef8 (ref T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7); public delegate void ActionRef8 (T0 a0, ref T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8); public delegate void ActionRef8 (T0 a0, T1 a1, ref T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9); public delegate void ActionRef8 (T0 a0, T1 a1, T2 a2, ref T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10); public delegate void ActionRef8 (T0 a0, T1 a1, T2 a2, T3 a3, ref T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11); public delegate void ActionRef8 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, ref T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12); public delegate void ActionRef8 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, ref T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13); public delegate void ActionRef8 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, ref T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14); public delegate void ActionRef8 (T0 a0, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, ref T8 a8, ref T9 a9, ref T10 a10, ref T11 a11, ref T12 a12, ref T13 a13, ref T14 a14, ref T15 a15); #endregion } ================================================ FILE: src/Aardvark.Base/Delegates/Delegates_template.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# Action comma = () => Out(", "); #region RefFunc //# for (int c = 1; c < 17; c++) { public delegate TRes RefFunc { */T__i__/*# }, comma); */, TRes> (/*# c.ForEach(i => { */ref T__i__ a__i__/*# }, comma); */); //# } #endregion #region FuncOut //# for (int o = 1; o < 9; o++) { //# for (int c = o; c < 17; c++) { public delegate TRes FuncOut__o__ { */T__i__/*# }, comma); */, TRes> (/*# c.ForEach(i => { if (i >= c - o) {*/out /*# } */T__i__ a__i__/*# }, comma); */); //# } //# } #endregion #region FuncRef //# for (int r = 1; r < 9; r++) { //# for (int c = r; c < 17; c++) { public delegate TRes FuncRef__r__ { */T__i__/*# }, comma); */, TRes> (/*# c.ForEach(i => { if (i >= c - r) {*/ref /*# } */T__i__ a__i__/*# }, comma); */); //# } //# } #endregion #region Recursive //# for (int c = 1; c < 5; c++) { public delegate Func { */T__i__/*# }, comma); */, TRes> Recursive { */T__i__/*# }, comma); */, TRes> (Recursive { */T__i__/*# }, comma); */, TRes> r); //# } #endregion #region RefAction //# for (int c = 1; c < 17; c++) { public delegate void RefAction { */T__i__/*# }, comma); */> (/*# c.ForEach(i => { */ref T__i__ a__i__/*# }, comma); */); //# } #endregion #region ActionRef //# for (int r = 1; r < 9; r++) { //# for (int c = r; c < 17; c++) { public delegate void ActionRef__r__ { */T__i__/*# }, comma); */> (/*# c.ForEach(i => { if (i >= c - r) {*/ref /*# } */T__i__ a__i__/*# }, comma); */); //# } //# } #endregion } ================================================ FILE: src/Aardvark.Base/Delegates/HigherOrderFunctions.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using static System.Math; namespace Aardvark.Base { public class ActionTable : Dict { } public static class HighFun { #region IntoFunc /// /// Wrap a value into a function. /// public static Func IntoFunc(this T x) { return () => x; } #endregion #region Compose /// /// Fun.Compose(f0, f1) returns f1(f0). /// public static Func Compose( this Func f0, Func f1) { return x => f1(f0(x)); } /// /// Fun.Compose(f0, f1, f2) returns f2(f1(f0)). /// public static Func Compose( this Func f0, Func f1, Func f2) { return x => f2(f1(f0(x))); } /// /// Fun.Compose(f0, f1, f2, f3) returns f3(f2(f1(f0))). /// public static Func Compose( this Func f0, Func f1, Func f2, Func f3) { return x => f3(f2(f1(f0(x)))); } #endregion #region Partial Application public static Func ApplyArg0( this Func fun, TArg0 a0) { return a1 => fun(a0, a1); } public static Func ApplyArg1( this Func fun, TArg1 a1) { return a0 => fun(a0, a1); } public static Func ApplyArg0( this Func fun, TArg0 a0) { return (a1, a2) => fun(a0, a1, a2); } public static Func ApplyArg1( this Func fun, TArg1 a1) { return (a0, a2) => fun(a0, a1, a2); } public static Func ApplyArg2( this Func fun, TArg2 a2) { return (a0, a1) => fun(a0, a1, a2); } public static Func ApplyArg0Arg1( this Func fun, TArg0 a0, TArg1 a1) { return a2 => fun(a0, a1, a2); } public static Func ApplyArg0Arg2( this Func fun, TArg0 a0, TArg2 a2) { return a1 => fun(a0, a1, a2); } public static Func ApplyArg1Arg2( this Func fun, TArg1 a1, TArg2 a2) { return a0 => fun(a0, a1, a2); } public static Func ApplyArg0( this Func fun, TArg0 a0) { return (a1, a2, a3) => fun(a0, a1, a2, a3); } public static Func ApplyArg1( this Func fun, TArg1 a1) { return (a0, a2, a3) => fun(a0, a1, a2, a3); } public static Func ApplyArg2( this Func fun, TArg2 a2) { return (a0, a1, a3) => fun(a0, a1, a2, a3); } public static Func ApplyArg3( this Func fun, TArg3 a3) { return (a0, a1, a2) => fun(a0, a1, a2, a3); } #endregion #region Currying public static Func> Curry( this Func fun) { return a0 => a1 => fun(a0, a1); } public static Func>> Curry( this Func fun) { return a0 => a1 => a2 => fun(a0, a1, a2); } public static Func>>> Curry( this Func fun) { return a0 => a1 => a2 => a3 => fun(a0, a1, a2, a3); } #endregion #region FixedPointCombinators public static Func Y( Func, Func> f) { Recursive rec = r => a0 => f(r(r))(a0); return rec(rec); } public static Func Y( Func, Func> f) { Recursive rec = r => (a0, a1) => f(r(r))(a0, a1); return rec(rec); } public static Func Y( Func, Func> f) { Recursive rec = r => (a0, a1, a2) => f(r(r))(a0, a1, a2); return rec(rec); } public static Func Y( Func, Func> f) { Recursive rec = r => (a0, a1, a2, a3) => f(r(r))(a0, a1, a2, a3); return rec(rec); } #endregion } public struct FuncOfT2Bool { public Func F { get; private set; } public FuncOfT2Bool(Func f) : this() { F = f; } public static implicit operator Func(FuncOfT2Bool x) { return x.F; } public static implicit operator FuncOfT2Bool(Func x) { return new FuncOfT2Bool(x); } //public static bool operator false(FuncOfT2Bool x) //{ // return false; //} //public static bool operator true(FuncOfT2Bool x) //{ // return true; //} public static FuncOfT2Bool operator &(FuncOfT2Bool a, FuncOfT2Bool b) { return new FuncOfT2Bool(et => a.F(et) & b.F(et)); } public static FuncOfT2Bool operator |(FuncOfT2Bool a, FuncOfT2Bool b) { return new FuncOfT2Bool(et => a.F(et) | b.F(et)); } public static FuncOfT2Bool operator ^(FuncOfT2Bool a, FuncOfT2Bool b) { return new FuncOfT2Bool(et => a.F(et) ^ b.F(et)); } public static FuncOfT2Bool operator !(FuncOfT2Bool a) { return new FuncOfT2Bool(et => !a.F(et)); } public static FuncOfT2Bool operator ==(FuncOfT2Bool a, FuncOfT2Bool b) { return new FuncOfT2Bool(et => a.F(et) == b.F(et)); } public static FuncOfT2Bool operator !=(FuncOfT2Bool a, FuncOfT2Bool b) { return new FuncOfT2Bool(et => a.F(et) != b.F(et)); } public static FuncOfT2Bool operator &(FuncOfT2Bool a, bool b) { return new FuncOfT2Bool(et => a.F(et) & b); } public static FuncOfT2Bool operator |(FuncOfT2Bool a, bool b) { return new FuncOfT2Bool(et => a.F(et) | b); } public static FuncOfT2Bool operator ^(FuncOfT2Bool a, bool b) { return new FuncOfT2Bool(et => a.F(et) ^ b); } public static FuncOfT2Bool operator ==(FuncOfT2Bool a, bool b) { return new FuncOfT2Bool(et => a.F(et) == b); } public static FuncOfT2Bool operator !=(FuncOfT2Bool a, bool b) { return new FuncOfT2Bool(et => a.F(et) != b); } public static FuncOfT2Bool operator &(bool a, FuncOfT2Bool b) { return new FuncOfT2Bool(et => a & b.F(et)); } public static FuncOfT2Bool operator |(bool a, FuncOfT2Bool b) { return new FuncOfT2Bool(et => a | b.F(et)); } public static FuncOfT2Bool operator ^(bool a, FuncOfT2Bool b) { return new FuncOfT2Bool(et => a ^ b.F(et)); } public static FuncOfT2Bool operator ==(bool a, FuncOfT2Bool b) { return new FuncOfT2Bool(et => a == b.F(et)); } public static FuncOfT2Bool operator !=(bool a, FuncOfT2Bool b) { return new FuncOfT2Bool(et => a != b.F(et)); } public override readonly bool Equals(object obj) { return F.Equals(obj); } public override readonly int GetHashCode() { return F.GetHashCode(); } } } ================================================ FILE: src/Aardvark.Base/Extensions/ArrayExtensions.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; using static System.Math; namespace Aardvark.Base { public static class ArrayFun { #region Generic Array Setting (initialization) /// /// Set all elements to the same supplied value. /// /// this public static T[] Set(this T[] self, T value) { #if NET6_0_OR_GREATER Array.Fill(self, value); #else var len = self.LongLength; for (int i = 0; i < len; i++) self[i] = value; #endif return self; } /// /// Set count elements to the same supplied value. /// /// this public static T[] Set(this T[] self, long count, T value) { if (count > self.LongLength) count = self.LongLength; for (long i = 0; i < count; i++) self[i] = value; return self; } /// /// Set count elements starting at the supplied index to the same /// supplied value. /// /// this public static T[] Set( this T[] self, long start, long count, T value) { long end = start + Math.Min(count, self.LongLength - start); for (long i = start; i < end; i++) self[i] = value; return self; } /// /// Set all elements to a function of the element index. /// /// this public static T[] SetByIndex(this T[] self, Func index_fun) { int count = self.Length; for (int i = 0; i < count; i++) self[i] = index_fun(i); return self; } /// /// Set all elements to a function of the element index. /// /// this public static T[] SetByIndexLong(this T[] self, Func index_fun) { long count = self.LongLength; for (long i = 0; i < count; i++) self[i] = index_fun(i); return self; } /// /// Set count elements to a function of the element index. /// /// this public static T[] SetByIndex( this T[] self, int count, Func index_fun) { if (count > self.Length) count = self.Length; for (int i = 0; i < count; i++) self[i] = index_fun(i); return self; } /// /// Set count elements to a function of the element index. /// /// this public static T[] SetByIndexLong( this T[] self, long count, Func index_fun) { if (count > self.LongLength) count = self.LongLength; for (long i = 0; i < count; i++) self[i] = index_fun(i); return self; } /// /// Set count elements starting at the supplied index to a function /// of the element index. /// /// this public static T[] SetByIndex( this T[] self, int start, int count, Func index_fun) { int end = Math.Min(start + count, self.Length); for (int i = start; i < end; i++) self[i] = index_fun(i); return self; } /// /// Set count elements starting at the supplied index to a function /// of the element index. /// /// this public static T[] SetByIndexLong( this T[] self, long start, long count, Func index_fun) { long end = Math.Min(start + count, self.LongLength); for (long i = start; i < end; i++) self[i] = index_fun(i); return self; } /// /// Set all elements to the elements of the supplied array. /// public static T[] Set(this T[] self, T[] array) { long len = Math.Min(self.LongLength, array.LongLength); for (long i = 0; i < len; i++) self[i] = array[i]; return self; } /// /// Set all elements to the same supplied value. /// /// this public static T[,] Set(this T[,] self, T value) { for (long i = 0; i < self.GetLongLength(0); i++) for (long j = 0; j < self.GetLongLength(1); j++) self[i, j] = value; return self; } #endregion #region Generic Array Copying /// /// Creates a copy of the array. /// public static T[] Copy(this T[] array) { var count = array.LongLength; var result = new T[count]; Array.Copy(array, result, count); return result; } /// /// Create a copy of the specified length. If the copy is longer /// it is filled with default elements. /// public static T[] Copy(this T[] array, long count) { var result = new T[count]; var len = Math.Min(count, array.LongLength); Array.Copy(array, result, len); return result; } /// /// Create a copy of the specified length. If the copy is longer /// it is filled with default elements. /// public static T[] Copy(this T[] array, int count) { var result = new T[count]; var len = Math.Min(count, array.Length); Array.Copy(array, result, len); return result; } /// /// Create a copy of the specified length starting at the specified /// start. If the copy is longer it is filled with default elements. /// public static T[] Copy(this T[] array, long start, long count) { var result = new T[count]; var len = Math.Min(count, array.LongLength - start); Array.Copy(array, start, result, 0, len); return result; } /// /// Create a copy of the specified length starting at the specified /// start. If the copy is longer it is filled with default elements. /// public static T[] Copy(this T[] array, int start, int count) { var result = new T[count]; var len = Math.Min(count, array.Length - start); Array.Copy(array, start, result, 0, len); return result; } /// /// Create a copy with the elements piped through a function. /// public static Tr[] Map(this T[] array, Func item_fun) { var len = array.LongLength; var result = new Tr[len]; for (var i = 0L; i < len; i++) result[i] = item_fun(array[i]); return result; } /// /// Create an array of resulting items by applying a supplied binary function /// to corresponding pairs of the supplied arrays. /// /// public static Tr[] Map2( this T0[] array0, T1[] array1, Func item0_item1_fun) { var len = Min(array0.LongLength, array1.LongLength); var result = new Tr[len]; for (var i = 0L; i < len; i++) result[i] = item0_item1_fun(array0[i], array1[i]); return result; } /// /// Create an array of resulting items by applying a supplied ternary function /// to corresponding triples of the supplied arrays. /// /// public static Tr[] Map3( this T0[] array0, T1[] array1, T2[] array2, Func item0_item1_item2_fun) { var len = Min(array0.LongLength, Min(array1.LongLength, array2.LongLength)); var result = new Tr[len]; for (var i = 0L; i < len; i++) result[i] = item0_item1_item2_fun(array0[i], array1[i], array2[i]); return result; } /// /// Create a copy with the elements piped through a function. /// The function gets the index of the element as a second argument. /// public static Tr[] Map(this T[] array, Func item_index_fun) { var len = array.LongLength; var result = new Tr[len]; for (var i = 0L; i < len; i++) result[i] = item_index_fun(array[i], i); return result; } public static Tr[] Map2( this T0[] array0, T1[] array1, Func item0_item1_index_fun) { var len = Min(array0.LongLength, array1.LongLength); var result = new Tr[len]; for (var i = 0L; i < len; i++) result[i] = item0_item1_index_fun(array0[i], array1[i], i); return result; } public static Tr[] Map3( this T0[] array0, T1[] array1, T2[] array2, Func item0_item1_item2_index_fun) { var len = Min(array0.LongLength, Min(array1.LongLength, array2.LongLength)); var result = new Tr[len]; for (var i = 0L; i < len; i++) result[i] = item0_item1_item2_index_fun(array0[i], array1[i], array2[i], i); return result; } /// /// Create a copy of count elements with the elements piped through a /// function. count may be longer than the array, in this case the /// result array has default elements at the end. /// public static Tr[] Map( this T[] array, long count, Func element_fun) { var result = new Tr[count]; var len = Math.Min(count, array.LongLength); for (var i = 0L; i < len; i++) result[i] = element_fun(array[i]); return result; } /// /// Create a copy of count elements with the elements piped through a /// function. count may be longer than the array, in this case the /// result array has default elements at the end. /// public static Tr[] Map( this T[] array, int count, Func element_fun) { var result = new Tr[count]; var len = Math.Min(count, array.Length); for (var i = 0; i < len; i++) result[i] = element_fun(array[i]); return result; } /// /// Create a copy of count elements with the elements piped through a /// function. count may be longer than the array, in this case the /// result array has default elements at the end. /// The function gets the index of the element as a second argument. /// public static Tr[] Map( this T[] array, long count, Func element_index_fun) { var result = new Tr[count]; var len = Math.Min(count, array.LongLength); for (var i = 0L; i < len; i++) result[i] = element_index_fun(array[i], i); return result; } /// /// Create a copy of specified length starting at the specified /// offset with the elements piped through a function. /// public static Tr[] Map( this T[] array, long start, long count, Func element_fun) { var result = new Tr[count]; var len = Math.Min(count, array.LongLength - start); for (var i = 0L; i < len; i++) result[i] = element_fun(array[start + i]); return result; } /// /// Create a copy of specified length starting at the specified /// offset with the elements piped through a function. /// public static Tr[] Map( this T[] array, int start, int count, Func element_fun) { var result = new Tr[count]; var len = Math.Min(count, array.Length - start); for (var i = 0; i < len; i++) result[i] = element_fun(array[start + i]); return result; } /// /// Create a copy of specified length starting at the specified /// offset with the elements piped through a function. /// The function gets the target index of the element as a second /// argument. /// public static Tr[] Map( this T[] array, long start, long count, Func element_index_fun) { var result = new Tr[count]; var len = Math.Min(count, array.LongLength - start); for (var i = 0L; i < len; i++) result[i] = element_index_fun(array[start + i], i); return result; } /// /// Create a copy of specified length starting at the specified /// offset with the elements piped through a function. /// The function gets the target index of the element as a second /// argument. /// public static Tr[] Map( this T[] array, int start, int count, Func element_index_fun) { var result = new Tr[count]; var len = Math.Min(count, array.Length - start); for (var i = 0; i < len; i++) result[i] = element_index_fun(array[start + i], i); return result; } /// /// Copy a range of elements to the target array. /// public static void CopyTo(this T[] array, long count, T[] target, long targetStart) => Array.Copy(array, 0, target, targetStart, count); /// /// Copy a range of elements to the target array. /// public static void CopyTo(this T[] array, int count, T[] target, int targetStart) => Array.Copy(array, 0, target, targetStart, count); /// /// Copy a range of elements to the target array. /// public static void CopyTo(this T[] array, long start, long count, T[] target, long targetStart) => Array.Copy(array, start, target, targetStart, count); /// /// Copy a range of elements to the target array. /// public static void CopyTo(this T[] array, int start, int count, T[] target, int targetStart) => Array.Copy(array, start, target, targetStart, count); /// /// Copies the array into a list. /// public static List CopyToList(this T[] array) { var result = new List(array.Length); result.AddRange(array); return result; } public static List MapToList(this T[] array, Func element_fun) { var count = array.Length; var result = new List(count); for (int i = 0; i < count; i++) result.Add(element_fun(array[i])); return result; } public static List MapToList(this T[] array, Func item_index_fun) { var count = array.Length; var result = new List(count); for (int i = 0; i < count; i++) result.Add(item_index_fun(array[i], i)); return result; } /// /// Copies the specified range of elements to the specified destination /// within the same array. /// public static void CopyRange(this T[] array, long start, long count, long targetStart) { var end = start + count; if (targetStart < start || targetStart >= end) { while (start < end) array[targetStart++] = array[start++]; } else { targetStart += count; while (start < end) array[--targetStart] = array[--end]; } } /// /// Create a copy with the elements reversed. /// public static T[] CopyReversed(this T[] array) { var result = new T[array.LongLength]; var lastIndex = array.LongLength - 1; for (var i = 0L; i <= lastIndex; i++) { result[i] = array[lastIndex - i]; } return result; } /// /// Concatenates two arrays. /// /// A new array with content of concatenated with content of . public static T[] Concat(this T[] first, T[] second) { var conArray = new T[first.Length + second.Length]; first.CopyTo(conArray, 0); second.CopyTo(conArray, first.Length); return conArray; } #endregion #region Generic Array Operations public static long LongSum(this T[] array, Func selector) { long sum = 0; for (long i = 0; i < array.LongLength; i++) sum += selector(array[i]); return sum; } public static T[] Resized(this T[] array, int newSize) { Array.Resize(ref array, newSize); return array; } public static T[] Resized(this T[] array, long newSize) { var resized = new T[newSize]; newSize = Math.Min(array.LongLength, newSize); for (long i = 0; i < newSize; i++) resized[i] = array[i]; return resized; } /// /// Enumerates the given fraction of the array elements from the /// beginning of the array. E.g. TakeFraction(0.1) would enumerate /// the first 1/10 of the array elements. Fraction must be in range /// [0.0, 1.0]. /// public static IEnumerable TakeFraction( this T[] array, double fraction) { if (fraction < 0.0 || fraction > 1.0) throw new ArgumentOutOfRangeException("Fraction not in range [0.0, 1.0]."); long take = (long)(array.LongLength * fraction); for (long i = 0; i < take; i++) yield return array[i]; } /// /// Enumerate all but last elements of an array. The number of /// elements to omit is supplied as a parameter and defaults to 1. /// public static IEnumerable SkipLast(this T[] array, long count = 1) { count = array.LongLength - count; for (long i = 0; i < count; i++) yield return array[i]; } /// /// Enumerate all but last elements of an array. The number of /// elements to omit is supplied as a parameter and defaults to 1. /// public static IEnumerable SkipLast(this T[] array, int count = 1) { return SkipLast(array, (long)count); } /// /// Merges two already sorted arrays. /// /// /// Sorted array. /// Sorted array. /// Sorted array. /// public static void Merge(this T[] array, T[] left, T[] right, Func comparer) { long li = 0, ri = 0, ti = 0; long lc = left.LongLength, rc = right.LongLength; while (li < lc && ri < rc) { if (comparer(left[li], right[ri]) < 0) { array[ti++] = left[li++]; } else { array[ti++] = right[ri++]; } } while (li < lc) array[ti++] = left[li++]; while (ri < rc) array[ti++] = right[ri++]; } private class AComparer : IComparer { public Func Fun; public int Compare(T x, T y) { return Fun(x, y); } } public static int BinarySearch(this T[] self, T item, Func comparer) { return Array.BinarySearch(self, item, new AComparer { Fun = comparer }); } public static IEnumerable Elements( this T[] array, long first, long count) { for (long e = first + count; first < e; first++) yield return array[first]; } public static IEnumerable ElementsWhere( this T[] array, int first, int count, Func predicate) { for (int end = first + count; first < end; first++) if (predicate(array[first])) yield return array[first]; } public static IEnumerable ElementsWhere( this T[] array, long first, long count, Func predicate) { for (long end = first + count; first < end; first++) if (predicate(array[first])) yield return array[first]; } #endregion #region Generic Array Modifications /// /// Apply the supplied transformation function to each element of the /// array. /// public static T[] Apply(this T[] self, Func element_fun) { long count = self.LongLength; for (long i = 0; i < count; i++) self[i] = element_fun(self[i]); return self; } /// /// Apply the supplied transformation function to the first count /// elements of the array. /// public static T[] Apply(this T[] self, long count, Func element_fun) { if (count > self.LongLength) count = self.LongLength; for (long i = 0; i < count; i++) self[i] = element_fun(self[i]); return self; } /// /// Apply the supplied transformation function to count /// elements of the array, starting at the supplied start index. /// public static T[] Apply(this T[] self, long start, long count, Func element_fun) { var end = Min(start + count, self.LongLength); for (long i = start; i < end; i++) self[i] = element_fun(self[i]); return self; } public static T[] Apply(this T[] self, Func element_index_fun) { long count = self.LongLength; for (long i = 0; i < count; i++) self[i] = element_index_fun(self[i], i); return self; } /// /// Apply the supplied transformation function to the first count /// elements of the array. /// public static T[] Apply(this T[] self, long count, Func element_index_fun) { if (count > self.LongLength) count = self.LongLength; for (long i = 0; i < count; i++) self[i] = element_index_fun(self[i], i); return self; } /// /// Apply the supplied transformation function to count /// elements of the array, starting at the supplied start index. /// public static T[] Apply(this T[] self, long start, long count, Func element_index_fun) { var end = Min(start + count, self.LongLength); for (long i = start; i < end; i++) self[i] = element_index_fun(self[i], i); return self; } /// /// Move an element from a given source index to a destination index, /// and shift all elements in between by one. /// public static void Move( this T[] self, long sourceIndex, long targetIndex) { if (sourceIndex == targetIndex) return; T help = self[sourceIndex]; if (targetIndex > sourceIndex) for (long i = sourceIndex; i < targetIndex; i++) self[i] = self[i + 1]; else for (long i = sourceIndex; i > targetIndex; i--) self[i] = self[i - 1]; self[targetIndex] = help; } /// /// Sets the array items to a mapped version of the items of array0. /// public static void SetMap( this T[] array, T0[] array0, Func item0_fun) { var count = Min(array.LongLength, array0.LongLength); for (long i = 0; i < count; i++) array[i] = item0_fun(array0[i]); } /// /// Sets the array items to a mapped version of corresponding /// pairs of items of array0 and array1. /// public static void SetMap2( this T[] array, T0[] array0, T1[] array1, Func item0_item1_fun) { var count = Min(array.LongLength, Min(array0.LongLength, array1.LongLength)); for (long i = 0; i < count; i++) array[i] = item0_item1_fun(array0[i], array1[i]); } /// /// Sets the array items to a mapped version of corresponding /// triples of items of array0, array1, and array2. /// public static void SetMap3( this T[] array, T0[] array0, T1[] array1, T2[] array2, Func item0_item1_item2_fun) { var count = Min( Min(array.LongLength, array0.LongLength), Min(array1.LongLength, array2.LongLength) ); for (long i = 0; i < count; i++) array[i] = item0_item1_item2_fun(array0[i], array1[i], array2[i]); } /// /// Swap the two elements specified by their indices. /// public static void Swap(this T[] self, int i, int j) { T help = self[i]; self[i] = self[j]; self[j] = help; } /// /// Swap the two elements specified by their indices. /// public static void Swap(this T[] self, long i, long j) { T help = self[i]; self[i] = self[j]; self[j] = help; } /// /// Reverse the order of elements in the supplied range [lo, hi[. /// public static void ReverseRange( this T[] a, long lo, long hi) { hi--; while (lo < hi) { var t = a[lo]; a[lo++] = a[hi]; a[hi--] = t; } } public static void Revert(this T[] array) { array.ReverseRange(0, array.LongLength); } /// /// Returns a copy of the array with the specified item replaced. /// public static T[] With(this T[] array, int index, T item) { if (array == null) { array = new T[index + 1]; array[index] = item; return array; } var len = array.LongLength; if (index < len) { array[index] = item; return array; } var newArray = new T[index + 1]; for (long i = 0; i < len; i++) newArray[i] = array[i]; newArray[index] = item; return newArray; } /// /// Synonym for WithAppended(). /// public static T[] WithAdded(this T[] array, T item) where T : class { return array.WithAppended(item); } /// /// Returns a copy of the array with the specified item appended /// at the end. If the item is already contained in the array, /// the original array is returned. /// public static T[] WithAppended(this T[] array, T item) where T : class { if (array == null) return new T[] { item }; var len = array.Length; for (int i = 0; i < len; i++) if (array[i] == item) return array; var newArray = new T[len + 1]; for (int i = 0; i < len; i++) newArray[i] = array[i]; newArray[len] = item; return newArray; } /// /// Returns a copy of the array with the specified item prepended /// to the front. If the item is already contained in the array, /// the original array is returned. /// public static T[] WithPrepended(this T[] array, T item) where T : class { if (array == null) return new T[] { item }; var len = array.Length; for (int i = 0; i < len; i++) if (array[i] == item) return array; var newArray = new T[len + 1]; for (int i = 0; i < len; i++) newArray[i+1] = array[i]; newArray[0] = item; return newArray; } /// /// Returns a copy of the item with the specified item removed. If the /// item is not contained in the array, the original array is returned. /// public static T[] WithRemoved(this T[] array, T item) where T : class { if (array == null) return array; var len = array.Length; if (len == 1) { if (array[0] == item) return null; } else { for (int i = 0; i < len; i++) if (array[i] == item) { var newArray = new T[len - 1]; for (int j = 0; j < i; j++) newArray[j] = array[j]; for (int j = i; j < len - 1; j++) newArray[j] = array[j + 1]; return newArray; } } return array; } #endregion #region Generic Array Functional Programming Standard Operations /// /// Performs an aggregation of all items in an array with the /// supplied aggregation function starting from the left and with the /// supplied seed, and returns the aggregated result. /// public static TSum FoldLeft( this TVal[] array, TSum seed, Func sum_item_fun) { long count = array.LongLength; for (long i = 0; i < count; i++) seed = sum_item_fun(seed, array[i]); return seed; } /// /// Performs an aggregation of all corresponding pairs of items of /// the supplied arrays with the supplied aggregation function /// starting from the left and with the supplied seed, and returns /// the aggregated result. /// public static TSum FoldLeft2( this T0[] array0, T1[] array1, TSum seed, Func sum_item0_item1_fun) { long count = Min(array0.LongLength, array1.LongLength); for (long i = 0; i < count; i++) seed = sum_item0_item1_fun(seed, array0[i], array1[i]); return seed; } /// /// Performs an aggregation of all corresponding triples of items of /// the supplied arrays with the supplied aggregation function /// starting from the left and with the supplied seed, and returns /// the aggregated result. /// public static TSum FoldLeft3( this T0[] array0, T1[] array1, T2[] array2, TSum seed, Func sum_item0_item1_item2_fun) { long count = Min(array0.LongLength, Min(array1.LongLength, array2.LongLength)); for (long i = 0; i < count; i++) seed = sum_item0_item1_item2_fun(seed, array0[i], array1[i], array2[i]); return seed; } /// /// Performs an aggregation of all items in an array with the /// supplied aggregation function starting from the right and with the /// supplied seed, and returns the aggregated result. /// public static TSum FoldRight( this TVal[] array, Func item_sum_fun, TSum seed) { long count = array.LongLength; for (long i = count - 1; i >= 0; i--) seed = item_sum_fun(array[i], seed); return seed; } /// /// Performs an aggregation of all corresponding pairs of items of /// the supplied arrays with the supplied aggregation function /// starting from the rigth and with the supplied seed, and returns /// the aggregated result. /// public static TSum FoldRight2( this T0[] array0, T1[] array1, Func item0_item1_sum_fun, TSum seed) { long count = Min(array0.LongLength, array1.LongLength); for (long i = count - 1; i >= 0; i--) seed = item0_item1_sum_fun(array0[i], array1[i], seed); return seed; } /// /// Performs an aggregation of all corresponding triples of items of /// the supplied arrays with the supplied aggregation function /// starting from the rigth and with the supplied seed, and returns /// the aggregated result. /// public static TSum FoldRight3( this T0[] array0, T1[] array1, T2[] array2, Func item0_item1_item2_sum_fun, TSum seed) { long count = Min(array0.LongLength, Min(array1.LongLength, array2.LongLength)); for (long i = count - 1; i >= 0; i--) seed = item0_item1_item2_sum_fun(array0[i], array1[i], array2[i], seed); return seed; } /// /// Performs an aggregation of the specified slice of items in an /// array with the supplied aggregation function starting from the /// left and with the initial supplied left sum, and returns the /// aggregated result. /// public static TSum FoldLeft( this TVal[] array, long start, long count, TSum seed, Func sum_item_fun) { for (long i = start, e = start + count; i < e; i++) seed = sum_item_fun(seed, array[i]); return seed; } /// /// Performs an aggregation of the specified slice of items in an /// array with the supplied aggregation function starting from the /// right and with the initial supplied right sum, and returns the /// aggregated result. /// public static TSum FoldRight( this TVal[] array, long start, long count, Func item_sum_fun, TSum seed) { for (long i = start + count - 1; i >= start; i--) seed = item_sum_fun(array[i], seed); return seed; } /// /// Performs an aggregation of all elements in an array with the /// supplied aggregation function starting from the left and with the /// initial supplied left sum. /// All intermediate results are returned as an array with the same /// length as the original. /// public static TSum[] ScanLeft( this TVal[] array, TSum leftSum, Func sum_val_addFun) { long count = array.LongLength; var result = new TSum[count]; for (long i = 0; i < count; i++) { leftSum = sum_val_addFun(leftSum, array[i]); result[i] = leftSum; } return result; } /// /// Performs an aggregation of all elements in an array with the /// supplied aggregation function starting from the left and with the /// initial supplied left sum. /// All intermediate results are returned as an array with the same /// length as the original. /// public static TSum[] ScanLeft( this TVal[] array, TSum leftSum, Func sum_val_index_addFun) { long count = array.LongLength; var result = new TSum[count]; for (long i = 0; i < count; i++) { leftSum = sum_val_index_addFun(leftSum, array[i], i); result[i] = leftSum; } return result; } /// /// Performs an aggregation of all elements in an array with the /// supplied aggregation function starting from the right and with the /// initial supplied right sum. /// All intermediate results are returned as an array with the same /// length as the original. /// public static TSum[] ScanRight( this TVal[] array, Func val_sum_addFun, TSum rightSum) { long count = array.LongLength; var result = new TSum[count]; for (long i = count - 1; i >= 0; i--) { rightSum = val_sum_addFun(array[i], rightSum); result[i] = rightSum; } return result; } /// /// Performs an aggregation of all elements in an array with the /// supplied aggregation function starting from the right and with the /// initial supplied right sum. /// All intermediate results are returned as an array with the same /// length as the original. /// public static TSum[] ScanRight( this TVal[] array, Func val_index_sum_addFun, TSum rightSum) { long count = array.LongLength; var result = new TSum[count]; for (long i = count - 1; i >= 0; i--) { rightSum = val_index_sum_addFun(array[i], i, rightSum); result[i] = rightSum; } return result; } /// /// Performs an aggregation of the specified slice of elements in an /// array with the supplied aggregation function starting from the /// left and with the initial supplied left sum. /// All intermediate results are returned as an array with the given /// count as length. /// public static TSum[] ScanLeft( this TVal[] array, long start, long count, TSum leftSum, Func sum_val_addFun) { var result = new TSum[count]; for (long i = 0; i < count; i++) { leftSum = sum_val_addFun(leftSum, array[start + i]); result[i] = leftSum; } return result; } /// /// Performs an aggregation of the specified slice of elements in an /// array with the supplied aggregation function starting from the /// left and with the initial supplied left sum. /// All intermediate results are returned as an array with the given /// count as length. /// public static TSum[] ScanLeft( this TVal[] array, long start, long count, TSum leftSum, Func sum_val_index_addFun) { var result = new TSum[count]; for (long i = 0; i < count; i++) { leftSum = sum_val_index_addFun(leftSum, array[start + i], start + i); result[i] = leftSum; } return result; } /// /// Performs an aggregation of the specified slice of elements in an /// array with the supplied aggregation function starting from the /// right and with the initial supplied right sum. /// All intermediate results are returned as an array with the given /// count as length. /// public static TSum[] ScanRight( this TVal[] array, long start, long count, Func val_sum_addFun, TSum rightSum) { var result = new TSum[count]; for (long i = count - 1; i >= 0; i--) { rightSum = val_sum_addFun(array[start + i], rightSum); result[i] = rightSum; } return result; } /// /// Performs an aggregation of the specified slice of elements in an /// array with the supplied aggregation function starting from the /// right and with the initial supplied right sum. /// All intermediate results are returned as an array with the given /// count as length. /// public static TSum[] ScanRight( this TVal[] array, long start, long count, Func val_index_sum_addFun, TSum rightSum) { var result = new TSum[count]; for (long i = count - 1; i >= 0; i--) { rightSum = val_index_sum_addFun(array[start + i], start + i, rightSum); result[i] = rightSum; } return result; } /// /// Apply the supplied mulFun to the first count corresponding pairs /// of elements from the supplied arrays. Aggregate the results /// starting with the supplied seed and the supplied addFun. /// public static TSum InnerProduct( this T1[] array, T2[] other, long count, Func mulFun, TSum seed, Func addFun) { if (array == null) throw new ArgumentException("array must be != null"); if (count > Math.Min(array.LongLength, other.LongLength)) throw new ArgumentException("count must be smaller than minimum of array lengths"); for (long i = 0; i < count; i++) seed = addFun(seed, mulFun(array[i], other[i])); return seed; } /// /// Apply the supplied mulFun to the first count corresponding pairs /// of elements from the supplied arrays. Aggregate the results /// starting with the supplied seed and the supplied addFun. /// public static TSum InnerProduct( this T1[] array, T2[] other, long count, Func mulFun, TSum seed, Func addFun, Func sum_exitIfTrueFun) { if (array == null) throw new ArgumentException("array must be != null"); if (count > Min(array.LongLength, other.LongLength)) throw new ArgumentException("count must be smaller than minimum of array lengths"); for (long i = 0; i < count; i++) { seed = addFun(seed, mulFun(array[i], other[i])); if (sum_exitIfTrueFun(seed)) break; } return seed; } /// /// Apply the supplied productFun to corresponding pairs of elements /// from supplied arrays. Aggregate the results starting with the /// supplied seed and the supplied sumFun. /// public static TSum InnerProduct( this T1[] array0, T2[] array1, Func item0_item1_productFun, TSum seed, Func sum_product_sumFun) { return InnerProduct(array0, array1, Math.Min(array0.LongLength, array1.LongLength), item0_item1_productFun, seed, sum_product_sumFun); } /// /// Apply the supplied productFun to corresponding pairs of elements /// from supplied arrays. Aggregate the results starting with the /// supplied seed and the supplied sumFun. /// public static TSum InnerProduct( this T1[] array0, T2[] array1, Func item0_item1_productFun, TSum seed, Func sum_product_sumFun, Func sum_exitIfTrueFun) { return InnerProduct(array0, array1, Math.Min(array0.LongLength, array1.LongLength), item0_item1_productFun, seed, sum_product_sumFun, sum_exitIfTrueFun); } public static TProduct[] ProductArray( this T0[] array0, T1[] array1, Func item0_item1_productFun) { return ProductArray(array0, array1, Math.Min(array0.LongLength, array1.LongLength), item0_item1_productFun); } public static TProduct[] ProductArray( this T0[] array0, T1[] array1, long count, Func item0_item1_productFun) { var result = new TProduct[count]; for (long i = 0; i < count; i++) result[i] = item0_item1_productFun(array0[i], array1[i]); return result; } public static TProduct[] ProductArray( this T0[] array0, T1[] array1, Func item0_item1_index_productFun) { return ProductArray(array0, array1, Math.Min(array0.LongLength, array1.LongLength), item0_item1_index_productFun); } public static TProduct[] ProductArray( this T0[] array0, T1[] array1, long count, Func item0_item1_index_productFun) { var result = new TProduct[count]; for (long i = 0; i < count; i++) result[i] = item0_item1_index_productFun(array0[i], array1[i], i); return result; } public static bool AllEqual( this T0[] array0, T1[] array1, Func item0_item1_equalFun) { var len = array0.LongLength; return len == array1.LongLength && array0.InnerProduct(array1, len, item0_item1_equalFun, true, (s, p) => s && p, s => !s); } #endregion #region Generic Jagged Array Operations /// /// Use this instead of Clone() or Copy() in order to get a full copy of the jagged array back. /// public static T[][] JaggedCopy(this T[][] array) { long count = array.LongLength; var result = new T[count][]; for (long i = 0; i < count; i++) result[i] = array[i].Copy(); return result; } public static T[][][] JaggedCopy(this T[][][] array) { long count = array.LongLength; var result = new T[count][][]; for (long i = 0; i < count; i++) result[i] = array[i].JaggedCopy(); return result; } public static long FlatCount(this T[][] array) { return array.LongSum(a => a.LongLength); } public static long FlatCount(this T[][][] array) { return array.LongSum(a => a.LongSum(b => b.LongLength)); } public static void FlatCopyTo(this T[][] array, T[] target, long start) { for (long j = 0; j < array.LongLength; j++) { var aj = array[j]; for (long i = 0; i < aj.LongLength; i++) target[start++] = aj[i]; } } public static void FlatCopyTo(this T[][][] array, T[] target, long start) { for (long k = 0; k < array.LongLength; k++) { var ak = array[k]; for (long j = 0; j < ak.LongLength; j++) { var akj = ak[j]; for (long i = 0; i < akj.LongLength; i++) target[start++] = akj[i]; } } } public static T[] FlatCopy(this T[][] array) { var result = new T[array.FlatCount()]; array.FlatCopyTo(result, 0); return result; } public static T[] FlatCopy(this T[][][] array) { var result = new T[array.FlatCount()]; array.FlatCopyTo(result, 0); return result; } #endregion #region Mapped Copy Functions public static int ForwardMapAdd( this int[] forwardMap, int index, ref int forwardCount) { int newIndex = forwardMap[index]; if (newIndex < 0) forwardMap[index] = newIndex = forwardCount++; return newIndex; } static public int ForwardMapAdd( this int[] forwardMap, int forwardCount, int[] indexArray, int indexCount) { for (int i = 0; i < indexCount; i++) { int index = indexArray[i]; if (forwardMap[index] < 0) forwardMap[index] = forwardCount++; } return forwardCount; } /// /// Copies from this array into the target array starting at the /// supplied offset and using the supplied forward map that /// specifies the new index for each element. The forward map /// may contain negative values for elements to be skipped. /// public static void ForwardMappedCopyTo( this T[] sourceArray, T[] targetArray, int[] forwardMap, int offset) { for (int i = 0; i < forwardMap.Length; i++) { int ni = forwardMap[i]; if (ni >= 0) targetArray[ni + offset] = sourceArray[i]; } } /// /// Copies from this array into the target array starting at the /// supplied offset using the supplied backward map that contains /// the source index for each index of the target array. /// public static void BackMappedCopyTo( this T[] source, T[] target, int[] backMap, int offset) { int count = backMap.Length; for (int i = 0; i < count; i++) target[i + offset] = source[backMap[i]]; } public static void BackMappedGroupCopyTo( this T[] source, int[] groupBackMap, int groupCount, int[] fia, T[] target, int start) { for (int gi = 0; gi < groupCount; gi++) { int ogi = groupBackMap[gi]; if (ogi < 0) continue; for (int ogei = fia[ogi], ogee = fia[ogi + 1]; ogei < ogee; ogei++) target[start++] = source[ogei]; } } public static void BackMappedGroupCopyTo( this int[] source, int[] groupBackMap, int groupCount, int[] fia, int[] elementForwardMap, int[] target, int start) { for (int gi = 0; gi < groupCount; gi++) { int ogi = groupBackMap[gi]; if (ogi < 0) continue; for (int ogei = fia[ogi], ogee = fia[ogi + 1]; ogei < ogee; ogei++) target[start++] = elementForwardMap[source[ogei]]; } } /// /// Copies from this array into the target array starting at the /// supplied offset using the supplied backward map that contains /// the source index for each index of the target array. /// public static void BackMappedCopyTo( this T[] source, T[] target, long[] backMap, long offset) { long count = backMap.LongLength; for (long i = 0; i < count; i++) target[i + offset] = source[backMap[i]]; } /// /// Returns a copy of this array by placing each element at a new /// position specified by the supplied forward map. The forward map /// may contain negative values for elements that should not be /// copied. The length of the result is computed to hold all forward /// mapped elements of the soruce array. /// public static T[] ForwardMappedCopy( this T[] sourceArray, int[] forwardMap) { return sourceArray.ForwardMappedCopy(forwardMap, forwardMap.Max() + 1); } /// /// Returns a copy of this array by placing each element at a new /// position specified by the supplied forward map. The forward map /// may contain negative values for elements that should not be /// copied. The length of the result needs to be supplied as /// a parameter. /// public static T[] ForwardMappedCopy( this T[] sourceArray, int[] forwardMap, int targetLength) { T[] targetArray = new T[targetLength]; sourceArray.ForwardMappedCopyTo(targetArray, forwardMap, 0); return targetArray; } /// /// Returns a copy of this array that is created by copying the /// elements at the positions specified in the supplied backward /// map. An optional count argument is used for the size of the /// resulting array. /// public static T[] BackMappedCopy( this T[] array, int[] backMap, int count = 0) { if (count <= 0) count = backMap.Length; var target = new T[count]; count = Min(backMap.Length, count); for (int i = 0; i < count; i++) target[i] = array[backMap[i]]; return target; } /// /// Returns a copy of this array that is created by copying the /// elements at the positions specified in the supplied backward /// map. An optional count argument is used for the size of the /// resulting array. /// public static T[] BackMappedCopySafe( this T[] array, int[] backMap, T defaultValue, int count = 0) { if (count <= 0) count = backMap.Length; var target = new T[count].Set(defaultValue); count = Min(backMap.Length, count); for (int i = 0; i < count; i++) { var ti = backMap[i]; if (ti < 0) continue; target[i] = array[ti]; } return target; } /// /// Returns a copy of this array that is created by copying the /// elements at the positions specified in the supplied backward /// map and applying a function to each element. An optional /// count argument is used for the size of the resulting array. /// public static Tr[] BackMappedCopy( this T[] array, int[] backMap, Func fun, int count = 0) { if (count <= 0) count = backMap.Length; var target = new Tr[count]; count = Min(backMap.Length, count); for (int i = 0; i < count; i++) target[i] = fun(array[backMap[i]]); return target; } /// /// Returns a copy of this array that is created by copying the /// elements at the positions specified in the supplied backward /// map. An optional count argument is used for the size of the /// resulting array. /// public static T[] BackMappedCopy( this T[] array, long[] backMap, long count = 0) { if (count <= 0) count = backMap.LongLength; var target = new T[count]; count = Min(backMap.Length, count); for (long i = 0; i < count; i++) target[i] = array[backMap[i]]; return target; } /// /// Returns a copy of this array that is created by copying the /// elements at the positions specified in the supplied backward /// map and applying a function to each element. An optional /// count argument is used for the size of the resulting array. /// public static Tr[] BackMappedCopy( this T[] array, long[] backMap, Func fun, long count = 0) { if (count <= 0) count = backMap.LongLength; var target = new Tr[count]; count = Min(backMap.Length, count); for (long i = 0; i < count; i++) target[i] = fun(array[backMap[i]]); return target; } /// /// Returns a copy of this array that is created by copying the /// elements at the positions specified in the index array of the /// supplied backward map. If the index array is null only the /// backward map is used to compute the position. An optional count /// argument is used for the size of the resulting array. /// public static T[] BackMappedCopy( this T[] array, int[] indexArray, int[] backMap, int count = 0) { if (indexArray == null) return array.BackMappedCopy(backMap, count); if (count <= 0) count = backMap.Length; var target = new T[count]; count = Min(backMap.Length, count); for (int i = 0; i < count; i++) target[i] = array[indexArray[backMap[i]]]; return target; } /// /// Returns a copy of this array that is created by copying the /// elements at the positions specified in the index array of the /// supplied backward map and applying a function to each element. /// If the index array is null only the backward map is used to /// compute the position. An optional count argument is used for /// the size of the resulting array. /// public static Tr[] BackMappedCopy( this T[] array, int[] indexArray, int[] backMap, Func fun, int count = 0) { if (indexArray == null) return array.BackMappedCopy(backMap, fun, count); if (count <= 0) count = backMap.Length; var target = new Tr[count]; count = Min(backMap.Length, count); for (int i = 0; i < count; i++) target[i] = fun(array[indexArray[backMap[i]]]); return target; } /// /// Copies all source arrays into this array, using the supplied /// array of forward maps. /// /// targetArray public static T[] ForwardMappedCopyFrom( this T[] targetArray, T[][] sourceArrays, int[][] forwardMaps) { var offset = 0; for (int i = 0; i < sourceArrays.Length; i++) { sourceArrays[i].ForwardMappedCopyTo( targetArray, forwardMaps[i], offset); offset += forwardMaps[i].Max() + 1; } return targetArray; } /// /// copies all srcArrays into this array /// indexed by an inversed indexMap /// returns itself /// public static T[] BackMappedCopyFrom( this T[] targetArray, T[][] sourceArrays, int[][] backwardMaps) { int offset = 0; int count = sourceArrays.Length; for (int i = 0; i < count; i++) { sourceArrays[i].BackMappedCopyTo( targetArray, backwardMaps[i], offset); offset += backwardMaps[i].Length; } return targetArray; } /// /// copies this indexArray to destinationIndexArray /// over iaIndexMap at position diaOffset /// and returns aIndexMap for /// copying the arrays that are indexed by sourceIndexArray /// !! destinationIndexArray has to be initialized with -1 /// public static int[] ForwardMappedCopyIndexArrayTo( this int[] sourceArray, int[] targetArray, int[] forwardMap, int targetOffset) { int count = forwardMap.Max() + 1; int targetIndexOffset = targetArray.Max() + 1; // creating destinationIndexArray, still indexing sourceArray sourceArray.ForwardMappedCopyTo( targetArray, forwardMap, targetOffset); var indexMap = new int[sourceArray.Max() + 1].Set(-1); var indexCount = 0; for (var ti = targetOffset; ti < targetOffset + count; ti++) { var oldIndex = targetArray[ti]; // creating indexMap var newIndex = indexMap[oldIndex]; if (newIndex == -1) indexMap[oldIndex] = newIndex = indexCount++; // reindexing targetArray targetArray[ti] = newIndex + targetIndexOffset; } return indexMap; } /// /// Copies this index array to the target array over iaIndexMap at /// position diaOffset and returns aIndexMap for /// copying the arrays that are indexed by sourceIndexArray /// !! destinationIndexArray has to be initialized with -1 /// public static int[] BackMappedCopyIndexArrayTo( this int[] sourceArray, int[] targetArray, int[] backwardMap, int targetOffest) { int count = backwardMap.Length; int targetIndexOffset = targetArray.Max() + 1; // creating targetArray, still indexing sourceArray sourceArray.BackMappedCopyTo( targetArray, backwardMap, targetOffest); var indexMap = new int[sourceArray.Max() + 1].Set(-1); var indexCount = 0; for (var ti = targetOffest; ti < targetOffest + count; ti++) { var oldIndex = targetArray[ti]; // creating indexMap var newIndex = indexMap[oldIndex]; if (newIndex == -1) indexMap[oldIndex] = newIndex = indexCount++; // reindexing targetArray targetArray[ti] = newIndex + targetIndexOffset; } return indexMap; } /// /// copies from this indexArray to destinationIndexArray /// over iaIndexMap /// and returns aIndexMap for /// copying the arrays that are indexed by sourceIndexArray /// public static int[] ForwardMappedCopyIndexArrayTo( this int[] sourceArray, out int[] targetArray, int[] forwardMap) { targetArray = new int[forwardMap.Max() + 1].Set(-1); return sourceArray.ForwardMappedCopyIndexArrayTo( targetArray, forwardMap, 0); } /// /// copies from this indexArray to destinationIndexArray /// over iaIndexMap /// and returns aIndexMap for /// copying the arrays that are indexed by sourceIndexArray /// public static int[] BackMappedCopyIndexArrayTo( this int[] sourceArray, out int[] targetArray, int[] backwardMap) { targetArray = new int[backwardMap.Length].Set(-1); return sourceArray.BackMappedCopyIndexArrayTo( targetArray, backwardMap, 0); } /// /// copies all srcIndexArrays to this indexArray /// over iaIndexMaps /// and returns aIndexMaps for /// copying the arrays that are indexed by srcIndexArrays /// public static int[][] ForwardMappedCopyFromIndexArrays( this int[] targetArray, int[][] sourceArrays, int[][] forwardMaps) { var count = sourceArrays.Length; var indexMaps = new int[count][]; var offset = 0; for (int i = 0; i < count; i++) { indexMaps[i] = sourceArrays[i] .ForwardMappedCopyIndexArrayTo( targetArray, forwardMaps[i], offset); offset += forwardMaps[i].Max() + 1; } return indexMaps; } /// /// copies all srcIndexArrays to this indexArray /// over iaIndexMaps /// and returns aIndexMaps for /// copying the arrays that are indexed by srcIndexArrays /// public static int[][] BackMappedCopyFromIndexArrays( this int[] targetArray, int[][] sourceArrays, int[][] backwardMaps) { var count = sourceArrays.Length; var indexMaps = new int[count][]; var offset = 0; for (int i = 0; i < count; i++) { indexMaps[i] = sourceArrays[i] .BackMappedCopyIndexArrayTo( targetArray, backwardMaps[i], offset); offset += backwardMaps[i].Length; } return indexMaps; } public static void ReverseGroups( this T[] array, int[] groupFirstIndices, int groupCount, Func reverseMap) { for (int gvi = groupFirstIndices[0], fi = 0; fi < groupCount; fi++) { int gve = groupFirstIndices[fi + 1]; if (reverseMap(fi)) for (int rfvi = gve - 1; gvi < rfvi; gvi++, rfvi--) array.Swap(gvi, rfvi); gvi = gve; } } /// /// Return an array with reversed groups. The specified first group /// indices array defines which consecutive elements constitute a /// group, and the reverse map function specifies wich of these /// groups should actually be reversed. /// public static T[] GroupReversedCopy( this T[] array, int[] groupFirstIndices, int groupCount, Func reverseMap) { var result = new T[array.Length]; for (int gvi = groupFirstIndices[0], gi = 0; gi < groupCount; gi++) { int gve = groupFirstIndices[gi + 1]; if (reverseMap(gi)) for (int rgvi = gve; gvi < gve; gvi++) result[--rgvi] = array[gvi]; else for (; gvi < gve; gvi++) result[gvi] = array[gvi]; } return result; } #endregion #region Creating Backward Maps /// /// returns the inverse of the given indexMap /// (be carefull with inversing inversedIndexMaps => can be to short! /// fix if needed: use inverseIndexMap(int[] indexMap, int size) instead) /// public static int[] CreateBackMap( this int[] forwardMap) { return CreateBackMap(forwardMap, forwardMap.Max() + 1); } public static int[] CreateBackToFirstMap( this int[] forwardMap, int resultLength) { var backMap = new int[resultLength].Set(-1); var count = forwardMap.Length; for (int i = 0; i < count; i++) { int ni = forwardMap[i]; if (ni < 0) continue; if (backMap[ni] < 0) backMap[ni] = i; } return backMap; } /// /// returns the backward map in the given size of the given forward map /// public static int[] CreateBackMap( this int[] forwardMap, int resultLength) { var backMap = new int[resultLength].Set(-1); var count = forwardMap.Length; for (int i = 0; i < count; i++) { int ni = forwardMap[i]; if (ni < 0) continue; backMap[ni] = i; } return backMap; } public static int[] CreateBackMap( this int[] forwardMap, int resultLength, int offset) { var backMap = new int[resultLength]; var count = forwardMap.Length; for (int i = 0; i < count; i++) { int ni = forwardMap[i]; if (ni < 0) continue; backMap[ni - offset] = i; } return backMap; } #endregion #region Integration /// /// Converts an array that contains the number of elements /// at each index into an array that holds the indices of /// the first element if the elements are stored in /// consecutive order. Returns the sum of all elements. /// Using double precision during integration. /// public static double Integrate(this float[] array, double sum = 0) { for (long i = 0; i < array.LongLength; i++) { var delta = array[i]; array[i] = (float)sum; sum += delta; } return sum; } /// /// Converts an array that contains the number of elements /// at each index into an array that holds the indices of /// the first element if the elements are stored in /// consecutive order. Returns the sum of all elements. /// Using single precision during integration. /// public static float Integrate(this float[] array, float sum = 0) { for (long i = 0; i < array.LongLength; i++) { var delta = array[i]; array[i] = sum; sum += delta; } return sum; } /// /// Converts an array that contains the number of elements /// at each index into an array that holds the indices of /// the first element if the elements are stored in /// consecutive order. Returns the sum of all elements. /// public static int Integrate(this int[] array, int sum = 0) { for (long i = 0; i < array.LongLength; i++) { var delta = array[i]; array[i] = sum; sum += delta; } return sum; } /// /// Converts an array that contains the number of elements /// at each index into an array that holds the indices of /// the first element if the elements are stored in /// consecutive order. Returns the sum of all elements. /// public static long Integrate(this long[] array, long sum = 0) { for (long i = 0; i < array.LongLength; i++) { var delta = array[i]; array[i] = sum; sum += delta; } return sum; } /// /// Integrates the array and returns the sum. Note that the /// value of the starting element will be the supplied initial /// sum value after the operation. /// public static double Integrate(this double[] array, double sum = 0.0) { for (long i = 0; i < array.LongLength; i++) { var value = array[i]; array[i] = sum; sum += value; } return sum; } /// /// Creates an array that contains the integrated sum up to each element of input array. /// The length of the integrated array is +1 of the input array and contains the total /// sum in the last element. /// Using double precision during integration. /// public static float[] Integrated(this float[] array, double sum = 0) { var integrated = new float[array.Length + 1]; integrated[0] = (float)sum; for (long i = 0; i < array.LongLength;) { sum += array[i]; integrated[++i] = (float)sum; } return integrated; } /// /// Creates an array that contains the integrated sum up to each element of input array. /// The length of the integrated array is +1 of the input array and contains the total /// sum in the last element. /// Using single precision during integration. /// public static float[] Integrated(this float[] array, float sum = 0) { var integrated = new float[array.Length + 1]; integrated[0] = sum; for (long i = 0; i < array.LongLength;) { sum += array[i]; integrated[++i] = sum; } return integrated; } /// /// Creates an array that contains the integrated sum up to each element of input array. /// The length of the integrated array is +1 of the input array and contains the total /// sum in the last element. /// public static int[] Integrated(this int[] array, int sum = 0) { var integrated = new int[array.Length + 1]; integrated[0] = sum; for (long i = 0; i < array.LongLength;) { sum += array[i]; integrated[++i] = sum; } return integrated; } /// /// Creates an array that contains the integrated sum up to each element of input array. /// The length of the integrated array is +1 of the input array and contains the total /// sum in the last element. /// public static long[] Integrated(this long[] array, long sum = 0) { var integrated = new long[array.Length + 1]; integrated[0] = sum; for (long i = 0; i < array.LongLength;) { sum += array[i]; integrated[++i] = sum; } return integrated; } /// /// Creates an array that contains the integrated sum up to each element of input array. /// The length of the integrated array is +1 of the input array and contains the total /// sum in the last element. /// public static double[] Integrated(this double[] array, double sum = 0) { var integrated = new double[array.Length + 1]; integrated[0] = sum; for (long i = 0; i < array.LongLength;) { sum += array[i]; integrated[++i] = sum; } return integrated; } #endregion #region Dense Forward Maps /// /// Count the indices in an index array that are actually used. /// static public int DenseCount( this int[] indexArray, int indexCount, int maxIndex) { int[] forwardMap = new int[maxIndex].Set(-1); return forwardMap.ForwardMapAdd(0, indexArray, indexCount); } /// /// Create a forward map from an index array that contains new /// indices in such a way, that no index is unused. /// static public int[] DenseForwardMap( this int[] indexArray, int indexCount, int maxIndex, out int denseCount) { int[] forwardMap = new int[maxIndex].Set(-1); denseCount = forwardMap.ForwardMapAdd( 0, indexArray, indexCount); return forwardMap; } public static int[] DenseForwardMap( this int[] indexArray, int[] groupSelectionArray, int groupSize, out int denseCount) { int count = 0; int[] forwardMap = new int[indexArray.Length].Set(-1); for (int gi = 0; gi < groupSelectionArray.Length; gi++) { int g = groupSelectionArray[gi] * groupSize; for (int i = g; i < g + groupSize; i++) { int index = indexArray[i]; if (forwardMap[index] < 0) forwardMap[index] = count++; } } denseCount = count; return forwardMap; } #endregion #region Comparable Array public static T[] MergeSorted(this T[] a0, T[] a1) where T : IComparable { int count0 = a0.Length; int count1 = a1.Length; var a = new T[count0 + count1]; int i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0].CompareTo(a1[i1]) < 0) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } public static int IndexOfMin(this T[] a) where T : IComparable { int index = 0; T min = a[0]; for (int i = 1; i < a.Length; i++) if (a[i].CompareTo(min) < 0) { min = a[i]; index = i; } return index; } public static int IndexOfMin(this T[] a, int start, int count) where T : IComparable { int index = start; T min = a[start]; for (int i = start + 1, e = start + count; i < e; i++) if (a[i].CompareTo(min) < 0) { min = a[i]; index = i; } return index; } public static int IndexOfMax(this T[] a) where T : IComparable { int index = 0; T max = a[0]; for (int i = 1; i < a.Length; i++) if (a[i].CompareTo(max) > 0) { max = a[i]; index = i; } return index; } public static int IndexOfMax(this T[] a, int start, int count) where T : IComparable { int index = start; T max = a[start]; for (int i = start + 1, e = start + count; i < e; i++) if (a[i].CompareTo(max) > 0) { max = a[i]; index = i; } return index; } public static int IndexOfMin(this T[] a, Func compare) { int index = 0; T min = a[0]; for (int i = 1; i < a.Length; i++) if (compare(a[i], min) < 0) { min = a[i]; index = i; } return index; } public static int IndexOfMax(this T[] a, Func compare) { int index = 0; T max = a[0]; for (int i = 1; i < a.Length; i++) if (compare(a[i], max) > 0) { max = a[i]; index = i; } return index; } public static long LongIndexOfMin(this T[] a) where T : IComparable { long index = 0; T min = a[0]; for (long i = 1; i < a.LongLength; i++) if (a[i].CompareTo(min) < 0) { min = a[i]; index = i; } return index; } public static long LongIndexOfMax(this T[] a) where T : IComparable { long index = 0; T max = a[0]; for (long i = 1; i < a.LongLength; i++) if (a[i].CompareTo(max) > 0) { max = a[i]; index = i; } return index; } public static long LongIndexOfMin(this T[] a, Func compare) { long index = 0; T min = a[0]; for (long i = 1; i < a.LongLength; i++) if (compare(a[i], min) < 0) { min = a[i]; index = i; } return index; } public static long LongIndexOfMax(this T[] a, Func compare) { long index = 0; T max = a[0]; for (long i = 1; i < a.LongLength; i++) if (compare(a[i], max) > 0) { max = a[i]; index = i; } return index; } #endregion #region Multi-Dimensional Arrays /// /// Set all elements to a function of the element index. /// /// this public static T[,] SetByIndex(this T[,] self, Func fun) { int count0 = self.GetLength(0); int count1 = self.GetLength(1); for (int i0 = 0; i0 < count0; i0++) for (int i1 = 0; i1 < count1; i1++) self[i0, i1] = fun(i0, i1); return self; } /// /// Set all elements to a function of the element index. /// /// this public static T[,] SetByIndexLong(this T[,] self, Func fun) { long count0 = self.GetLongLength(0); long count1 = self.GetLongLength(1); for (long i0 = 0; i0 < count0; i0++) for (long i1 = 0; i1 < count1; i1++) self[i0, i1] = fun(i0, i1); return self; } /// /// Set all elements to a function of the element index. /// /// this public static T[, ,] SetByIndex(this T[, ,] self, Func fun) { int count0 = self.GetLength(0); int count1 = self.GetLength(1); int count2 = self.GetLength(2); for (int i0 = 0; i0 < count0; i0++) for (int i1 = 0; i1 < count1; i1++) for (int i2 = 0; i2 < count2; i2++) self[i0, i1, i2] = fun(i0, i1, i2); return self; } /// /// Set all elements to a function of the element index. /// /// this public static T[, ,] SetByIndexLong(this T[, ,] self, Func fun) { long count0 = self.GetLongLength(0); long count1 = self.GetLongLength(1); long count2 = self.GetLongLength(2); for (long i0 = 0; i0 < count0; i0++) for (long i1 = 0; i1 < count1; i1++) for (long i2 = 0; i2 < count2; i2++) self[i0, i1, i2] = fun(i0, i1, i2); return self; } #endregion #region Memcopy /// /// Copies the specified part of an array to the target-pointer. /// NOTE: May cause AccessViolationException if the target-pointer /// is not sufficiently allocated. /// /// The input Array /// The start index for copying /// The number of elements to copy /// The target pointer public static void CopyTo(this Array input, int offset, int length, IntPtr target) { var gc = GCHandle.Alloc(input, GCHandleType.Pinned); try { var typeSize = input.GetType().GetElementType().GetCLRSize(); var dataSize = length * typeSize; unsafe { var src = gc.AddrOfPinnedObject() + offset * typeSize; Buffer.MemoryCopy(src.ToPointer(), target.ToPointer(), dataSize, dataSize); }; } finally { gc.Free(); } } public static void CopyTo(this Array input, int length, IntPtr target) => CopyTo(input, 0, length, target); public static void CopyTo(this Array input, IntPtr target) => CopyTo(input, 0, input.Length, target); public static void CopyTo(this IntPtr input, Array target, int offset, int length) { var gc = GCHandle.Alloc(target, GCHandleType.Pinned); try { var typeSize = target.GetType().GetElementType().GetCLRSize(); var dataSize = length * typeSize; unsafe { var dst = gc.AddrOfPinnedObject() + offset * typeSize; Buffer.MemoryCopy(input.ToPointer(), dst.ToPointer(), dataSize, dataSize); }; } finally { gc.Free(); } } public static void CopyTo(this IntPtr input, Array target, int length) => CopyTo(input, target, 0, length); public static void CopyTo(this IntPtr input, Array target) => CopyTo(input, target, target.Length); public static void CopyTo(this IntPtr input, IntPtr target, int size) { unsafe { Buffer.MemoryCopy(input.ToPointer(), target.ToPointer(), size, size); }; } #if NET6_0_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span AsByteSpan(this Array data) { var elementSize = data.GetType().GetElementType().GetCLRSize(); var span = MemoryMarshal.CreateSpan(ref MemoryMarshal.GetArrayDataReference(data), data.Length * elementSize); return span; } #endif [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span AsByteSpan(this T[] data) where T : struct { return MemoryMarshal.AsBytes(data.AsSpan()); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ReadOnlySpan AsByteSpan(this string data) { return MemoryMarshal.AsBytes(data.AsSpan()); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span AsCastSpan(this TFrom[] arr) where TFrom : struct where TTo : struct { return MemoryMarshal.Cast(arr.AsSpan()); } internal static unsafe T UseAsStream(this Array data, Func action) { var gc = GCHandle.Alloc(data, GCHandleType.Pinned); var l = data.GetType().GetElementType().GetCLRSize() * data.Length; try { using var stream = new UnmanagedMemoryStream(((byte*)gc.AddrOfPinnedObject())!, l, l, FileAccess.Read); return action(stream); } finally { gc.Free(); } } internal static unsafe void UseAsStream(this Array data, Action action) { var gc = GCHandle.Alloc(data, GCHandleType.Pinned); var l = data.GetType().GetElementType().GetCLRSize() * data.Length; try { using var stream = new UnmanagedMemoryStream(((byte*)gc.AddrOfPinnedObject())!, l, l, FileAccess.Read); action(stream); } finally { gc.Free(); } } #endregion #region Hashes #region MD5 /// /// Computes the MD5 hash of the data array. /// /// 128bit/16byte data hash public static byte[] ComputeMD5Hash(this byte[] data) { #if NET6_0_OR_GREATER return MD5.HashData(data); #else using var md5 = MD5.Create(); return md5.ComputeHash(data); #endif } /// /// Computes the MD5 hash of the data array. /// /// 128bit/16byte data hash public static byte[] ComputeMD5Hash(this Array data) { #if NET6_0_OR_GREATER return MD5.HashData(data.AsByteSpan()); #else using var md5 = MD5.Create(); return data.UseAsStream((stream) => md5.ComputeHash(stream)); #endif } /// /// Computes the MD5 hash of the data array. /// /// 128bit/16byte data hash public static byte[] ComputeMD5Hash(this T[] data) where T : struct #if NET6_0_OR_GREATER => MD5.HashData(data.AsByteSpan()); #else => ((Array)data).ComputeMD5Hash(); #endif /// /// Computes the MD5 hash of the given string. /// 128bit/16byte data hash /// public static byte[] ComputeMD5Hash(this string s) { #if NET6_0_OR_GREATER return MD5.HashData(s.AsByteSpan()); #else return Encoding.Unicode.GetBytes(s).ComputeMD5Hash(); #endif } #endregion #region SHA1 /// /// Computes the SHA1 hash of the data array. /// /// 160bit/20byte data hash public static byte[] ComputeSHA1Hash(this byte[] data) { #if NET6_0_OR_GREATER return SHA1.HashData(data); #else using var sha = SHA1.Create(); var hash = sha.ComputeHash(data); return hash; #endif } /// /// Computes the SHA1 hash of the data array. /// /// 160bit/20byte data hash public static byte[] ComputeSHA1Hash(this Array data) { #if NET6_0_OR_GREATER return SHA1.HashData(data.AsByteSpan()); #else using var sha = SHA1.Create(); return data.UseAsStream((stream) => sha.ComputeHash(stream)); #endif } /// /// Computes the SHA1 hash of the data array. /// /// 160bit/20byte data hash public static byte[] ComputeSHA1Hash(this T[] data) where T : struct #if NET6_0_OR_GREATER => SHA1.HashData(data.AsByteSpan()); #else => ((Array)data).ComputeSHA1Hash(); #endif /// /// Computes the SHA1 hash of the given string. /// 160bit/20byte data hash /// public static byte[] ComputeSHA1Hash(this string s) { #if NET6_0_OR_GREATER return SHA1.HashData(s.AsByteSpan()); #else return Encoding.Unicode.GetBytes(s).ComputeSHA1Hash(); #endif } #endregion #region SHA256 /// /// Computes the SHA256 hash of the data array. /// /// 256bit/32byte data hash public static byte[] ComputeSHA256Hash(this byte[] data) { #if NET6_0_OR_GREATER return SHA256.HashData(data); #else using var sha = SHA256.Create(); var hash = sha.ComputeHash(data); return hash; #endif } /// /// Computes the SHA256 hash of the data array. /// /// 256bit/32byte data hash public static byte[] ComputeSHA256Hash(this Array data) { #if NET6_0_OR_GREATER return SHA256.HashData(data.AsByteSpan()); #else using var sha = SHA256.Create(); return data.UseAsStream((stream) => sha.ComputeHash(stream)); #endif } /// /// Computes the SHA256 hash of the data array. /// /// 256bit/32byte data hash public static byte[] ComputeSHA256Hash(this T[] data) where T : struct #if NET6_0_OR_GREATER => SHA256.HashData(data.AsByteSpan()); #else => ((Array)data).ComputeSHA256Hash(); #endif /// /// Computes the SHA256 hash of the given string. /// /// 256bit/32byte data hash public static byte[] ComputeSHA256Hash(this string s) { #if NET6_0_OR_GREATER return SHA256.HashData(s.AsByteSpan()); #else return Encoding.Unicode.GetBytes(s).ComputeSHA256Hash(); #endif } #endregion #region SHA512 /// /// Computes the SHA512 hash of the data array. /// /// 512bit/64byte data hash public static byte[] ComputeSHA512Hash(this byte[] data) { #if NET6_0_OR_GREATER return SHA512.HashData(data); #else using var sha = SHA512.Create(); var hash = sha.ComputeHash(data); return hash; #endif } /// /// Computes the SHA512 hash of the data array. /// /// 512bit/64byte data hash public static byte[] ComputeSHA512Hash(this Array data) { #if NET6_0_OR_GREATER return SHA512.HashData(data.AsByteSpan()); #else using var sha = SHA512.Create(); return data.UseAsStream((stream) => sha.ComputeHash(stream)); #endif } /// /// Computes the SHA512 hash of the data array. /// /// 512bit/64byte data hash public static byte[] ComputeSHA512Hash(this T[] data) where T : struct #if NET6_0_OR_GREATER => SHA512.HashData(data.AsByteSpan()); #else => ((Array)data).ComputeSHA512Hash(); #endif /// /// Computes the SHA512 hash of the given string. /// /// 512bit/64byte data hash public static byte[] ComputeSHA512Hash(this string s) { #if NET6_0_OR_GREATER return SHA512.HashData(s.AsByteSpan()); #else return Encoding.Unicode.GetBytes(s).ComputeSHA512Hash(); #endif } #endregion #region Adler32 /// /// Computes a checksum of the data array using the Adler-32 algorithm (). /// public static uint ComputeAdler32Checksum(this byte[] data) { var a = new Adler32(); a.Update(data); return a.Checksum; } /// /// Computes a checksum of the data array using the Adler-32 algorithm (). /// public static uint ComputeAdler32Checksum(this Array data) { var a = new Adler32(); if (data != null) { #if NET6_0_OR_GREATER a.Update(data.AsByteSpan()); #else data.UseAsStream((stream) => a.Update(stream)); #endif } return a.Checksum; } /// /// Computes a checksum of the data array using the Adler-32 algorithm (). /// public static uint ComputeAdler32Checksum(this T[] data) where T : struct { #if NET6_0_OR_GREATER var a = new Adler32(); if (data != null) a.Update(data.AsByteSpan()); return a.Checksum; #else return ((Array)data).ComputeAdler32Checksum(); #endif } /// /// Computes a checksum of the given string using the Adler-32 algorithm (). /// public static uint ComputeAdler32Checksum(this string s) { var a = new Adler32(); #if NET6_0_OR_GREATER a.Update(s.AsByteSpan()); #else a.Update(Encoding.Unicode.GetBytes(s)); #endif return a.Checksum; } #endregion #endregion } } ================================================ FILE: src/Aardvark.Base/Extensions/CastExtensions.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace Aardvark.Base { public static class CastExtensions { public static T[] ToArrayOfT(this IEnumerable s) { return (from T o in s select (T)o).ToArray(); } public static List ToListOfT(this IEnumerable s) { return (from T o in s select o).ToList(); } public static IEnumerable ToIEnumerableOfT(this IEnumerable s) { return from T o in s select o; } public static List IntoList(this T item) { return new List() { item }; } public static T[] IntoArray(this T item) { return new T[] { item }; } public static IEnumerable IntoIEnumerable(this T item) { return new T[] { item }; // yield return item; // this generates a more code } /// /// Returns the item as a T. /// Or throws an exception if not convertible. /// public static T To(this object item) where T : class { if (item is T) return item as T; throw new ArgumentException(string.Format("expected {0} instead of {1}", typeof(T), item.GetType())); } } } ================================================ FILE: src/Aardvark.Base/Extensions/DagExtensions.cs ================================================ using System; using System.Collections.Generic; namespace Aardvark.VRVis { public static class TreeExtensions { public static IEnumerable DepthFirst( this T self, Func> subNodes ) { yield return self; var stack = new Stack>(); stack.Push(subNodes(self).GetEnumerator()); while (stack.Count > 0) { var e = stack.Peek(); if (e.MoveNext()) { yield return e.Current; stack.Push(subNodes(e.Current).GetEnumerator()); } else { stack.Pop(); } } } public static IEnumerable BreadthFirst( this T self, Func> subNodes ) { yield return self; var queue = new Queue>(); queue.Enqueue(subNodes(self)); while (queue.Count > 0) { var nodes = queue.Dequeue(); if (nodes == null) continue; foreach (var n in nodes) { yield return n; queue.Enqueue(subNodes(n)); } } } } } ================================================ FILE: src/Aardvark.Base/Extensions/DateTimeExtensions.cs ================================================ using System; using System.Collections.Generic; using System.Text; namespace Aardvark.Base { public static class DateTimeExtensions { /// /// Calculates the UTC Julian day from the given DateTime and time zone. /// Julian days start at 12h noon January 1, 4713 BC (day 0). The fractional part contains the fraction of a day since the last noon. /// public static double ComputeJulianDayUTC(this DateTime date, double timeZone) { return date.ComputeJulianDay() - (timeZone / 24.0); } /// /// Calculates the Julian day from the given DateTime. /// Julian days start at 12h noon January 1, 4713 BC (day 0). The fractional part contains the fraction of a day since the last noon. /// public static double ComputeJulianDay(this DateTime date) { var y = date.Year; var m = date.Month; var d = date.Day; var dt = date.TimeOfDay.TotalDays; if (m < 3) { m = m + 12; y = y - 1; } int jd = d + (153 * m - 457) / 5 + 365 * y + (y / 4) - (y / 100) + (y / 400); return jd + 1721118.5 + dt; } // whatever the use of this should be public static double GregorianDayOfMonthFromJulianDay(double J) { // the following calculates the day of the month of a JD var p = Fun.Floor(J + 0.5); var s1 = p + 68569; var n = Fun.Floor(4 * s1 / 146097); var s2 = s1 - Fun.Floor((146097 * n + 3) / 4); var i = Fun.Floor(4000 * (s2 + 1) / 1461001); var s3 = s2 - Fun.Floor(1461 * i / 4) + 31; var q = Fun.Floor(80 * s3 / 2447); var e = s3 - Fun.Floor(2447 * q / 80); // int s4 = System.Math.Floor(q / 11); // int m = q + 2 - 12 * s4; // int y = 100 * (n - 49) + i + s4; return e + J - p + 0.5; } /// /// Calculates date of a Julian day. /// NOTE: A Julian day starts at 12h noon /// public static DateTime ComputeDateFromJulianDay(double jd) { var p = (int)(jd + 68569.5); var q = 4 * p / 146097; var r = p - (146097 * q + 3) / 4; var s = 4000 * (r + 1) / 1461001; var t = r - 1461 * s / 4 + 31; var u = 80 * t / 2447; var v = u / 11; var Y = 100 * (q - 49) + s + v; var M = u + 2 - 12 * v; var D = t - 2447 * u / 80; var timeOfDay = (jd + 0.5).Frac(); var tmp = timeOfDay * 24; var _h = (int)tmp; tmp = (tmp - _h) * 60; var _m = (int)tmp; tmp = (tmp - _m) * 60; var _s = (int)tmp; tmp = (tmp - _s) * 1000; var _ms = (int)tmp; return new DateTime(Y, M, D, _h, _m, _s, _ms); } /// /// Calculates date of a Julian day. /// NOTE: A Julian day starts at 12h noon /// public static DateTime ComputeDateFromJulianDay(int jd) { var p = (int)(jd + 68569); var q = 4 * p / 146097; var r = p - (146097 * q + 3) / 4; var s = 4000 * (r + 1) / 1461001; var t = r - 1461 * s / 4 + 31; var u = 80 * t / 2447; var v = u / 11; var Y = 100 * (q - 49) + s + v; var M = u + 2 - 12 * v; var D = t - 2447 * u / 80; return new DateTime(Y, M, D, 12, 0, 0, 0); } } } ================================================ FILE: src/Aardvark.Base/Extensions/DictionaryExtensions.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Aardvark.Base { #region Dictionary Extensions public static class DictionaryFun { public static Dictionary Copy( this Dictionary self) { var r = new Dictionary(self.Count); foreach (var kvp in self) r[kvp.Key] = kvp.Value; return r; } public static Dictionary Copy( this Dictionary self, Func fun) { var r = new Dictionary(self.Count); foreach (var kvp in self) r[kvp.Key] = fun(kvp.Value); return r; } public static Dictionary Copy( this Dictionary self, Dictionary> funMap, Func defaultFun) { var r = new Dictionary(self.Count); foreach (var kvp in self) { if (funMap.TryGetValue(kvp.Key, out Func fun)) r[kvp.Key] = fun(kvp.Value); else if (defaultFun != null) r[kvp.Key] = defaultFun(kvp.Value); } return r; } /// /// Combines the dictionary with another one. Duplicate keys /// are overwritten. /// public static Dictionary Combine( this Dictionary self, Dictionary second) { var result = self.Copy(); foreach (var kvp in second) result[kvp.Key] = kvp.Value; return result; } } #endregion #region IDictionaryExt public static class IDictionaryExtensions { /// /// Tries to get a value from the dictionary. /// If the key is not found, default(T) will be returned. /// public static Tv Get( this IDictionary self, Tk key) { if (self.TryGetValue(key, out Tv value)) return value; return default(Tv); } /// /// Tries to get a value from the dictionary. /// If the key is not found, the specified defaultValue will be returned. /// public static Tv Get( this IDictionary self, Tk key, Tv defaultValue) { if (self.TryGetValue(key, out Tv value)) return value; return defaultValue; } /// /// Gets the value with the given key. If not found, a new value for the key is created. /// public static TV GetCreate(this IDictionary self, TK key, Func creator = null) { if (!self.TryGetValue(key, out TV value)) { value = (creator != null) ? creator(key) : default(TV); self[key] = value; } return value; } /// /// Removes the value with the given key from the dictionary and passes it as return argument. /// /// The value removed from the dictionary /// if key not found public static TV Pop(this IDictionary self, TK key) { if (self.TryGetValue(key, out TV value)) { self.Remove(key); return value; } throw new KeyNotFoundException(); } /// /// Removes the value with the given key from the dictionary and passes it as out argument. /// In case the value is not found default(T) will be returned. /// /// true if the value was removed from the dictionary, false otherwise. public static bool TryPop(this IDictionary self, TK key, out TV value) => self.TryGetValue(key, out value) && self.Remove(key); /// /// Removes the value with the given key from the dictionary and passes it as return argument. /// In case the value is not found default(T) will be returned. /// /// The value removed from the dictionary or default(T) public static TV TryPop(this IDictionary self, TK key) => self.TryPop(key, out TV value) ? value : default; public static T1v[] CopyToArray(this IDictionary self, Func, T1v> fun) { var r = new T1v[self.Count]; var i = 0L; foreach (var kvp in self) r[i++] = fun(kvp); return r; } public static T1v[] CopyToArray(this IDictionary self, Func fun) { var r = new T1v[self.Count]; var i = 0L; foreach (var kvp in self) r[i++] = fun(kvp.Key, kvp.Value); return r; } /// /// Adds a range of KeyValuePairs, will throw DuplicateKeyException /// public static Td AddRange(this Td self, IEnumerable> keyValuePairs) where Td: IDictionary { foreach (var kvp in keyValuePairs) self.Add(kvp.Key, kvp.Value); return self; } /// /// Adds a range of KeyValuePairs as Tup, will throw DuplicateKeyException /// public static Td AddRange(this Td self, IEnumerable> keyValueTuples) where Td : IDictionary { foreach (var kvp in keyValueTuples) self.Add(kvp.E0, kvp.E1); return self; } /// /// Adds a range of KeyValuePairs, duplicate keys will be overwritten /// public static Td SetRange(this Td self, IEnumerable> keyValuePairs) where Td : IDictionary { foreach (var kvp in keyValuePairs) self[kvp.Key] = kvp.Value; return self; } /// /// Adds a range of KeyValuePairs, duplicate keys will be overwritten /// public static Td SetRange(this Td self, IEnumerable> keyValueTuples) where Td : IDictionary { foreach (var kvp in keyValueTuples) self[kvp.E0] = kvp.E1; return self; } /// /// Compares the key value pairs of two dictionaries using Equals to compare the values. /// public static bool DictionaryEquals(this IDictionary self, IDictionary other) { return DictionaryEquals(self, other, (valueA, valueB) => valueA.Equals(valueB)); } /// /// Compares the key value pairs of two dictionaries using a custom valueComparisonFunc /// (which returns true if both are equal). /// public static bool DictionaryEquals(this IDictionary self, IDictionary other, Func valueComparisonFunc) { if (self.Count != other.Count) return false; else { foreach (var item in self) { Tv valueA = item.Value; if (!other.TryGetValue(item.Key, out Tv valueB) || !valueComparisonFunc(valueA, valueB)) return false; } } return true; } /// /// Returns the value stored with the supplied key or the specified default value if not found. /// public static TValue GetOrDefault(this IDictionary self, TKey key, TValue defaultValue) => self.TryGetValue(key, out var result) ? result : defaultValue; } #endregion #region KeyValuePair Extensions public static class KeyValuePairs { public static KeyValuePair Create( TKey key, TValue value) { return new KeyValuePair(key, value); } public static KeyValuePair Copy( this KeyValuePair kvp, Func func) { return new KeyValuePair(kvp.Key, func(kvp.Value)); } } #endregion } ================================================ FILE: src/Aardvark.Base/Extensions/EnumHelpers.cs ================================================ using System; using System.Collections.Generic; namespace Aardvark.Base { public static class EnumHelpers { static readonly Dict> s_neighbourValuesDicts = new Dict>(); static Dict GetNeighbourValuesDict(Type enumType) { if (!enumType.IsEnum) throw new ArgumentException($"{enumType.Name} is not an enumeration type."); if (!s_neighbourValuesDicts.TryGetValue(enumType, out Dict neighbourValuesDict)) { var values = (T[])Enum.GetValues(enumType); neighbourValuesDict = new Dict(); for (int i = 0; i < values.Length; i++) { neighbourValuesDict[Convert.ToInt64(values[i])] = ( values[(i > 0 ? i : values.Length) - 1], values[i < values.Length - 1 ? i + 1 : 0] ); // previous and next value } s_neighbourValuesDicts[enumType] = neighbourValuesDict; } return neighbourValuesDict; } /// /// Returns the previous value of the enumeration or the last when the current value is the first one. /// public static T GetPrevValue(T enumValue) // NOTE: where T: enum { var neighbourValuesDict = GetNeighbourValuesDict(typeof(T)); var intValue = Convert.ToInt64(enumValue); neighbourValuesDict.TryGetValue(intValue, out (object, object) result); return (T)result.Item1; } /// /// Returns the next value of the enumeration or the first when the current value is the last one. /// public static T GetNextValue(T enumValue) // NOTE: where T: enum { var neighbourValuesDict = GetNeighbourValuesDict(typeof(T)); var intValue = Convert.ToInt64(enumValue); neighbourValuesDict.TryGetValue(intValue, out (object, object) result); return (T)result.Item2; } static readonly Dictionary)> s_valueIndexMapping = new Dictionary)>(); // long = worst case enum value static (Array, Dictionary) GetValueIndexMapping(Type enumType) { if (!enumType.IsEnum) throw new ArgumentException($"{enumType.Name} is not an enumeration type."); return s_valueIndexMapping.GetCreate(enumType, et => { var enumValues = Enum.GetValues(et); var enumIndices = new Dictionary(); for (int i = 0; i < enumValues.Length; i++) enumIndices.Add(Convert.ToInt64(enumValues.GetValue(i)), i); return (enumValues, enumIndices); }); } /// /// Return the index of the enumeration value /// public static int GetIndex(T enumValue) { var mapping = GetValueIndexMapping(typeof(T)); return mapping.Item2[Convert.ToInt64(enumValue)]; } /// /// Return the index of the enumeration value /// public static int GetIndex(Type enumType, object enumValue) { var mapping = GetValueIndexMapping(enumType); return mapping.Item2[Convert.ToInt64(enumValue)]; } /// /// Returns the enumeartion value of a certain index /// public static int GetValue(Type enumType, int index) { var mapping = GetValueIndexMapping(enumType); return (int)mapping.Item1.GetValue(index); } /// /// Returns the enumeartion value of a certain index /// public static T GetValue(int index) { var mapping = GetValueIndexMapping(typeof(T)); return (T)mapping.Item1.GetValue(index); } } } ================================================ FILE: src/Aardvark.Base/Extensions/EventHandlerExtensions.cs ================================================ using System; namespace Aardvark.Base { public static class EventHandlerExtensions { /// /// Safely invokes the event using null as sender and EventArgs.Empty /// public static void TryInvoke(this EventHandler eh) { eh?.Invoke(null, EventArgs.Empty); } /// /// Safely invokes the event using the supplied sender with EventArgs.Empty /// public static void TryInvoke(this EventHandler eh, object sender) { eh?.Invoke(sender, EventArgs.Empty); } } } ================================================ FILE: src/Aardvark.Base/Extensions/FuncActionExtensions.cs ================================================ using System; namespace Aardvark.Base { public static partial class FuncActionExtensions { /// /// Encapsulates the expression "[object] != null ? 'select something from [object]' : defaultValue /// public static Tr TrySelect(this To o, Func selector, Tr defaultValue = default(Tr)) where To : class { return o != null ? selector(o) : defaultValue; } } } ================================================ FILE: src/Aardvark.Base/Extensions/FuncActionExtensions_auto.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Aardvark.Base { public static partial class FuncActionExtensions { public static TR ExecuteFirst(this Func[] funArray, T0 e0) { return funArray[0](e0); } public static bool ExecuteUpToTrue(this Func[] funArray, T0 e0) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](e0)) return true; return false; } public static bool ExecuteUpToTrueChecked(this Func[] funArray, T0 e0) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](e0)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull(this Func[] funArray, T0 e0) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](e0); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked(this Func[] funArray, T0 e0) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](e0); if (r != null) return r; } catch (Exception) { } } return null; } public static TR ExecuteFirst(this Func[] funArray, T0 e0, T1 e1) { return funArray[0](e0, e1); } public static bool ExecuteUpToTrue(this Func[] funArray, T0 e0, T1 e1) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](e0, e1)) return true; return false; } public static bool ExecuteUpToTrueChecked(this Func[] funArray, T0 e0, T1 e1) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](e0, e1)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull(this Func[] funArray, T0 e0, T1 e1) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](e0, e1); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked(this Func[] funArray, T0 e0, T1 e1) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](e0, e1); if (r != null) return r; } catch (Exception) { } } return null; } public static TR ExecuteFirst(this Func[] funArray, T0 e0, T1 e1, T2 e2) { return funArray[0](e0, e1, e2); } public static bool ExecuteUpToTrue(this Func[] funArray, T0 e0, T1 e1, T2 e2) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](e0, e1, e2)) return true; return false; } public static bool ExecuteUpToTrueChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](e0, e1, e2)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull(this Func[] funArray, T0 e0, T1 e1, T2 e2) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](e0, e1, e2); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](e0, e1, e2); if (r != null) return r; } catch (Exception) { } } return null; } public static TR ExecuteFirst(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3) { return funArray[0](e0, e1, e2, e3); } public static bool ExecuteUpToTrue(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](e0, e1, e2, e3)) return true; return false; } public static bool ExecuteUpToTrueChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](e0, e1, e2, e3)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](e0, e1, e2, e3); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](e0, e1, e2, e3); if (r != null) return r; } catch (Exception) { } } return null; } public static TR ExecuteFirst(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4) { return funArray[0](e0, e1, e2, e3, e4); } public static bool ExecuteUpToTrue(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](e0, e1, e2, e3, e4)) return true; return false; } public static bool ExecuteUpToTrueChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](e0, e1, e2, e3, e4)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](e0, e1, e2, e3, e4); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](e0, e1, e2, e3, e4); if (r != null) return r; } catch (Exception) { } } return null; } public static TR ExecuteFirst(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5) { return funArray[0](e0, e1, e2, e3, e4, e5); } public static bool ExecuteUpToTrue(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](e0, e1, e2, e3, e4, e5)) return true; return false; } public static bool ExecuteUpToTrueChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](e0, e1, e2, e3, e4, e5)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](e0, e1, e2, e3, e4, e5); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](e0, e1, e2, e3, e4, e5); if (r != null) return r; } catch (Exception) { } } return null; } public static TR ExecuteFirst(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6) { return funArray[0](e0, e1, e2, e3, e4, e5, e6); } public static bool ExecuteUpToTrue(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](e0, e1, e2, e3, e4, e5, e6)) return true; return false; } public static bool ExecuteUpToTrueChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](e0, e1, e2, e3, e4, e5, e6)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6); if (r != null) return r; } catch (Exception) { } } return null; } public static TR ExecuteFirst(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7) { return funArray[0](e0, e1, e2, e3, e4, e5, e6, e7); } public static bool ExecuteUpToTrue(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7)) return true; return false; } public static bool ExecuteUpToTrueChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7); if (r != null) return r; } catch (Exception) { } } return null; } public static TR ExecuteFirst(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8) { return funArray[0](e0, e1, e2, e3, e4, e5, e6, e7, e8); } public static bool ExecuteUpToTrue(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8)) return true; return false; } public static bool ExecuteUpToTrueChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8); if (r != null) return r; } catch (Exception) { } } return null; } public static TR ExecuteFirst(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9) { return funArray[0](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9); } public static bool ExecuteUpToTrue(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9)) return true; return false; } public static bool ExecuteUpToTrueChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9); if (r != null) return r; } catch (Exception) { } } return null; } public static TR ExecuteFirst(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10) { return funArray[0](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10); } public static bool ExecuteUpToTrue(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10)) return true; return false; } public static bool ExecuteUpToTrueChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10); if (r != null) return r; } catch (Exception) { } } return null; } public static TR ExecuteFirst(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11) { return funArray[0](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11); } public static bool ExecuteUpToTrue(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11)) return true; return false; } public static bool ExecuteUpToTrueChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11); if (r != null) return r; } catch (Exception) { } } return null; } public static TR ExecuteFirst(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12) { return funArray[0](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12); } public static bool ExecuteUpToTrue(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12)) return true; return false; } public static bool ExecuteUpToTrueChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12); if (r != null) return r; } catch (Exception) { } } return null; } public static TR ExecuteFirst(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12, T13 e13) { return funArray[0](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13); } public static bool ExecuteUpToTrue(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12, T13 e13) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13)) return true; return false; } public static bool ExecuteUpToTrueChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12, T13 e13) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12, T13 e13) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12, T13 e13) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13); if (r != null) return r; } catch (Exception) { } } return null; } public static TR ExecuteFirst(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12, T13 e13, T14 e14) { return funArray[0](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14); } public static bool ExecuteUpToTrue(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12, T13 e13, T14 e14) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14)) return true; return false; } public static bool ExecuteUpToTrueChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12, T13 e13, T14 e14) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12, T13 e13, T14 e14) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12, T13 e13, T14 e14) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14); if (r != null) return r; } catch (Exception) { } } return null; } public static TR ExecuteFirst(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12, T13 e13, T14 e14, T15 e15) { return funArray[0](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15); } public static bool ExecuteUpToTrue(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12, T13 e13, T14 e14, T15 e15) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15)) return true; return false; } public static bool ExecuteUpToTrueChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12, T13 e13, T14 e14, T15 e15) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12, T13 e13, T14 e14, T15 e15) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked(this Func[] funArray, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9, T10 e10, T11 e11, T12 e12, T13 e13, T14 e14, T15 e15) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15); if (r != null) return r; } catch (Exception) { } } return null; } } } ================================================ FILE: src/Aardvark.Base/Extensions/FuncActionExtensions_template.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Aardvark.Base { public static partial class FuncActionExtensions { //# Action comma = () => Out(", "); //# for (int tc = 1; tc <= 16; tc++) { //# var Ti = tc.Expand(i => "T" + i).Join(", "); //# var ei = tc.Expand(i => "e" + i).Join(", "); public static TR ExecuteFirst<__Ti__, TR>(this Func<__Ti__, TR>[] funArray, /*# tc.ForEach(i=>{*/T__i__ e__i__/*#}, comma); */) { return funArray[0](__ei__); } public static bool ExecuteUpToTrue<__Ti__>(this Func<__Ti__, bool>[] funArray, /*# tc.ForEach(i=>{*/T__i__ e__i__/*#}, comma); */) { for (int i = 0; i < funArray.Length; i++) if (funArray[i](__ei__)) return true; return false; } public static bool ExecuteUpToTrueChecked<__Ti__>(this Func<__Ti__, bool>[] funArray, /*# tc.ForEach(i=>{*/T__i__ e__i__/*#}, comma); */) { for (int i = 0; i < funArray.Length; i++) { try { if (funArray[i](__ei__)) return true; } catch (Exception) { } } return false; } public static TR ExecuteUpToNotNull<__Ti__, TR>(this Func<__Ti__, TR>[] funArray, /*# tc.ForEach(i=>{*/T__i__ e__i__/*#}, comma); */) where TR : class { for (int i = 0; i < funArray.Length; i++) { var r = funArray[i](__ei__); if (r != null) return r; } return null; } public static TR ExecuteUpToNotNullChecked<__Ti__, TR>(this Func<__Ti__, TR>[] funArray, /*# tc.ForEach(i=>{*/T__i__ e__i__/*#}, comma); */) where TR : class { for (int i = 0; i < funArray.Length; i++) { try { var r = funArray[i](__ei__); if (r != null) return r; } catch (Exception) { } } return null; } //# } // tc } } ================================================ FILE: src/Aardvark.Base/Extensions/HigherOrderFunctions.cs ================================================ using System; using System.Collections.Generic; using static System.Math; namespace Aardvark.Base { public static class ControlFun { #region ForEach on ints /// /// Perform the supplied action for all integers i in [0, n). /// public static void ForEach(this int n, Action i_act) { for (int k = 0; k < n; k++) { i_act(k); } } /// /// Perform the supplied action for all integers in [start, n). /// public static void ForEach(this int n, int start, Action i_act) { for (int k = start; k < n; k++) { i_act(k); } } /// /// Perform the supplied action for all integers i in [0, n). /// Perform the supplied separating action between the integers. /// public static void ForEach(this int n, Action i_act, Action sep) { for (int k = 0; k < n - 1; k++) { i_act(k); sep(); } i_act(n - 1); } /// /// Perform the supplied action for all integers i in [start, n). /// Perform the supplied separating action between the integers. /// public static void ForEach( this int n, int start, Action i_act, Action sep) { for (int k = start; k < n - 1; k++) { i_act(k); sep(); } i_act(n - 1); } /// /// Perform the supplied action for all integers i in [0, n). /// Perform the supplied separating action between the integers. /// The seperating action receives the index of the preceeding item. /// public static void ForEach(this int n, Action i_act, Action i_sep) { for (int k = 0; k < n - 1; k++) { i_act(k); i_sep(k); } i_act(n - 1); } /// /// Perform the supplied action for all integers i in [start, n). /// Perform the supplied separating action between the integers. /// The seperating action receives the index of the preceeding item. /// public static void ForEach( this int n, int start, Action i_act, Action i_sep) { for (int k = start; k < n - 1; k++) { i_act(k); i_sep(k); } i_act(n - 1); } #endregion #region ForEach on longs /// /// Perform the supplied action for all integers i in [0, n). /// public static void ForEach(this long n, Action i_act) { for (long k = 0; k < n; k++) { i_act(k); } } /// /// Perform the supplied action for all integers in [start, n). /// public static void ForEach(this long n, long start, Action i_act) { for (long k = start; k < n; k++) { i_act(k); } } #endregion #region ForEach on IEnumerable /// /// Perform the supplied action for all items in the IEnumerable. /// public static void ForEach( this IEnumerable items, Action item_act) { foreach (var item in items) item_act(item); } /// /// Perform the supplied action for all items in the IEnumerable. /// The action gets the index of the item i out of [0, n) as last /// parameter. /// public static void ForEach( this IEnumerable items, Action item_i_act) { int i = 0; foreach (var item in items) item_i_act(item, i++); } /// /// Perform the supplied action for all pairs of items in the IEnumerable /// and from the second IEnumerable. /// public static void ForEach( this IEnumerable items0, IEnumerable items1, Action item0_item1_act) { foreach (var item in items0.ZipTuples(items1)) item0_item1_act(item.Item1, item.Item2); } /// /// Perform the supplied action for all triples of items from /// each of the supplied IEnumerables. /// public static void ForEach( this IEnumerable items0, IEnumerable items1, IEnumerable items2, Action item0_item1_item2_act) { foreach (var item in items0.ZipTuples(items1, items2)) item0_item1_item2_act(item.E0, item.E1, item.E2); } /// /// Perform the supplied action for all corresponding pairs /// of items from the IEnumerable and from the second IEnumerable. /// The action gets the index of the item as last parameter. /// public static void ForEach( this IEnumerable items0, IEnumerable items1, Action item0_item1_i_act) { int i = 0; foreach (var item in items0.ZipTuples(items1)) item0_item1_i_act(item.Item1, item.Item2, i++); } /// /// Perform the supplied action for all triples of items from /// each of the supplied IEnumerables. /// The action gets the index of the item as last parameter. /// public static void ForEach( this IEnumerable items0, IEnumerable items1, IEnumerable items2, Action item0_item1_item2_i_act) { int i = 0; foreach (var item in items0.ZipTuples(items1, items2)) item0_item1_item2_i_act(item.E0, item.E1, item.E2, i++); } /// /// Perform the supplied action for all items in the IEnumerable. /// Perform the supplied separating action between the items. /// public static void ForEach( this IEnumerable items, Action item_act, Action sep) { bool notfirst = false; foreach (var item in items) { if (notfirst) sep(); else notfirst = true; item_act(item); } } /// /// Perform the supplied action for all items in the IEnumerable. /// The action gets the index i out of [0, n) of the item as last /// parameter. Perform the supplied separating action between items. /// public static void ForEach( this IEnumerable items, Action item_i_act, Action sep) { int i = -1; foreach (var item in items) { if (i >= 0) sep(); item_i_act(item, ++i); } } /// /// Perform the supplied action for all items in the IEnumerable. /// The action gets the index of the item as last parameter. /// Perform the supplied separating action between items. /// The seperating action receives the index of the preceeding item. /// public static void ForEach( this IEnumerable items, Action item_i_act, Action i_sep) { int i = -1; foreach (var item in items) { if (i >= 0) i_sep(i); item_i_act(item, ++i); } } /// /// Perform the supplied action for all corresponding pairs /// of items from the IEnumerable and from the second IEnumerable. /// Perform the supplied separating action between the items. /// public static void ForEach( this IEnumerable items0, IEnumerable items1, Action item0_item1_act, Action sep) { bool notfirst = false; foreach (var item in items0.ZipTuples(items1)) { if (notfirst) sep(); else notfirst = true; item0_item1_act(item.Item1, item.Item2); } } /// /// Perform the supplied action for all triples of items from /// each of the supplied IEnumerables. /// Perform the supplied separating action between the items. /// public static void ForEach( this IEnumerable items0, IEnumerable items1, IEnumerable items2, Action item0_item1_item2_act, Action sep) { bool notfirst = false; foreach (var item in items0.ZipTuples(items1, items2)) { if (notfirst) sep(); else notfirst = true; item0_item1_item2_act(item.E0, item.E1, item.E2); } } /// /// Perform the supplied action for all corresponding pairs /// of items from the IEnumerable and from the second IEnumerable. /// The action gets the index of the item as last parameter. /// Perform the supplied separating action between the items. /// public static void ForEach( this IEnumerable items0, IEnumerable items1, Action item0_item1_i_act, Action sep) { int i = -1; foreach (var item in items0.ZipTuples(items1)) { if (i >= 0) sep(); item0_item1_i_act(item.Item1, item.Item2, ++i); } } /// /// Perform the supplied action for all triples of items from /// each of the supplied IEnumerables. /// The action gets the index of the item as last parameter. /// Perform the supplied separating action between the items. /// public static void ForEach( this IEnumerable items0, IEnumerable items1, IEnumerable items2, Action item0_item1_item2_int_act, Action sep) { int i = -1; foreach (var item in items0.ZipTuples(items1, items2)) { if (i >= 0) sep(); item0_item1_item2_int_act(item.E0, item.E1, item.E2, ++i); } } /// /// Perform the supplied action for all corresponding pairs /// of items from the IEnumerable and from the second IEnumerable. /// The action gets the index of the item as last parameter. /// Perform the supplied separating action between the items. /// The seperating action receives the index of the preceeding items. /// public static void ForEach( this IEnumerable items0, IEnumerable items1, Action item0_item1_i_act, Action i_sep) { int i = -1; foreach (var item in items0.ZipTuples(items1)) { if (i >= 0) i_sep(i); item0_item1_i_act(item.Item1, item.Item2, ++i); } } /// /// Perform the supplied action for all triples of items from /// each of the supplied IEnumerables. /// The action gets the index of the item as last parameter. /// Perform the supplied separating action between the items. /// The seperating action receives the index of the preceeding items. /// public static void ForEach( this IEnumerable items0, IEnumerable items1, IEnumerable items2, Action item0_item1_item2_i_act, Action i_sep) { int i = -1; foreach (var item in items0.ZipTuples(items1, items2)) { if (i >= 0) i_sep(i); item0_item1_item2_i_act(item.E0, item.E1, item.E2, ++i); } } #endregion #region ForEach on Arrays /// /// Perform the supplied action for all items in the Array. /// public static void ForEach( this T[] array, Action item_act) { int count = array.Length; for (int i = 0; i < count; i++) item_act(array[i]); } /// /// Perform the supplied action for all items in the Array. /// The action gets the index of the item i out of [0, n) as last /// parameter. /// public static void ForEach( this T[] array, Action item_i_act) { int count = array.Length; for (int i = 0; i < count; i++) item_i_act(array[i], i); } /// /// Perform the supplied action for all pairs of items in the array /// and from the second array. /// public static void ForEach( this T0[] array0, T1[] array1, Action item0_item1_act) { int count = Min(array0.Length, array1.Length); for (int i = 0; i < count; i++) item0_item1_act(array0[i], array1[i]); } /// /// Perform the supplied action for all triples of items from /// each of the supplied arrays. /// public static void ForEach( this T0[] array0, T1[] array1, T2[] array2, Action item0_item1_item2_act) { int count = Min(array0.Length, Min(array1.Length, array2.Length)); for (int i = 0; i < count; i++) item0_item1_item2_act(array0[i], array1[i], array2[i]); } /// /// Perform the supplied action for all corresponding pairs /// of items from the array and from the second array. /// The action gets the index of the item as last parameter. /// public static void ForEach( this T0[] array0, T1[] array1, Action item0_item1_i_act) { int count = Min(array0.Length, array1.Length); for (int i = 0; i < count; i++) item0_item1_i_act(array0[i], array1[i], i); } /// /// Perform the supplied action for all triples of items from /// each of the supplied arrays. /// The action gets the index of the item as last parameter. /// public static void ForEach( this T0[] array0, T1[] array1, T2[] array2, Action item0_item1_item2_i_act) { int count = Min(array0.Length, Min(array1.Length, array2.Length)); for (int i = 0; i < count; i++) item0_item1_item2_i_act(array0[i], array1[i], array2[i], i); } #endregion #region ForEach on Lists /// /// Perform the supplied action for all items in the List. /// The action gets the index of the item i out of [0, n) as last /// parameter. /// public static void ForEach(this List list, Action fun) { var cnt = list.Count; for (int i = 0; i < cnt; i++) fun(list[i], i); } #endregion #region ForEach Dictionary /// /// Perform the supplied action for all items in the ValueCollection. /// public static void ForEach(this Dictionary.ValueCollection self, Action fun) { foreach (var v in self) fun(v); } /// /// Perform the supplied action for all items in the KeyCollection. /// public static void ForEach(this Dictionary.KeyCollection self, Action fun) { foreach (var k in self) fun(k); } /// /// Perform the supplied action for all KeyValuePairs in the Dictionary. /// public static void ForEach(this Dictionary self, Action> fun) { foreach (var kv in self) fun(kv); } #endregion #region Switch public static void Switch( this T value, Dictionary> actionDict) { if (actionDict.TryGetValue(value, out Action action)) action(value); } public static void Switch( this T value, Dictionary> actionDict, Action defaultAction) { if (actionDict.TryGetValue(value, out Action action)) action(value); else defaultAction(value); } public static TResult Switch( this T value, Dictionary> funcDict) { if (funcDict.TryGetValue(value, out Func func)) return func(value); else return default(TResult); } public static TResult Switch( this T value, Dictionary> funcDict, Func defaultFunc) { if (funcDict.TryGetValue(value, out Func func)) return func(value); else return defaultFunc(value); } #endregion } } ================================================ FILE: src/Aardvark.Base/Extensions/ICollectionExtensions.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Aardvark.Base { public static class ICollectionExtensions { /// /// Adds the item to the collection if not contained, otherwise removes the item from the collection. /// /// Containment state of the item after the operation public static bool ToggleContainment(this ICollection self, T item) { if (!self.Remove(item)) { self.Add(item); return true; } return false; } /// /// Adds the elements in the items enumeration to the collection. /// public static void AddRange(this ICollection self, IEnumerable items) { foreach (var item in items) self.Add(item); } } } ================================================ FILE: src/Aardvark.Base/Extensions/IEnumerableExtensions.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; using System.Text; namespace Aardvark.Base { public static class EnumerableUtils { public static IEnumerable Generate(this Func anotherElement) { if (anotherElement is null) throw new ArgumentNullException(nameof(anotherElement)); while (true) yield return anotherElement(); } public static IEnumerable Guids() { while (true) yield return Guid.NewGuid(); } } public static partial class EnumerableEx { #region Indexed Values public static IEnumerable> IndexedValues( this IEnumerable self) { return self.Select((item, i) => new IndexedValue(i, item)); } /// /// If you have a sequence of indexed values, where all indexes /// starting from 0 up to some maximal value are present and /// unique, sorting can be performed this simple array based /// reshuffling operation with O(n) cost. /// public static T[] SortedByDenseIndex( this IEnumerable> indexedValues) { var array = indexedValues.ToArray(); var len = array.Length; var sorted = new T[len]; for (int i = 0; i < len; i++) sorted[array[i].Index] = array[i].Value; return sorted; } /// /// Returns elements with index into 'other'. /// public static IEnumerable> IndexIntoOther( this IEnumerable self, IList other) { var map = new Dictionary(); for (int i = 0; i < other.Count; i++) map[other[i]] = i; return self.Select(item => new IndexedValue(map[item], item)); } #endregion #region Special Selects public static IEnumerable WhereNotNull(this IEnumerable self) { return self.Where(x => x != null); } public static IEnumerable IndicesOf(this IEnumerable self, Func predicate) { int i = 0; foreach (var x in self) { if (predicate(x)) yield return i; i++; } } public static IEnumerable SelectNotNull(this IEnumerable self, Func selector) { return self.Select(selector).WhereNotNull(); } public static T FirstOrDefault(this IEnumerable self, T defaultValue) { foreach (var x in self) return x; return defaultValue; } public static T FirstOrDefault(this IEnumerable self, Func predicate, T defaultValue) { foreach (var x in self) if (predicate(x)) return x; return defaultValue; } /// /// Yields every stride-th element. /// public static IEnumerable TakePeriodic( this IEnumerable self, int stride) { if (self is null) throw new ArgumentNullException(nameof(self)); if (stride < 1) throw new ArgumentOutOfRangeException(nameof(stride)); var i = 0; foreach (var s in self) if (i++ % stride == 0) yield return s; } /// /// Take the first count items of a sequence and put them into an /// array. If the sequence is shorter than the specified count, the /// array is filled up with default values. /// public static T[] TakeToArrayDefault(this IEnumerable self, int count) { var array = new T[count]; var en = self.GetEnumerator(); for (int i = 0; i < count && en.MoveNext(); i++) array[i] = en.Current; return array; } /// /// Take the first count items of a sequence and put them into an /// array. If the sequence is shorter than the specified count, an /// Argument exception is thrown. /// public static T[] TakeToArray(this IEnumerable self, int count) { var array = new T[count]; var en = self.GetEnumerator(); for (int i = 0; i < count; i++) { if (en.MoveNext()) array[i] = en.Current; else throw new ArgumentException(); } return array; } /// /// Take the first count items of a sequence and put them into a /// list. If the supplied sequence has less than count elements /// the resulting list is shorter than count items. /// public static List TakeToList(this IEnumerable self, int count) { var list = new List(count); var en = self.GetEnumerator(); for (int i = 0; i < count && en.MoveNext(); i++) list.Add(en.Current); return list; } /// /// Returns the index of the first element triggering the condition or -1 as default. /// public static int FirstIndexOf(this IEnumerable self, Func where) { var en = self.GetEnumerator(); for (int i = 0; en.MoveNext(); i++) if (where(en.Current)) return i; return -1; } /// /// Maps the elements of an array to a result array. /// public static R[] SelectToArray(this T[] self, Func selector) { var result = new R[self.Length]; for (int i = 0; i < self.Length; i++) { result[i] = selector(self[i]); } return result; } /// /// Maps the elements of an array to a result list. /// public static List SelectToList(this T[] self, Func selector) { var result = new List(self.Length); for (int i = 0; i < self.Length; i++) { result.Add(selector(self[i])); } return result; } /// /// Maps the elements of a list to a result array. /// public static R[] SelectToArray(this List self, Func selector) { var result = new R[self.Count]; for (int i = 0; i < self.Count; i++) { result[i] = selector(self[i]); } return result; } /// /// Maps the elements of a list to a result list. /// public static List SelectToList(this List self, Func selector) { var result = new List(self.Count); for (int i = 0; i < self.Count; i++) { result.Add(selector(self[i])); } return result; } #endregion #region Zipping /// /// Interleave this' elements with other's elements resulting in /// a sequence of length min(this.Length, other.Length). /// public static IEnumerable Zip( this IEnumerable self, IEnumerable other) { if (self is null) throw new ArgumentNullException(nameof(self)); if (other is null) throw new ArgumentNullException(nameof(other)); var e0 = self.GetEnumerator(); var e1 = other.GetEnumerator(); while (e0.MoveNext() && e1.MoveNext()) { yield return e0.Current; yield return e1.Current; } } public static IEnumerable Zip( this IEnumerable self, IEnumerable other1, IEnumerable other2) { if (self is null) throw new ArgumentNullException(nameof(self)); if (other1 is null) throw new ArgumentNullException(nameof(other1)); if (other2 is null) throw new ArgumentNullException(nameof(other2)); var e0 = self.GetEnumerator(); var e1 = other1.GetEnumerator(); var e2 = other2.GetEnumerator(); while (e0.MoveNext() && e1.MoveNext() && e2.MoveNext()) { yield return e0.Current; yield return e1.Current; yield return e2.Current; } } public static IEnumerable ZipAll( this IEnumerable self, IEnumerable other) { if (self is null) throw new ArgumentNullException(nameof(self)); if (other is null) throw new ArgumentNullException(nameof(other)); var e0 = self.GetEnumerator(); var e1 = other.GetEnumerator(); bool t0 = e0.MoveNext(), t1 = e1.MoveNext(); while (t0 && t1) { yield return e0.Current; yield return e1.Current; t0 = e0.MoveNext(); t1 = e1.MoveNext(); } while (t0) { yield return e0.Current; t0 = e0.MoveNext(); } while (t1) { yield return e1.Current; t1 = e1.MoveNext(); } } public static IEnumerable ZipAll( this IEnumerable self, IEnumerable other1, IEnumerable other2) { if (self is null) throw new ArgumentNullException(nameof(self)); if (other1 is null) throw new ArgumentNullException(nameof(other1)); if (other2 is null) throw new ArgumentNullException(nameof(other2)); var e0 = self.GetEnumerator(); var e1 = other1.GetEnumerator(); var e2 = other2.GetEnumerator(); bool t0 = e0.MoveNext(), t1 = e1.MoveNext(), t2 = e2.MoveNext(); while (t0 && t1 && t2) { yield return e0.Current; yield return e1.Current; yield return e2.Current; t0 = e0.MoveNext(); t1 = e1.MoveNext(); t2 = e2.MoveNext(); } while (t0 && t1) { yield return e0.Current; yield return e1.Current; t0 = e0.MoveNext(); t1 = e1.MoveNext(); } while (t0 && t2) { yield return e0.Current; yield return e2.Current; t0 = e0.MoveNext(); t2 = e2.MoveNext(); } while (t1 && t2) { yield return e1.Current; yield return e2.Current; t1 = e1.MoveNext(); t2 = e2.MoveNext(); } while (t0) { yield return e0.Current; t0 = e0.MoveNext(); } while (t1) { yield return e1.Current; t1 = e1.MoveNext(); } while (t2) { yield return e2.Current; t2 = e2.MoveNext(); } } public static IEnumerable<(T, T)> ZipPairs( this IEnumerable self, IEnumerable other) { if (self is null) throw new ArgumentNullException(nameof(self)); if (other is null) throw new ArgumentNullException(nameof(other)); var e0 = self.GetEnumerator(); var e1 = other.GetEnumerator(); while (e0.MoveNext() && e1.MoveNext()) yield return (e0.Current, e1.Current); } public static IEnumerable<(T, T, T)> ZipTriples( this IEnumerable self, IEnumerable other1, IEnumerable other2) { if (self is null) throw new ArgumentNullException(nameof(self)); if (other1 is null) throw new ArgumentNullException(nameof(other1)); if (other2 is null) throw new ArgumentNullException(nameof(other2)); var e0 = self.GetEnumerator(); var e1 = other1.GetEnumerator(); var e2 = other2.GetEnumerator(); while (e0.MoveNext() && e1.MoveNext() && e2.MoveNext()) yield return (e0.Current, e1.Current, e2.Current); } public static IEnumerable<(T0, T1)> ZipTuples( this IEnumerable self, IEnumerable other) { if (self is null) throw new ArgumentNullException(nameof(self)); if (other is null) throw new ArgumentNullException(nameof(other)); var e0 = self.GetEnumerator(); var e1 = other.GetEnumerator(); while (e0.MoveNext() && e1.MoveNext()) yield return (e0.Current, e1.Current); } public static IEnumerable> ZipTuples( this IEnumerable self, IEnumerable other1, IEnumerable other2) { if (self is null) throw new ArgumentNullException(nameof(self)); if (other1 is null) throw new ArgumentNullException(nameof(other1)); if (other2 is null) throw new ArgumentNullException(nameof(other2)); var e0 = self.GetEnumerator(); var e1 = other1.GetEnumerator(); var e2 = other2.GetEnumerator(); while (e0.MoveNext() && e1.MoveNext() && e2.MoveNext()) yield return new Tup( e0.Current, e1.Current, e2.Current); } #endregion #region Chunking public static IEnumerable Chunk( this IEnumerable self, long chunkSize ) { if (self is null) throw new ArgumentNullException(nameof(self)); if (chunkSize < 1) throw new ArgumentOutOfRangeException(nameof(chunkSize)); var chunk = new List(); foreach (var item in self) { chunk.Add(item); if (chunk.Count == chunkSize) // yield full chunk { yield return chunk.ToArray(); chunk.Clear(); } } // yield rest if (chunk.Count > 0) yield return chunk.ToArray(); } public static IEnumerable Chunk( this IEnumerable self, long chunkSize, Func selector ) { if (self is null) throw new ArgumentNullException(nameof(self)); if (chunkSize < 1) throw new ArgumentOutOfRangeException(nameof(chunkSize)); if (selector is null) throw new ArgumentNullException(nameof(selector)); var chunk = new List(); foreach (var item in self) { chunk.Add(selector(item)); if (chunk.Count == chunkSize) // yield full chunk { yield return chunk.ToArray(); chunk.Clear(); } } // yield rest if (chunk.Count > 0) yield return chunk.ToArray(); } #endregion #region Pairs /// /// A B C D ... -> (A, B) (C, D) ... /// If sequence does not have even elements the last element is not selected. /// public static IEnumerable<(T, T)> PairSequence(this IEnumerable self) { if (self is null) throw new ArgumentNullException(nameof(self)); var first = self.TakePeriodic(2); var second = self.Skip(1).TakePeriodic(2); return first.ZipPairs(second); //todo: very inefficient: double enumeration } /// /// wrap = false: A B C D ... -> (A, B) (B, C) (C, D) ... /// wrap = true: A B C D -> (A, B) (B, C) (C, D) (D, A) /// public static IEnumerable<(T, T)> PairChain(this IEnumerable self, bool wrap = false) { if (self is null) throw new ArgumentNullException(nameof(self)); using (var e = self.GetEnumerator()) { if (e.MoveNext()) { T first = e.Current; T prev = first; while (e.MoveNext()) { var x = e.Current; yield return (prev, x); prev = x; } if (wrap) yield return (prev, first); } } } /// /// wrap = false: A B C D ... -> (0, 1) (1, 2) (2, 3) ... /// wrap = true: A B C D -> (0, 1) (1, 2) (2, 3) (3, 0) /// public static IEnumerable<(int, int)> PairChainIndexed(this IEnumerable self, bool wrap = false) { if (self is null) throw new ArgumentNullException(nameof(self)); using (var e = self.GetEnumerator()) { if (e.MoveNext()) { int prev = 0; while (e.MoveNext()) { var x = prev + 1; yield return (prev, x); prev = x; } if (wrap) yield return (prev, 0); } } } /// /// A B C D -> (A, B) (B, C) (C, D) (D, A) /// public static IEnumerable<(T, T)> PairChainWrap(this IEnumerable self) { return PairChain(self, true); } /// /// A B C -> (0, 1) (1, 2) (2, 0) /// public static IEnumerable<(int, int)> PairChainWrapIndexed(this IEnumerable self) { return PairChainIndexed(self, true); } /// /// A B C -> (A, A) (A, B) (A, C) (B, A) (B, B) (B, C) (C, A) (C, B) (C, C) /// public static IEnumerable<(T, T)> Pairs(this IEnumerable self) { return Pairs(self, false, false); } /// /// A B C -> (A, A) (A, B) (A, C) (B, A) (B, B) (B, C) (C, A) (C, B) (C, C) /// excludeIdenticalPairs: A B C -> (A, B) (A, C) (B, A) (B, C) (C, A) (C, B) /// excludeReversePairs: A B C -> (A, A) (A, B) (A, C) (B, B) (B, C) (C, C) /// both: A B C -> (A, B) (A, C) (B, C) /// public static IEnumerable<(T, T)> Pairs(this IEnumerable self, bool excludeIdenticalPairs, bool excludeReversePairs) { if (self is null) throw new ArgumentNullException(nameof(self)); var a = self.ToArray(); for (int i = 0; i < a.Length; i++) for (int j = excludeReversePairs ? i : 0; j < a.Length; j++) { if (excludeIdenticalPairs && i == j) continue; yield return (a[i], a[j]); } } /// /// Computes how many pairs method Pairs() will generate. /// Is efficient on ILists(of T), but will fully enumerate other IEnumerables. /// public static int PairsCount(this IEnumerable self, bool excludeIdenticalPairs, bool excludeReversePairs) { if (self is null) throw new ArgumentNullException(nameof(self)); var c = self.Count(); if(excludeIdenticalPairs) { if (excludeReversePairs) return (c * (c - 1)) / 2; else return c * (c - 1); } else { if (excludeReversePairs) return ((c + 1) * c) / 2; else return c * c; } } /// /// [A B C].Pairs([x y z]) -> (A, x) (A, y) (A, z) (B, x) (B, y) (B, z) (C, x) (C, y) (C, z) /// public static IEnumerable<(T, T)> Pairs(this IEnumerable self, IEnumerable other) { if (self is null) throw new ArgumentNullException(nameof(self)); if (other is null) throw new ArgumentNullException(nameof(other)); var a = self.ToArray(); var b = other.ToArray(); for (int i = 0; i < a.Length; i++) for (int j = 0; j < b.Length; j++) yield return (a[i], b[j]); } #endregion #region Triples /// /// A B C D ... -> (A, B, C) (D, E, F) ... /// If sequence does not have even elements the last element is not selected. /// public static IEnumerable<(T, T, T)> TripleSequence(this IEnumerable self) { if (self is null) throw new ArgumentNullException(nameof(self)); var first = self.TakePeriodic(3); var second = self.Skip(1).TakePeriodic(3); var third = self.Skip(2).TakePeriodic(3); return first.ZipTriples(second, third); //todo: very inefficient: triple enumeration } /// /// wrap = false: A B C D ... -> (A, B, C) (B, C, D) (C, D, E) ... /// wrap = true: A B C D -> (A, B, C) (B, C, D) (C, D, A) (D, A, B) /// public static IEnumerable<(T, T, T)> TripleChain(this IEnumerable self, bool wrap = false) { if (self is null) throw new ArgumentNullException(nameof(self)); using (var e = self.GetEnumerator()) { if (e.MoveNext()) { T first = e.Current; if (e.MoveNext()) { T second = e.Current; T prev1 = first; T prev2 = second; while (e.MoveNext()) { var x = e.Current; yield return (prev1, prev2, x); prev1 = prev2; prev2 = x; } if (wrap) { yield return (prev1, prev2, first); yield return (prev2, first, second); } } } } } /// /// A B C D -> (A, B, C) (B, C, D) (C, D, A) (D, A, B) /// public static IEnumerable<(T, T, T)> TripleChainWrap(this IEnumerable self) { return TripleChain(self, true); } /// /// A B C -> AAA, AAB, AAC, ABA, ABB, ABC, ACA, ACB, ACC, BAA, BAB, BAC, BBA, BBB, BBC, BCA, BCB, BCC, CAA, CAB, CAC, CBA, CBB, CBC, CCA, CCB, CCC /// public static IEnumerable<(T, T, T)> Triples(this IEnumerable self) { return Triples(self, false, false); } /// /// A B C -> AAA, AAB, AAC, ABA, ABB, ABC, ACA, ACB, ACC, BAA, BAB, BAC, BBA, BBB, BBC, BCA, BCB, BCC, CAA, CAB, CAC, CBA, CBB, CBC, CCA, CCB, CCC /// excludeIdenticalPairs: A B C -> ABC, CBA /// excludeReversePairs: A B C -> AAA, AAB, AAC, ABA, ABB, ABC, ACA, ACB, ACC, BAB, BAC, BBB, BBC, BCB, BCC, CAC, CBC, CCC /// both: A B C -> ABC /// public static IEnumerable<(T, T, T)> Triples(this IEnumerable self, bool excludeIdenticalPairs, bool excludeReversePairs) { //todo: check implementation; + what about excludePermutations? reversePairs do not extend to triples. if (self is null) throw new ArgumentNullException(nameof(self)); var a = self.ToArray(); for (int i = 0; i < a.Length; i++) for (int j = excludeReversePairs ? i : 0; j < a.Length; j++) { if (excludeIdenticalPairs && i == j) continue; for (int k = excludeReversePairs ? j : 0; k < a.Length; k++) { if (excludeIdenticalPairs && (j == k || i == k)) continue; yield return (a[i], a[j], a[k]); } } } /// /// [A B].Triples([x y], [X Y]) -> (A, x, X) (A, x, Y) (A, y, X) (A, y, Y) (B, x, X) (B, x, Y) (B, y, X) (B, y, Y) (C, x, X) (C, x, Y) (C, y, X) (C, y, Y) /// public static IEnumerable<(T, T, T)> Triples(this IEnumerable self, IEnumerable other1, IEnumerable other2) { if (self is null) throw new ArgumentNullException(nameof(self)); if (other1 is null) throw new ArgumentNullException(nameof(other1)); if (other2 is null) throw new ArgumentNullException(nameof(other2)); var a = self.ToArray(); var b = other1.ToArray(); var c = other2.ToArray(); for (int i = 0; i < a.Length; i++) for (int j = 0; j < b.Length; j++) for (int k = 0; k < c.Length; k++) yield return (a[i], b[j], c[k]); } #endregion #region Repetition /// /// Returns an enumeration which will infinitely yield copies of 'self'. /// A.Repeat -> [A A A A ...] /// public static IEnumerable Repeat(this T self) { while (true) yield return self; } /// /// Returns an enumeration which will yield 'count' copies of 'self'. /// A.Repeat(3) -> [A A A] /// public static IEnumerable Repeat(this T self, long count) { if (count < 0) throw new ArgumentOutOfRangeException(nameof(count)); for (long i = 0; i < count; i++) yield return self; } /// /// Appends an infinite number of copies of the sequence's last element. /// [A B C].WithRepeatedLast() -> [A B C C C C C ...] /// Does nothing for an empty sequence. /// Throws an exception for a null sequence. /// public static IEnumerable WithRepeatedLast(this IEnumerable self) { if (self is null) throw new ArgumentNullException(nameof(self)); if (self.IsEmptyOrNull()) yield break; T last = default(T); foreach (var x in self) yield return last = x; while (true) yield return last; } /// /// Duplicates each element of the sequence. /// [A B C].DupElements() -> [A A B B C C] /// public static IEnumerable Dup(this IEnumerable self) { if (self is null) throw new ArgumentNullException(nameof(self)); foreach (var x in self) { yield return x; yield return x; } } /// /// Duplicates each element of the sequence n times. /// [A B C].DupElements(4) -> [A A A A B B B B C C C C] /// public static IEnumerable Dup(this IEnumerable self, int n) { if (self is null) throw new ArgumentNullException(nameof(self)); if (n < 0) throw new ArgumentOutOfRangeException(nameof(n)); foreach (var x in self) for (int i = 0; i < n; i++) yield return x; } #endregion #region Reordering /// /// Moves the first element to the end of the sequence. /// [A B C].AddFirstToEnd() -> [A B C A] /// public static IEnumerable AddFirstToEnd(this IEnumerable self) { if (self is null) throw new ArgumentNullException(nameof(self)); if (self.IsEmpty()) yield break; var first = self.First(); foreach (var x in self) { yield return x; } yield return first; } /// /// Moves the first element to the end of the sequence. /// [A B C D E].MoveFirstToEnd() -> [B C D E A] /// public static IEnumerable WithFirstMovedToEnd(this IEnumerable self) { if (self is null) throw new ArgumentNullException(nameof(self)); if (self.IsEmpty()) return self; return self.Skip(1).Concat(self.Take(1)); } /// /// Interleaves given IEnumerable with specified element. /// E.g. { 'A', 'B', 'C' }.Interleave('X') -> { 'A', 'X', 'B', 'X', 'C' }. /// public static IEnumerable Interleave( this IEnumerable self, T separator) { if (self is null) throw new ArgumentNullException(nameof(self)); bool notFirst = false; foreach (var x in self) { if (notFirst) yield return separator; else notFirst = true; yield return x; } } #endregion #region Grouping /// /// Groups enumeration by an array of keys. /// public static IEnumerable FlatGroupByMany( this IEnumerable elements, params Func[] groupSelectorFuncs) { if (elements is null) throw new ArgumentNullException(nameof(elements)); if (groupSelectorFuncs is null) throw new ArgumentNullException(nameof(groupSelectorFuncs)); IEnumerable result = elements; foreach (var selectorFunc in groupSelectorFuncs.Reverse()) { if (selectorFunc is null) throw new ArgumentNullException(nameof(selectorFunc)); result = from g in (from item in result group item by selectorFunc(item)) from e in g select e; } return result; } #endregion #region All public static bool AllDistinct(this IEnumerable elements) { if (elements == null) return true; var set = new HashSet(); foreach (var element in elements) if (!set.Add(element)) return false; return true; } public static bool AllEqual(this IEnumerable elements) { if (elements == null) return true; using var enumerator = elements.GetEnumerator(); if (!enumerator.MoveNext()) return true; var first = enumerator.Current; var comparer = EqualityComparer.Default; while (enumerator.MoveNext()) if (!comparer.Equals(first, enumerator.Current)) return false; return true; } #endregion #region Comparisons /// /// Returns true if elements contains no items or if elements is null, false otherwise. /// public static bool IsEmptyOrNull(this T[] self) => self == null || self.Length == 0; /// /// Returns true if elements contains no items or if elements is null, false otherwise. /// public static bool IsEmptyOrNull(this ICollection self) => self == null || self.Count == 0; /// /// Returns true if elements contains no items or if elements is null, false otherwise. /// public static bool IsEmptyOrNull(this IEnumerable elements) => elements == null || !elements.Any(); // will check for ICollection internally /// /// Returns the input enumeration if it is not null, otherwise an empty enumeration. /// public static IEnumerable NonNull(IEnumerable elements) => elements ?? Enumerable.Empty(); /// /// Compares both enumerables using SequenceEqual and additionally checks /// whether both enumerables are null. /// public static bool EnumerableEquals(this IEnumerable self, IEnumerable other) { if (self == null && other == null) return true; if (self != null && other == null) return false; if (self != null && self.SequenceEqual(other)) return true; else return false; } #endregion #region Min/Max/Most public static T Min(this IEnumerable seq, Func lessThan) { if (seq is null) throw new ArgumentNullException(nameof(seq)); if (lessThan is null) throw new ArgumentNullException(nameof(lessThan)); if (seq.IsEmptyOrNull()) throw new ArgumentNullException(nameof(seq)); var min = seq.First(); foreach (var x in seq.Skip(1)) if (lessThan(x, min)) min = x; return min; } public static T Max(this IEnumerable seq, Func greaterThan) { if (seq is null) throw new ArgumentNullException(nameof(seq)); if (greaterThan is null) throw new ArgumentNullException(nameof(greaterThan)); if (seq.IsEmptyOrNull()) throw new ArgumentNullException(nameof(seq)); var max = seq.First(); foreach (var x in seq.Skip(1)) if (greaterThan(x, max)) max = x; return max; } /// /// Aardvark.Runtime.IEnumerableExtensions: /// No-Throw version. Finds the smallest element in seq according to lessThan, that is smaller than maxValue, or the first such element if there are equally small elements, or maxValue if no element is smaller. /// For normal operation set maxValue = +Inf or the maximum of T. /// public static T Min(this IEnumerable seq, Func lessThan, T maxValue) { var min = maxValue; foreach (var x in seq) if (lessThan(x, min)) min = x; return min; } /// /// Aardvark.Runtime.IEnumerableExtensions: /// No-Throw version. Finds the largest element in seq according to greaterThan, that is greater than minValue, or the first such element if there are equally large elements, or minValue if no element is greater. /// For normal operation set minValue = -Inf or the minimum of T. /// public static T Max(this IEnumerable seq, Func greaterThan, T minValue) { var max = minValue; foreach (var x in seq) if (greaterThan(x, max)) max = x; return max; } /// /// Aardvark.Runtime.IEnumerableExtensions: /// Invokes a transform function on each element of a sequence and /// returns the element that yielded the maximum value (and the maximum value in rv_maxVal). /// Only elements that yield larger values than minVal are considered. /// If multiple elements yield the maximum value, the first in the sequence is chosen. /// /// The type of the elements of source. /// The type in which the elements are to be transformed before being compared. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// A function how to compare elements of type TDst. greaterThan(a,b) => a>b (Sorry, is needed for general operation without providing a function for all types.) /// An element in the sequence has to yield a value larger than this to be considered. /// The return value if no element is greater than minVal, or the source is empty. /// The maximum value found, or minVal if no element yielded a larger value. /// The element that yielded the maximum value in the sequence. /// source, selector or greaterThan is null. public static TSrc MaxElement(this IEnumerable source, Func selector, Func greaterThan, TDst minVal, TSrc defaultRv, out TDst rv_maxVal) { if (source == null) throw new ArgumentNullException(); if (selector == null) throw new ArgumentNullException(); if (greaterThan == null) throw new ArgumentNullException(); var e = source.GetEnumerator(); TSrc maxEl = defaultRv; rv_maxVal = minVal; while (e.MoveNext()) { TSrc el = e.Current; TDst val = selector(el); if (greaterThan(val, rv_maxVal)) { rv_maxVal = val; maxEl = el; } } return maxEl; } /// /// Aardvark.Runtime.IEnumerableExtensions: /// Invokes a transform function on each element of a sequence and /// returns the element that yielded the minimum value (and the minimum value in rv_minVal). /// Only elements that yield smaller values than maxVal are considered. /// If multiple elements yield the minimum value, the first in the sequence is chosen. /// /// The type of the elements of source. /// The type in which the elements are to be transformed before being compared. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// A function how to compare elements of type TDst. smallerThan(a,b) => a<b (Sorry, is needed for general operation without providing a function for all types.) /// An element in the sequence has to yield a value smaller than this to be considered. /// The return value if no element is smaller than maxVal, or the source is empty. /// The minimum value found, or maxVal if no element yielded a larger value. /// The element that yielded the minimum value in the sequence. /// source, selector or smallerThan is null. public static TSrc MinElement(this IEnumerable source, Func selector, Func smallerThan, TDst maxVal, TSrc defaultRv, out TDst rv_minVal) { if (source == null) throw new ArgumentNullException(); if (selector == null) throw new ArgumentNullException(); if (smallerThan == null) throw new ArgumentNullException(); var e = source.GetEnumerator(); TSrc minEl = defaultRv; rv_minVal = maxVal; while (e.MoveNext()) { TSrc el = e.Current; TDst val = selector(el); if (smallerThan(val, rv_minVal)) { rv_minVal = val; minEl = el; } } return minEl; } /// /// Returns true if more elements than not satisfy the given predicate. /// public static bool Most(this IEnumerable self, Func predicate) { Contract.Requires(self != null); long countTrue = 0; long countFalse = 0; foreach (var x in self) if (predicate(x)) countTrue++; else countFalse++; return countTrue > countFalse; } #endregion #region Min/Max-Index public static int MinIndex(this IEnumerable self, Func lessThan, out T minValue) { var e = self.GetEnumerator(); if (!e.MoveNext()) { minValue = default(T); return -1; } var currentMinValue = e.Current; var currentMinIndex = 0; var index = 1; while (e.MoveNext()) { if (lessThan(e.Current, currentMinValue)) { currentMinValue = e.Current; currentMinIndex = index; } index++; } minValue = currentMinValue; return currentMinIndex; } public static int MaxIndex(this IEnumerable self, Func greaterThan, out T maxValue) { var e = self.GetEnumerator(); if (!e.MoveNext()) { maxValue = default(T); return -1; } var currentMaxValue = e.Current; var currentMaxIndex = 0; var index = 1; while (e.MoveNext()) { if (greaterThan(e.Current, currentMaxValue)) { currentMaxValue = e.Current; currentMaxIndex = index; } index++; } maxValue = currentMaxValue; return currentMaxIndex; } public static int MinIndex(this IEnumerable self, out T minValue) where T : IComparable { return MinIndex(self, (a, b) => a.CompareTo(b) < 0, out minValue); } public static int MaxIndex(this IEnumerable self, out T minValue) where T : IComparable { return MaxIndex(self, (a, b) => a.CompareTo(b) > 0, out minValue); } public static int MinIndex(this IEnumerable self) where T : IComparable { T foo; return MinIndex(self, (a, b) => a.CompareTo(b) < 0, out foo); } public static int MaxIndex(this IEnumerable self) where T : IComparable { T foo; return MaxIndex(self, (a, b) => a.CompareTo(b) > 0, out foo); } public static int MinIndex(this T[] self, Func lessThan, out T minValue) { if (self.Length <= 0) { minValue = default(T); return -1; } var currentMinValue = self[0]; var currentMinIndex = 0; for(int i = 1; i < self.Length; i++) { if (lessThan(self[i], currentMinValue)) { currentMinValue = self[i]; currentMinIndex = i; } } minValue = currentMinValue; return currentMinIndex; } public static int MaxIndex(this T[] self, Func greaterThan, out T maxValue) { if (self.Length <= 0) { maxValue = default(T); return -1; } var currentMaxValue = self[0]; var currentMaxIndex = 0; for (int i = 1; i < self.Length; i++) { if (greaterThan(self[i], currentMaxValue)) { currentMaxValue = self[i]; currentMaxIndex = i; } } maxValue = currentMaxValue; return currentMaxIndex; } public static int MinIndex(this T[] self, out T minValue) where T : IComparable { return MinIndex(self, (a, b) => a.CompareTo(b) < 0, out minValue); } public static int MaxIndex(this T[] self, out T maxValue) where T : IComparable { return MaxIndex(self, (a, b) => a.CompareTo(b) > 0, out maxValue); } public static int MinIndex(this T[] self) where T : IComparable { T foo; return MinIndex(self, (a, b) => a.CompareTo(b) < 0, out foo); } public static int MaxIndex(this T[] self) where T : IComparable { T foo; return MaxIndex(self, (a, b) => a.CompareTo(b) > 0, out foo); } public static int MinIndex(this List self, Func lessThan, out T minValue) { if (self.Count <= 0) { minValue = default(T); return -1; } var currentMinValue = self[0]; var currentMinIndex = 0; for (int i = 1; i < self.Count; i++) { if (lessThan(self[i], currentMinValue)) { currentMinValue = self[i]; currentMinIndex = i; } } minValue = currentMinValue; return currentMinIndex; } public static int MaxIndex(this List self, Func greaterThan, out T maxValue) { if (self.Count <= 0) { maxValue = default(T); return -1; } var currentMaxValue = self[0]; var currentMaxIndex = 0; for (int i = 1; i < self.Count; i++) { if (greaterThan(self[i], currentMaxValue)) { currentMaxValue = self[i]; currentMaxIndex = i; } } maxValue = currentMaxValue; return currentMaxIndex; } public static int MinIndex(this List self, out T minValue) where T : IComparable { return MinIndex(self, (a, b) => a.CompareTo(b) < 0, out minValue); } public static int MaxIndex(this List self, out T maxValue) where T : IComparable { return MaxIndex(self, (a, b) => a.CompareTo(b) > 0, out maxValue); } public static int MinIndex(this List self) where T : IComparable { T foo; return MinIndex(self, (a, b) => a.CompareTo(b) < 0, out foo); } public static int MaxIndex(this List self) where T : IComparable { T foo; return MaxIndex(self, (a, b) => a.CompareTo(b) > 0, out foo); } #region Specializations public static int MinIndex(this byte[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this sbyte[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this short[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this ushort[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this int[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this uint[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this long[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this ulong[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this float[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this double[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this decimal[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this byte[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this sbyte[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this short[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this ushort[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this int[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this uint[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this long[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this ulong[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this float[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this double[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this decimal[] self) { if (self == null || self.Length == 0) throw new ArgumentException(); if (self.Length == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Length; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MinIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] < bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } public static int MaxIndex(this List self) { if (self == null || self.Count == 0) throw new ArgumentException(); if (self.Count == 1) return 0; var bestValue = self[0]; var bestIndex = 0; for (int i = 1; i < self.Count; i++) { if (self[i] > bestValue) { bestValue = self[i]; bestIndex = i; } } return bestIndex; } #endregion #endregion #region Predicates public static bool TrueForAny( this IEnumerable sequence, Func predicate) { foreach (var item in sequence) if (predicate(item)) return true; return false; } public static bool TrueForAll( this IEnumerable sequence, Func predicate) { foreach (var item in sequence) if (!predicate(item)) return false; return true; } #endregion #region Conversions public static T[] ToArrayDebug(this IEnumerable self) { if (self is null) throw new ArgumentNullException(nameof(self)); var array = self.ToArray(); return array; } /// /// Outputs the enumeration in the form "(begin)element0(between)element1[...](end)". /// Each element is formatted by the delegate format. /// You may set any parameter to null, in which case the default values /// (v => v.ToString(), "", ", ", "") are used. /// public static string ToString( this IEnumerable self, Func format, string begin = null, string between = null, string end = null) { if (self is null) throw new ArgumentNullException(nameof(self)); if (format==null) format = v => v == null ? "" : v.ToString(); if (begin == null) begin = ""; if (between == null) between = ", "; if (end == null) end = ""; var sb = new StringBuilder(begin); bool first = true; foreach (var e in self) { if (!first) sb.Append(between); first = false; sb.Append(format(e)); } sb.Append(end); return sb.ToString(); } /// /// Creates a Dictionary(of TKey,TValue) from an IEnumerable(of TSource) /// according to specified key selector and element selector functions. /// /// The type of the elements of source. /// The type of the key returned by keySelector. /// The type of the value returned by elementSelector. /// An IEnumerable(of TSource) to create a Dictionary(of TKey,TValue) from. /// A function to extract a key from each element. /// A transform function to produce a result element value from each element. /// If a duplicate key was found, insert this element as value for the key. This value must be distinct from all other values generated by elementSelector. /// A Dictionary(of TKey,TValue) that contains values of type TElement selected from the input sequence. /// source or keySelector or elementSelector is null. -or- keySelector produces a key that is null. public static Dictionary ToDictionaryDistinct( this IEnumerable source, Func keySelector, Func elementSelector, TElement duplicateValue ) { if (source is null) throw new ArgumentNullException(nameof(source)); if (keySelector is null) throw new ArgumentNullException(nameof(keySelector)); if (elementSelector is null) throw new ArgumentNullException(nameof(elementSelector)); Dictionary dictionary = new Dictionary(); foreach (TSource local in source) { try { dictionary.Add(keySelector(local), elementSelector(local)); } catch (ArgumentException) { //An element with the same key already exists in the Dictionary. dictionary[keySelector(local)] = duplicateValue; } } return dictionary; } /// /// Creates a Dictionary(of TKey,TValue) from an IEnumerable(of TSource) /// containing all Key Value pairs with distinct keys. /// For duplicate keys, the returned value of is inserted instead. /// /// The type of the elements of source. /// The type of the key returned by keySelector. /// The type of the value returned by elementSelector. /// An IEnumerable(of T) to create a Dictionary(of TKey,TValue) from. /// A function to extract a key from each element. /// A transform function to produce a result element value from each element. /// If a duplicate key was found, the function is called with the element to be inserted and the duplicate element already associated with the key, and must return true if the first (original) element should be kept of false if the second (new) element should be inserted. /// A System.Collections.Generic.Dictionary(of TKey,TValue) that contains values of type TElement selected from the input sequence. /// Any of the arguments is null. -or- keySelector produces a key that is null. public static Dictionary ToDictionaryDistinct( this IEnumerable source, Func keySelector, Func elementSelector, Func duplicateKeyKeepElement) { if (source is null) throw new ArgumentNullException(nameof(source)); if (keySelector is null) throw new ArgumentNullException(nameof(keySelector)); if (elementSelector is null) throw new ArgumentNullException(nameof(elementSelector)); if (duplicateKeyKeepElement is null) throw new ArgumentNullException(nameof(duplicateKeyKeepElement)); var dictionary = new Dictionary(); foreach (var v in source) { var key = keySelector(v); var element = elementSelector(v); try { dictionary.Add(key, element); } catch (ArgumentException) { //[inefficient ISSUE 20091202 andi] Unfortunately very inefficient because of Dictionary implementation, since it is necessary to hash 3 times! if(!duplicateKeyKeepElement(dictionary[key], element)) dictionary[key] = element; } } return dictionary; } /// /// Creates a Dictionary(of TKey,TValue) from an IEnumerable(of TSource) /// containing all Key Value pairs with distinct keys. /// For duplicate keys, the returned value of is inserted instead. /// /// The type of the elements of source. /// The type of the key returned by keySelector. /// The type of the value returned by elementSelector. /// An IEnumerable(of T) to create a Dictionary(of TKey,TValue) from. /// A function to extract a key from each element. /// A transform function to produce a result element value from each element. /// If a duplicate key was found, the function is called with the element to be inserted and the duplicate element already associated with the key, and must return the element to be inserted instead at this key. /// A System.Collections.Generic.Dictionary(of TKey,TValue) that contains values of type TElement selected from the input sequence. /// Any of the arguments is null. -or- keySelector produces a key that is null. public static Dictionary ToDictionaryDistinct( this IEnumerable source, Func keySelector, Func elementSelector, Func duplicateKeyElementSelector ) { if (source is null) throw new ArgumentNullException(nameof(source)); if (keySelector is null) throw new ArgumentNullException(nameof(keySelector)); if (elementSelector is null) throw new ArgumentNullException(nameof(elementSelector)); if (duplicateKeyElementSelector is null) throw new ArgumentNullException(nameof(duplicateKeyElementSelector)); var dictionary = new Dictionary(); foreach (var v in source) { var key = keySelector(v); var element = elementSelector(v); try { dictionary.Add(key, element); } catch (ArgumentException) { //[inefficient ISSUE 20091202 andi] Unfortunately very inefficient because of Dictionary implementation, since it is necessary to hash 3 times! dictionary[key] = duplicateKeyElementSelector(dictionary[key], element); } } return dictionary; } /// /// This is a more efficient version of System.Linq.Enumerable.ToArray() when the number of elements of cannot be efficiently determined but is known. /// Creates an array from a . /// /// An array of size count that contains the elements from the input sequence. /// An to create an array from. /// The known size of the result-array. /// is null. /// is different from the number of elements in . public static TElement[] ToArray(this IEnumerable source, int count) { if (count == 0) { return Array.Empty(); } else { TElement[] array = null; int num = 0; ICollection collection = source as ICollection; if (collection != null) { num = collection.Count; array = new TElement[num]; if (num > 0) { collection.CopyTo(array, 0); } } else { array = new TElement[count]; foreach (TElement current in source) { if (count == num) throw new ArgumentException("Enumerable has more elements than count.", "count"); array[num] = current; num++; } } if (count > num) throw new ArgumentException("Enumerable has less elements than count.", "count"); return array; } } #endregion #region Missing Operators /// /// Lazily applies action to each element of sequence. /// public static IEnumerable Do(this IEnumerable self, Action action) { foreach (var x in self) { action(x); yield return x; } } /// /// Lazily applies action to each element of sequence. /// public static IEnumerable Do(this IEnumerable self, Action action) { long index = 0; foreach (var x in self) { action(x, index++); yield return x; } } /// /// Creates sequence containing the given item. /// public static IEnumerable Return(this T item) { yield return item; } /// /// Determines whether an array contains no elements. /// public static bool IsEmpty(this T[] self) => self.Length == 0; /// /// Determines whether a sequence contains no elements. /// public static bool IsEmpty(this ICollection self) => self.Count == 0; /// /// Determines whether a sequence contains no elements. /// public static bool IsEmpty(this IEnumerable self) => !self.Any(); // checks for ICollection internally /// /// Returns a sequence that contains only distinct contiguous elements. /// public static IEnumerable DistinctUntilChanged(this IEnumerable self) where T : IEquatable { bool first = true; T current = default(T); foreach (var x in self) { if (first) first = false; else if (x.Equals(current)) continue; current = x; yield return current; } } /// /// Returns index of first occurence of elementToFind. /// public static int IndexOf(this IEnumerable list, T elementToFind) { int i = 0; foreach (T element in list) { if (element.Equals(elementToFind)) return i; i++; } return -1; } /// /// Concats single item to sequence. /// public static IEnumerable Concat(this IEnumerable sequence, T item) { foreach (var x in sequence) yield return x; yield return item; } /// /// Concats sequence to single item. /// public static IEnumerable Concat(this T item, IEnumerable sequence) { yield return item; foreach (var x in sequence) yield return x; } /// /// Returns sequence of indices [0, sequence.Count()-1]. /// public static IEnumerable Indices(this IEnumerable sequence) { var i = 0; foreach (var x in sequence) yield return i++; } public static IEnumerable SelectMany(this IEnumerable<(T, T)> self) { foreach (var x in self) { yield return x.Item1; yield return x.Item2; } } public static IEnumerable SelectMany(this IEnumerable self, Func projection) { foreach (var y in self) { var x = projection(y); yield return x.Item1; yield return x.Item2; } } public static IEnumerable SelectMany(this IEnumerable<(T, T, T)> self) { foreach (var x in self) { yield return x.Item1; yield return x.Item2; yield return x.Item3; } } public static IEnumerable SelectMany(this IEnumerable self, Func projection) { foreach (var y in self) { var x = projection(y); yield return x.Item1; yield return x.Item2; yield return x.Item3; } } public static IEnumerable SelectMany(this IEnumerable<(T, T, T, T)> self) { foreach (var x in self) { yield return x.Item1; yield return x.Item2; yield return x.Item3; yield return x.Item4; } } public static IEnumerable SelectMany(this IEnumerable self, Func projection) { foreach (var y in self) { var x = projection(y); yield return x.Item1; yield return x.Item2; yield return x.Item3; yield return x.Item4; } } #endregion #region Math /// /// Converts a sequence that contains numbers of elements /// into a sequence that represents the indices of the /// first element if the elements are stored in consecutive /// order and is closed by the total count elements. /// The length of the integrated sequence is +1 of the input. /// public static IEnumerable Integrated(this IEnumerable counts, int sum = 0) { foreach (var c in counts) { yield return sum; sum += c; } yield return sum; } /// /// Integrates a sequence of values. /// Returns a sequence of N+1 values where the last is the sum off all value. /// public static IEnumerable Integrated(this IEnumerable values, double sum = 0) { foreach (var c in values) { yield return sum; sum += c; } yield return sum; } #endregion } } ================================================ FILE: src/Aardvark.Base/Extensions/IListExtensions.cs ================================================ using System; using System.Collections.Generic; namespace Aardvark.Base { public static class IListExtensions { /// /// Swap the two elements specified by ther indices. /// public static void Swap(this IList self, int i, int j) { T help = self[i]; self[i] = self[j]; self[j] = help; } public static SubRange SubRange(this IList self, int index, int count) => new SubRange(self, index, count); #region FindIndex /// /// Searches for an element that matches the conditions defined by the specified predicate, /// and returns the zero-based index of the first occurrence within the range of elements in the IList(of T) /// that starts at the and contains elements. /// If startSearch differs from startIndex, a cyclic search is performed in the range starting at . /// /// The type of the elements of the IList(of T). /// The list to search. /// The zero-based starting index of the search range. /// The number of elements in the search range. /// The first element to search in a cyclic manner. Will be wrapped around, if outside [startIndex, startIndex+count-1]. Non-cyclick search if this equals . /// If true the search is performed in direction of increasing indices, else in the direction of decreasing indices. /// The Predicate(of T) that defines the conditions of the element to search for. /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1. public static int FindIndex(this IList list, int startIndex, int count, bool forward, int startSearch, Predicate match) { if (list == null) throw new ArgumentNullException("list"); var listCount = list.Count; if ((startIndex < 0) || (startIndex > listCount)) throw new ArgumentOutOfRangeException("startIndex", "Index was out of range. Must be non-negative and less than the size of the collection."); if ((count < 0) || (startIndex > (listCount - count))) throw new ArgumentOutOfRangeException("count", "Count must be positive and count must refer to a location within the string/array/collection."); if (match == null) throw new ArgumentNullException("match"); if (count == 0) return -1; int endIndex = startIndex + count; if ((startSearch < startIndex) || (startSearch >= endIndex)) { //wrap around startSearch to be in the interval [startIndex, startIndex+count-1] startSearch = (startSearch - startIndex) % count; if (startSearch < 0) startSearch += count; //this is the ModP implementation. Since Fun.ModP() is in Aardvark.Math it is not accessible here. startSearch += startIndex; } if (forward) { for (int i = startSearch; i < endIndex; i++) if (match(list[i])) return i; for (int i = startIndex; i < startSearch; i++) if (match(list[i])) return i; } else { for (int i = startSearch; i >= startIndex; i--) if (match(list[i])) return i; for (int i = endIndex - 1; i > startSearch; i--) if (match(list[i])) return i; } return -1; } /// /// Searches for an element that matches the conditions defined by the specified predicate, /// and returns the zero-based index of the first occurrence within the range of elements in the IList(of T) /// that starts at the and contains elements. /// /// The type of the elements of the IList(of T). /// The list to search. /// The zero-based starting index of the search range. /// The number of elements in the search range. /// If true the search is performed in direction of increasing indices, else in the direction of decreasing indices. /// The Predicate(of T) that defines the conditions of the element to search for. /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1. public static int FindIndex(this IList list, int startIndex, int count, bool forward, Predicate match) => FindIndex(list, startIndex, count, forward, startIndex, match); /// /// Searches for an element that matches the conditions defined by the specified predicate, /// and returns the zero-based index of the first occurrence within the range of elements in the IList(of T) /// that extends from the to the end of the list. /// If startSearch differs from startIndex, a cyclic search is performed in the range starting at . /// /// The type of the elements of the IList(of T). /// The list to search. /// The zero-based starting index of the search range. /// The first element to search in a cyclic manner. Non-cyclick search if this equals /// If true the search is performed in direction of increasing indices, else in the direction of decreasing indices. /// The Predicate(of T) that defines the conditions of the element to search for. /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1. public static int FindIndex(this IList list, int startIndex, bool forward, int startSearch, Predicate match) { if(list == null) throw new ArgumentNullException("list"); return FindIndex(list, startIndex, list.Count - startIndex, forward, startSearch, match); } /// /// Searches for an element that matches the conditions defined by the specified predicate, /// and returns the zero-based index of the first occurrence within the range of elements in the IList(of T) /// that extends from the to the end of the list. /// /// The type of the elements of the IList(of T). /// The list to search. /// The zero-based starting index of the search range. /// If true the search is performed in direction of increasing indices, else in the direction of decreasing indices. /// The Predicate(of T) that defines the conditions of the element to search for. /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1. public static int FindIndex(this IList list, int startIndex, bool forward, Predicate match) => FindIndex(list, startIndex, forward, startIndex, match); /// /// Searches for an element that matches the conditions defined by the specified predicate, /// and returns the zero-based index of the first occurrence. /// If startSearch differs from startIndex, a cyclic search is performed in the range starting at . /// /// The type of the elements of the IList(of T). /// The list to search. /// The first element to search in a cyclic manner. /// If true the search is performed in direction of increasing indices, else in the direction of decreasing indices. /// The Predicate(of T) that defines the conditions of the element to search for. /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1. public static int FindIndex(this IList list, bool forward, int startSearch, Predicate match) => FindIndex(list, 0, forward, startSearch, match); /// /// Searches for an element that matches the conditions defined by the specified predicate, /// and returns the zero-based index of the first occurrence. /// /// The type of the elements of the IList(of T). /// The list to search. /// If true the search is performed in direction of increasing indices, else in the direction of decreasing indices. /// The Predicate(of T) that defines the conditions of the element to search for. /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1. public static int FindIndex(this IList list, bool forward, Predicate match) => FindIndex(list, 0, forward, 0, match); #endregion FindIndex #region IList of IComparables public static int CompareTo(this IList self, IList other) where T : IComparable { int imax = System.Math.Min(self.Count, other.Count); for (int i = 0; i < imax; i++) { int r = self[i].CompareTo(other[i]); if (r != 0) return r; } return (self.Count < other.Count) ? -1 : ((self.Count > other.Count) ? 1 : 0); } public static int FirstIndexOf(this IList self, IList other) where T : IComparable => self.FirstIndexOf(other, 0); /// /// Search first occurance of other in self, and return index if found /// or -1 if not found. NOTE: simple algorithm, not optimized. /// public static int FirstIndexOf(this IList self, IList other, int startIndex) where T : IComparable { for (int i = startIndex; i < 1 + self.Count - other.Count; i++) { bool match = true; for (int j = 0; j < other.Count; j++) if (self[i + j].CompareTo(other[j]) != 0) { match = false; break; } if (match) return i; } return -1; } public static int SmallestIndex(this IList self) where T: IComparable { int index = 0; T min = self[0]; for (int i = 1; i < self.Count; i++) if (self[i].CompareTo(min) < 0) { min = self[i]; index = i; } return index; } public static int LargestIndex(this IList self) where T : IComparable { int index = 0; T max = self[0]; for (int i = 1; i < self.Count; i++) if (self[i].CompareTo(max) > 0) { max = self[i]; index = i; } return index; } /// /// Returns the index of the n-smallest item. /// /// /// [0-self.Count()-1]; n=0 -> index of min element public static int NSmallestIndex(this IList self, int n) where T : IComparable { if (n == 0) return self.SmallestIndex(); T min; var sorted = new List(self); sorted.Sort(); min = sorted[n]; return self.IndexOf(min); } /// /// Returns the index of the n-largest item. /// /// /// [0-self.Count()-1]; n=0 -> index of max element public static int NLargestIndex(this IList self, int n) where T : IComparable { if (n == 0) return self.LargestIndex(); T max; var sorted = new List(self); sorted.Sort(); max = sorted[sorted.Count - 1 - n]; return self.IndexOf(max); } #endregion #region Generic IList Copying /// /// Use this instead of Clone() in order to get a typed array back. /// public static T[] Copy(this IList xs) { var count = xs.Count; var result = new T[count]; for (var i = 0; i < count; i++) result[i] = xs[i]; return result; } /// /// Create a copy of the specified length. If the copy is longer /// it is filled with default elements. /// public static T[] Copy(this IList xs, int count) { var result = new T[count]; var len = Math.Min(count, xs.Count); for (var i = 0; i < len; i++) result[i] = xs[i]; return result; } /// /// Create a copy of the specified length starting at the specified /// start. If the copy is longer it is filled with default elements. /// public static T[] Copy(this IList xs, int start, int count) { var result = new T[count]; var len = Math.Min(count, xs.Count - start); for (var i = 0; i < len; i++) result[i] = xs[i + start]; return result; } /// /// Create a copy with the elements piped through a function. /// public static Tr[] Map(this IList xs, Func item_fun) { var len = xs.Count; var result = new Tr[len]; for (var i = 0; i < len; i++) result[i] = item_fun(xs[i]); return result; } /// /// Create an array of resulting items by applying a supplied binary function /// to corresponding pairs of the supplied ILists. /// /// public static Tr[] Map2( this IList xs0, IList xs1, Func item0_item1_fun) { var len = Fun.Min(xs0.Count, xs1.Count); var result = new Tr[len]; for (var i = 0; i < len; i++) result[i] = item0_item1_fun(xs0[i], xs1[i]); return result; } /// /// Create an array of resulting items by applying a supplied ternary function /// to corresponding triples of the supplied ILists. /// /// public static Tr[] Map3( this IList xs0, IList xs1, IList xs2, Func item0_item1_item2_fun) { var len = Fun.Min(xs0.Count, xs1.Count, xs2.Count); var result = new Tr[len]; for (var i = 0; i < len; i++) result[i] = item0_item1_item2_fun(xs0[i], xs1[i], xs2[i]); return result; } /// /// Create a copy with the elements piped through a function. /// The function gets the index of the element as a second argument. /// public static Tr[] Map(this IList xs, Func item_index_fun) { var len = xs.Count; var result = new Tr[len]; for (var i = 0; i < len; i++) result[i] = item_index_fun(xs[i], i); return result; } public static Tr[] Map2( this IList xs0, IList xs1, Func item0_item1_index_fun) { var len = Fun.Min(xs0.Count, xs1.Count); var result = new Tr[len]; for (var i = 0; i < len; i++) result[i] = item0_item1_index_fun(xs0[i], xs1[i], i); return result; } public static Tr[] Map3( this IList xs0, IList xs1, IList xs2, Func item0_item1_item2_index_fun) { var len = Fun.Min(xs0.Count, xs1.Count, xs2.Count); var result = new Tr[len]; for (var i = 0; i < len; i++) result[i] = item0_item1_item2_index_fun(xs0[i], xs1[i], xs2[i], i); return result; } /// /// Create a copy of count elements with the elements piped through a /// function. count may be longer than the input, in this case the /// result array has default elements at the end. /// public static Tr[] Map( this IList xs, int count, Func element_fun) { var result = new Tr[count]; var len = Math.Min(count, xs.Count); for (var i = 0; i < len; i++) result[i] = element_fun(xs[i]); return result; } /// /// Create a copy of count elements with the elements piped through a /// function. count may be longer than the input, in this case the /// result array has default elements at the end. /// The function gets the index of the element as a second argument. /// public static Tr[] Map( this IList xs, int count, Func element_index_fun) { var result = new Tr[count]; var len = Math.Min(count, xs.Count); for (var i = 0; i < len; i++) result[i] = element_index_fun(xs[i], i); return result; } /// /// Create a copy of specified length starting at the specified /// offset with the elements piped through a function. /// public static Tr[] Map( this IList xs, int start, int count, Func element_fun) { var result = new Tr[count]; var len = Math.Min(count, xs.Count - start); for (var i = 0; i < len; i++) result[i] = element_fun(xs[start + i]); return result; } /// /// Create a copy of specified length starting at the specified /// offset with the elements piped through a function. /// The function gets the target index of the element as a second /// argument. /// public static Tr[] Map( this IList xs, int start, int count, Func element_index_fun) { var result = new Tr[count]; var len = Math.Min(count, xs.Count - start); for (var i = 0; i < len; i++) result[i] = element_index_fun(xs[start + i], i); return result; } /// /// Copy a range of elements to the target array. /// public static void CopyTo(this IList xs, int count, T[] target, int targetStart) { for (var i = 0; i < count; i++) target[targetStart + i] = xs[i]; } /// /// Copy a range of elements to the target array. /// public static void CopyTo(this IList xs, int start, int count, T[] target, int targetStart) { for (var i = 0; i < count; i++) target[targetStart + i] = xs[start + i]; } /// /// Copies the IList into a list. /// public static List CopyToList(this IList xs) { var result = new List(xs.Count); result.AddRange(xs); return result; } public static List MapToList(this IList xs, Func element_fun) { var count = xs.Count; var result = new List(count); for (int i = 0; i < count; i++) result.Add(element_fun(xs[i])); return result; } public static List MapToList(this IList xs, Func item_index_fun) { var count = xs.Count; var result = new List(count); for (int i = 0; i < count; i++) result.Add(item_index_fun(xs[i], i)); return result; } /// /// Copies the specified range of elements to the specified destination /// within the same IList. /// public static void CopyRange(this IList xs, int start, int count, int targetStart) { var end = start + count; if (targetStart < start || targetStart >= end) { while (start < end) xs[targetStart++] = xs[start++]; } else { targetStart += count; while (start < end) xs[--targetStart] = xs[--end]; } } /// /// Create a copy with the elements reversed. /// public static T[] CopyReversed(this IList xs) { var result = new T[xs.Count]; var lastIndex = xs.Count - 1; for (var i = 0; i <= lastIndex; i++) { result[i] = xs[lastIndex - i]; } return result; } #endregion } } ================================================ FILE: src/Aardvark.Base/Extensions/IsExternalInit.cs ================================================ #if !NET8_0_OR_GREATER using System.ComponentModel; namespace System.Runtime.CompilerServices { // See: https://github.com/dotnet/roslyn/issues/45510 [EditorBrowsable(EditorBrowsableState.Never)] public static class IsExternalInit { } } #endif ================================================ FILE: src/Aardvark.Base/Extensions/ListExtensions.cs ================================================ using System; using System.Collections.Generic; using static System.Math; namespace Aardvark.Base { public static class ListFun { #region Copying public static List Copy(this List self) { var result = new List(self.Count); foreach (var item in self) result.Add(item); return result; } /// /// Create a copy with the elements piped through a function. /// public static List Map(this List list, Func item_fun) { var count = list.Count; var result = new List(count); for (var i = 0; i < count; i++) result.Add(item_fun(list[i])); return result; } public static List Map2( this List list0, List list1, Func item0_item1_fun) { var count = Min(list0.Count, list1.Count); var result = new List(count); for (var i = 0; i < count; i++) result.Add(item0_item1_fun(list0[i], list1[i])); return result; } public static List Map3( this List list0, List list1, List list2, Func item0_item1_item2_fun) { var count = Min(Min(list0.Count, list1.Count), list2.Count); var result = new List(count); for (var i = 0; i < count; i++) result.Add(item0_item1_item2_fun(list0[i], list1[i], list2[i])); return result; } /// /// Create a copy with the elements piped through a function. /// public static List Map(this List list, Func item_index_fun) { var count = list.Count; var result = new List(count); for (int i = 0; i < count; i++) result.Add(item_index_fun(list[i], i)); return result; } public static List Map2( this List list0, List list1, Func item0_item1_index_fun) { var count = Min(list0.Count, list1.Count); var result = new List(count); for (var i = 0; i < count; i++) result.Add(item0_item1_index_fun(list0[i], list1[i], i)); return result; } public static List Map3( this List list0, List list1, List list2, Func item0_item1_item2_index_fun) { var count = Min(Min(list0.Count, list1.Count), list2.Count); var result = new List(count); for (var i = 0; i < count; i++) result.Add(item0_item1_item2_index_fun(list0[i], list1[i], list2[i], i)); return result; } public static T[] CopyToArray(this List self) { return self.CopyToArray(self.Count); } public static T[] CopyToArray(this List self, int count) { var result = new T[count]; for (int i = 0; i < count; i++) result[i] = self[i]; return result; } public static Tr[] MapToArray(this List list, Func item_fun) { return list.MapToArray(list.Count, item_fun); } public static Tr[] MapToArray(this List list, int count, Func item_fun) { var result = new Tr[count]; if (list.Count < count) count = list.Count; for (int i = 0; i < count; i++) result[i] = item_fun(list[i]); return result; } public static Tr[] MapToArray( this List list, int start, int count, Func item_fun) { var result = new Tr[count]; if (start + count > list.Count) count = list.Count - start; for (int i = 0; i < count; i++) result[i] = item_fun(list[i + start]); return result; } #endregion #region Mapped Copy /// /// Returns an array copy of this list that is created by copying the /// elements at the positions specified in the supplied backward map. /// public static T[] BackwardMappedCopyToArray( this List sourceArray, int[] backwardMap) { T[] targetArray = new T[backwardMap.Length]; sourceArray.BackwardMappedCopyToArray(targetArray, backwardMap, 0); return targetArray; } /// /// Copies from this list into the target array starting at the /// supplied offset using the supplied backward map that contains /// the source index for each index of the target array. /// public static void BackwardMappedCopyToArray( this List source, T[] target, int[] backwardMap, int offset) { for (int i = 0; i < backwardMap.Length; i++) target[i + offset] = source[backwardMap[i]]; } /// /// Returns an array copy of this list that is created by copying the /// elements at the positions specified in the supplied backward map. /// public static Tr[] BackwardMappedCopyToArray( this List sourceArray, int[] backwardMap, Func fun) { Tr[] targetArray = new Tr[backwardMap.Length]; sourceArray.BackwardMappedCopyToArray(targetArray, backwardMap, 0, fun); return targetArray; } /// /// Copies from this list into the target array starting at the /// supplied offset using the supplied backward map that contains /// the source index for each index of the target array. /// public static void BackwardMappedCopyToArray( this List source, Tr[] target, int[] backwardMap, int offset, Func fun) { for (int i = 0; i < backwardMap.Length; i++) target[i + offset] = fun(source[backwardMap[i]]); } #endregion #region Adding Values public static List AddRange(this List list, T value, int count) { for (int i = 0; i < count; i++) list.Add(value); return list; } /// /// Add a specifable number of elements, each generated by a supplied /// function of the respective element index in the list. /// /// the supplied list, so that the function can be directly used after initialization public static List AddByIndex(this List list, int count, Func index_fun) { for (int i = list.Count, e = i + count; i < e; i++) list.Add(index_fun(i)); return list; } #endregion #region Setters /// /// Set all elements to the same supplied value. /// /// this public static List Set(this List self, T value) { for (int i = 0; i < self.Count; i++) self[i] = value; return self; } /// /// Set all elements to a function of the element index. /// /// this public static List Set(this List self, Func fun) { for (int i = 0; i < self.Count; i++) self[i] = fun(i); return self; } /// /// Set count elements starting at the supplied index to the same /// supplied value. /// /// this public static List Set(this List self, int start, int count, T value) { int end = System.Math.Min(start + count, self.Count); for (int i = start; i < end; i++) self[i] = value; return self; } /// /// Set count elements starting at the supplied index to the same /// supplied value. /// /// this public static List Set(this List self, int start, int count, Func fun) { int end = System.Math.Min(start + count, self.Count); for (int i = start; i < end; i++) self[i] = fun(i); return self; } #endregion #region /// /// Swap the two elements specified by ther indices. /// public static void Swap(this List self, int i, int j) { T help = self[i]; self[i] = self[j]; self[j] = help; } #endregion #region Heap public static IEnumerable> NLargestIndicesAscending( this IEnumerable values, int n) where T : IComparable { return values.NLargestIndices(n).HeapAscendingDequeueAll(); } public static List> NLargestIndices( this IEnumerable values, int n) where T : IComparable { if (n < 0) throw new ArgumentException("n >= 0 required"); var list = new List>(n + 1); if (n == 0) return list; int i = 0; foreach (var v in values) { var vi = i++; if (list.Count < n) { list.HeapAscendingEnqueue(v.ComparableIndexedValue(vi)); continue; } if (v.CompareTo(list[0].Value) < 0) continue; list.HeapAscendingEnqueue(v.ComparableIndexedValue(vi)); list.HeapAscendingDequeue(); } return list; } public static IEnumerable> NSmallestIndicesDescending( this IEnumerable values, int n) where T : IComparable { return values.NSmallestIndices(n).HeapDescendingDequeueAll(); } public static List> NSmallestIndices( this IEnumerable values, int n) where T : IComparable { if (n < 0) throw new ArgumentException("n < 0 requried"); var list = new List>(n + 1); if (n == 0) return list; int i = 0; foreach (var v in values) { var vi = i++; if (list.Count < n) { list.HeapDescendingEnqueue(v.ComparableIndexedValue(vi)); continue; } if (v.CompareTo(list[0].Value) > 0) continue; list.HeapDescendingEnqueue(v.ComparableIndexedValue(vi)); list.HeapDescendingDequeue(); } return list; } /// /// Adds an element to the heap, and maintains the heap condition. /// For default comparison functions the smallest item is on top of /// the heap. /// public static void HeapEnqueue( this List heap, Func compare, T element) { int i = heap.Count; heap.Add(element); while (i > 0) { int i2 = (i - 1) / 2; if (compare(element, heap[i2]) > 0) break; heap[i] = heap[i2]; i = i2; } heap[i] = element; } /// /// Removes and returns the item at the top of the heap (i.e. the /// 0th position of the list). For default comparison functions this /// is the smallest element. /// public static T HeapDequeue( this List heap, Func compare) { var result = heap[0]; var count = heap.Count; if (count == 1) { heap.Clear(); return result; } var element = heap[--count]; heap.RemoveAt(count); int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && compare(heap[i1], heap[i2]) > 0) ? i2 : i1; // smaller child if (compare(heap[ni], element) > 0) break; heap[i] = heap[ni]; i = ni; i1 = 2 * i + 1; } heap[i] = element; return result; } /// /// Removes and returns all items from the heap as an IEnumerable. For /// default comparison functiosn this is in ascending order. /// public static IEnumerable HeapDequeueAll( this List heap, Func compare) { while (heap.Count > 0) yield return heap.HeapDequeue(compare); } /// /// Reomves an arbitrary element from the heap, maintains the heap /// conditions, and returns the removed element. /// public static T HeapRemoveAt( this List heap, Func compare, int index) { var result = heap[index]; var count = heap.Count; if (count == 1) { heap.Clear(); return result; } var element = heap[--count]; heap.RemoveAt(count); if (index == count) return result; int i = index; while (i > 0) { int i2 = (i - 1) / 2; if (compare(element, heap[i2]) > 0) break; heap[i] = heap[i2]; i = i2; } if (i == index) { int i1 = 2 * i + 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && compare(heap[i1], heap[i2]) > 0) ? i2 : i1; // smaller child if (compare(heap[ni], element) > 0) break; heap[i] = heap[ni]; i = ni; i1 = 2 * i + 1; } } heap[i] = element; return result; } /// /// Adds an element to the heap, and maintains the heap condition. /// For default comparison functions the smallest item is on top of /// the heap. /// public static void HeapAscendingEnqueue( this List heap, T element) where T : IComparable { int i = heap.Count; heap.Add(element); while (i > 0) { int i2 = (i - 1) / 2; if (element.CompareTo(heap[i2]) > 0) break; heap[i] = heap[i2]; i = i2; } heap[i] = element; } /// /// Removes and returns the item at the top of the heap (i.e. the /// 0th position of the list). For default comparison functions this /// is the smallest element. /// public static T HeapAscendingDequeue( this List heap) where T : IComparable { var result = heap[0]; var count = heap.Count; if (count == 1) { heap.Clear(); return result; } var element = heap[--count]; heap.RemoveAt(count); int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && heap[i1].CompareTo(heap[i2]) > 0) ? i2 : i1; // smaller child if (heap[ni].CompareTo(element) > 0) break; heap[i] = heap[ni]; i = ni; i1 = 2 * i + 1; } heap[i] = element; return result; } /// /// Removes and returns all items from the heap as an IEnumerable. For /// default comparison functiosn this is in ascending order. /// public static IEnumerable HeapAscendingDequeueAll( this List heap) where T : IComparable { while (heap.Count > 0) yield return heap.HeapAscendingDequeue(); } /// /// Reomves an arbitrary element from the heap, maintains the heap /// conditions, and returns the removed element. /// public static T HeapAscendingRemoveAt( this List heap, int index) where T : IComparable { var result = heap[index]; var count = heap.Count; if (count == 1) { heap.Clear(); return result; } var element = heap[--count]; heap.RemoveAt(count); if (index == count) return result; int i = index; while (i > 0) { int i2 = (i - 1) / 2; if (element.CompareTo(heap[i2]) > 0) break; heap[i] = heap[i2]; i = i2; } if (i == index) { int i1 = 2 * i + 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && heap[i1].CompareTo(heap[i2]) > 0) ? i2 : i1; // smaller child if (heap[ni].CompareTo(element) > 0) break; heap[i] = heap[ni]; i = ni; i1 = 2 * i + 1; } } heap[i] = element; return result; } /// /// Adds an element to the heap, and maintains the heap condition. /// For default comparison functions the smallest item is on top of /// the heap. /// public static void HeapDescendingEnqueue( this List heap, T element) where T : IComparable { int i = heap.Count; heap.Add(element); while (i > 0) { int i2 = (i - 1) / 2; if (element.CompareTo(heap[i2]) < 0) break; heap[i] = heap[i2]; i = i2; } heap[i] = element; } /// /// Removes and returns the item at the top of the heap (i.e. the /// 0th position of the list). For default comparison functions this /// is the smallest element. /// public static T HeapDescendingDequeue( this List heap) where T : IComparable { var result = heap[0]; var count = heap.Count; if (count == 1) { heap.Clear(); return result; } var element = heap[--count]; heap.RemoveAt(count); int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && heap[i1].CompareTo(heap[i2]) < 0) ? i2 : i1; // smaller child if (heap[ni].CompareTo(element) < 0) break; heap[i] = heap[ni]; i = ni; i1 = 2 * i + 1; } heap[i] = element; return result; } /// /// Removes and returns all items from the heap as an IEnumerable. For /// default comparison functiosn this is in ascending order. /// public static IEnumerable HeapDescendingDequeueAll( this List heap) where T : IComparable { while (heap.Count > 0) yield return heap.HeapDescendingDequeue(); } /// /// Reomves an arbitrary element from the heap, maintains the heap /// conditions, and returns the removed element. /// public static T HeapDescendingRemoveAt( this List heap, int index) where T : IComparable { var result = heap[index]; var count = heap.Count; if (count == 1) { heap.Clear(); return result; } var element = heap[--count]; heap.RemoveAt(count); if (index == count) return result; int i = index; while (i > 0) { int i2 = (i - 1) / 2; if (element.CompareTo(heap[i2]) < 0) break; heap[i] = heap[i2]; i = i2; } if (i == index) { int i1 = 2 * i + 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && heap[i1].CompareTo(heap[i2]) < 0) ? i2 : i1; // smaller child if (heap[ni].CompareTo(element) < 0) break; heap[i] = heap[ni]; i = ni; i1 = 2 * i + 1; } } heap[i] = element; return result; } #endregion #region Lists of IComparables public static List MergeSortedAscending(this List a0, List a1) where T : IComparable { int c0 = a0.Count; int c1 = a1.Count; var a = new List(c0 + c1); int i0 = 0, i1 = 0; while (i0 < c0 && i1 < c1) { if (a0[i0].CompareTo(a1[i1]) <= 0) a.Add(a0[i0++]); else a.Add(a1[i1++]); } while (i0 < c0) a.Add(a0[i0++]); while (i1 < c1) a.Add(a1[i1++]); return a; } public static T[] MergeSortAscending(this T[] a0, T[] a1) where T : IComparable { long c0 = a0.LongLength; long c1 = a1.LongLength; var a = new T[c0 + c1]; long i0 = 0, i1 = 0, i = 0; while (i0 < c0 && i1 < c1) { if (a0[i0].CompareTo(a1[i1]) <= 0) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < c0) a[i++] = a0[i0++]; while (i1 < c1) a[i++] = a1[i1++]; return a; } public static int SmallestIndex(this List a) where T : IComparable { int index = 0; T min = a[0]; for (int i = 1; i < a.Count; i++) if (a[i].CompareTo(min) < 0) { min = a[i]; index = i; } return index; } public static int LargestIndex(this List a) where T : IComparable { int index = 0; T max = a[0]; for (int i = 1; i < a.Count; i++) if (a[i].CompareTo(max) > 0) { max = a[i]; index = i; } return index; } #endregion } } ================================================ FILE: src/Aardvark.Base/Extensions/NonGenericArray.cs ================================================ using System; using System.Collections.Generic; namespace Aardvark.Base { public static class NonGenericArrayExtensions { #region Non-Generic Array [Obsolete] private static readonly Dictionary> CopyFunMap = new Dictionary> { { typeof(byte[]), a => ((byte[])a).Copy() }, { typeof(sbyte[]), a => ((sbyte[])a).Copy() }, { typeof(ushort[]), a => ((ushort[])a).Copy() }, { typeof(short[]), a => ((short[])a).Copy() }, { typeof(uint[]), a => ((uint[])a).Copy() }, { typeof(int[]), a => ((int[])a).Copy() }, { typeof(ulong[]), a => ((ulong[])a).Copy() }, { typeof(long[]), a => ((long[])a).Copy() }, { typeof(float[]), a => ((float[])a).Copy() }, { typeof(double[]), a => ((double[])a).Copy() }, { typeof(C3b[]), a => ((C3b[])a).Copy() }, { typeof(C3us[]), a => ((C3us[])a).Copy() }, { typeof(C3ui[]), a => ((C3ui[])a).Copy() }, { typeof(C3f[]), a => ((C3f[])a).Copy() }, { typeof(C3d[]), a => ((C3d[])a).Copy() }, { typeof(C4b[]), a => ((C4b[])a).Copy() }, { typeof(C4us[]), a => ((C4us[])a).Copy() }, { typeof(C4ui[]), a => ((C4ui[])a).Copy() }, { typeof(C4f[]), a => ((C4f[])a).Copy() }, { typeof(C4d[]), a => ((C4d[])a).Copy() }, { typeof(V2i[]), a => ((V2i[])a).Copy() }, { typeof(V2l[]), a => ((V2l[])a).Copy() }, { typeof(V2f[]), a => ((V2f[])a).Copy() }, { typeof(V2d[]), a => ((V2d[])a).Copy() }, { typeof(V3i[]), a => ((V3i[])a).Copy() }, { typeof(V3l[]), a => ((V3l[])a).Copy() }, { typeof(V3f[]), a => ((V3f[])a).Copy() }, { typeof(V3d[]), a => ((V3d[])a).Copy() }, { typeof(V4i[]), a => ((V4i[])a).Copy() }, { typeof(V4l[]), a => ((V4l[])a).Copy() }, { typeof(V4f[]), a => ((V4f[])a).Copy() }, { typeof(V4d[]), a => ((V4d[])a).Copy() }, }; /// /// Creates a copy of the array. /// public static Array Copy(this Array array) { var counts = new long[array.Rank]; for (int i = 0; i < counts.Length; i++) { counts[i] = array.GetLongLength(i); } var result = Array.CreateInstance(array.GetType().GetElementType(), counts); Array.Copy(array, result, array.LongLength); return result; } [Obsolete] private static readonly Dictionary> CopyFunFunMap = new Dictionary> { { typeof(byte[]), (a, f) => ((byte[])a).Map((Func)f) }, { typeof(sbyte[]), (a, f) => ((sbyte[])a).Map((Func)f) }, { typeof(ushort[]), (a, f) => ((ushort[])a).Map((Func)f) }, { typeof(short[]), (a, f) => ((short[])a).Map((Func)f) }, { typeof(uint[]), (a, f) => ((uint[])a).Map((Func)f) }, { typeof(int[]), (a, f) => ((int[])a).Map((Func)f) }, { typeof(ulong[]), (a, f) => ((ulong[])a).Map((Func)f) }, { typeof(long[]), (a, f) => ((long[])a).Map((Func)f) }, { typeof(float[]), (a, f) => ((float[])a).Map((Func)f) }, { typeof(double[]), (a, f) => ((double[])a).Map((Func)f) }, { typeof(C3b[]), (a, f) => ((C3b[])a).Map((Func)f) }, { typeof(C3us[]), (a, f) => ((C3us[])a).Map((Func)f) }, { typeof(C3ui[]), (a, f) => ((C3ui[])a).Map((Func)f) }, { typeof(C3f[]), (a, f) => ((C3f[])a).Map((Func)f) }, { typeof(C3d[]), (a, f) => ((C3d[])a).Map((Func)f) }, { typeof(C4b[]), (a, f) => ((C4b[])a).Map((Func)f) }, { typeof(C4us[]), (a, f) => ((C4us[])a).Map((Func)f) }, { typeof(C4ui[]), (a, f) => ((C4ui[])a).Map((Func)f) }, { typeof(C4f[]), (a, f) => ((C4f[])a).Map((Func)f) }, { typeof(C4d[]), (a, f) => ((C4d[])a).Map((Func)f) }, { typeof(V2i[]), (a, f) => ((V2i[])a).Map((Func)f) }, { typeof(V2l[]), (a, f) => ((V2l[])a).Map((Func)f) }, { typeof(V2f[]), (a, f) => ((V2f[])a).Map((Func)f) }, { typeof(V2d[]), (a, f) => ((V2d[])a).Map((Func)f) }, { typeof(V3i[]), (a, f) => ((V3i[])a).Map((Func)f) }, { typeof(V3l[]), (a, f) => ((V3l[])a).Map((Func)f) }, { typeof(V3f[]), (a, f) => ((V3f[])a).Map((Func)f) }, { typeof(V3d[]), (a, f) => ((V3d[])a).Map((Func)f) }, { typeof(V4i[]), (a, f) => ((V4i[])a).Map((Func)f) }, { typeof(V4l[]), (a, f) => ((V4l[])a).Map((Func)f) }, { typeof(V4f[]), (a, f) => ((V4f[])a).Map((Func)f) }, { typeof(V4d[]), (a, f) => ((V4d[])a).Map((Func)f) }, }; [Obsolete("Anybody using this?")] public static Array Copy(this Array array, Func funOfElementTypeToElementType, Func defaultFun = null) { var arrayType = array.GetType(); if (typeof(T) == arrayType.GetElementType()) return CopyFunFunMap[arrayType](array, funOfElementTypeToElementType); else if (defaultFun != null) return defaultFun(array); else return CopyFunMap[arrayType](array); } private static readonly Dictionary> ResizedFunMap = new Dictionary> { { typeof(byte[]), (a, s) => ((byte[])a).Resized(s) }, { typeof(sbyte[]), (a, s) => ((sbyte[])a).Resized(s) }, { typeof(ushort[]), (a, s) => ((ushort[])a).Resized(s) }, { typeof(short[]), (a, s) => ((short[])a).Resized(s) }, { typeof(uint[]), (a, s) => ((uint[])a).Resized(s) }, { typeof(int[]), (a, s) => ((int[])a).Resized(s) }, { typeof(ulong[]), (a, s) => ((ulong[])a).Resized(s) }, { typeof(long[]), (a, s) => ((long[])a).Resized(s) }, { typeof(float[]), (a, s) => ((float[])a).Resized(s) }, { typeof(double[]), (a, s) => ((double[])a).Resized(s) }, { typeof(C3b[]), (a, s) => ((C3b[])a).Resized(s) }, { typeof(C3us[]), (a, s) => ((C3us[])a).Resized(s) }, { typeof(C3ui[]), (a, s) => ((C3ui[])a).Resized(s) }, { typeof(C3f[]), (a, s) => ((C3f[])a).Resized(s) }, { typeof(C3d[]), (a, s) => ((C3d[])a).Resized(s) }, { typeof(C4b[]), (a, s) => ((C4b[])a).Resized(s) }, { typeof(C4us[]), (a, s) => ((C4us[])a).Resized(s) }, { typeof(C4ui[]), (a, s) => ((C4ui[])a).Resized(s) }, { typeof(C4f[]), (a, s) => ((C4f[])a).Resized(s) }, { typeof(C4d[]), (a, s) => ((C4d[])a).Resized(s) }, { typeof(V2i[]), (a, s) => ((V2i[])a).Resized(s) }, { typeof(V2l[]), (a, s) => ((V2l[])a).Resized(s) }, { typeof(V2f[]), (a, s) => ((V2f[])a).Resized(s) }, { typeof(V2d[]), (a, s) => ((V2d[])a).Resized(s) }, { typeof(V3i[]), (a, s) => ((V3i[])a).Resized(s) }, { typeof(V3l[]), (a, s) => ((V3l[])a).Resized(s) }, { typeof(V3f[]), (a, s) => ((V3f[])a).Resized(s) }, { typeof(V3d[]), (a, s) => ((V3d[])a).Resized(s) }, { typeof(V4i[]), (a, s) => ((V4i[])a).Resized(s) }, { typeof(V4l[]), (a, s) => ((V4l[])a).Resized(s) }, { typeof(V4f[]), (a, s) => ((V4f[])a).Resized(s) }, { typeof(V4d[]), (a, s) => ((V4d[])a).Resized(s) }, }; public static Array Resized(this Array array, int size) { return ResizedFunMap[array.GetType()](array, size); } private static readonly Dictionary> BackMappedCopyFunMap = new Dictionary> { { typeof(byte[]), (a,m,c) => ((byte[])a).BackMappedCopy(m, c) }, { typeof(sbyte[]), (a,m,c) => ((sbyte[])a).BackMappedCopy(m, c) }, { typeof(short[]), (a,m,c) => ((short[])a).BackMappedCopy(m, c) }, { typeof(ushort[]), (a,m,c) => ((ushort[])a).BackMappedCopy(m, c) }, { typeof(int[]), (a,m,c) => ((int[])a).BackMappedCopy(m, c) }, { typeof(uint[]), (a,m,c) => ((uint[])a).BackMappedCopy(m, c) }, { typeof(long[]), (a,m,c) => ((long[])a).BackMappedCopy(m, c) }, { typeof(ulong[]), (a,m,c) => ((ulong[])a).BackMappedCopy(m, c) }, { typeof(float[]), (a,m,c) => ((float[])a).BackMappedCopy(m, c) }, { typeof(double[]), (a,m,c) => ((double[])a).BackMappedCopy(m, c) }, { typeof(C3b[]), (a,m,c) => ((C3b[])a).BackMappedCopy(m, c) }, { typeof(C3us[]), (a,m,c) => ((C3us[])a).BackMappedCopy(m, c) }, { typeof(C3ui[]), (a,m,c) => ((C3ui[])a).BackMappedCopy(m, c) }, { typeof(C3f[]), (a,m,c) => ((C3f[])a).BackMappedCopy(m, c) }, { typeof(C3d[]), (a,m,c) => ((C3d[])a).BackMappedCopy(m, c) }, { typeof(C4b[]), (a,m,c) => ((C4b[])a).BackMappedCopy(m, c) }, { typeof(C4us[]), (a,m,c) => ((C4us[])a).BackMappedCopy(m, c) }, { typeof(C4ui[]), (a,m,c) => ((C4ui[])a).BackMappedCopy(m, c) }, { typeof(C4f[]), (a,m,c) => ((C4f[])a).BackMappedCopy(m, c) }, { typeof(C4d[]), (a,m,c) => ((C4d[])a).BackMappedCopy(m, c) }, { typeof(V2i[]), (a,m,c) => ((V2i[])a).BackMappedCopy(m, c) }, { typeof(V2l[]), (a,m,c) => ((V2l[])a).BackMappedCopy(m, c) }, { typeof(V2f[]), (a,m,c) => ((V2f[])a).BackMappedCopy(m, c) }, { typeof(V2d[]), (a,m,c) => ((V2d[])a).BackMappedCopy(m, c) }, { typeof(V3i[]), (a,m,c) => ((V3i[])a).BackMappedCopy(m, c) }, { typeof(V3l[]), (a,m,c) => ((V3l[])a).BackMappedCopy(m, c) }, { typeof(V3f[]), (a,m,c) => ((V3f[])a).BackMappedCopy(m, c) }, { typeof(V3d[]), (a,m,c) => ((V3d[])a).BackMappedCopy(m, c) }, { typeof(V4i[]), (a,m,c) => ((V4i[])a).BackMappedCopy(m, c) }, { typeof(V4l[]), (a,m,c) => ((V4l[])a).BackMappedCopy(m, c) }, { typeof(V4f[]), (a,m,c) => ((V4f[])a).BackMappedCopy(m, c) }, { typeof(V4d[]), (a,m,c) => ((V4d[])a).BackMappedCopy(m, c) }, }; public static Array BackMappedCopy( this Array source, int[] backMap, int count = 0) { if (BackMappedCopyFunMap.TryGetValue(source.GetType(), out Func fun)) return fun(source, backMap, count); return null; } private static readonly Dictionary> BackMappedIndexedCopyFunMap = new Dictionary> { { typeof(byte[]), (a,i,m,c) => ((byte[])a).BackMappedCopy(i, m, c) }, { typeof(sbyte[]), (a,i,m,c) => ((sbyte[])a).BackMappedCopy(i, m, c) }, { typeof(short[]), (a,i,m,c) => ((short[])a).BackMappedCopy(i, m, c) }, { typeof(ushort[]), (a,i,m,c) => ((ushort[])a).BackMappedCopy(i, m, c) }, { typeof(int[]), (a,i,m,c) => ((int[])a).BackMappedCopy(i, m, c) }, { typeof(uint[]), (a,i,m,c) => ((uint[])a).BackMappedCopy(i, m, c) }, { typeof(long[]), (a,i,m,c) => ((long[])a).BackMappedCopy(i, m, c) }, { typeof(ulong[]), (a,i,m,c) => ((ulong[])a).BackMappedCopy(i, m, c) }, { typeof(float[]), (a,i,m,c) => ((float[])a).BackMappedCopy(i, m, c) }, { typeof(double[]), (a,i,m,c) => ((double[])a).BackMappedCopy(i, m, c) }, { typeof(C3b[]), (a,i,m,c) => ((C3b[])a).BackMappedCopy(i, m, c) }, { typeof(C3us[]), (a,i,m,c) => ((C3us[])a).BackMappedCopy(i, m, c) }, { typeof(C3ui[]), (a,i,m,c) => ((C3ui[])a).BackMappedCopy(i, m, c) }, { typeof(C3f[]), (a,i,m,c) => ((C3f[])a).BackMappedCopy(i, m, c) }, { typeof(C3d[]), (a,i,m,c) => ((C3d[])a).BackMappedCopy(i, m, c) }, { typeof(C4b[]), (a,i,m,c) => ((C4b[])a).BackMappedCopy(i, m, c) }, { typeof(C4us[]), (a,i,m,c) => ((C4us[])a).BackMappedCopy(i, m, c) }, { typeof(C4ui[]), (a,i,m,c) => ((C4ui[])a).BackMappedCopy(i, m, c) }, { typeof(C4f[]), (a,i,m,c) => ((C4f[])a).BackMappedCopy(i, m, c) }, { typeof(C4d[]), (a,i,m,c) => ((C4d[])a).BackMappedCopy(i, m, c) }, { typeof(V2i[]), (a,i,m,c) => ((V2i[])a).BackMappedCopy(i, m, c) }, { typeof(V2l[]), (a,i,m,c) => ((V2l[])a).BackMappedCopy(i, m, c) }, { typeof(V2f[]), (a,i,m,c) => ((V2f[])a).BackMappedCopy(i, m, c) }, { typeof(V2d[]), (a,i,m,c) => ((V2d[])a).BackMappedCopy(i, m, c) }, { typeof(V3i[]), (a,i,m,c) => ((V3i[])a).BackMappedCopy(i, m, c) }, { typeof(V3l[]), (a,i,m,c) => ((V3l[])a).BackMappedCopy(i, m, c) }, { typeof(V3f[]), (a,i,m,c) => ((V3f[])a).BackMappedCopy(i, m, c) }, { typeof(V3d[]), (a,i,m,c) => ((V3d[])a).BackMappedCopy(i, m, c) }, { typeof(V4i[]), (a,i,m,c) => ((V4i[])a).BackMappedCopy(i, m, c) }, { typeof(V4l[]), (a,i,m,c) => ((V4l[])a).BackMappedCopy(i, m, c) }, { typeof(V4f[]), (a,i,m,c) => ((V4f[])a).BackMappedCopy(i, m, c) }, { typeof(V4d[]), (a,i,m,c) => ((V4d[])a).BackMappedCopy(i, m, c) }, }; public static Array BackMappedCopy( this Array source, int[] indexArray, int[] backMap, int count = 0) { if (BackMappedIndexedCopyFunMap.TryGetValue(source.GetType(), out Func fun)) return fun(source, indexArray, backMap, count); return null; } private static readonly Dictionary> BackMappedCopyToFunMap = new Dictionary> { { typeof(byte[]), (s,t,m,o) => ((byte[])s).BackMappedCopyTo((byte[])t,m,o) }, { typeof(sbyte[]), (s,t,m,o) => ((sbyte[])s).BackMappedCopyTo((sbyte[])t,m,o) }, { typeof(short[]), (s,t,m,o) => ((short[])s).BackMappedCopyTo((short[])t,m,o) }, { typeof(ushort[]), (s,t,m,o) => ((ushort[])s).BackMappedCopyTo((ushort[])t,m,o) }, { typeof(int[]), (s,t,m,o) => ((int[])s).BackMappedCopyTo((int[])t,m,o) }, { typeof(uint[]), (s,t,m,o) => ((uint[])s).BackMappedCopyTo((uint[])t,m,o) }, { typeof(long[]), (s,t,m,o) => ((long[])s).BackMappedCopyTo((long[])t,m,o) }, { typeof(ulong[]), (s,t,m,o) => ((ulong[])s).BackMappedCopyTo((ulong[])t,m,o) }, { typeof(float[]), (s,t,m,o) => ((float[])s).BackMappedCopyTo((float[])t,m,o) }, { typeof(double[]), (s,t,m,o) => ((double[])s).BackMappedCopyTo((double[])t,m,o) }, { typeof(C3b[]), (s,t,m,o) => ((C3b[])s).BackMappedCopyTo((C3b[])t,m,o) }, { typeof(C3us[]), (s,t,m,o) => ((C3us[])s).BackMappedCopyTo((C3us[])t,m,o) }, { typeof(C3ui[]), (s,t,m,o) => ((C3ui[])s).BackMappedCopyTo((C3ui[])t,m,o) }, { typeof(C3f[]), (s,t,m,o) => ((C3f[])s).BackMappedCopyTo((C3f[])t,m,o) }, { typeof(C3d[]), (s,t,m,o) => ((C3d[])s).BackMappedCopyTo((C3d[])t,m,o) }, { typeof(C4b[]), (s,t,m,o) => ((C4b[])s).BackMappedCopyTo((C4b[])t,m,o) }, { typeof(C4us[]), (s,t,m,o) => ((C4us[])s).BackMappedCopyTo((C4us[])t,m,o) }, { typeof(C4ui[]), (s,t,m,o) => ((C4ui[])s).BackMappedCopyTo((C4ui[])t,m,o) }, { typeof(C4f[]), (s,t,m,o) => ((C4f[])s).BackMappedCopyTo((C4f[])t,m,o) }, { typeof(C4d[]), (s,t,m,o) => ((C4d[])s).BackMappedCopyTo((C4d[])t,m,o) }, { typeof(V2i[]), (s,t,m,o) => ((V2i[])s).BackMappedCopyTo((V2i[])t,m,o) }, { typeof(V2l[]), (s,t,m,o) => ((V2l[])s).BackMappedCopyTo((V2l[])t,m,o) }, { typeof(V2f[]), (s,t,m,o) => ((V2f[])s).BackMappedCopyTo((V2f[])t,m,o) }, { typeof(V2d[]), (s,t,m,o) => ((V2d[])s).BackMappedCopyTo((V2d[])t,m,o) }, { typeof(V3i[]), (s,t,m,o) => ((V3i[])s).BackMappedCopyTo((V3i[])t,m,o) }, { typeof(V3l[]), (s,t,m,o) => ((V3l[])s).BackMappedCopyTo((V3l[])t,m,o) }, { typeof(V3f[]), (s,t,m,o) => ((V3f[])s).BackMappedCopyTo((V3f[])t,m,o) }, { typeof(V3d[]), (s,t,m,o) => ((V3d[])s).BackMappedCopyTo((V3d[])t,m,o) }, { typeof(V4i[]), (s,t,m,o) => ((V4i[])s).BackMappedCopyTo((V4i[])t,m,o) }, { typeof(V4l[]), (s,t,m,o) => ((V4l[])s).BackMappedCopyTo((V4l[])t,m,o) }, { typeof(V4f[]), (s,t,m,o) => ((V4f[])s).BackMappedCopyTo((V4f[])t,m,o) }, { typeof(V4d[]), (s,t,m,o) => ((V4d[])s).BackMappedCopyTo((V4d[])t,m,o) }, }; public static Array BackMappedCopyTo( this Array source, int[] backwardMap, Array target, int offset) { BackMappedCopyToFunMap[source.GetType()]( source, target, backwardMap, offset); return target; } private static readonly Dictionary> BackMappedGroupCopyToFunMap = new Dictionary> { { typeof(byte[]), (s,t,c,b,f,o) => ((byte[])s).BackMappedGroupCopyTo(b, c, f, (byte[])t, o) }, { typeof(sbyte[]), (s,t,c,b,f,o) => ((sbyte[])s).BackMappedGroupCopyTo(b, c, f, (sbyte[])t, o) }, { typeof(short[]), (s,t,c,b,f,o) => ((short[])s).BackMappedGroupCopyTo(b, c, f, (short[])t, o) }, { typeof(ushort[]), (s,t,c,b,f,o) => ((ushort[])s).BackMappedGroupCopyTo(b, c, f, (ushort[])t, o) }, { typeof(int[]), (s,t,c,b,f,o) => ((int[])s).BackMappedGroupCopyTo(b, c, f, (int[])t, o) }, { typeof(uint[]), (s,t,c,b,f,o) => ((uint[])s).BackMappedGroupCopyTo(b, c, f, (uint[])t, o) }, { typeof(long[]), (s,t,c,b,f,o) => ((long[])s).BackMappedGroupCopyTo(b, c, f, (long[])t, o) }, { typeof(ulong[]), (s,t,c,b,f,o) => ((ulong[])s).BackMappedGroupCopyTo(b, c, f, (ulong[])t, o) }, { typeof(float[]), (s,t,c,b,f,o) => ((float[])s).BackMappedGroupCopyTo(b, c, f, (float[])t, o) }, { typeof(double[]), (s,t,c,b,f,o) => ((double[])s).BackMappedGroupCopyTo(b, c, f, (double[])t, o) }, }; public static void BackMappedGroupCopyTo(this Array source, int[] faceBackMap, int faceCount, int[] fia, Array target, int offset) { BackMappedGroupCopyToFunMap[source.GetType()] (source, target, faceCount, faceBackMap, fia, offset); } private static readonly Dictionary> SwapFunMap = new Dictionary> { { typeof(byte[]), (a, i, j) => ((byte[])a).Swap(i, j) }, { typeof(sbyte[]), (a, i, j) => ((sbyte[])a).Swap(i, j) }, { typeof(short[]), (a, i, j) => ((short[])a).Swap(i, j) }, { typeof(ushort[]), (a, i, j) => ((ushort[])a).Swap(i, j) }, { typeof(int[]), (a, i, j) => ((int[])a).Swap(i, j) }, { typeof(uint[]), (a, i, j) => ((uint[])a).Swap(i, j) }, { typeof(long[]), (a, i, j) => ((long[])a).Swap(i, j) }, { typeof(ulong[]), (a, i, j) => ((ulong[])a).Swap(i, j) }, { typeof(float[]), (a, i, j) => ((float[])a).Swap(i, j) }, { typeof(double[]), (a, i, j) => ((double[])a).Swap(i, j) }, { typeof(C3b[]), (a, i, j) => ((C3b[])a).Swap(i, j) }, { typeof(C3us[]), (a, i, j) => ((C3us[])a).Swap(i, j) }, { typeof(C3ui[]), (a, i, j) => ((C3ui[])a).Swap(i, j) }, { typeof(C3f[]), (a, i, j) => ((C3f[])a).Swap(i, j) }, { typeof(C3d[]), (a, i, j) => ((C3d[])a).Swap(i, j) }, { typeof(C4b[]), (a, i, j) => ((C4b[])a).Swap(i, j) }, { typeof(C4us[]), (a, i, j) => ((C4us[])a).Swap(i, j) }, { typeof(C4ui[]), (a, i, j) => ((C4ui[])a).Swap(i, j) }, { typeof(C4f[]), (a, i, j) => ((C4f[])a).Swap(i, j) }, { typeof(C4d[]), (a, i, j) => ((C4d[])a).Swap(i, j) }, { typeof(V2i[]), (a, i, j) => ((V2i[])a).Swap(i, j) }, { typeof(V2l[]), (a, i, j) => ((V2l[])a).Swap(i, j) }, { typeof(V2f[]), (a, i, j) => ((V2f[])a).Swap(i, j) }, { typeof(V2d[]), (a, i, j) => ((V2d[])a).Swap(i, j) }, { typeof(V3i[]), (a, i, j) => ((V3i[])a).Swap(i, j) }, { typeof(V3l[]), (a, i, j) => ((V3l[])a).Swap(i, j) }, { typeof(V3f[]), (a, i, j) => ((V3f[])a).Swap(i, j) }, { typeof(V3d[]), (a, i, j) => ((V3d[])a).Swap(i, j) }, { typeof(V4i[]), (a, i, j) => ((V4i[])a).Swap(i, j) }, { typeof(V4l[]), (a, i, j) => ((V4l[])a).Swap(i, j) }, { typeof(V4f[]), (a, i, j) => ((V4f[])a).Swap(i, j) }, { typeof(V4d[]), (a, i, j) => ((V4d[])a).Swap(i, j) }, }; public static void Swap(this Array array, long i, long j) { SwapFunMap[array.GetType()](array, i, j); } private static readonly Dictionary, Array>> GroupReversedCopyMap = new Dictionary, Array>> { { typeof(byte[]), (a, g, c, r) => ((byte[])a).GroupReversedCopy(g, c, r) }, { typeof(sbyte[]), (a, g, c, r) => ((sbyte[])a).GroupReversedCopy(g, c, r) }, { typeof(short[]), (a, g, c, r) => ((short[])a).GroupReversedCopy(g, c, r) }, { typeof(ushort[]), (a, g, c, r) => ((ushort[])a).GroupReversedCopy(g, c, r) }, { typeof(int[]), (a, g, c, r) => ((int[])a).GroupReversedCopy(g, c, r) }, { typeof(uint[]), (a, g, c, r) => ((uint[])a).GroupReversedCopy(g, c, r) }, { typeof(long[]), (a, g, c, r) => ((long[])a).GroupReversedCopy(g, c, r) }, { typeof(ulong[]), (a, g, c, r) => ((ulong[])a).GroupReversedCopy(g, c, r) }, { typeof(float[]), (a, g, c, r) => ((float[])a).GroupReversedCopy(g, c, r) }, { typeof(double[]), (a, g, c, r) => ((double[])a).GroupReversedCopy(g, c, r) }, { typeof(C3b[]), (a, g, c, r) => ((C3b[])a).GroupReversedCopy(g, c, r) }, { typeof(C3us[]), (a, g, c, r) => ((C3us[])a).GroupReversedCopy(g, c, r) }, { typeof(C3ui[]), (a, g, c, r) => ((C3ui[])a).GroupReversedCopy(g, c, r) }, { typeof(C3f[]), (a, g, c, r) => ((C3f[])a).GroupReversedCopy(g, c, r) }, { typeof(C3d[]), (a, g, c, r) => ((C3d[])a).GroupReversedCopy(g, c, r) }, { typeof(C4b[]), (a, g, c, r) => ((C4b[])a).GroupReversedCopy(g, c, r) }, { typeof(C4us[]), (a, g, c, r) => ((C4us[])a).GroupReversedCopy(g, c, r) }, { typeof(C4ui[]), (a, g, c, r) => ((C4ui[])a).GroupReversedCopy(g, c, r) }, { typeof(C4f[]), (a, g, c, r) => ((C4f[])a).GroupReversedCopy(g, c, r) }, { typeof(C4d[]), (a, g, c, r) => ((C4d[])a).GroupReversedCopy(g, c, r) }, { typeof(V2i[]), (a, g, c, r) => ((V2i[])a).GroupReversedCopy(g, c, r) }, { typeof(V2l[]), (a, g, c, r) => ((V2l[])a).GroupReversedCopy(g, c, r) }, { typeof(V2f[]), (a, g, c, r) => ((V2f[])a).GroupReversedCopy(g, c, r) }, { typeof(V2d[]), (a, g, c, r) => ((V2d[])a).GroupReversedCopy(g, c, r) }, { typeof(V3i[]), (a, g, c, r) => ((V3i[])a).GroupReversedCopy(g, c, r) }, { typeof(V3l[]), (a, g, c, r) => ((V3l[])a).GroupReversedCopy(g, c, r) }, { typeof(V3f[]), (a, g, c, r) => ((V3f[])a).GroupReversedCopy(g, c, r) }, { typeof(V3d[]), (a, g, c, r) => ((V3d[])a).GroupReversedCopy(g, c, r) }, { typeof(V4i[]), (a, g, c, r) => ((V4i[])a).GroupReversedCopy(g, c, r) }, { typeof(V4l[]), (a, g, c, r) => ((V4l[])a).GroupReversedCopy(g, c, r) }, { typeof(V4f[]), (a, g, c, r) => ((V4f[])a).GroupReversedCopy(g, c, r) }, { typeof(V4d[]), (a, g, c, r) => ((V4d[])a).GroupReversedCopy(g, c, r) }, }; public static Array GroupReversedCopy( this Array array, int[] groupArray, int groupCount, Func reverseMap) { return GroupReversedCopyMap[array.GetType()]( array, groupArray, groupCount, reverseMap); } private static readonly Dictionary>> ReverseGroupsMap = new Dictionary>> { { typeof(byte[]), (a, g, c, r) => ((byte[])a).ReverseGroups(g, c, r) }, { typeof(sbyte[]), (a, g, c, r) => ((sbyte[])a).ReverseGroups(g, c, r) }, { typeof(short[]), (a, g, c, r) => ((short[])a).ReverseGroups(g, c, r) }, { typeof(ushort[]), (a, g, c, r) => ((ushort[])a).ReverseGroups(g, c, r) }, { typeof(int[]), (a, g, c, r) => ((int[])a).ReverseGroups(g, c, r) }, { typeof(uint[]), (a, g, c, r) => ((uint[])a).ReverseGroups(g, c, r) }, { typeof(long[]), (a, g, c, r) => ((long[])a).ReverseGroups(g, c, r) }, { typeof(ulong[]), (a, g, c, r) => ((ulong[])a).ReverseGroups(g, c, r) }, { typeof(float[]), (a, g, c, r) => ((float[])a).ReverseGroups(g, c, r) }, { typeof(double[]), (a, g, c, r) => ((double[])a).ReverseGroups(g, c, r) }, { typeof(C3b[]), (a, g, c, r) => ((C3b[])a).ReverseGroups(g, c, r) }, { typeof(C3us[]), (a, g, c, r) => ((C3us[])a).ReverseGroups(g, c, r) }, { typeof(C3ui[]), (a, g, c, r) => ((C3ui[])a).ReverseGroups(g, c, r) }, { typeof(C3f[]), (a, g, c, r) => ((C3f[])a).ReverseGroups(g, c, r) }, { typeof(C3d[]), (a, g, c, r) => ((C3d[])a).ReverseGroups(g, c, r) }, { typeof(C4b[]), (a, g, c, r) => ((C4b[])a).ReverseGroups(g, c, r) }, { typeof(C4us[]), (a, g, c, r) => ((C4us[])a).ReverseGroups(g, c, r) }, { typeof(C4ui[]), (a, g, c, r) => ((C4ui[])a).ReverseGroups(g, c, r) }, { typeof(C4f[]), (a, g, c, r) => ((C4f[])a).ReverseGroups(g, c, r) }, { typeof(C4d[]), (a, g, c, r) => ((C4d[])a).ReverseGroups(g, c, r) }, { typeof(V2i[]), (a, g, c, r) => ((V2i[])a).ReverseGroups(g, c, r) }, { typeof(V2l[]), (a, g, c, r) => ((V2l[])a).ReverseGroups(g, c, r) }, { typeof(V2f[]), (a, g, c, r) => ((V2f[])a).ReverseGroups(g, c, r) }, { typeof(V2d[]), (a, g, c, r) => ((V2d[])a).ReverseGroups(g, c, r) }, { typeof(V3i[]), (a, g, c, r) => ((V3i[])a).ReverseGroups(g, c, r) }, { typeof(V3l[]), (a, g, c, r) => ((V3l[])a).ReverseGroups(g, c, r) }, { typeof(V3f[]), (a, g, c, r) => ((V3f[])a).ReverseGroups(g, c, r) }, { typeof(V3d[]), (a, g, c, r) => ((V3d[])a).ReverseGroups(g, c, r) }, { typeof(V4i[]), (a, g, c, r) => ((V4i[])a).ReverseGroups(g, c, r) }, { typeof(V4l[]), (a, g, c, r) => ((V4l[])a).ReverseGroups(g, c, r) }, { typeof(V4f[]), (a, g, c, r) => ((V4f[])a).ReverseGroups(g, c, r) }, { typeof(V4d[]), (a, g, c, r) => ((V4d[])a).ReverseGroups(g, c, r) }, }; public static void ReverseGroups( this Array array, int[] groupArray, int groupCount, Func reverseMap) { ReverseGroupsMap[array.GetType()]( array, groupArray, groupCount, reverseMap); } /// /// Apply a supplied function to each element of an array, with /// supplied conversion functions if the array is of a different /// type. /// public static Array Apply( this Array array, Func fun, Func funT1ofT0, Func funT0ofT1) { int length = array.Length; if (array is T0[] t0a) { for (int i = 0; i < length; i++) t0a[i] = funT0ofT1(fun(funT1ofT0(t0a[i]))); return array; } if (array is T1[] t1a) { for (int i = 0; i < length; i++) t1a[i] = fun(t1a[i]); return array; } throw new InvalidOperationException(); } public static IEnumerable Elements( this Array array, Func convert) { if (array is T0[] t0a) { foreach (var e in t0a) yield return convert(e); yield break; } if (array is T1[] t1a) { foreach (var e in t1a) yield return e; yield break; } } public static T1[] CopyAndConvert( this Array array, Func convert) { int length = array.Length; var result = new T1[length]; if (array is T0[] t0a) { for (int i = 0; i < length; i++) result[i] = convert(t0a[i]); return result; } if (array is T1[] t1a) { for (int i = 0; i < length; i++) result[i] = t1a[i]; return result; } throw new InvalidOperationException(); } public static Tr[] CopyAndConvert( this Array array, Func convert, Func fun) { int length = array.Length; var result = new Tr[length]; if (array is T0[] t0a) { for (int i = 0; i < length; i++) result[i] = fun(convert(t0a[i])); return result; } if (array is T1[] t1a) { for (int i = 0; i < length; i++) result[i] = fun(t1a[i]); return result; } throw new InvalidOperationException(); } #endregion } } ================================================ FILE: src/Aardvark.Base/Extensions/SequenceExtensions_auto.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Aardvark.Base { public static partial class SequenceExtensions { #region byte Sequences #region Extreme Values /// /// Finds the smallest element in a sequence, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or maxValue if no element is smaller. /// The default value of minValue is byte.MaxValue. /// /// A sequence of values to determine the minimum value of. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence is null. public static byte Min(this IEnumerable sequence, byte minValue = byte.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value < minValue) minValue = value; return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is byte.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence or selector is null. public static byte MinValue(this IEnumerable sequence, Func element_valueSelector, byte minValue = byte.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is byte.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is smaller than the initial min value. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static byte MinValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq minElement, byte minValue = byte.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is byte.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static TSeq MinElement(this IEnumerable sequence, Func element_valueSelector, byte minValue = byte.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and return this value. /// public static byte MinValue(this TSeq[] sequence, Func element_valueSelector, byte minValue = byte.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static byte MinValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq minElement, byte minValue = byte.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and returns the /// corresponding element. /// public static TSeq MinElement(this TSeq[] sequence, Func element_valueSelector, byte minValue = byte.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Finds the largest element in a sequence, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or minValue if no element is larger. /// The default value of maxValue is byte.MinValue. /// /// A sequence of values to determine the maximum value of. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence is null. public static byte Max(this IEnumerable sequence, byte maxValue = byte.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value > maxValue) maxValue = value; return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is byte.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence or selector is null. public static byte MaxValue(this IEnumerable sequence, Func element_valueSelector, byte maxValue = byte.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is byte.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is larger than the initial max value. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static byte MaxValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq maxElement, byte maxValue = byte.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is byte.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static TSeq MaxElement(this IEnumerable sequence, Func element_valueSelector, byte maxValue = byte.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and return this value. /// public static byte MaxValue(this TSeq[] sequence, Func element_valueSelector, byte maxValue = byte.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static byte MaxValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq maxElement, byte maxValue = byte.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and returns the /// corresponding element. /// public static TSeq MaxElement(this TSeq[] sequence, Func element_valueSelector, byte maxValue = byte.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } #endregion #region Sorting /// /// Merge an ascendingly sorted byte array with another ascendingly /// sorted byte array resulting in a single ascendingly sorted /// byte array. /// public static byte[] MergeAscending(this byte[] a0, byte[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new byte[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] < a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an ascendingly sorted byte array with another ascendingly /// sorted byte array resulting in a single ascendingly sorted /// byte array. /// public static TSeq[] MergeAscending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) < element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted byte array with another descendingly /// sorted byte array resulting in a single descendingly sorted /// byte array. /// public static byte[] MergeDescending(this byte[] a0, byte[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new byte[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] > a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted byte array with another descendingly /// sorted byte array resulting in a single descendingly sorted /// byte array. /// public static TSeq[] MergeDescending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) > element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } #endregion #endregion #region sbyte Sequences #region Extreme Values /// /// Finds the smallest element in a sequence, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or maxValue if no element is smaller. /// The default value of minValue is sbyte.MaxValue. /// /// A sequence of values to determine the minimum value of. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence is null. public static sbyte Min(this IEnumerable sequence, sbyte minValue = sbyte.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value < minValue) minValue = value; return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is sbyte.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence or selector is null. public static sbyte MinValue(this IEnumerable sequence, Func element_valueSelector, sbyte minValue = sbyte.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is sbyte.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is smaller than the initial min value. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static sbyte MinValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq minElement, sbyte minValue = sbyte.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is sbyte.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static TSeq MinElement(this IEnumerable sequence, Func element_valueSelector, sbyte minValue = sbyte.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and return this value. /// public static sbyte MinValue(this TSeq[] sequence, Func element_valueSelector, sbyte minValue = sbyte.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static sbyte MinValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq minElement, sbyte minValue = sbyte.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and returns the /// corresponding element. /// public static TSeq MinElement(this TSeq[] sequence, Func element_valueSelector, sbyte minValue = sbyte.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Finds the largest element in a sequence, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or minValue if no element is larger. /// The default value of maxValue is sbyte.MinValue. /// /// A sequence of values to determine the maximum value of. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence is null. public static sbyte Max(this IEnumerable sequence, sbyte maxValue = sbyte.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value > maxValue) maxValue = value; return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is sbyte.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence or selector is null. public static sbyte MaxValue(this IEnumerable sequence, Func element_valueSelector, sbyte maxValue = sbyte.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is sbyte.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is larger than the initial max value. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static sbyte MaxValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq maxElement, sbyte maxValue = sbyte.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is sbyte.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static TSeq MaxElement(this IEnumerable sequence, Func element_valueSelector, sbyte maxValue = sbyte.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and return this value. /// public static sbyte MaxValue(this TSeq[] sequence, Func element_valueSelector, sbyte maxValue = sbyte.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static sbyte MaxValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq maxElement, sbyte maxValue = sbyte.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and returns the /// corresponding element. /// public static TSeq MaxElement(this TSeq[] sequence, Func element_valueSelector, sbyte maxValue = sbyte.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } #endregion #region Sorting /// /// Merge an ascendingly sorted sbyte array with another ascendingly /// sorted sbyte array resulting in a single ascendingly sorted /// sbyte array. /// public static sbyte[] MergeAscending(this sbyte[] a0, sbyte[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new sbyte[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] < a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an ascendingly sorted sbyte array with another ascendingly /// sorted sbyte array resulting in a single ascendingly sorted /// sbyte array. /// public static TSeq[] MergeAscending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) < element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted sbyte array with another descendingly /// sorted sbyte array resulting in a single descendingly sorted /// sbyte array. /// public static sbyte[] MergeDescending(this sbyte[] a0, sbyte[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new sbyte[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] > a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted sbyte array with another descendingly /// sorted sbyte array resulting in a single descendingly sorted /// sbyte array. /// public static TSeq[] MergeDescending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) > element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } #endregion #endregion #region short Sequences #region Extreme Values /// /// Finds the smallest element in a sequence, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or maxValue if no element is smaller. /// The default value of minValue is short.MaxValue. /// /// A sequence of values to determine the minimum value of. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence is null. public static short Min(this IEnumerable sequence, short minValue = short.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value < minValue) minValue = value; return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is short.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence or selector is null. public static short MinValue(this IEnumerable sequence, Func element_valueSelector, short minValue = short.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is short.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is smaller than the initial min value. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static short MinValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq minElement, short minValue = short.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is short.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static TSeq MinElement(this IEnumerable sequence, Func element_valueSelector, short minValue = short.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and return this value. /// public static short MinValue(this TSeq[] sequence, Func element_valueSelector, short minValue = short.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static short MinValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq minElement, short minValue = short.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and returns the /// corresponding element. /// public static TSeq MinElement(this TSeq[] sequence, Func element_valueSelector, short minValue = short.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Finds the largest element in a sequence, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or minValue if no element is larger. /// The default value of maxValue is short.MinValue. /// /// A sequence of values to determine the maximum value of. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence is null. public static short Max(this IEnumerable sequence, short maxValue = short.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value > maxValue) maxValue = value; return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is short.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence or selector is null. public static short MaxValue(this IEnumerable sequence, Func element_valueSelector, short maxValue = short.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is short.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is larger than the initial max value. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static short MaxValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq maxElement, short maxValue = short.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is short.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static TSeq MaxElement(this IEnumerable sequence, Func element_valueSelector, short maxValue = short.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and return this value. /// public static short MaxValue(this TSeq[] sequence, Func element_valueSelector, short maxValue = short.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static short MaxValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq maxElement, short maxValue = short.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and returns the /// corresponding element. /// public static TSeq MaxElement(this TSeq[] sequence, Func element_valueSelector, short maxValue = short.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } #endregion #region Sorting /// /// Merge an ascendingly sorted short array with another ascendingly /// sorted short array resulting in a single ascendingly sorted /// short array. /// public static short[] MergeAscending(this short[] a0, short[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new short[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] < a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an ascendingly sorted short array with another ascendingly /// sorted short array resulting in a single ascendingly sorted /// short array. /// public static TSeq[] MergeAscending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) < element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted short array with another descendingly /// sorted short array resulting in a single descendingly sorted /// short array. /// public static short[] MergeDescending(this short[] a0, short[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new short[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] > a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted short array with another descendingly /// sorted short array resulting in a single descendingly sorted /// short array. /// public static TSeq[] MergeDescending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) > element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } #endregion #endregion #region ushort Sequences #region Extreme Values /// /// Finds the smallest element in a sequence, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or maxValue if no element is smaller. /// The default value of minValue is ushort.MaxValue. /// /// A sequence of values to determine the minimum value of. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence is null. public static ushort Min(this IEnumerable sequence, ushort minValue = ushort.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value < minValue) minValue = value; return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is ushort.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence or selector is null. public static ushort MinValue(this IEnumerable sequence, Func element_valueSelector, ushort minValue = ushort.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is ushort.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is smaller than the initial min value. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static ushort MinValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq minElement, ushort minValue = ushort.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is ushort.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static TSeq MinElement(this IEnumerable sequence, Func element_valueSelector, ushort minValue = ushort.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and return this value. /// public static ushort MinValue(this TSeq[] sequence, Func element_valueSelector, ushort minValue = ushort.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static ushort MinValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq minElement, ushort minValue = ushort.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and returns the /// corresponding element. /// public static TSeq MinElement(this TSeq[] sequence, Func element_valueSelector, ushort minValue = ushort.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Finds the largest element in a sequence, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or minValue if no element is larger. /// The default value of maxValue is ushort.MinValue. /// /// A sequence of values to determine the maximum value of. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence is null. public static ushort Max(this IEnumerable sequence, ushort maxValue = ushort.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value > maxValue) maxValue = value; return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is ushort.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence or selector is null. public static ushort MaxValue(this IEnumerable sequence, Func element_valueSelector, ushort maxValue = ushort.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is ushort.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is larger than the initial max value. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static ushort MaxValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq maxElement, ushort maxValue = ushort.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is ushort.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static TSeq MaxElement(this IEnumerable sequence, Func element_valueSelector, ushort maxValue = ushort.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and return this value. /// public static ushort MaxValue(this TSeq[] sequence, Func element_valueSelector, ushort maxValue = ushort.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static ushort MaxValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq maxElement, ushort maxValue = ushort.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and returns the /// corresponding element. /// public static TSeq MaxElement(this TSeq[] sequence, Func element_valueSelector, ushort maxValue = ushort.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } #endregion #region Sorting /// /// Merge an ascendingly sorted ushort array with another ascendingly /// sorted ushort array resulting in a single ascendingly sorted /// ushort array. /// public static ushort[] MergeAscending(this ushort[] a0, ushort[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new ushort[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] < a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an ascendingly sorted ushort array with another ascendingly /// sorted ushort array resulting in a single ascendingly sorted /// ushort array. /// public static TSeq[] MergeAscending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) < element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted ushort array with another descendingly /// sorted ushort array resulting in a single descendingly sorted /// ushort array. /// public static ushort[] MergeDescending(this ushort[] a0, ushort[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new ushort[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] > a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted ushort array with another descendingly /// sorted ushort array resulting in a single descendingly sorted /// ushort array. /// public static TSeq[] MergeDescending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) > element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } #endregion #endregion #region int Sequences #region Extreme Values /// /// Finds the smallest element in a sequence, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or maxValue if no element is smaller. /// The default value of minValue is int.MaxValue. /// /// A sequence of values to determine the minimum value of. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence is null. public static int Min(this IEnumerable sequence, int minValue = int.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value < minValue) minValue = value; return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is int.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence or selector is null. public static int MinValue(this IEnumerable sequence, Func element_valueSelector, int minValue = int.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is int.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is smaller than the initial min value. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static int MinValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq minElement, int minValue = int.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is int.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static TSeq MinElement(this IEnumerable sequence, Func element_valueSelector, int minValue = int.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and return this value. /// public static int MinValue(this TSeq[] sequence, Func element_valueSelector, int minValue = int.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static int MinValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq minElement, int minValue = int.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and returns the /// corresponding element. /// public static TSeq MinElement(this TSeq[] sequence, Func element_valueSelector, int minValue = int.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Finds the largest element in a sequence, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or minValue if no element is larger. /// The default value of maxValue is int.MinValue. /// /// A sequence of values to determine the maximum value of. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence is null. public static int Max(this IEnumerable sequence, int maxValue = int.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value > maxValue) maxValue = value; return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is int.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence or selector is null. public static int MaxValue(this IEnumerable sequence, Func element_valueSelector, int maxValue = int.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is int.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is larger than the initial max value. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static int MaxValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq maxElement, int maxValue = int.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is int.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static TSeq MaxElement(this IEnumerable sequence, Func element_valueSelector, int maxValue = int.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and return this value. /// public static int MaxValue(this TSeq[] sequence, Func element_valueSelector, int maxValue = int.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static int MaxValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq maxElement, int maxValue = int.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and returns the /// corresponding element. /// public static TSeq MaxElement(this TSeq[] sequence, Func element_valueSelector, int maxValue = int.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } #endregion #region Sorting /// /// Merge an ascendingly sorted int array with another ascendingly /// sorted int array resulting in a single ascendingly sorted /// int array. /// public static int[] MergeAscending(this int[] a0, int[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new int[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] < a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an ascendingly sorted int array with another ascendingly /// sorted int array resulting in a single ascendingly sorted /// int array. /// public static TSeq[] MergeAscending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) < element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted int array with another descendingly /// sorted int array resulting in a single descendingly sorted /// int array. /// public static int[] MergeDescending(this int[] a0, int[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new int[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] > a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted int array with another descendingly /// sorted int array resulting in a single descendingly sorted /// int array. /// public static TSeq[] MergeDescending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) > element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } #endregion #endregion #region uint Sequences #region Extreme Values /// /// Finds the smallest element in a sequence, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or maxValue if no element is smaller. /// The default value of minValue is uint.MaxValue. /// /// A sequence of values to determine the minimum value of. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence is null. public static uint Min(this IEnumerable sequence, uint minValue = uint.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value < minValue) minValue = value; return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is uint.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence or selector is null. public static uint MinValue(this IEnumerable sequence, Func element_valueSelector, uint minValue = uint.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is uint.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is smaller than the initial min value. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static uint MinValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq minElement, uint minValue = uint.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is uint.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static TSeq MinElement(this IEnumerable sequence, Func element_valueSelector, uint minValue = uint.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and return this value. /// public static uint MinValue(this TSeq[] sequence, Func element_valueSelector, uint minValue = uint.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static uint MinValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq minElement, uint minValue = uint.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and returns the /// corresponding element. /// public static TSeq MinElement(this TSeq[] sequence, Func element_valueSelector, uint minValue = uint.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Finds the largest element in a sequence, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or minValue if no element is larger. /// The default value of maxValue is uint.MinValue. /// /// A sequence of values to determine the maximum value of. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence is null. public static uint Max(this IEnumerable sequence, uint maxValue = uint.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value > maxValue) maxValue = value; return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is uint.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence or selector is null. public static uint MaxValue(this IEnumerable sequence, Func element_valueSelector, uint maxValue = uint.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is uint.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is larger than the initial max value. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static uint MaxValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq maxElement, uint maxValue = uint.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is uint.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static TSeq MaxElement(this IEnumerable sequence, Func element_valueSelector, uint maxValue = uint.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and return this value. /// public static uint MaxValue(this TSeq[] sequence, Func element_valueSelector, uint maxValue = uint.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static uint MaxValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq maxElement, uint maxValue = uint.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and returns the /// corresponding element. /// public static TSeq MaxElement(this TSeq[] sequence, Func element_valueSelector, uint maxValue = uint.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } #endregion #region Sorting /// /// Merge an ascendingly sorted uint array with another ascendingly /// sorted uint array resulting in a single ascendingly sorted /// uint array. /// public static uint[] MergeAscending(this uint[] a0, uint[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new uint[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] < a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an ascendingly sorted uint array with another ascendingly /// sorted uint array resulting in a single ascendingly sorted /// uint array. /// public static TSeq[] MergeAscending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) < element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted uint array with another descendingly /// sorted uint array resulting in a single descendingly sorted /// uint array. /// public static uint[] MergeDescending(this uint[] a0, uint[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new uint[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] > a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted uint array with another descendingly /// sorted uint array resulting in a single descendingly sorted /// uint array. /// public static TSeq[] MergeDescending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) > element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } #endregion #endregion #region long Sequences #region Extreme Values /// /// Finds the smallest element in a sequence, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or maxValue if no element is smaller. /// The default value of minValue is long.MaxValue. /// /// A sequence of values to determine the minimum value of. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence is null. public static long Min(this IEnumerable sequence, long minValue = long.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value < minValue) minValue = value; return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is long.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence or selector is null. public static long MinValue(this IEnumerable sequence, Func element_valueSelector, long minValue = long.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is long.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is smaller than the initial min value. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static long MinValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq minElement, long minValue = long.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is long.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static TSeq MinElement(this IEnumerable sequence, Func element_valueSelector, long minValue = long.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and return this value. /// public static long MinValue(this TSeq[] sequence, Func element_valueSelector, long minValue = long.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static long MinValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq minElement, long minValue = long.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and returns the /// corresponding element. /// public static TSeq MinElement(this TSeq[] sequence, Func element_valueSelector, long minValue = long.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Finds the largest element in a sequence, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or minValue if no element is larger. /// The default value of maxValue is long.MinValue. /// /// A sequence of values to determine the maximum value of. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence is null. public static long Max(this IEnumerable sequence, long maxValue = long.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value > maxValue) maxValue = value; return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is long.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence or selector is null. public static long MaxValue(this IEnumerable sequence, Func element_valueSelector, long maxValue = long.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is long.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is larger than the initial max value. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static long MaxValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq maxElement, long maxValue = long.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is long.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static TSeq MaxElement(this IEnumerable sequence, Func element_valueSelector, long maxValue = long.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and return this value. /// public static long MaxValue(this TSeq[] sequence, Func element_valueSelector, long maxValue = long.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static long MaxValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq maxElement, long maxValue = long.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and returns the /// corresponding element. /// public static TSeq MaxElement(this TSeq[] sequence, Func element_valueSelector, long maxValue = long.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } #endregion #region Sorting /// /// Merge an ascendingly sorted long array with another ascendingly /// sorted long array resulting in a single ascendingly sorted /// long array. /// public static long[] MergeAscending(this long[] a0, long[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new long[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] < a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an ascendingly sorted long array with another ascendingly /// sorted long array resulting in a single ascendingly sorted /// long array. /// public static TSeq[] MergeAscending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) < element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted long array with another descendingly /// sorted long array resulting in a single descendingly sorted /// long array. /// public static long[] MergeDescending(this long[] a0, long[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new long[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] > a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted long array with another descendingly /// sorted long array resulting in a single descendingly sorted /// long array. /// public static TSeq[] MergeDescending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) > element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } #endregion #endregion #region ulong Sequences #region Extreme Values /// /// Finds the smallest element in a sequence, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or maxValue if no element is smaller. /// The default value of minValue is ulong.MaxValue. /// /// A sequence of values to determine the minimum value of. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence is null. public static ulong Min(this IEnumerable sequence, ulong minValue = ulong.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value < minValue) minValue = value; return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is ulong.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence or selector is null. public static ulong MinValue(this IEnumerable sequence, Func element_valueSelector, ulong minValue = ulong.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is ulong.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is smaller than the initial min value. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static ulong MinValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq minElement, ulong minValue = ulong.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is ulong.MaxValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static TSeq MinElement(this IEnumerable sequence, Func element_valueSelector, ulong minValue = ulong.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and return this value. /// public static ulong MinValue(this TSeq[] sequence, Func element_valueSelector, ulong minValue = ulong.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static ulong MinValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq minElement, ulong minValue = ulong.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and returns the /// corresponding element. /// public static TSeq MinElement(this TSeq[] sequence, Func element_valueSelector, ulong minValue = ulong.MaxValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Finds the largest element in a sequence, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or minValue if no element is larger. /// The default value of maxValue is ulong.MinValue. /// /// A sequence of values to determine the maximum value of. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence is null. public static ulong Max(this IEnumerable sequence, ulong maxValue = ulong.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value > maxValue) maxValue = value; return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is ulong.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence or selector is null. public static ulong MaxValue(this IEnumerable sequence, Func element_valueSelector, ulong maxValue = ulong.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is ulong.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is larger than the initial max value. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static ulong MaxValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq maxElement, ulong maxValue = ulong.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is ulong.MinValue. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static TSeq MaxElement(this IEnumerable sequence, Func element_valueSelector, ulong maxValue = ulong.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and return this value. /// public static ulong MaxValue(this TSeq[] sequence, Func element_valueSelector, ulong maxValue = ulong.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static ulong MaxValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq maxElement, ulong maxValue = ulong.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and returns the /// corresponding element. /// public static TSeq MaxElement(this TSeq[] sequence, Func element_valueSelector, ulong maxValue = ulong.MinValue) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } #endregion #region Sorting /// /// Merge an ascendingly sorted ulong array with another ascendingly /// sorted ulong array resulting in a single ascendingly sorted /// ulong array. /// public static ulong[] MergeAscending(this ulong[] a0, ulong[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new ulong[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] < a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an ascendingly sorted ulong array with another ascendingly /// sorted ulong array resulting in a single ascendingly sorted /// ulong array. /// public static TSeq[] MergeAscending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) < element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted ulong array with another descendingly /// sorted ulong array resulting in a single descendingly sorted /// ulong array. /// public static ulong[] MergeDescending(this ulong[] a0, ulong[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new ulong[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] > a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted ulong array with another descendingly /// sorted ulong array resulting in a single descendingly sorted /// ulong array. /// public static TSeq[] MergeDescending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) > element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } #endregion #endregion #region float Sequences #region Extreme Values /// /// Finds the smallest element in a sequence, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or maxValue if no element is smaller. /// The default value of minValue is float.PositiveInfinity. /// /// A sequence of values to determine the minimum value of. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence is null. public static float Min(this IEnumerable sequence, float minValue = float.PositiveInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value < minValue) minValue = value; return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is float.PositiveInfinity. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence or selector is null. public static float MinValue(this IEnumerable sequence, Func element_valueSelector, float minValue = float.PositiveInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is float.PositiveInfinity. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is smaller than the initial min value. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static float MinValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq minElement, float minValue = float.PositiveInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is float.PositiveInfinity. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static TSeq MinElement(this IEnumerable sequence, Func element_valueSelector, float minValue = float.PositiveInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and return this value. /// public static float MinValue(this TSeq[] sequence, Func element_valueSelector, float minValue = float.PositiveInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static float MinValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq minElement, float minValue = float.PositiveInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and returns the /// corresponding element. /// public static TSeq MinElement(this TSeq[] sequence, Func element_valueSelector, float minValue = float.PositiveInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Finds the largest element in a sequence, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or minValue if no element is larger. /// The default value of maxValue is float.NegativeInfinity. /// /// A sequence of values to determine the maximum value of. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence is null. public static float Max(this IEnumerable sequence, float maxValue = float.NegativeInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value > maxValue) maxValue = value; return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is float.NegativeInfinity. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence or selector is null. public static float MaxValue(this IEnumerable sequence, Func element_valueSelector, float maxValue = float.NegativeInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is float.NegativeInfinity. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is larger than the initial max value. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static float MaxValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq maxElement, float maxValue = float.NegativeInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is float.NegativeInfinity. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static TSeq MaxElement(this IEnumerable sequence, Func element_valueSelector, float maxValue = float.NegativeInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and return this value. /// public static float MaxValue(this TSeq[] sequence, Func element_valueSelector, float maxValue = float.NegativeInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static float MaxValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq maxElement, float maxValue = float.NegativeInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and returns the /// corresponding element. /// public static TSeq MaxElement(this TSeq[] sequence, Func element_valueSelector, float maxValue = float.NegativeInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } #endregion #region Sorting /// /// Merge an ascendingly sorted float array with another ascendingly /// sorted float array resulting in a single ascendingly sorted /// float array. /// public static float[] MergeAscending(this float[] a0, float[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new float[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] < a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an ascendingly sorted float array with another ascendingly /// sorted float array resulting in a single ascendingly sorted /// float array. /// public static TSeq[] MergeAscending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) < element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted float array with another descendingly /// sorted float array resulting in a single descendingly sorted /// float array. /// public static float[] MergeDescending(this float[] a0, float[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new float[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] > a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted float array with another descendingly /// sorted float array resulting in a single descendingly sorted /// float array. /// public static TSeq[] MergeDescending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) > element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } #endregion #endregion #region double Sequences #region Extreme Values /// /// Finds the smallest element in a sequence, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or maxValue if no element is smaller. /// The default value of minValue is double.PositiveInfinity. /// /// A sequence of values to determine the minimum value of. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence is null. public static double Min(this IEnumerable sequence, double minValue = double.PositiveInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value < minValue) minValue = value; return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is double.PositiveInfinity. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The minimum value in the sequence. /// sequence or selector is null. public static double MinValue(this IEnumerable sequence, Func element_valueSelector, double minValue = double.PositiveInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is double.PositiveInfinity. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is smaller than the initial min value. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static double MinValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq minElement, double minValue = double.PositiveInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the smallest value, that is smaller than the initially /// supplied minValue, or the first such element if there are equally small /// elements, or minValue if no element is smaller. /// The default value of minValue is double.PositiveInfinity. /// /// The type of the elements of sequence. /// A sequence of values to determine the minimum value of. /// A transform function to apply to each element. /// The initially supplied minimum value. /// The element that yielded the minimum value in the sequence. /// sequence or selector is null. public static TSeq MinElement(this IEnumerable sequence, Func element_valueSelector, double minValue = double.PositiveInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and return this value. /// public static double MinValue(this TSeq[] sequence, Func element_valueSelector, double minValue = double.PositiveInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value < minValue) minValue = value; } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static double MinValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq minElement, double minValue = double.PositiveInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the smallest value of all elements and returns the /// corresponding element. /// public static TSeq MinElement(this TSeq[] sequence, Func element_valueSelector, double minValue = double.PositiveInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var minElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value < minValue) { minValue = value; minElement = element; } } return minElement; } /// /// Finds the largest element in a sequence, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or minValue if no element is larger. /// The default value of maxValue is double.NegativeInfinity. /// /// A sequence of values to determine the maximum value of. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence is null. public static double Max(this IEnumerable sequence, double maxValue = double.NegativeInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value > maxValue) maxValue = value; return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is double.NegativeInfinity. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The maximum value in the sequence. /// sequence or selector is null. public static double MaxValue(this IEnumerable sequence, Func element_valueSelector, double maxValue = double.NegativeInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is double.NegativeInfinity. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is larger than the initial max value. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static double MaxValue(this IEnumerable sequence, Func element_valueSelector, ref TSeq maxElement, double maxValue = double.NegativeInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the largest value, that is larger than the initially /// supplied maxValue, or the first such element if there are equally large /// elements, or maxValue if no element is larger. /// The default value of maxValue is double.NegativeInfinity. /// /// The type of the elements of sequence. /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The initially supplied maximum value. /// The element that yielded the maximum value in the sequence. /// sequence or selector is null. public static TSeq MaxElement(this IEnumerable sequence, Func element_valueSelector, double maxValue = double.NegativeInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and return this value. /// public static double MaxValue(this TSeq[] sequence, Func element_valueSelector, double maxValue = double.NegativeInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value > maxValue) maxValue = value; } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static double MaxValue(this TSeq[] sequence, Func element_valueSelector, ref TSeq maxElement, double maxValue = double.NegativeInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxValue; } /// /// Invokes the value selector function on each element of a sequence, /// finds the largest value of all elements and returns the /// corresponding element. /// public static TSeq MaxElement(this TSeq[] sequence, Func element_valueSelector, double maxValue = double.NegativeInfinity) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var maxElement = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value > maxValue) { maxValue = value; maxElement = element; } } return maxElement; } #endregion #region Sorting /// /// Merge an ascendingly sorted double array with another ascendingly /// sorted double array resulting in a single ascendingly sorted /// double array. /// public static double[] MergeAscending(this double[] a0, double[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new double[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] < a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an ascendingly sorted double array with another ascendingly /// sorted double array resulting in a single ascendingly sorted /// double array. /// public static TSeq[] MergeAscending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) < element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted double array with another descendingly /// sorted double array resulting in a single descendingly sorted /// double array. /// public static double[] MergeDescending(this double[] a0, double[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new double[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0] > a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an descendingly sorted double array with another descendingly /// sorted double array resulting in a single descendingly sorted /// double array. /// public static TSeq[] MergeDescending(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0]) > element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } #endregion #endregion } } namespace Aardvark.Base.CSharp { /// /// The following extensions reside in the special namespace /// Aardvark.Base.CSharp as they mess with normal FSharp operation. /// public static partial class CSharpSequenceExtensions { #region Sequences of Tups public static IEnumerable Select( this IEnumerable> sequence, Func selector) { return sequence.Select(tup => selector(tup.E0, tup.E1)); } public static IEnumerable> Where( this IEnumerable> sequence, Func predicate) { return sequence.Where(tup => predicate(tup.E0, tup.E1)); } public static void ForEach(this Tup[] array, Action act) { for (int i = 0; i < array.Length; i++) { var tup = array[i]; act(tup.E0, tup.E1); } } public static void ForEach(this Tup[] array, Action act) { int index = 0; for (int i = 0; i < array.Length; i++) { var tup = array[i]; act(tup.E0, tup.E1, index++); } } public static void ForEach(this List> list, Action act) { for (int i = 0; i < list.Count; i++) { var tup = list[i]; act(tup.E0, tup.E1); } } public static void ForEach(this List> list, Action act) { int index = 0; for (int i = 0; i < list.Count; i++) { var tup = list[i]; act(tup.E0, tup.E1, index++); } } public static void ForEach(this IEnumerable> seq, Action act) { foreach (var tup in seq) act(tup.E0, tup.E1); } public static void ForEach(this IEnumerable> seq, Action act) { int index = 0; foreach (var tup in seq) act(tup.E0, tup.E1, index++); } public static void Add(this List> list, T0 e0, T1 e1) { list.Add(new Tup(e0, e1)); } public static T[] CopyToArray(this List> list, Func fun) { var count = list.Count; var array = new T[count]; for (int i = 0; i < count; i++) { var tup = list[i]; array[i] = fun(tup.E0, tup.E1); } return array; } public static T[] Map(this Tup[] array, Func fun) { var count = array.Length; var result = new T[count]; for (int i = 0; i < count; i++) { var tup = array[i]; result[i] = fun(tup.E0, tup.E1); } return result; } public static List Map(this List> list, Func fun) { var count = list.Count; var result = new List(count); for (int i = 0; i < count; i++) { var tup = list[i]; result.Add(fun(tup.E0, tup.E1)); } return result; } public static IEnumerable Select( this IEnumerable> sequence, Func selector) { return sequence.Select(tup => selector(tup.E0, tup.E1, tup.E2)); } public static IEnumerable> Where( this IEnumerable> sequence, Func predicate) { return sequence.Where(tup => predicate(tup.E0, tup.E1, tup.E2)); } public static void ForEach(this Tup[] array, Action act) { for (int i = 0; i < array.Length; i++) { var tup = array[i]; act(tup.E0, tup.E1, tup.E2); } } public static void ForEach(this Tup[] array, Action act) { int index = 0; for (int i = 0; i < array.Length; i++) { var tup = array[i]; act(tup.E0, tup.E1, tup.E2, index++); } } public static void ForEach(this List> list, Action act) { for (int i = 0; i < list.Count; i++) { var tup = list[i]; act(tup.E0, tup.E1, tup.E2); } } public static void ForEach(this List> list, Action act) { int index = 0; for (int i = 0; i < list.Count; i++) { var tup = list[i]; act(tup.E0, tup.E1, tup.E2, index++); } } public static void ForEach(this IEnumerable> seq, Action act) { foreach (var tup in seq) act(tup.E0, tup.E1, tup.E2); } public static void ForEach(this IEnumerable> seq, Action act) { int index = 0; foreach (var tup in seq) act(tup.E0, tup.E1, tup.E2, index++); } public static void Add(this List> list, T0 e0, T1 e1, T2 e2) { list.Add(new Tup(e0, e1, e2)); } public static T[] CopyToArray(this List> list, Func fun) { var count = list.Count; var array = new T[count]; for (int i = 0; i < count; i++) { var tup = list[i]; array[i] = fun(tup.E0, tup.E1, tup.E2); } return array; } public static T[] Map(this Tup[] array, Func fun) { var count = array.Length; var result = new T[count]; for (int i = 0; i < count; i++) { var tup = array[i]; result[i] = fun(tup.E0, tup.E1, tup.E2); } return result; } public static List Map(this List> list, Func fun) { var count = list.Count; var result = new List(count); for (int i = 0; i < count; i++) { var tup = list[i]; result.Add(fun(tup.E0, tup.E1, tup.E2)); } return result; } public static IEnumerable Select( this IEnumerable> sequence, Func selector) { return sequence.Select(tup => selector(tup.E0, tup.E1, tup.E2, tup.E3)); } public static IEnumerable> Where( this IEnumerable> sequence, Func predicate) { return sequence.Where(tup => predicate(tup.E0, tup.E1, tup.E2, tup.E3)); } public static void ForEach(this Tup[] array, Action act) { for (int i = 0; i < array.Length; i++) { var tup = array[i]; act(tup.E0, tup.E1, tup.E2, tup.E3); } } public static void ForEach(this Tup[] array, Action act) { int index = 0; for (int i = 0; i < array.Length; i++) { var tup = array[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, index++); } } public static void ForEach(this List> list, Action act) { for (int i = 0; i < list.Count; i++) { var tup = list[i]; act(tup.E0, tup.E1, tup.E2, tup.E3); } } public static void ForEach(this List> list, Action act) { int index = 0; for (int i = 0; i < list.Count; i++) { var tup = list[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, index++); } } public static void ForEach(this IEnumerable> seq, Action act) { foreach (var tup in seq) act(tup.E0, tup.E1, tup.E2, tup.E3); } public static void ForEach(this IEnumerable> seq, Action act) { int index = 0; foreach (var tup in seq) act(tup.E0, tup.E1, tup.E2, tup.E3, index++); } public static void Add(this List> list, T0 e0, T1 e1, T2 e2, T3 e3) { list.Add(new Tup(e0, e1, e2, e3)); } public static T[] CopyToArray(this List> list, Func fun) { var count = list.Count; var array = new T[count]; for (int i = 0; i < count; i++) { var tup = list[i]; array[i] = fun(tup.E0, tup.E1, tup.E2, tup.E3); } return array; } public static T[] Map(this Tup[] array, Func fun) { var count = array.Length; var result = new T[count]; for (int i = 0; i < count; i++) { var tup = array[i]; result[i] = fun(tup.E0, tup.E1, tup.E2, tup.E3); } return result; } public static List Map(this List> list, Func fun) { var count = list.Count; var result = new List(count); for (int i = 0; i < count; i++) { var tup = list[i]; result.Add(fun(tup.E0, tup.E1, tup.E2, tup.E3)); } return result; } public static IEnumerable Select( this IEnumerable> sequence, Func selector) { return sequence.Select(tup => selector(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4)); } public static IEnumerable> Where( this IEnumerable> sequence, Func predicate) { return sequence.Where(tup => predicate(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4)); } public static void ForEach(this Tup[] array, Action act) { for (int i = 0; i < array.Length; i++) { var tup = array[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4); } } public static void ForEach(this Tup[] array, Action act) { int index = 0; for (int i = 0; i < array.Length; i++) { var tup = array[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, index++); } } public static void ForEach(this List> list, Action act) { for (int i = 0; i < list.Count; i++) { var tup = list[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4); } } public static void ForEach(this List> list, Action act) { int index = 0; for (int i = 0; i < list.Count; i++) { var tup = list[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, index++); } } public static void ForEach(this IEnumerable> seq, Action act) { foreach (var tup in seq) act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4); } public static void ForEach(this IEnumerable> seq, Action act) { int index = 0; foreach (var tup in seq) act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, index++); } public static void Add(this List> list, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4) { list.Add(new Tup(e0, e1, e2, e3, e4)); } public static T[] CopyToArray(this List> list, Func fun) { var count = list.Count; var array = new T[count]; for (int i = 0; i < count; i++) { var tup = list[i]; array[i] = fun(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4); } return array; } public static T[] Map(this Tup[] array, Func fun) { var count = array.Length; var result = new T[count]; for (int i = 0; i < count; i++) { var tup = array[i]; result[i] = fun(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4); } return result; } public static List Map(this List> list, Func fun) { var count = list.Count; var result = new List(count); for (int i = 0; i < count; i++) { var tup = list[i]; result.Add(fun(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4)); } return result; } public static IEnumerable Select( this IEnumerable> sequence, Func selector) { return sequence.Select(tup => selector(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5)); } public static IEnumerable> Where( this IEnumerable> sequence, Func predicate) { return sequence.Where(tup => predicate(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5)); } public static void ForEach(this Tup[] array, Action act) { for (int i = 0; i < array.Length; i++) { var tup = array[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5); } } public static void ForEach(this Tup[] array, Action act) { int index = 0; for (int i = 0; i < array.Length; i++) { var tup = array[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, index++); } } public static void ForEach(this List> list, Action act) { for (int i = 0; i < list.Count; i++) { var tup = list[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5); } } public static void ForEach(this List> list, Action act) { int index = 0; for (int i = 0; i < list.Count; i++) { var tup = list[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, index++); } } public static void ForEach(this IEnumerable> seq, Action act) { foreach (var tup in seq) act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5); } public static void ForEach(this IEnumerable> seq, Action act) { int index = 0; foreach (var tup in seq) act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, index++); } public static void Add(this List> list, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5) { list.Add(new Tup(e0, e1, e2, e3, e4, e5)); } public static T[] CopyToArray(this List> list, Func fun) { var count = list.Count; var array = new T[count]; for (int i = 0; i < count; i++) { var tup = list[i]; array[i] = fun(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5); } return array; } public static T[] Map(this Tup[] array, Func fun) { var count = array.Length; var result = new T[count]; for (int i = 0; i < count; i++) { var tup = array[i]; result[i] = fun(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5); } return result; } public static List Map(this List> list, Func fun) { var count = list.Count; var result = new List(count); for (int i = 0; i < count; i++) { var tup = list[i]; result.Add(fun(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5)); } return result; } public static IEnumerable Select( this IEnumerable> sequence, Func selector) { return sequence.Select(tup => selector(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6)); } public static IEnumerable> Where( this IEnumerable> sequence, Func predicate) { return sequence.Where(tup => predicate(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6)); } public static void ForEach(this Tup[] array, Action act) { for (int i = 0; i < array.Length; i++) { var tup = array[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6); } } public static void ForEach(this Tup[] array, Action act) { int index = 0; for (int i = 0; i < array.Length; i++) { var tup = array[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6, index++); } } public static void ForEach(this List> list, Action act) { for (int i = 0; i < list.Count; i++) { var tup = list[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6); } } public static void ForEach(this List> list, Action act) { int index = 0; for (int i = 0; i < list.Count; i++) { var tup = list[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6, index++); } } public static void ForEach(this IEnumerable> seq, Action act) { foreach (var tup in seq) act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6); } public static void ForEach(this IEnumerable> seq, Action act) { int index = 0; foreach (var tup in seq) act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6, index++); } public static void Add(this List> list, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6) { list.Add(new Tup(e0, e1, e2, e3, e4, e5, e6)); } public static T[] CopyToArray(this List> list, Func fun) { var count = list.Count; var array = new T[count]; for (int i = 0; i < count; i++) { var tup = list[i]; array[i] = fun(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6); } return array; } public static T[] Map(this Tup[] array, Func fun) { var count = array.Length; var result = new T[count]; for (int i = 0; i < count; i++) { var tup = array[i]; result[i] = fun(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6); } return result; } public static List Map(this List> list, Func fun) { var count = list.Count; var result = new List(count); for (int i = 0; i < count; i++) { var tup = list[i]; result.Add(fun(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6)); } return result; } public static IEnumerable Select( this IEnumerable> sequence, Func selector) { return sequence.Select(tup => selector(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6, tup.E7)); } public static IEnumerable> Where( this IEnumerable> sequence, Func predicate) { return sequence.Where(tup => predicate(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6, tup.E7)); } public static void ForEach(this Tup[] array, Action act) { for (int i = 0; i < array.Length; i++) { var tup = array[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6, tup.E7); } } public static void ForEach(this Tup[] array, Action act) { int index = 0; for (int i = 0; i < array.Length; i++) { var tup = array[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6, tup.E7, index++); } } public static void ForEach(this List> list, Action act) { for (int i = 0; i < list.Count; i++) { var tup = list[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6, tup.E7); } } public static void ForEach(this List> list, Action act) { int index = 0; for (int i = 0; i < list.Count; i++) { var tup = list[i]; act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6, tup.E7, index++); } } public static void ForEach(this IEnumerable> seq, Action act) { foreach (var tup in seq) act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6, tup.E7); } public static void ForEach(this IEnumerable> seq, Action act) { int index = 0; foreach (var tup in seq) act(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6, tup.E7, index++); } public static void Add(this List> list, T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7) { list.Add(new Tup(e0, e1, e2, e3, e4, e5, e6, e7)); } public static T[] CopyToArray(this List> list, Func fun) { var count = list.Count; var array = new T[count]; for (int i = 0; i < count; i++) { var tup = list[i]; array[i] = fun(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6, tup.E7); } return array; } public static T[] Map(this Tup[] array, Func fun) { var count = array.Length; var result = new T[count]; for (int i = 0; i < count; i++) { var tup = array[i]; result[i] = fun(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6, tup.E7); } return result; } public static List Map(this List> list, Func fun) { var count = list.Count; var result = new List(count); for (int i = 0; i < count; i++) { var tup = list[i]; result.Add(fun(tup.E0, tup.E1, tup.E2, tup.E3, tup.E4, tup.E5, tup.E6, tup.E7)); } return result; } #endregion } } ================================================ FILE: src/Aardvark.Base/Extensions/SequenceExtensions_template.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Aardvark.Base { public static partial class SequenceExtensions { //# Action, Func> F = (o, f) => { Filter = f; o(0); Filter = null; }; //# foreach (var t in Meta.StandardNumericTypes) { //# var type = t.Name; #region __type__ Sequences #region Extreme Values //# foreach (var isMin in new[] { true, false }) { //# Func f = null; if (!isMin) f = s => s == " < " ? " > " : s; //# string Min, min, max, MaxValue, small, smalle; //string-tokens to be replaced in Max-Version //# if (isMin) { //# Min = "Min"; //# min = "min"; max = "max"; //# MaxValue = t.IsReal ? "PositiveInfinity" : "MaxValue"; //# small = "small"; smalle = "smalle"; //# } else { //# Min = "Max"; //# min = "max"; max = "min"; //# MaxValue = t.IsReal ? "NegativeInfinity" : "MinValue"; //# small = "large"; smalle = "large"; //# } /// /// Finds the __smalle__st element in a sequence, that is __smalle__r than the initially /// supplied __min__Value, or the first such element if there are equally __small__ /// elements, or __max__Value if no element is __smalle__r. /// The default value of __min__Value is __type__.__MaxValue__. /// /// A sequence of values to determine the __min__imum value of. /// The initially supplied __min__imum value. /// The __min__imum value in the sequence. /// sequence is null. public static __type__ __Min__(this IEnumerable<__type__> sequence, __type__ __min__Value = __type__.__MaxValue__) { if (sequence == null) throw new ArgumentNullException("sequence"); foreach (var value in sequence) if (value/*#F(o=>{*/ < /*#},f);*/__min__Value) __min__Value = value; return __min__Value; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the __smalle__st value, that is __smalle__r than the initially /// supplied __min__Value, or the first such element if there are equally __small__ /// elements, or __min__Value if no element is __smalle__r. /// The default value of __min__Value is __type__.__MaxValue__. /// /// The type of the elements of sequence. /// A sequence of values to determine the __min__imum value of. /// A transform function to apply to each element. /// The initially supplied __min__imum value. /// The __min__imum value in the sequence. /// sequence or selector is null. public static __type__ __Min__Value(this IEnumerable sequence, Func element_valueSelector, __type__ __min__Value = __type__.__MaxValue__) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value/*#F(o=>{*/ < /*#},f);*/__min__Value) __min__Value = value; } return __min__Value; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the __smalle__st value, that is __smalle__r than the initially /// supplied __min__Value, or the first such element if there are equally __small__ /// elements, or __min__Value if no element is __smalle__r. /// The default value of __min__Value is __type__.__MaxValue__. /// /// The type of the elements of sequence. /// A sequence of values to determine the __min__imum value of. /// A transform function to apply to each element. /// Is set to the element that yielded the smallest value or is not set if no element is __smalle__r than the initial __min__ value. /// The initially supplied __min__imum value. /// The element that yielded the __min__imum value in the sequence. /// sequence or selector is null. public static __type__ __Min__Value(this IEnumerable sequence, Func element_valueSelector, ref TSeq __min__Element, __type__ __min__Value = __type__.__MaxValue__) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); foreach (var element in sequence) { var value = element_valueSelector(element); if (value/*#F(o=>{*/ < /*#},f);*/__min__Value) { __min__Value = value; __min__Element = element; } } return __min__Value; } /// /// Invokes the value selector function on each element of a sequence, and /// finds the element with the __smalle__st value, that is __smalle__r than the initially /// supplied __min__Value, or the first such element if there are equally __small__ /// elements, or __min__Value if no element is __smalle__r. /// The default value of __min__Value is __type__.__MaxValue__. /// /// The type of the elements of sequence. /// A sequence of values to determine the __min__imum value of. /// A transform function to apply to each element. /// The initially supplied __min__imum value. /// The element that yielded the __min__imum value in the sequence. /// sequence or selector is null. public static TSeq __Min__Element(this IEnumerable sequence, Func element_valueSelector, __type__ __min__Value = __type__.__MaxValue__) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var __min__Element = default(TSeq); foreach (var element in sequence) { var value = element_valueSelector(element); if (value/*#F(o=>{*/ < /*#},f);*/__min__Value) { __min__Value = value; __min__Element = element; } } return __min__Element; } /// /// Invokes the value selector function on each element of a sequence, /// finds the __smalle__st value of all elements and return this value. /// public static __type__ __Min__Value(this TSeq[] sequence, Func element_valueSelector, __type__ __min__Value = __type__.__MaxValue__) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var value = element_valueSelector(sequence[i]); if (value/*#F(o=>{*/ < /*#},f);*/__min__Value) __min__Value = value; } return __min__Value; } /// /// Invokes the value selector function on each element of a sequence, /// finds the __smalle__st value of all elements, returns the value and /// the corresponding element as a referenced parameter. /// public static __type__ __Min__Value(this TSeq[] sequence, Func element_valueSelector, ref TSeq __min__Element, __type__ __min__Value = __type__.__MaxValue__) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value/*#F(o=>{*/ < /*#},f);*/__min__Value) { __min__Value = value; __min__Element = element; } } return __min__Value; } /// /// Invokes the value selector function on each element of a sequence, /// finds the __smalle__st value of all elements and returns the /// corresponding element. /// public static TSeq __Min__Element(this TSeq[] sequence, Func element_valueSelector, __type__ __min__Value = __type__.__MaxValue__) { if (sequence == null) throw new ArgumentNullException("sequence"); if (element_valueSelector == null) throw new ArgumentNullException("element_valueSelector"); var __min__Element = default(TSeq); for (long i = 0; i < sequence.LongLength; i++) { var element = sequence[i]; var value = element_valueSelector(element); if (value/*#F(o=>{*/ < /*#},f);*/__min__Value) { __min__Value = value; __min__Element = element; } } return __min__Element; } //# } // foreach isMin #endregion #region Sorting //# foreach (var isAsc in new[] { true, false }) { //# var Ascending = isAsc ? "Ascending" : "Descending"; //# var ascending = isAsc ? "ascending" : "descending"; //# Func f = null; if (!isAsc) f = s => s == " < " ? " > " : s; /// /// Merge an __ascending__ly sorted __type__ array with another __ascending__ly /// sorted __type__ array resulting in a single __ascending__ly sorted /// __type__ array. /// public static __type__[] Merge__Ascending__(this __type__[] a0, __type__[] a1) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new __type__[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (a0[i0]/*#F(o=>{*/ < /*#},f);*/a1[i1]) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } /// /// Merge an __ascending__ly sorted __type__ array with another __ascending__ly /// sorted __type__ array resulting in a single __ascending__ly sorted /// __type__ array. /// public static TSeq[] Merge__Ascending__(this TSeq[] a0, TSeq[] a1, Func element_valueSelector) { long count0 = a0.LongLength; long count1 = a1.LongLength; var a = new TSeq[count0 + count1]; long i = 0, i0 = 0, i1 = 0; while (i0 < count0 && i1 < count1) { if (element_valueSelector(a0[i0])/*#F(o=>{*/ < /*#},f);*/element_valueSelector(a1[i1])) a[i++] = a0[i0++]; else a[i++] = a1[i1++]; } while (i0 < count0) a[i++] = a0[i0++]; while (i1 < count1) a[i++] = a1[i1++]; return a; } //# } // isAsc #endregion #endregion //# } // foreach t } } namespace Aardvark.Base.CSharp { /// /// The following extensions reside in the special namespace /// Aardvark.Base.CSharp as they mess with normal FSharp operation. /// public static partial class CSharpSequenceExtensions { #region Sequences of Tups //# Action comma = () => Out(", "); //# for (int tc = 2; tc <= 8; tc++) { //# var Ti = tc.Expand(i => "T" + i).Join(", "); //# var ei = tc.Expand(i => "e" + i).Join(", "); //# var tupEi = tc.Expand(i => "tup.E" + i).Join(", "); public static IEnumerable Select<__Ti__, T>( this IEnumerable> sequence, Func<__Ti__, T> selector) { return sequence.Select(tup => selector(__tupEi__)); } public static IEnumerable> Where<__Ti__>( this IEnumerable> sequence, Func<__Ti__, bool> predicate) { return sequence.Where(tup => predicate(__tupEi__)); } public static void ForEach<__Ti__>(this Tup<__Ti__>[] array, Action<__Ti__> act) { for (int i = 0; i < array.Length; i++) { var tup = array[i]; act(__tupEi__); } } public static void ForEach<__Ti__>(this Tup<__Ti__>[] array, Action<__Ti__, int> act) { int index = 0; for (int i = 0; i < array.Length; i++) { var tup = array[i]; act(__tupEi__, index++); } } public static void ForEach<__Ti__>(this List> list, Action<__Ti__> act) { for (int i = 0; i < list.Count; i++) { var tup = list[i]; act(__tupEi__); } } public static void ForEach<__Ti__>(this List> list, Action<__Ti__, int> act) { int index = 0; for (int i = 0; i < list.Count; i++) { var tup = list[i]; act(__tupEi__, index++); } } public static void ForEach<__Ti__>(this IEnumerable> seq, Action<__Ti__> act) { foreach (var tup in seq) act(__tupEi__); } public static void ForEach<__Ti__>(this IEnumerable> seq, Action<__Ti__, int> act) { int index = 0; foreach (var tup in seq) act(__tupEi__, index++); } public static void Add<__Ti__>(this List> list, /*# tc.ForEach(i=>{*/T__i__ e__i__/*#}, comma); */) { list.Add(new Tup<__Ti__>(__ei__)); } public static T[] CopyToArray<__Ti__, T>(this List> list, Func<__Ti__, T> fun) { var count = list.Count; var array = new T[count]; for (int i = 0; i < count; i++) { var tup = list[i]; array[i] = fun(__tupEi__); } return array; } public static T[] Map<__Ti__, T>(this Tup<__Ti__>[] array, Func<__Ti__, T> fun) { var count = array.Length; var result = new T[count]; for (int i = 0; i < count; i++) { var tup = array[i]; result[i] = fun(__tupEi__); } return result; } public static List Map<__Ti__, T>(this List> list, Func<__Ti__, T> fun) { var count = list.Count; var result = new List(count); for (int i = 0; i < count; i++) { var tup = list[i]; result.Add(fun(__tupEi__)); } return result; } //# } // tc #endregion } } ================================================ FILE: src/Aardvark.Base/Extensions/StreamExtensions.cs ================================================ using System; using System.IO; namespace Aardvark.Base { public static class StreamExtensions { /// /// Reads number of bytes from the current stream and advances the position within the stream. /// /// The stream to read from. /// The buffer to read into. /// The byte offset in at which to begin storing the data read from the current stream. /// The number of bytes to be read from the current stream. Defaults to .Length - if negative. /// public static void ReadBytes(this Stream stream, byte[] buffer, int offset = 0, int count = -1) { if (stream == null) throw new ArgumentNullException(nameof(stream)); if (buffer == null) throw new ArgumentNullException(nameof(buffer)); if (offset < 0 || offset > buffer.Length) throw new ArgumentOutOfRangeException(nameof(offset)); if (count < 0) count = buffer.Length - offset; if (count > buffer.Length - offset) throw new ArgumentException("The offset and count do not describe a valid range inside the buffer.", nameof(count)); #if NET8_0_OR_GREATER stream.ReadExactly(buffer, offset, count); #else int totalRead = 0; while (totalRead < count) { int read = stream.Read(buffer, offset + totalRead, count - totalRead); if (read == 0) { throw new EndOfStreamException(); } totalRead += read; } #endif } } } ================================================ FILE: src/Aardvark.Base/Extensions/StringExtensions.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Security.Cryptography; using System.Text; namespace Aardvark.Base { public static class CharFun { public static bool IsWhiteSpace(this char ch) { return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; } public static bool IsSpaceOrTab(this char ch) { return ch == ' ' || ch == '\t'; } } public static class StringFun { #region To public static bool ToBool(this string self) { var s = self.Trim().ToLower(); if (s == "true" || s == "t") return true; if (s == "false" || s == "f") return false; double r; // Double.TryParse() sets r to 0 if the conversion fails, // which means we don't really need to check the return value. Double.TryParse(s, out r); return r != 0.0; } public static byte ToByte(this string self) { return byte.Parse(self, CultureInfo.InvariantCulture); } public static sbyte ToSByte(this string self) { return sbyte.Parse(self, CultureInfo.InvariantCulture); } public static short ToShort(this string self) { return short.Parse(self, CultureInfo.InvariantCulture); } public static ushort ToUShort(this string self) { return ushort.Parse(self, CultureInfo.InvariantCulture); } public static int ToInt(this string self) { return int.Parse(self, CultureInfo.InvariantCulture); } public static uint ToUInt(this string self) { return uint.Parse(self, CultureInfo.InvariantCulture); } public static long ToLong(this string self) { return long.Parse(self, CultureInfo.InvariantCulture); } public static ulong ToULong(this string self) { return ulong.Parse(self, CultureInfo.InvariantCulture); } public static float ToFloat(this string self) { return float.Parse(self, CultureInfo.InvariantCulture); } public static double ToDouble(this string self) { return double.Parse(self, CultureInfo.InvariantCulture); } public static DateTime ToDateTime(this string self) { return DateTime.Parse(self, CultureInfo.InvariantCulture); } public static decimal ToDecimal(this string self, decimal def) { decimal result; if (!decimal.TryParse(self, out result)) { result = def; } return result; } public static decimal ToDecimal(this string self) { return decimal.Parse(self, CultureInfo.InvariantCulture); } #endregion #region Manipulations public static string Capitalized(this string self) { if (self == null || self == "") return self; return self.Substring(0, 1).ToUpperInvariant() + self.Substring(1); } public static string[] ToLower(this string[] self) { return self.Map(s => s.ToLower()); } public static string[] ToUpper(this string[] self) { return self.Map(s => s.ToUpper()); } public static IEnumerable ToLower(this IEnumerable self) { foreach (var s in self) yield return s.ToLower(); } public static IEnumerable ToUpper(this IEnumerable self) { foreach (var s in self) yield return s.ToUpper(); } #endregion #region Plural /// /// Returns the english plural of the supplied word (i.e. the word /// with "s" appended) if the supplied integer is not equal to one. /// Otherwise the word is returned unchanged. /// public static string Plural(this string word, int s) { return word.Plural((long)s); } static readonly Dictionary s_irregularPlural = new Dictionary { { "aircraft", "aircraft" }, { "axis", "axes" }, { "bison", "bison" }, { "child", "children" }, { "deer", "deer" }, { "fish", "fish" }, { "foot", "feet" }, { "goose", "geese" }, { "louse", "lice" }, { "man", "men" }, { "moose", "moose" }, { "mouse", "mice" }, { "ox", "oxen" }, { "pike", "pike" }, { "salmon", "salmon" }, { "sheep", "sheep" }, { "tooth", "teeth" }, { "trout", "trout" }, { "woman", "women" }, }; static readonly Dictionary[] s_pluralEndings = new Dictionary[] { null, new Dictionary { { "y", "ies" } }, new Dictionary { { "ch" , "ches" }, { "ex", "ices" }, { "sh" , "shes" }, { "ss", "sses" }, }, }; /// /// Returns the english plural of the supplied word (i.e. the word /// with "s" appended) if the supplied integer is not equal to one. /// Otherwise the word is returned unchanged. /// public static string Plural(this string word, long s) { if (s == 1) return word; string irregular; if (s_irregularPlural.TryGetValue(word, out irregular)) return irregular; else { for (int i = s_pluralEndings.Length-1; i > 0; i--) { if (i > word.Length) continue; string ending = word.Substring(word.Length - i); string plural; if (s_pluralEndings[i].TryGetValue(ending, out plural)) return word.Substring(0, word.Length - i) + plural; } return word + "s"; } } #endregion #region Sub strings /// /// Returns leftmost n characters of this string. /// public static string Left(this string self, int n) { if (self.Length <= n) return self; return self.Substring(0, n); } /// /// Returns rightmost n characters of this string. /// public static string Right(this string self, int n) { int length = self.Length; if (length <= n) return self; return self.Substring(length - n); } /// /// Return the substring for the range [start, end). For the start /// index, negative indices count from the end. For the end index, /// negative and the indices and the index 0 count from the end. /// The ranges are clamped to the input string so that no exceptions /// can occur. If the the start and end index are crossed, the null /// string is returned. As an example the call s.Sub(-3, 0) returns /// a string containing the last 3 characters s or the complete /// string s if its length is less than 3 characters. /// public static string Sub(this string self, int start, int end) { int len = self.Length; start = start < 0 ? Math.Max(0, len + start) : Math.Min(start, len); end = end <= 0 ? Math.Max(0, len + end) : Math.Min(end, len); return start < end ? self.Substring(start, end - start) : null; } public static string Join(this IEnumerable strings) { var result = new StringBuilder(); foreach (var s in strings) result.Append(s); return result.ToString(); } public static string Join(this IEnumerable strings, string delimiter) { var result = new StringBuilder(); bool notFirst = false; foreach (var s in strings) { if (notFirst) result.Append(delimiter); else notFirst = true; result.Append(s); } return result.ToString(); } private static readonly char[] s_whiteSpace = new char[] { ' ', '\t', '\n', '\r' }; public static string[] SplitOnWhitespace(this string s) { return s.Split(s_whiteSpace, StringSplitOptions.RemoveEmptyEntries); } #endregion #region Square Brackets/Comma Split /// /// Splits a nested structure of comma-separated square bracket /// delimited lists at level 1, i.e. inside the top most bracket. /// E.g. "[[a, b], foo, [c, d]]" returns "[a, b]", "foo" and "[c, d]". /// public static IEnumerable NestedBracketSplitLevelOne(this string text) { int level = 0; int begin = 0; int len = text.Length; for (int pos = 0; pos < len; pos++) { switch (text[pos]) { case '[': if (++level == 1) begin = pos + 1; break; case ']': if (level-- == 1) yield return text.Substring(begin, pos - begin).Trim(); break; case ',': if (level == 1) { yield return text.Substring(begin, pos - begin).Trim(); begin = pos + 1; } break; } } } /// /// Splits a nested structure of comma-separated square bracked /// delimited lists at a specified split level. Level 0 means that /// the split is performed outside the outermost square brackets. /// Level 1 means that the split is peformed inside the outermost /// square brackets. /// NOTE: The resulting parts are not trimmed. Use the Trim extension /// to trim all resulting strings. /// public static IEnumerable NestedBracketSplit(this string text, int splitLevel) { int level = 0; int begin = 0; int len = text.Length; for (int pos = 0; pos < len; pos++) { switch (text[pos]) { case '[': ++level; if (level == splitLevel) begin = pos + 1; break; case ']': if (level == splitLevel) yield return text.Substring(begin, pos - begin); --level; break; case ',': if (level == splitLevel) { yield return text.Substring(begin, pos - begin); begin = pos + 1; } break; } } if (level == splitLevel && len > begin) yield return text.Substring(begin, len - begin); } #endregion #region Guid /// /// Computes the SHA1 hash of the given string and returns it as Guid. /// public static Guid ToGuid(this string self) { if (string.IsNullOrEmpty(self)) return Guid.Empty; var hash = self.ComputeSHA1Hash(); #if NET8_0_OR_GREATER return new Guid(hash.AsSpan(0, 16)); #else Array.Resize(ref hash, 16); return new Guid(hash); #endif } /// /// Combines the given strings and returns a Guid based on the SHA1 hash. /// public static Guid ToGuid(this IEnumerable self) { var sb = new StringBuilder(); foreach (var x in self) sb.Append(x); return sb.ToString().ToGuid(); } /// /// Combines the given Guids to a string and returns a Guid based on the SHA1 hash. /// public static Guid ToGuid(this IEnumerable self) { var sb = new StringBuilder(); foreach (var x in self) sb.Append(x.ToString()); return sb.ToString().ToGuid(); } #endregion #region Properties public static bool IsNullOrEmpty(this string self) { return string.IsNullOrEmpty(self); } #endregion #region Formatting /// /// Same as String.Format, but uses the InvariantCulture formatter /// (The one we usually want. You know, . as decimal point,...) /// public static string FormatInvariant(this string format, params object[] args) { return string.Format(System.Globalization.CultureInfo.InvariantCulture, format, args); } #endregion #region Hex/Binary /// /// Converts the byte array to string using base-64 encoding; /// public static string ToBase64(this byte[] data) { return Convert.ToBase64String(data); } #if NET6_0_OR_GREATER /// /// Converts the byte span to string using base-64 encoding; /// public static string ToBase64(this Span span) { return Convert.ToBase64String(span); } /// /// Converts the byte span to string using base-64 encoding; /// public static string ToBase64(this ReadOnlySpan span) { return Convert.ToBase64String(span); } #endif /// /// Builds a string representing the byte arrays as hexadecimal number. /// public static string ToHex(this byte[] bytes) { char[] c = new char[bytes.Length * 2]; byte b; for (int bx = 0, cx = 0; bx < bytes.Length; ++bx, ++cx) { b = ((byte)(bytes[bx] >> 4)); c[cx] = (char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30); b = ((byte)(bytes[bx] & 0x0F)); c[++cx] = (char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30); } return new string(c); } /// /// Converts a hexadecimal number as string to a byte array. /// public static byte[] HexToBytes(this string str) { if (str.Length == 0 || str.Length % 2 != 0) return System.Array.Empty(); byte[] buffer = new byte[str.Length / 2]; char c; for (int bx = 0, sx = 0; bx < buffer.Length; ++bx, ++sx) { // Convert first half of byte c = str[sx]; buffer[bx] = (byte)((c > '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0')) << 4); // Convert second half of byte c = str[++sx]; buffer[bx] |= (byte)(c > '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0')); } return buffer; } #endregion } } ================================================ FILE: src/Aardvark.Base/Extensions/Structs.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; using System.Text; namespace Aardvark.Base { #region IndexedValue public readonly struct IndexedValue { public readonly int Index; public readonly T Value; #region Constructor public IndexedValue(int index, T value) { Index = index; Value = value; } #endregion } #endregion #region ComparableIndexedValue public readonly struct ComparableIndexedValue : IComparable> where T : IComparable { public readonly int Index; public readonly T Value; #region Constructor public ComparableIndexedValue(int index, T value) { Index = index; Value = value; } #endregion #region IComparable> Members public int CompareTo(ComparableIndexedValue other) { return Value.CompareTo(other.Value); } #endregion } #endregion public static class StructsExtensions { #region ComparableIndexedValue public static IEnumerable> ComparableIndexedValues( this IEnumerable self) where T : IComparable { return self.Select((item, i) => new ComparableIndexedValue(i, item)); } public static ComparableIndexedValue ComparableIndexedValue( this T self, int index) where T : IComparable { return new ComparableIndexedValue(index, self); } #endregion } } ================================================ FILE: src/Aardvark.Base/Extensions/SubRange.cs ================================================ using System; using System.Collections.Generic; namespace Aardvark.Base { /// /// A SubRange is an IList that servers as a window into other ILists. /// public class SubRange : IList { private readonly IList m_base; private readonly int m_start; private readonly int m_count; private readonly int m_stop; #region Constructor public SubRange(IList of, int index, int count) { m_base = of; m_start = index; m_count = count; m_stop = m_start + m_count; } #endregion #region IList Members public int IndexOf(T item) { for (int i = m_start; i < m_stop; i++) { if (m_base[i].Equals(item)) return i - m_start; } return -1; } public void Insert(int index, T item) { throw new InvalidOperationException(); } public void RemoveAt(int index) { throw new InvalidOperationException(); } public T this[int index] { get { if (index < 0 || index > m_count) throw new IndexOutOfRangeException(); return m_base[m_start + index]; } set { if (index < 0 || index > m_count) throw new IndexOutOfRangeException(); m_base[m_start + index] = value; } } #endregion #region ICollection Members public void Add(T item) { throw new InvalidOperationException(); } public void Clear() { throw new InvalidOperationException(); } public bool Contains(T item) { return IndexOf(item) != -1; } public void CopyTo(T[] array, int arrayIndex) { for (int i = 0; i < m_count; i++) { array[arrayIndex + i] = m_base[m_start + i]; } } public int Count { get { return m_count; } } public bool IsReadOnly { get { return m_base.IsReadOnly; } } public bool Remove(T item) { throw new InvalidOperationException(); } #endregion #region IEnumerable Members public IEnumerator GetEnumerator() { for (int i = m_start; i < m_stop; i++) yield return m_base[i]; } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { for (int i = m_start; i < m_stop; i++) yield return m_base[i]; } #endregion } } ================================================ FILE: src/Aardvark.Base/Extensions/SystemDrawingExtensions.cs ================================================ using System.Drawing; namespace Aardvark.Base.SystemDrawingInterop { /// /// Extensions for converting between System.Drawing and Aardvark data types. /// public static class SystemDrawingExtensions { #region System.Drawing.Point /// /// System.Drawing.Point to V2i. /// public static V2i ToV2i(this Point p) => new V2i(p.X, p.Y); /// /// V2i to System.Drawing.Point. /// public static Point ToPoint(this V2i p) => new Point(p.X, p.Y); #endregion #region System.Drawing.Size /// /// System.Drawing.Size to V2i. /// public static V2i ToV2i(this Size s) => new V2i(s.Width, s.Height); /// /// V2i to System.Drawing.Size. /// public static Size ToSize(this V2i v) => new Size(v.X, v.Y); #endregion #region System.Drawing.Rectangle /// /// System.Drawing.Rectangle to Box2i. /// public static Box2i ToBox2i(this Rectangle r) => new Box2i(r.Left, r.Top, r.Right, r.Bottom); /// /// Box2i to System.Drawing.Rectangle. /// public static Rectangle ToRectangle(this Box2i p) => new Rectangle(p.Min.X, p.Min.Y, p.SizeX, p.SizeY); #endregion #region System.Drawing.Color /// /// C3b to System.Drawing.Color. /// public static Color ToColor(this C3b color) => Color.FromArgb(color.R, color.G, color.B); /// /// System.Drawing.Color to C3b. /// public static C3b ToC3b(this Color color) => new C3b(color.R, color.G, color.B); /// /// C3us to System.Drawing.Color. /// public static Color ToColor(this C3us color) => Color.FromArgb( Col.UShortToByte(color.R), Col.UShortToByte(color.G), Col.UShortToByte(color.B)); /// /// System.Drawing.Color to C3us. /// public static C3us ToC3us(this Color color) => new C3us( Col.ByteToUShort(color.R), Col.ByteToUShort(color.G), Col.ByteToUShort(color.B)); /// /// C3ui to System.Drawing.Color. /// public static Color ToColor(this C3ui color) => Color.FromArgb( Col.UIntToByte(color.R), Col.UIntToByte(color.G), Col.UIntToByte(color.B)); /// /// System.Drawing.Color to C3ui. /// public static C3ui ToC3ui(this Color color) => new C3ui( Col.ByteToUInt(color.R), Col.ByteToUInt(color.G), Col.ByteToUInt(color.B)); /// /// C3f to System.Drawing.Color. /// public static Color ToColor(this C3f color) => Color.FromArgb( Col.FloatToByteClamped(color.R), Col.FloatToByteClamped(color.G), Col.FloatToByteClamped(color.B)); /// /// System.Drawing.Color to C3f. /// public static C3f ToC3f(this Color color) => new C3f( Col.ByteToFloat(color.R), Col.ByteToFloat(color.G), Col.ByteToFloat(color.B)); /// /// C3d to System.Drawing.Color. /// public static Color ToColor(this C3d color) => Color.FromArgb( Col.DoubleToByteClamped(color.R), Col.DoubleToByteClamped(color.G), Col.DoubleToByteClamped(color.B)); /// /// System.Drawing.Color to C3d. /// public static C3d ToC3d(this Color color) => new C3d( Col.ByteToDouble(color.R), Col.ByteToDouble(color.G), Col.ByteToDouble(color.B)); /// /// C4b to System.Drawing.Color. /// public static Color ToColor(this C4b color) => Color.FromArgb(color.A, color.R, color.G, color.B); /// /// System.Drawing.Color to C4b. /// public static C4b ToC4b(this Color color) => new C4b(color.R, color.G, color.B, color.A); /// /// C4us to System.Drawing.Color. /// public static Color ToColor(this C4us color) => Color.FromArgb( Col.UShortToByte(color.A), Col.UShortToByte(color.R), Col.UShortToByte(color.G), Col.UShortToByte(color.B)); /// /// System.Drawing.Color to C4us. /// public static C4us ToC4us(this Color color) => new C4us( Col.ByteToUShort(color.R), Col.ByteToUShort(color.G), Col.ByteToUShort(color.B), Col.ByteToUShort(color.A)); /// /// C4ui to System.Drawing.Color. /// public static Color ToColor(this C4ui color) => Color.FromArgb( Col.UIntToByte(color.A), Col.UIntToByte(color.R), Col.UIntToByte(color.G), Col.UIntToByte(color.B)); /// /// System.Drawing.Color to C4ui. /// public static C4ui ToC4ui(this Color color) => new C4ui( Col.ByteToUInt(color.R), Col.ByteToUInt(color.G), Col.ByteToUInt(color.B), Col.ByteToUInt(color.A)); /// /// C4f to System.Drawing.Color. /// public static Color ToColor(this C4f color) => Color.FromArgb( Col.FloatToByteClamped(color.A), Col.FloatToByteClamped(color.R), Col.FloatToByteClamped(color.G), Col.FloatToByteClamped(color.B)); /// /// System.Drawing.Color to C4f. /// public static C4f ToC4f(this Color color) => new C4f( Col.ByteToFloat(color.R), Col.ByteToFloat(color.G), Col.ByteToFloat(color.B), Col.ByteToFloat(color.A)); /// /// C4d to System.Drawing.Color. /// public static Color ToColor(this C4d color) => Color.FromArgb( Col.DoubleToByteClamped(color.A), Col.DoubleToByteClamped(color.R), Col.DoubleToByteClamped(color.G), Col.DoubleToByteClamped(color.B)); /// /// System.Drawing.Color to C4d. /// public static C4d ToC4d(this Color color) => new C4d( Col.ByteToDouble(color.R), Col.ByteToDouble(color.G), Col.ByteToDouble(color.B), Col.ByteToDouble(color.A)); #endregion } } ================================================ FILE: src/Aardvark.Base/Extensions/TupleExtensions.cs ================================================ using System; namespace Aardvark.Base { public static class TupleExtensions { /// /// Number of NaNs in tuple. /// public static int CountNonNaNs(this (double, double) p) { int count = 2; if (double.IsNaN(p.Item1)) --count; if (double.IsNaN(p.Item2)) --count; return count; } /// /// Number of NaNs in tuple. /// public static int CountNonNaNs(this (double, double, double) p) { int count = 3; if (double.IsNaN(p.Item1)) --count; if (double.IsNaN(p.Item2)) --count; if (double.IsNaN(p.Item3)) --count; return count; } /// /// Number of NaNs in tuple. /// public static int CountNonNaNs(this (double, double, double, double) p) { int count = 4; if (double.IsNaN(p.Item1)) --count; if (double.IsNaN(p.Item2)) --count; if (double.IsNaN(p.Item3)) --count; if (double.IsNaN(p.Item4)) --count; return count; } /// /// Gets i-th value of tuple. /// public static double Get(this (double, double) p, int i) { switch (i) { case 0: return p.Item1; case 1: return p.Item2; default: throw new IndexOutOfRangeException(); } } /// /// Gets i-th value of tuple. /// public static double Get(this (double, double, double) p, int i) { switch (i) { case 0: return p.Item1; case 1: return p.Item2; case 2: return p.Item3; default: throw new IndexOutOfRangeException(); } } /// /// Gets i-th value of tuple. /// public static double Get(this (double, double, double, double) p, int i) { switch (i) { case 0: return p.Item1; case 1: return p.Item2; case 2: return p.Item3; case 3: return p.Item4; default: throw new IndexOutOfRangeException(); } } #if !TRAVIS_CI /// /// Sets i-th value in tuple (in-place). /// public static void Set(this ref (double, double) p, int i, double value) { switch (i) { case 0: p.Item1 = value; break; case 1: p.Item2 = value; break; default: throw new IndexOutOfRangeException(); } } /// /// Sets i-th value in tuple (in-place). /// public static void Set(this ref (double, double, double) p, int i, double value) { switch (i) { case 0: p.Item1 = value; break; case 1: p.Item2 = value; break; case 2: p.Item3 = value; break; default: throw new IndexOutOfRangeException(); } } /// /// Sets i-th value in tuple (in-place). /// public static void Set(this ref (double, double, double, double) p, int i, double value) { switch (i) { case 0: p.Item1 = value; break; case 1: p.Item2 = value; break; case 2: p.Item3 = value; break; case 3: p.Item4 = value; break; default: throw new IndexOutOfRangeException(); } } #endif /// /// Creates tuple from given values with values in ascending order. /// public static (double, double) CreateAscending(double d0, double d1) => d0 < d1 ? (d0, d1) : (d1, d0); /// /// Creates tuple from given values with values in ascending order. /// public static (double, double, double) CreateAscending(double d0, double d1, double d2) { if (d0 < d1) { if (d1 < d2) return (d0, d1, d2); else return (d0 < d2) ? (d0, d2, d1) : (d2, d0, d1); } else { if (d2 < d1) return (d2, d1, d0); else return (d0 < d2) ? (d1, d0, d2) : (d1, d2, d0); } } } } ================================================ FILE: src/Aardvark.Base/Extensions/TypeExtensions.cs ================================================ using System; using System.Collections.Concurrent; using System.Reflection; using System.Runtime.CompilerServices; namespace Aardvark.Base { public static class TypeExtensions { private static readonly MethodInfo unsafeSizeOfMeth = typeof(Unsafe).GetMethod(nameof(Unsafe.SizeOf), BindingFlags.Public | BindingFlags.Static); private static readonly ConcurrentDictionary unsafeTypeSizes = new(); /// /// Returns the managed size of the given type. /// public static int GetCLRSize(this Type t) { return unsafeTypeSizes.GetOrAdd(t, t => { var mi = unsafeSizeOfMeth.MakeGenericMethod(t); return (int)mi.Invoke(null, null); }); } } } ================================================ FILE: src/Aardvark.Base/Extensions/VariousExtensions.cs ================================================ using System; using System.Collections.Generic; namespace Aardvark.Base { public static class VariousExtensions { public static IEnumerable Expand(this int n, Func fun) { for (int i = 0; i < n; i++) yield return fun(i); } } } ================================================ FILE: src/Aardvark.Base/Geodesy/GeoConsts.cs ================================================ namespace Aardvark.Base { /// /// Holds data for a geodesic transform from one datum to another. /// public class GeoDatum { private readonly double m_dx; private readonly double m_dy; private readonly double m_dz; private readonly double m_rx; private readonly double m_ry; private readonly double m_rz; private readonly double m_ds; /// /// Constructs geodetic datum. /// Deltas and Scaling should be provided in meters. /// Rotation has to be given in arc-seconds. /// /// Delta x /// Delta y /// Delta z /// Rotation x /// Rotation y /// Rotation z /// Scaling public GeoDatum( double dx, double dy, double dz, double rx, double ry, double rz, double ds ) { m_dx = dx; m_dy = dy; m_dz = dy; m_rx = rx; m_ry = ry; m_rz = rz; m_ds = ds; } /// /// Delta X /// public double dX => m_dx; /// /// Delta Y /// public double dY => m_dy; /// /// Delta Z /// public double dZ => m_dz; /// /// Rotation X in arc-seconds. /// public double rXsec => m_rx; /// /// Rotation Y in arc-seconds. /// public double rYsec => m_ry; /// /// Rotation Z in arc seconds. /// public double rZsec => m_rz; /// /// Rotation X in radians. /// public double rXrad => m_rx * Constant.ArcSecond; /// /// Rotation Y in radians. /// public double rYrad => m_ry * Constant.ArcSecond; /// /// Rotation Z in radians. /// public double rZrad => m_rz * Constant.ArcSecond; /// /// Scaling in meters. /// public double dS => m_ds; /// /// Conversion from WGS84 to Austria NS (MGI 1). /// public static readonly GeoDatum Wgs84toAustriaNs1 = new GeoDatum(-575.0, -93.0, -466.0, 5.1, 1.6, 5.2, -2.5); /// /// Cconversion from WGS84 to Austria NS (MGI 2). /// public static readonly GeoDatum Wgs84toAustriaNs2 = new GeoDatum(-577.326, -90.129, -463.919, 5.14, 1.47, 5.30, -2.4232); /// /// Conversion from Austria NS1 (MGI) to WGS84. /// public static readonly GeoDatum AustriaNs1toWgs84 = new GeoDatum(575.0, 93.0, 466.0, -5.1, -1.6, -5.2, 2.5); /// /// Conversion FROM Austria NS2 (MGI) TO WGS84. /// public static readonly GeoDatum AustriaNs2toWgs84 = new GeoDatum(577.326, 90.129, 463.919, -5.14, -1.47, -5.30, 2.4232); } /// /// This struct provides properties for a particular World-Ellipsoid. /// It is defined by ist two radii: "a" and "b". /// public readonly struct GeoEllipsoid { public readonly double A; public readonly double B; public readonly double F; /// /// Construct a geo-ellipsoid from semi-major axis a (bigger radius), /// semi-minor axis b (smaller radius) and flattening f. Since only /// two of these are necessary for specification, use the static /// functions and to construct /// ellipsoids given their defining parameters. /// public GeoEllipsoid(double a, double b, double f) { A = a; B = b; F = f; } public static GeoEllipsoid FromAB(double a, double b) => new GeoEllipsoid(a, b, (a - b) / a); public static GeoEllipsoid FromAF(double a, double f) => new GeoEllipsoid(a, a * (1.0 - f), f); /// /// Returns the inverse of the flattening: 1/f. /// public double InvF => (1.0 / F); /// /// Returns the first eccentricity squared: e^2 = (a^2-b^2)/a^2. /// public double EQ => (A * A - B * B) / (A * A); /// /// Returns the second eccentricity squared: e2^2 = (a^2-b^2)/b^2. /// public double E2Q => (A * A - B * B) / (B * B); public static readonly GeoEllipsoid Airy1830 = FromAB(6377563.396, 6356256.909); public static readonly GeoEllipsoid Bessel1841 = FromAB(6377397.15508, 6356078.96290); public static readonly GeoEllipsoid Grs80 = FromAF(6378137.0, 1.0 / 298.257222101); public static readonly GeoEllipsoid International1924 = FromAF(6378388.0, 1.0 / 297.0); public static readonly GeoEllipsoid Clarke1880 = FromAF(6378249.145, 1.0 / 293.465); public static readonly GeoEllipsoid Wgs84 = FromAF(6378137.0, 1.0 / 298.257223563); } /// /// Static class. Provides constants for Geodesic Conversions. /// public static class GeoConstant { /// /// Returns the M28 meridian used in austrian Gauss-Krueger System (MGI) -> GK-reference meridian for West-Austria. /// (28 deg from Ferro = 10 deg + 20 min from Greenwich). /// public const double AustriaM28 = 10 + 1 / 3.0; /// /// Returns the M31 meridian used in austrian Gauss-Krueger System (MGI) -> GK-reference meridian for Mid-Austria. /// (31 deg from Ferro = 13 deg + 20 min from Greenwich). /// public const double AustriaM31 = 13 + 1 / 3.0; /// /// Returns the M34 meridian used in austrian Gauss-Krueger System (MGI) -> GK-reference meridian for East-Austria. /// (34 deg from Ferro = 16 deg + 20 min from Greenwich). /// public const double AustriaM34 = 16 + 1 / 3.0; } } ================================================ FILE: src/Aardvark.Base/Geodesy/GeoConversion.cs ================================================ using System; using System.Globalization; using System.Net; using static Aardvark.Base.Constant; using static System.Math; namespace Aardvark.Base { public static class Geo { #region Conversion Methods /// /// Returns the XYZ-coordinates from longitude, latitude and height on a given reference ellipsoid. /// public static V3d XyzFromLonLatHeight(V3d lonLatHeight, GeoEllipsoid ellipsoid) { double lam = Conversion.RadiansFromDegrees(lonLatHeight.X); double phi = Conversion.RadiansFromDegrees(lonLatHeight.Y); double h = lonLatHeight.Z; double cos_lam = Cos(lam); double cos_phi = Cos(phi); double sin_lam = Sin(lam); double sin_phi = Sin(phi); // eccentricity square double eq = ellipsoid.EQ; // radius of the curvature in prime vertical double Rv = ellipsoid.A / (1.0 - eq * sin_phi * sin_phi).Sqrt(); V3d result = new V3d { X = (Rv + h) * cos_phi * cos_lam, Y = (Rv + h) * cos_phi * sin_lam, Z = ((1.0 - eq) * Rv + h) * sin_phi }; return result; } /// /// Returns the longitude, latitude and height from XYZ-coords on a given world reference ellipsoid. /// /// Vector with xyz. /// GeoEllipsoid from the GeoConsts class. /// Position vector with Lon,Lat,Hei public static V3d LonLatHeightFromXyz(V3d xyz, GeoEllipsoid ellipsoid) { // this implementation follows the Bowring Method (85). // It might be extended to the newer Toms Method (99), but is delivers suitable results. double a = ellipsoid.A; double b = ellipsoid.B; // Distance between x and y. double W = (xyz.X * xyz.X + xyz.Y * xyz.Y).Sqrt(); // apprx phi double PHI = Atan((xyz.Z * a) / (W * b)); double eq = ellipsoid.EQ; double e2q = ellipsoid.E2Q;// (eq / (1.0 - eq)).Sqrt(); double lam = Atan(xyz.Y / xyz.X); double sinPhi = (PHI).Sin(); double sinPhiTo3 = sinPhi * sinPhi * sinPhi; double cosPhi = (PHI).Cos(); double cosPhiTo3 = cosPhi * cosPhi * cosPhi; double phi = Atan((xyz.Z + e2q * b * sinPhiTo3) / (W - eq * a * cosPhiTo3)); double sinphi = phi.Sin(); // curvature in the prime vertical double Rv = a / (1.0 - eq * sinphi * sinphi).Sqrt(); double cosphi = phi.Cos(); double h = W / cosphi - Rv; double lat = Conversion.DegreesFromRadians(phi);// phi * 180 / pi; double lon = Conversion.DegreesFromRadians(lam); // lam * 180 / pi; return new V3d(lon, lat, h); } /// /// Returns WGS84 Longitude/Latitude/Height for given street address, /// or null if address not found. Uses maps.google.com webservice. /// [Obsolete("Uses unsupported Google Geocoding V2 API.")] public static V3d? Wgs84FromStreetAddress(string address, string key) { var output = "csv"; var url = @"http://maps.google.com/maps/geo?" + "q=" + Uri.EscapeDataString(address) + "&output=" + output + "&key=" + key; var resp = new WebClient().DownloadString(url); var tokens = resp.Split(','); if (tokens.Length != 4) throw new FormatException(); if (tokens[0] != "200") return null; return new V3d( double.Parse(tokens[2], CultureInfo.InvariantCulture), double.Parse(tokens[3], CultureInfo.InvariantCulture), 151.0); } /// /// Transforms XYZ coord on one reference ellipsoid to XYZ coords on another /// ref ellipsoid. The ellipsoids-difference is defined in a geometric datum /// which is passes as the second argument. /// public static V3d HelmertsTransformXyzToXyz(V3d xyz, GeoDatum datum) { // transformation matrix var T = new M33d(1.0, datum.rZrad, -datum.rYrad, -datum.rZrad, 1.0, datum.rXrad, datum.rYrad, -datum.rXrad, 1.0); // delta in ellipsoid center positions var dP = new V3d(datum.dX, datum.dY, datum.dZ); // scale factor var mu = new Scale3d(datum.dS * 0.000001 + 1.0); var result = dP + (mu * T) * xyz; return result; } /// /// Gauss-Krueger projection from a reference ellipsoid datum (Lon/Lat/Height) to local GK-coordinates (in meters). /// /// V3d with Lon/Lat/Height. /// /// public static V3d GaussKruegerEllipsoidToPlane( V3d lonLatHeight, GeoEllipsoid ellipsoid, double zeroMeridian ) { double phi = Conversion.RadiansFromDegrees(lonLatHeight.Y); double lam = Conversion.RadiansFromDegrees(lonLatHeight.X - zeroMeridian); double cosphi = phi.Cos(); double a = ellipsoid.A; double b = ellipsoid.B; double n = (a - b) / (a + b); //n = (a-b)/(a+b); double nTo2 = n * n; double nTo3 = nTo2 * n; double nTo4 = nTo3 * n; double nTo5 = nTo4 * n; // arc length approx. polynom coefficients double c1 = (a + b) / 2.0 * (1.0 + nTo2 / 4.0 + nTo4 / 64.0); double c2 = -(3.0 / 2.0) * n + (9.0 / 16.0) * nTo3 - (3.0 / 32.0) * nTo5; double c3 = (15.0 / 16.0) * nTo2 - (15.0 / 32.0) * nTo4; double c4 = -(35.0 / 48.0) * nTo3 + (105.0 / 256.0) * nTo5; double c5 = (315.0 / 512.0) * nTo4; // sine of multiple of phi double sin2phi = (2.0 * phi).Sin(); double sin4phi = (4.0 * phi).Sin(); double sin6phi = (6.0 * phi).Sin(); double sin8phi = (8.0 * phi).Sin(); // arc lenght of the meridan double B = c1 * (phi + c2 * sin2phi + c3 * sin4phi + c4 * sin6phi + c5 * sin8phi); //% second nummerical eccentrencity double e2q = ellipsoid.E2Q; // cos(phi) to powers double cosphiTo2 = cosphi * cosphi; double cosphiTo3 = cosphiTo2 * cosphi; double cosphiTo4 = cosphiTo3 * cosphi; double cosphiTo5 = cosphiTo4 * cosphi; double cosphiTo6 = cosphiTo5 * cosphi; double cosphiTo7 = cosphiTo6 * cosphi; double cosphiTo8 = cosphiTo7 * cosphi; //% auxilary quantity 1 double nuTo2 = e2q * cosphiTo2; //%radius of the curvature in prime vertical double N = (a * a) / (b * (1.0 + nuTo2).Sqrt()); // lambda to powers double lamTo2 = lam * lam; double lamTo3 = lamTo2 * lam; double lamTo4 = lamTo3 * lam; double lamTo5 = lamTo4 * lam; double lamTo6 = lamTo5 * lam; double lamTo7 = lamTo6 * lam; double lamTo8 = lamTo7 * lam; //% auxilary quantity 2 double t = phi.Tan(); // t to powers double tTo2 = t * t; double tTo4 = tTo2 * tTo2; double tTo6 = tTo2 * tTo4; // nu^2 to powers double nuTo4 = nuTo2 * nuTo2; //double nuqTo22 = nuq.Pow(22); //% x-coord: breite double x1 = t / 2.0 * N * cosphiTo2 * lamTo2; double x2 = t / 24.0 * N * cosphiTo4 * (5.0 - tTo2 + 9.0 * nuTo2 + 4.0 * nuTo4) * lamTo4; double x3 = t / 720.0 * N * cosphiTo6 * (61.0 - 58.0 * tTo2 + tTo4 + 270.0 * nuTo2 - 330.0 * tTo2 * nuTo4) * lamTo6; double x4 = t / 403204.0 * N * cosphiTo8 * (1385.0 - 3111.0 * tTo2 + 543.0 * tTo4 - tTo6) * lamTo8; double nX = B + x1 + x2 + x3 + x4; nX = nX - 5000000; // <-- im model // y-coord: laenge double y1 = N * cosphi * lam; double y2 = N / 6.0 * cosphiTo3 * (1.0 - tTo2 + nuTo2) * lamTo3; double y3 = N / 120.0 * cosphiTo5 * (5.0 - 18.0 * tTo2 + tTo4 + 14 * nuTo2 - 58.0 * tTo2 * nuTo2) * lamTo5; double y4 = N / 5040.0 * cosphiTo7 * (61.0 - 479.0 * tTo2 + 179.0 * tTo4 - tTo6) * lamTo7; double nY = y1 + y2 + y3 + y4; //%nY = nY + 500000+L0/3*1000000; %<-- potsdam datum return new V3d(nY, nX, lonLatHeight.Z); //<-- Laenge, Breite, Hoehe } public static V3d GaussKruegerPlaneToEllipsoid( V3d rightHeightAlt, GeoEllipsoid ellipsoid, double referenceMeridan ) { double a = ellipsoid.A; double b = ellipsoid.B; double Y = rightHeightAlt.X; double X = rightHeightAlt.Y + 5000000; double n = (a - b) / (a + b); double nTo2 = n * n; double nTo3 = nTo2 * n; double nTo4 = nTo3 * n; double nTo5 = nTo4 * n; double c1 = (a + b) / 2.0 * (1.0 + 1.0 / 4.0 * nTo2 * 1.0 / 64.0 * nTo4); double c2 = 3.0 / 2.0 * n - 27.0 / 32.0 * nTo3 - 269.0 / 512.0 * nTo5; double c3 = 21.0 / 16.0 * nTo2 - 55.0 / 32 * nTo4; double c4 = 151.0 / 96.0 * nTo3 - 417.0 / 128.0 * nTo5; double c5 = 1097.0 / 512.0 * nTo4; double c0 = X / c1; //latitude footprint in radians double fPHI = c0 + c2 * (2.0 * c0).Sin() + c3 * (4.0 * c0).Sin() + c4 * (6.0 * c0).Sin() + c5 * (8.0 * c0).Sin(); //% second nummerical eccentrencity double e2q = ellipsoid.E2Q; //% auxilary quantity 1 double cosfPHI = fPHI.Cos(); double nuTo2 = e2q * cosfPHI * cosfPHI; double nuTo4 = nuTo2 * nuTo2; //%radius of the curvature in prime vertical double N = (a * a) / (b * (1.0 + nuTo2).Sqrt()); double Nto2 = N * N; double Nto3 = Nto2 * N; double Nto4 = Nto3 * N; double Nto5 = Nto4 * N; double Nto6 = Nto5 * N; double Nto7 = Nto6 * N; double Nto8 = Nto7 * N; //% auxilary quantity 2 double t = fPHI.Tan(); // t to powers double tTo2 = t * t; double tTo4 = tTo2 * tTo2; double tTo6 = tTo2 * tTo4; double Yto2 = Y * Y; double Yto3 = Yto2 * Y; double Yto4 = Yto3 * Y; double Yto5 = Yto4 * Y; double Yto6 = Yto5 * Y; double Yto7 = Yto6 * Y; double Yto8 = Yto7 * Y; double p1 = fPHI + (t / (2.0 * Nto2)) * (-1.0 - nuTo2) * Yto2; double p2 = (t / (24.0 * Nto4)) * (5.0 + 3.0 * tTo2 + 6.0 * nuTo2 - 6 * tTo2 * nuTo2 - 3.0 * nuTo4 - 9.0 * tTo2 * nuTo4) * Yto4; double p3 = (t / (720.0 * Nto6)) * (-61.0 - 90.0 * tTo2 - 45.0 * tTo4 - 107.0 * nuTo2 + 162.0 * tTo2 * nuTo2 + 45.0 * tTo4 * nuTo2) * Yto6; double p4 = (t / (40320.0 * Nto8)) * (1385.0 + 3633.0 * tTo2 + 4045 * tTo4 + 1575 * tTo6) * Yto8; double phi = p1 + p2 + p3 + p4; double l1 = Y / (cosfPHI * N); double l2 = ((-1.0 - 2.0 * tTo2 - nuTo2) * Yto3) / (6.0 * Nto3 * cosfPHI); double l3 = (5.0 + 28.0 * tTo2 + 24 * tTo4 + 6.0 * nuTo2 + 8.0 * tTo2 * nuTo2) * Yto5 / (120.0 * Nto5 * cosfPHI); double l4 = (-61.0 - 662 * tTo2 - 1320 * tTo4 - 720 * tTo6) * Yto7 / (5040.0 * Nto7 * cosfPHI); double lam = l1 + l2 + l3 + l4; double lat = Conversion.DegreesFromRadians(phi); double lon = Conversion.DegreesFromRadians(lam) + referenceMeridan; return new V3d(lon, lat, rightHeightAlt.Z); } #endregion #region Amap conversions // amap info for OK50 map // utm zone 33 // easting 68500 - 682900 (low = east) // northing 5104320 - 5432000 (low = south) // no pixel offsets // 0/65535 ------------------------122880/65535 // | | // | | // | | // |----x/y | // | | | // | | | // 0/0------------------------------122880/0 // conversion into pixel coordinates // map size: width 122880 px, height 65535 px // given: utm wgs84 coordinates of zone 33 (important, zone 32 does not work // and needs to be converted into zone 33 first; this is only required for parts // of western austria). // x = (easting - 68500.0) / 5.0 // y = (northing - 5104320) / 5.0 public static V2i OK50PixelCoordinatesFromWgs84(int easting, int northing) => new V2i((easting - 68500) / 5.0, (northing - 5104320) / 5.0); public static V2i OK50PixelCoordinatesFromWgs84(V2i wgs84) => OK50PixelCoordinatesFromWgs84(wgs84.X, wgs84.Y); public static V2i Wgs84FromOK50PixelCoordinates(V2i pos) => new V2i(pos.X * 5 + 68500, pos.Y * 5 + 5104320); #endregion #region Distance public static double DistanceVincentyWgs84(V2d lonLat0, V2d lonLat1) => DistanceVincenty(lonLat0, lonLat1, GeoEllipsoid.Wgs84); /// /// Vincenty Inverse Solution of Geodesics on the Ellipsoid (c) Chris Veness 2002-2012 /// from: Vincenty inverse formula - T Vincenty, "Direct and Inverse Solutions of Geodesics on the /// Ellipsoid with application of nested equations", Survey Review, vol XXII no 176, 1975 /// http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf /// Calculates geodetic distance between two points on the WGS 84 /// ellipsoid specified by latitude/longitude using Vincenty /// inverse formula for ellipsoids. /// public static double DistanceVincenty( V2d lonLat0, V2d lonLat1, GeoEllipsoid ellipsoid) { double a = ellipsoid.A, b = ellipsoid.B, f = ellipsoid.F; double L = (lonLat1.X - lonLat0.X) * RadiansPerDegree; double U1 = Atan((1 - f) * Tan(lonLat0.Y * RadiansPerDegree)); double U2 = Atan((1 - f) * Tan(lonLat1.Y * RadiansPerDegree)); double sinU1 = Sin(U1), cosU1 = Cos(U1); double sinU2 = Sin(U2), cosU2 = Cos(U2); double lambda = L, lambdaP; int iterLimit = 100; double sinSigma, cosSigma, sigma, cosSqAlpha, cos2SigmaM; do { double sinLambda = Sin(lambda), cosLambda = Cos(lambda); sinSigma = Sqrt((cosU2 * sinLambda) * (cosU2 * sinLambda) + (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) * (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda)); if (sinSigma == 0) return 0; // co-incident points cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda; sigma = Atan2(sinSigma, cosSigma); double sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma; cosSqAlpha = 1 - sinAlpha * sinAlpha; cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha; if (double.IsNaN(cos2SigmaM)) cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (§6) double C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha)); lambdaP = lambda; lambda = L + (1 - C) * f * sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM))); } while (Abs(lambda - lambdaP) > 1e-12 && --iterLimit > 0); if (iterLimit == 0) return double.NaN; // formula failed to converge double uSq = cosSqAlpha * (a * a - b * b) / (b * b); double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq))); double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq))); double deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM))); double s = b * A * (sigma - deltaSigma); return s; } public static double DistanceVincentyWgs84( V2d lonLat0, V2d lonLat1, out double brng0, out double brng1) => DistanceVincenty(lonLat0, lonLat1, GeoEllipsoid.Wgs84, out brng0, out brng1); /// /// Vincenty Inverse Solution of Geodesics on the Ellipsoid (c) Chris Veness 2002-2012 /// from: Vincenty inverse formula - T Vincenty, "Direct and Inverse Solutions of Geodesics on the /// Ellipsoid with application of nested equations", Survey Review, vol XXII no 176, 1975 /// http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf /// Calculates geodetic distance between two points on the WGS 84 /// ellipsoid specified by latitude/longitude using Vincenty /// inverse formula for ellipsoids. /// public static double DistanceVincenty( V2d lonLat0, V2d lonLat1, GeoEllipsoid ellipsoid, out double brng0, out double brng1) { double a = ellipsoid.A, b = ellipsoid.B, f = ellipsoid.F; double L = (lonLat1.X - lonLat0.X) * RadiansPerDegree; double U1 = Atan((1 - f) * Tan(lonLat0.Y * RadiansPerDegree)); double U2 = Atan((1 - f) * Tan(lonLat1.Y * RadiansPerDegree)); double sinU1 = Sin(U1), cosU1 = Cos(U1); double sinU2 = Sin(U2), cosU2 = Cos(U2); double lambda = L, lambdaP; int iterLimit = 100; double sinSigma, cosSigma, sinLambda, cosLambda, sigma, cosSqAlpha, cos2SigmaM; do { sinLambda = Sin(lambda); cosLambda = Cos(lambda); sinSigma = Sqrt((cosU2 * sinLambda) * (cosU2 * sinLambda) + (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) * (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda)); if (sinSigma == 0) { brng0 = double.NaN; brng1 = double.NaN; return 0; // co-incident points } cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda; sigma = Atan2(sinSigma, cosSigma); var sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma; cosSqAlpha = 1 - sinAlpha * sinAlpha; cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha; if (double.IsNaN(cos2SigmaM)) cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (§6) var C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha)); lambdaP = lambda; lambda = L + (1 - C) * f * sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM))); } while (Abs(lambda - lambdaP) > 1e-12 && --iterLimit > 0); if (iterLimit == 0) { brng0 = double.NaN; brng1 = double.NaN; return double.NaN; // formula failed to converge } var uSq = cosSqAlpha * (a * a - b * b) / (b * b); var A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq))); var B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq))); var deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM))); var s = b * A * (sigma - deltaSigma); var fwdAz = Atan2(cosU2 * sinLambda, cosU1 * sinU2 - sinU1 * cosU2 * cosLambda); var revAz = Atan2(cosU1 * sinLambda, -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda); brng0 = fwdAz * DegreesPerRadian; brng1 = revAz * DegreesPerRadian; return s; } public static V2d DirectionVincentyWgs84(V2d lonLat, double brng, double dist) => DirectionVincenty(lonLat, brng, dist, GeoEllipsoid.Wgs84, out double finalBrng); /// /// Vincenty Direct Solution of Geodesics on the Ellipsoid (c) Chris Veness 2005-2012 /// from: Vincenty direct formula - T Vincenty, "Direct and Inverse Solutions of Geodesics on the /// Ellipsoid with application of nested equations", Survey Review, vol XXII no 176, 1975 /// http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf /// public static V2d DirectionVincenty(V2d lonLat, double brng, double dist, GeoEllipsoid gel) => DirectionVincenty(lonLat, brng, dist, gel, out double finalBrng); public static V2d DirectionVincentyWgs84( V2d lonLat, double brng, double dist, out double finalBrng) => DirectionVincenty(lonLat, brng, dist, GeoEllipsoid.Wgs84, out finalBrng); /// /// Vincenty Direct Solution of Geodesics on the Ellipsoid (c) Chris Veness 2005-2012 /// from: Vincenty direct formula - T Vincenty, "Direct and Inverse Solutions of Geodesics on the /// Ellipsoid with application of nested equations", Survey Review, vol XXII no 176, 1975 /// http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf /// public static V2d DirectionVincenty(V2d lonLat, double brng, double dist, GeoEllipsoid gel, out double finalBrng) { double a = gel.A, b = gel.B, f = gel.F; // WGS-84 ellipsiod var s = dist; var alpha1 = brng * RadiansPerDegree; var sinAlpha1 = Sin(alpha1); var cosAlpha1 = Cos(alpha1); var tanU1 = (1 - f) * Tan(lonLat.Y * RadiansPerDegree); double cosU1 = 1 / Sqrt((1 + tanU1 * tanU1)), sinU1 = tanU1 * cosU1; var sigma1 = Atan2(tanU1, cosAlpha1); var sinAlpha = cosU1 * sinAlpha1; var cosSqAlpha = 1 - sinAlpha * sinAlpha; var uSq = cosSqAlpha * (a * a - b * b) / (b * b); var A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq))); var B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq))); var sigma = s / (b * A); var sigmaP = 2 * PI; double sinSigma = 0, cosSigma = 0, cos2SigmaM = 0; while (Abs(sigma - sigmaP) > 1e-12) { cos2SigmaM = Cos(2 * sigma1 + sigma); sinSigma = Sin(sigma); cosSigma = Cos(sigma); var deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM))); sigmaP = sigma; sigma = s / (b * A) + deltaSigma; } var tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1; var lat2 = Atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1, (1 - f) * Sqrt(sinAlpha * sinAlpha + tmp * tmp)); var lambda = Atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1); var C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha)); var L = lambda - (1 - C) * f * sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM))); var lon2 = (lonLat.X * RadiansPerDegree + L + 3 * PI) % (2 * PI) - PI; // normalise to -180...+180 var revAz = Atan2(sinAlpha, -tmp); // final bearing, if required finalBrng = revAz * DegreesPerRadian; return new V2d(lon2 * DegreesPerRadian, lat2 * DegreesPerRadian); } public static double ComputeLength(V2d[] lonLatArray, GeoEllipsoid gel, params int[] indexArray) { var pc = indexArray.Length; var p0 = lonLatArray[indexArray[0]]; var d = 0.0; for (int i = 1; i < pc; i++) { var p1 = lonLatArray[indexArray[i]]; d += DistanceVincenty(p0, p1, gel); p0 = p1; } return d; } public static double ComputeLengthWgs84(V2d[] lonLatArray, params int[] indexArray) => ComputeLength(lonLatArray, GeoEllipsoid.Wgs84, indexArray); public static double ComputePerimeter(V2d[] lonLatArray, GeoEllipsoid gel, params int[] indexArray) { var pc = indexArray.Length; var p0 = lonLatArray[indexArray[pc - 1]]; var d = 0.0; for (int i = 0; i < pc; i++) { var p1 = lonLatArray[indexArray[i]]; d += DistanceVincenty(p0, p1, gel); p0 = p1; } return d; } public static double ComputePerimeterWgs84(V2d[] lonLatArray, params int[] indexArray) => ComputePerimeter(lonLatArray, GeoEllipsoid.Wgs84, indexArray); #endregion } } ================================================ FILE: src/Aardvark.Base/Geometry/Algorithms_auto.cs ================================================ using Aardvark.Base.Sorting; using System; using System.Collections.Generic; using System.Linq; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! public static partial class GeometryFun { #region Bresenham /// /// Iterates along Bresenham Discrete Line Raster from P0 to P1. /// Yields each integer position V2i. /// public static IEnumerable BresenhamLineIterator(V2i p0, V2i p1) { int x0 = p0.X, y0 = p0.Y, x1 = p1.X, y1 = p1.Y; int dx, dy; int incx, incy; int balance; if (x1 >= x0) { dx = x1 - x0; incx = 1; } else { dx = x0 - x1; incx = -1; } if (y1 >= y0) { dy = y1 - y0; incy = 1; } else { dy = y0 - y1; incy = -1; } if (dx >= dy) { dy <<= 1; balance = dy - dx; dx <<= 1; while (x0 != x1) { yield return new V2i(x0, y0); if (balance >= 0) { y0 += incy; balance -= dx; } balance += dy; x0 += incx; } yield return new V2i(x0, y0); } else { dx <<= 1; balance = dx - dy; dy <<= 1; while (y0 != y1) { yield return new V2i(x0, y0); if (balance >= 0) { x0 += incx; balance -= dy; } balance += dx; y0 += incy; } yield return new V2i(x0, y0); } } /// /// Iterates along Bresenham discrete line raster from p0 to p1. /// Yields each integer position V2l. /// public static IEnumerable BresenhamLineIterator(V2l p0, V2l p1) { long x0 = p0.X, y0 = p0.Y, x1 = p1.X, y1 = p1.Y; long dx, dy; long incx, incy; long balance; if (x1 >= x0) { dx = x1 - x0; incx = 1; } else { dx = x0 - x1; incx = -1; } if (y1 >= y0) { dy = y1 - y0; incy = 1; } else { dy = y0 - y1; incy = -1; } if (dx >= dy) { dy <<= 1; balance = dy - dx; dx <<= 1; while (x0 != x1) { yield return new V2l(x0, y0); if (balance >= 0) { y0 += incy; balance -= dx; } balance += dy; x0 += incx; } yield return new V2l(x0, y0); } else { dx <<= 1; balance = dx - dy; dy <<= 1; while (y0 != y1) { yield return new V2l(x0, y0); if (balance >= 0) { x0 += incx; balance -= dy; } balance += dx; y0 += incy; } yield return new V2l(x0, y0); } } #endregion #region Convex Hull in 2D (float) /// /// Returns those indices of the supplied index array to the supplied /// points set that constitute the convex hull. The returned indices /// enumerate the convex hull in counter-clockwise fashion. /// Implemented via Andrew's monotone chain 2d convex hull algorithm. /// public static IndexPolygon2f ConvexHullIndexPolygon( this int[] indexArray, V2f[] pointArray) { var sortedIndex = indexArray.Copy(); sortedIndex.PermutationQuickSort(pointArray, Vec.LexicalCompare); return ConvexHullIndexPolygonOfSortedIndexArray(sortedIndex, pointArray); } /// /// Returns the indices of the points of the supplied point set that /// constitute the convex hull. The returned indices enumerate the /// convex hull in counter-clockwise fashion. Implemented via Andrew's /// monotone chain 2d convex hull algorithm. /// public static IndexPolygon2f ConvexHullIndexPolygon(this V2f[] pointArray, int pointCount = 0) { if (pointCount == 0) pointCount = pointArray.Length; var sortedIndex = new int[pointCount].SetByIndex(i => i); sortedIndex.PermutationQuickSort(pointArray, Vec.LexicalCompare); return ConvexHullIndexPolygonOfSortedIndexArray(sortedIndex, pointArray); } private static IndexPolygon2f ConvexHullIndexPolygonOfSortedIndexArray(int[] idx, V2f[] p) { // Copyright 2001, softSurfer (www.softsurfer.com) // This code may be freely used and modified for any purpose // providing that this copyright notice is included with it. // SoftSurfer makes no warranty for this code, and cannot be held // liable for any real or imagined damage resulting from its use. // Users of this code must verify correctness for their application. int n = idx.Length; var hull = new int[n + 1]; // the output array hull[] will be used as the stack int bot = 0, top = -1; // indices for bottom and top of the stack int i; // array scan index // Get the indices of points with min x-coord and min|max y-coord int minmin = 0, minmax; float xmin = p[idx[0]].X; for (i = 1; i < n; i++) if (p[idx[i]].X != xmin) break; minmax = i - 1; if (minmax == n - 1) { // degenerate case: all x-coords == xmin hull[++top] = idx[minmin]; if (p[idx[minmax]].Y != p[idx[minmin]].Y) // a nontrivial segment hull[++top] = idx[minmax]; return new IndexPolygon2f(hull, 0, top + 1, p); } // get the indices of points with max x-coord and min|max y-coord int maxmin, maxmax = n - 1; float xmax = p[idx[maxmax]].X; for (i = n - 2; i >= 0; i--) if (p[idx[i]].X != xmax) break; maxmin = i + 1; // compute the lower hull on the stack hull hull[++top] = idx[minmin]; // push minmin point onto stack i = minmax; var pimaxmin = p[idx[maxmin]]; var phtop = p[hull[top]]; while (++i <= maxmin) { int ii = idx[i]; var pii = p[ii]; // ignore points above or on line p[idx[minmin], p[idx[maxmin]] if (pii.PosLeftOfLineValue(phtop, pimaxmin) >= 0 && i < maxmin) continue; while (top > 0) // at least 2 points on the stack { // test if p[ii] is left of the line at the stack top if (pii.PosLeftOfLineValue(p[hull[top - 1]], p[hull[top]]) > 0) break; // p[ii] is a new hull vertex top--; // pop top point off stack } hull[++top] = ii; // push p[ii] onto stack phtop = pii; } // compute the upper hull on the stack hull above the bottom hull if (maxmax != maxmin) // if distinct xmax points hull[++top] = idx[maxmax]; // push maxmax point onto stack bot = top; // the bottom point of the upper hull stack i = maxmin; var piminmax = p[idx[minmax]]; phtop = p[hull[top]]; while (--i >= minmax) { int ii = idx[i]; var pii = p[ii]; // ignore points below the line p[idx[maxmax]], p[idx[minmax]] if (pii.PosLeftOfLineValue(phtop, piminmax) >= 0 && i > minmax) continue; while (top > bot) // at least 2 points on the upper stack { // test if p[ii] is left of the line at the stack top if (pii.PosLeftOfLineValue(p[hull[top - 1]], p[hull[top]]) > 0) break; // p[ii] is a new hull vertex top--; // pop top point off stack } hull[++top] = ii; // push p[ii] onto stack phtop = pii; } if (minmax != minmin) ++top; return new IndexPolygon2f(hull, 0, top, p); } #endregion #region Ramer–Douglas–Peucker (float) /// /// Returns those indices of the supplied polyline that constitute /// the simplified polyline. A larger epsilon results in a simpler polyline. /// Implemented via the Ramer–Douglas–Peucker algorithm. /// http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm /// public static int[] Simplify(this V2f[] polyline, float epsilon) { return Simplify(polyline, epsilon, 0, polyline.Length - 1); } private static int[] Simplify(V2f[] polyline, float eps, int indexFirst, int indexLast) { if (indexFirst == indexLast - 1) return new[] { indexFirst, indexLast }; var pFirst = polyline[indexFirst]; var pLast = polyline[indexLast]; var line = new Line2f(pFirst, pLast); float distMax = 0; var indexMax = 0; for (var i = indexFirst + 1; i < indexLast; i++) { var d = line.GetDistanceToLine(polyline[i]); if (d > distMax) { distMax = d; indexMax = i; } } if (distMax < eps) return new[] { indexFirst, indexLast }; var left = Simplify(polyline, eps, indexFirst, indexMax); var right = Simplify(polyline, eps, indexMax, indexLast); var result = new int[left.Length + right.Length - 1]; left.CopyTo(result, 0); right.CopyTo(1, right.Length - 1, result, left.Length); return result; } #endregion #region Delaunay Triangulation O(n^2/3) (float) /// /// Compute the Delaunay triangulation of the supplied x-sorted point /// array in the XY-plane and return a triangle index array with /// counter-clockwise triangles. /// public static int[] TriangulateXY(this V3f[] xSortedPoints) { int vc = xSortedPoints.Length; V2f[] pxy = new V2f[vc + 4].SetByIndexLong(0, vc, i => xSortedPoints[i].XY); return Triangulate2d(pxy); } /// /// Compute the Delaunay triangulation of the supplied x-sorted point /// array and return a triangle index array with counter-clockwise /// triangles. /// public static int[] Triangulate(this V2f[] xSortedPoints) { int vc = xSortedPoints.Length; V2f[] pxy = new V2f[vc + 4].SetByIndexLong(0, vc, i => xSortedPoints[i]); return Triangulate2d(pxy); } /// /// Internal wrapper around the Delaunay triangulation that constructs /// the triangle index array. /// private static int[] Triangulate2d(V2f[] pa) { Triangulate2d(pa, out Triangle1i[] tri, out int tc); var ia = new int[3 * tc]; for (int ti = 0, i = 0; ti < tc; ti++) { var tr = tri[ti]; ia[i++] = tr.I0; ia[i++] = tr.I1; ia[i++] = tr.I2; } return ia; } /// /// Compute the Delaunay triangluation of the supplied points. Note that /// the supplied point array must be by 3 larger than the actual number of /// points. /// private static void Triangulate2d(V2f[] pa, out Triangle1i[] ta, out int triangleCount) { int vc = pa.Length - 4; int tcMax = 2 * vc + 2; // sharp upper bound with no degenerates int ecMax = 6 * vc - 3; // sharp bound: last step replaces all tris ta = new Triangle1i[tcMax]; var ra = new float[tcMax]; var ca = new V2f[tcMax]; var ea = new Line1i[ecMax]; // -------------------------------------- set up the supertriangle ta[0] = new Triangle1i(vc, vc + 2, vc + 1); ra[0] = -1; ta[1] = new Triangle1i(vc, vc + 3, vc + 2); ra[1] = -1; int tc = 2, cc = 0; // triangle count, complete count // ------------- superquad vertices at the end of vertex array var box = new Box2f(pa.Take(vc)).EnlargedBy(0.1f); V2f center = box.Center, size = box.Size; pa[vc + 0] = box.Min; pa[vc + 1] = new V2f(box.Min.X, box.Max.Y); pa[vc + 2] = box.Max; pa[vc + 3] = new V2f(box.Max.X, box.Min.Y); // ------------------------------ include the points one at a time for (int i = 0; i < vc; i++) { V2f p = pa[i]; int ec = 0; /* if the point lies inside the circumcircle then the triangle is removed and its edges are added to the edge array */ for (int ti = cc; ti < tc; ti++) { var tr = ta[ti]; float r2 = ra[ti]; if (r2 < 0) { Triangle2f.ComputeCircumCircleSquared( pa[tr.I0], pa[tr.I1], pa[tr.I2], out center, out r2); ra[ti] = r2; ca[ti] = center; } else center = ca[ti]; // ---------------- include this if points are sorted by X if (center.X < p.X && (p.X - center.X).Square() > r2) { Fun.Swap(ref ta[ti], ref ta[cc]); ra[ti] = ra[cc]; ca[ti] = ca[cc]; ++cc; continue; } if (Vec.DistanceSquared(p, center) <= r2) { int nec = ec + 3; if (nec >= ecMax) { ecMax = Fun.Max(nec, (int)(1.1f * (float)ecMax)); Array.Resize(ref ea, ecMax); } ea[ec] = tr.Line01; ea[ec + 1] = tr.Line12; ea[ec + 2] = tr.Line20; --tc; ec = nec; ta[ti] = ta[tc]; ra[ti] = ra[tc]; ca[ti] = ca[tc]; --ti; } } // ---------------------------------------- tag multiple edges for (int ei = 0; ei < ec - 1; ei++) for (int ej = ei + 1; ej < ec; ej++) if (ea[ei].I0 == ea[ej].I1 && ea[ei].I1 == ea[ej].I0) { ea[ei] = Line1i.Invalid; ea[ej] = Line1i.Invalid; } // ------------------ form new triangles for the current point for (int ei = 0; ei < ec; ei++) { var e = ea[ei]; if (e.I0 < 0 || e.I1 < 0) continue; // skip tagged edges if (tc >= tcMax) // necessary for degenerate cases { tcMax = Fun.Max(tcMax + 1, (int)(1.1 * (float)tcMax)); Array.Resize(ref ta, tcMax); Array.Resize(ref ra, tcMax); Array.Resize(ref ca, tcMax); } ta[tc] = new Triangle1i(e.I0, e.I1, i); ra[tc++] = -1; } } // ------------------ remove triangles with supertriangle vertices for (int ti = 0; ti < tc; ti++) if (ta[ti].I0 >= vc || ta[ti].I1 >= vc || ta[ti].I2 >= vc) ta[ti--] = ta[--tc]; triangleCount = tc; } #endregion #region Box containing Percentile of points (float) /// /// Compute a box containing approximately the supplied percentile /// of points, by performing a separate sorting operation on each /// coordinate. /// public static Box3f ComputeBoxContaining( this IEnumerable points, float percentile) { if (percentile < 0 || percentile > 1) throw new ArgumentOutOfRangeException(); var pa = points.ToArray(); long offset = (long)(pa.Length * percentile) / 2; long mid = pa.Length / 2; long lo = mid - offset, hi = mid + offset; var xa = pa.Map(v => v.X); xa.QuickSortAscending(); var ya = pa.Map(v => v.Y); ya.QuickSortAscending(); var za = pa.Map(v => v.Z); za.QuickSortAscending(); return new Box3f(new V3f(xa[lo], ya[lo], za[lo]), new V3f(xa[hi], ya[hi], za[hi])); } #endregion #region Convex Hull in 2D (double) /// /// Returns those indices of the supplied index array to the supplied /// points set that constitute the convex hull. The returned indices /// enumerate the convex hull in counter-clockwise fashion. /// Implemented via Andrew's monotone chain 2d convex hull algorithm. /// public static IndexPolygon2d ConvexHullIndexPolygon( this int[] indexArray, V2d[] pointArray) { var sortedIndex = indexArray.Copy(); sortedIndex.PermutationQuickSort(pointArray, Vec.LexicalCompare); return ConvexHullIndexPolygonOfSortedIndexArray(sortedIndex, pointArray); } /// /// Returns the indices of the points of the supplied point set that /// constitute the convex hull. The returned indices enumerate the /// convex hull in counter-clockwise fashion. Implemented via Andrew's /// monotone chain 2d convex hull algorithm. /// public static IndexPolygon2d ConvexHullIndexPolygon(this V2d[] pointArray, int pointCount = 0) { if (pointCount == 0) pointCount = pointArray.Length; var sortedIndex = new int[pointCount].SetByIndex(i => i); sortedIndex.PermutationQuickSort(pointArray, Vec.LexicalCompare); return ConvexHullIndexPolygonOfSortedIndexArray(sortedIndex, pointArray); } private static IndexPolygon2d ConvexHullIndexPolygonOfSortedIndexArray(int[] idx, V2d[] p) { // Copyright 2001, softSurfer (www.softsurfer.com) // This code may be freely used and modified for any purpose // providing that this copyright notice is included with it. // SoftSurfer makes no warranty for this code, and cannot be held // liable for any real or imagined damage resulting from its use. // Users of this code must verify correctness for their application. int n = idx.Length; var hull = new int[n + 1]; // the output array hull[] will be used as the stack int bot = 0, top = -1; // indices for bottom and top of the stack int i; // array scan index // Get the indices of points with min x-coord and min|max y-coord int minmin = 0, minmax; double xmin = p[idx[0]].X; for (i = 1; i < n; i++) if (p[idx[i]].X != xmin) break; minmax = i - 1; if (minmax == n - 1) { // degenerate case: all x-coords == xmin hull[++top] = idx[minmin]; if (p[idx[minmax]].Y != p[idx[minmin]].Y) // a nontrivial segment hull[++top] = idx[minmax]; return new IndexPolygon2d(hull, 0, top + 1, p); } // get the indices of points with max x-coord and min|max y-coord int maxmin, maxmax = n - 1; double xmax = p[idx[maxmax]].X; for (i = n - 2; i >= 0; i--) if (p[idx[i]].X != xmax) break; maxmin = i + 1; // compute the lower hull on the stack hull hull[++top] = idx[minmin]; // push minmin point onto stack i = minmax; var pimaxmin = p[idx[maxmin]]; var phtop = p[hull[top]]; while (++i <= maxmin) { int ii = idx[i]; var pii = p[ii]; // ignore points above or on line p[idx[minmin], p[idx[maxmin]] if (pii.PosLeftOfLineValue(phtop, pimaxmin) >= 0 && i < maxmin) continue; while (top > 0) // at least 2 points on the stack { // test if p[ii] is left of the line at the stack top if (pii.PosLeftOfLineValue(p[hull[top - 1]], p[hull[top]]) > 0) break; // p[ii] is a new hull vertex top--; // pop top point off stack } hull[++top] = ii; // push p[ii] onto stack phtop = pii; } // compute the upper hull on the stack hull above the bottom hull if (maxmax != maxmin) // if distinct xmax points hull[++top] = idx[maxmax]; // push maxmax point onto stack bot = top; // the bottom point of the upper hull stack i = maxmin; var piminmax = p[idx[minmax]]; phtop = p[hull[top]]; while (--i >= minmax) { int ii = idx[i]; var pii = p[ii]; // ignore points below the line p[idx[maxmax]], p[idx[minmax]] if (pii.PosLeftOfLineValue(phtop, piminmax) >= 0 && i > minmax) continue; while (top > bot) // at least 2 points on the upper stack { // test if p[ii] is left of the line at the stack top if (pii.PosLeftOfLineValue(p[hull[top - 1]], p[hull[top]]) > 0) break; // p[ii] is a new hull vertex top--; // pop top point off stack } hull[++top] = ii; // push p[ii] onto stack phtop = pii; } if (minmax != minmin) ++top; return new IndexPolygon2d(hull, 0, top, p); } #endregion #region Ramer–Douglas–Peucker (double) /// /// Returns those indices of the supplied polyline that constitute /// the simplified polyline. A larger epsilon results in a simpler polyline. /// Implemented via the Ramer–Douglas–Peucker algorithm. /// http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm /// public static int[] Simplify(this V2d[] polyline, double epsilon) { return Simplify(polyline, epsilon, 0, polyline.Length - 1); } private static int[] Simplify(V2d[] polyline, double eps, int indexFirst, int indexLast) { if (indexFirst == indexLast - 1) return new[] { indexFirst, indexLast }; var pFirst = polyline[indexFirst]; var pLast = polyline[indexLast]; var line = new Line2d(pFirst, pLast); double distMax = 0; var indexMax = 0; for (var i = indexFirst + 1; i < indexLast; i++) { var d = line.GetDistanceToLine(polyline[i]); if (d > distMax) { distMax = d; indexMax = i; } } if (distMax < eps) return new[] { indexFirst, indexLast }; var left = Simplify(polyline, eps, indexFirst, indexMax); var right = Simplify(polyline, eps, indexMax, indexLast); var result = new int[left.Length + right.Length - 1]; left.CopyTo(result, 0); right.CopyTo(1, right.Length - 1, result, left.Length); return result; } #endregion #region Delaunay Triangulation O(n^2/3) (double) /// /// Compute the Delaunay triangulation of the supplied x-sorted point /// array in the XY-plane and return a triangle index array with /// counter-clockwise triangles. /// public static int[] TriangulateXY(this V3d[] xSortedPoints) { int vc = xSortedPoints.Length; V2d[] pxy = new V2d[vc + 4].SetByIndexLong(0, vc, i => xSortedPoints[i].XY); return Triangulate2d(pxy); } /// /// Compute the Delaunay triangulation of the supplied x-sorted point /// array and return a triangle index array with counter-clockwise /// triangles. /// public static int[] Triangulate(this V2d[] xSortedPoints) { int vc = xSortedPoints.Length; V2d[] pxy = new V2d[vc + 4].SetByIndexLong(0, vc, i => xSortedPoints[i]); return Triangulate2d(pxy); } /// /// Internal wrapper around the Delaunay triangulation that constructs /// the triangle index array. /// private static int[] Triangulate2d(V2d[] pa) { Triangulate2d(pa, out Triangle1i[] tri, out int tc); var ia = new int[3 * tc]; for (int ti = 0, i = 0; ti < tc; ti++) { var tr = tri[ti]; ia[i++] = tr.I0; ia[i++] = tr.I1; ia[i++] = tr.I2; } return ia; } /// /// Compute the Delaunay triangluation of the supplied points. Note that /// the supplied point array must be by 3 larger than the actual number of /// points. /// private static void Triangulate2d(V2d[] pa, out Triangle1i[] ta, out int triangleCount) { int vc = pa.Length - 4; int tcMax = 2 * vc + 2; // sharp upper bound with no degenerates int ecMax = 6 * vc - 3; // sharp bound: last step replaces all tris ta = new Triangle1i[tcMax]; var ra = new double[tcMax]; var ca = new V2d[tcMax]; var ea = new Line1i[ecMax]; // -------------------------------------- set up the supertriangle ta[0] = new Triangle1i(vc, vc + 2, vc + 1); ra[0] = -1; ta[1] = new Triangle1i(vc, vc + 3, vc + 2); ra[1] = -1; int tc = 2, cc = 0; // triangle count, complete count // ------------- superquad vertices at the end of vertex array var box = new Box2d(pa.Take(vc)).EnlargedBy(0.1); V2d center = box.Center, size = box.Size; pa[vc + 0] = box.Min; pa[vc + 1] = new V2d(box.Min.X, box.Max.Y); pa[vc + 2] = box.Max; pa[vc + 3] = new V2d(box.Max.X, box.Min.Y); // ------------------------------ include the points one at a time for (int i = 0; i < vc; i++) { V2d p = pa[i]; int ec = 0; /* if the point lies inside the circumcircle then the triangle is removed and its edges are added to the edge array */ for (int ti = cc; ti < tc; ti++) { var tr = ta[ti]; double r2 = ra[ti]; if (r2 < 0) { Triangle2d.ComputeCircumCircleSquared( pa[tr.I0], pa[tr.I1], pa[tr.I2], out center, out r2); ra[ti] = r2; ca[ti] = center; } else center = ca[ti]; // ---------------- include this if points are sorted by X if (center.X < p.X && (p.X - center.X).Square() > r2) { Fun.Swap(ref ta[ti], ref ta[cc]); ra[ti] = ra[cc]; ca[ti] = ca[cc]; ++cc; continue; } if (Vec.DistanceSquared(p, center) <= r2) { int nec = ec + 3; if (nec >= ecMax) { ecMax = Fun.Max(nec, (int)(1.1 * (double)ecMax)); Array.Resize(ref ea, ecMax); } ea[ec] = tr.Line01; ea[ec + 1] = tr.Line12; ea[ec + 2] = tr.Line20; --tc; ec = nec; ta[ti] = ta[tc]; ra[ti] = ra[tc]; ca[ti] = ca[tc]; --ti; } } // ---------------------------------------- tag multiple edges for (int ei = 0; ei < ec - 1; ei++) for (int ej = ei + 1; ej < ec; ej++) if (ea[ei].I0 == ea[ej].I1 && ea[ei].I1 == ea[ej].I0) { ea[ei] = Line1i.Invalid; ea[ej] = Line1i.Invalid; } // ------------------ form new triangles for the current point for (int ei = 0; ei < ec; ei++) { var e = ea[ei]; if (e.I0 < 0 || e.I1 < 0) continue; // skip tagged edges if (tc >= tcMax) // necessary for degenerate cases { tcMax = Fun.Max(tcMax + 1, (int)(1.1 * (double)tcMax)); Array.Resize(ref ta, tcMax); Array.Resize(ref ra, tcMax); Array.Resize(ref ca, tcMax); } ta[tc] = new Triangle1i(e.I0, e.I1, i); ra[tc++] = -1; } } // ------------------ remove triangles with supertriangle vertices for (int ti = 0; ti < tc; ti++) if (ta[ti].I0 >= vc || ta[ti].I1 >= vc || ta[ti].I2 >= vc) ta[ti--] = ta[--tc]; triangleCount = tc; } #endregion #region Box containing Percentile of points (double) /// /// Compute a box containing approximately the supplied percentile /// of points, by performing a separate sorting operation on each /// coordinate. /// public static Box3d ComputeBoxContaining( this IEnumerable points, double percentile) { if (percentile < 0 || percentile > 1) throw new ArgumentOutOfRangeException(); var pa = points.ToArray(); long offset = (long)(pa.Length * percentile) / 2; long mid = pa.Length / 2; long lo = mid - offset, hi = mid + offset; var xa = pa.Map(v => v.X); xa.QuickSortAscending(); var ya = pa.Map(v => v.Y); ya.QuickSortAscending(); var za = pa.Map(v => v.Z); za.QuickSortAscending(); return new Box3d(new V3d(xa[lo], ya[lo], za[lo]), new V3d(xa[hi], ya[hi], za[hi])); } #endregion } } ================================================ FILE: src/Aardvark.Base/Geometry/Algorithms_template.cs ================================================ using Aardvark.Base.Sorting; using System; using System.Collections.Generic; using System.Linq; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! public static partial class GeometryFun { #region Bresenham /// /// Iterates along Bresenham Discrete Line Raster from P0 to P1. /// Yields each integer position V2i. /// public static IEnumerable BresenhamLineIterator(V2i p0, V2i p1) { int x0 = p0.X, y0 = p0.Y, x1 = p1.X, y1 = p1.Y; int dx, dy; int incx, incy; int balance; if (x1 >= x0) { dx = x1 - x0; incx = 1; } else { dx = x0 - x1; incx = -1; } if (y1 >= y0) { dy = y1 - y0; incy = 1; } else { dy = y0 - y1; incy = -1; } if (dx >= dy) { dy <<= 1; balance = dy - dx; dx <<= 1; while (x0 != x1) { yield return new V2i(x0, y0); if (balance >= 0) { y0 += incy; balance -= dx; } balance += dy; x0 += incx; } yield return new V2i(x0, y0); } else { dx <<= 1; balance = dx - dy; dy <<= 1; while (y0 != y1) { yield return new V2i(x0, y0); if (balance >= 0) { x0 += incx; balance -= dy; } balance += dx; y0 += incy; } yield return new V2i(x0, y0); } } /// /// Iterates along Bresenham discrete line raster from p0 to p1. /// Yields each integer position V2l. /// public static IEnumerable BresenhamLineIterator(V2l p0, V2l p1) { long x0 = p0.X, y0 = p0.Y, x1 = p1.X, y1 = p1.Y; long dx, dy; long incx, incy; long balance; if (x1 >= x0) { dx = x1 - x0; incx = 1; } else { dx = x0 - x1; incx = -1; } if (y1 >= y0) { dy = y1 - y0; incy = 1; } else { dy = y0 - y1; incy = -1; } if (dx >= dy) { dy <<= 1; balance = dy - dx; dx <<= 1; while (x0 != x1) { yield return new V2l(x0, y0); if (balance >= 0) { y0 += incy; balance -= dx; } balance += dy; x0 += incx; } yield return new V2l(x0, y0); } else { dx <<= 1; balance = dx - dy; dy <<= 1; while (y0 != y1) { yield return new V2l(x0, y0); if (balance >= 0) { x0 += incx; balance -= dy; } balance += dx; y0 += incy; } yield return new V2l(x0, y0); } } #endregion //# foreach (var isDouble in new[] { false, true }) { //# var rtype = isDouble ? "double" : "float"; //# var tc = isDouble ? "d" : "f"; //# var v2t = "V2" + tc; //# var v3t = "V3" + tc; //# var box2t = "Box2" + tc; //# var line2t = "Line2" + tc; //# var box3t = "Box3" + tc; //# var triangle2t = "Triangle2" + tc; //# var zerodotone = isDouble ? "0.1" : "0.1f"; //# var onedotone = isDouble ? "1.1" : "1.1f"; //# var ipolygon2t = "IndexPolygon2" + tc; #region Convex Hull in 2D (__rtype__) /// /// Returns those indices of the supplied index array to the supplied /// points set that constitute the convex hull. The returned indices /// enumerate the convex hull in counter-clockwise fashion. /// Implemented via Andrew's monotone chain 2d convex hull algorithm. /// public static __ipolygon2t__ ConvexHullIndexPolygon( this int[] indexArray, __v2t__[] pointArray) { var sortedIndex = indexArray.Copy(); sortedIndex.PermutationQuickSort(pointArray, Vec.LexicalCompare); return ConvexHullIndexPolygonOfSortedIndexArray(sortedIndex, pointArray); } /// /// Returns the indices of the points of the supplied point set that /// constitute the convex hull. The returned indices enumerate the /// convex hull in counter-clockwise fashion. Implemented via Andrew's /// monotone chain 2d convex hull algorithm. /// public static __ipolygon2t__ ConvexHullIndexPolygon(this __v2t__[] pointArray, int pointCount = 0) { if (pointCount == 0) pointCount = pointArray.Length; var sortedIndex = new int[pointCount].SetByIndex(i => i); sortedIndex.PermutationQuickSort(pointArray, Vec.LexicalCompare); return ConvexHullIndexPolygonOfSortedIndexArray(sortedIndex, pointArray); } private static __ipolygon2t__ ConvexHullIndexPolygonOfSortedIndexArray(int[] idx, __v2t__[] p) { // Copyright 2001, softSurfer (www.softsurfer.com) // This code may be freely used and modified for any purpose // providing that this copyright notice is included with it. // SoftSurfer makes no warranty for this code, and cannot be held // liable for any real or imagined damage resulting from its use. // Users of this code must verify correctness for their application. int n = idx.Length; var hull = new int[n + 1]; // the output array hull[] will be used as the stack int bot = 0, top = -1; // indices for bottom and top of the stack int i; // array scan index // Get the indices of points with min x-coord and min|max y-coord int minmin = 0, minmax; __rtype__ xmin = p[idx[0]].X; for (i = 1; i < n; i++) if (p[idx[i]].X != xmin) break; minmax = i - 1; if (minmax == n - 1) { // degenerate case: all x-coords == xmin hull[++top] = idx[minmin]; if (p[idx[minmax]].Y != p[idx[minmin]].Y) // a nontrivial segment hull[++top] = idx[minmax]; return new __ipolygon2t__(hull, 0, top + 1, p); } // get the indices of points with max x-coord and min|max y-coord int maxmin, maxmax = n - 1; __rtype__ xmax = p[idx[maxmax]].X; for (i = n - 2; i >= 0; i--) if (p[idx[i]].X != xmax) break; maxmin = i + 1; // compute the lower hull on the stack hull hull[++top] = idx[minmin]; // push minmin point onto stack i = minmax; var pimaxmin = p[idx[maxmin]]; var phtop = p[hull[top]]; while (++i <= maxmin) { int ii = idx[i]; var pii = p[ii]; // ignore points above or on line p[idx[minmin], p[idx[maxmin]] if (pii.PosLeftOfLineValue(phtop, pimaxmin) >= 0 && i < maxmin) continue; while (top > 0) // at least 2 points on the stack { // test if p[ii] is left of the line at the stack top if (pii.PosLeftOfLineValue(p[hull[top - 1]], p[hull[top]]) > 0) break; // p[ii] is a new hull vertex top--; // pop top point off stack } hull[++top] = ii; // push p[ii] onto stack phtop = pii; } // compute the upper hull on the stack hull above the bottom hull if (maxmax != maxmin) // if distinct xmax points hull[++top] = idx[maxmax]; // push maxmax point onto stack bot = top; // the bottom point of the upper hull stack i = maxmin; var piminmax = p[idx[minmax]]; phtop = p[hull[top]]; while (--i >= minmax) { int ii = idx[i]; var pii = p[ii]; // ignore points below the line p[idx[maxmax]], p[idx[minmax]] if (pii.PosLeftOfLineValue(phtop, piminmax) >= 0 && i > minmax) continue; while (top > bot) // at least 2 points on the upper stack { // test if p[ii] is left of the line at the stack top if (pii.PosLeftOfLineValue(p[hull[top - 1]], p[hull[top]]) > 0) break; // p[ii] is a new hull vertex top--; // pop top point off stack } hull[++top] = ii; // push p[ii] onto stack phtop = pii; } if (minmax != minmin) ++top; return new __ipolygon2t__(hull, 0, top, p); } #endregion #region Ramer–Douglas–Peucker (__rtype__) /// /// Returns those indices of the supplied polyline that constitute /// the simplified polyline. A larger epsilon results in a simpler polyline. /// Implemented via the Ramer–Douglas–Peucker algorithm. /// http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm /// public static int[] Simplify(this __v2t__[] polyline, __rtype__ epsilon) { return Simplify(polyline, epsilon, 0, polyline.Length - 1); } private static int[] Simplify(__v2t__[] polyline, __rtype__ eps, int indexFirst, int indexLast) { if (indexFirst == indexLast - 1) return new[] { indexFirst, indexLast }; var pFirst = polyline[indexFirst]; var pLast = polyline[indexLast]; var line = new __line2t__(pFirst, pLast); __rtype__ distMax = 0; var indexMax = 0; for (var i = indexFirst + 1; i < indexLast; i++) { var d = line.GetDistanceToLine(polyline[i]); if (d > distMax) { distMax = d; indexMax = i; } } if (distMax < eps) return new[] { indexFirst, indexLast }; var left = Simplify(polyline, eps, indexFirst, indexMax); var right = Simplify(polyline, eps, indexMax, indexLast); var result = new int[left.Length + right.Length - 1]; left.CopyTo(result, 0); right.CopyTo(1, right.Length - 1, result, left.Length); return result; } #endregion #region Delaunay Triangulation O(n^2/3) (__rtype__) /// /// Compute the Delaunay triangulation of the supplied x-sorted point /// array in the XY-plane and return a triangle index array with /// counter-clockwise triangles. /// public static int[] TriangulateXY(this __v3t__[] xSortedPoints) { int vc = xSortedPoints.Length; __v2t__[] pxy = new __v2t__[vc + 4].SetByIndexLong(0, vc, i => xSortedPoints[i].XY); return Triangulate2d(pxy); } /// /// Compute the Delaunay triangulation of the supplied x-sorted point /// array and return a triangle index array with counter-clockwise /// triangles. /// public static int[] Triangulate(this __v2t__[] xSortedPoints) { int vc = xSortedPoints.Length; __v2t__[] pxy = new __v2t__[vc + 4].SetByIndexLong(0, vc, i => xSortedPoints[i]); return Triangulate2d(pxy); } /// /// Internal wrapper around the Delaunay triangulation that constructs /// the triangle index array. /// private static int[] Triangulate2d(__v2t__[] pa) { Triangulate2d(pa, out Triangle1i[] tri, out int tc); var ia = new int[3 * tc]; for (int ti = 0, i = 0; ti < tc; ti++) { var tr = tri[ti]; ia[i++] = tr.I0; ia[i++] = tr.I1; ia[i++] = tr.I2; } return ia; } /// /// Compute the Delaunay triangluation of the supplied points. Note that /// the supplied point array must be by 3 larger than the actual number of /// points. /// private static void Triangulate2d(__v2t__[] pa, out Triangle1i[] ta, out int triangleCount) { int vc = pa.Length - 4; int tcMax = 2 * vc + 2; // sharp upper bound with no degenerates int ecMax = 6 * vc - 3; // sharp bound: last step replaces all tris ta = new Triangle1i[tcMax]; var ra = new __rtype__[tcMax]; var ca = new __v2t__[tcMax]; var ea = new Line1i[ecMax]; // -------------------------------------- set up the supertriangle ta[0] = new Triangle1i(vc, vc + 2, vc + 1); ra[0] = -1; ta[1] = new Triangle1i(vc, vc + 3, vc + 2); ra[1] = -1; int tc = 2, cc = 0; // triangle count, complete count // ------------- superquad vertices at the end of vertex array var box = new __box2t__(pa.Take(vc)).EnlargedBy(__zerodotone__); __v2t__ center = box.Center, size = box.Size; pa[vc + 0] = box.Min; pa[vc + 1] = new __v2t__(box.Min.X, box.Max.Y); pa[vc + 2] = box.Max; pa[vc + 3] = new __v2t__(box.Max.X, box.Min.Y); // ------------------------------ include the points one at a time for (int i = 0; i < vc; i++) { __v2t__ p = pa[i]; int ec = 0; /* if the point lies inside the circumcircle then the triangle is removed and its edges are added to the edge array */ for (int ti = cc; ti < tc; ti++) { var tr = ta[ti]; __rtype__ r2 = ra[ti]; if (r2 < 0) { __triangle2t__.ComputeCircumCircleSquared( pa[tr.I0], pa[tr.I1], pa[tr.I2], out center, out r2); ra[ti] = r2; ca[ti] = center; } else center = ca[ti]; // ---------------- include this if points are sorted by X if (center.X < p.X && (p.X - center.X).Square() > r2) { Fun.Swap(ref ta[ti], ref ta[cc]); ra[ti] = ra[cc]; ca[ti] = ca[cc]; ++cc; continue; } if (Vec.DistanceSquared(p, center) <= r2) { int nec = ec + 3; if (nec >= ecMax) { ecMax = Fun.Max(nec, (int)(__onedotone__ * (__rtype__)ecMax)); Array.Resize(ref ea, ecMax); } ea[ec] = tr.Line01; ea[ec + 1] = tr.Line12; ea[ec + 2] = tr.Line20; --tc; ec = nec; ta[ti] = ta[tc]; ra[ti] = ra[tc]; ca[ti] = ca[tc]; --ti; } } // ---------------------------------------- tag multiple edges for (int ei = 0; ei < ec - 1; ei++) for (int ej = ei + 1; ej < ec; ej++) if (ea[ei].I0 == ea[ej].I1 && ea[ei].I1 == ea[ej].I0) { ea[ei] = Line1i.Invalid; ea[ej] = Line1i.Invalid; } // ------------------ form new triangles for the current point for (int ei = 0; ei < ec; ei++) { var e = ea[ei]; if (e.I0 < 0 || e.I1 < 0) continue; // skip tagged edges if (tc >= tcMax) // necessary for degenerate cases { tcMax = Fun.Max(tcMax + 1, (int)(1.1 * (__rtype__)tcMax)); Array.Resize(ref ta, tcMax); Array.Resize(ref ra, tcMax); Array.Resize(ref ca, tcMax); } ta[tc] = new Triangle1i(e.I0, e.I1, i); ra[tc++] = -1; } } // ------------------ remove triangles with supertriangle vertices for (int ti = 0; ti < tc; ti++) if (ta[ti].I0 >= vc || ta[ti].I1 >= vc || ta[ti].I2 >= vc) ta[ti--] = ta[--tc]; triangleCount = tc; } #endregion #region Box containing Percentile of points (__rtype__) /// /// Compute a box containing approximately the supplied percentile /// of points, by performing a separate sorting operation on each /// coordinate. /// public static __box3t__ ComputeBoxContaining( this IEnumerable<__v3t__> points, __rtype__ percentile) { if (percentile < 0 || percentile > 1) throw new ArgumentOutOfRangeException(); var pa = points.ToArray(); long offset = (long)(pa.Length * percentile) / 2; long mid = pa.Length / 2; long lo = mid - offset, hi = mid + offset; var xa = pa.Map(v => v.X); xa.QuickSortAscending(); var ya = pa.Map(v => v.Y); ya.QuickSortAscending(); var za = pa.Map(v => v.Z); za.QuickSortAscending(); return new __box3t__(new __v3t__(xa[lo], ya[lo], za[lo]), new __v3t__(xa[hi], ya[hi], za[hi])); } #endregion //# } } } ================================================ FILE: src/Aardvark.Base/Geometry/BbTree.cs ================================================ using Aardvark.Base; using System; using Aardvark.Base.Sorting; namespace Aardvark.Base { public struct BbTreeHit { public int NodeIndex; public double RayT; public BbTreeHit(int nodeIndex, double rayT) { NodeIndex = nodeIndex; RayT = rayT; } } public class BbTree { private int m_nodeCount; private Box3d m_box; private int[] m_indexArray; private int[] m_leafArray; private Box3d[] m_boxes; private Box3dAndFlags[] m_combinedBoxArray; public Box3d[] m_leftBoxArray; public Box3d[] m_rightBoxArray; [Flags] public enum BuildFlags { None, CreateBoxArrays = 0x01, CreateCombinedArray = 0x02, LeafLimit01 = 0x010, LeafLimit04 = 0x040, LeafLimit08 = 0x080, LeafLimit16 = 0x100, LeafLimitMask = 0xff0, Default = CreateBoxArrays | LeafLimit01 } #region Constructor public BbTree(Box3d[] boundingBoxes, BuildFlags buildFlags = BuildFlags.Default, int[] countArray = null) { var count = boundingBoxes.Length; m_combinedBoxArray = null; m_leftBoxArray = null; m_rightBoxArray = null; Report.BeginTimed(c_reportVerbosity, "building bb-tree [{0}]", count); if (count > 1) { m_boxes = boundingBoxes; m_nodeCount = count - 1; var createParams = new InParams { LeafLimit = Fun.Max(1, (int)(buildFlags & BuildFlags.LeafLimitMask) >> 4), LeafCount = 0, BuildFlags = buildFlags, NodeCount = 0, BbArray = boundingBoxes, CountArray = countArray, }; if (createParams.LeafLimit > 1) m_leafArray = new int[2 * count]; m_indexArray = new int[2 * m_nodeCount]; if ((buildFlags & BuildFlags.CreateCombinedArray) != 0) m_combinedBoxArray = new Box3dAndFlags[m_nodeCount]; if ((buildFlags & BuildFlags.CreateBoxArrays) != 0) { m_leftBoxArray = new Box3d[m_nodeCount]; m_rightBoxArray = new Box3d[m_nodeCount]; } m_box = new Box3d(createParams.BbArray); Create(createParams, new int[count].SetByIndex(i => i), 0, count, m_box); if (createParams.LeafLimit > 1) m_leafArray = m_leafArray.Copy(createParams.LeafCount); } else { m_nodeCount = 0; m_box = count > 0 ? new Box3d(boundingBoxes) : Box3d.Invalid; } Report.End(c_reportVerbosity); } #endregion #region Properties public int[] IndexArray { get { return m_indexArray; } } public int[] LeafArray { get { return m_leafArray; } } public int NodeCount { get { return m_nodeCount; } } public Box3d Box3d { get { return m_box; } } public Box3d[] Boxes { get { return m_boxes; } } public Box3d[] LeftBoxArray { get { return m_leftBoxArray; } } public Box3d[] RightBoxArray { get { return m_rightBoxArray; } } public int GetLeft(int i) { return m_indexArray[i * 2]; } public int GetRight(int i) { return m_indexArray[i * 2 + 1]; } #endregion #region Constants private const double c_splitPenalty = 1.0; // 2.0 still OK, but gets slow beyond that private const int c_reportVerbosity = 2; #endregion #region Construction private class InParams { public BuildFlags BuildFlags; public int NodeCount; public int LeafLimit; public Box3d[] BbArray; public int[] CountArray; public int LeafCount; } private int CalculateSplit( InParams inParams, int[] indexArray, int start, int count, Box3d box, out int[] sortedIndexArray, out Box3d leftBox, out Box3d rightBox) { int bestLeft = 0; var bestCost = double.MaxValue; var bestLeftBox = Box3d.Invalid; var bestRightBox = Box3d.Invalid; var bestDim = -1; double invBoxArea = box.SurfaceArea > Constant.PositiveTinyValue ? 1.0 / box.SurfaceArea : 0.0; var iaa = new int[3][].SetByIndex(i => indexArray.Copy(start, count)); for (int d = 0; d < 3; d++) { var ia = iaa[d]; ia.PermutationQuickSortAscending(inParams.BbArray, (ba, i) => ba[i].Center[d]); var bbLeftArray = ia.ScanLeft(Box3d.Invalid, (b, i) => new Box3d(b, inParams.BbArray[i])); var bbRightArray = ia.ScanRight((i, b) => new Box3d(inParams.BbArray[i], b), Box3d.Invalid); long[] cLeftArray = null, cRightArray = null; if (inParams.CountArray != null) { cLeftArray = ia.ScanLeft(0L, (c, i) => c + inParams.CountArray[i]); cRightArray = ia.ScanRight((i, c) => inParams.CountArray[i] + c, 0L); } for (int s = 1; s < count; s++) { var lBox = bbLeftArray[s-1]; var leftP = lBox.SurfaceArea * invBoxArea; var rBox = bbRightArray[s]; var rightP = rBox.SurfaceArea * invBoxArea; long lCount = cLeftArray != null ? cLeftArray[s - 1] : s; long rCount = cRightArray != null ? cRightArray[s] : count - s; var cBox = Box.Intersection(lBox, rBox); var cSize = new V3d(cBox.Max.X > cBox.Min.X ? cBox.Max.X - cBox.Min.X : 0, cBox.Max.Y > cBox.Min.Y ? cBox.Max.Y - cBox.Min.Y : 0, cBox.Max.Z > cBox.Min.Z ? cBox.Max.Z - cBox.Min.Z : 0); var commonP = 2 * (cSize.X * cSize.Y + cSize.X * cSize.Z + cSize.Y * cSize.Z) * invBoxArea; var cost = (leftP + (commonP * c_splitPenalty)) * (1 + lCount) + (rightP + (commonP * c_splitPenalty)) * (1 + rCount); if (cost < bestCost) { bestCost = cost; bestDim = d; bestLeft = s; bestLeftBox = lBox; bestRightBox = rBox; } } } sortedIndexArray = iaa[bestDim]; leftBox = bestLeftBox; rightBox = bestRightBox; return bestLeft; } private int CreateLeaf(InParams inParams, int[] indices, int signedCount) { var index = inParams.LeafCount; if (signedCount > 0) { m_leafArray[index++] = signedCount; indices.CopyTo(m_leafArray, index); inParams.LeafCount = index + signedCount; } else { m_leafArray[index++] = -signedCount; indices.CopyTo(indices.Length + signedCount, -signedCount, m_leafArray, index); inParams.LeafCount = index - signedCount; } return -index; } private int Create(InParams inParams, int[] indices, int start, int count, Box3d box) { int ni = inParams.NodeCount++; int[] sortedIndices; Box3d leftBox, rightBox; var leftCount = CalculateSplit(inParams, indices, start, count, box, out sortedIndices, out leftBox, out rightBox); var rightCount = count - leftCount; m_indexArray[2 * ni] = leftCount > inParams.LeafLimit ? Create(inParams, sortedIndices, 0, leftCount, leftBox) : m_leafArray == null ? -1 - sortedIndices[0] : CreateLeaf(inParams, sortedIndices, leftCount); m_indexArray[2 * ni + 1] = rightCount > inParams.LeafLimit ? Create(inParams, sortedIndices, leftCount, rightCount, rightBox) : m_leafArray == null ? -1 - sortedIndices[count - 1] : CreateLeaf(inParams, sortedIndices, -rightCount); if ((inParams.BuildFlags & BuildFlags.CreateBoxArrays) != 0) { m_leftBoxArray[ni] = leftBox; m_rightBoxArray[ni] = rightBox; } if ((inParams.BuildFlags & BuildFlags.CreateCombinedArray) != 0) m_combinedBoxArray[ni] = new Box3dAndFlags(box, leftBox, rightBox); return ni; } #endregion } } ================================================ FILE: src/Aardvark.Base/Geometry/ClippingFunctions_auto.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Aardvark.Base { public static partial class GeometryFun { #region Helpers (float) public static bool ClosestIntersection(this Polygon2f poly, V2f start, V2f end, out bool enter, out int otherIndex, out V2f p) { float min = float.MaxValue; bool intersects = false; V2f point = V2f.NaN; bool tempenter = false; int tempindex = -1; V2f temppoint = V2f.NaN; float templength = float.MaxValue; Line2f line = new Line2f(start, end); int i = 0; foreach (var l in poly.EdgeLines) { if (line.Intersects(l, 4 * float.Epsilon, out temppoint)) { templength = (temppoint - line.P0).Length; if (templength < min) { tempenter = l.LeftValueOfDir(line.Direction) >= 0; tempindex = i; min = templength; point = temppoint; } intersects = true; } i++; } enter = tempenter; otherIndex = tempindex; p = point; return intersects; } internal static float Closest(this List points, V2f p) { float temp; float min = float.MaxValue; for (int i = 0; i < points.Count; i++) { temp = (p - points[i]).Length; if (temp < min) min = temp; } return min; } internal static bool Intersects(V2f[] poly, V2f p0, V2f p1, ref List known, out bool enter, out int index0, out V2f p) { int index = 0; Line2f l; int i0 = 0; int i1 = 1; for (int i = 1; i <= poly.Length; i++) { if (i < poly.Length) { i0 = i - 1; i1 = i; } else { i0 = poly.Length - 1; i1 = 0; } l = new Line2f(poly[i0], poly[i1]); if (l.Intersects(new Line2f(p0, p1), 4 *float.Epsilon, out p)) { if (!Fun.IsTiny(known.Closest(p))) { enter = (l.LeftValueOfPos(p1) >= -4 *float.Epsilon); index0 = index; return true; } } index++; } p = V2f.NaN; index0 = -1; enter = false; return false; } internal static IEnumerable AllVertices(Polygon2f poly) { int pc = poly.PointCount; for (int pi = 0; pi < pc; pi++) yield return poly[pi]; yield return poly[0]; } #endregion #region Intersections (float) #region Line2f - Polygon2f /// /// Returns the Line-Segments of line inside the Polygon (CCW ordered). /// Works with all (convex and non-convex) Polygons /// public static IEnumerable ClipWith(this Line2f line, Polygon2f poly) { bool i0, i1; i0 = poly.Contains(line.P0); i1 = poly.Contains(line.P1); var resulting = new List(); var enter = new List(); if (i0) { resulting.Add(line.P0); enter.Add(true); } if (i1) { resulting.Add(line.P1); enter.Add(false); } var p = V2f.NaN; var direction = line.Direction; foreach (var l in poly.EdgeLines) { if (line.Intersects(l, out p)) { var d = l.Direction; var n = new V2f(-d.Y, d.X); if (!p.IsNaN) { bool addflag = true; bool flag = direction.Dot(n) > 0; for (int i = 0; i < resulting.Count; i++) { if (Fun.IsTiny((resulting[i] - p).Length)) { if (flag != enter[i]) { resulting.RemoveAt(i); enter.RemoveAt(i); } addflag = false; break; } } if (addflag) { resulting.Add(p); enter.Add(flag); } } } } var dir = line.P1 - line.P0; resulting = (from r in resulting select r).OrderBy(x => x.Dot(dir)).ToList(); var counter = resulting.Count; var lines = new List(); for (int i = 0; i < counter - 1; i += 2) { lines.Add(new Line2f(resulting[i], resulting[i + 1])); } return lines; } /// /// Returns the Line-Segments of line inside the Polygon (CCW ordered). /// Works only with Convex-Polygons /// If the line is clipped entirely, the points of the returned Line2f are NaN. /// public static Line2f ClipWithConvex(this Line2f line, Polygon2f poly) { var p = V2f.NaN; bool i0, i1; i0 = poly.Contains(line.P0); i1 = poly.Contains(line.P1); if (i0 && i1) return line; else if ((!i0 && i1) || (i0 && !i1)) { foreach (var l in poly.EdgeLines) { if (line.Intersects(l, out p)) break; } if (i0) return new Line2f(line.P0, p); else return new Line2f(p, line.P1); } else { V2f p0 = V2f.NaN; V2f p1 = V2f.NaN; int c = 0; foreach (var l in poly.EdgeLines) { if (line.Intersects(l, out p)) { if (c == 0) p0 = p; else p1 = p; c++; } } if (c == 2) { V2f u = p1 - p0; if (u.Dot(line.Direction) > 0) return new Line2f(p0, p1); else return new Line2f(p1, p0); } else return new Line2f(V2f.NaN, V2f.NaN); } } #endregion #region Polygon2f - Polygon2f /// /// Clips one Polygon with an other. Returns a Polygon representing the Intersection of the two. /// Works only with Convex Polygons. (For non-convex Polygons use Polygon2f.ClipWith(Polygon2f)) /// !!!! UNTESTED !!!! /// public static Polygon2f ClippedByConvex(this Polygon2f poly, Polygon2f second) { V2f[][] arr = new V2f[2][]; arr[0] = AllVertices(poly).ToArray(); arr[1] = AllVertices(second).ToArray(); Polygon2f[] polygon = new Polygon2f[2]; polygon[0] = poly; polygon[1] = second; bool current = false; int currentIndex = 0; int otherIndex = 1; bool enter = false; int index = -1; V2f point = V2f.NaN; List points = new List(); for (int i = 1; i < arr[currentIndex].Length; i = (i + 1) % arr[currentIndex].Length) { if (i < 1) i = 1; currentIndex = (current ? 1 : 0); otherIndex = (current ? 0 : 1); V2f start = arr[currentIndex][i - 1]; V2f end = arr[currentIndex][i]; if (Intersects(arr[otherIndex], start, end, ref points, out enter, out index, out point)) { if (enter) { points.Add(point); int u = i; int count = 0; while (polygon[otherIndex].Contains(arr[currentIndex][u])) { points.Add(arr[currentIndex][u]); u = (u + arr[currentIndex].Length - 1) % arr[currentIndex].Length; count++; } if (count == 0) i--; else { i += count - 1; } } else { points.Add(point); i = index; current = !current; currentIndex = (current ? 1 : 0); otherIndex = (current ? 0 : 1); } } else { if (i < arr[currentIndex].Length && polygon[otherIndex].Contains(arr[currentIndex][i])) { if (Closest(points, arr[currentIndex][i]) < 0.001f) break; points.Add(arr[currentIndex][i]); } } } return new Polygon2f(points); } /// /// Clips one Polygon with an other. Returns a Polygon-Set representing the Intersections of the two. /// Works only with all (convex/concave) Polygons /// !!!! UNTESTED !!!! /// public static IEnumerable ClippedBy(this Polygon2f p0, Polygon2f p1, float relativeEpsilon) { List i0 = SubPrimitives.ComputeNonConcaveSubPolygons(p0, relativeEpsilon); List i1 = SubPrimitives.ComputeNonConcaveSubPolygons(p1, relativeEpsilon); List polys = new List(); for (int i = 0; i < i0.Count; i++) { for (int u = 0; u < i1.Count; u++) { Polygon2f q0 = new Polygon2f(from o in i0[i] select p0[o]); Polygon2f q1 = new Polygon2f(from o in i1[u] select p1[o]); Polygon2f r = q0.ClippedByConvex(q1); if (r.PointCount > 0) polys.Add(r); } } return Union(polys); } #endregion #endregion #region Unions (float) #region Polygon2f - Polygon2f public static IEnumerable Union(List p) { List polys = new List(); polys.Add(p[0]); List temp; for (int i = 1; i < p.Count; i++) { bool found = false; for (int u = 0; u < polys.Count; u++) { temp = polys[u].Union(p[i]).ToList(); if (temp.Count == 1) { polys[u] = temp[0]; found = true; } } if (!found) { polys.Add(p[i]); } } return polys; } /// /// Returns the unified Polygon of the two given ones. /// Works only with convex-Polygons /// Returns an empty Polygon if the two do not intersect /// public static IEnumerable Union(this Polygon2f p0, Polygon2f p1) { Polygon2f[] arr = new Polygon2f[2]; arr[0] = p0; arr[1] = p1; int current = 0; int other = 1; List points = new List(); bool enter = false; int index = -1; V2f point = V2f.NaN; bool firstIntersectionFound = false; V2f firstIntersectionPoint = V2f.NaN; for (int i = 0; i >= 0; i = (i + 1) % arr[current].PointCount) { V2f start = arr[current][(i + arr[current].PointCount - 1) % arr[current].PointCount]; V2f end = arr[current][i]; if (arr[other].ClosestIntersection(start, end, out enter, out index, out point)) { if (!firstIntersectionFound) { firstIntersectionFound = true; firstIntersectionPoint = point; } else { if ((point - firstIntersectionPoint).Length < 0.001f) break; } if (enter) { points.Add(point); while ((arr[other][(index + 1) % arr[other].PointCount] - point).Length < 0.001f) index = (index + 1) % arr[other].PointCount; if (!arr[current].Contains(arr[other][(index + 1) % arr[other].PointCount])) { points.Add(arr[other][(index + 1) % arr[other].PointCount]); index = (index + 1) % arr[other].PointCount; } i = index; current = (current == 1 ? 0 : 1); other = (current == 1 ? 0 : 1); } else { points.Add(point); if (!arr[other].Contains(arr[current][i])) { points.Add(arr[current][i]); } } } else { if (i == arr[current].PointCount - 1 && !firstIntersectionFound) break; if (!arr[other].Contains(end) && firstIntersectionFound) { points.Add(end); } } } if (!firstIntersectionFound) { if (p0.Contains(p1[0])) yield return p0; else if (p1.Contains(p0[0])) yield return p1; else { yield return p0; yield return p1; } } else yield return new Polygon2f(points); } #endregion public static IEnumerable Union(this Box2f b0, Box2f b1) { Polygon2f p0 = new Polygon2f(b0.ComputeCornersCCW()); Polygon2f p1 = new Polygon2f(b1.ComputeCornersCCW()); return p0.Union(p1); } #endregion #region Helpers (double) public static bool ClosestIntersection(this Polygon2d poly, V2d start, V2d end, out bool enter, out int otherIndex, out V2d p) { double min = double.MaxValue; bool intersects = false; V2d point = V2d.NaN; bool tempenter = false; int tempindex = -1; V2d temppoint = V2d.NaN; double templength = double.MaxValue; Line2d line = new Line2d(start, end); int i = 0; foreach (var l in poly.EdgeLines) { if (line.Intersects(l, 4 * double.Epsilon, out temppoint)) { templength = (temppoint - line.P0).Length; if (templength < min) { tempenter = l.LeftValueOfDir(line.Direction) >= 0; tempindex = i; min = templength; point = temppoint; } intersects = true; } i++; } enter = tempenter; otherIndex = tempindex; p = point; return intersects; } internal static double Closest(this List points, V2d p) { double temp; double min = double.MaxValue; for (int i = 0; i < points.Count; i++) { temp = (p - points[i]).Length; if (temp < min) min = temp; } return min; } internal static bool Intersects(V2d[] poly, V2d p0, V2d p1, ref List known, out bool enter, out int index0, out V2d p) { int index = 0; Line2d l; int i0 = 0; int i1 = 1; for (int i = 1; i <= poly.Length; i++) { if (i < poly.Length) { i0 = i - 1; i1 = i; } else { i0 = poly.Length - 1; i1 = 0; } l = new Line2d(poly[i0], poly[i1]); if (l.Intersects(new Line2d(p0, p1), 4 *double.Epsilon, out p)) { if (!Fun.IsTiny(known.Closest(p))) { enter = (l.LeftValueOfPos(p1) >= -4 *double.Epsilon); index0 = index; return true; } } index++; } p = V2d.NaN; index0 = -1; enter = false; return false; } internal static IEnumerable AllVertices(Polygon2d poly) { int pc = poly.PointCount; for (int pi = 0; pi < pc; pi++) yield return poly[pi]; yield return poly[0]; } #endregion #region Intersections (double) #region Line2d - Polygon2d /// /// Returns the Line-Segments of line inside the Polygon (CCW ordered). /// Works with all (convex and non-convex) Polygons /// public static IEnumerable ClipWith(this Line2d line, Polygon2d poly) { bool i0, i1; i0 = poly.Contains(line.P0); i1 = poly.Contains(line.P1); var resulting = new List(); var enter = new List(); if (i0) { resulting.Add(line.P0); enter.Add(true); } if (i1) { resulting.Add(line.P1); enter.Add(false); } var p = V2d.NaN; var direction = line.Direction; foreach (var l in poly.EdgeLines) { if (line.Intersects(l, out p)) { var d = l.Direction; var n = new V2d(-d.Y, d.X); if (!p.IsNaN) { bool addflag = true; bool flag = direction.Dot(n) > 0; for (int i = 0; i < resulting.Count; i++) { if (Fun.IsTiny((resulting[i] - p).Length)) { if (flag != enter[i]) { resulting.RemoveAt(i); enter.RemoveAt(i); } addflag = false; break; } } if (addflag) { resulting.Add(p); enter.Add(flag); } } } } var dir = line.P1 - line.P0; resulting = (from r in resulting select r).OrderBy(x => x.Dot(dir)).ToList(); var counter = resulting.Count; var lines = new List(); for (int i = 0; i < counter - 1; i += 2) { lines.Add(new Line2d(resulting[i], resulting[i + 1])); } return lines; } /// /// Returns the Line-Segments of line inside the Polygon (CCW ordered). /// Works only with Convex-Polygons /// If the line is clipped entirely, the points of the returned Line2d are NaN. /// public static Line2d ClipWithConvex(this Line2d line, Polygon2d poly) { var p = V2d.NaN; bool i0, i1; i0 = poly.Contains(line.P0); i1 = poly.Contains(line.P1); if (i0 && i1) return line; else if ((!i0 && i1) || (i0 && !i1)) { foreach (var l in poly.EdgeLines) { if (line.Intersects(l, out p)) break; } if (i0) return new Line2d(line.P0, p); else return new Line2d(p, line.P1); } else { V2d p0 = V2d.NaN; V2d p1 = V2d.NaN; int c = 0; foreach (var l in poly.EdgeLines) { if (line.Intersects(l, out p)) { if (c == 0) p0 = p; else p1 = p; c++; } } if (c == 2) { V2d u = p1 - p0; if (u.Dot(line.Direction) > 0) return new Line2d(p0, p1); else return new Line2d(p1, p0); } else return new Line2d(V2d.NaN, V2d.NaN); } } #endregion #region Polygon2d - Polygon2d /// /// Clips one Polygon with an other. Returns a Polygon representing the Intersection of the two. /// Works only with Convex Polygons. (For non-convex Polygons use Polygon2d.ClipWith(Polygon2d)) /// !!!! UNTESTED !!!! /// public static Polygon2d ClippedByConvex(this Polygon2d poly, Polygon2d second) { V2d[][] arr = new V2d[2][]; arr[0] = AllVertices(poly).ToArray(); arr[1] = AllVertices(second).ToArray(); Polygon2d[] polygon = new Polygon2d[2]; polygon[0] = poly; polygon[1] = second; bool current = false; int currentIndex = 0; int otherIndex = 1; bool enter = false; int index = -1; V2d point = V2d.NaN; List points = new List(); for (int i = 1; i < arr[currentIndex].Length; i = (i + 1) % arr[currentIndex].Length) { if (i < 1) i = 1; currentIndex = (current ? 1 : 0); otherIndex = (current ? 0 : 1); V2d start = arr[currentIndex][i - 1]; V2d end = arr[currentIndex][i]; if (Intersects(arr[otherIndex], start, end, ref points, out enter, out index, out point)) { if (enter) { points.Add(point); int u = i; int count = 0; while (polygon[otherIndex].Contains(arr[currentIndex][u])) { points.Add(arr[currentIndex][u]); u = (u + arr[currentIndex].Length - 1) % arr[currentIndex].Length; count++; } if (count == 0) i--; else { i += count - 1; } } else { points.Add(point); i = index; current = !current; currentIndex = (current ? 1 : 0); otherIndex = (current ? 0 : 1); } } else { if (i < arr[currentIndex].Length && polygon[otherIndex].Contains(arr[currentIndex][i])) { if (Closest(points, arr[currentIndex][i]) < 0.001) break; points.Add(arr[currentIndex][i]); } } } return new Polygon2d(points); } /// /// Clips one Polygon with an other. Returns a Polygon-Set representing the Intersections of the two. /// Works only with all (convex/concave) Polygons /// !!!! UNTESTED !!!! /// public static IEnumerable ClippedBy(this Polygon2d p0, Polygon2d p1, double relativeEpsilon) { List i0 = SubPrimitives.ComputeNonConcaveSubPolygons(p0, relativeEpsilon); List i1 = SubPrimitives.ComputeNonConcaveSubPolygons(p1, relativeEpsilon); List polys = new List(); for (int i = 0; i < i0.Count; i++) { for (int u = 0; u < i1.Count; u++) { Polygon2d q0 = new Polygon2d(from o in i0[i] select p0[o]); Polygon2d q1 = new Polygon2d(from o in i1[u] select p1[o]); Polygon2d r = q0.ClippedByConvex(q1); if (r.PointCount > 0) polys.Add(r); } } return Union(polys); } #endregion #endregion #region Unions (double) #region Polygon2d - Polygon2d public static IEnumerable Union(List p) { List polys = new List(); polys.Add(p[0]); List temp; for (int i = 1; i < p.Count; i++) { bool found = false; for (int u = 0; u < polys.Count; u++) { temp = polys[u].Union(p[i]).ToList(); if (temp.Count == 1) { polys[u] = temp[0]; found = true; } } if (!found) { polys.Add(p[i]); } } return polys; } /// /// Returns the unified Polygon of the two given ones. /// Works only with convex-Polygons /// Returns an empty Polygon if the two do not intersect /// public static IEnumerable Union(this Polygon2d p0, Polygon2d p1) { Polygon2d[] arr = new Polygon2d[2]; arr[0] = p0; arr[1] = p1; int current = 0; int other = 1; List points = new List(); bool enter = false; int index = -1; V2d point = V2d.NaN; bool firstIntersectionFound = false; V2d firstIntersectionPoint = V2d.NaN; for (int i = 0; i >= 0; i = (i + 1) % arr[current].PointCount) { V2d start = arr[current][(i + arr[current].PointCount - 1) % arr[current].PointCount]; V2d end = arr[current][i]; if (arr[other].ClosestIntersection(start, end, out enter, out index, out point)) { if (!firstIntersectionFound) { firstIntersectionFound = true; firstIntersectionPoint = point; } else { if ((point - firstIntersectionPoint).Length < 0.001) break; } if (enter) { points.Add(point); while ((arr[other][(index + 1) % arr[other].PointCount] - point).Length < 0.001) index = (index + 1) % arr[other].PointCount; if (!arr[current].Contains(arr[other][(index + 1) % arr[other].PointCount])) { points.Add(arr[other][(index + 1) % arr[other].PointCount]); index = (index + 1) % arr[other].PointCount; } i = index; current = (current == 1 ? 0 : 1); other = (current == 1 ? 0 : 1); } else { points.Add(point); if (!arr[other].Contains(arr[current][i])) { points.Add(arr[current][i]); } } } else { if (i == arr[current].PointCount - 1 && !firstIntersectionFound) break; if (!arr[other].Contains(end) && firstIntersectionFound) { points.Add(end); } } } if (!firstIntersectionFound) { if (p0.Contains(p1[0])) yield return p0; else if (p1.Contains(p0[0])) yield return p1; else { yield return p0; yield return p1; } } else yield return new Polygon2d(points); } #endregion public static IEnumerable Union(this Box2d b0, Box2d b1) { Polygon2d p0 = new Polygon2d(b0.ComputeCornersCCW()); Polygon2d p1 = new Polygon2d(b1.ComputeCornersCCW()); return p0.Union(p1); } #endregion } } ================================================ FILE: src/Aardvark.Base/Geometry/ClippingFunctions_template.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Aardvark.Base { public static partial class GeometryFun { //# foreach (var isDouble in new[] { false, true }) { //# var rtype = isDouble ? "double" : "float"; //# var tc = isDouble ? "d" : "f"; //# var v2t = "V2" + tc; //# var v3t = "V3" + tc; //# var box2t = "Box2" + tc; //# var line2t = "Line2" + tc; //# var box3t = "Box3" + tc; //# var triangle2t = "Triangle2" + tc; //# var polygon2t = "Polygon2" + tc; //# var eps = isDouble ? "0.001" : "0.001f"; #region Helpers (__rtype__) public static bool ClosestIntersection(this __polygon2t__ poly, __v2t__ start, __v2t__ end, out bool enter, out int otherIndex, out __v2t__ p) { __rtype__ min = __rtype__.MaxValue; bool intersects = false; __v2t__ point = __v2t__.NaN; bool tempenter = false; int tempindex = -1; __v2t__ temppoint = __v2t__.NaN; __rtype__ templength = __rtype__.MaxValue; __line2t__ line = new __line2t__(start, end); int i = 0; foreach (var l in poly.EdgeLines) { if (line.Intersects(l, 4 * __rtype__.Epsilon, out temppoint)) { templength = (temppoint - line.P0).Length; if (templength < min) { tempenter = l.LeftValueOfDir(line.Direction) >= 0; tempindex = i; min = templength; point = temppoint; } intersects = true; } i++; } enter = tempenter; otherIndex = tempindex; p = point; return intersects; } internal static __rtype__ Closest(this List<__v2t__> points, __v2t__ p) { __rtype__ temp; __rtype__ min = __rtype__.MaxValue; for (int i = 0; i < points.Count; i++) { temp = (p - points[i]).Length; if (temp < min) min = temp; } return min; } internal static bool Intersects(__v2t__[] poly, __v2t__ p0, __v2t__ p1, ref List<__v2t__> known, out bool enter, out int index0, out __v2t__ p) { int index = 0; __line2t__ l; int i0 = 0; int i1 = 1; for (int i = 1; i <= poly.Length; i++) { if (i < poly.Length) { i0 = i - 1; i1 = i; } else { i0 = poly.Length - 1; i1 = 0; } l = new __line2t__(poly[i0], poly[i1]); if (l.Intersects(new __line2t__(p0, p1), 4 *__rtype__.Epsilon, out p)) { if (!Fun.IsTiny(known.Closest(p))) { enter = (l.LeftValueOfPos(p1) >= -4 *__rtype__.Epsilon); index0 = index; return true; } } index++; } p = __v2t__.NaN; index0 = -1; enter = false; return false; } internal static IEnumerable<__v2t__> AllVertices(__polygon2t__ poly) { int pc = poly.PointCount; for (int pi = 0; pi < pc; pi++) yield return poly[pi]; yield return poly[0]; } #endregion #region Intersections (__rtype__) #region __line2t__ - __polygon2t__ /// /// Returns the Line-Segments of line inside the Polygon (CCW ordered). /// Works with all (convex and non-convex) Polygons /// public static IEnumerable<__line2t__> ClipWith(this __line2t__ line, __polygon2t__ poly) { bool i0, i1; i0 = poly.Contains(line.P0); i1 = poly.Contains(line.P1); var resulting = new List<__v2t__>(); var enter = new List(); if (i0) { resulting.Add(line.P0); enter.Add(true); } if (i1) { resulting.Add(line.P1); enter.Add(false); } var p = __v2t__.NaN; var direction = line.Direction; foreach (var l in poly.EdgeLines) { if (line.Intersects(l, out p)) { var d = l.Direction; var n = new __v2t__(-d.Y, d.X); if (!p.IsNaN) { bool addflag = true; bool flag = direction.Dot(n) > 0; for (int i = 0; i < resulting.Count; i++) { if (Fun.IsTiny((resulting[i] - p).Length)) { if (flag != enter[i]) { resulting.RemoveAt(i); enter.RemoveAt(i); } addflag = false; break; } } if (addflag) { resulting.Add(p); enter.Add(flag); } } } } var dir = line.P1 - line.P0; resulting = (from r in resulting select r).OrderBy(x => x.Dot(dir)).ToList(); var counter = resulting.Count; var lines = new List<__line2t__>(); for (int i = 0; i < counter - 1; i += 2) { lines.Add(new __line2t__(resulting[i], resulting[i + 1])); } return lines; } /// /// Returns the Line-Segments of line inside the Polygon (CCW ordered). /// Works only with Convex-Polygons /// If the line is clipped entirely, the points of the returned __line2t__ are NaN. /// public static __line2t__ ClipWithConvex(this __line2t__ line, __polygon2t__ poly) { var p = __v2t__.NaN; bool i0, i1; i0 = poly.Contains(line.P0); i1 = poly.Contains(line.P1); if (i0 && i1) return line; else if ((!i0 && i1) || (i0 && !i1)) { foreach (var l in poly.EdgeLines) { if (line.Intersects(l, out p)) break; } if (i0) return new __line2t__(line.P0, p); else return new __line2t__(p, line.P1); } else { __v2t__ p0 = __v2t__.NaN; __v2t__ p1 = __v2t__.NaN; int c = 0; foreach (var l in poly.EdgeLines) { if (line.Intersects(l, out p)) { if (c == 0) p0 = p; else p1 = p; c++; } } if (c == 2) { __v2t__ u = p1 - p0; if (u.Dot(line.Direction) > 0) return new __line2t__(p0, p1); else return new __line2t__(p1, p0); } else return new __line2t__(__v2t__.NaN, __v2t__.NaN); } } #endregion #region __polygon2t__ - __polygon2t__ /// /// Clips one Polygon with an other. Returns a Polygon representing the Intersection of the two. /// Works only with Convex Polygons. (For non-convex Polygons use __polygon2t__.ClipWith(__polygon2t__)) /// !!!! UNTESTED !!!! /// public static __polygon2t__ ClippedByConvex(this __polygon2t__ poly, __polygon2t__ second) { __v2t__[][] arr = new __v2t__[2][]; arr[0] = AllVertices(poly).ToArray(); arr[1] = AllVertices(second).ToArray(); __polygon2t__[] polygon = new __polygon2t__[2]; polygon[0] = poly; polygon[1] = second; bool current = false; int currentIndex = 0; int otherIndex = 1; bool enter = false; int index = -1; __v2t__ point = __v2t__.NaN; List<__v2t__> points = new List<__v2t__>(); for (int i = 1; i < arr[currentIndex].Length; i = (i + 1) % arr[currentIndex].Length) { if (i < 1) i = 1; currentIndex = (current ? 1 : 0); otherIndex = (current ? 0 : 1); __v2t__ start = arr[currentIndex][i - 1]; __v2t__ end = arr[currentIndex][i]; if (Intersects(arr[otherIndex], start, end, ref points, out enter, out index, out point)) { if (enter) { points.Add(point); int u = i; int count = 0; while (polygon[otherIndex].Contains(arr[currentIndex][u])) { points.Add(arr[currentIndex][u]); u = (u + arr[currentIndex].Length - 1) % arr[currentIndex].Length; count++; } if (count == 0) i--; else { i += count - 1; } } else { points.Add(point); i = index; current = !current; currentIndex = (current ? 1 : 0); otherIndex = (current ? 0 : 1); } } else { if (i < arr[currentIndex].Length && polygon[otherIndex].Contains(arr[currentIndex][i])) { if (Closest(points, arr[currentIndex][i]) < __eps__) break; points.Add(arr[currentIndex][i]); } } } return new __polygon2t__(points); } /// /// Clips one Polygon with an other. Returns a Polygon-Set representing the Intersections of the two. /// Works only with all (convex/concave) Polygons /// !!!! UNTESTED !!!! /// public static IEnumerable<__polygon2t__> ClippedBy(this __polygon2t__ p0, __polygon2t__ p1, __rtype__ relativeEpsilon) { List i0 = SubPrimitives.ComputeNonConcaveSubPolygons(p0, relativeEpsilon); List i1 = SubPrimitives.ComputeNonConcaveSubPolygons(p1, relativeEpsilon); List<__polygon2t__> polys = new List<__polygon2t__>(); for (int i = 0; i < i0.Count; i++) { for (int u = 0; u < i1.Count; u++) { __polygon2t__ q0 = new __polygon2t__(from o in i0[i] select p0[o]); __polygon2t__ q1 = new __polygon2t__(from o in i1[u] select p1[o]); __polygon2t__ r = q0.ClippedByConvex(q1); if (r.PointCount > 0) polys.Add(r); } } return Union(polys); } #endregion #endregion #region Unions (__rtype__) #region __polygon2t__ - __polygon2t__ public static IEnumerable<__polygon2t__> Union(List<__polygon2t__> p) { List<__polygon2t__> polys = new List<__polygon2t__>(); polys.Add(p[0]); List<__polygon2t__> temp; for (int i = 1; i < p.Count; i++) { bool found = false; for (int u = 0; u < polys.Count; u++) { temp = polys[u].Union(p[i]).ToList(); if (temp.Count == 1) { polys[u] = temp[0]; found = true; } } if (!found) { polys.Add(p[i]); } } return polys; } /// /// Returns the unified Polygon of the two given ones. /// Works only with convex-Polygons /// Returns an empty Polygon if the two do not intersect /// public static IEnumerable<__polygon2t__> Union(this __polygon2t__ p0, __polygon2t__ p1) { __polygon2t__[] arr = new __polygon2t__[2]; arr[0] = p0; arr[1] = p1; int current = 0; int other = 1; List<__v2t__> points = new List<__v2t__>(); bool enter = false; int index = -1; __v2t__ point = __v2t__.NaN; bool firstIntersectionFound = false; __v2t__ firstIntersectionPoint = __v2t__.NaN; for (int i = 0; i >= 0; i = (i + 1) % arr[current].PointCount) { __v2t__ start = arr[current][(i + arr[current].PointCount - 1) % arr[current].PointCount]; __v2t__ end = arr[current][i]; if (arr[other].ClosestIntersection(start, end, out enter, out index, out point)) { if (!firstIntersectionFound) { firstIntersectionFound = true; firstIntersectionPoint = point; } else { if ((point - firstIntersectionPoint).Length < __eps__) break; } if (enter) { points.Add(point); while ((arr[other][(index + 1) % arr[other].PointCount] - point).Length < __eps__) index = (index + 1) % arr[other].PointCount; if (!arr[current].Contains(arr[other][(index + 1) % arr[other].PointCount])) { points.Add(arr[other][(index + 1) % arr[other].PointCount]); index = (index + 1) % arr[other].PointCount; } i = index; current = (current == 1 ? 0 : 1); other = (current == 1 ? 0 : 1); } else { points.Add(point); if (!arr[other].Contains(arr[current][i])) { points.Add(arr[current][i]); } } } else { if (i == arr[current].PointCount - 1 && !firstIntersectionFound) break; if (!arr[other].Contains(end) && firstIntersectionFound) { points.Add(end); } } } if (!firstIntersectionFound) { if (p0.Contains(p1[0])) yield return p0; else if (p1.Contains(p0[0])) yield return p1; else { yield return p0; yield return p1; } } else yield return new __polygon2t__(points); } #endregion public static IEnumerable<__polygon2t__> Union(this __box2t__ b0, __box2t__ b1) { __polygon2t__ p0 = new __polygon2t__(b0.ComputeCornersCCW()); __polygon2t__ p1 = new __polygon2t__(b1.ComputeCornersCCW()); return p0.Union(p1); } #endregion //# } } } ================================================ FILE: src/Aardvark.Base/Geometry/Interfaces/IBoundingBox_auto.cs ================================================ namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! /// /// Return an axis aligned two-dimensional box that contains the complete geometry. /// public interface IBoundingBox2i { Box2i BoundingBox2i { get; } } /// /// Return an axis aligned three-dimensional box that contains the complete geometry. /// public interface IBoundingBox3i { Box3i BoundingBox3i { get; } } /// /// Return an axis aligned two-dimensional box that contains the complete geometry. /// public interface IBoundingBox2l { Box2l BoundingBox2l { get; } } /// /// Return an axis aligned three-dimensional box that contains the complete geometry. /// public interface IBoundingBox3l { Box3l BoundingBox3l { get; } } /// /// Return an axis aligned two-dimensional box that contains the complete geometry. /// public interface IBoundingBox2f { Box2f BoundingBox2f { get; } } /// /// Return an axis aligned three-dimensional box that contains the complete geometry. /// public interface IBoundingBox3f { Box3f BoundingBox3f { get; } } /// /// Return an axis aligned two-dimensional box that contains the complete geometry. /// public interface IBoundingBox2d { Box2d BoundingBox2d { get; } } /// /// Return an axis aligned three-dimensional box that contains the complete geometry. /// public interface IBoundingBox3d { Box3d BoundingBox3d { get; } } } ================================================ FILE: src/Aardvark.Base/Geometry/Interfaces/IBoundingBox_template.cs ================================================ namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var ft in Meta.SignedVecFieldTypes) { //# var ftype = ft.Name; //# var tc = ft.Char; /// /// Return an axis aligned two-dimensional box that contains the complete geometry. /// public interface IBoundingBox2__tc__ { Box2__tc__ BoundingBox2__tc__ { get; } } /// /// Return an axis aligned three-dimensional box that contains the complete geometry. /// public interface IBoundingBox3__tc__ { Box3__tc__ BoundingBox3__tc__ { get; } } //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Interfaces/IBoundingCircle.cs ================================================ namespace Aardvark.Base { public interface IBoundingCircle2f { Circle2f BoundingCircle2f { get; } } public interface IBoundingCircle2d { Circle2d BoundingCircle2d { get; } } } ================================================ FILE: src/Aardvark.Base/Geometry/Interfaces/IBoundingSphere.cs ================================================ namespace Aardvark.Base { public interface IBoundingSphere3f { Sphere3f BoundingSphere3f { get; } } public interface IBoundingSphere3d { Sphere3d BoundingSphere3d { get; } } } ================================================ FILE: src/Aardvark.Base/Geometry/Interfaces/IImmutablePolygon.cs ================================================ using System; using System.Collections.Generic; namespace Aardvark.Base { /// /// An immutable polygon. /// public interface IImmutablePolygon { /// /// Polygon outline. /// IReadOnlyList Points { get; } /// /// Gets number of vertices. /// int Count { get; } /// /// Returns new polygon with point added. /// IImmutablePolygon AddPoint(T p); /// /// Returns new polygon with points added. /// IImmutablePolygon AddPoints(IEnumerable points); /// /// Returns new polygon with point replaced. /// IImmutablePolygon SetPoint(int index, T p); /// /// Returns new polygon with point p inserted at given index. /// IImmutablePolygon InsertPoint(int index, T p); /// /// Returns new polygon with point removed. /// IImmutablePolygon RemovePoint(int index); /// /// Returns new polygon with points removed. /// IImmutablePolygon RemovePoints(IEnumerable indexes); /// /// Returns new polygon with transformed points. /// IImmutablePolygon Transform(Func transform); } } ================================================ FILE: src/Aardvark.Base/Geometry/Interfaces/IPolygon.cs ================================================ namespace Aardvark.Base { public interface IPolygon { int PointCount { get; } T this[int index] { get; } // counter clockwise access } } ================================================ FILE: src/Aardvark.Base/Geometry/IntersectionTests_auto.cs ================================================ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; namespace Aardvark.Base { public static partial class GeometryFun { private static readonly int[] c_cubeEdgeVertex0 = new int[] { 0, 2, 4, 6, 0, 1, 4, 5, 0, 1, 2, 3 }; private static readonly int[] c_cubeEdgeVertex1 = new int[] { 1, 3, 5, 7, 2, 3, 6, 7, 4, 5, 6, 7 }; // Contains-tests should return true if the contained object is // either entirely inside the containing object or lies on the // boundary of the containing object. #region Triangle2f contains V2f public static bool Contains( this Triangle2f triangle, V2f point ) { var v0p = point - triangle.P0; return triangle.Line01.LeftValueOfDir(v0p) >= 0 && triangle.Line02.RightValueOfDir(v0p) >= 0 && triangle.Line12.LeftValueOfPos(point) >= 0; } #endregion #region Triangle2f contains Line2f (sm) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Triangle2f triangle, Line2f linesegment) => triangle.Contains(linesegment.P0) && triangle.Contains(linesegment.P1); #endregion #region Triangle2f contains Triangle2f (sm) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Triangle2f triangle, Triangle2f other) => triangle.Contains(other.P0) && triangle.Contains(other.P1) && triangle.Contains(other.P2); #endregion #region Triangle2f contains Quad2f (sm) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Triangle2f triangle, Quad2f q) => triangle.Contains(q.P0) && triangle.Contains(q.P1) && triangle.Contains(q.P2) && triangle.Contains(q.P3); #endregion #region Triangle2f contains Circle2f public static bool Contains(this Triangle2f triangle, Circle2f circle) { var center = circle.Center; return triangle.Contains(center) && circle.Radius <= center.GetMinimalDistanceTo(triangle.Line01) && circle.Radius <= center.GetMinimalDistanceTo(triangle.Line12) && circle.Radius <= center.GetMinimalDistanceTo(triangle.Line20); } #endregion #region Circle2f contains V2f (sm) /// /// True if point p is contained in this circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Circle2f circle, V2f p) => (p - circle.Center).LengthSquared <= circle.RadiusSquared; #endregion #region Circle2f contains Line2f (sm) /// /// True if line segment is contained in this circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Circle2f circle, Line2f l) => circle.Contains(l.P0) && circle.Contains(l.P1); #endregion #region Circle2f contains Triangle2f (sm) /// /// True if triangle is contained in this circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Circle2f circle, Triangle2f t) => circle.Contains(t.P0) && circle.Contains(t.P1) && circle.Contains(t.P2); #endregion #region Circle2f contains Quad2f (sm) /// /// True if quad is contained in this circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Circle2f circle, Quad2f q) => circle.Contains(q.P0) && circle.Contains(q.P1) && circle.Contains(q.P2) && circle.Contains(q.P3); #endregion #region Circle2f contains Circle2f (sm) /// /// True if other circle is contained in this circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Circle2f circle, Circle2f other) => (other.Center - circle.Center).Length + other.Radius <= circle.Radius; #endregion #region Quad2f contains V2f (haaser) /// /// True if point is contained in this quad. /// public static bool Contains(this Quad2f quad, V2f point) { return LeftValOfPos(0, 1, ref point) >= 0 && LeftValOfPos(1, 2, ref point) >= 0 && LeftValOfPos(2, 3, ref point) >= 0 && LeftValOfPos(3, 0, ref point) >= 0; float LeftValOfPos(int i0, int i1, ref V2f p) => (p.X - quad[i0].X) * (quad[i0].Y - quad[i1].Y) + (p.Y - quad[i0].Y) * (quad[i1].X - quad[i0].X); } #endregion #region Quad2f contains Line2f /// /// True if line segment is contained in this quad. /// public static bool Contains(this Quad2f quad, Line2f l) => quad.Contains(l.P0) && quad.Contains(l.P1); #endregion #region Quad2f contains Triangle2f /// /// True if triangle is contained in this quad. /// public static bool Contains(this Quad2f quad, Triangle2f t) => quad.Contains(t.P0) && quad.Contains(t.P1) && quad.Contains(t.P2); #endregion #region Quad2f contains Quad2f /// /// True if other quad is contained in this quad. /// public static bool Contains(this Quad2f quad, Quad2f q) => quad.Contains(q.P0) && quad.Contains(q.P1) && quad.Contains(q.P2) && quad.Contains(q.P3); #endregion #region Quad2f contains Circle2f /// /// True if circle is contained in this quad. /// public static bool Contains(this Quad2f quad, Circle2f circle) { var center = circle.Center; return quad.Contains(center) && circle.Radius <= center.GetMinimalDistanceTo(quad.Line01) && circle.Radius <= center.GetMinimalDistanceTo(quad.Line12) && circle.Radius <= center.GetMinimalDistanceTo(quad.Line23) && circle.Radius <= center.GetMinimalDistanceTo(quad.Line30); } #endregion #region Box3f contains Quad3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains( this Box3f box, Quad3f quad ) { return box.Contains(quad.P0) && box.Contains(quad.P1) && box.Contains(quad.P2) && box.Contains(quad.P3); } #endregion #region Box3f contains Triangle3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains( this Box3f box, Triangle3f triangle ) { return box.Contains(triangle.P0) && box.Contains(triangle.P1) && box.Contains(triangle.P2); } #endregion #region Box3f contains Sphere3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains( this Box3f box, Sphere3f sphere ) { return box.Contains(sphere.Center) && !box.Intersects(sphere); } #endregion #region Box3f contains Cylinder3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains( this Box3f box, Cylinder3f cylinder ) { return box.Contains(cylinder.Center) && !box.Intersects(cylinder); } #endregion #region Hull3f contains V3f /// /// Hull normals are expected to point outside. /// public static bool Contains(this Hull3f hull, V3f point) { var planes = hull.PlaneArray; for (var i = 0; i < planes.Length; i++) { if (planes[i].Height(point) > 0) return false; } return true; } #endregion #region Hull3f contains Sphere3f (sm) /// /// Hull normals are expected to point outside. /// public static bool Contains(this Hull3f hull, Sphere3f sphere) { var planes = hull.PlaneArray; var negativeRadius = -sphere.Radius; for (var i = 0; i < planes.Length; i++) { if (planes[i].Height(sphere.Center) > negativeRadius) return false; } return true; } #endregion #region Polygon2f contains V2f (haaser) internal static V3i InsideTriangleFlags(ref V2f p0, ref V2f p1, ref V2f p2, ref V2f point) { V2f n0 = new V2f(p0.Y - p1.Y, p1.X - p0.X); V2f n1 = new V2f(p1.Y - p2.Y, p2.X - p1.X); V2f n2 = new V2f(p2.Y - p0.Y, p0.X - p2.X); int t0 = Fun.Sign(n0.Dot(point - p0)); int t1 = Fun.Sign(n1.Dot(point - p1)); int t2 = Fun.Sign(n2.Dot(point - p2)); if (t0 == 0) t1 = 1; if (t1 == 0) t1 = 1; if (t2 == 0) t2 = 1; return new V3i(t0, t1, t2); } internal static V3i InsideTriangleFlags(ref V2f p0, ref V2f p1, ref V2f p2, ref V2f point, int t0) { V2f n1 = new V2f(p1.Y - p2.Y, p2.X - p1.X); V2f n2 = new V2f(p2.Y - p0.Y, p0.X - p2.X); int t1 = Fun.Sign(n1.Dot(point - p1)); int t2 = Fun.Sign(n2.Dot(point - p2)); if (t1 == 0) t1 = 1; if (t2 == 0) t2 = 1; return new V3i(t0, t1, t2); } /// /// Returns true if the Polygon2f contains the given point. /// Works with all (convex and non-convex) Polygons. /// Assumes that the Vertices of the Polygon are sorted counter clockwise /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Polygon2f poly, V2f point) { return poly.Contains(point, true); } /// /// Returns true if the Polygon2f contains the given point. /// Works with all (convex and non-convex) Polygons. /// CCW represents the sorting order of the Polygon-Vertices (true -> CCW, false -> CW) /// public static bool Contains(this Polygon2f poly, V2f point, bool CCW) { int pc = poly.PointCount; if (pc < 3) return false; int counter = 0; V2f p0 = poly[0], p1 = poly[1], p2 = poly[2]; V3i temp = InsideTriangleFlags(ref p0, ref p1, ref p2, ref point); int t2_cache = temp.Z; if (temp.X == temp.Y && temp.Y == temp.Z) counter += temp.X; for (int pi = 3; pi < pc; pi++) { p1 = p2; p2 = poly[pi]; temp = InsideTriangleFlags(ref p0, ref p1, ref p2, ref point, -t2_cache); t2_cache = temp.Z; if (temp.X == temp.Y && temp.Y == temp.Z) counter += temp.X; } if (CCW) return counter > 0; else return counter < 0; } #endregion #region Plane3f +- eps contains V3f (sm) /// /// Returns true if point is within given eps to plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Plane3f plane, float eps, V3f point) { var d = plane.Height(point); return d >= -eps && d <= eps; } #endregion #region Plane3f +- eps contains Box3f (sm) /// /// Returns true if the space within eps to a plane fully contains the given box. /// public static bool Contains(this Plane3f plane, float eps, Box3f box) { var corners = box.ComputeCorners(); for (var i = 0; i < 8; i++) { var d = plane.Height(corners[i]); if (d < -eps || d > eps) return false; } return true; } #endregion #region Polygon3f +- eps contains V3f (sm) /// /// Returns true if point is within given eps to polygon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Polygon3f polygon, float eps, V3f point, out float distance) { var plane = polygon.GetPlane3f(); distance = plane.Height(point); if (distance < -eps || distance > eps) return false; var w2p = plane.GetWorldToPlane(); var poly2d = new Polygon2f(polygon.GetPointArray().Map(p => w2p.TransformPos(p).XY)); return poly2d.Contains(w2p.TransformPos(point).XY); } /// /// Returns true if point is within given eps to polygon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Polygon3f polygon, Plane3f supportingPlane, Euclidean3f world2plane, Polygon2f poly2d, float eps, V3f point, out float distance) { distance = supportingPlane.Height(point); if (distance < -eps || distance > eps) return false; return poly2d.Contains(world2plane.TransformPos(point).XY); } /// /// Returns true if point is within given eps to polygon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Polygon3f polygon, Plane3f supportingPlane, M44f world2plane, Polygon2f poly2d, float eps, V3f point, out float distance) { distance = supportingPlane.Height(point); if (distance < -eps || distance > eps) return false; return poly2d.Contains(world2plane.TransformPos(point).XY); } #endregion // Intersection tests #region Line2f intersects Line2f /// /// Returns true if the two line segments intersect. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Line2f l0, Line2f l1) => l0.IntersectsLine(l1.P0, l1.P1, out V2f _); /// /// Returns true if the two line segments intersect. /// The intersection point is returned in p. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Line2f l0, Line2f l1, out V2f p) => l0.IntersectsLine(l1.P0, l1.P1, out p); /// /// Returns true if the two line segments intersect within given tolerance. /// The intersection point is returned in p. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Line2f l0, Line2f l1, float absoluteEpsilon, out V2f p) => l0.IntersectsLine(l1.P0, l1.P1, absoluteEpsilon, out p); /// /// Returns true if the line segment intersects the line segment between p0 and p1. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine(this Line2f line, V2f p0, V2f p1) => line.IntersectsLine(p0, p1, out _); /// /// Returns true if the line segment intersects the line segment between p0 and p1. /// The intersection point is returned in p. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine(this Line2f line, V2f p0, V2f p1, out V2f p) => line.IntersectsLine(p0, p1, false, out p); /// /// Returns true if the line segment intersects the line segment between p0 and p1. /// The intersection point is returned in p. /// If overlapping is true and the segments are parallel, then /// the closest point to p0 of the intersection range is returned in p. /// public static bool IntersectsLine( this Line2f line, V2f p0, V2f p1, bool overlapping, out V2f p ) { var a = line.P0 - p0; if (Fun.IsTiny(a.LengthSquared)) { p = p0; return true; } var u = line.P1 - line.P0; var v = p1 - p0; var lu = u.Length; var cross = u.X * v.Y - u.Y * v.X; if (!Fun.IsTiny(cross)) { // non-parallel lines cross = 1 / cross; var t0 = (a.Y * v.X - a.X * v.Y) * cross; if (t0 > 1 || t0 < 0) { p = V2f.NaN; return false; } float t1 = (a.Y * u.X - a.X * u.Y) * cross; if (t1 > 1 || t1 < 0) { p = V2f.NaN; return false; } p = line.P0 + u * t0; return true; } else { // parallel lines if (!overlapping) { p = V2f.NaN; return false; } var normalizedDirection = u / lu; var r0 = new Range1f(0, lu); var r1 = new Range1f((p0 - line.P0).Dot(normalizedDirection), (p1 - line.P0).Dot(normalizedDirection)); r1.Repair(); if (r0.Intersects(r1, 0, out Range1f result)) { p = line.P0 + normalizedDirection * result.Min; return true; } p = V2f.NaN; return false; } } /// /// Returns true if the line segment intersects the line segment between p0 and p1 within given tolerance. /// The intersection point is returned in p. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine(this Line2f line, V2f p0, V2f p1, float absoluteEpsilon, out V2f p) => line.IntersectsLine(p0, p1, absoluteEpsilon, false, out p); /// /// Returns true if the line segment intersects the line segment between p0 and p1 within given tolerance. /// The intersection point is returned in p. /// If overlapping is true and the segments are parallel, then /// the closest point to p0 of the intersection range is returned in p. /// public static bool IntersectsLine( this Line2f line, V2f p0, V2f p1, float absoluteEpsilon, bool overlapping, out V2f p ) { var a = line.P0 - p0; if (Fun.IsTiny(a.LengthSquared)) { p = p0; return true; } var u = line.P1 - line.P0; var v = p1 - p0; var lu = u.Length; var lv = v.Length; var relativeEpsilonU = absoluteEpsilon / lu; var RelativeEpsilonV = absoluteEpsilon / lv; var cross = u.X * v.Y - u.Y * v.X; if (!Fun.IsTiny(cross)) { // non-parallel lines cross = 1 / cross; var t0 = (a.Y * v.X - a.X * v.Y) * cross; if (t0 > 1 + relativeEpsilonU || t0 < -relativeEpsilonU) { p = V2f.NaN; return false; } var t1 = (a.Y * u.X - a.X * u.Y) * cross; if (t1 > 1 + RelativeEpsilonV || t1 < -RelativeEpsilonV) { p = V2f.NaN; return false; } p = line.P0 + u * t0; return true; } else { // parallel lines if (!overlapping) { p = V2f.NaN; return false; } var normalizedDirection = u / lu; var r0 = new Range1f(0, lu); var r1 = new Range1f((p0 - line.P0).Dot(normalizedDirection), (p1 - line.P0).Dot(normalizedDirection)); r1.Repair(); if (r0.Intersects(r1, absoluteEpsilon, out Range1f result)) { p = line.P0 + normalizedDirection * result.Min; return true; } p = V2f.NaN; return false; } } #endregion #region Ray2f intersects Line2f /// /// Returns true if the Ray and the Line intersect. /// ATTENTION: Both-Sided Ray /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray2f ray, Line2f line ) { return ray.IntersectsLine(line.P0, line.P1, out _); } /// /// returns true if the Ray and the Line intersect. /// t holds the smallest Intersection-Parameter for the Ray /// ATTENTION: t can be negative /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray2f ray, Line2f line, out float t ) { return ray.IntersectsLine(line.P0, line.P1, out t); } /// /// returns true if the Ray and the Line(p0,p1) intersect. /// ATTENTION: Both-Sided Ray /// public static bool IntersectsLine( this Ray2f ray, V2f p0, V2f p1 ) { V2f n = new V2f(-ray.Direction.Y, ray.Direction.X); float d0 = n.Dot(p0 - ray.Origin); float d1 = n.Dot(p1 - ray.Origin); if (d0.Sign() != d1.Sign()) return true; else if (Fun.IsTiny(d0) && Fun.IsTiny(d1)) return true; else return false; } /// /// returns true if the Ray and the Line(p0,p1) intersect. /// t holds the Intersection-Parameter for the Ray /// If both Line-Points are on the Ray no Intersection is returned /// ATTENTION: t can be negative /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine( this Ray2f ray, V2f p0, V2f p1, out float t ) { return ray.IntersectsLine(p0, p1, false, out t); } /// /// returns true if the Ray and the Line(p0,p1) intersect. /// if overlapping is true t holds the smallest Intersection-Parameter for the Ray /// if overlagging is false and both Line-Points are on the Ray no Intersection is returned /// ATTENTION: t can be negative /// public static bool IntersectsLine( this Ray2f ray, V2f p0, V2f p1, bool overlapping, out float t ) { V2f a = p0 - ray.Origin; V2f u = p1 - p0; V2f v = ray.Direction; float lv2 = v.LengthSquared; float cross = u.X * v.Y - u.Y * v.X; float n = a.Y * u.X - a.X * u.Y; if (!Fun.IsTiny(cross)) { cross = 1 / cross; float t0 = (a.Y * v.X - a.X * v.Y) * cross; if (t0 >= 0 && t0 <= 1) { t = n * cross; return true; } t = float.NaN; return false; } if (Fun.IsTiny(n) && overlapping) { float ta = v.Dot(a) / lv2; float tb = v.Dot(p1 - ray.Origin) / lv2; if ((ta < 0 && tb > 0) || (ta > 0 && tb < 0)) { t = 0; return true; } else { if (ta >= 0) t = Fun.Min(ta, tb); else t = Fun.Max(ta, tb); return true; } } t = float.NaN; return false; } #endregion #region Ray2f intersects Ray2f /// /// Returns true if the Rays intersect /// ATTENTION: Both-Sided Rays /// public static bool Intersects( this Ray2f r0, Ray2f r1 ) { if (!r0.Direction.IsParallelTo(r1.Direction)) return true; else { V2f n0 = new V2f(-r0.Direction.Y, r0.Direction.X); if (Fun.IsTiny(n0.Dot(r1.Origin - r0.Origin))) return true; else return false; } } /// /// Returns true if the Rays intersect /// t0 and t1 are the corresponding Ray-Parameters for the Intersection /// ATTENTION: Both-Sided Rays /// public static bool Intersects( this Ray2f r0, Ray2f r1, out float t0, out float t1 ) { V2f a = r0.Origin - r1.Origin; if (r0.Origin.ApproximateEquals(r1.Origin, Constant.PositiveTinyValue)) { t0 = 0; t1 = 0; return true; } V2f u = r0.Direction; V2f v = r1.Direction; float cross = u.X * v.Y - u.Y * v.X; if (!Fun.IsTiny(cross)) { //Rays not parallel cross = 1 / cross; t0 = (a.Y * v.X - a.X * v.Y) * cross; t1 = (a.Y * u.X - a.X * u.Y) * cross; return true; } else { t0 = float.NaN; t1 = float.NaN; //Rays are parallel if (Fun.IsTiny(a.Y * u.X - a.X * u.Y)) return true; else return false; } } /// /// Returns true if the Rays intersect. /// public static bool Intersects(this Ray2f r0, Ray2f r1, out float t) { V2f a = r1.Origin - r0.Origin; if (a.Abs().AllSmaller(Constant.PositiveTinyValue)) { t = 0; return true; // Early exit when rays have same origin } float cross = r0.Direction.Dot270(r1.Direction); if (!Fun.IsTiny(cross)) // Rays not parallel { t = r1.Direction.Dot90(a) / cross; return true; } else // Rays are parallel { t = float.NaN; return false; } } #endregion #region Ray2f intersects Circle2f /// /// Computes the intersection between the given and . /// /// The ray to intersect. /// The circle to intersect the ray with. /// The ray parameter of the first intersection. Set to infinity if there is no intersection. /// The ray parameter of the second intersection. Set to infinity if there is no intersection. /// True if there is an intersection, false otherwise. public static bool Intersects(this Ray2f ray, Circle2f circle, out float t0, out float t1) { var p = ray.Origin - circle.Center; var a = ray.Direction.X.Square() + ray.Direction.Y.Square(); var b = 2 * ray.Direction.X * p.X + 2 * ray.Direction.Y * p.Y; var c = p.X.Square() + p.Y.Square() - circle.Radius.Square(); var d = b.Square() - 4 * a * c; if (d < 0) { t0 = float.PositiveInfinity; t1 = float.PositiveInfinity; return false; } else { var div = 1 / (a + a); d = d.Sqrt(); t0 = (-b + d) * div; t1 = (-b - d) * div; return true; } } #endregion #region Plane2f intersects Line2f /// /// Returns true if the Plane2f and the Line2f intersect or the Line2f /// lies completely in the Plane's Epsilon-Range /// ATTENTION: Works only with Normalized Plane2ds /// public static bool Intersects( this Plane2f plane, Line2f line, float absoluteEpsilon ) { float lengthOfNormal2 = plane.Normal.LengthSquared; float d0 = plane.Height(line.P0); float d1 = plane.Height(line.P1); return d0 * d1 < absoluteEpsilon * absoluteEpsilon * lengthOfNormal2; } /// /// Returns true if the Plane2f and the Line2f intersect /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Plane2f plane, Line2f line ) { return plane.IntersectsLine(line.P0, line.P1); } /// /// Returns true if the Plane2f and the line between p0 and p1 intersect /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine( this Plane2f plane, V2f p0, V2f p1 ) { float d0 = plane.Height(p0); float d1 = plane.Height(p1); return d0 * d1 <= 0; } /// /// Returns true if the Plane2f and the Line2f intersect /// point holds the Intersection-Point. If no Intersection is found point is V2f.NaN /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Plane2f plane, Line2f line, out V2f point ) { return plane.Intersects(line, 0, out point); } /// /// Returns true if the Plane2f and the Line2f intersect or the Line2f /// lies completely in the Plane's Epsilon-Range /// point holds the Intersection-Point. If the Line2f is inside Epsilon point holds the centroid of the Line2f /// If no Intersection is found point is V2f.NaN /// ATTENTION: Works only with Normalized Plane2ds /// public static bool Intersects( this Plane2f plane, Line2f line, float absoluteEpsilon, out V2f point ) { float h0 = plane.Height(line.P0); float h1 = plane.Height(line.P1); int s0 = (h0 > -absoluteEpsilon ? (h0 < absoluteEpsilon ? 0 : 1) : -1); int s1 = (h1 > -absoluteEpsilon ? (h1 < absoluteEpsilon ? 0 : 1) : -1); if (s0 == s1) { if (s0 != 0) { point = V2f.NaN; return false; } else { point = (line.P0 + line.P1) * 0.5f; return true; } } else { if (s0 == 0) { point = line.P0; return true; } else if (s1 == 0) { point = line.P1; return true; } else { V2f dir = line.Direction; float no = plane.Normal.Dot(line.P0); float nd = plane.Normal.Dot(dir); float t = (plane.Distance - no) / nd; point = line.P0 + t * dir; return true; } } } #endregion #region Plane2f intersects Ray2f /// /// Returns true if the Plane2f and the Ray2f intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane2f plane, Ray2f ray) => !plane.Normal.IsOrthogonalTo(ray.Direction); /// /// Returns true if the Plane2d and the Ray2d intersect. /// point holds the Intersection-Point if an intersection is found (else V2d.NaN) /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane2f plane, Ray2f ray, out V2f point) => plane.Intersects(ray, out float t, out point); /// /// Returns true if the Plane2f and the Ray2f intersect. /// t holds the ray paramater of the intersection point if the intersection is found (else Double.PositiveInfinity). /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane2f plane, Ray2f ray, out float t) { float dot = Vec.Dot(plane.Normal, ray.Direction); if (Fun.IsTiny(dot)) { t = float.PositiveInfinity; return false; } t = -plane.Height(ray.Origin) / dot; return true; } /// /// Returns true if the Plane2f and the Ray2f intersect. /// t and p hold the ray paramater and point of the intersection if one is found (else Double.PositiveInfinity and V2f.PositiveInfinity). /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane2f plane, Ray2f ray, out float t, out V2f p) { bool result = Intersects(plane, ray, out t); p = ray.Origin + t * ray.Direction; return result; } /// /// Returns the intersection point of the given Plane2f and Ray2f, or V2f.PositiveInfinity if ray is parallel to plane. /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Intersect(this Plane2f plane, Ray2f ray) { float dot = Vec.Dot(ray.Direction, plane.Normal); if (Fun.IsTiny(dot)) return V2f.PositiveInfinity; return ray.GetPointOnRay(-plane.Height(ray.Origin) / dot); } #endregion #region Plane2f intersects Plane2f /// /// Returns true if the two Plane2ds intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane2f p0, Plane2f p1) { var hit = p0.Coefficients.Cross(p1.Coefficients); return !hit.Z.IsTiny(); } /// /// Returns true if the two Plane2ds intersect. /// Point holds the intersection point if an intersection is found. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane2f p0, Plane2f p1, out V2f point) { var hit = p0.Coefficients.Cross(p1.Coefficients); point = hit.XY / hit.Z; return !hit.Z.IsTiny(); } #endregion #region Plane2f intersects IEnumerable /// /// returns true if the Plane2f divides the Point-Cloud /// public static bool Divides( this Plane2f plane, IEnumerable data ) { int first = int.MinValue; foreach (var p in data) { if (first == int.MinValue) { first = plane.Height(p).Sign(); } else { if (plane.Height(p).Sign() != first) return true; } } return false; } #endregion #region Circle2f intersects Circle2f (sm) /// /// Returns true if the circles intersect, or one contains the other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Circle2f c0, Circle2f c1) => (c0.Center - c1.Center).LengthSquared <= (c0.Radius + c1.Radius).Square(); #endregion #region Triangle2f intersects Line2f /// /// Returns true if the triangle and the line intersect or the triangle contains the line /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Triangle2f triangle, Line2f line ) { return triangle.IntersectsLine(line.P0, line.P1); } /// /// Returns true if the triangle and the line between p0 and p1 intersect or the triangle contains the line /// public static bool IntersectsLine( this Triangle2f triangle, V2f p0, V2f p1 ) { if(triangle.Contains(p0))return true; if(triangle.Contains(p1))return true; if(triangle.Line01.IntersectsLine(p0,p1))return true; if(triangle.Line12.IntersectsLine(p0,p1))return true; if(triangle.Line20.IntersectsLine(p0,p1))return true; return false; } #endregion #region Triangle2f intersects Ray2f /// /// Returns true if the Triangle and the Ray intersect /// public static bool Intersects( this Triangle2f triangle, Ray2f ray ) { if (triangle.Contains(ray.Origin)) return true; if (ray.IntersectsLine(triangle.P0, triangle.P1)) return true; if (ray.IntersectsLine(triangle.P1, triangle.P2)) return true; if (ray.IntersectsLine(triangle.P2, triangle.P0)) return true; return false; } #endregion #region Triangle2f intersects Plane2f /// /// returns true if the Triangle2f and the Plane2f intersect /// public static bool Intersects( this Triangle2f triangle, Plane2f plane ) { if (plane.Intersects(triangle.Line01)) return true; if (plane.Intersects(triangle.Line12)) return true; if (plane.Intersects(triangle.Line20)) return true; return false; } #endregion #region Triangle2f intersects Triangle2f /// /// Returns true if the triangles intersect or one contains the other. /// public static bool Intersects(this Triangle2f t0, Triangle2f t1) { var l = t0.Line01; if (l.IntersectsLine(t1.P0, t1.P1)) return true; if (l.IntersectsLine(t1.P1, t1.P2)) return true; if (l.IntersectsLine(t1.P2, t1.P0)) return true; l = t0.Line12; if (l.IntersectsLine(t1.P0, t1.P1)) return true; if (l.IntersectsLine(t1.P1, t1.P2)) return true; if (l.IntersectsLine(t1.P2, t1.P0)) return true; l = t0.Line20; if (l.IntersectsLine(t1.P0, t1.P1)) return true; if (l.IntersectsLine(t1.P1, t1.P2)) return true; if (l.IntersectsLine(t1.P2, t1.P0)) return true; if (t0.Contains(t1.P0)) return true; if (t1.Contains(t0.P0)) return true; return false; } #endregion #region Box2f intersects Line2f /// /// Returns true if the box and the line intersect. /// public static bool Intersects(this Box2f box, Line2f line) { var out0 = box.OutsideFlags(line.P0); if (out0 == 0) return true; var out1 = box.OutsideFlags(line.P1); if (out1 == 0) return true; return box.IntersectsLine(line.P0, line.P1, out0, out1); } /// /// Returns true if the box and the line intersect. The outside flags /// of the end points of the line with respect to the box have to be /// supplied as parameters. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Box2f box, Line2f line, Box.Flags out0, Box.Flags out1) { return box.IntersectsLine(line.P0, line.P1, out0, out1); } /// /// Returns true if the box and the line intersect. The outside flags /// of the end points of the line with respect to the box have to be /// supplied as parameters. /// private static bool IntersectsLine( this Box2f box, V2f p0, V2f p1) { var out0 = box.OutsideFlags(p0); if (out0 == 0) return true; var out1 = box.OutsideFlags(p1); if (out1 == 0) return true; return box.IntersectsLine(p0, p1, out0, out1); } /// /// Returns true if the box and the line intersect. The outside flags /// of the end points of the line with respect to the box have to be /// supplied as parameters. /// private static bool IntersectsLine( this Box2f box, V2f p0, V2f p1, Box.Flags out0, Box.Flags out1) { if ((out0 & out1) != 0) return false; V2f min = box.Min; V2f max = box.Max; var bf = out0 | out1; if ((bf & Box.Flags.X) != 0) { float dx = p1.X - p0.X; if ((bf & Box.Flags.MinX) != 0) { if (dx == 0 && p0.X < min.X) return false; float t = (min.X - p0.X) / dx; V2f p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MinX) == 0) return true; } if ((bf & Box.Flags.MaxX) != 0) { if (dx == 0 && p0.X > max.X) return false; float t = (max.X - p0.X) / dx; V2f p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MaxX) == 0) return true; } } if ((bf & Box.Flags.Y) != 0) { float dy = p1.Y - p0.Y; if ((bf & Box.Flags.MinY) != 0) { if (dy == 0 && p0.Y < min.Y) return false; float t = (min.Y - p0.Y) / dy; V2f p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MinY) == 0) return true; } if ((bf & Box.Flags.MaxY) != 0) { if (dy == 0 && p0.Y > max.Y) return false; float t = (max.Y - p0.Y) / dy; V2f p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MaxY) == 0) return true; } } return false; } #endregion #region Box2f intersects Ray2f /// /// Returns true if the box and the ray intersect /// public static bool Intersects( this Box2f box, Ray2f ray ) { /* * Getting a Normal-Vector for the Ray and calculating * the Normal Distances for every Box-Point: */ V2f n = new V2f(-ray.Direction.Y, ray.Direction.X); float d0 = n.Dot(box.Min - ray.Origin); //n.Dot(box.p0 - ray.Origin) float d1 = n.X * (box.Max.X - ray.Origin.X) + n.Y * (box.Min.Y - ray.Origin.Y); //n.Dot(box.p1 - ray.Origin) float d2 = n.Dot(box.Max - ray.Origin); //n.Dot(box.p2 - ray.Origin) float d3 = n.X * (box.Min.X - ray.Origin.X) + n.Y * (box.Max.Y - ray.Origin.Y); //n.Dot(box.p3 - ray.Origin) /* * If Zero lies in the Range of the Distances there * have to be Points on both sides of the Ray. * This means the Box and the Ray have an Intersection */ Range1f r = new Range1f(d0, d1, d2, d3); return r.Contains(0); } #endregion #region Box2f intersects Plane2f /// /// returns true if the box and the plane intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Box2f box, Plane2f plane ) { //UNTESTED return plane.Divides(box.ComputeCorners()); } /// /// NOT TESTED YET. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Box2f box, Plane2f plane, out Line2f line) { return Intersects( plane.Normal.X, plane.Normal.Y, plane.Distance, box.Min.X, box.Min.Y, box.Max.X, box.Max.Y, out line); } /// /// Intersects an infinite line given by its normal vector [nx, ny] /// and its distance to the origin d, with an axis aligned box given /// by it minimal point [xmin, ymin] and its maximal point /// [xmax, ymax]. Returns true if there is an intersection and computes /// the actual intersection line. /// NOT TESTED YET. /// public static bool Intersects( float nx, float ny, float d, float xmin, float ymin, float xmax, float ymax, out Line2f line) { if (nx.IsTiny()) // horizontal { if (d <= ymin || d >= ymax) { line = default; return false; } line = new Line2f(new V2f(xmin, d), new V2f(xmax, d)); return true; } if (ny.IsTiny()) // vertical { if (d <= xmin || d >= xmax) { line = default; return false; } line = new Line2f(new V2f(d, ymin), new V2f(d, ymax)); return true; } if (nx.Sign() != ny.Sign()) { float x0 = (d - ny * ymin) / nx; if (x0 >= xmax) { line = default; return false; } if (x0 > xmin) xmin = x0; float x1 = (d - ny * ymax) / nx; if (x1 <= xmin) { line = default; return false; } if (x1 < xmax) xmax = x1; float y0 = (d - nx * xmin) / ny; if (y0 >= ymax) { line = default; return false; } if (y0 > ymin) ymin = y0; float y1 = (d - nx * xmax) / ny; if (y1 <= ymin) { line = default; return false; } if (y1 < ymax) ymax = y1; line = new Line2f(new V2f(xmin, ymin), new V2f(xmax, ymax)); } else { float x0 = (d - ny * ymax) / nx; if (x0 >= xmax) { line = default; return false; } if (x0 > xmin) xmin = x0; float x1 = (d - ny * ymin) / nx; if (x1 <= xmin) { line = default; return false; } if (x1 < xmax) xmax = x1; float y0 = (d - nx * xmax) / ny; if (y0 >= ymax) { line = default; return false; } if (y0 > ymin) ymin = y0; float y1 = (d - nx * xmin) / ny; if (y1 <= ymin) { line = default; return false; } if (y1 < ymax) ymax = y1; line = new Line2f(new V2f(xmax, ymin), new V2f(xmin, ymax)); } return true; } #endregion #region Box2f intersects Triangle2f /// /// Returns true if the Box and the Triangle intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Box2f box, Triangle2f triangle ) { return box.IntersectsTriangle(triangle.P0, triangle.P1, triangle.P2); } /// /// Returns true if the Box and the Triangle intersect /// public static bool IntersectsTriangle( this Box2f box, V2f p0, V2f p1, V2f p2 ) { var out0 = box.OutsideFlags(p0); if (out0 == 0) return true; var out1 = box.OutsideFlags(p1); if (out1 == 0) return true; var out2 = box.OutsideFlags(p2); if (out2 == 0) return true; return box.IntersectsTriangle(p0, p1, p2, out0, out1, out2); } /// /// Returns true if the Box and the Triangle intersect. The outside flags /// of the end points of the Triangle with respect to the box have to be /// supplied as parameters. /// private static bool IntersectsTriangle( this Box2f box, V2f p0, V2f p1, V2f p2, Box.Flags out0, Box.Flags out1, Box.Flags out2 ) { /* --------------------------------------------------------------- If all of the points of the triangle are on the same side outside the box, no intersection is possible. --------------------------------------------------------------- */ if ((out0 & out1 & out2) != 0) return false; /* --------------------------------------------------------------- If two points of the triangle are not on the same side outside the box, it is possible that the edge between them intersects the box. The outside flags we computed are also used to optimize the intersection routine with the edge. --------------------------------------------------------------- */ if (box.IntersectsLine(p0, p1, out0, out1)) return true; if (box.IntersectsLine(p1, p2, out1, out2)) return true; if (box.IntersectsLine(p2, p0, out2, out0)) return true; /* --------------------------------------------------------------- The only case left: The triangle contains the the whole box i.e. every point. When no triangle-line intersects the box and one box point is inside the triangle the triangle must contain the box --------------------------------------------------------------- */ V2f a = box.Min - p0; V2f u = p1 - p0; V2f v = p2 - p0; float cross = u.X * v.Y - u.Y * v.X; if (Fun.IsTiny(cross)) return false; cross = 1 / cross; float t0 = (a.Y * v.X - a.X * v.Y) * cross; if (t0 < 0 || t0 > 1) return false; float t1 = (a.Y * u.X - a.X * u.Y) * cross; if (t1 < 0 || t1 > 1) return false; return (t0 + t1 < 1); } #endregion #region Box2f intersects Box2f (Box2f-Implementation) //Directly in Box-Implementation #endregion #region Quad2f intersects Line2f /// /// returns true if the Quad and the line intersect or the quad contains the line /// public static bool Intersects( this Quad2f quad, Line2f line ) { if (quad.Contains(line.P0)) return true; if (quad.Contains(line.P1)) return true; if (line.IntersectsLine(quad.P0, quad.P1)) return true; if (line.IntersectsLine(quad.P1, quad.P2)) return true; if (line.IntersectsLine(quad.P2, quad.P3)) return true; if (line.IntersectsLine(quad.P3, quad.P0)) return true; return false; } /// /// returns true if the Quad and the line between p0 and p1 intersect or the quad contains the line /// public static bool IntersectsLine( this Quad2f quad, V2f p0, V2f p1 ) { if (quad.Contains(p0)) return true; if (quad.Contains(p1)) return true; Line2f line = new Line2f(p0, p1); if (line.IntersectsLine(quad.P0, quad.P1)) return true; if (line.IntersectsLine(quad.P1, quad.P2)) return true; if (line.IntersectsLine(quad.P2, quad.P3)) return true; if (line.IntersectsLine(quad.P3, quad.P0)) return true; return false; } #endregion #region Quad2f intersects Ray2f /// /// returns true if the quad and the ray intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Quad2f quad, Ray2f ray ) { return ray.Plane2f.Divides(quad.Points); } #endregion #region Quad2f intersects Plane2f /// /// returns true if the Quad2f and the Plane2f intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Quad2f quad, Plane2f plane ) { //UNTESTED if (plane.Divides(quad.Points)) return true; else return false; } #endregion #region Quad2f intersects Triangle2f /// /// returns true if the Quad2f and the Triangle2f intersect or one contains the other /// public static bool Intersects( this Quad2f quad, Triangle2f triangle ) { if (quad.Intersects(triangle.Line01)) return true; if (quad.Intersects(triangle.Line12)) return true; if (quad.Intersects(triangle.Line20)) return true; if (quad.Contains(triangle.P0)) return true; if (triangle.Contains(quad.P0)) return true; return false; } #endregion #region Quad2f intersects Box2f /// /// Returns true if the box and the Quad intersect or one contains the other /// public static bool Intersects( this Box2f box, Quad2f quad ) { Box.Flags out0 = box.OutsideFlags(quad.P0); if (out0 == 0) return true; Box.Flags out1 = box.OutsideFlags(quad.P1); if (out1 == 0) return true; Box.Flags out2 = box.OutsideFlags(quad.P2); if (out2 == 0) return true; Box.Flags out3 = box.OutsideFlags(quad.P3); if (out3 == 0) return true; /* --------------------------------------------------------------- If all of the points of the Quad are on the same side outside the box, no intersection is possible. --------------------------------------------------------------- */ if ((out0 & out1 & out2 & out3) != 0) return false; /* --------------------------------------------------------------- If two points of the Quad are not on the same side outside the box, it is possible that the edge between them intersects the box. The outside flags we computed are also used to optimize the intersection routine with the edge. --------------------------------------------------------------- */ if (box.IntersectsLine(quad.P0, quad.P1, out0, out1)) return true; if (box.IntersectsLine(quad.P1, quad.P2, out1, out2)) return true; if (box.IntersectsLine(quad.P2, quad.P3, out2, out3)) return true; if (box.IntersectsLine(quad.P3, quad.P0, out3, out0)) return true; /* --------------------------------------------------------------- The only case left: The Quad contains the the whole box i.e. every point. When no triangle-line intersects the box and one box point is inside the Quad the Quad must contain the box --------------------------------------------------------------- */ return quad.Contains(box.Min); } #endregion #region Quad2f intersects Quad2f /// /// returns true if the Quad2ds intersect or one contains the other /// public static bool Intersects( this Quad2f q0, Quad2f quad ) { if (q0.IntersectsLine(quad.P0, quad.P1)) return true; if (q0.IntersectsLine(quad.P1, quad.P2)) return true; if (q0.IntersectsLine(quad.P2, quad.P3)) return true; if (q0.IntersectsLine(quad.P3, quad.P0)) return true; if (q0.Contains(quad.P0)) return true; if (quad.Contains(q0.P0)) return true; return false; } #endregion #region Polygon2f intersects Line2f /// /// returns true if the Polygon2f and the Line2f intersect or the Polygon contains the Line /// public static bool Intersects( this Polygon2f poly, Line2f line ) { foreach (var l in poly.EdgeLines) { if (l.Intersects(line)) return true; } if (poly.Contains(line.P0)) return true; return false; } #endregion #region Polygon2f intersects Ray2f /// /// returns true if the Polygon2f and the Ray2f intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Polygon2f poly, Ray2f ray ) { //UNTESTED return ray.Plane2f.Divides(poly.Points); } #endregion #region Polygon2f intersects Plane2f /// /// returns true if the Polygon2f and the Plane2f itnersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Polygon2f poly, Plane2f plane ) { //UNTESTED return plane.Divides(poly.Points); } #endregion #region Polygon2f intersects Triangle2f /// /// returns true if the Polygon2f and the Triangle2f intersect or one contains the other /// public static bool Intersects( this Polygon2f poly, Triangle2f triangle ) { foreach (var line in poly.EdgeLines) { if (triangle.Intersects(line)) return true; } if (triangle.Contains(poly[0])) return true; if (poly.Contains(triangle.P0)) return true; return false; } #endregion #region Polygon2f intersects Box2f /// /// returns true if the Polygon2f and the Box2f intersect or one contains the other /// public static bool Intersects( this Polygon2f poly, Box2f box ) { //UNTESTED int count = poly.PointCount; Box.Flags[] outFlags = new Box.Flags[count]; int i0 = 0; foreach (var p in poly.Points) outFlags[i0++] = box.OutsideFlags(p); i0 = 0; int i1 = 1; foreach (var l in poly.EdgeLines) { if (box.Intersects(l, outFlags[i0], outFlags[i1])) return true; i0++; i1 = (i1 + 1) % count; } if (box.Contains(poly[0])) return true; if (poly.Contains(box.Min)) return true; return false; } #endregion #region Polygon2f intersects Quad2f /// /// returns true if the Polygon2f and the Quad2f interset or one contains the other /// public static bool Intersects( this Polygon2f poly, Quad2f quad ) { foreach (var l in poly.EdgeLines) { if (quad.Intersects(l)) return true; } if (quad.Contains(poly[0])) return true; if (poly.Contains(quad.P0)) return true; return false; } #endregion #region Polygon2f intersects Polygon2f /// /// returns true if the Polygon2ds intersect or one contains the other /// public static bool Intersects( this Polygon2f poly0, Polygon2f poly1 ) { //check if projected ranges intersect for all possible normals V2f[] allnormals = new V2f[poly0.PointCount + poly1.PointCount]; int c = 0; foreach (var d in poly0.Edges) { allnormals[c] = new V2f(-d.Y, d.X); c++; } foreach (var d in poly1.Edges) { allnormals[c] = new V2f(-d.Y, d.X); c++; } foreach (var n in allnormals) { var r0 = poly0.ProjectTo(n); var r1 = poly1.ProjectTo(n); if (!r0.Intersects(r1)) return false; } return true; } private static Range1f ProjectTo(this Polygon2f poly, V2f dir) { float min = float.MaxValue; float max = float.MinValue; foreach (var p in poly.Points) { float dotproduct = p.Dot(dir); if (dotproduct < min) min = dotproduct; if (dotproduct > max) max = dotproduct; } return new Range1f(min, max); } #endregion #region Line3f intersects Line3f (haaser) /// /// Returns true if the minimal distance between the given lines is smaller than Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Line3f l0, Line3f l1 ) { return l0.Intersects(l1, Constant.PositiveTinyValue); } /// /// Returns true if the minimal distance between the given lines is smaller than absoluteEpsilon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Line3f l0, Line3f l1, float absoluteEpsilon ) { if (l0.GetMinimalDistanceTo(l1) < absoluteEpsilon) return true; else return false; } /// /// Returns true if the minimal distance between the given lines is smaller than absoluteEpsilon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Line3f l0, Line3f l1, float absoluteEpsilon, out V3f point ) { if (l0.GetMinimalDistanceTo(l1, out point) < absoluteEpsilon) return true; else return false; } #endregion #region Line3f intersects Special (inconsistent argument order) #region Line3f intersects Plane3f /// /// Returns true if the line and the plane intersect. /// public static bool Intersects( this Line3f line, Plane3f plane, out float t ) { if (!line.Ray3f.Intersects(plane, out t)) return false; if (t >= 0 && t <= 1) return true; t = float.PositiveInfinity; return false; } /// /// Returns true if the line and the plane intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Line3f line, Plane3f plane, out float t, out V3f p ) { bool result = line.Intersects(plane, out t); p = line.Origin + t * line.Direction; return result; } #endregion #region Line3f intersects Triangle3f /// /// Returns true if the line and the triangle intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Line3f line, Triangle3f triangle ) { return line.Ray3f.IntersectsTriangle(triangle.P0, triangle.P1, triangle.P2, 0, 1, out _); } /// /// Returns true if the line and the triangle intersect. /// point holds the intersection point. /// public static bool Intersects( this Line3f line, Triangle3f triangle, out V3f point ) { Ray3f ray = line.Ray3f; if (ray.IntersectsTriangle(triangle.P0, triangle.P1, triangle.P2, 0, 1, out float temp)) { point = ray.GetPointOnRay(temp); return true; } else { point = V3f.NaN; return false; } } #endregion #endregion #region Ray3f intersects Line3f (haaser) /// /// Returns true if the minimal distance between the line and the ray is smaller than Constant<float>.PositiveTinyValue /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3f ray, Line3f line ) { return ray.Intersects(line, Constant.PositiveTinyValue); } /// /// Returns true if the minimal distance between the line and the ray is smaller than absoluteEpsilon /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3f ray, Line3f line, float absoluteEpsilon ) { if (ray.GetMinimalDistanceTo(line) < absoluteEpsilon) return true; else return false; } /// /// Returns true if the minimal distance between the line and the ray is smaller than absoluteEpsilon /// t holds the corresponding ray parameter /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3f ray, Line3f line, float absoluteEpsilon, out float t ) { if (ray.GetMinimalDistanceTo(line, out t) < absoluteEpsilon) return true; else return false; } #endregion #region Ray3f intersects Ray3f (haaser) /// /// returns true if the minimal distance between the rays is smaller than Constant<float>.PositiveTinyValue /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3f r0, Ray3f r1 ) { return r0.Intersects(r1, out _, out _, Constant.PositiveTinyValue); } /// /// returns true if the minimal distance between the rays is smaller than Constant<float>.PositiveTinyValue /// t0 and t1 hold the ray-parameters for the intersection /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3f r0, Ray3f r1, out float t0, out float t1 ) { return r0.Intersects(r1, out t0, out t1, Constant.PositiveTinyValue); } /// /// returns true if the minimal distance between the rays is smaller than absoluteEpsilon /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3f r0, Ray3f r1, float absoluteEpsilon ) { return r0.Intersects(r1, out _, out _, absoluteEpsilon); } /// /// returns true if the minimal distance between the rays is smaller than absoluteEpsilon /// t0 and t1 hold the ray-parameters for the intersection /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3f r0, Ray3f r1, out float t0, out float t1, float absoluteEpsilon ) { if (r0.GetMinimalDistanceTo(r1, out t0, out t1) < absoluteEpsilon) return true; else return false; } #endregion #region Ray3f intersects Special (inconsistent argument order) #region Ray3f intersects Triangle3f /// /// Returns true if the ray and the triangle intersect. If you need /// information about the hit point see the Ray3f.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Ray3f ray, Triangle3f triangle) => ray.IntersectsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, float.MinValue, float.MaxValue); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3f.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Ray3f ray, Triangle3f triangle, float tmin, float tmax) => ray.IntersectsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, tmin, tmax); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3f.Hits method. /// t holds the corresponding ray-parameter /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Ray3f ray, Triangle3f triangle, float tmin, float tmax, out float t) => ray.IntersectsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, tmin, tmax, out t); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3f.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsTriangle(this Ray3f ray, V3f p0, V3f p1, V3f p2, float tmin, float tmax) => ray.IntersectsTriangle(p0, p1, p2, tmin, tmax, out float _); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3f.Hits method. /// t holds the corresponding ray-parameter /// public static bool IntersectsTriangle(this Ray3f ray, V3f p0, V3f p1, V3f p2, float tmin, float tmax, out float t) { var edge01 = p1 - p0; var edge02 = p2 - p0; var plane = Vec.Cross(ray.Direction, edge02); var det = Vec.Dot(edge01, plane); if (det > -1E-4f && det < 1E-4f) { t = float.NaN; return false; } //ray ~= parallel / Triangle var tv = ray.Origin - p0; det = 1 / det; // det is now inverse det var u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) { t = float.NaN; return false; } plane = Vec.Cross(tv, edge01); // plane is now qv var v = Vec.Dot(ray.Direction, plane) * det; if (v < 0 || u + v > 1) { t = float.NaN; return false; } var temp_t = Vec.Dot(edge02, plane) * det; if (temp_t < tmin || temp_t >= tmax) { t = float.NaN; return false; } t = temp_t; return true; } /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3f.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsTrianglePointAndEdges(this Ray3f ray, V3f p0, V3f edge01, V3f edge02, float tmin, float tmax) => ray.IntersectsTrianglePointAndEdges(p0, edge01, edge02, tmin, tmax, out _); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3f.Hits method. /// t holds the corresponding ray-parameter /// public static bool IntersectsTrianglePointAndEdges(this Ray3f ray, V3f p0, V3f edge01, V3f edge02, float tmin, float tmax, out float t) { var plane = Vec.Cross(ray.Direction, edge02); var det = Vec.Dot(edge01, plane); if (det > -1E-4f && det < 1E-4f) { t = float.NaN; return false; } //ray ~= parallel / Triangle var tv = ray.Origin - p0; det = 1 / det; // det is now inverse det var u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) { t = float.NaN; return false; } plane = Vec.Cross(tv, edge01); // plane is now qv var v = Vec.Dot(ray.Direction, plane) * det; if (v < 0 || u + v > 1) { t = float.NaN; return false; } var temp_t = Vec.Dot(edge02, plane) * det; if (temp_t < tmin || temp_t >= tmax) { t = float.NaN; return false; } t = temp_t; return true; } #endregion #region Ray3f intersects Quad3f /// /// Returns true if the ray and the triangle intersect. If you need /// information about the hit point see the Ray3f.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Ray3f ray, Quad3f quad) => ray.Intersects(quad, float.MinValue, float.MaxValue); /// /// Returns true if the ray and the quad intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3f.Hits method. /// public static bool Intersects(this Ray3f ray, Quad3f quad, float tmin, float tmax) { var edge02 = quad.P2 - quad.P0; return ray.IntersectsTrianglePointAndEdges(quad.P0, quad.Edge01, edge02, tmin, tmax) || ray.IntersectsTrianglePointAndEdges(quad.P0, edge02, quad.Edge03, tmin, tmax); } /// /// Returns true if the ray and the quad intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3f.Hits method. /// public static bool IntersectsQuad(this Ray3f ray, V3f p0, V3f p1, V3f p2, V3f p3, float tmin, float tmax) { var edge02 = p2 - p0; return ray.IntersectsTrianglePointAndEdges(p0, p1 - p0, edge02, tmin, tmax) || ray.IntersectsTrianglePointAndEdges(p0, edge02, p3 - p0, tmin, tmax); } #endregion #region Ray3f intersects Polygon3f (haaser) /// /// Returns true if the ray and the polygon intersect within the /// supplied parameter interval of the ray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Ray3f ray, Polygon3f poly, float tmin, float tmax) => ray.Intersects(poly, tmin, tmax, out _); /// /// Returns true if the ray and the polygon intersect within the /// supplied parameter interval of the ray. /// t holds the correspoinding paramter. /// public static bool Intersects(this Ray3f ray, Polygon3f poly, float tmin, float tmax, out float t) { var tris = poly.ComputeTriangulationOfConcavePolygon(1E-5f); var count = tris.Length; for (var i = 0; i < count; i += 3) { if (ray.IntersectsTriangle(poly[tris[i + 0]], poly[tris[i + 1]], poly[tris[i + 2]], tmin, tmax, out t)) { return true; } } t = float.NaN; return false; } /// /// Returns true if the ray and the polygon, which is given by vertices, intersect within the /// supplied parameter interval of the ray. /// (The Method triangulates the polygon) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsPolygon(this Ray3f ray, V3f[] vertices, float tmin, float tmax) => ray.Intersects(new Polygon3f(vertices), tmin, tmax); /// /// Returns true if the ray and the polygon, which is given by vertices and triangulation, intersect within the /// supplied parameter interval of the ray. /// public static bool IntersectsPolygon( this Ray3f ray, V3f[] vertices, int[] triangulation, float tmin, float tmax ) { for (var i = 0; i < triangulation.Length; i += 3) { if (ray.IntersectsTriangle(vertices[triangulation[i + 0]], vertices[triangulation[i + 1]], vertices[triangulation[i + 2]], tmin, tmax)) return true; } return false; } /// /// Returns true if the ray and the polygon, which is given by vertices and triangulation, intersect within the /// supplied parameter interval of the ray. /// public static bool Intersects( this Ray3f ray, Polygon3f polygon, int[] triangulation, float tmin, float tmax ) { for (var i = 0; i < triangulation.Length; i += 3) { if (ray.IntersectsTriangle(polygon[triangulation[i + 0]], polygon[triangulation[i + 1]], polygon[triangulation[i + 2]], tmin, tmax)) return true; } return false; } #endregion #region Ray3f intersects Sphere3f /// /// Returns true if the ray and the triangle intersect. If you need /// information about the hit point see the Ray3f.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Ray3f ray, Sphere3f sphere) => ray.Intersects(sphere, float.MinValue, float.MaxValue); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3f.Hits method. /// public static bool Intersects(this Ray3f ray, Sphere3f sphere, float tmin, float tmax) { // calculate closest point var t = ray.Direction.Dot(sphere.Center - ray.Origin) / ray.Direction.LengthSquared; if (t < 0) t = 0; if (t < tmin) t = tmin; if (t > tmax) t = tmax; V3f p = ray.Origin + t * ray.Direction; // distance to sphere? var d = (p - sphere.Center).LengthSquared; if (d <= sphere.RadiusSquared) return true; return false; } #endregion #region Sphere3f intersects Triangle3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Sphere3f sphere, Triangle3f triangle ) { V3f v = sphere.Center.GetClosestPointOn(triangle) - sphere.Center; return sphere.RadiusSquared >= v.LengthSquared; } #endregion #endregion #region Triangle3f intersects Line3f (haaser) /// /// Returns true if the triangle and the line intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Triangle3f tri, Line3f line ) { return tri.IntersectsLine(line.P0, line.P1, out _); } /// /// Returns true if the triangle and the line intersect. /// point holds the intersection point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Triangle3f tri, Line3f line, out V3f point ) { return tri.IntersectsLine(line.P0, line.P1, out point); } /// /// returns true if the triangle and the line, given by p0 and p1, intersect. /// public static bool IntersectsLine( this Triangle3f tri, V3f p0, V3f p1 ) { V3f edge01 = tri.Edge01; V3f edge02 = tri.Edge02; V3f dir = p1 - p0; V3f plane = Vec.Cross(dir, edge02); float det = Vec.Dot(edge01, plane); if (det > -1E-4f && det < 1E-4f)return false; //ray ~= parallel / Triangle V3f tv = p0 - tri.P0; det = 1 / det; // det is now inverse det float u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) { return false; } plane = Vec.Cross(tv, edge01); // plane is now qv float v = Vec.Dot(dir, plane) * det; if (v < 0 || u + v > 1) { return false; } float temp_t = Vec.Dot(edge02, plane) * det; if (temp_t < 0 || temp_t >= 1) { return false; } return true; } /// /// returns true if the triangle and the line, given by p0 and p1, intersect. /// point holds the intersection point. /// public static bool IntersectsLine( this Triangle3f tri, V3f p0, V3f p1, out V3f point ) { V3f edge01 = tri.Edge01; V3f edge02 = tri.Edge02; V3f dir = p1 - p0; V3f plane = Vec.Cross(dir, edge02); float det = Vec.Dot(edge01, plane); if (det > -1E-4f && det < 1E-4f) { point = V3f.NaN; return false; } //ray ~= parallel / Triangle V3f tv = p0 - tri.P0; det = 1 / det; // det is now inverse det float u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) { point = V3f.NaN; return false; } plane = Vec.Cross(tv, edge01); // plane is now qv float v = Vec.Dot(dir, plane) * det; if (v < 0 || u + v > 1) { point = V3f.NaN; return false; } float temp_t = Vec.Dot(edge02, plane) * det; if (temp_t < 0 || temp_t >= 1) { point = V3f.NaN; return false; } point = p0 + temp_t * dir; return true; } #endregion #region Triangle3f intersects Ray3f (haaser) /// /// Returns true if the triangle and the ray intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Triangle3f tri, Ray3f ray ) { return tri.Intersects(ray, float.MinValue, float.MaxValue, out _); } /// /// Returns true if the triangle and the ray intersect /// within the given parameter interval /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Triangle3f tri, Ray3f ray, float tmin, float tmax ) { return tri.Intersects(ray, tmin, tmax, out _); } /// /// Returns true if the triangle and the ray intersect. /// t holds the intersection paramter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Triangle3f tri, Ray3f ray, out float t ) { return tri.Intersects(ray, float.MinValue, float.MaxValue, out t); } /// /// Returns true if the triangle and the ray intersect /// within the given parameter interval /// t holds the intersection paramter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Triangle3f tri, Ray3f ray, float tmin, float tmax, out float t ) { return ray.Intersects(tri, tmin, tmax, out t); } #endregion #region Triangle3f intersects Triangle3f (haaser) /// /// Returns true if the triangles intersect. /// public static bool Intersects( this Triangle3f t0, Triangle3f t1 ) { if (t0.IntersectsLine(t1.P0, t1.P1, out _)) return true; if (t0.IntersectsLine(t1.P1, t1.P2, out _)) return true; if (t0.IntersectsLine(t1.P2, t1.P0, out _)) return true; if (t1.IntersectsLine(t0.P0, t0.P1, out _)) return true; if (t1.IntersectsLine(t0.P1, t0.P2, out _)) return true; if (t1.IntersectsLine(t0.P2, t0.P0, out _)) return true; return false; } /// /// Returns true if the triangles intersect. /// line holds the cutting-line of the two triangles. /// public static bool Intersects( this Triangle3f t0, Triangle3f t1, out Line3f line ) { List points = new List(); if (t0.IntersectsLine(t1.P0, t1.P1, out V3f temp)) points.Add(temp); if (t0.IntersectsLine(t1.P1, t1.P2, out temp)) points.Add(temp); if (t0.IntersectsLine(t1.P2, t1.P0, out temp)) points.Add(temp); if (points.Count == 2) { line = new Line3f(points[0], points[1]); return true; } if (t1.IntersectsLine(t0.P0, t0.P1, out temp)) points.Add(temp); if (t1.IntersectsLine(t0.P1, t0.P2, out temp)) points.Add(temp); if (t1.IntersectsLine(t0.P2, t0.P0, out temp)) points.Add(temp); if (points.Count == 2) { line = new Line3f(points[0], points[1]); return true; } line = new Line3f(V3f.NaN, V3f.NaN); return false; } #endregion #region Quad3f intersects Line3f (haaser) /// /// Returns true if the quad and the line, given by p0 and p1, intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Quad3f quad, Line3f line) { return quad.IntersectsLine(line.P0, line.P1, out _); } /// /// Returns true if the quad and the line, given by p0 and p1, intersect. /// point holds the intersection point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Quad3f quad, Line3f line, out V3f point) { return quad.IntersectsLine(line.P0, line.P1, out point); } /// /// Returns true if the quad and the line, given by p0 and p1, intersect. /// public static bool IntersectsLine( this Quad3f quad, V3f p0, V3f p1) { Ray3f ray = new Ray3f(p0, p1 - p0); if (quad.Intersects(ray, 0, 1, out _)) { return true; } else { return false; } } /// /// Returns true if the quad and the line, given by p0 and p1, intersect. /// point holds the intersection point. /// public static bool IntersectsLine( this Quad3f quad, V3f p0, V3f p1, out V3f point) { Ray3f ray = new Ray3f(p0, p1 - p0); if (quad.Intersects(ray, 0, 1, out float t)) { point = ray.GetPointOnRay(t); return true; } else { point = V3f.NaN; return false; } } #endregion #region Quad3f intersects Ray3f (haaser) /// /// Returns true if the quad and the ray intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Quad3f quad, Ray3f ray ) { return quad.Intersects(ray, float.MinValue, float.MaxValue, out _); } /// /// Returns true if the quad and the ray intersect. /// t holds the intersection parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Quad3f quad, Ray3f ray, out float t ) { return quad.Intersects(ray, float.MinValue, float.MaxValue, out t); } /// /// Returns true if the quad and the ray intersect /// within the given paramter range /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Quad3f quad, Ray3f ray, float tmin, float tmax ) { return quad.Intersects(ray, tmin, tmax, out _); } /// /// Returns true if the quad and the ray intersect /// within the given paramter range /// t holds the intersection parameter. /// public static bool Intersects( this Quad3f quad, Ray3f ray, float tmin, float tmax, out float t ) { V3f edge02 = quad.P2 - quad.P0; if (ray.IntersectsTrianglePointAndEdges(quad.P0, quad.Edge01, edge02, tmin, tmax, out t)) return true; if (ray.IntersectsTrianglePointAndEdges(quad.P0, edge02, quad.Edge03, tmin, tmax, out t)) return true; t = float.NaN; return false; } #endregion #region Quad3f intersects Triangle3f (haaser) /// /// Returns true if the quad and the triangle intersect. /// public static bool Intersects( this Quad3f quad, Triangle3f tri ) { if (quad.IntersectsLine(tri.P0, tri.P1)) return true; if (quad.IntersectsLine(tri.P1, tri.P2)) return true; if (quad.IntersectsLine(tri.P2, tri.P0)) return true; if (tri.IntersectsLine(quad.P0, quad.P1)) return true; if (tri.IntersectsLine(quad.P1, quad.P2)) return true; if (tri.IntersectsLine(quad.P2, quad.P3)) return true; if (tri.IntersectsLine(quad.P3, quad.P0)) return true; return false; } /// /// Returns true if the quad and the triangle, given by p0/p1/p1, intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsTriangle( this Quad3f quad, V3f p0, V3f p1, V3f p2 ) { Triangle3f tri = new Triangle3f(p0, p1, p2); return quad.Intersects(tri); } #endregion #region Quad3f intersects Quad3f (haaser) /// /// Returns true if the given quads intersect. /// public static bool Intersects( this Quad3f q0, Quad3f q1 ) { if (q0.IntersectsTriangle(q1.P0, q1.P1, q1.P2)) return true; if (q0.IntersectsTriangle(q1.P2, q1.P3, q1.P0)) return true; if (q1.IntersectsTriangle(q0.P0, q0.P1, q0.P2)) return true; if (q1.IntersectsTriangle(q0.P2, q0.P3, q0.P0)) return true; return false; } #endregion #region Plane3f intersects Line3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane3f plane, Line3f line) { return plane.IntersectsLine(line.P0, line.P1, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane3f plane, Line3f line, float absoluteEpsilon) { return plane.IntersectsLine(line.P0, line.P1, absoluteEpsilon); } public static bool IntersectsLine(this Plane3f plane, V3f p0, V3f p1, float absoluteEpsilon) { float h0 = plane.Height(p0); int s0 = (h0 > absoluteEpsilon ? 1 :(h0 < -absoluteEpsilon ? -1 : 0)); if (s0 == 0) return true; float h1 = plane.Height(p1); int s1 = (h1 > absoluteEpsilon ? 1 : (h1 < -absoluteEpsilon ? -1 : 0)); if (s1 == 0) return true; if (s0 == s1) return false; else return true; } public static bool IntersectsLine(this Plane3f plane, V3f p0, V3f p1, float absoluteEpsilon, out V3f point) { // == d // + t0* == d //t0 == (d - ) / ; V3f dir = p1 - p0; float ld = dir.Length; dir /= ld; float nDotd = plane.Normal.Dot(dir); if (!Fun.IsTiny(nDotd)) { float t0 = (plane.Distance - plane.Normal.Dot(p0)) / nDotd; if (t0 >= -absoluteEpsilon && t0 <= ld + absoluteEpsilon) { point = p0 + dir * t0; return true; } else { point = V3f.NaN; return false; } } else { point = V3f.NaN; return false; } } #endregion #region Plane3f intersects Ray3f /// /// Returns true if the Ray3f and the Plane3f intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Ray3f ray, Plane3f plane) => !plane.Normal.IsOrthogonalTo(ray.Direction); /// /// Returns true if the ray and the plane intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3f ray, Plane3f plane, out float t ) { float dot = Vec.Dot(ray.Direction, plane.Normal); if (Fun.IsTiny(dot)) { t = float.PositiveInfinity; return false; } t = -plane.Height(ray.Origin) / dot; return true; } /// /// Returns the intersection point with the given plane, or V3f.PositiveInfinity if ray is parallel to plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Intersect( this Ray3f ray, Plane3f plane ) { float dot = Vec.Dot(ray.Direction, plane.Normal); if (Fun.IsTiny(dot)) return V3f.PositiveInfinity; return ray.GetPointOnRay(-plane.Height(ray.Origin) / dot); } /// /// Returns true if the ray and the plane intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3f ray, Plane3f plane, out float t, out V3f p ) { bool result = Intersects(ray, plane, out t); p = ray.Origin + t * ray.Direction; return result; } #endregion #region Plane3f intersects Plane3f public static bool Intersects(this Plane3f p0, Plane3f p1) { bool parallel = p0.Normal.IsParallelTo(p1.Normal); if (parallel) return Fun.IsTiny(p0.Distance - p1.Distance); else return true; } public static bool Intersects(this Plane3f p0, Plane3f p1, out Ray3f ray) { V3f dir = p0.Normal.Cross(p1.Normal); float len = dir.Length; if (Fun.IsTiny(len)) { if (Fun.IsTiny(p0.Distance - p1.Distance)) { ray = new Ray3f(p0.Normal * p0.Distance, V3f.Zero); return true; } else { ray = Ray3f.Invalid; return false; } } dir *= 1 / len; var alu = new float[,] { { p0.Normal.X, p0.Normal.Y, p0.Normal.Z }, { p1.Normal.X, p1.Normal.Y, p1.Normal.Z }, { dir.X, dir.Y, dir.Z } }; int[] p = alu.LuFactorize(); var b = new float[] { p0.Distance, p1.Distance, 0 }; var x = alu.LuSolve(p, b); ray = new Ray3f(new V3f(x), dir); return true; } #endregion #region Plane3f intersects Plane3f intersects Plane3f public static bool Intersects(this Plane3f p0, Plane3f p1, Plane3f p2, out V3f point) { var alu = new float[,] { { p0.Normal.X, p0.Normal.Y, p0.Normal.Z }, { p1.Normal.X, p1.Normal.Y, p1.Normal.Z }, { p2.Normal.X, p2.Normal.Y, p2.Normal.Z } }; var p = new int[3]; if (!alu.LuFactorize(p)) { point = V3f.NaN; return false; } var b = new float[] { p0.Distance, p1.Distance, p2.Distance }; var x = alu.LuSolve(p, b); point = new V3f(x); return true; } #endregion #region Plane3f intersects Triangle3f /// /// Returns whether the given plane and triangle intersect. /// public static bool Intersects( this Plane3f plane, Triangle3f triangle ) { int sign = plane.Sign(triangle.P0); if (sign == 0) return true; if (sign != plane.Sign(triangle.P1)) return true; if (sign != plane.Sign(triangle.P2)) return true; return false; } #endregion #region Plane3f intersects Sphere3f /// /// Returns whether the given sphere and plane intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Plane3f plane, Sphere3f sphere ) { return sphere.Radius >= plane.Height(sphere.Center).Abs(); } #endregion #region Plane3f intersects Polygon3f /// /// returns true if the Plane3f and the Polygon3f intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Plane3f plane, Polygon3f poly ) { return plane.Intersects(poly, Constant.PositiveTinyValue); } /// /// returns true if the Plane3f and the polygon, intersect /// within a tolerance of absoluteEpsilon /// public static bool Intersects( this Plane3f plane, Polygon3f polygon, float absoluteEpsilon ) { float height = plane.Height(polygon[0]); int sign0 = height > -absoluteEpsilon ? (height < absoluteEpsilon ? 0 : 1) : -1; if (sign0 == 0) return true; int pc = polygon.PointCount; for (int i = 1; i < pc; i++) { height = plane.Height(polygon[i]); int sign = height > -absoluteEpsilon ? (height < absoluteEpsilon ? 0 : 1) : -1; if (sign != sign0) return true; } return false; } /// /// returns true if the Plane3f and the Polygon3f intersect. /// line holds the intersection line /// ATTENTION: works only with non-concave polygons! /// public static bool IntersectsConvex( this Plane3f plane, Polygon3f poly, out Line3f line ) { return plane.IntersectsConvex(poly, Constant.PositiveTinyValue, out line); } /// /// Returns true if the Plane3f and the polygon, given by points, intersect /// within a tolerance of absoluteEpsilon. /// Line holds the intersection line. /// ATTENTION: works only with non-concave polygons! /// public static bool IntersectsConvex( this Plane3f plane, Polygon3f polygon, float absoluteEpsilon, out Line3f line ) { int count = polygon.PointCount; int[] signs = new int[count]; int pc = 0, nc = 0, zc = 0; for (int pi = 0; pi < count; pi++) { float h = plane.Height(polygon[pi]); if (h < -absoluteEpsilon) { nc++; signs[pi] = -1; continue; } if (h > absoluteEpsilon) { pc++; signs[pi] = 1; continue; } zc++; signs[pi] = 0; } if (zc == count) { line = new Line3f(polygon[0], polygon[0]); return false; } else if (pc == 0 && zc == 0) { line = new Line3f(V3f.NaN, V3f.NaN); return false; } else if (nc == 0 && zc == 0) { line = new Line3f(V3f.NaN, V3f.NaN); return false; } else { int pointcount = 0; V3f[] linePoints = new V3f[2]; for (int i = 0; i < count; i++) { int u = (i + 1) % count; if (signs[i] != signs[u] || signs[i] == 0 || signs[u] == 0) { if (plane.IntersectsLine(polygon[i], polygon[u], absoluteEpsilon, out V3f point)) { linePoints[pointcount++] = point; //If Endpoint is on Plane => Next startpoint is on plane => same intersection point // => skip all following lines which start within absoluteEpsilon (whic have a zero sign) while (signs[(i + 1) % count] == 0) i++; } } if (pointcount == 2) { // line = new Line3f(linePoints[0], linePoints[1]); return true; } } line = new Line3f(V3f.NaN, V3f.NaN); return false; } } #endregion #region Plane3f intersects Cylinder3f /// /// Returns whether the given sphere and cylinder intersect. /// public static bool Intersects(this Plane3f plane, Cylinder3f cylinder) { if (plane.IsParallelToAxis(cylinder)) { var distance = cylinder.P0.GetMinimalDistanceTo(plane); return distance < cylinder.Radius; } return true; } /// /// Tests if the given plane is parallel to the cylinder axis (i.e. the plane's normal is orthogonal to the axis). /// The plane will intersect the cylinder in two rays or in one tangent line. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelToAxis(this Plane3f plane, Cylinder3f cylinder) => plane.Normal.IsOrthogonalTo(cylinder.Axis.Direction.Normalized); /// /// Tests if the given plane is orthogonal to the cylinder axis (i.e. the plane's normal is parallel to the axis). /// The plane will intersect the cylinder in a circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalToAxis(this Plane3f plane, Cylinder3f cylinder) => plane.Normal.IsParallelTo(cylinder.Axis.Direction.Normalized); /// /// Returns true if the given plane and cylinder intersect in an ellipse. /// This is only true if the plane is neither orthogonal nor parallel to the cylinder axis. Otherwise the intersection methods returning a circle or rays have to be used. /// /// /// The cylinder is assumed to have infinite extent along its axis. /// public static bool Intersects(this Plane3f plane, Cylinder3f cylinder, out Ellipse3f ellipse) { if (plane.IsParallelToAxis(cylinder) || plane.IsOrthogonalToAxis(cylinder)) { ellipse = Ellipse3f.Zero; return false; } var dir = cylinder.Axis.Direction.Normalized; cylinder.Axis.Ray3f.Intersects(plane, out _, out V3f center); var cosTheta = dir.Dot(plane.Normal); var eNormal = plane.Normal; var eCenter = center; var eMajor = (dir - cosTheta * eNormal).Normalized; var eMinor = (eNormal.Cross(eMajor)).Normalized; eMajor = eNormal.Cross(eMinor).Normalized; //to be sure - if ellipse is nearly a circle eMajor = eMajor * cylinder.Radius / cosTheta.Abs(); eMinor *= cylinder.Radius; ellipse = new Ellipse3f(eCenter, eNormal, eMajor, eMinor); return true; } /// /// Returns true if the given plane and cylinder intersect in a circle. /// This is only true if the plane is orthogonal to the cylinder axis. Otherwise the intersection methods returning an ellipse or rays have to be used. /// /// /// The cylinder is assumed to have infinite extent along its axis. /// public static bool Intersects(this Plane3f plane, Cylinder3f cylinder, out Circle3f circle) { if (plane.IsOrthogonalToAxis(cylinder)) { circle = cylinder.GetCircle(cylinder.GetHeight(plane.Point)); return true; } circle = Circle3f.Zero; return false; } /// /// Returns true if the given plane and cylinder intersect in one or two rays. /// This is only true if the plane is parallel to the cylinder axis. Otherwise the intersection methods returning an ellipse or a circle have to be used. /// /// /// The cylinder is assumed to have infinite extent along its axis. /// Output of intersection rays. The array contains two rays (intersection), one ray (plane is tangent to cylinder) or no ray (no intersection). public static bool Intersects(this Plane3f plane, Cylinder3f cylinder, out Ray3f[] rays) { if (plane.IsParallelToAxis(cylinder)) { var distance = cylinder.P0.GetMinimalDistanceTo(plane); var center = cylinder.P0 - distance * plane.Normal; var axis = cylinder.Axis.Direction.Normalized; if (distance == cylinder.Radius) //one tangent line { rays = new[] { new Ray3f(center, axis) }; return true; } else //two intersection lines { var offset = axis.Cross(plane.Normal); var extent = (cylinder.Radius.Square() - distance.Square()).Sqrt(); rays = new[] { new Ray3f(center - extent * offset, axis), new Ray3f(center + extent * offset, axis) }; return true; } } rays = Array.Empty(); return false; } #endregion #region Sphere3f intersects Sphere3f (sm) /// /// Returns true if the spheres intersect, or one contains the other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Sphere3f s0, Sphere3f s1) => (s0.Center - s1.Center).LengthSquared <= (s0.Radius + s1.Radius).Square(); #endregion #region Box3f intersects Line3f /// /// Returns true if the box and the line intersect. /// public static bool Intersects(this Box3f box, Line3f line) { var out0 = box.OutsideFlags(line.P0); if (out0 == 0) return true; var out1 = box.OutsideFlags(line.P1); if (out1 == 0) return true; return box.IntersectsLine(line.P0, line.P1, out0, out1); } /// /// Returns true if the box and the line intersect. /// public static bool IntersectsLine( this Box3f box, V3f p0, V3f p1) { var out0 = box.OutsideFlags(p0); if (out0 == 0) return true; var out1 = box.OutsideFlags(p1); if (out1 == 0) return true; return box.IntersectsLine(p0, p1, out0, out1); } /// /// Returns true if the box and the line intersect. The outside flags /// of the end points of the line with respect to the box have to be /// supplied, and have to be already individually tested against /// intersection with the box. /// public static bool IntersectsLine( this Box3f box, V3f p0, V3f p1, Box.Flags out0, Box.Flags out1) { if ((out0 & out1) != 0) return false; V3f min = box.Min; V3f max = box.Max; var bf = out0 | out1; if ((bf & Box.Flags.X) != 0) { float dx = p1.X - p0.X; if ((bf & Box.Flags.MinX) != 0) { if (dx == 0 && p0.X < min.X) return false; float t = (min.X - p0.X) / dx; V3f p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MinX) == 0) return true; } if ((bf & Box.Flags.MaxX) != 0) { if (dx == 0 && p0.X > max.X) return false; float t = (max.X - p0.X) / dx; V3f p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MaxX) == 0) return true; } } if ((bf & Box.Flags.Y) != 0) { float dy = p1.Y - p0.Y; if ((bf & Box.Flags.MinY) != 0) { if (dy == 0 && p0.Y < min.Y) return false; float t = (min.Y - p0.Y) / dy; V3f p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MinY) == 0) return true; } if ((bf & Box.Flags.MaxY) != 0) { if (dy == 0 && p0.Y > max.Y) return false; float t = (max.Y - p0.Y) / dy; V3f p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MaxY) == 0) return true; } } if ((bf & Box.Flags.Z) != 0) { float dz = p1.Z - p0.Z; if ((bf & Box.Flags.MinZ) != 0) { if (dz == 0 && p0.Z < min.Z) return false; float t = (min.Z - p0.Z) / dz; V3f p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MinZ) == 0) return true; } if ((bf & Box.Flags.MaxZ) != 0) { if (dz == 0 && p0.Z > max.Z) return false; float t = (max.Z - p0.Z) / dz; V3f p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MaxZ) == 0) return true; } } return false; } #endregion #region Box3f intersects Ray3f (haaser) public static bool Intersects(this Box3f box, Ray3f ray, out float t) { Box.Flags out0 = box.OutsideFlags(ray.Origin); if (out0 == 0) { t = 0; return true; } Box3f largeBox = box.EnlargedByRelativeEps(1E-5f); float tmin = float.PositiveInfinity; float ttemp; if ((out0 & Box.Flags.X) != 0) { if (!Fun.IsTiny(ray.Direction.X)) { if ((out0 & Box.Flags.MinX) != 0) { ttemp = (box.Min.X - ray.Origin.X) / ray.Direction.X; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } else if ((out0 & Box.Flags.MaxX) != 0) { ttemp = (box.Max.X - ray.Origin.X) / ray.Direction.X; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } } } if ((out0 & Box.Flags.Y) != 0) { if (!Fun.IsTiny(ray.Direction.Y)) { if ((out0 & Box.Flags.MinY) != 0) { ttemp = (box.Min.Y - ray.Origin.Y) / ray.Direction.Y; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } else if ((out0 & Box.Flags.MaxY) != 0) { ttemp = (box.Max.Y - ray.Origin.Y) / ray.Direction.Y; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } } } if ((out0 & Box.Flags.Z) != 0) { if (!Fun.IsTiny(ray.Direction.Z)) { if ((out0 & Box.Flags.MinZ) != 0) { ttemp = (box.Min.Z - ray.Origin.Z) / ray.Direction.Z; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } else if ((out0 & Box.Flags.MaxZ) != 0) { ttemp = (box.Max.Z - ray.Origin.Z) / ray.Direction.Z; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } } } if (tmin < float.PositiveInfinity) { t = tmin; return true; } t = float.NaN; return false; } #endregion #region Box3f intersects Plane3f /// /// Returns true if the box and the plane intersect or touch with a /// supplied epsilon tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Box3f box, Plane3f plane, float eps) { var signs = box.GetIntersectionSignsWithPlane(plane, eps); return signs != Signs.Negative && signs != Signs.Positive; } /// /// Classify the position of all the eight vertices of a box with /// respect to a supplied plane. /// public static Signs GetIntersectionSignsWithPlane( this Box3f box, Plane3f plane, float eps) { var normal = plane.Normal; var distance = plane.Distance; float npMinX = normal.X * box.Min.X; float npMaxX = normal.X * box.Max.X; float npMinY = normal.Y * box.Min.Y; float npMaxY = normal.Y * box.Max.Y; float npMinZ = normal.Z * box.Min.Z; float npMaxZ = normal.Z * box.Max.Z; float hMinZ = npMinZ - distance; float hMaxZ = npMaxZ - distance; float hMinYMinZ = npMinY + hMinZ; float hMaxYMinZ = npMaxY + hMinZ; float hMinYMaxZ = npMinY + hMaxZ; float hMaxYMaxZ = npMaxY + hMaxZ; return (npMinX + hMinYMinZ).GetSigns(eps) | (npMaxX + hMinYMinZ).GetSigns(eps) | (npMinX + hMaxYMinZ).GetSigns(eps) | (npMaxX + hMaxYMinZ).GetSigns(eps) | (npMinX + hMinYMaxZ).GetSigns(eps) | (npMaxX + hMinYMaxZ).GetSigns(eps) | (npMinX + hMaxYMaxZ).GetSigns(eps) | (npMaxX + hMaxYMaxZ).GetSigns(eps); } /// /// Returns true if the box intersects the supplied plane. The /// bounding boxes of the resulting parts are returned in the out /// parameters. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Signs GetIntersectionSigns( this Box3f box, Plane3f plane, float eps, out Box3f negBox, out Box3f zeroBox, out Box3f posBox) { return box.GetIntersectionSigns(plane.Normal, plane.Distance, eps, out negBox, out zeroBox, out posBox); } /// /// Returns true if the box intersects the supplied plane. The /// bounding boxes of the resulting parts are returned in the out /// parameters. /// public static Signs GetIntersectionSigns( this Box3f box, V3f normal, float distance, float eps, out Box3f negBox, out Box3f zeroBox, out Box3f posBox) { float npMinX = normal.X * box.Min.X; float npMaxX = normal.X * box.Max.X; float npMinY = normal.Y * box.Min.Y; float npMaxY = normal.Y * box.Max.Y; float npMinZ = normal.Z * box.Min.Z; float npMaxZ = normal.Z * box.Max.Z; var ha = new float[8]; float hMinZ = npMinZ - distance; float hMaxZ = npMaxZ - distance; float hMinYMinZ = npMinY + hMinZ; ha[0] = npMinX + hMinYMinZ; ha[1] = npMaxX + hMinYMinZ; float hMaxYMinZ = npMaxY + hMinZ; ha[2] = npMinX + hMaxYMinZ; ha[3] = npMaxX + hMaxYMinZ; float hMinYMaxZ = npMinY + hMaxZ; ha[4] = npMinX + hMinYMaxZ; ha[5] = npMaxX + hMinYMaxZ; float hMaxYMaxZ = npMaxY + hMaxZ; ha[6] = npMinX + hMaxYMaxZ; ha[7] = npMaxX + hMaxYMaxZ; Signs all = Signs.None; var sa = new Signs[8]; for (int i = 0; i < 8; i++) { sa[i] = ha[i].GetSigns(eps); all |= sa[i]; } negBox = Box3f.Invalid; zeroBox = Box3f.Invalid; posBox = Box3f.Invalid; if (all == Signs.Zero) { zeroBox = box; return all; } if (all == Signs.Positive) { posBox = box; return all; } if (all == Signs.Negative) { negBox = box; return all; } var pa = box.ComputeCorners(); for (int i = 0; i < 8; i++) { if (sa[i] == Signs.Negative) negBox.ExtendBy(pa[i]); else if (sa[i] == Signs.Positive) posBox.ExtendBy(pa[i]); else { negBox.ExtendBy(pa[i]); zeroBox.ExtendBy(pa[i]); posBox.ExtendBy(pa[i]); } } if (all == Signs.NonPositive) { posBox = Box3f.Invalid; return all; } if (all == Signs.NonNegative) { negBox = Box3f.Invalid; return all; } for (int ei = 0; ei < 12; ei++) { int i0 = c_cubeEdgeVertex0[ei], i1 = c_cubeEdgeVertex1[ei]; if ((sa[i0] == Signs.Negative && sa[i1] == Signs.Positive) || (sa[i0] == Signs.Positive && sa[i1] == Signs.Negative)) { float h0 = ha[i0]; float t = h0 / (h0 - ha[i1]); V3f p0 = pa[i0]; V3f sp = p0 + t * (pa[i1] - p0); negBox.ExtendBy(sp); zeroBox.ExtendBy(sp); posBox.ExtendBy(sp); } } return all; } #endregion #region Box3f intersects Sphere3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Box3f box, Sphere3f sphere ) { V3f v = sphere.Center.GetClosestPointOn(box) - sphere.Center; return sphere.RadiusSquared >= v.LengthSquared; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Box3f box, Cylinder3f cylinder ) { return box.Intersects(cylinder.BoundingBox3f); //throw new NotImplementedException(); } #endregion #region Box3f intersects Triangle3f /// /// Returns true if the box and the triangle intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Box3f box, Triangle3f triangle ) { return box.IntersectsTriangle(triangle.P0, triangle.P1, triangle.P2); } /// /// Returns true if the box and the triangle intersect. /// public static bool IntersectsTriangle( this Box3f box, V3f p0, V3f p1, V3f p2 ) { /* --------------------------------------------------------------- If one of the points of the triangle is inside the box, it intersects, of course. --------------------------------------------------------------- */ var out0 = box.OutsideFlags(p0); if (out0 == 0) return true; var out1 = box.OutsideFlags(p1); if (out1 == 0) return true; var out2 = box.OutsideFlags(p2); if (out2 == 0) return true; return box.IntersectsTriangle(p0, p1, p2, out0, out1, out2); } /// /// Returns true if the box and the triangle intersect. The outside /// flags of the triangle vertices with respect to the box have to be /// supplied, and already be individually tested for intersection with /// the box. /// public static bool IntersectsTriangle( this Box3f box, V3f p0, V3f p1, V3f p2, Box.Flags out0, Box.Flags out1, Box.Flags out2 ) { /* --------------------------------------------------------------- If all of the points of the triangle are on the same side outside the box, no intersection is possible. --------------------------------------------------------------- */ if ((out0 & out1 & out2) != 0) return false; /* --------------------------------------------------------------- If two points of the triangle are not on the same side outside the box, it is possible that the edge between them intersects the box. The outside flags we computed are also used to optimize the intersection routine with the edge. --------------------------------------------------------------- */ if (box.IntersectsLine(p0, p1, out0, out1)) return true; if (box.IntersectsLine(p1, p2, out1, out2)) return true; if (box.IntersectsLine(p2, p0, out2, out0)) return true; /* --------------------------------------------------------------- The only case left: the edges of the triangle go outside around the box. Intersect the four space diagonals of the box with the triangle to test for intersection. --------------------------------------------------------------- */ Ray3f ray = new Ray3f(box.Min, box.Size); if (ray.IntersectsTriangle(p0, p1, p2, 0, 1)) return true; ray.Origin.X = box.Max.X; ray.Direction.X = -ray.Direction.X; if (ray.IntersectsTriangle(p0, p1, p2, 0, 1)) return true; ray.Direction.X = -ray.Direction.X; ray.Origin.X = box.Min.X; ray.Origin.Y = box.Max.Y; ray.Direction.Y = -ray.Direction.Y; if (ray.IntersectsTriangle(p0, p1, p2, 0, 1)) return true; ray.Direction.Y = -ray.Direction.Y; ray.Origin.Y = box.Min.Y; ray.Origin.Z = box.Max.Z; ray.Direction.Z = -ray.Direction.Z; if (ray.IntersectsTriangle(p0, p1, p2, 0, 1)) return true; return false; } #endregion #region Box3f intersects Quad3f (haaser) public static bool Intersects( this Box3f box, Quad3f quad ) { Box.Flags out0 = box.OutsideFlags(quad.P0); if (out0 == 0) return true; Box.Flags out1 = box.OutsideFlags(quad.P1); if (out1 == 0) return true; Box.Flags out2 = box.OutsideFlags(quad.P2); if (out2 == 0) return true; Box.Flags out3 = box.OutsideFlags(quad.P3); if (out3 == 0) return true; return box.IntersectsQuad(quad.P0, quad.P1, quad.P2, quad.P3, out0, out1, out2, out3); } public static bool IntersectsQuad( this Box3f box, V3f p0, V3f p1, V3f p2, V3f p3 ) { var out0 = box.OutsideFlags(p0); if (out0 == 0) return true; var out1 = box.OutsideFlags(p1); if (out1 == 0) return true; var out2 = box.OutsideFlags(p2); if (out2 == 0) return true; var out3 = box.OutsideFlags(p3); if (out3 == 0) return true; return box.IntersectsQuad(p0, p1, p2, p3, out0, out1, out2, out3); } public static bool IntersectsQuad( this Box3f box, V3f p0, V3f p1, V3f p2, V3f p3, Box.Flags out0, Box.Flags out1, Box.Flags out2, Box.Flags out3 ) { /* --------------------------------------------------------------- If all of the points of the quad are on the same side outside the box, no intersection is possible. --------------------------------------------------------------- */ if ((out0 & out1 & out2 & out3) != 0) return false; /* --------------------------------------------------------------- If two points of the quad are not on the same side outside the box, it is possible that the edge between them intersects the box. The outside flags we computed are also used to optimize the intersection routine with the edge. --------------------------------------------------------------- */ if (box.IntersectsLine(p0, p1, out0, out1)) return true; if (box.IntersectsLine(p1, p2, out1, out2)) return true; if (box.IntersectsLine(p2, p3, out2, out3)) return true; if (box.IntersectsLine(p3, p0, out3, out0)) return true; /* --------------------------------------------------------------- The only case left: the edges of the quad go outside around the box. Intersect the four space diagonals of the box with the triangle to test for intersection. --------------------------------------------------------------- */ Ray3f ray = new Ray3f(box.Min, box.Size); if (ray.IntersectsQuad(p0, p1, p2, p3, 0, 1)) return true; ray.Origin.X = box.Max.X; ray.Direction.X = -ray.Direction.X; if (ray.IntersectsQuad(p0, p1, p2, p3, 0, 1)) return true; ray.Direction.X = -ray.Direction.X; ray.Origin.X = box.Min.X; ray.Origin.Y = box.Max.Y; ray.Direction.Y = -ray.Direction.Y; if (ray.IntersectsQuad(p0, p1, p2, p3, 0, 1)) return true; ray.Direction.Y = -ray.Direction.Y; ray.Origin.Y = box.Min.Y; ray.Origin.Z = box.Max.Z; ray.Direction.Z = -ray.Direction.Z; if (ray.IntersectsQuad(p0, p1, p2, p3, 0, 1)) return true; return false; } #endregion #region Box3f intersects Polygon3f (haaser) public static bool Intersects(this Box3f box, Polygon3f poly) { int edges = poly.PointCount; Box.Flags[] outside = new Box.Flags[edges]; for (int i = 0; i < edges; i++) { outside[i] = box.OutsideFlags(poly[i]); if (outside[i] == 0) return true; } /* --------------------------------------------------------------- If all of the points of the polygon are on the same side outside the box, no intersection is possible. --------------------------------------------------------------- */ Box.Flags sum = outside[0]; for (int i = 1; i < edges; i++) sum &= outside[i]; if (sum != 0) return false; /* --------------------------------------------------------------- If two points of the polygon are not on the same side outside the box, it is possible that the edge between them intersects the box. The outside flags we computed are also used to optimize the intersection routine with the edge. --------------------------------------------------------------- */ int u; for (int i = 0; i < edges; i++) { u = (i + 1) % edges; if (box.IntersectsLine(poly[i], poly[u], outside[i], outside[u])) return true; } /* --------------------------------------------------------------- The only case left: the edges of the polygon go outside around the box. Intersect the four space diagonals of the box with the triangle to test for intersection. The polygon needs to be triangulated for this check --------------------------------------------------------------- */ int[] tris = poly.ComputeTriangulationOfConcavePolygon(1E-5f); Ray3f ray = new Ray3f(box.Min, box.Size); if (ray.Intersects(poly, tris, 0, 1)) return true; ray.Origin.X = box.Max.X; ray.Direction.X = -ray.Direction.X; if (ray.Intersects(poly, tris, 0, 1)) return true; ray.Direction.X = -ray.Direction.X; ray.Origin.X = box.Min.X; ray.Origin.Y = box.Max.Y; ray.Direction.Y = -ray.Direction.Y; if (ray.Intersects(poly, tris, 0, 1)) return true; ray.Direction.Y = -ray.Direction.Y; ray.Origin.Y = box.Min.Y; ray.Origin.Z = box.Max.Z; ray.Direction.Z = -ray.Direction.Z; if (ray.Intersects(poly, tris, 0, 1)) return true; return false; } #endregion #region Box3f intersects Projection-Trafo (haaser) /// /// returns true if the Box3f and the frustum described by the M44f intersect or the frustum contains the Box3f /// Assumes DirectX clip-space: /// -w < x < w /// -w < y < w /// 0 < z < w /// public static bool IntersectsFrustum(this Box3f box, M44f projection) { //Let's look at the left clip-plane //which corresponds to: //-w < x // # which can easily be transformed to: //0 < x + w // # for a given vector v this means (* is a dot product here) //0 < proj.R0 * v + proj.R3 * v // # or in other words: //0 < (proj.R0 + proj.R3) * v //therefore (proj.R0 + proj.R3) is the plane describing the left clip-plane. //The other planes can be derived in a similar way (only the near plane is a little different) //see http://fgiesen.wordpress.com/2012/08/31/frustum-planes-from-the-projection-matrix/ for a full explanation var r0 = projection.R0; var r1 = projection.R1; var r2 = projection.R2; var r3 = projection.R3; V4f plane; V3f n; //left plane = r3 + r0; n = plane.XYZ; box.GetMinMaxInDirection(n, out V3f min, out V3f max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; //right plane = r3 - r0; n = plane.XYZ; box.GetMinMaxInDirection(n, out min, out max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; //top plane = r3 + r1; n = plane.XYZ; box.GetMinMaxInDirection(n, out min, out max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; //bottom plane = r3 - r1; n = plane.XYZ; box.GetMinMaxInDirection(n, out min, out max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; //near plane = r2; n = plane.XYZ; box.GetMinMaxInDirection(n, out min, out max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; //far plane = r3 - r2; n = plane.XYZ; box.GetMinMaxInDirection(n, out min, out max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; return true; } #endregion #region Hull3f intersects Line3f /// /// returns true if the Hull3f and the Line3f intersect or the Hull3f contains the Line3f /// [Hull3f-Normals must point outside] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Hull3f hull, Line3f line ) { if (hull.Contains(line.P0)) return true; if (hull.Contains(line.P1)) return true; return hull.Intersects(line.Ray3f, 0, 1, out _); } /// /// returns true if the Hull3f and the Line between p0 and p1 intersect or the Hull3f contains the Line /// [Hull3f-Normals must point outside] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine( this Hull3f hull, V3f p0, V3f p1 ) { return hull.Intersects(new Line3f(p0, p1)); } #endregion #region Hull3f intersects Ray3f /// /// returns true if the Hull3f and the Ray3f intersect /// [Hull3f-Normals must point outside] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Hull3f hull, Ray3f ray ) { return hull.Intersects(ray, float.NegativeInfinity, float.PositiveInfinity, out _); } /// /// returns true if the Hull3f and the Ray3f intersect /// the out parameter t holds the ray-parameter where an intersection was found /// [Hull3f-Normals must point outside] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Hull3f hull, Ray3f ray, out float t ) { return hull.Intersects(ray, float.NegativeInfinity, float.PositiveInfinity, out t); } /// /// returns true if the Hull3f and the Ray3f intersect and the /// ray-parameter for the intersection is between t_min and t_max /// the out parameter t holds the ray-parameter where an intersection was found /// [Hull3f-Normals must point outside] /// public static bool Intersects( this Hull3f hull, Ray3f ray, float t_min, float t_max, out float t ) { if (!float.IsInfinity(t_min) && hull.Contains(ray.GetPointOnRay(t_min))) { t = t_min; return true; } if (!float.IsInfinity(t_max) && hull.Contains(ray.GetPointOnRay(t_max))) { t = t_max; return true; } var planes = hull.PlaneArray; for (int i = 0; i < planes.Length; i++) { if (!Fun.IsTiny(planes[i].Normal.Dot(ray.Direction)) && ray.Intersects(planes[i], out float temp_t) && temp_t >= t_min && temp_t <= t_max) { V3f candidatePoint = ray.GetPointOnRay(temp_t); bool contained = true; for (int u = 0; u < planes.Length; u++) { if (u != i && planes[u].Height(candidatePoint) > Constant.PositiveTinyValue) { contained = false; break; } } if (contained) { t = temp_t; return true; } } } t = float.NaN; return false; } #endregion #region Hull3f intersects Plane3f /// /// returns true if the Hull3f and the Plane3f intersect /// [Hull3f-Normals must point outside] /// public static bool Intersects( this Hull3f hull, Plane3f plane ) { foreach (var p in hull.PlaneArray) { if (!p.Normal.IsParallelTo(plane.Normal) && p.Intersects(plane, out Ray3f ray)) { if (hull.Intersects(ray)) return true; } } return false; } #endregion #region Hull3f intersects Box3f /// /// Returns true if the hull and the box intersect. /// public static bool Intersects( this Hull3f hull, Box3f box ) { if (box.IsInvalid) return false; bool intersecting = false; foreach (Plane3f p in hull.PlaneArray) { box.GetMinMaxInDirection(p.Normal, out V3f min, out V3f max); if (p.Height(min) > 0) return false; // outside if (p.Height(max) >= 0) intersecting = true; } if (intersecting) return true; // intersecting return true; // inside } /// Test hull against intersection of the supplied bounding box. /// Note that this is a conservative test, since in some cases /// around the edges of the hull it may return true although the /// hull does not intersect the box. public static bool Intersects( this FastHull3f fastHull, Box3f box) { var planes = fastHull.Hull.PlaneArray; int count = planes.Length; bool intersecting = false; for (int pi = 0; pi < count; pi++) { int minCornerIndex = fastHull.MinCornerIndexArray[pi]; if (planes[pi].Height(box.Corner(minCornerIndex)) > 0) return false; if (planes[pi].Height(box.Corner(minCornerIndex ^ 7)) >= 0) intersecting = true; } if (intersecting) return true; return true; } #endregion #region Hull3f intersects Sphere3f /// /// Returns true if the hull and the sphere intersect. /// public static bool Intersects( this Hull3f hull, Sphere3f sphere ) { if (sphere.IsInvalid) return false; bool intersecting = false; foreach (Plane3f p in hull.PlaneArray) { float height = p.Height(sphere.Center); if (height > sphere.Radius) return false; // outside if (height.Abs() < sphere.Radius) intersecting = true; } if (intersecting) return true; // intersecting return true; // inside } #endregion #region Plane3f intersects Box3f /// /// Returns true if the box and the plane intersect or touch with a /// supplied epsilon tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane3f plane, float eps, Box3f box) => box.Intersects(plane, eps); #endregion // Contains-tests should return true if the contained object is // either entirely inside the containing object or lies on the // boundary of the containing object. #region Triangle2d contains V2d public static bool Contains( this Triangle2d triangle, V2d point ) { var v0p = point - triangle.P0; return triangle.Line01.LeftValueOfDir(v0p) >= 0 && triangle.Line02.RightValueOfDir(v0p) >= 0 && triangle.Line12.LeftValueOfPos(point) >= 0; } #endregion #region Triangle2d contains Line2d (sm) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Triangle2d triangle, Line2d linesegment) => triangle.Contains(linesegment.P0) && triangle.Contains(linesegment.P1); #endregion #region Triangle2d contains Triangle2d (sm) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Triangle2d triangle, Triangle2d other) => triangle.Contains(other.P0) && triangle.Contains(other.P1) && triangle.Contains(other.P2); #endregion #region Triangle2d contains Quad2d (sm) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Triangle2d triangle, Quad2d q) => triangle.Contains(q.P0) && triangle.Contains(q.P1) && triangle.Contains(q.P2) && triangle.Contains(q.P3); #endregion #region Triangle2d contains Circle2d public static bool Contains(this Triangle2d triangle, Circle2d circle) { var center = circle.Center; return triangle.Contains(center) && circle.Radius <= center.GetMinimalDistanceTo(triangle.Line01) && circle.Radius <= center.GetMinimalDistanceTo(triangle.Line12) && circle.Radius <= center.GetMinimalDistanceTo(triangle.Line20); } #endregion #region Circle2d contains V2d (sm) /// /// True if point p is contained in this circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Circle2d circle, V2d p) => (p - circle.Center).LengthSquared <= circle.RadiusSquared; #endregion #region Circle2d contains Line2d (sm) /// /// True if line segment is contained in this circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Circle2d circle, Line2d l) => circle.Contains(l.P0) && circle.Contains(l.P1); #endregion #region Circle2d contains Triangle2d (sm) /// /// True if triangle is contained in this circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Circle2d circle, Triangle2d t) => circle.Contains(t.P0) && circle.Contains(t.P1) && circle.Contains(t.P2); #endregion #region Circle2d contains Quad2d (sm) /// /// True if quad is contained in this circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Circle2d circle, Quad2d q) => circle.Contains(q.P0) && circle.Contains(q.P1) && circle.Contains(q.P2) && circle.Contains(q.P3); #endregion #region Circle2d contains Circle2d (sm) /// /// True if other circle is contained in this circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Circle2d circle, Circle2d other) => (other.Center - circle.Center).Length + other.Radius <= circle.Radius; #endregion #region Quad2d contains V2d (haaser) /// /// True if point is contained in this quad. /// public static bool Contains(this Quad2d quad, V2d point) { return LeftValOfPos(0, 1, ref point) >= 0 && LeftValOfPos(1, 2, ref point) >= 0 && LeftValOfPos(2, 3, ref point) >= 0 && LeftValOfPos(3, 0, ref point) >= 0; double LeftValOfPos(int i0, int i1, ref V2d p) => (p.X - quad[i0].X) * (quad[i0].Y - quad[i1].Y) + (p.Y - quad[i0].Y) * (quad[i1].X - quad[i0].X); } #endregion #region Quad2d contains Line2d /// /// True if line segment is contained in this quad. /// public static bool Contains(this Quad2d quad, Line2d l) => quad.Contains(l.P0) && quad.Contains(l.P1); #endregion #region Quad2d contains Triangle2d /// /// True if triangle is contained in this quad. /// public static bool Contains(this Quad2d quad, Triangle2d t) => quad.Contains(t.P0) && quad.Contains(t.P1) && quad.Contains(t.P2); #endregion #region Quad2d contains Quad2d /// /// True if other quad is contained in this quad. /// public static bool Contains(this Quad2d quad, Quad2d q) => quad.Contains(q.P0) && quad.Contains(q.P1) && quad.Contains(q.P2) && quad.Contains(q.P3); #endregion #region Quad2d contains Circle2d /// /// True if circle is contained in this quad. /// public static bool Contains(this Quad2d quad, Circle2d circle) { var center = circle.Center; return quad.Contains(center) && circle.Radius <= center.GetMinimalDistanceTo(quad.Line01) && circle.Radius <= center.GetMinimalDistanceTo(quad.Line12) && circle.Radius <= center.GetMinimalDistanceTo(quad.Line23) && circle.Radius <= center.GetMinimalDistanceTo(quad.Line30); } #endregion #region Box3d contains Quad3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains( this Box3d box, Quad3d quad ) { return box.Contains(quad.P0) && box.Contains(quad.P1) && box.Contains(quad.P2) && box.Contains(quad.P3); } #endregion #region Box3d contains Triangle3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains( this Box3d box, Triangle3d triangle ) { return box.Contains(triangle.P0) && box.Contains(triangle.P1) && box.Contains(triangle.P2); } #endregion #region Box3d contains Sphere3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains( this Box3d box, Sphere3d sphere ) { return box.Contains(sphere.Center) && !box.Intersects(sphere); } #endregion #region Box3d contains Cylinder3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains( this Box3d box, Cylinder3d cylinder ) { return box.Contains(cylinder.Center) && !box.Intersects(cylinder); } #endregion #region Hull3d contains V3d /// /// Hull normals are expected to point outside. /// public static bool Contains(this Hull3d hull, V3d point) { var planes = hull.PlaneArray; for (var i = 0; i < planes.Length; i++) { if (planes[i].Height(point) > 0) return false; } return true; } #endregion #region Hull3d contains Sphere3d (sm) /// /// Hull normals are expected to point outside. /// public static bool Contains(this Hull3d hull, Sphere3d sphere) { var planes = hull.PlaneArray; var negativeRadius = -sphere.Radius; for (var i = 0; i < planes.Length; i++) { if (planes[i].Height(sphere.Center) > negativeRadius) return false; } return true; } #endregion #region Polygon2d contains V2d (haaser) internal static V3i InsideTriangleFlags(ref V2d p0, ref V2d p1, ref V2d p2, ref V2d point) { V2d n0 = new V2d(p0.Y - p1.Y, p1.X - p0.X); V2d n1 = new V2d(p1.Y - p2.Y, p2.X - p1.X); V2d n2 = new V2d(p2.Y - p0.Y, p0.X - p2.X); int t0 = Fun.Sign(n0.Dot(point - p0)); int t1 = Fun.Sign(n1.Dot(point - p1)); int t2 = Fun.Sign(n2.Dot(point - p2)); if (t0 == 0) t1 = 1; if (t1 == 0) t1 = 1; if (t2 == 0) t2 = 1; return new V3i(t0, t1, t2); } internal static V3i InsideTriangleFlags(ref V2d p0, ref V2d p1, ref V2d p2, ref V2d point, int t0) { V2d n1 = new V2d(p1.Y - p2.Y, p2.X - p1.X); V2d n2 = new V2d(p2.Y - p0.Y, p0.X - p2.X); int t1 = Fun.Sign(n1.Dot(point - p1)); int t2 = Fun.Sign(n2.Dot(point - p2)); if (t1 == 0) t1 = 1; if (t2 == 0) t2 = 1; return new V3i(t0, t1, t2); } /// /// Returns true if the Polygon2d contains the given point. /// Works with all (convex and non-convex) Polygons. /// Assumes that the Vertices of the Polygon are sorted counter clockwise /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Polygon2d poly, V2d point) { return poly.Contains(point, true); } /// /// Returns true if the Polygon2d contains the given point. /// Works with all (convex and non-convex) Polygons. /// CCW represents the sorting order of the Polygon-Vertices (true -> CCW, false -> CW) /// public static bool Contains(this Polygon2d poly, V2d point, bool CCW) { int pc = poly.PointCount; if (pc < 3) return false; int counter = 0; V2d p0 = poly[0], p1 = poly[1], p2 = poly[2]; V3i temp = InsideTriangleFlags(ref p0, ref p1, ref p2, ref point); int t2_cache = temp.Z; if (temp.X == temp.Y && temp.Y == temp.Z) counter += temp.X; for (int pi = 3; pi < pc; pi++) { p1 = p2; p2 = poly[pi]; temp = InsideTriangleFlags(ref p0, ref p1, ref p2, ref point, -t2_cache); t2_cache = temp.Z; if (temp.X == temp.Y && temp.Y == temp.Z) counter += temp.X; } if (CCW) return counter > 0; else return counter < 0; } #endregion #region Plane3d +- eps contains V3d (sm) /// /// Returns true if point is within given eps to plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Plane3d plane, double eps, V3d point) { var d = plane.Height(point); return d >= -eps && d <= eps; } #endregion #region Plane3d +- eps contains Box3d (sm) /// /// Returns true if the space within eps to a plane fully contains the given box. /// public static bool Contains(this Plane3d plane, double eps, Box3d box) { var corners = box.ComputeCorners(); for (var i = 0; i < 8; i++) { var d = plane.Height(corners[i]); if (d < -eps || d > eps) return false; } return true; } #endregion #region Polygon3d +- eps contains V3d (sm) /// /// Returns true if point is within given eps to polygon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Polygon3d polygon, double eps, V3d point, out double distance) { var plane = polygon.GetPlane3d(); distance = plane.Height(point); if (distance < -eps || distance > eps) return false; var w2p = plane.GetWorldToPlane(); var poly2d = new Polygon2d(polygon.GetPointArray().Map(p => w2p.TransformPos(p).XY)); return poly2d.Contains(w2p.TransformPos(point).XY); } /// /// Returns true if point is within given eps to polygon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Polygon3d polygon, Plane3d supportingPlane, Euclidean3d world2plane, Polygon2d poly2d, double eps, V3d point, out double distance) { distance = supportingPlane.Height(point); if (distance < -eps || distance > eps) return false; return poly2d.Contains(world2plane.TransformPos(point).XY); } /// /// Returns true if point is within given eps to polygon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this Polygon3d polygon, Plane3d supportingPlane, M44d world2plane, Polygon2d poly2d, double eps, V3d point, out double distance) { distance = supportingPlane.Height(point); if (distance < -eps || distance > eps) return false; return poly2d.Contains(world2plane.TransformPos(point).XY); } #endregion // Intersection tests #region Line2d intersects Line2d /// /// Returns true if the two line segments intersect. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Line2d l0, Line2d l1) => l0.IntersectsLine(l1.P0, l1.P1, out V2d _); /// /// Returns true if the two line segments intersect. /// The intersection point is returned in p. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Line2d l0, Line2d l1, out V2d p) => l0.IntersectsLine(l1.P0, l1.P1, out p); /// /// Returns true if the two line segments intersect within given tolerance. /// The intersection point is returned in p. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Line2d l0, Line2d l1, double absoluteEpsilon, out V2d p) => l0.IntersectsLine(l1.P0, l1.P1, absoluteEpsilon, out p); /// /// Returns true if the line segment intersects the line segment between p0 and p1. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine(this Line2d line, V2d p0, V2d p1) => line.IntersectsLine(p0, p1, out _); /// /// Returns true if the line segment intersects the line segment between p0 and p1. /// The intersection point is returned in p. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine(this Line2d line, V2d p0, V2d p1, out V2d p) => line.IntersectsLine(p0, p1, false, out p); /// /// Returns true if the line segment intersects the line segment between p0 and p1. /// The intersection point is returned in p. /// If overlapping is true and the segments are parallel, then /// the closest point to p0 of the intersection range is returned in p. /// public static bool IntersectsLine( this Line2d line, V2d p0, V2d p1, bool overlapping, out V2d p ) { var a = line.P0 - p0; if (Fun.IsTiny(a.LengthSquared)) { p = p0; return true; } var u = line.P1 - line.P0; var v = p1 - p0; var lu = u.Length; var cross = u.X * v.Y - u.Y * v.X; if (!Fun.IsTiny(cross)) { // non-parallel lines cross = 1 / cross; var t0 = (a.Y * v.X - a.X * v.Y) * cross; if (t0 > 1 || t0 < 0) { p = V2d.NaN; return false; } double t1 = (a.Y * u.X - a.X * u.Y) * cross; if (t1 > 1 || t1 < 0) { p = V2d.NaN; return false; } p = line.P0 + u * t0; return true; } else { // parallel lines if (!overlapping) { p = V2d.NaN; return false; } var normalizedDirection = u / lu; var r0 = new Range1d(0, lu); var r1 = new Range1d((p0 - line.P0).Dot(normalizedDirection), (p1 - line.P0).Dot(normalizedDirection)); r1.Repair(); if (r0.Intersects(r1, 0, out Range1d result)) { p = line.P0 + normalizedDirection * result.Min; return true; } p = V2d.NaN; return false; } } /// /// Returns true if the line segment intersects the line segment between p0 and p1 within given tolerance. /// The intersection point is returned in p. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine(this Line2d line, V2d p0, V2d p1, double absoluteEpsilon, out V2d p) => line.IntersectsLine(p0, p1, absoluteEpsilon, false, out p); /// /// Returns true if the line segment intersects the line segment between p0 and p1 within given tolerance. /// The intersection point is returned in p. /// If overlapping is true and the segments are parallel, then /// the closest point to p0 of the intersection range is returned in p. /// public static bool IntersectsLine( this Line2d line, V2d p0, V2d p1, double absoluteEpsilon, bool overlapping, out V2d p ) { var a = line.P0 - p0; if (Fun.IsTiny(a.LengthSquared)) { p = p0; return true; } var u = line.P1 - line.P0; var v = p1 - p0; var lu = u.Length; var lv = v.Length; var relativeEpsilonU = absoluteEpsilon / lu; var RelativeEpsilonV = absoluteEpsilon / lv; var cross = u.X * v.Y - u.Y * v.X; if (!Fun.IsTiny(cross)) { // non-parallel lines cross = 1 / cross; var t0 = (a.Y * v.X - a.X * v.Y) * cross; if (t0 > 1 + relativeEpsilonU || t0 < -relativeEpsilonU) { p = V2d.NaN; return false; } var t1 = (a.Y * u.X - a.X * u.Y) * cross; if (t1 > 1 + RelativeEpsilonV || t1 < -RelativeEpsilonV) { p = V2d.NaN; return false; } p = line.P0 + u * t0; return true; } else { // parallel lines if (!overlapping) { p = V2d.NaN; return false; } var normalizedDirection = u / lu; var r0 = new Range1d(0, lu); var r1 = new Range1d((p0 - line.P0).Dot(normalizedDirection), (p1 - line.P0).Dot(normalizedDirection)); r1.Repair(); if (r0.Intersects(r1, absoluteEpsilon, out Range1d result)) { p = line.P0 + normalizedDirection * result.Min; return true; } p = V2d.NaN; return false; } } #endregion #region Ray2d intersects Line2d /// /// Returns true if the Ray and the Line intersect. /// ATTENTION: Both-Sided Ray /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray2d ray, Line2d line ) { return ray.IntersectsLine(line.P0, line.P1, out _); } /// /// returns true if the Ray and the Line intersect. /// t holds the smallest Intersection-Parameter for the Ray /// ATTENTION: t can be negative /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray2d ray, Line2d line, out double t ) { return ray.IntersectsLine(line.P0, line.P1, out t); } /// /// returns true if the Ray and the Line(p0,p1) intersect. /// ATTENTION: Both-Sided Ray /// public static bool IntersectsLine( this Ray2d ray, V2d p0, V2d p1 ) { V2d n = new V2d(-ray.Direction.Y, ray.Direction.X); double d0 = n.Dot(p0 - ray.Origin); double d1 = n.Dot(p1 - ray.Origin); if (d0.Sign() != d1.Sign()) return true; else if (Fun.IsTiny(d0) && Fun.IsTiny(d1)) return true; else return false; } /// /// returns true if the Ray and the Line(p0,p1) intersect. /// t holds the Intersection-Parameter for the Ray /// If both Line-Points are on the Ray no Intersection is returned /// ATTENTION: t can be negative /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine( this Ray2d ray, V2d p0, V2d p1, out double t ) { return ray.IntersectsLine(p0, p1, false, out t); } /// /// returns true if the Ray and the Line(p0,p1) intersect. /// if overlapping is true t holds the smallest Intersection-Parameter for the Ray /// if overlagging is false and both Line-Points are on the Ray no Intersection is returned /// ATTENTION: t can be negative /// public static bool IntersectsLine( this Ray2d ray, V2d p0, V2d p1, bool overlapping, out double t ) { V2d a = p0 - ray.Origin; V2d u = p1 - p0; V2d v = ray.Direction; double lv2 = v.LengthSquared; double cross = u.X * v.Y - u.Y * v.X; double n = a.Y * u.X - a.X * u.Y; if (!Fun.IsTiny(cross)) { cross = 1 / cross; double t0 = (a.Y * v.X - a.X * v.Y) * cross; if (t0 >= 0 && t0 <= 1) { t = n * cross; return true; } t = double.NaN; return false; } if (Fun.IsTiny(n) && overlapping) { double ta = v.Dot(a) / lv2; double tb = v.Dot(p1 - ray.Origin) / lv2; if ((ta < 0 && tb > 0) || (ta > 0 && tb < 0)) { t = 0; return true; } else { if (ta >= 0) t = Fun.Min(ta, tb); else t = Fun.Max(ta, tb); return true; } } t = double.NaN; return false; } #endregion #region Ray2d intersects Ray2d /// /// Returns true if the Rays intersect /// ATTENTION: Both-Sided Rays /// public static bool Intersects( this Ray2d r0, Ray2d r1 ) { if (!r0.Direction.IsParallelTo(r1.Direction)) return true; else { V2d n0 = new V2d(-r0.Direction.Y, r0.Direction.X); if (Fun.IsTiny(n0.Dot(r1.Origin - r0.Origin))) return true; else return false; } } /// /// Returns true if the Rays intersect /// t0 and t1 are the corresponding Ray-Parameters for the Intersection /// ATTENTION: Both-Sided Rays /// public static bool Intersects( this Ray2d r0, Ray2d r1, out double t0, out double t1 ) { V2d a = r0.Origin - r1.Origin; if (r0.Origin.ApproximateEquals(r1.Origin, Constant.PositiveTinyValue)) { t0 = 0; t1 = 0; return true; } V2d u = r0.Direction; V2d v = r1.Direction; double cross = u.X * v.Y - u.Y * v.X; if (!Fun.IsTiny(cross)) { //Rays not parallel cross = 1 / cross; t0 = (a.Y * v.X - a.X * v.Y) * cross; t1 = (a.Y * u.X - a.X * u.Y) * cross; return true; } else { t0 = double.NaN; t1 = double.NaN; //Rays are parallel if (Fun.IsTiny(a.Y * u.X - a.X * u.Y)) return true; else return false; } } /// /// Returns true if the Rays intersect. /// public static bool Intersects(this Ray2d r0, Ray2d r1, out double t) { V2d a = r1.Origin - r0.Origin; if (a.Abs().AllSmaller(Constant.PositiveTinyValue)) { t = 0; return true; // Early exit when rays have same origin } double cross = r0.Direction.Dot270(r1.Direction); if (!Fun.IsTiny(cross)) // Rays not parallel { t = r1.Direction.Dot90(a) / cross; return true; } else // Rays are parallel { t = double.NaN; return false; } } #endregion #region Ray2d intersects Circle2d /// /// Computes the intersection between the given and . /// /// The ray to intersect. /// The circle to intersect the ray with. /// The ray parameter of the first intersection. Set to infinity if there is no intersection. /// The ray parameter of the second intersection. Set to infinity if there is no intersection. /// True if there is an intersection, false otherwise. public static bool Intersects(this Ray2d ray, Circle2d circle, out double t0, out double t1) { var p = ray.Origin - circle.Center; var a = ray.Direction.X.Square() + ray.Direction.Y.Square(); var b = 2 * ray.Direction.X * p.X + 2 * ray.Direction.Y * p.Y; var c = p.X.Square() + p.Y.Square() - circle.Radius.Square(); var d = b.Square() - 4 * a * c; if (d < 0) { t0 = double.PositiveInfinity; t1 = double.PositiveInfinity; return false; } else { var div = 1 / (a + a); d = d.Sqrt(); t0 = (-b + d) * div; t1 = (-b - d) * div; return true; } } #endregion #region Plane2d intersects Line2d /// /// Returns true if the Plane2d and the Line2d intersect or the Line2d /// lies completely in the Plane's Epsilon-Range /// ATTENTION: Works only with Normalized Plane2ds /// public static bool Intersects( this Plane2d plane, Line2d line, double absoluteEpsilon ) { double lengthOfNormal2 = plane.Normal.LengthSquared; double d0 = plane.Height(line.P0); double d1 = plane.Height(line.P1); return d0 * d1 < absoluteEpsilon * absoluteEpsilon * lengthOfNormal2; } /// /// Returns true if the Plane2d and the Line2d intersect /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Plane2d plane, Line2d line ) { return plane.IntersectsLine(line.P0, line.P1); } /// /// Returns true if the Plane2d and the line between p0 and p1 intersect /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine( this Plane2d plane, V2d p0, V2d p1 ) { double d0 = plane.Height(p0); double d1 = plane.Height(p1); return d0 * d1 <= 0; } /// /// Returns true if the Plane2d and the Line2d intersect /// point holds the Intersection-Point. If no Intersection is found point is V2d.NaN /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Plane2d plane, Line2d line, out V2d point ) { return plane.Intersects(line, 0, out point); } /// /// Returns true if the Plane2d and the Line2d intersect or the Line2d /// lies completely in the Plane's Epsilon-Range /// point holds the Intersection-Point. If the Line2d is inside Epsilon point holds the centroid of the Line2d /// If no Intersection is found point is V2d.NaN /// ATTENTION: Works only with Normalized Plane2ds /// public static bool Intersects( this Plane2d plane, Line2d line, double absoluteEpsilon, out V2d point ) { double h0 = plane.Height(line.P0); double h1 = plane.Height(line.P1); int s0 = (h0 > -absoluteEpsilon ? (h0 < absoluteEpsilon ? 0 : 1) : -1); int s1 = (h1 > -absoluteEpsilon ? (h1 < absoluteEpsilon ? 0 : 1) : -1); if (s0 == s1) { if (s0 != 0) { point = V2d.NaN; return false; } else { point = (line.P0 + line.P1) * 0.5; return true; } } else { if (s0 == 0) { point = line.P0; return true; } else if (s1 == 0) { point = line.P1; return true; } else { V2d dir = line.Direction; double no = plane.Normal.Dot(line.P0); double nd = plane.Normal.Dot(dir); double t = (plane.Distance - no) / nd; point = line.P0 + t * dir; return true; } } } #endregion #region Plane2d intersects Ray2d /// /// Returns true if the Plane2d and the Ray2d intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane2d plane, Ray2d ray) => !plane.Normal.IsOrthogonalTo(ray.Direction); /// /// Returns true if the Plane2d and the Ray2d intersect. /// point holds the Intersection-Point if an intersection is found (else V2d.NaN) /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane2d plane, Ray2d ray, out V2d point) => plane.Intersects(ray, out double t, out point); /// /// Returns true if the Plane2d and the Ray2d intersect. /// t holds the ray paramater of the intersection point if the intersection is found (else Double.PositiveInfinity). /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane2d plane, Ray2d ray, out double t) { double dot = Vec.Dot(plane.Normal, ray.Direction); if (Fun.IsTiny(dot)) { t = double.PositiveInfinity; return false; } t = -plane.Height(ray.Origin) / dot; return true; } /// /// Returns true if the Plane2d and the Ray2d intersect. /// t and p hold the ray paramater and point of the intersection if one is found (else Double.PositiveInfinity and V2d.PositiveInfinity). /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane2d plane, Ray2d ray, out double t, out V2d p) { bool result = Intersects(plane, ray, out t); p = ray.Origin + t * ray.Direction; return result; } /// /// Returns the intersection point of the given Plane2d and Ray2d, or V2d.PositiveInfinity if ray is parallel to plane. /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Intersect(this Plane2d plane, Ray2d ray) { double dot = Vec.Dot(ray.Direction, plane.Normal); if (Fun.IsTiny(dot)) return V2d.PositiveInfinity; return ray.GetPointOnRay(-plane.Height(ray.Origin) / dot); } #endregion #region Plane2d intersects Plane2d /// /// Returns true if the two Plane2ds intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane2d p0, Plane2d p1) { var hit = p0.Coefficients.Cross(p1.Coefficients); return !hit.Z.IsTiny(); } /// /// Returns true if the two Plane2ds intersect. /// Point holds the intersection point if an intersection is found. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane2d p0, Plane2d p1, out V2d point) { var hit = p0.Coefficients.Cross(p1.Coefficients); point = hit.XY / hit.Z; return !hit.Z.IsTiny(); } #endregion #region Plane2d intersects IEnumerable /// /// returns true if the Plane2d divides the Point-Cloud /// public static bool Divides( this Plane2d plane, IEnumerable data ) { int first = int.MinValue; foreach (var p in data) { if (first == int.MinValue) { first = plane.Height(p).Sign(); } else { if (plane.Height(p).Sign() != first) return true; } } return false; } #endregion #region Circle2d intersects Circle2d (sm) /// /// Returns true if the circles intersect, or one contains the other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Circle2d c0, Circle2d c1) => (c0.Center - c1.Center).LengthSquared <= (c0.Radius + c1.Radius).Square(); #endregion #region Triangle2d intersects Line2d /// /// Returns true if the triangle and the line intersect or the triangle contains the line /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Triangle2d triangle, Line2d line ) { return triangle.IntersectsLine(line.P0, line.P1); } /// /// Returns true if the triangle and the line between p0 and p1 intersect or the triangle contains the line /// public static bool IntersectsLine( this Triangle2d triangle, V2d p0, V2d p1 ) { if(triangle.Contains(p0))return true; if(triangle.Contains(p1))return true; if(triangle.Line01.IntersectsLine(p0,p1))return true; if(triangle.Line12.IntersectsLine(p0,p1))return true; if(triangle.Line20.IntersectsLine(p0,p1))return true; return false; } #endregion #region Triangle2d intersects Ray2d /// /// Returns true if the Triangle and the Ray intersect /// public static bool Intersects( this Triangle2d triangle, Ray2d ray ) { if (triangle.Contains(ray.Origin)) return true; if (ray.IntersectsLine(triangle.P0, triangle.P1)) return true; if (ray.IntersectsLine(triangle.P1, triangle.P2)) return true; if (ray.IntersectsLine(triangle.P2, triangle.P0)) return true; return false; } #endregion #region Triangle2d intersects Plane2d /// /// returns true if the Triangle2d and the Plane2d intersect /// public static bool Intersects( this Triangle2d triangle, Plane2d plane ) { if (plane.Intersects(triangle.Line01)) return true; if (plane.Intersects(triangle.Line12)) return true; if (plane.Intersects(triangle.Line20)) return true; return false; } #endregion #region Triangle2d intersects Triangle2d /// /// Returns true if the triangles intersect or one contains the other. /// public static bool Intersects(this Triangle2d t0, Triangle2d t1) { var l = t0.Line01; if (l.IntersectsLine(t1.P0, t1.P1)) return true; if (l.IntersectsLine(t1.P1, t1.P2)) return true; if (l.IntersectsLine(t1.P2, t1.P0)) return true; l = t0.Line12; if (l.IntersectsLine(t1.P0, t1.P1)) return true; if (l.IntersectsLine(t1.P1, t1.P2)) return true; if (l.IntersectsLine(t1.P2, t1.P0)) return true; l = t0.Line20; if (l.IntersectsLine(t1.P0, t1.P1)) return true; if (l.IntersectsLine(t1.P1, t1.P2)) return true; if (l.IntersectsLine(t1.P2, t1.P0)) return true; if (t0.Contains(t1.P0)) return true; if (t1.Contains(t0.P0)) return true; return false; } #endregion #region Box2d intersects Line2d /// /// Returns true if the box and the line intersect. /// public static bool Intersects(this Box2d box, Line2d line) { var out0 = box.OutsideFlags(line.P0); if (out0 == 0) return true; var out1 = box.OutsideFlags(line.P1); if (out1 == 0) return true; return box.IntersectsLine(line.P0, line.P1, out0, out1); } /// /// Returns true if the box and the line intersect. The outside flags /// of the end points of the line with respect to the box have to be /// supplied as parameters. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Box2d box, Line2d line, Box.Flags out0, Box.Flags out1) { return box.IntersectsLine(line.P0, line.P1, out0, out1); } /// /// Returns true if the box and the line intersect. The outside flags /// of the end points of the line with respect to the box have to be /// supplied as parameters. /// private static bool IntersectsLine( this Box2d box, V2d p0, V2d p1) { var out0 = box.OutsideFlags(p0); if (out0 == 0) return true; var out1 = box.OutsideFlags(p1); if (out1 == 0) return true; return box.IntersectsLine(p0, p1, out0, out1); } /// /// Returns true if the box and the line intersect. The outside flags /// of the end points of the line with respect to the box have to be /// supplied as parameters. /// private static bool IntersectsLine( this Box2d box, V2d p0, V2d p1, Box.Flags out0, Box.Flags out1) { if ((out0 & out1) != 0) return false; V2d min = box.Min; V2d max = box.Max; var bf = out0 | out1; if ((bf & Box.Flags.X) != 0) { double dx = p1.X - p0.X; if ((bf & Box.Flags.MinX) != 0) { if (dx == 0 && p0.X < min.X) return false; double t = (min.X - p0.X) / dx; V2d p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MinX) == 0) return true; } if ((bf & Box.Flags.MaxX) != 0) { if (dx == 0 && p0.X > max.X) return false; double t = (max.X - p0.X) / dx; V2d p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MaxX) == 0) return true; } } if ((bf & Box.Flags.Y) != 0) { double dy = p1.Y - p0.Y; if ((bf & Box.Flags.MinY) != 0) { if (dy == 0 && p0.Y < min.Y) return false; double t = (min.Y - p0.Y) / dy; V2d p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MinY) == 0) return true; } if ((bf & Box.Flags.MaxY) != 0) { if (dy == 0 && p0.Y > max.Y) return false; double t = (max.Y - p0.Y) / dy; V2d p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MaxY) == 0) return true; } } return false; } #endregion #region Box2d intersects Ray2d /// /// Returns true if the box and the ray intersect /// public static bool Intersects( this Box2d box, Ray2d ray ) { /* * Getting a Normal-Vector for the Ray and calculating * the Normal Distances for every Box-Point: */ V2d n = new V2d(-ray.Direction.Y, ray.Direction.X); double d0 = n.Dot(box.Min - ray.Origin); //n.Dot(box.p0 - ray.Origin) double d1 = n.X * (box.Max.X - ray.Origin.X) + n.Y * (box.Min.Y - ray.Origin.Y); //n.Dot(box.p1 - ray.Origin) double d2 = n.Dot(box.Max - ray.Origin); //n.Dot(box.p2 - ray.Origin) double d3 = n.X * (box.Min.X - ray.Origin.X) + n.Y * (box.Max.Y - ray.Origin.Y); //n.Dot(box.p3 - ray.Origin) /* * If Zero lies in the Range of the Distances there * have to be Points on both sides of the Ray. * This means the Box and the Ray have an Intersection */ Range1d r = new Range1d(d0, d1, d2, d3); return r.Contains(0); } #endregion #region Box2d intersects Plane2d /// /// returns true if the box and the plane intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Box2d box, Plane2d plane ) { //UNTESTED return plane.Divides(box.ComputeCorners()); } /// /// NOT TESTED YET. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Box2d box, Plane2d plane, out Line2d line) { return Intersects( plane.Normal.X, plane.Normal.Y, plane.Distance, box.Min.X, box.Min.Y, box.Max.X, box.Max.Y, out line); } /// /// Intersects an infinite line given by its normal vector [nx, ny] /// and its distance to the origin d, with an axis aligned box given /// by it minimal point [xmin, ymin] and its maximal point /// [xmax, ymax]. Returns true if there is an intersection and computes /// the actual intersection line. /// NOT TESTED YET. /// public static bool Intersects( double nx, double ny, double d, double xmin, double ymin, double xmax, double ymax, out Line2d line) { if (nx.IsTiny()) // horizontal { if (d <= ymin || d >= ymax) { line = default; return false; } line = new Line2d(new V2d(xmin, d), new V2d(xmax, d)); return true; } if (ny.IsTiny()) // vertical { if (d <= xmin || d >= xmax) { line = default; return false; } line = new Line2d(new V2d(d, ymin), new V2d(d, ymax)); return true; } if (nx.Sign() != ny.Sign()) { double x0 = (d - ny * ymin) / nx; if (x0 >= xmax) { line = default; return false; } if (x0 > xmin) xmin = x0; double x1 = (d - ny * ymax) / nx; if (x1 <= xmin) { line = default; return false; } if (x1 < xmax) xmax = x1; double y0 = (d - nx * xmin) / ny; if (y0 >= ymax) { line = default; return false; } if (y0 > ymin) ymin = y0; double y1 = (d - nx * xmax) / ny; if (y1 <= ymin) { line = default; return false; } if (y1 < ymax) ymax = y1; line = new Line2d(new V2d(xmin, ymin), new V2d(xmax, ymax)); } else { double x0 = (d - ny * ymax) / nx; if (x0 >= xmax) { line = default; return false; } if (x0 > xmin) xmin = x0; double x1 = (d - ny * ymin) / nx; if (x1 <= xmin) { line = default; return false; } if (x1 < xmax) xmax = x1; double y0 = (d - nx * xmax) / ny; if (y0 >= ymax) { line = default; return false; } if (y0 > ymin) ymin = y0; double y1 = (d - nx * xmin) / ny; if (y1 <= ymin) { line = default; return false; } if (y1 < ymax) ymax = y1; line = new Line2d(new V2d(xmax, ymin), new V2d(xmin, ymax)); } return true; } #endregion #region Box2d intersects Triangle2d /// /// Returns true if the Box and the Triangle intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Box2d box, Triangle2d triangle ) { return box.IntersectsTriangle(triangle.P0, triangle.P1, triangle.P2); } /// /// Returns true if the Box and the Triangle intersect /// public static bool IntersectsTriangle( this Box2d box, V2d p0, V2d p1, V2d p2 ) { var out0 = box.OutsideFlags(p0); if (out0 == 0) return true; var out1 = box.OutsideFlags(p1); if (out1 == 0) return true; var out2 = box.OutsideFlags(p2); if (out2 == 0) return true; return box.IntersectsTriangle(p0, p1, p2, out0, out1, out2); } /// /// Returns true if the Box and the Triangle intersect. The outside flags /// of the end points of the Triangle with respect to the box have to be /// supplied as parameters. /// private static bool IntersectsTriangle( this Box2d box, V2d p0, V2d p1, V2d p2, Box.Flags out0, Box.Flags out1, Box.Flags out2 ) { /* --------------------------------------------------------------- If all of the points of the triangle are on the same side outside the box, no intersection is possible. --------------------------------------------------------------- */ if ((out0 & out1 & out2) != 0) return false; /* --------------------------------------------------------------- If two points of the triangle are not on the same side outside the box, it is possible that the edge between them intersects the box. The outside flags we computed are also used to optimize the intersection routine with the edge. --------------------------------------------------------------- */ if (box.IntersectsLine(p0, p1, out0, out1)) return true; if (box.IntersectsLine(p1, p2, out1, out2)) return true; if (box.IntersectsLine(p2, p0, out2, out0)) return true; /* --------------------------------------------------------------- The only case left: The triangle contains the the whole box i.e. every point. When no triangle-line intersects the box and one box point is inside the triangle the triangle must contain the box --------------------------------------------------------------- */ V2d a = box.Min - p0; V2d u = p1 - p0; V2d v = p2 - p0; double cross = u.X * v.Y - u.Y * v.X; if (Fun.IsTiny(cross)) return false; cross = 1 / cross; double t0 = (a.Y * v.X - a.X * v.Y) * cross; if (t0 < 0 || t0 > 1) return false; double t1 = (a.Y * u.X - a.X * u.Y) * cross; if (t1 < 0 || t1 > 1) return false; return (t0 + t1 < 1); } #endregion #region Box2d intersects Box2d (Box2d-Implementation) //Directly in Box-Implementation #endregion #region Quad2d intersects Line2d /// /// returns true if the Quad and the line intersect or the quad contains the line /// public static bool Intersects( this Quad2d quad, Line2d line ) { if (quad.Contains(line.P0)) return true; if (quad.Contains(line.P1)) return true; if (line.IntersectsLine(quad.P0, quad.P1)) return true; if (line.IntersectsLine(quad.P1, quad.P2)) return true; if (line.IntersectsLine(quad.P2, quad.P3)) return true; if (line.IntersectsLine(quad.P3, quad.P0)) return true; return false; } /// /// returns true if the Quad and the line between p0 and p1 intersect or the quad contains the line /// public static bool IntersectsLine( this Quad2d quad, V2d p0, V2d p1 ) { if (quad.Contains(p0)) return true; if (quad.Contains(p1)) return true; Line2d line = new Line2d(p0, p1); if (line.IntersectsLine(quad.P0, quad.P1)) return true; if (line.IntersectsLine(quad.P1, quad.P2)) return true; if (line.IntersectsLine(quad.P2, quad.P3)) return true; if (line.IntersectsLine(quad.P3, quad.P0)) return true; return false; } #endregion #region Quad2d intersects Ray2d /// /// returns true if the quad and the ray intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Quad2d quad, Ray2d ray ) { return ray.Plane2d.Divides(quad.Points); } #endregion #region Quad2d intersects Plane2d /// /// returns true if the Quad2d and the Plane2d intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Quad2d quad, Plane2d plane ) { //UNTESTED if (plane.Divides(quad.Points)) return true; else return false; } #endregion #region Quad2d intersects Triangle2d /// /// returns true if the Quad2d and the Triangle2d intersect or one contains the other /// public static bool Intersects( this Quad2d quad, Triangle2d triangle ) { if (quad.Intersects(triangle.Line01)) return true; if (quad.Intersects(triangle.Line12)) return true; if (quad.Intersects(triangle.Line20)) return true; if (quad.Contains(triangle.P0)) return true; if (triangle.Contains(quad.P0)) return true; return false; } #endregion #region Quad2d intersects Box2d /// /// Returns true if the box and the Quad intersect or one contains the other /// public static bool Intersects( this Box2d box, Quad2d quad ) { Box.Flags out0 = box.OutsideFlags(quad.P0); if (out0 == 0) return true; Box.Flags out1 = box.OutsideFlags(quad.P1); if (out1 == 0) return true; Box.Flags out2 = box.OutsideFlags(quad.P2); if (out2 == 0) return true; Box.Flags out3 = box.OutsideFlags(quad.P3); if (out3 == 0) return true; /* --------------------------------------------------------------- If all of the points of the Quad are on the same side outside the box, no intersection is possible. --------------------------------------------------------------- */ if ((out0 & out1 & out2 & out3) != 0) return false; /* --------------------------------------------------------------- If two points of the Quad are not on the same side outside the box, it is possible that the edge between them intersects the box. The outside flags we computed are also used to optimize the intersection routine with the edge. --------------------------------------------------------------- */ if (box.IntersectsLine(quad.P0, quad.P1, out0, out1)) return true; if (box.IntersectsLine(quad.P1, quad.P2, out1, out2)) return true; if (box.IntersectsLine(quad.P2, quad.P3, out2, out3)) return true; if (box.IntersectsLine(quad.P3, quad.P0, out3, out0)) return true; /* --------------------------------------------------------------- The only case left: The Quad contains the the whole box i.e. every point. When no triangle-line intersects the box and one box point is inside the Quad the Quad must contain the box --------------------------------------------------------------- */ return quad.Contains(box.Min); } #endregion #region Quad2d intersects Quad2d /// /// returns true if the Quad2ds intersect or one contains the other /// public static bool Intersects( this Quad2d q0, Quad2d quad ) { if (q0.IntersectsLine(quad.P0, quad.P1)) return true; if (q0.IntersectsLine(quad.P1, quad.P2)) return true; if (q0.IntersectsLine(quad.P2, quad.P3)) return true; if (q0.IntersectsLine(quad.P3, quad.P0)) return true; if (q0.Contains(quad.P0)) return true; if (quad.Contains(q0.P0)) return true; return false; } #endregion #region Polygon2d intersects Line2d /// /// returns true if the Polygon2d and the Line2d intersect or the Polygon contains the Line /// public static bool Intersects( this Polygon2d poly, Line2d line ) { foreach (var l in poly.EdgeLines) { if (l.Intersects(line)) return true; } if (poly.Contains(line.P0)) return true; return false; } #endregion #region Polygon2d intersects Ray2d /// /// returns true if the Polygon2d and the Ray2d intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Polygon2d poly, Ray2d ray ) { //UNTESTED return ray.Plane2d.Divides(poly.Points); } #endregion #region Polygon2d intersects Plane2d /// /// returns true if the Polygon2d and the Plane2d itnersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Polygon2d poly, Plane2d plane ) { //UNTESTED return plane.Divides(poly.Points); } #endregion #region Polygon2d intersects Triangle2d /// /// returns true if the Polygon2d and the Triangle2d intersect or one contains the other /// public static bool Intersects( this Polygon2d poly, Triangle2d triangle ) { foreach (var line in poly.EdgeLines) { if (triangle.Intersects(line)) return true; } if (triangle.Contains(poly[0])) return true; if (poly.Contains(triangle.P0)) return true; return false; } #endregion #region Polygon2d intersects Box2d /// /// returns true if the Polygon2d and the Box2d intersect or one contains the other /// public static bool Intersects( this Polygon2d poly, Box2d box ) { //UNTESTED int count = poly.PointCount; Box.Flags[] outFlags = new Box.Flags[count]; int i0 = 0; foreach (var p in poly.Points) outFlags[i0++] = box.OutsideFlags(p); i0 = 0; int i1 = 1; foreach (var l in poly.EdgeLines) { if (box.Intersects(l, outFlags[i0], outFlags[i1])) return true; i0++; i1 = (i1 + 1) % count; } if (box.Contains(poly[0])) return true; if (poly.Contains(box.Min)) return true; return false; } #endregion #region Polygon2d intersects Quad2d /// /// returns true if the Polygon2d and the Quad2d interset or one contains the other /// public static bool Intersects( this Polygon2d poly, Quad2d quad ) { foreach (var l in poly.EdgeLines) { if (quad.Intersects(l)) return true; } if (quad.Contains(poly[0])) return true; if (poly.Contains(quad.P0)) return true; return false; } #endregion #region Polygon2d intersects Polygon2d /// /// returns true if the Polygon2ds intersect or one contains the other /// public static bool Intersects( this Polygon2d poly0, Polygon2d poly1 ) { //check if projected ranges intersect for all possible normals V2d[] allnormals = new V2d[poly0.PointCount + poly1.PointCount]; int c = 0; foreach (var d in poly0.Edges) { allnormals[c] = new V2d(-d.Y, d.X); c++; } foreach (var d in poly1.Edges) { allnormals[c] = new V2d(-d.Y, d.X); c++; } foreach (var n in allnormals) { var r0 = poly0.ProjectTo(n); var r1 = poly1.ProjectTo(n); if (!r0.Intersects(r1)) return false; } return true; } private static Range1d ProjectTo(this Polygon2d poly, V2d dir) { double min = double.MaxValue; double max = double.MinValue; foreach (var p in poly.Points) { double dotproduct = p.Dot(dir); if (dotproduct < min) min = dotproduct; if (dotproduct > max) max = dotproduct; } return new Range1d(min, max); } #endregion #region Line3d intersects Line3d (haaser) /// /// Returns true if the minimal distance between the given lines is smaller than Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Line3d l0, Line3d l1 ) { return l0.Intersects(l1, Constant.PositiveTinyValue); } /// /// Returns true if the minimal distance between the given lines is smaller than absoluteEpsilon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Line3d l0, Line3d l1, double absoluteEpsilon ) { if (l0.GetMinimalDistanceTo(l1) < absoluteEpsilon) return true; else return false; } /// /// Returns true if the minimal distance between the given lines is smaller than absoluteEpsilon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Line3d l0, Line3d l1, double absoluteEpsilon, out V3d point ) { if (l0.GetMinimalDistanceTo(l1, out point) < absoluteEpsilon) return true; else return false; } #endregion #region Line3d intersects Special (inconsistent argument order) #region Line3d intersects Plane3d /// /// Returns true if the line and the plane intersect. /// public static bool Intersects( this Line3d line, Plane3d plane, out double t ) { if (!line.Ray3d.Intersects(plane, out t)) return false; if (t >= 0 && t <= 1) return true; t = double.PositiveInfinity; return false; } /// /// Returns true if the line and the plane intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Line3d line, Plane3d plane, out double t, out V3d p ) { bool result = line.Intersects(plane, out t); p = line.Origin + t * line.Direction; return result; } #endregion #region Line3d intersects Triangle3d /// /// Returns true if the line and the triangle intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Line3d line, Triangle3d triangle ) { return line.Ray3d.IntersectsTriangle(triangle.P0, triangle.P1, triangle.P2, 0, 1, out _); } /// /// Returns true if the line and the triangle intersect. /// point holds the intersection point. /// public static bool Intersects( this Line3d line, Triangle3d triangle, out V3d point ) { Ray3d ray = line.Ray3d; if (ray.IntersectsTriangle(triangle.P0, triangle.P1, triangle.P2, 0, 1, out double temp)) { point = ray.GetPointOnRay(temp); return true; } else { point = V3d.NaN; return false; } } #endregion #endregion #region Ray3d intersects Line3d (haaser) /// /// Returns true if the minimal distance between the line and the ray is smaller than Constant<double>.PositiveTinyValue /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3d ray, Line3d line ) { return ray.Intersects(line, Constant.PositiveTinyValue); } /// /// Returns true if the minimal distance between the line and the ray is smaller than absoluteEpsilon /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3d ray, Line3d line, double absoluteEpsilon ) { if (ray.GetMinimalDistanceTo(line) < absoluteEpsilon) return true; else return false; } /// /// Returns true if the minimal distance between the line and the ray is smaller than absoluteEpsilon /// t holds the corresponding ray parameter /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3d ray, Line3d line, double absoluteEpsilon, out double t ) { if (ray.GetMinimalDistanceTo(line, out t) < absoluteEpsilon) return true; else return false; } #endregion #region Ray3d intersects Ray3d (haaser) /// /// returns true if the minimal distance between the rays is smaller than Constant<double>.PositiveTinyValue /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3d r0, Ray3d r1 ) { return r0.Intersects(r1, out _, out _, Constant.PositiveTinyValue); } /// /// returns true if the minimal distance between the rays is smaller than Constant<double>.PositiveTinyValue /// t0 and t1 hold the ray-parameters for the intersection /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3d r0, Ray3d r1, out double t0, out double t1 ) { return r0.Intersects(r1, out t0, out t1, Constant.PositiveTinyValue); } /// /// returns true if the minimal distance between the rays is smaller than absoluteEpsilon /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3d r0, Ray3d r1, double absoluteEpsilon ) { return r0.Intersects(r1, out _, out _, absoluteEpsilon); } /// /// returns true if the minimal distance between the rays is smaller than absoluteEpsilon /// t0 and t1 hold the ray-parameters for the intersection /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3d r0, Ray3d r1, out double t0, out double t1, double absoluteEpsilon ) { if (r0.GetMinimalDistanceTo(r1, out t0, out t1) < absoluteEpsilon) return true; else return false; } #endregion #region Ray3d intersects Special (inconsistent argument order) #region Ray3d intersects Triangle3d /// /// Returns true if the ray and the triangle intersect. If you need /// information about the hit point see the Ray3d.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Ray3d ray, Triangle3d triangle) => ray.IntersectsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, double.MinValue, double.MaxValue); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3d.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Ray3d ray, Triangle3d triangle, double tmin, double tmax) => ray.IntersectsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, tmin, tmax); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3d.Hits method. /// t holds the corresponding ray-parameter /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Ray3d ray, Triangle3d triangle, double tmin, double tmax, out double t) => ray.IntersectsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, tmin, tmax, out t); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3d.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsTriangle(this Ray3d ray, V3d p0, V3d p1, V3d p2, double tmin, double tmax) => ray.IntersectsTriangle(p0, p1, p2, tmin, tmax, out double _); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3d.Hits method. /// t holds the corresponding ray-parameter /// public static bool IntersectsTriangle(this Ray3d ray, V3d p0, V3d p1, V3d p2, double tmin, double tmax, out double t) { var edge01 = p1 - p0; var edge02 = p2 - p0; var plane = Vec.Cross(ray.Direction, edge02); var det = Vec.Dot(edge01, plane); if (det > -1E-7 && det < 1E-7) { t = double.NaN; return false; } //ray ~= parallel / Triangle var tv = ray.Origin - p0; det = 1 / det; // det is now inverse det var u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) { t = double.NaN; return false; } plane = Vec.Cross(tv, edge01); // plane is now qv var v = Vec.Dot(ray.Direction, plane) * det; if (v < 0 || u + v > 1) { t = double.NaN; return false; } var temp_t = Vec.Dot(edge02, plane) * det; if (temp_t < tmin || temp_t >= tmax) { t = double.NaN; return false; } t = temp_t; return true; } /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3d.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsTrianglePointAndEdges(this Ray3d ray, V3d p0, V3d edge01, V3d edge02, double tmin, double tmax) => ray.IntersectsTrianglePointAndEdges(p0, edge01, edge02, tmin, tmax, out _); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3d.Hits method. /// t holds the corresponding ray-parameter /// public static bool IntersectsTrianglePointAndEdges(this Ray3d ray, V3d p0, V3d edge01, V3d edge02, double tmin, double tmax, out double t) { var plane = Vec.Cross(ray.Direction, edge02); var det = Vec.Dot(edge01, plane); if (det > -1E-7 && det < 1E-7) { t = double.NaN; return false; } //ray ~= parallel / Triangle var tv = ray.Origin - p0; det = 1 / det; // det is now inverse det var u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) { t = double.NaN; return false; } plane = Vec.Cross(tv, edge01); // plane is now qv var v = Vec.Dot(ray.Direction, plane) * det; if (v < 0 || u + v > 1) { t = double.NaN; return false; } var temp_t = Vec.Dot(edge02, plane) * det; if (temp_t < tmin || temp_t >= tmax) { t = double.NaN; return false; } t = temp_t; return true; } #endregion #region Ray3d intersects Quad3d /// /// Returns true if the ray and the triangle intersect. If you need /// information about the hit point see the Ray3d.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Ray3d ray, Quad3d quad) => ray.Intersects(quad, double.MinValue, double.MaxValue); /// /// Returns true if the ray and the quad intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3d.Hits method. /// public static bool Intersects(this Ray3d ray, Quad3d quad, double tmin, double tmax) { var edge02 = quad.P2 - quad.P0; return ray.IntersectsTrianglePointAndEdges(quad.P0, quad.Edge01, edge02, tmin, tmax) || ray.IntersectsTrianglePointAndEdges(quad.P0, edge02, quad.Edge03, tmin, tmax); } /// /// Returns true if the ray and the quad intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3d.Hits method. /// public static bool IntersectsQuad(this Ray3d ray, V3d p0, V3d p1, V3d p2, V3d p3, double tmin, double tmax) { var edge02 = p2 - p0; return ray.IntersectsTrianglePointAndEdges(p0, p1 - p0, edge02, tmin, tmax) || ray.IntersectsTrianglePointAndEdges(p0, edge02, p3 - p0, tmin, tmax); } #endregion #region Ray3d intersects Polygon3d (haaser) /// /// Returns true if the ray and the polygon intersect within the /// supplied parameter interval of the ray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Ray3d ray, Polygon3d poly, double tmin, double tmax) => ray.Intersects(poly, tmin, tmax, out _); /// /// Returns true if the ray and the polygon intersect within the /// supplied parameter interval of the ray. /// t holds the correspoinding paramter. /// public static bool Intersects(this Ray3d ray, Polygon3d poly, double tmin, double tmax, out double t) { var tris = poly.ComputeTriangulationOfConcavePolygon(1E-5); var count = tris.Length; for (var i = 0; i < count; i += 3) { if (ray.IntersectsTriangle(poly[tris[i + 0]], poly[tris[i + 1]], poly[tris[i + 2]], tmin, tmax, out t)) { return true; } } t = double.NaN; return false; } /// /// Returns true if the ray and the polygon, which is given by vertices, intersect within the /// supplied parameter interval of the ray. /// (The Method triangulates the polygon) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsPolygon(this Ray3d ray, V3d[] vertices, double tmin, double tmax) => ray.Intersects(new Polygon3d(vertices), tmin, tmax); /// /// Returns true if the ray and the polygon, which is given by vertices and triangulation, intersect within the /// supplied parameter interval of the ray. /// public static bool IntersectsPolygon( this Ray3d ray, V3d[] vertices, int[] triangulation, double tmin, double tmax ) { for (var i = 0; i < triangulation.Length; i += 3) { if (ray.IntersectsTriangle(vertices[triangulation[i + 0]], vertices[triangulation[i + 1]], vertices[triangulation[i + 2]], tmin, tmax)) return true; } return false; } /// /// Returns true if the ray and the polygon, which is given by vertices and triangulation, intersect within the /// supplied parameter interval of the ray. /// public static bool Intersects( this Ray3d ray, Polygon3d polygon, int[] triangulation, double tmin, double tmax ) { for (var i = 0; i < triangulation.Length; i += 3) { if (ray.IntersectsTriangle(polygon[triangulation[i + 0]], polygon[triangulation[i + 1]], polygon[triangulation[i + 2]], tmin, tmax)) return true; } return false; } #endregion #region Ray3d intersects Sphere3d /// /// Returns true if the ray and the triangle intersect. If you need /// information about the hit point see the Ray3d.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Ray3d ray, Sphere3d sphere) => ray.Intersects(sphere, double.MinValue, double.MaxValue); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the Ray3d.Hits method. /// public static bool Intersects(this Ray3d ray, Sphere3d sphere, double tmin, double tmax) { // calculate closest point var t = ray.Direction.Dot(sphere.Center - ray.Origin) / ray.Direction.LengthSquared; if (t < 0) t = 0; if (t < tmin) t = tmin; if (t > tmax) t = tmax; V3d p = ray.Origin + t * ray.Direction; // distance to sphere? var d = (p - sphere.Center).LengthSquared; if (d <= sphere.RadiusSquared) return true; return false; } #endregion #region Sphere3d intersects Triangle3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Sphere3d sphere, Triangle3d triangle ) { V3d v = sphere.Center.GetClosestPointOn(triangle) - sphere.Center; return sphere.RadiusSquared >= v.LengthSquared; } #endregion #endregion #region Triangle3d intersects Line3d (haaser) /// /// Returns true if the triangle and the line intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Triangle3d tri, Line3d line ) { return tri.IntersectsLine(line.P0, line.P1, out _); } /// /// Returns true if the triangle and the line intersect. /// point holds the intersection point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Triangle3d tri, Line3d line, out V3d point ) { return tri.IntersectsLine(line.P0, line.P1, out point); } /// /// returns true if the triangle and the line, given by p0 and p1, intersect. /// public static bool IntersectsLine( this Triangle3d tri, V3d p0, V3d p1 ) { V3d edge01 = tri.Edge01; V3d edge02 = tri.Edge02; V3d dir = p1 - p0; V3d plane = Vec.Cross(dir, edge02); double det = Vec.Dot(edge01, plane); if (det > -1E-7 && det < 1E-7)return false; //ray ~= parallel / Triangle V3d tv = p0 - tri.P0; det = 1 / det; // det is now inverse det double u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) { return false; } plane = Vec.Cross(tv, edge01); // plane is now qv double v = Vec.Dot(dir, plane) * det; if (v < 0 || u + v > 1) { return false; } double temp_t = Vec.Dot(edge02, plane) * det; if (temp_t < 0 || temp_t >= 1) { return false; } return true; } /// /// returns true if the triangle and the line, given by p0 and p1, intersect. /// point holds the intersection point. /// public static bool IntersectsLine( this Triangle3d tri, V3d p0, V3d p1, out V3d point ) { V3d edge01 = tri.Edge01; V3d edge02 = tri.Edge02; V3d dir = p1 - p0; V3d plane = Vec.Cross(dir, edge02); double det = Vec.Dot(edge01, plane); if (det > -1E-7 && det < 1E-7) { point = V3d.NaN; return false; } //ray ~= parallel / Triangle V3d tv = p0 - tri.P0; det = 1 / det; // det is now inverse det double u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) { point = V3d.NaN; return false; } plane = Vec.Cross(tv, edge01); // plane is now qv double v = Vec.Dot(dir, plane) * det; if (v < 0 || u + v > 1) { point = V3d.NaN; return false; } double temp_t = Vec.Dot(edge02, plane) * det; if (temp_t < 0 || temp_t >= 1) { point = V3d.NaN; return false; } point = p0 + temp_t * dir; return true; } #endregion #region Triangle3d intersects Ray3d (haaser) /// /// Returns true if the triangle and the ray intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Triangle3d tri, Ray3d ray ) { return tri.Intersects(ray, double.MinValue, double.MaxValue, out _); } /// /// Returns true if the triangle and the ray intersect /// within the given parameter interval /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Triangle3d tri, Ray3d ray, double tmin, double tmax ) { return tri.Intersects(ray, tmin, tmax, out _); } /// /// Returns true if the triangle and the ray intersect. /// t holds the intersection paramter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Triangle3d tri, Ray3d ray, out double t ) { return tri.Intersects(ray, double.MinValue, double.MaxValue, out t); } /// /// Returns true if the triangle and the ray intersect /// within the given parameter interval /// t holds the intersection paramter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Triangle3d tri, Ray3d ray, double tmin, double tmax, out double t ) { return ray.Intersects(tri, tmin, tmax, out t); } #endregion #region Triangle3d intersects Triangle3d (haaser) /// /// Returns true if the triangles intersect. /// public static bool Intersects( this Triangle3d t0, Triangle3d t1 ) { if (t0.IntersectsLine(t1.P0, t1.P1, out _)) return true; if (t0.IntersectsLine(t1.P1, t1.P2, out _)) return true; if (t0.IntersectsLine(t1.P2, t1.P0, out _)) return true; if (t1.IntersectsLine(t0.P0, t0.P1, out _)) return true; if (t1.IntersectsLine(t0.P1, t0.P2, out _)) return true; if (t1.IntersectsLine(t0.P2, t0.P0, out _)) return true; return false; } /// /// Returns true if the triangles intersect. /// line holds the cutting-line of the two triangles. /// public static bool Intersects( this Triangle3d t0, Triangle3d t1, out Line3d line ) { List points = new List(); if (t0.IntersectsLine(t1.P0, t1.P1, out V3d temp)) points.Add(temp); if (t0.IntersectsLine(t1.P1, t1.P2, out temp)) points.Add(temp); if (t0.IntersectsLine(t1.P2, t1.P0, out temp)) points.Add(temp); if (points.Count == 2) { line = new Line3d(points[0], points[1]); return true; } if (t1.IntersectsLine(t0.P0, t0.P1, out temp)) points.Add(temp); if (t1.IntersectsLine(t0.P1, t0.P2, out temp)) points.Add(temp); if (t1.IntersectsLine(t0.P2, t0.P0, out temp)) points.Add(temp); if (points.Count == 2) { line = new Line3d(points[0], points[1]); return true; } line = new Line3d(V3d.NaN, V3d.NaN); return false; } #endregion #region Quad3d intersects Line3d (haaser) /// /// Returns true if the quad and the line, given by p0 and p1, intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Quad3d quad, Line3d line) { return quad.IntersectsLine(line.P0, line.P1, out _); } /// /// Returns true if the quad and the line, given by p0 and p1, intersect. /// point holds the intersection point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Quad3d quad, Line3d line, out V3d point) { return quad.IntersectsLine(line.P0, line.P1, out point); } /// /// Returns true if the quad and the line, given by p0 and p1, intersect. /// public static bool IntersectsLine( this Quad3d quad, V3d p0, V3d p1) { Ray3d ray = new Ray3d(p0, p1 - p0); if (quad.Intersects(ray, 0, 1, out _)) { return true; } else { return false; } } /// /// Returns true if the quad and the line, given by p0 and p1, intersect. /// point holds the intersection point. /// public static bool IntersectsLine( this Quad3d quad, V3d p0, V3d p1, out V3d point) { Ray3d ray = new Ray3d(p0, p1 - p0); if (quad.Intersects(ray, 0, 1, out double t)) { point = ray.GetPointOnRay(t); return true; } else { point = V3d.NaN; return false; } } #endregion #region Quad3d intersects Ray3d (haaser) /// /// Returns true if the quad and the ray intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Quad3d quad, Ray3d ray ) { return quad.Intersects(ray, double.MinValue, double.MaxValue, out _); } /// /// Returns true if the quad and the ray intersect. /// t holds the intersection parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Quad3d quad, Ray3d ray, out double t ) { return quad.Intersects(ray, double.MinValue, double.MaxValue, out t); } /// /// Returns true if the quad and the ray intersect /// within the given paramter range /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Quad3d quad, Ray3d ray, double tmin, double tmax ) { return quad.Intersects(ray, tmin, tmax, out _); } /// /// Returns true if the quad and the ray intersect /// within the given paramter range /// t holds the intersection parameter. /// public static bool Intersects( this Quad3d quad, Ray3d ray, double tmin, double tmax, out double t ) { V3d edge02 = quad.P2 - quad.P0; if (ray.IntersectsTrianglePointAndEdges(quad.P0, quad.Edge01, edge02, tmin, tmax, out t)) return true; if (ray.IntersectsTrianglePointAndEdges(quad.P0, edge02, quad.Edge03, tmin, tmax, out t)) return true; t = double.NaN; return false; } #endregion #region Quad3d intersects Triangle3d (haaser) /// /// Returns true if the quad and the triangle intersect. /// public static bool Intersects( this Quad3d quad, Triangle3d tri ) { if (quad.IntersectsLine(tri.P0, tri.P1)) return true; if (quad.IntersectsLine(tri.P1, tri.P2)) return true; if (quad.IntersectsLine(tri.P2, tri.P0)) return true; if (tri.IntersectsLine(quad.P0, quad.P1)) return true; if (tri.IntersectsLine(quad.P1, quad.P2)) return true; if (tri.IntersectsLine(quad.P2, quad.P3)) return true; if (tri.IntersectsLine(quad.P3, quad.P0)) return true; return false; } /// /// Returns true if the quad and the triangle, given by p0/p1/p1, intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsTriangle( this Quad3d quad, V3d p0, V3d p1, V3d p2 ) { Triangle3d tri = new Triangle3d(p0, p1, p2); return quad.Intersects(tri); } #endregion #region Quad3d intersects Quad3d (haaser) /// /// Returns true if the given quads intersect. /// public static bool Intersects( this Quad3d q0, Quad3d q1 ) { if (q0.IntersectsTriangle(q1.P0, q1.P1, q1.P2)) return true; if (q0.IntersectsTriangle(q1.P2, q1.P3, q1.P0)) return true; if (q1.IntersectsTriangle(q0.P0, q0.P1, q0.P2)) return true; if (q1.IntersectsTriangle(q0.P2, q0.P3, q0.P0)) return true; return false; } #endregion #region Plane3d intersects Line3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane3d plane, Line3d line) { return plane.IntersectsLine(line.P0, line.P1, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane3d plane, Line3d line, double absoluteEpsilon) { return plane.IntersectsLine(line.P0, line.P1, absoluteEpsilon); } public static bool IntersectsLine(this Plane3d plane, V3d p0, V3d p1, double absoluteEpsilon) { double h0 = plane.Height(p0); int s0 = (h0 > absoluteEpsilon ? 1 :(h0 < -absoluteEpsilon ? -1 : 0)); if (s0 == 0) return true; double h1 = plane.Height(p1); int s1 = (h1 > absoluteEpsilon ? 1 : (h1 < -absoluteEpsilon ? -1 : 0)); if (s1 == 0) return true; if (s0 == s1) return false; else return true; } public static bool IntersectsLine(this Plane3d plane, V3d p0, V3d p1, double absoluteEpsilon, out V3d point) { // == d // + t0* == d //t0 == (d - ) / ; V3d dir = p1 - p0; double ld = dir.Length; dir /= ld; double nDotd = plane.Normal.Dot(dir); if (!Fun.IsTiny(nDotd)) { double t0 = (plane.Distance - plane.Normal.Dot(p0)) / nDotd; if (t0 >= -absoluteEpsilon && t0 <= ld + absoluteEpsilon) { point = p0 + dir * t0; return true; } else { point = V3d.NaN; return false; } } else { point = V3d.NaN; return false; } } #endregion #region Plane3d intersects Ray3d /// /// Returns true if the Ray3d and the Plane3d intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Ray3d ray, Plane3d plane) => !plane.Normal.IsOrthogonalTo(ray.Direction); /// /// Returns true if the ray and the plane intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3d ray, Plane3d plane, out double t ) { double dot = Vec.Dot(ray.Direction, plane.Normal); if (Fun.IsTiny(dot)) { t = double.PositiveInfinity; return false; } t = -plane.Height(ray.Origin) / dot; return true; } /// /// Returns the intersection point with the given plane, or V3d.PositiveInfinity if ray is parallel to plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Intersect( this Ray3d ray, Plane3d plane ) { double dot = Vec.Dot(ray.Direction, plane.Normal); if (Fun.IsTiny(dot)) return V3d.PositiveInfinity; return ray.GetPointOnRay(-plane.Height(ray.Origin) / dot); } /// /// Returns true if the ray and the plane intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Ray3d ray, Plane3d plane, out double t, out V3d p ) { bool result = Intersects(ray, plane, out t); p = ray.Origin + t * ray.Direction; return result; } #endregion #region Plane3d intersects Plane3d public static bool Intersects(this Plane3d p0, Plane3d p1) { bool parallel = p0.Normal.IsParallelTo(p1.Normal); if (parallel) return Fun.IsTiny(p0.Distance - p1.Distance); else return true; } public static bool Intersects(this Plane3d p0, Plane3d p1, out Ray3d ray) { V3d dir = p0.Normal.Cross(p1.Normal); double len = dir.Length; if (Fun.IsTiny(len)) { if (Fun.IsTiny(p0.Distance - p1.Distance)) { ray = new Ray3d(p0.Normal * p0.Distance, V3d.Zero); return true; } else { ray = Ray3d.Invalid; return false; } } dir *= 1 / len; var alu = new double[,] { { p0.Normal.X, p0.Normal.Y, p0.Normal.Z }, { p1.Normal.X, p1.Normal.Y, p1.Normal.Z }, { dir.X, dir.Y, dir.Z } }; int[] p = alu.LuFactorize(); var b = new double[] { p0.Distance, p1.Distance, 0 }; var x = alu.LuSolve(p, b); ray = new Ray3d(new V3d(x), dir); return true; } #endregion #region Plane3d intersects Plane3d intersects Plane3d public static bool Intersects(this Plane3d p0, Plane3d p1, Plane3d p2, out V3d point) { var alu = new double[,] { { p0.Normal.X, p0.Normal.Y, p0.Normal.Z }, { p1.Normal.X, p1.Normal.Y, p1.Normal.Z }, { p2.Normal.X, p2.Normal.Y, p2.Normal.Z } }; var p = new int[3]; if (!alu.LuFactorize(p)) { point = V3d.NaN; return false; } var b = new double[] { p0.Distance, p1.Distance, p2.Distance }; var x = alu.LuSolve(p, b); point = new V3d(x); return true; } #endregion #region Plane3d intersects Triangle3d /// /// Returns whether the given plane and triangle intersect. /// public static bool Intersects( this Plane3d plane, Triangle3d triangle ) { int sign = plane.Sign(triangle.P0); if (sign == 0) return true; if (sign != plane.Sign(triangle.P1)) return true; if (sign != plane.Sign(triangle.P2)) return true; return false; } #endregion #region Plane3d intersects Sphere3d /// /// Returns whether the given sphere and plane intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Plane3d plane, Sphere3d sphere ) { return sphere.Radius >= plane.Height(sphere.Center).Abs(); } #endregion #region Plane3d intersects Polygon3d /// /// returns true if the Plane3d and the Polygon3d intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Plane3d plane, Polygon3d poly ) { return plane.Intersects(poly, Constant.PositiveTinyValue); } /// /// returns true if the Plane3d and the polygon, intersect /// within a tolerance of absoluteEpsilon /// public static bool Intersects( this Plane3d plane, Polygon3d polygon, double absoluteEpsilon ) { double height = plane.Height(polygon[0]); int sign0 = height > -absoluteEpsilon ? (height < absoluteEpsilon ? 0 : 1) : -1; if (sign0 == 0) return true; int pc = polygon.PointCount; for (int i = 1; i < pc; i++) { height = plane.Height(polygon[i]); int sign = height > -absoluteEpsilon ? (height < absoluteEpsilon ? 0 : 1) : -1; if (sign != sign0) return true; } return false; } /// /// returns true if the Plane3d and the Polygon3d intersect. /// line holds the intersection line /// ATTENTION: works only with non-concave polygons! /// public static bool IntersectsConvex( this Plane3d plane, Polygon3d poly, out Line3d line ) { return plane.IntersectsConvex(poly, Constant.PositiveTinyValue, out line); } /// /// Returns true if the Plane3d and the polygon, given by points, intersect /// within a tolerance of absoluteEpsilon. /// Line holds the intersection line. /// ATTENTION: works only with non-concave polygons! /// public static bool IntersectsConvex( this Plane3d plane, Polygon3d polygon, double absoluteEpsilon, out Line3d line ) { int count = polygon.PointCount; int[] signs = new int[count]; int pc = 0, nc = 0, zc = 0; for (int pi = 0; pi < count; pi++) { double h = plane.Height(polygon[pi]); if (h < -absoluteEpsilon) { nc++; signs[pi] = -1; continue; } if (h > absoluteEpsilon) { pc++; signs[pi] = 1; continue; } zc++; signs[pi] = 0; } if (zc == count) { line = new Line3d(polygon[0], polygon[0]); return false; } else if (pc == 0 && zc == 0) { line = new Line3d(V3d.NaN, V3d.NaN); return false; } else if (nc == 0 && zc == 0) { line = new Line3d(V3d.NaN, V3d.NaN); return false; } else { int pointcount = 0; V3d[] linePoints = new V3d[2]; for (int i = 0; i < count; i++) { int u = (i + 1) % count; if (signs[i] != signs[u] || signs[i] == 0 || signs[u] == 0) { if (plane.IntersectsLine(polygon[i], polygon[u], absoluteEpsilon, out V3d point)) { linePoints[pointcount++] = point; //If Endpoint is on Plane => Next startpoint is on plane => same intersection point // => skip all following lines which start within absoluteEpsilon (whic have a zero sign) while (signs[(i + 1) % count] == 0) i++; } } if (pointcount == 2) { // line = new Line3d(linePoints[0], linePoints[1]); return true; } } line = new Line3d(V3d.NaN, V3d.NaN); return false; } } #endregion #region Plane3d intersects Cylinder3d /// /// Returns whether the given sphere and cylinder intersect. /// public static bool Intersects(this Plane3d plane, Cylinder3d cylinder) { if (plane.IsParallelToAxis(cylinder)) { var distance = cylinder.P0.GetMinimalDistanceTo(plane); return distance < cylinder.Radius; } return true; } /// /// Tests if the given plane is parallel to the cylinder axis (i.e. the plane's normal is orthogonal to the axis). /// The plane will intersect the cylinder in two rays or in one tangent line. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelToAxis(this Plane3d plane, Cylinder3d cylinder) => plane.Normal.IsOrthogonalTo(cylinder.Axis.Direction.Normalized); /// /// Tests if the given plane is orthogonal to the cylinder axis (i.e. the plane's normal is parallel to the axis). /// The plane will intersect the cylinder in a circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalToAxis(this Plane3d plane, Cylinder3d cylinder) => plane.Normal.IsParallelTo(cylinder.Axis.Direction.Normalized); /// /// Returns true if the given plane and cylinder intersect in an ellipse. /// This is only true if the plane is neither orthogonal nor parallel to the cylinder axis. Otherwise the intersection methods returning a circle or rays have to be used. /// /// /// The cylinder is assumed to have infinite extent along its axis. /// public static bool Intersects(this Plane3d plane, Cylinder3d cylinder, out Ellipse3d ellipse) { if (plane.IsParallelToAxis(cylinder) || plane.IsOrthogonalToAxis(cylinder)) { ellipse = Ellipse3d.Zero; return false; } var dir = cylinder.Axis.Direction.Normalized; cylinder.Axis.Ray3d.Intersects(plane, out _, out V3d center); var cosTheta = dir.Dot(plane.Normal); var eNormal = plane.Normal; var eCenter = center; var eMajor = (dir - cosTheta * eNormal).Normalized; var eMinor = (eNormal.Cross(eMajor)).Normalized; eMajor = eNormal.Cross(eMinor).Normalized; //to be sure - if ellipse is nearly a circle eMajor = eMajor * cylinder.Radius / cosTheta.Abs(); eMinor *= cylinder.Radius; ellipse = new Ellipse3d(eCenter, eNormal, eMajor, eMinor); return true; } /// /// Returns true if the given plane and cylinder intersect in a circle. /// This is only true if the plane is orthogonal to the cylinder axis. Otherwise the intersection methods returning an ellipse or rays have to be used. /// /// /// The cylinder is assumed to have infinite extent along its axis. /// public static bool Intersects(this Plane3d plane, Cylinder3d cylinder, out Circle3d circle) { if (plane.IsOrthogonalToAxis(cylinder)) { circle = cylinder.GetCircle(cylinder.GetHeight(plane.Point)); return true; } circle = Circle3d.Zero; return false; } /// /// Returns true if the given plane and cylinder intersect in one or two rays. /// This is only true if the plane is parallel to the cylinder axis. Otherwise the intersection methods returning an ellipse or a circle have to be used. /// /// /// The cylinder is assumed to have infinite extent along its axis. /// Output of intersection rays. The array contains two rays (intersection), one ray (plane is tangent to cylinder) or no ray (no intersection). public static bool Intersects(this Plane3d plane, Cylinder3d cylinder, out Ray3d[] rays) { if (plane.IsParallelToAxis(cylinder)) { var distance = cylinder.P0.GetMinimalDistanceTo(plane); var center = cylinder.P0 - distance * plane.Normal; var axis = cylinder.Axis.Direction.Normalized; if (distance == cylinder.Radius) //one tangent line { rays = new[] { new Ray3d(center, axis) }; return true; } else //two intersection lines { var offset = axis.Cross(plane.Normal); var extent = (cylinder.Radius.Square() - distance.Square()).Sqrt(); rays = new[] { new Ray3d(center - extent * offset, axis), new Ray3d(center + extent * offset, axis) }; return true; } } rays = Array.Empty(); return false; } #endregion #region Sphere3d intersects Sphere3d (sm) /// /// Returns true if the spheres intersect, or one contains the other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Sphere3d s0, Sphere3d s1) => (s0.Center - s1.Center).LengthSquared <= (s0.Radius + s1.Radius).Square(); #endregion #region Box3d intersects Line3d /// /// Returns true if the box and the line intersect. /// public static bool Intersects(this Box3d box, Line3d line) { var out0 = box.OutsideFlags(line.P0); if (out0 == 0) return true; var out1 = box.OutsideFlags(line.P1); if (out1 == 0) return true; return box.IntersectsLine(line.P0, line.P1, out0, out1); } /// /// Returns true if the box and the line intersect. /// public static bool IntersectsLine( this Box3d box, V3d p0, V3d p1) { var out0 = box.OutsideFlags(p0); if (out0 == 0) return true; var out1 = box.OutsideFlags(p1); if (out1 == 0) return true; return box.IntersectsLine(p0, p1, out0, out1); } /// /// Returns true if the box and the line intersect. The outside flags /// of the end points of the line with respect to the box have to be /// supplied, and have to be already individually tested against /// intersection with the box. /// public static bool IntersectsLine( this Box3d box, V3d p0, V3d p1, Box.Flags out0, Box.Flags out1) { if ((out0 & out1) != 0) return false; V3d min = box.Min; V3d max = box.Max; var bf = out0 | out1; if ((bf & Box.Flags.X) != 0) { double dx = p1.X - p0.X; if ((bf & Box.Flags.MinX) != 0) { if (dx == 0 && p0.X < min.X) return false; double t = (min.X - p0.X) / dx; V3d p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MinX) == 0) return true; } if ((bf & Box.Flags.MaxX) != 0) { if (dx == 0 && p0.X > max.X) return false; double t = (max.X - p0.X) / dx; V3d p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MaxX) == 0) return true; } } if ((bf & Box.Flags.Y) != 0) { double dy = p1.Y - p0.Y; if ((bf & Box.Flags.MinY) != 0) { if (dy == 0 && p0.Y < min.Y) return false; double t = (min.Y - p0.Y) / dy; V3d p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MinY) == 0) return true; } if ((bf & Box.Flags.MaxY) != 0) { if (dy == 0 && p0.Y > max.Y) return false; double t = (max.Y - p0.Y) / dy; V3d p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MaxY) == 0) return true; } } if ((bf & Box.Flags.Z) != 0) { double dz = p1.Z - p0.Z; if ((bf & Box.Flags.MinZ) != 0) { if (dz == 0 && p0.Z < min.Z) return false; double t = (min.Z - p0.Z) / dz; V3d p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MinZ) == 0) return true; } if ((bf & Box.Flags.MaxZ) != 0) { if (dz == 0 && p0.Z > max.Z) return false; double t = (max.Z - p0.Z) / dz; V3d p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MaxZ) == 0) return true; } } return false; } #endregion #region Box3d intersects Ray3d (haaser) public static bool Intersects(this Box3d box, Ray3d ray, out double t) { Box.Flags out0 = box.OutsideFlags(ray.Origin); if (out0 == 0) { t = 0; return true; } Box3d largeBox = box.EnlargedByRelativeEps(1E-5); double tmin = double.PositiveInfinity; double ttemp; if ((out0 & Box.Flags.X) != 0) { if (!Fun.IsTiny(ray.Direction.X)) { if ((out0 & Box.Flags.MinX) != 0) { ttemp = (box.Min.X - ray.Origin.X) / ray.Direction.X; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } else if ((out0 & Box.Flags.MaxX) != 0) { ttemp = (box.Max.X - ray.Origin.X) / ray.Direction.X; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } } } if ((out0 & Box.Flags.Y) != 0) { if (!Fun.IsTiny(ray.Direction.Y)) { if ((out0 & Box.Flags.MinY) != 0) { ttemp = (box.Min.Y - ray.Origin.Y) / ray.Direction.Y; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } else if ((out0 & Box.Flags.MaxY) != 0) { ttemp = (box.Max.Y - ray.Origin.Y) / ray.Direction.Y; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } } } if ((out0 & Box.Flags.Z) != 0) { if (!Fun.IsTiny(ray.Direction.Z)) { if ((out0 & Box.Flags.MinZ) != 0) { ttemp = (box.Min.Z - ray.Origin.Z) / ray.Direction.Z; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } else if ((out0 & Box.Flags.MaxZ) != 0) { ttemp = (box.Max.Z - ray.Origin.Z) / ray.Direction.Z; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } } } if (tmin < double.PositiveInfinity) { t = tmin; return true; } t = double.NaN; return false; } #endregion #region Box3d intersects Plane3d /// /// Returns true if the box and the plane intersect or touch with a /// supplied epsilon tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Box3d box, Plane3d plane, double eps) { var signs = box.GetIntersectionSignsWithPlane(plane, eps); return signs != Signs.Negative && signs != Signs.Positive; } /// /// Classify the position of all the eight vertices of a box with /// respect to a supplied plane. /// public static Signs GetIntersectionSignsWithPlane( this Box3d box, Plane3d plane, double eps) { var normal = plane.Normal; var distance = plane.Distance; double npMinX = normal.X * box.Min.X; double npMaxX = normal.X * box.Max.X; double npMinY = normal.Y * box.Min.Y; double npMaxY = normal.Y * box.Max.Y; double npMinZ = normal.Z * box.Min.Z; double npMaxZ = normal.Z * box.Max.Z; double hMinZ = npMinZ - distance; double hMaxZ = npMaxZ - distance; double hMinYMinZ = npMinY + hMinZ; double hMaxYMinZ = npMaxY + hMinZ; double hMinYMaxZ = npMinY + hMaxZ; double hMaxYMaxZ = npMaxY + hMaxZ; return (npMinX + hMinYMinZ).GetSigns(eps) | (npMaxX + hMinYMinZ).GetSigns(eps) | (npMinX + hMaxYMinZ).GetSigns(eps) | (npMaxX + hMaxYMinZ).GetSigns(eps) | (npMinX + hMinYMaxZ).GetSigns(eps) | (npMaxX + hMinYMaxZ).GetSigns(eps) | (npMinX + hMaxYMaxZ).GetSigns(eps) | (npMaxX + hMaxYMaxZ).GetSigns(eps); } /// /// Returns true if the box intersects the supplied plane. The /// bounding boxes of the resulting parts are returned in the out /// parameters. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Signs GetIntersectionSigns( this Box3d box, Plane3d plane, double eps, out Box3d negBox, out Box3d zeroBox, out Box3d posBox) { return box.GetIntersectionSigns(plane.Normal, plane.Distance, eps, out negBox, out zeroBox, out posBox); } /// /// Returns true if the box intersects the supplied plane. The /// bounding boxes of the resulting parts are returned in the out /// parameters. /// public static Signs GetIntersectionSigns( this Box3d box, V3d normal, double distance, double eps, out Box3d negBox, out Box3d zeroBox, out Box3d posBox) { double npMinX = normal.X * box.Min.X; double npMaxX = normal.X * box.Max.X; double npMinY = normal.Y * box.Min.Y; double npMaxY = normal.Y * box.Max.Y; double npMinZ = normal.Z * box.Min.Z; double npMaxZ = normal.Z * box.Max.Z; var ha = new double[8]; double hMinZ = npMinZ - distance; double hMaxZ = npMaxZ - distance; double hMinYMinZ = npMinY + hMinZ; ha[0] = npMinX + hMinYMinZ; ha[1] = npMaxX + hMinYMinZ; double hMaxYMinZ = npMaxY + hMinZ; ha[2] = npMinX + hMaxYMinZ; ha[3] = npMaxX + hMaxYMinZ; double hMinYMaxZ = npMinY + hMaxZ; ha[4] = npMinX + hMinYMaxZ; ha[5] = npMaxX + hMinYMaxZ; double hMaxYMaxZ = npMaxY + hMaxZ; ha[6] = npMinX + hMaxYMaxZ; ha[7] = npMaxX + hMaxYMaxZ; Signs all = Signs.None; var sa = new Signs[8]; for (int i = 0; i < 8; i++) { sa[i] = ha[i].GetSigns(eps); all |= sa[i]; } negBox = Box3d.Invalid; zeroBox = Box3d.Invalid; posBox = Box3d.Invalid; if (all == Signs.Zero) { zeroBox = box; return all; } if (all == Signs.Positive) { posBox = box; return all; } if (all == Signs.Negative) { negBox = box; return all; } var pa = box.ComputeCorners(); for (int i = 0; i < 8; i++) { if (sa[i] == Signs.Negative) negBox.ExtendBy(pa[i]); else if (sa[i] == Signs.Positive) posBox.ExtendBy(pa[i]); else { negBox.ExtendBy(pa[i]); zeroBox.ExtendBy(pa[i]); posBox.ExtendBy(pa[i]); } } if (all == Signs.NonPositive) { posBox = Box3d.Invalid; return all; } if (all == Signs.NonNegative) { negBox = Box3d.Invalid; return all; } for (int ei = 0; ei < 12; ei++) { int i0 = c_cubeEdgeVertex0[ei], i1 = c_cubeEdgeVertex1[ei]; if ((sa[i0] == Signs.Negative && sa[i1] == Signs.Positive) || (sa[i0] == Signs.Positive && sa[i1] == Signs.Negative)) { double h0 = ha[i0]; double t = h0 / (h0 - ha[i1]); V3d p0 = pa[i0]; V3d sp = p0 + t * (pa[i1] - p0); negBox.ExtendBy(sp); zeroBox.ExtendBy(sp); posBox.ExtendBy(sp); } } return all; } #endregion #region Box3d intersects Sphere3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Box3d box, Sphere3d sphere ) { V3d v = sphere.Center.GetClosestPointOn(box) - sphere.Center; return sphere.RadiusSquared >= v.LengthSquared; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Box3d box, Cylinder3d cylinder ) { return box.Intersects(cylinder.BoundingBox3d); //throw new NotImplementedException(); } #endregion #region Box3d intersects Triangle3d /// /// Returns true if the box and the triangle intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Box3d box, Triangle3d triangle ) { return box.IntersectsTriangle(triangle.P0, triangle.P1, triangle.P2); } /// /// Returns true if the box and the triangle intersect. /// public static bool IntersectsTriangle( this Box3d box, V3d p0, V3d p1, V3d p2 ) { /* --------------------------------------------------------------- If one of the points of the triangle is inside the box, it intersects, of course. --------------------------------------------------------------- */ var out0 = box.OutsideFlags(p0); if (out0 == 0) return true; var out1 = box.OutsideFlags(p1); if (out1 == 0) return true; var out2 = box.OutsideFlags(p2); if (out2 == 0) return true; return box.IntersectsTriangle(p0, p1, p2, out0, out1, out2); } /// /// Returns true if the box and the triangle intersect. The outside /// flags of the triangle vertices with respect to the box have to be /// supplied, and already be individually tested for intersection with /// the box. /// public static bool IntersectsTriangle( this Box3d box, V3d p0, V3d p1, V3d p2, Box.Flags out0, Box.Flags out1, Box.Flags out2 ) { /* --------------------------------------------------------------- If all of the points of the triangle are on the same side outside the box, no intersection is possible. --------------------------------------------------------------- */ if ((out0 & out1 & out2) != 0) return false; /* --------------------------------------------------------------- If two points of the triangle are not on the same side outside the box, it is possible that the edge between them intersects the box. The outside flags we computed are also used to optimize the intersection routine with the edge. --------------------------------------------------------------- */ if (box.IntersectsLine(p0, p1, out0, out1)) return true; if (box.IntersectsLine(p1, p2, out1, out2)) return true; if (box.IntersectsLine(p2, p0, out2, out0)) return true; /* --------------------------------------------------------------- The only case left: the edges of the triangle go outside around the box. Intersect the four space diagonals of the box with the triangle to test for intersection. --------------------------------------------------------------- */ Ray3d ray = new Ray3d(box.Min, box.Size); if (ray.IntersectsTriangle(p0, p1, p2, 0, 1)) return true; ray.Origin.X = box.Max.X; ray.Direction.X = -ray.Direction.X; if (ray.IntersectsTriangle(p0, p1, p2, 0, 1)) return true; ray.Direction.X = -ray.Direction.X; ray.Origin.X = box.Min.X; ray.Origin.Y = box.Max.Y; ray.Direction.Y = -ray.Direction.Y; if (ray.IntersectsTriangle(p0, p1, p2, 0, 1)) return true; ray.Direction.Y = -ray.Direction.Y; ray.Origin.Y = box.Min.Y; ray.Origin.Z = box.Max.Z; ray.Direction.Z = -ray.Direction.Z; if (ray.IntersectsTriangle(p0, p1, p2, 0, 1)) return true; return false; } #endregion #region Box3d intersects Quad3d (haaser) public static bool Intersects( this Box3d box, Quad3d quad ) { Box.Flags out0 = box.OutsideFlags(quad.P0); if (out0 == 0) return true; Box.Flags out1 = box.OutsideFlags(quad.P1); if (out1 == 0) return true; Box.Flags out2 = box.OutsideFlags(quad.P2); if (out2 == 0) return true; Box.Flags out3 = box.OutsideFlags(quad.P3); if (out3 == 0) return true; return box.IntersectsQuad(quad.P0, quad.P1, quad.P2, quad.P3, out0, out1, out2, out3); } public static bool IntersectsQuad( this Box3d box, V3d p0, V3d p1, V3d p2, V3d p3 ) { var out0 = box.OutsideFlags(p0); if (out0 == 0) return true; var out1 = box.OutsideFlags(p1); if (out1 == 0) return true; var out2 = box.OutsideFlags(p2); if (out2 == 0) return true; var out3 = box.OutsideFlags(p3); if (out3 == 0) return true; return box.IntersectsQuad(p0, p1, p2, p3, out0, out1, out2, out3); } public static bool IntersectsQuad( this Box3d box, V3d p0, V3d p1, V3d p2, V3d p3, Box.Flags out0, Box.Flags out1, Box.Flags out2, Box.Flags out3 ) { /* --------------------------------------------------------------- If all of the points of the quad are on the same side outside the box, no intersection is possible. --------------------------------------------------------------- */ if ((out0 & out1 & out2 & out3) != 0) return false; /* --------------------------------------------------------------- If two points of the quad are not on the same side outside the box, it is possible that the edge between them intersects the box. The outside flags we computed are also used to optimize the intersection routine with the edge. --------------------------------------------------------------- */ if (box.IntersectsLine(p0, p1, out0, out1)) return true; if (box.IntersectsLine(p1, p2, out1, out2)) return true; if (box.IntersectsLine(p2, p3, out2, out3)) return true; if (box.IntersectsLine(p3, p0, out3, out0)) return true; /* --------------------------------------------------------------- The only case left: the edges of the quad go outside around the box. Intersect the four space diagonals of the box with the triangle to test for intersection. --------------------------------------------------------------- */ Ray3d ray = new Ray3d(box.Min, box.Size); if (ray.IntersectsQuad(p0, p1, p2, p3, 0, 1)) return true; ray.Origin.X = box.Max.X; ray.Direction.X = -ray.Direction.X; if (ray.IntersectsQuad(p0, p1, p2, p3, 0, 1)) return true; ray.Direction.X = -ray.Direction.X; ray.Origin.X = box.Min.X; ray.Origin.Y = box.Max.Y; ray.Direction.Y = -ray.Direction.Y; if (ray.IntersectsQuad(p0, p1, p2, p3, 0, 1)) return true; ray.Direction.Y = -ray.Direction.Y; ray.Origin.Y = box.Min.Y; ray.Origin.Z = box.Max.Z; ray.Direction.Z = -ray.Direction.Z; if (ray.IntersectsQuad(p0, p1, p2, p3, 0, 1)) return true; return false; } #endregion #region Box3d intersects Polygon3d (haaser) public static bool Intersects(this Box3d box, Polygon3d poly) { int edges = poly.PointCount; Box.Flags[] outside = new Box.Flags[edges]; for (int i = 0; i < edges; i++) { outside[i] = box.OutsideFlags(poly[i]); if (outside[i] == 0) return true; } /* --------------------------------------------------------------- If all of the points of the polygon are on the same side outside the box, no intersection is possible. --------------------------------------------------------------- */ Box.Flags sum = outside[0]; for (int i = 1; i < edges; i++) sum &= outside[i]; if (sum != 0) return false; /* --------------------------------------------------------------- If two points of the polygon are not on the same side outside the box, it is possible that the edge between them intersects the box. The outside flags we computed are also used to optimize the intersection routine with the edge. --------------------------------------------------------------- */ int u; for (int i = 0; i < edges; i++) { u = (i + 1) % edges; if (box.IntersectsLine(poly[i], poly[u], outside[i], outside[u])) return true; } /* --------------------------------------------------------------- The only case left: the edges of the polygon go outside around the box. Intersect the four space diagonals of the box with the triangle to test for intersection. The polygon needs to be triangulated for this check --------------------------------------------------------------- */ int[] tris = poly.ComputeTriangulationOfConcavePolygon(1E-5); Ray3d ray = new Ray3d(box.Min, box.Size); if (ray.Intersects(poly, tris, 0, 1)) return true; ray.Origin.X = box.Max.X; ray.Direction.X = -ray.Direction.X; if (ray.Intersects(poly, tris, 0, 1)) return true; ray.Direction.X = -ray.Direction.X; ray.Origin.X = box.Min.X; ray.Origin.Y = box.Max.Y; ray.Direction.Y = -ray.Direction.Y; if (ray.Intersects(poly, tris, 0, 1)) return true; ray.Direction.Y = -ray.Direction.Y; ray.Origin.Y = box.Min.Y; ray.Origin.Z = box.Max.Z; ray.Direction.Z = -ray.Direction.Z; if (ray.Intersects(poly, tris, 0, 1)) return true; return false; } #endregion #region Box3d intersects Projection-Trafo (haaser) /// /// returns true if the Box3d and the frustum described by the M44d intersect or the frustum contains the Box3d /// Assumes DirectX clip-space: /// -w < x < w /// -w < y < w /// 0 < z < w /// public static bool IntersectsFrustum(this Box3d box, M44d projection) { //Let's look at the left clip-plane //which corresponds to: //-w < x // # which can easily be transformed to: //0 < x + w // # for a given vector v this means (* is a dot product here) //0 < proj.R0 * v + proj.R3 * v // # or in other words: //0 < (proj.R0 + proj.R3) * v //therefore (proj.R0 + proj.R3) is the plane describing the left clip-plane. //The other planes can be derived in a similar way (only the near plane is a little different) //see http://fgiesen.wordpress.com/2012/08/31/frustum-planes-from-the-projection-matrix/ for a full explanation var r0 = projection.R0; var r1 = projection.R1; var r2 = projection.R2; var r3 = projection.R3; V4d plane; V3d n; //left plane = r3 + r0; n = plane.XYZ; box.GetMinMaxInDirection(n, out V3d min, out V3d max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; //right plane = r3 - r0; n = plane.XYZ; box.GetMinMaxInDirection(n, out min, out max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; //top plane = r3 + r1; n = plane.XYZ; box.GetMinMaxInDirection(n, out min, out max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; //bottom plane = r3 - r1; n = plane.XYZ; box.GetMinMaxInDirection(n, out min, out max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; //near plane = r2; n = plane.XYZ; box.GetMinMaxInDirection(n, out min, out max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; //far plane = r3 - r2; n = plane.XYZ; box.GetMinMaxInDirection(n, out min, out max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; return true; } #endregion #region Hull3d intersects Line3d /// /// returns true if the Hull3d and the Line3d intersect or the Hull3d contains the Line3d /// [Hull3d-Normals must point outside] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Hull3d hull, Line3d line ) { if (hull.Contains(line.P0)) return true; if (hull.Contains(line.P1)) return true; return hull.Intersects(line.Ray3d, 0, 1, out _); } /// /// returns true if the Hull3d and the Line between p0 and p1 intersect or the Hull3d contains the Line /// [Hull3d-Normals must point outside] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine( this Hull3d hull, V3d p0, V3d p1 ) { return hull.Intersects(new Line3d(p0, p1)); } #endregion #region Hull3d intersects Ray3d /// /// returns true if the Hull3d and the Ray3d intersect /// [Hull3d-Normals must point outside] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Hull3d hull, Ray3d ray ) { return hull.Intersects(ray, double.NegativeInfinity, double.PositiveInfinity, out _); } /// /// returns true if the Hull3d and the Ray3d intersect /// the out parameter t holds the ray-parameter where an intersection was found /// [Hull3d-Normals must point outside] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this Hull3d hull, Ray3d ray, out double t ) { return hull.Intersects(ray, double.NegativeInfinity, double.PositiveInfinity, out t); } /// /// returns true if the Hull3d and the Ray3d intersect and the /// ray-parameter for the intersection is between t_min and t_max /// the out parameter t holds the ray-parameter where an intersection was found /// [Hull3d-Normals must point outside] /// public static bool Intersects( this Hull3d hull, Ray3d ray, double t_min, double t_max, out double t ) { if (!double.IsInfinity(t_min) && hull.Contains(ray.GetPointOnRay(t_min))) { t = t_min; return true; } if (!double.IsInfinity(t_max) && hull.Contains(ray.GetPointOnRay(t_max))) { t = t_max; return true; } var planes = hull.PlaneArray; for (int i = 0; i < planes.Length; i++) { if (!Fun.IsTiny(planes[i].Normal.Dot(ray.Direction)) && ray.Intersects(planes[i], out double temp_t) && temp_t >= t_min && temp_t <= t_max) { V3d candidatePoint = ray.GetPointOnRay(temp_t); bool contained = true; for (int u = 0; u < planes.Length; u++) { if (u != i && planes[u].Height(candidatePoint) > Constant.PositiveTinyValue) { contained = false; break; } } if (contained) { t = temp_t; return true; } } } t = double.NaN; return false; } #endregion #region Hull3d intersects Plane3d /// /// returns true if the Hull3d and the Plane3d intersect /// [Hull3d-Normals must point outside] /// public static bool Intersects( this Hull3d hull, Plane3d plane ) { foreach (var p in hull.PlaneArray) { if (!p.Normal.IsParallelTo(plane.Normal) && p.Intersects(plane, out Ray3d ray)) { if (hull.Intersects(ray)) return true; } } return false; } #endregion #region Hull3d intersects Box3d /// /// Returns true if the hull and the box intersect. /// public static bool Intersects( this Hull3d hull, Box3d box ) { if (box.IsInvalid) return false; bool intersecting = false; foreach (Plane3d p in hull.PlaneArray) { box.GetMinMaxInDirection(p.Normal, out V3d min, out V3d max); if (p.Height(min) > 0) return false; // outside if (p.Height(max) >= 0) intersecting = true; } if (intersecting) return true; // intersecting return true; // inside } /// Test hull against intersection of the supplied bounding box. /// Note that this is a conservative test, since in some cases /// around the edges of the hull it may return true although the /// hull does not intersect the box. public static bool Intersects( this FastHull3d fastHull, Box3d box) { var planes = fastHull.Hull.PlaneArray; int count = planes.Length; bool intersecting = false; for (int pi = 0; pi < count; pi++) { int minCornerIndex = fastHull.MinCornerIndexArray[pi]; if (planes[pi].Height(box.Corner(minCornerIndex)) > 0) return false; if (planes[pi].Height(box.Corner(minCornerIndex ^ 7)) >= 0) intersecting = true; } if (intersecting) return true; return true; } #endregion #region Hull3d intersects Sphere3d /// /// Returns true if the hull and the sphere intersect. /// public static bool Intersects( this Hull3d hull, Sphere3d sphere ) { if (sphere.IsInvalid) return false; bool intersecting = false; foreach (Plane3d p in hull.PlaneArray) { double height = p.Height(sphere.Center); if (height > sphere.Radius) return false; // outside if (height.Abs() < sphere.Radius) intersecting = true; } if (intersecting) return true; // intersecting return true; // inside } #endregion #region Plane3d intersects Box3d /// /// Returns true if the box and the plane intersect or touch with a /// supplied epsilon tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Plane3d plane, double eps, Box3d box) => box.Intersects(plane, eps); #endregion } } ================================================ FILE: src/Aardvark.Base/Geometry/IntersectionTests_template.cs ================================================ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; namespace Aardvark.Base { public static partial class GeometryFun { private static readonly int[] c_cubeEdgeVertex0 = new int[] { 0, 2, 4, 6, 0, 1, 4, 5, 0, 1, 2, 3 }; private static readonly int[] c_cubeEdgeVertex1 = new int[] { 1, 3, 5, 7, 2, 3, 6, 7, 4, 5, 6, 7 }; //# foreach (var isDouble in new[] { false, true }) { //# var rtype = isDouble ? "double" : "float"; //# var tc = isDouble ? "d" : "f"; //# var v2t = "V2" + tc; //# var v3t = "V3" + tc; //# var v4t = "V4" + tc; //# var m44t = "M44" + tc; //# var line2t = "Line2" + tc; //# var line3t = "Line3" + tc; //# var plane2t = "Plane2" + tc; //# var plane3t = "Plane3" + tc; //# var ray2t = "Ray2" + tc; //# var ray3t = "Ray3" + tc; //# var circle2t = "Circle2" + tc; //# var circle3t = "Circle3" + tc; //# var quad2t = "Quad2" + tc; //# var quad3t = "Quad3" + tc; //# var range1t = "Range1" + tc; //# var box2t = "Box2" + tc; //# var box3t = "Box3" + tc; //# var hull2t = "Hull2" + tc; //# var hull3t = "Hull3" + tc; //# var sphere3t = "Sphere3" + tc; //# var cylinder3t = "Cylinder3" + tc; //# var ellipse3t = "Ellipse3" + tc; //# var triangle2t = "Triangle2" + tc; //# var triangle3t = "Triangle3" + tc; //# var polygon2t = "Polygon2" + tc; //# var polygon3t = "Polygon3" + tc; //# var euclidean3t = "Euclidean3" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var eminus5 = isDouble ? "1E-5" : "1E-5f"; //# var epsdot = isDouble ? "1E-7" : "1E-4f"; // Contains-tests should return true if the contained object is // either entirely inside the containing object or lies on the // boundary of the containing object. #region __triangle2t__ contains __v2t__ public static bool Contains( this __triangle2t__ triangle, __v2t__ point ) { var v0p = point - triangle.P0; return triangle.Line01.LeftValueOfDir(v0p) >= 0 && triangle.Line02.RightValueOfDir(v0p) >= 0 && triangle.Line12.LeftValueOfPos(point) >= 0; } #endregion #region __triangle2t__ contains __line2t__ (sm) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this __triangle2t__ triangle, __line2t__ linesegment) => triangle.Contains(linesegment.P0) && triangle.Contains(linesegment.P1); #endregion #region __triangle2t__ contains __triangle2t__ (sm) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this __triangle2t__ triangle, __triangle2t__ other) => triangle.Contains(other.P0) && triangle.Contains(other.P1) && triangle.Contains(other.P2); #endregion #region __triangle2t__ contains __quad2t__ (sm) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this __triangle2t__ triangle, __quad2t__ q) => triangle.Contains(q.P0) && triangle.Contains(q.P1) && triangle.Contains(q.P2) && triangle.Contains(q.P3); #endregion #region __triangle2t__ contains __circle2t__ public static bool Contains(this __triangle2t__ triangle, __circle2t__ circle) { var center = circle.Center; return triangle.Contains(center) && circle.Radius <= center.GetMinimalDistanceTo(triangle.Line01) && circle.Radius <= center.GetMinimalDistanceTo(triangle.Line12) && circle.Radius <= center.GetMinimalDistanceTo(triangle.Line20); } #endregion #region __circle2t__ contains __v2t__ (sm) /// /// True if point p is contained in this circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this __circle2t__ circle, __v2t__ p) => (p - circle.Center).LengthSquared <= circle.RadiusSquared; #endregion #region __circle2t__ contains __line2t__ (sm) /// /// True if line segment is contained in this circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this __circle2t__ circle, __line2t__ l) => circle.Contains(l.P0) && circle.Contains(l.P1); #endregion #region __circle2t__ contains __triangle2t__ (sm) /// /// True if triangle is contained in this circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this __circle2t__ circle, __triangle2t__ t) => circle.Contains(t.P0) && circle.Contains(t.P1) && circle.Contains(t.P2); #endregion #region __circle2t__ contains __quad2t__ (sm) /// /// True if quad is contained in this circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this __circle2t__ circle, __quad2t__ q) => circle.Contains(q.P0) && circle.Contains(q.P1) && circle.Contains(q.P2) && circle.Contains(q.P3); #endregion #region __circle2t__ contains __circle2t__ (sm) /// /// True if other circle is contained in this circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this __circle2t__ circle, __circle2t__ other) => (other.Center - circle.Center).Length + other.Radius <= circle.Radius; #endregion #region __quad2t__ contains __v2t__ (haaser) /// /// True if point is contained in this quad. /// public static bool Contains(this __quad2t__ quad, __v2t__ point) { return LeftValOfPos(0, 1, ref point) >= 0 && LeftValOfPos(1, 2, ref point) >= 0 && LeftValOfPos(2, 3, ref point) >= 0 && LeftValOfPos(3, 0, ref point) >= 0; __rtype__ LeftValOfPos(int i0, int i1, ref __v2t__ p) => (p.X - quad[i0].X) * (quad[i0].Y - quad[i1].Y) + (p.Y - quad[i0].Y) * (quad[i1].X - quad[i0].X); } #endregion #region __quad2t__ contains __line2t__ /// /// True if line segment is contained in this quad. /// public static bool Contains(this __quad2t__ quad, __line2t__ l) => quad.Contains(l.P0) && quad.Contains(l.P1); #endregion #region __quad2t__ contains __triangle2t__ /// /// True if triangle is contained in this quad. /// public static bool Contains(this __quad2t__ quad, __triangle2t__ t) => quad.Contains(t.P0) && quad.Contains(t.P1) && quad.Contains(t.P2); #endregion #region __quad2t__ contains __quad2t__ /// /// True if other quad is contained in this quad. /// public static bool Contains(this __quad2t__ quad, __quad2t__ q) => quad.Contains(q.P0) && quad.Contains(q.P1) && quad.Contains(q.P2) && quad.Contains(q.P3); #endregion #region __quad2t__ contains __circle2t__ /// /// True if circle is contained in this quad. /// public static bool Contains(this __quad2t__ quad, __circle2t__ circle) { var center = circle.Center; return quad.Contains(center) && circle.Radius <= center.GetMinimalDistanceTo(quad.Line01) && circle.Radius <= center.GetMinimalDistanceTo(quad.Line12) && circle.Radius <= center.GetMinimalDistanceTo(quad.Line23) && circle.Radius <= center.GetMinimalDistanceTo(quad.Line30); } #endregion #region __box3t__ contains __quad3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains( this __box3t__ box, __quad3t__ quad ) { return box.Contains(quad.P0) && box.Contains(quad.P1) && box.Contains(quad.P2) && box.Contains(quad.P3); } #endregion #region __box3t__ contains __triangle3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains( this __box3t__ box, __triangle3t__ triangle ) { return box.Contains(triangle.P0) && box.Contains(triangle.P1) && box.Contains(triangle.P2); } #endregion #region __box3t__ contains __sphere3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains( this __box3t__ box, __sphere3t__ sphere ) { return box.Contains(sphere.Center) && !box.Intersects(sphere); } #endregion #region __box3t__ contains __cylinder3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains( this __box3t__ box, __cylinder3t__ cylinder ) { return box.Contains(cylinder.Center) && !box.Intersects(cylinder); } #endregion #region __hull3t__ contains __v3t__ /// /// Hull normals are expected to point outside. /// public static bool Contains(this __hull3t__ hull, __v3t__ point) { var planes = hull.PlaneArray; for (var i = 0; i < planes.Length; i++) { if (planes[i].Height(point) > 0) return false; } return true; } #endregion #region __hull3t__ contains __sphere3t__ (sm) /// /// Hull normals are expected to point outside. /// public static bool Contains(this __hull3t__ hull, __sphere3t__ sphere) { var planes = hull.PlaneArray; var negativeRadius = -sphere.Radius; for (var i = 0; i < planes.Length; i++) { if (planes[i].Height(sphere.Center) > negativeRadius) return false; } return true; } #endregion #region __polygon2t__ contains __v2t__ (haaser) internal static V3i InsideTriangleFlags(ref __v2t__ p0, ref __v2t__ p1, ref __v2t__ p2, ref __v2t__ point) { __v2t__ n0 = new __v2t__(p0.Y - p1.Y, p1.X - p0.X); __v2t__ n1 = new __v2t__(p1.Y - p2.Y, p2.X - p1.X); __v2t__ n2 = new __v2t__(p2.Y - p0.Y, p0.X - p2.X); int t0 = Fun.Sign(n0.Dot(point - p0)); int t1 = Fun.Sign(n1.Dot(point - p1)); int t2 = Fun.Sign(n2.Dot(point - p2)); if (t0 == 0) t1 = 1; if (t1 == 0) t1 = 1; if (t2 == 0) t2 = 1; return new V3i(t0, t1, t2); } internal static V3i InsideTriangleFlags(ref __v2t__ p0, ref __v2t__ p1, ref __v2t__ p2, ref __v2t__ point, int t0) { __v2t__ n1 = new __v2t__(p1.Y - p2.Y, p2.X - p1.X); __v2t__ n2 = new __v2t__(p2.Y - p0.Y, p0.X - p2.X); int t1 = Fun.Sign(n1.Dot(point - p1)); int t2 = Fun.Sign(n2.Dot(point - p2)); if (t1 == 0) t1 = 1; if (t2 == 0) t2 = 1; return new V3i(t0, t1, t2); } /// /// Returns true if the __polygon2t__ contains the given point. /// Works with all (convex and non-convex) Polygons. /// Assumes that the Vertices of the Polygon are sorted counter clockwise /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this __polygon2t__ poly, __v2t__ point) { return poly.Contains(point, true); } /// /// Returns true if the __polygon2t__ contains the given point. /// Works with all (convex and non-convex) Polygons. /// CCW represents the sorting order of the Polygon-Vertices (true -> CCW, false -> CW) /// public static bool Contains(this __polygon2t__ poly, __v2t__ point, bool CCW) { int pc = poly.PointCount; if (pc < 3) return false; int counter = 0; __v2t__ p0 = poly[0], p1 = poly[1], p2 = poly[2]; V3i temp = InsideTriangleFlags(ref p0, ref p1, ref p2, ref point); int t2_cache = temp.Z; if (temp.X == temp.Y && temp.Y == temp.Z) counter += temp.X; for (int pi = 3; pi < pc; pi++) { p1 = p2; p2 = poly[pi]; temp = InsideTriangleFlags(ref p0, ref p1, ref p2, ref point, -t2_cache); t2_cache = temp.Z; if (temp.X == temp.Y && temp.Y == temp.Z) counter += temp.X; } if (CCW) return counter > 0; else return counter < 0; } #endregion #region __plane3t__ +- eps contains __v3t__ (sm) /// /// Returns true if point is within given eps to plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this __plane3t__ plane, __rtype__ eps, __v3t__ point) { var d = plane.Height(point); return d >= -eps && d <= eps; } #endregion #region __plane3t__ +- eps contains __box3t__ (sm) /// /// Returns true if the space within eps to a plane fully contains the given box. /// public static bool Contains(this __plane3t__ plane, __rtype__ eps, __box3t__ box) { var corners = box.ComputeCorners(); for (var i = 0; i < 8; i++) { var d = plane.Height(corners[i]); if (d < -eps || d > eps) return false; } return true; } #endregion #region __polygon3t__ +- eps contains __v3t__ (sm) /// /// Returns true if point is within given eps to polygon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this __polygon3t__ polygon, __rtype__ eps, __v3t__ point, out __rtype__ distance) { var plane = polygon.Get__plane3t__(); distance = plane.Height(point); if (distance < -eps || distance > eps) return false; var w2p = plane.GetWorldToPlane(); var poly2d = new __polygon2t__(polygon.GetPointArray().Map(p => w2p.TransformPos(p).XY)); return poly2d.Contains(w2p.TransformPos(point).XY); } /// /// Returns true if point is within given eps to polygon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this __polygon3t__ polygon, __plane3t__ supportingPlane, __euclidean3t__ world2plane, __polygon2t__ poly2d, __rtype__ eps, __v3t__ point, out __rtype__ distance) { distance = supportingPlane.Height(point); if (distance < -eps || distance > eps) return false; return poly2d.Contains(world2plane.TransformPos(point).XY); } /// /// Returns true if point is within given eps to polygon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Contains(this __polygon3t__ polygon, __plane3t__ supportingPlane, __m44t__ world2plane, __polygon2t__ poly2d, __rtype__ eps, __v3t__ point, out __rtype__ distance) { distance = supportingPlane.Height(point); if (distance < -eps || distance > eps) return false; return poly2d.Contains(world2plane.TransformPos(point).XY); } #endregion // Intersection tests #region __line2t__ intersects __line2t__ /// /// Returns true if the two line segments intersect. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __line2t__ l0, __line2t__ l1) => l0.IntersectsLine(l1.P0, l1.P1, out __v2t__ _); /// /// Returns true if the two line segments intersect. /// The intersection point is returned in p. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __line2t__ l0, __line2t__ l1, out __v2t__ p) => l0.IntersectsLine(l1.P0, l1.P1, out p); /// /// Returns true if the two line segments intersect within given tolerance. /// The intersection point is returned in p. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __line2t__ l0, __line2t__ l1, __rtype__ absoluteEpsilon, out __v2t__ p) => l0.IntersectsLine(l1.P0, l1.P1, absoluteEpsilon, out p); /// /// Returns true if the line segment intersects the line segment between p0 and p1. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine(this __line2t__ line, __v2t__ p0, __v2t__ p1) => line.IntersectsLine(p0, p1, out _); /// /// Returns true if the line segment intersects the line segment between p0 and p1. /// The intersection point is returned in p. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine(this __line2t__ line, __v2t__ p0, __v2t__ p1, out __v2t__ p) => line.IntersectsLine(p0, p1, false, out p); /// /// Returns true if the line segment intersects the line segment between p0 and p1. /// The intersection point is returned in p. /// If overlapping is true and the segments are parallel, then /// the closest point to p0 of the intersection range is returned in p. /// public static bool IntersectsLine( this __line2t__ line, __v2t__ p0, __v2t__ p1, bool overlapping, out __v2t__ p ) { var a = line.P0 - p0; if (Fun.IsTiny(a.LengthSquared)) { p = p0; return true; } var u = line.P1 - line.P0; var v = p1 - p0; var lu = u.Length; var cross = u.X * v.Y - u.Y * v.X; if (!Fun.IsTiny(cross)) { // non-parallel lines cross = 1 / cross; var t0 = (a.Y * v.X - a.X * v.Y) * cross; if (t0 > 1 || t0 < 0) { p = __v2t__.NaN; return false; } __rtype__ t1 = (a.Y * u.X - a.X * u.Y) * cross; if (t1 > 1 || t1 < 0) { p = __v2t__.NaN; return false; } p = line.P0 + u * t0; return true; } else { // parallel lines if (!overlapping) { p = __v2t__.NaN; return false; } var normalizedDirection = u / lu; var r0 = new __range1t__(0, lu); var r1 = new __range1t__((p0 - line.P0).Dot(normalizedDirection), (p1 - line.P0).Dot(normalizedDirection)); r1.Repair(); if (r0.Intersects(r1, 0, out __range1t__ result)) { p = line.P0 + normalizedDirection * result.Min; return true; } p = __v2t__.NaN; return false; } } /// /// Returns true if the line segment intersects the line segment between p0 and p1 within given tolerance. /// The intersection point is returned in p. /// If the segments are parallel and overlap, then no intersection is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine(this __line2t__ line, __v2t__ p0, __v2t__ p1, __rtype__ absoluteEpsilon, out __v2t__ p) => line.IntersectsLine(p0, p1, absoluteEpsilon, false, out p); /// /// Returns true if the line segment intersects the line segment between p0 and p1 within given tolerance. /// The intersection point is returned in p. /// If overlapping is true and the segments are parallel, then /// the closest point to p0 of the intersection range is returned in p. /// public static bool IntersectsLine( this __line2t__ line, __v2t__ p0, __v2t__ p1, __rtype__ absoluteEpsilon, bool overlapping, out __v2t__ p ) { var a = line.P0 - p0; if (Fun.IsTiny(a.LengthSquared)) { p = p0; return true; } var u = line.P1 - line.P0; var v = p1 - p0; var lu = u.Length; var lv = v.Length; var relativeEpsilonU = absoluteEpsilon / lu; var RelativeEpsilonV = absoluteEpsilon / lv; var cross = u.X * v.Y - u.Y * v.X; if (!Fun.IsTiny(cross)) { // non-parallel lines cross = 1 / cross; var t0 = (a.Y * v.X - a.X * v.Y) * cross; if (t0 > 1 + relativeEpsilonU || t0 < -relativeEpsilonU) { p = __v2t__.NaN; return false; } var t1 = (a.Y * u.X - a.X * u.Y) * cross; if (t1 > 1 + RelativeEpsilonV || t1 < -RelativeEpsilonV) { p = __v2t__.NaN; return false; } p = line.P0 + u * t0; return true; } else { // parallel lines if (!overlapping) { p = __v2t__.NaN; return false; } var normalizedDirection = u / lu; var r0 = new __range1t__(0, lu); var r1 = new __range1t__((p0 - line.P0).Dot(normalizedDirection), (p1 - line.P0).Dot(normalizedDirection)); r1.Repair(); if (r0.Intersects(r1, absoluteEpsilon, out __range1t__ result)) { p = line.P0 + normalizedDirection * result.Min; return true; } p = __v2t__.NaN; return false; } } #endregion #region __ray2t__ intersects __line2t__ /// /// Returns true if the Ray and the Line intersect. /// ATTENTION: Both-Sided Ray /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __ray2t__ ray, __line2t__ line ) { return ray.IntersectsLine(line.P0, line.P1, out _); } /// /// returns true if the Ray and the Line intersect. /// t holds the smallest Intersection-Parameter for the Ray /// ATTENTION: t can be negative /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __ray2t__ ray, __line2t__ line, out __rtype__ t ) { return ray.IntersectsLine(line.P0, line.P1, out t); } /// /// returns true if the Ray and the Line(p0,p1) intersect. /// ATTENTION: Both-Sided Ray /// public static bool IntersectsLine( this __ray2t__ ray, __v2t__ p0, __v2t__ p1 ) { __v2t__ n = new __v2t__(-ray.Direction.Y, ray.Direction.X); __rtype__ d0 = n.Dot(p0 - ray.Origin); __rtype__ d1 = n.Dot(p1 - ray.Origin); if (d0.Sign() != d1.Sign()) return true; else if (Fun.IsTiny(d0) && Fun.IsTiny(d1)) return true; else return false; } /// /// returns true if the Ray and the Line(p0,p1) intersect. /// t holds the Intersection-Parameter for the Ray /// If both Line-Points are on the Ray no Intersection is returned /// ATTENTION: t can be negative /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine( this __ray2t__ ray, __v2t__ p0, __v2t__ p1, out __rtype__ t ) { return ray.IntersectsLine(p0, p1, false, out t); } /// /// returns true if the Ray and the Line(p0,p1) intersect. /// if overlapping is true t holds the smallest Intersection-Parameter for the Ray /// if overlagging is false and both Line-Points are on the Ray no Intersection is returned /// ATTENTION: t can be negative /// public static bool IntersectsLine( this __ray2t__ ray, __v2t__ p0, __v2t__ p1, bool overlapping, out __rtype__ t ) { __v2t__ a = p0 - ray.Origin; __v2t__ u = p1 - p0; __v2t__ v = ray.Direction; __rtype__ lv2 = v.LengthSquared; __rtype__ cross = u.X * v.Y - u.Y * v.X; __rtype__ n = a.Y * u.X - a.X * u.Y; if (!Fun.IsTiny(cross)) { cross = 1 / cross; __rtype__ t0 = (a.Y * v.X - a.X * v.Y) * cross; if (t0 >= 0 && t0 <= 1) { t = n * cross; return true; } t = __rtype__.NaN; return false; } if (Fun.IsTiny(n) && overlapping) { __rtype__ ta = v.Dot(a) / lv2; __rtype__ tb = v.Dot(p1 - ray.Origin) / lv2; if ((ta < 0 && tb > 0) || (ta > 0 && tb < 0)) { t = 0; return true; } else { if (ta >= 0) t = Fun.Min(ta, tb); else t = Fun.Max(ta, tb); return true; } } t = __rtype__.NaN; return false; } #endregion #region __ray2t__ intersects __ray2t__ /// /// Returns true if the Rays intersect /// ATTENTION: Both-Sided Rays /// public static bool Intersects( this __ray2t__ r0, __ray2t__ r1 ) { if (!r0.Direction.IsParallelTo(r1.Direction)) return true; else { __v2t__ n0 = new __v2t__(-r0.Direction.Y, r0.Direction.X); if (Fun.IsTiny(n0.Dot(r1.Origin - r0.Origin))) return true; else return false; } } /// /// Returns true if the Rays intersect /// t0 and t1 are the corresponding Ray-Parameters for the Intersection /// ATTENTION: Both-Sided Rays /// public static bool Intersects( this __ray2t__ r0, __ray2t__ r1, out __rtype__ t0, out __rtype__ t1 ) { __v2t__ a = r0.Origin - r1.Origin; if (r0.Origin.ApproximateEquals(r1.Origin, Constant<__rtype__>.PositiveTinyValue)) { t0 = 0; t1 = 0; return true; } __v2t__ u = r0.Direction; __v2t__ v = r1.Direction; __rtype__ cross = u.X * v.Y - u.Y * v.X; if (!Fun.IsTiny(cross)) { //Rays not parallel cross = 1 / cross; t0 = (a.Y * v.X - a.X * v.Y) * cross; t1 = (a.Y * u.X - a.X * u.Y) * cross; return true; } else { t0 = __rtype__.NaN; t1 = __rtype__.NaN; //Rays are parallel if (Fun.IsTiny(a.Y * u.X - a.X * u.Y)) return true; else return false; } } /// /// Returns true if the Rays intersect. /// public static bool Intersects(this __ray2t__ r0, __ray2t__ r1, out __rtype__ t) { __v2t__ a = r1.Origin - r0.Origin; if (a.Abs().AllSmaller(Constant<__rtype__>.PositiveTinyValue)) { t = 0; return true; // Early exit when rays have same origin } __rtype__ cross = r0.Direction.Dot270(r1.Direction); if (!Fun.IsTiny(cross)) // Rays not parallel { t = r1.Direction.Dot90(a) / cross; return true; } else // Rays are parallel { t = __rtype__.NaN; return false; } } #endregion #region __ray2t__ intersects __circle2t__ /// /// Computes the intersection between the given and . /// /// The ray to intersect. /// The circle to intersect the ray with. /// The ray parameter of the first intersection. Set to infinity if there is no intersection. /// The ray parameter of the second intersection. Set to infinity if there is no intersection. /// True if there is an intersection, false otherwise. public static bool Intersects(this __ray2t__ ray, __circle2t__ circle, out __rtype__ t0, out __rtype__ t1) { var p = ray.Origin - circle.Center; var a = ray.Direction.X.Square() + ray.Direction.Y.Square(); var b = 2 * ray.Direction.X * p.X + 2 * ray.Direction.Y * p.Y; var c = p.X.Square() + p.Y.Square() - circle.Radius.Square(); var d = b.Square() - 4 * a * c; if (d < 0) { t0 = __rtype__.PositiveInfinity; t1 = __rtype__.PositiveInfinity; return false; } else { var div = 1 / (a + a); d = d.Sqrt(); t0 = (-b + d) * div; t1 = (-b - d) * div; return true; } } #endregion #region __plane2t__ intersects __line2t__ /// /// Returns true if the __plane2t__ and the __line2t__ intersect or the __line2t__ /// lies completely in the Plane's Epsilon-Range /// ATTENTION: Works only with Normalized Plane2ds /// public static bool Intersects( this __plane2t__ plane, __line2t__ line, __rtype__ absoluteEpsilon ) { __rtype__ lengthOfNormal2 = plane.Normal.LengthSquared; __rtype__ d0 = plane.Height(line.P0); __rtype__ d1 = plane.Height(line.P1); return d0 * d1 < absoluteEpsilon * absoluteEpsilon * lengthOfNormal2; } /// /// Returns true if the __plane2t__ and the __line2t__ intersect /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __plane2t__ plane, __line2t__ line ) { return plane.IntersectsLine(line.P0, line.P1); } /// /// Returns true if the __plane2t__ and the line between p0 and p1 intersect /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine( this __plane2t__ plane, __v2t__ p0, __v2t__ p1 ) { __rtype__ d0 = plane.Height(p0); __rtype__ d1 = plane.Height(p1); return d0 * d1 <= 0; } /// /// Returns true if the __plane2t__ and the __line2t__ intersect /// point holds the Intersection-Point. If no Intersection is found point is __v2t__.NaN /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __plane2t__ plane, __line2t__ line, out __v2t__ point ) { return plane.Intersects(line, 0, out point); } /// /// Returns true if the __plane2t__ and the __line2t__ intersect or the __line2t__ /// lies completely in the Plane's Epsilon-Range /// point holds the Intersection-Point. If the __line2t__ is inside Epsilon point holds the centroid of the __line2t__ /// If no Intersection is found point is __v2t__.NaN /// ATTENTION: Works only with Normalized Plane2ds /// public static bool Intersects( this __plane2t__ plane, __line2t__ line, __rtype__ absoluteEpsilon, out __v2t__ point ) { __rtype__ h0 = plane.Height(line.P0); __rtype__ h1 = plane.Height(line.P1); int s0 = (h0 > -absoluteEpsilon ? (h0 < absoluteEpsilon ? 0 : 1) : -1); int s1 = (h1 > -absoluteEpsilon ? (h1 < absoluteEpsilon ? 0 : 1) : -1); if (s0 == s1) { if (s0 != 0) { point = __v2t__.NaN; return false; } else { point = (line.P0 + line.P1) * __half__; return true; } } else { if (s0 == 0) { point = line.P0; return true; } else if (s1 == 0) { point = line.P1; return true; } else { __v2t__ dir = line.Direction; __rtype__ no = plane.Normal.Dot(line.P0); __rtype__ nd = plane.Normal.Dot(dir); __rtype__ t = (plane.Distance - no) / nd; point = line.P0 + t * dir; return true; } } } #endregion #region __plane2t__ intersects __ray2t__ /// /// Returns true if the __plane2t__ and the __ray2t__ intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __plane2t__ plane, __ray2t__ ray) => !plane.Normal.IsOrthogonalTo(ray.Direction); /// /// Returns true if the Plane2d and the Ray2d intersect. /// point holds the Intersection-Point if an intersection is found (else V2d.NaN) /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __plane2t__ plane, __ray2t__ ray, out __v2t__ point) => plane.Intersects(ray, out __rtype__ t, out point); /// /// Returns true if the __plane2t__ and the __ray2t__ intersect. /// t holds the ray paramater of the intersection point if the intersection is found (else Double.PositiveInfinity). /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __plane2t__ plane, __ray2t__ ray, out __rtype__ t) { __rtype__ dot = Vec.Dot(plane.Normal, ray.Direction); if (Fun.IsTiny(dot)) { t = __rtype__.PositiveInfinity; return false; } t = -plane.Height(ray.Origin) / dot; return true; } /// /// Returns true if the __plane2t__ and the __ray2t__ intersect. /// t and p hold the ray paramater and point of the intersection if one is found (else Double.PositiveInfinity and __v2t__.PositiveInfinity). /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __plane2t__ plane, __ray2t__ ray, out __rtype__ t, out __v2t__ p) { bool result = Intersects(plane, ray, out t); p = ray.Origin + t * ray.Direction; return result; } /// /// Returns the intersection point of the given __plane2t__ and __ray2t__, or __v2t__.PositiveInfinity if ray is parallel to plane. /// ATTENTION: Works only with Normalized Plane2ds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ Intersect(this __plane2t__ plane, __ray2t__ ray) { __rtype__ dot = Vec.Dot(ray.Direction, plane.Normal); if (Fun.IsTiny(dot)) return __v2t__.PositiveInfinity; return ray.GetPointOnRay(-plane.Height(ray.Origin) / dot); } #endregion #region __plane2t__ intersects __plane2t__ /// /// Returns true if the two Plane2ds intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __plane2t__ p0, __plane2t__ p1) { var hit = p0.Coefficients.Cross(p1.Coefficients); return !hit.Z.IsTiny(); } /// /// Returns true if the two Plane2ds intersect. /// Point holds the intersection point if an intersection is found. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __plane2t__ p0, __plane2t__ p1, out __v2t__ point) { var hit = p0.Coefficients.Cross(p1.Coefficients); point = hit.XY / hit.Z; return !hit.Z.IsTiny(); } #endregion #region __plane2t__ intersects IEnumerable<__v2t__> /// /// returns true if the __plane2t__ divides the Point-Cloud /// public static bool Divides( this __plane2t__ plane, IEnumerable<__v2t__> data ) { int first = int.MinValue; foreach (var p in data) { if (first == int.MinValue) { first = plane.Height(p).Sign(); } else { if (plane.Height(p).Sign() != first) return true; } } return false; } #endregion #region __circle2t__ intersects __circle2t__ (sm) /// /// Returns true if the circles intersect, or one contains the other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __circle2t__ c0, __circle2t__ c1) => (c0.Center - c1.Center).LengthSquared <= (c0.Radius + c1.Radius).Square(); #endregion #region __triangle2t__ intersects __line2t__ /// /// Returns true if the triangle and the line intersect or the triangle contains the line /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __triangle2t__ triangle, __line2t__ line ) { return triangle.IntersectsLine(line.P0, line.P1); } /// /// Returns true if the triangle and the line between p0 and p1 intersect or the triangle contains the line /// public static bool IntersectsLine( this __triangle2t__ triangle, __v2t__ p0, __v2t__ p1 ) { if(triangle.Contains(p0))return true; if(triangle.Contains(p1))return true; if(triangle.Line01.IntersectsLine(p0,p1))return true; if(triangle.Line12.IntersectsLine(p0,p1))return true; if(triangle.Line20.IntersectsLine(p0,p1))return true; return false; } #endregion #region __triangle2t__ intersects __ray2t__ /// /// Returns true if the Triangle and the Ray intersect /// public static bool Intersects( this __triangle2t__ triangle, __ray2t__ ray ) { if (triangle.Contains(ray.Origin)) return true; if (ray.IntersectsLine(triangle.P0, triangle.P1)) return true; if (ray.IntersectsLine(triangle.P1, triangle.P2)) return true; if (ray.IntersectsLine(triangle.P2, triangle.P0)) return true; return false; } #endregion #region __triangle2t__ intersects __plane2t__ /// /// returns true if the __triangle2t__ and the __plane2t__ intersect /// public static bool Intersects( this __triangle2t__ triangle, __plane2t__ plane ) { if (plane.Intersects(triangle.Line01)) return true; if (plane.Intersects(triangle.Line12)) return true; if (plane.Intersects(triangle.Line20)) return true; return false; } #endregion #region __triangle2t__ intersects __triangle2t__ /// /// Returns true if the triangles intersect or one contains the other. /// public static bool Intersects(this __triangle2t__ t0, __triangle2t__ t1) { var l = t0.Line01; if (l.IntersectsLine(t1.P0, t1.P1)) return true; if (l.IntersectsLine(t1.P1, t1.P2)) return true; if (l.IntersectsLine(t1.P2, t1.P0)) return true; l = t0.Line12; if (l.IntersectsLine(t1.P0, t1.P1)) return true; if (l.IntersectsLine(t1.P1, t1.P2)) return true; if (l.IntersectsLine(t1.P2, t1.P0)) return true; l = t0.Line20; if (l.IntersectsLine(t1.P0, t1.P1)) return true; if (l.IntersectsLine(t1.P1, t1.P2)) return true; if (l.IntersectsLine(t1.P2, t1.P0)) return true; if (t0.Contains(t1.P0)) return true; if (t1.Contains(t0.P0)) return true; return false; } #endregion #region __box2t__ intersects __line2t__ /// /// Returns true if the box and the line intersect. /// public static bool Intersects(this __box2t__ box, __line2t__ line) { var out0 = box.OutsideFlags(line.P0); if (out0 == 0) return true; var out1 = box.OutsideFlags(line.P1); if (out1 == 0) return true; return box.IntersectsLine(line.P0, line.P1, out0, out1); } /// /// Returns true if the box and the line intersect. The outside flags /// of the end points of the line with respect to the box have to be /// supplied as parameters. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __box2t__ box, __line2t__ line, Box.Flags out0, Box.Flags out1) { return box.IntersectsLine(line.P0, line.P1, out0, out1); } /// /// Returns true if the box and the line intersect. The outside flags /// of the end points of the line with respect to the box have to be /// supplied as parameters. /// private static bool IntersectsLine( this __box2t__ box, __v2t__ p0, __v2t__ p1) { var out0 = box.OutsideFlags(p0); if (out0 == 0) return true; var out1 = box.OutsideFlags(p1); if (out1 == 0) return true; return box.IntersectsLine(p0, p1, out0, out1); } /// /// Returns true if the box and the line intersect. The outside flags /// of the end points of the line with respect to the box have to be /// supplied as parameters. /// private static bool IntersectsLine( this __box2t__ box, __v2t__ p0, __v2t__ p1, Box.Flags out0, Box.Flags out1) { if ((out0 & out1) != 0) return false; __v2t__ min = box.Min; __v2t__ max = box.Max; var bf = out0 | out1; if ((bf & Box.Flags.X) != 0) { __rtype__ dx = p1.X - p0.X; if ((bf & Box.Flags.MinX) != 0) { if (dx == 0 && p0.X < min.X) return false; __rtype__ t = (min.X - p0.X) / dx; __v2t__ p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MinX) == 0) return true; } if ((bf & Box.Flags.MaxX) != 0) { if (dx == 0 && p0.X > max.X) return false; __rtype__ t = (max.X - p0.X) / dx; __v2t__ p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MaxX) == 0) return true; } } if ((bf & Box.Flags.Y) != 0) { __rtype__ dy = p1.Y - p0.Y; if ((bf & Box.Flags.MinY) != 0) { if (dy == 0 && p0.Y < min.Y) return false; __rtype__ t = (min.Y - p0.Y) / dy; __v2t__ p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MinY) == 0) return true; } if ((bf & Box.Flags.MaxY) != 0) { if (dy == 0 && p0.Y > max.Y) return false; __rtype__ t = (max.Y - p0.Y) / dy; __v2t__ p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MaxY) == 0) return true; } } return false; } #endregion #region __box2t__ intersects __ray2t__ /// /// Returns true if the box and the ray intersect /// public static bool Intersects( this __box2t__ box, __ray2t__ ray ) { /* * Getting a Normal-Vector for the Ray and calculating * the Normal Distances for every Box-Point: */ __v2t__ n = new __v2t__(-ray.Direction.Y, ray.Direction.X); __rtype__ d0 = n.Dot(box.Min - ray.Origin); //n.Dot(box.p0 - ray.Origin) __rtype__ d1 = n.X * (box.Max.X - ray.Origin.X) + n.Y * (box.Min.Y - ray.Origin.Y); //n.Dot(box.p1 - ray.Origin) __rtype__ d2 = n.Dot(box.Max - ray.Origin); //n.Dot(box.p2 - ray.Origin) __rtype__ d3 = n.X * (box.Min.X - ray.Origin.X) + n.Y * (box.Max.Y - ray.Origin.Y); //n.Dot(box.p3 - ray.Origin) /* * If Zero lies in the Range of the Distances there * have to be Points on both sides of the Ray. * This means the Box and the Ray have an Intersection */ __range1t__ r = new __range1t__(d0, d1, d2, d3); return r.Contains(0); } #endregion #region __box2t__ intersects __plane2t__ /// /// returns true if the box and the plane intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __box2t__ box, __plane2t__ plane ) { //UNTESTED return plane.Divides(box.ComputeCorners()); } /// /// NOT TESTED YET. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __box2t__ box, __plane2t__ plane, out __line2t__ line) { return Intersects( plane.Normal.X, plane.Normal.Y, plane.Distance, box.Min.X, box.Min.Y, box.Max.X, box.Max.Y, out line); } /// /// Intersects an infinite line given by its normal vector [nx, ny] /// and its distance to the origin d, with an axis aligned box given /// by it minimal point [xmin, ymin] and its maximal point /// [xmax, ymax]. Returns true if there is an intersection and computes /// the actual intersection line. /// NOT TESTED YET. /// public static bool Intersects( __rtype__ nx, __rtype__ ny, __rtype__ d, __rtype__ xmin, __rtype__ ymin, __rtype__ xmax, __rtype__ ymax, out __line2t__ line) { if (nx.IsTiny()) // horizontal { if (d <= ymin || d >= ymax) { line = default; return false; } line = new __line2t__(new __v2t__(xmin, d), new __v2t__(xmax, d)); return true; } if (ny.IsTiny()) // vertical { if (d <= xmin || d >= xmax) { line = default; return false; } line = new __line2t__(new __v2t__(d, ymin), new __v2t__(d, ymax)); return true; } if (nx.Sign() != ny.Sign()) { __rtype__ x0 = (d - ny * ymin) / nx; if (x0 >= xmax) { line = default; return false; } if (x0 > xmin) xmin = x0; __rtype__ x1 = (d - ny * ymax) / nx; if (x1 <= xmin) { line = default; return false; } if (x1 < xmax) xmax = x1; __rtype__ y0 = (d - nx * xmin) / ny; if (y0 >= ymax) { line = default; return false; } if (y0 > ymin) ymin = y0; __rtype__ y1 = (d - nx * xmax) / ny; if (y1 <= ymin) { line = default; return false; } if (y1 < ymax) ymax = y1; line = new __line2t__(new __v2t__(xmin, ymin), new __v2t__(xmax, ymax)); } else { __rtype__ x0 = (d - ny * ymax) / nx; if (x0 >= xmax) { line = default; return false; } if (x0 > xmin) xmin = x0; __rtype__ x1 = (d - ny * ymin) / nx; if (x1 <= xmin) { line = default; return false; } if (x1 < xmax) xmax = x1; __rtype__ y0 = (d - nx * xmax) / ny; if (y0 >= ymax) { line = default; return false; } if (y0 > ymin) ymin = y0; __rtype__ y1 = (d - nx * xmin) / ny; if (y1 <= ymin) { line = default; return false; } if (y1 < ymax) ymax = y1; line = new __line2t__(new __v2t__(xmax, ymin), new __v2t__(xmin, ymax)); } return true; } #endregion #region __box2t__ intersects __triangle2t__ /// /// Returns true if the Box and the Triangle intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __box2t__ box, __triangle2t__ triangle ) { return box.IntersectsTriangle(triangle.P0, triangle.P1, triangle.P2); } /// /// Returns true if the Box and the Triangle intersect /// public static bool IntersectsTriangle( this __box2t__ box, __v2t__ p0, __v2t__ p1, __v2t__ p2 ) { var out0 = box.OutsideFlags(p0); if (out0 == 0) return true; var out1 = box.OutsideFlags(p1); if (out1 == 0) return true; var out2 = box.OutsideFlags(p2); if (out2 == 0) return true; return box.IntersectsTriangle(p0, p1, p2, out0, out1, out2); } /// /// Returns true if the Box and the Triangle intersect. The outside flags /// of the end points of the Triangle with respect to the box have to be /// supplied as parameters. /// private static bool IntersectsTriangle( this __box2t__ box, __v2t__ p0, __v2t__ p1, __v2t__ p2, Box.Flags out0, Box.Flags out1, Box.Flags out2 ) { /* --------------------------------------------------------------- If all of the points of the triangle are on the same side outside the box, no intersection is possible. --------------------------------------------------------------- */ if ((out0 & out1 & out2) != 0) return false; /* --------------------------------------------------------------- If two points of the triangle are not on the same side outside the box, it is possible that the edge between them intersects the box. The outside flags we computed are also used to optimize the intersection routine with the edge. --------------------------------------------------------------- */ if (box.IntersectsLine(p0, p1, out0, out1)) return true; if (box.IntersectsLine(p1, p2, out1, out2)) return true; if (box.IntersectsLine(p2, p0, out2, out0)) return true; /* --------------------------------------------------------------- The only case left: The triangle contains the the whole box i.e. every point. When no triangle-line intersects the box and one box point is inside the triangle the triangle must contain the box --------------------------------------------------------------- */ __v2t__ a = box.Min - p0; __v2t__ u = p1 - p0; __v2t__ v = p2 - p0; __rtype__ cross = u.X * v.Y - u.Y * v.X; if (Fun.IsTiny(cross)) return false; cross = 1 / cross; __rtype__ t0 = (a.Y * v.X - a.X * v.Y) * cross; if (t0 < 0 || t0 > 1) return false; __rtype__ t1 = (a.Y * u.X - a.X * u.Y) * cross; if (t1 < 0 || t1 > 1) return false; return (t0 + t1 < 1); } #endregion #region __box2t__ intersects __box2t__ (__box2t__-Implementation) //Directly in Box-Implementation #endregion #region __quad2t__ intersects __line2t__ /// /// returns true if the Quad and the line intersect or the quad contains the line /// public static bool Intersects( this __quad2t__ quad, __line2t__ line ) { if (quad.Contains(line.P0)) return true; if (quad.Contains(line.P1)) return true; if (line.IntersectsLine(quad.P0, quad.P1)) return true; if (line.IntersectsLine(quad.P1, quad.P2)) return true; if (line.IntersectsLine(quad.P2, quad.P3)) return true; if (line.IntersectsLine(quad.P3, quad.P0)) return true; return false; } /// /// returns true if the Quad and the line between p0 and p1 intersect or the quad contains the line /// public static bool IntersectsLine( this __quad2t__ quad, __v2t__ p0, __v2t__ p1 ) { if (quad.Contains(p0)) return true; if (quad.Contains(p1)) return true; __line2t__ line = new __line2t__(p0, p1); if (line.IntersectsLine(quad.P0, quad.P1)) return true; if (line.IntersectsLine(quad.P1, quad.P2)) return true; if (line.IntersectsLine(quad.P2, quad.P3)) return true; if (line.IntersectsLine(quad.P3, quad.P0)) return true; return false; } #endregion #region __quad2t__ intersects __ray2t__ /// /// returns true if the quad and the ray intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __quad2t__ quad, __ray2t__ ray ) { return ray.__plane2t__.Divides(quad.Points); } #endregion #region __quad2t__ intersects __plane2t__ /// /// returns true if the __quad2t__ and the __plane2t__ intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __quad2t__ quad, __plane2t__ plane ) { //UNTESTED if (plane.Divides(quad.Points)) return true; else return false; } #endregion #region __quad2t__ intersects __triangle2t__ /// /// returns true if the __quad2t__ and the __triangle2t__ intersect or one contains the other /// public static bool Intersects( this __quad2t__ quad, __triangle2t__ triangle ) { if (quad.Intersects(triangle.Line01)) return true; if (quad.Intersects(triangle.Line12)) return true; if (quad.Intersects(triangle.Line20)) return true; if (quad.Contains(triangle.P0)) return true; if (triangle.Contains(quad.P0)) return true; return false; } #endregion #region __quad2t__ intersects __box2t__ /// /// Returns true if the box and the Quad intersect or one contains the other /// public static bool Intersects( this __box2t__ box, __quad2t__ quad ) { Box.Flags out0 = box.OutsideFlags(quad.P0); if (out0 == 0) return true; Box.Flags out1 = box.OutsideFlags(quad.P1); if (out1 == 0) return true; Box.Flags out2 = box.OutsideFlags(quad.P2); if (out2 == 0) return true; Box.Flags out3 = box.OutsideFlags(quad.P3); if (out3 == 0) return true; /* --------------------------------------------------------------- If all of the points of the Quad are on the same side outside the box, no intersection is possible. --------------------------------------------------------------- */ if ((out0 & out1 & out2 & out3) != 0) return false; /* --------------------------------------------------------------- If two points of the Quad are not on the same side outside the box, it is possible that the edge between them intersects the box. The outside flags we computed are also used to optimize the intersection routine with the edge. --------------------------------------------------------------- */ if (box.IntersectsLine(quad.P0, quad.P1, out0, out1)) return true; if (box.IntersectsLine(quad.P1, quad.P2, out1, out2)) return true; if (box.IntersectsLine(quad.P2, quad.P3, out2, out3)) return true; if (box.IntersectsLine(quad.P3, quad.P0, out3, out0)) return true; /* --------------------------------------------------------------- The only case left: The Quad contains the the whole box i.e. every point. When no triangle-line intersects the box and one box point is inside the Quad the Quad must contain the box --------------------------------------------------------------- */ return quad.Contains(box.Min); } #endregion #region __quad2t__ intersects __quad2t__ /// /// returns true if the Quad2ds intersect or one contains the other /// public static bool Intersects( this __quad2t__ q0, __quad2t__ quad ) { if (q0.IntersectsLine(quad.P0, quad.P1)) return true; if (q0.IntersectsLine(quad.P1, quad.P2)) return true; if (q0.IntersectsLine(quad.P2, quad.P3)) return true; if (q0.IntersectsLine(quad.P3, quad.P0)) return true; if (q0.Contains(quad.P0)) return true; if (quad.Contains(q0.P0)) return true; return false; } #endregion #region __polygon2t__ intersects __line2t__ /// /// returns true if the __polygon2t__ and the __line2t__ intersect or the Polygon contains the Line /// public static bool Intersects( this __polygon2t__ poly, __line2t__ line ) { foreach (var l in poly.EdgeLines) { if (l.Intersects(line)) return true; } if (poly.Contains(line.P0)) return true; return false; } #endregion #region __polygon2t__ intersects __ray2t__ /// /// returns true if the __polygon2t__ and the __ray2t__ intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __polygon2t__ poly, __ray2t__ ray ) { //UNTESTED return ray.__plane2t__.Divides(poly.Points); } #endregion #region __polygon2t__ intersects __plane2t__ /// /// returns true if the __polygon2t__ and the __plane2t__ itnersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __polygon2t__ poly, __plane2t__ plane ) { //UNTESTED return plane.Divides(poly.Points); } #endregion #region __polygon2t__ intersects __triangle2t__ /// /// returns true if the __polygon2t__ and the __triangle2t__ intersect or one contains the other /// public static bool Intersects( this __polygon2t__ poly, __triangle2t__ triangle ) { foreach (var line in poly.EdgeLines) { if (triangle.Intersects(line)) return true; } if (triangle.Contains(poly[0])) return true; if (poly.Contains(triangle.P0)) return true; return false; } #endregion #region __polygon2t__ intersects __box2t__ /// /// returns true if the __polygon2t__ and the __box2t__ intersect or one contains the other /// public static bool Intersects( this __polygon2t__ poly, __box2t__ box ) { //UNTESTED int count = poly.PointCount; Box.Flags[] outFlags = new Box.Flags[count]; int i0 = 0; foreach (var p in poly.Points) outFlags[i0++] = box.OutsideFlags(p); i0 = 0; int i1 = 1; foreach (var l in poly.EdgeLines) { if (box.Intersects(l, outFlags[i0], outFlags[i1])) return true; i0++; i1 = (i1 + 1) % count; } if (box.Contains(poly[0])) return true; if (poly.Contains(box.Min)) return true; return false; } #endregion #region __polygon2t__ intersects __quad2t__ /// /// returns true if the __polygon2t__ and the __quad2t__ interset or one contains the other /// public static bool Intersects( this __polygon2t__ poly, __quad2t__ quad ) { foreach (var l in poly.EdgeLines) { if (quad.Intersects(l)) return true; } if (quad.Contains(poly[0])) return true; if (poly.Contains(quad.P0)) return true; return false; } #endregion #region __polygon2t__ intersects __polygon2t__ /// /// returns true if the Polygon2ds intersect or one contains the other /// public static bool Intersects( this __polygon2t__ poly0, __polygon2t__ poly1 ) { //check if projected ranges intersect for all possible normals __v2t__[] allnormals = new __v2t__[poly0.PointCount + poly1.PointCount]; int c = 0; foreach (var d in poly0.Edges) { allnormals[c] = new __v2t__(-d.Y, d.X); c++; } foreach (var d in poly1.Edges) { allnormals[c] = new __v2t__(-d.Y, d.X); c++; } foreach (var n in allnormals) { var r0 = poly0.ProjectTo(n); var r1 = poly1.ProjectTo(n); if (!r0.Intersects(r1)) return false; } return true; } private static __range1t__ ProjectTo(this __polygon2t__ poly, __v2t__ dir) { __rtype__ min = __rtype__.MaxValue; __rtype__ max = __rtype__.MinValue; foreach (var p in poly.Points) { __rtype__ dotproduct = p.Dot(dir); if (dotproduct < min) min = dotproduct; if (dotproduct > max) max = dotproduct; } return new __range1t__(min, max); } #endregion #region __line3t__ intersects __line3t__ (haaser) /// /// Returns true if the minimal distance between the given lines is smaller than Constant<__rtype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __line3t__ l0, __line3t__ l1 ) { return l0.Intersects(l1, Constant<__rtype__>.PositiveTinyValue); } /// /// Returns true if the minimal distance between the given lines is smaller than absoluteEpsilon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __line3t__ l0, __line3t__ l1, __rtype__ absoluteEpsilon ) { if (l0.GetMinimalDistanceTo(l1) < absoluteEpsilon) return true; else return false; } /// /// Returns true if the minimal distance between the given lines is smaller than absoluteEpsilon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __line3t__ l0, __line3t__ l1, __rtype__ absoluteEpsilon, out __v3t__ point ) { if (l0.GetMinimalDistanceTo(l1, out point) < absoluteEpsilon) return true; else return false; } #endregion #region __line3t__ intersects Special (inconsistent argument order) #region __line3t__ intersects __plane3t__ /// /// Returns true if the line and the plane intersect. /// public static bool Intersects( this __line3t__ line, __plane3t__ plane, out __rtype__ t ) { if (!line.__ray3t__.Intersects(plane, out t)) return false; if (t >= 0 && t <= 1) return true; t = __rtype__.PositiveInfinity; return false; } /// /// Returns true if the line and the plane intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __line3t__ line, __plane3t__ plane, out __rtype__ t, out __v3t__ p ) { bool result = line.Intersects(plane, out t); p = line.Origin + t * line.Direction; return result; } #endregion #region __line3t__ intersects __triangle3t__ /// /// Returns true if the line and the triangle intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __line3t__ line, __triangle3t__ triangle ) { return line.__ray3t__.IntersectsTriangle(triangle.P0, triangle.P1, triangle.P2, 0, 1, out _); } /// /// Returns true if the line and the triangle intersect. /// point holds the intersection point. /// public static bool Intersects( this __line3t__ line, __triangle3t__ triangle, out __v3t__ point ) { __ray3t__ ray = line.__ray3t__; if (ray.IntersectsTriangle(triangle.P0, triangle.P1, triangle.P2, 0, 1, out __rtype__ temp)) { point = ray.GetPointOnRay(temp); return true; } else { point = __v3t__.NaN; return false; } } #endregion #endregion #region __ray3t__ intersects __line3t__ (haaser) /// /// Returns true if the minimal distance between the line and the ray is smaller than Constant<__rtype__>.PositiveTinyValue /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __ray3t__ ray, __line3t__ line ) { return ray.Intersects(line, Constant<__rtype__>.PositiveTinyValue); } /// /// Returns true if the minimal distance between the line and the ray is smaller than absoluteEpsilon /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __ray3t__ ray, __line3t__ line, __rtype__ absoluteEpsilon ) { if (ray.GetMinimalDistanceTo(line) < absoluteEpsilon) return true; else return false; } /// /// Returns true if the minimal distance between the line and the ray is smaller than absoluteEpsilon /// t holds the corresponding ray parameter /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __ray3t__ ray, __line3t__ line, __rtype__ absoluteEpsilon, out __rtype__ t ) { if (ray.GetMinimalDistanceTo(line, out t) < absoluteEpsilon) return true; else return false; } #endregion #region __ray3t__ intersects __ray3t__ (haaser) /// /// returns true if the minimal distance between the rays is smaller than Constant<__rtype__>.PositiveTinyValue /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __ray3t__ r0, __ray3t__ r1 ) { return r0.Intersects(r1, out _, out _, Constant<__rtype__>.PositiveTinyValue); } /// /// returns true if the minimal distance between the rays is smaller than Constant<__rtype__>.PositiveTinyValue /// t0 and t1 hold the ray-parameters for the intersection /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __ray3t__ r0, __ray3t__ r1, out __rtype__ t0, out __rtype__ t1 ) { return r0.Intersects(r1, out t0, out t1, Constant<__rtype__>.PositiveTinyValue); } /// /// returns true if the minimal distance between the rays is smaller than absoluteEpsilon /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __ray3t__ r0, __ray3t__ r1, __rtype__ absoluteEpsilon ) { return r0.Intersects(r1, out _, out _, absoluteEpsilon); } /// /// returns true if the minimal distance between the rays is smaller than absoluteEpsilon /// t0 and t1 hold the ray-parameters for the intersection /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __ray3t__ r0, __ray3t__ r1, out __rtype__ t0, out __rtype__ t1, __rtype__ absoluteEpsilon ) { if (r0.GetMinimalDistanceTo(r1, out t0, out t1) < absoluteEpsilon) return true; else return false; } #endregion #region __ray3t__ intersects Special (inconsistent argument order) #region __ray3t__ intersects __triangle3t__ /// /// Returns true if the ray and the triangle intersect. If you need /// information about the hit point see the __ray3t__.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __ray3t__ ray, __triangle3t__ triangle) => ray.IntersectsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, __rtype__.MinValue, __rtype__.MaxValue); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the __ray3t__.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __ray3t__ ray, __triangle3t__ triangle, __rtype__ tmin, __rtype__ tmax) => ray.IntersectsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, tmin, tmax); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the __ray3t__.Hits method. /// t holds the corresponding ray-parameter /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __ray3t__ ray, __triangle3t__ triangle, __rtype__ tmin, __rtype__ tmax, out __rtype__ t) => ray.IntersectsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, tmin, tmax, out t); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the __ray3t__.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsTriangle(this __ray3t__ ray, __v3t__ p0, __v3t__ p1, __v3t__ p2, __rtype__ tmin, __rtype__ tmax) => ray.IntersectsTriangle(p0, p1, p2, tmin, tmax, out __rtype__ _); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the __ray3t__.Hits method. /// t holds the corresponding ray-parameter /// public static bool IntersectsTriangle(this __ray3t__ ray, __v3t__ p0, __v3t__ p1, __v3t__ p2, __rtype__ tmin, __rtype__ tmax, out __rtype__ t) { var edge01 = p1 - p0; var edge02 = p2 - p0; var plane = Vec.Cross(ray.Direction, edge02); var det = Vec.Dot(edge01, plane); if (det > -__epsdot__ && det < __epsdot__) { t = __rtype__.NaN; return false; } //ray ~= parallel / Triangle var tv = ray.Origin - p0; det = 1 / det; // det is now inverse det var u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) { t = __rtype__.NaN; return false; } plane = Vec.Cross(tv, edge01); // plane is now qv var v = Vec.Dot(ray.Direction, plane) * det; if (v < 0 || u + v > 1) { t = __rtype__.NaN; return false; } var temp_t = Vec.Dot(edge02, plane) * det; if (temp_t < tmin || temp_t >= tmax) { t = __rtype__.NaN; return false; } t = temp_t; return true; } /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the __ray3t__.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsTrianglePointAndEdges(this __ray3t__ ray, __v3t__ p0, __v3t__ edge01, __v3t__ edge02, __rtype__ tmin, __rtype__ tmax) => ray.IntersectsTrianglePointAndEdges(p0, edge01, edge02, tmin, tmax, out _); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the __ray3t__.Hits method. /// t holds the corresponding ray-parameter /// public static bool IntersectsTrianglePointAndEdges(this __ray3t__ ray, __v3t__ p0, __v3t__ edge01, __v3t__ edge02, __rtype__ tmin, __rtype__ tmax, out __rtype__ t) { var plane = Vec.Cross(ray.Direction, edge02); var det = Vec.Dot(edge01, plane); if (det > -__epsdot__ && det < __epsdot__) { t = __rtype__.NaN; return false; } //ray ~= parallel / Triangle var tv = ray.Origin - p0; det = 1 / det; // det is now inverse det var u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) { t = __rtype__.NaN; return false; } plane = Vec.Cross(tv, edge01); // plane is now qv var v = Vec.Dot(ray.Direction, plane) * det; if (v < 0 || u + v > 1) { t = __rtype__.NaN; return false; } var temp_t = Vec.Dot(edge02, plane) * det; if (temp_t < tmin || temp_t >= tmax) { t = __rtype__.NaN; return false; } t = temp_t; return true; } #endregion #region __ray3t__ intersects __quad3t__ /// /// Returns true if the ray and the triangle intersect. If you need /// information about the hit point see the __ray3t__.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __ray3t__ ray, __quad3t__ quad) => ray.Intersects(quad, __rtype__.MinValue, __rtype__.MaxValue); /// /// Returns true if the ray and the quad intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the __ray3t__.Hits method. /// public static bool Intersects(this __ray3t__ ray, __quad3t__ quad, __rtype__ tmin, __rtype__ tmax) { var edge02 = quad.P2 - quad.P0; return ray.IntersectsTrianglePointAndEdges(quad.P0, quad.Edge01, edge02, tmin, tmax) || ray.IntersectsTrianglePointAndEdges(quad.P0, edge02, quad.Edge03, tmin, tmax); } /// /// Returns true if the ray and the quad intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the __ray3t__.Hits method. /// public static bool IntersectsQuad(this __ray3t__ ray, __v3t__ p0, __v3t__ p1, __v3t__ p2, __v3t__ p3, __rtype__ tmin, __rtype__ tmax) { var edge02 = p2 - p0; return ray.IntersectsTrianglePointAndEdges(p0, p1 - p0, edge02, tmin, tmax) || ray.IntersectsTrianglePointAndEdges(p0, edge02, p3 - p0, tmin, tmax); } #endregion #region __ray3t__ intersects __polygon3t__ (haaser) /// /// Returns true if the ray and the polygon intersect within the /// supplied parameter interval of the ray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __ray3t__ ray, __polygon3t__ poly, __rtype__ tmin, __rtype__ tmax) => ray.Intersects(poly, tmin, tmax, out _); /// /// Returns true if the ray and the polygon intersect within the /// supplied parameter interval of the ray. /// t holds the correspoinding paramter. /// public static bool Intersects(this __ray3t__ ray, __polygon3t__ poly, __rtype__ tmin, __rtype__ tmax, out __rtype__ t) { var tris = poly.ComputeTriangulationOfConcavePolygon(__eminus5__); var count = tris.Length; for (var i = 0; i < count; i += 3) { if (ray.IntersectsTriangle(poly[tris[i + 0]], poly[tris[i + 1]], poly[tris[i + 2]], tmin, tmax, out t)) { return true; } } t = __rtype__.NaN; return false; } /// /// Returns true if the ray and the polygon, which is given by vertices, intersect within the /// supplied parameter interval of the ray. /// (The Method triangulates the polygon) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsPolygon(this __ray3t__ ray, __v3t__[] vertices, __rtype__ tmin, __rtype__ tmax) => ray.Intersects(new __polygon3t__(vertices), tmin, tmax); /// /// Returns true if the ray and the polygon, which is given by vertices and triangulation, intersect within the /// supplied parameter interval of the ray. /// public static bool IntersectsPolygon( this __ray3t__ ray, __v3t__[] vertices, int[] triangulation, __rtype__ tmin, __rtype__ tmax ) { for (var i = 0; i < triangulation.Length; i += 3) { if (ray.IntersectsTriangle(vertices[triangulation[i + 0]], vertices[triangulation[i + 1]], vertices[triangulation[i + 2]], tmin, tmax)) return true; } return false; } /// /// Returns true if the ray and the polygon, which is given by vertices and triangulation, intersect within the /// supplied parameter interval of the ray. /// public static bool Intersects( this __ray3t__ ray, __polygon3t__ polygon, int[] triangulation, __rtype__ tmin, __rtype__ tmax ) { for (var i = 0; i < triangulation.Length; i += 3) { if (ray.IntersectsTriangle(polygon[triangulation[i + 0]], polygon[triangulation[i + 1]], polygon[triangulation[i + 2]], tmin, tmax)) return true; } return false; } #endregion #region __ray3t__ intersects __sphere3t__ /// /// Returns true if the ray and the triangle intersect. If you need /// information about the hit point see the __ray3t__.Hits method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __ray3t__ ray, __sphere3t__ sphere) => ray.Intersects(sphere, __rtype__.MinValue, __rtype__.MaxValue); /// /// Returns true if the ray and the triangle intersect within the /// supplied parameter interval of the ray. If you need information /// about the hit point see the __ray3t__.Hits method. /// public static bool Intersects(this __ray3t__ ray, __sphere3t__ sphere, __rtype__ tmin, __rtype__ tmax) { // calculate closest point var t = ray.Direction.Dot(sphere.Center - ray.Origin) / ray.Direction.LengthSquared; if (t < 0) t = 0; if (t < tmin) t = tmin; if (t > tmax) t = tmax; __v3t__ p = ray.Origin + t * ray.Direction; // distance to sphere? var d = (p - sphere.Center).LengthSquared; if (d <= sphere.RadiusSquared) return true; return false; } #endregion #region __sphere3t__ intersects __triangle3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __sphere3t__ sphere, __triangle3t__ triangle ) { __v3t__ v = sphere.Center.GetClosestPointOn(triangle) - sphere.Center; return sphere.RadiusSquared >= v.LengthSquared; } #endregion #endregion #region __triangle3t__ intersects __line3t__ (haaser) /// /// Returns true if the triangle and the line intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __triangle3t__ tri, __line3t__ line ) { return tri.IntersectsLine(line.P0, line.P1, out _); } /// /// Returns true if the triangle and the line intersect. /// point holds the intersection point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __triangle3t__ tri, __line3t__ line, out __v3t__ point ) { return tri.IntersectsLine(line.P0, line.P1, out point); } /// /// returns true if the triangle and the line, given by p0 and p1, intersect. /// public static bool IntersectsLine( this __triangle3t__ tri, __v3t__ p0, __v3t__ p1 ) { __v3t__ edge01 = tri.Edge01; __v3t__ edge02 = tri.Edge02; __v3t__ dir = p1 - p0; __v3t__ plane = Vec.Cross(dir, edge02); __rtype__ det = Vec.Dot(edge01, plane); if (det > -__epsdot__ && det < __epsdot__)return false; //ray ~= parallel / Triangle __v3t__ tv = p0 - tri.P0; det = 1 / det; // det is now inverse det __rtype__ u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) { return false; } plane = Vec.Cross(tv, edge01); // plane is now qv __rtype__ v = Vec.Dot(dir, plane) * det; if (v < 0 || u + v > 1) { return false; } __rtype__ temp_t = Vec.Dot(edge02, plane) * det; if (temp_t < 0 || temp_t >= 1) { return false; } return true; } /// /// returns true if the triangle and the line, given by p0 and p1, intersect. /// point holds the intersection point. /// public static bool IntersectsLine( this __triangle3t__ tri, __v3t__ p0, __v3t__ p1, out __v3t__ point ) { __v3t__ edge01 = tri.Edge01; __v3t__ edge02 = tri.Edge02; __v3t__ dir = p1 - p0; __v3t__ plane = Vec.Cross(dir, edge02); __rtype__ det = Vec.Dot(edge01, plane); if (det > -__epsdot__ && det < __epsdot__) { point = __v3t__.NaN; return false; } //ray ~= parallel / Triangle __v3t__ tv = p0 - tri.P0; det = 1 / det; // det is now inverse det __rtype__ u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) { point = __v3t__.NaN; return false; } plane = Vec.Cross(tv, edge01); // plane is now qv __rtype__ v = Vec.Dot(dir, plane) * det; if (v < 0 || u + v > 1) { point = __v3t__.NaN; return false; } __rtype__ temp_t = Vec.Dot(edge02, plane) * det; if (temp_t < 0 || temp_t >= 1) { point = __v3t__.NaN; return false; } point = p0 + temp_t * dir; return true; } #endregion #region __triangle3t__ intersects __ray3t__ (haaser) /// /// Returns true if the triangle and the ray intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __triangle3t__ tri, __ray3t__ ray ) { return tri.Intersects(ray, __rtype__.MinValue, __rtype__.MaxValue, out _); } /// /// Returns true if the triangle and the ray intersect /// within the given parameter interval /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __triangle3t__ tri, __ray3t__ ray, __rtype__ tmin, __rtype__ tmax ) { return tri.Intersects(ray, tmin, tmax, out _); } /// /// Returns true if the triangle and the ray intersect. /// t holds the intersection paramter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __triangle3t__ tri, __ray3t__ ray, out __rtype__ t ) { return tri.Intersects(ray, __rtype__.MinValue, __rtype__.MaxValue, out t); } /// /// Returns true if the triangle and the ray intersect /// within the given parameter interval /// t holds the intersection paramter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __triangle3t__ tri, __ray3t__ ray, __rtype__ tmin, __rtype__ tmax, out __rtype__ t ) { return ray.Intersects(tri, tmin, tmax, out t); } #endregion #region __triangle3t__ intersects __triangle3t__ (haaser) /// /// Returns true if the triangles intersect. /// public static bool Intersects( this __triangle3t__ t0, __triangle3t__ t1 ) { if (t0.IntersectsLine(t1.P0, t1.P1, out _)) return true; if (t0.IntersectsLine(t1.P1, t1.P2, out _)) return true; if (t0.IntersectsLine(t1.P2, t1.P0, out _)) return true; if (t1.IntersectsLine(t0.P0, t0.P1, out _)) return true; if (t1.IntersectsLine(t0.P1, t0.P2, out _)) return true; if (t1.IntersectsLine(t0.P2, t0.P0, out _)) return true; return false; } /// /// Returns true if the triangles intersect. /// line holds the cutting-line of the two triangles. /// public static bool Intersects( this __triangle3t__ t0, __triangle3t__ t1, out __line3t__ line ) { List<__v3t__> points = new List<__v3t__>(); if (t0.IntersectsLine(t1.P0, t1.P1, out __v3t__ temp)) points.Add(temp); if (t0.IntersectsLine(t1.P1, t1.P2, out temp)) points.Add(temp); if (t0.IntersectsLine(t1.P2, t1.P0, out temp)) points.Add(temp); if (points.Count == 2) { line = new __line3t__(points[0], points[1]); return true; } if (t1.IntersectsLine(t0.P0, t0.P1, out temp)) points.Add(temp); if (t1.IntersectsLine(t0.P1, t0.P2, out temp)) points.Add(temp); if (t1.IntersectsLine(t0.P2, t0.P0, out temp)) points.Add(temp); if (points.Count == 2) { line = new __line3t__(points[0], points[1]); return true; } line = new __line3t__(__v3t__.NaN, __v3t__.NaN); return false; } #endregion #region __quad3t__ intersects __line3t__ (haaser) /// /// Returns true if the quad and the line, given by p0 and p1, intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __quad3t__ quad, __line3t__ line) { return quad.IntersectsLine(line.P0, line.P1, out _); } /// /// Returns true if the quad and the line, given by p0 and p1, intersect. /// point holds the intersection point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __quad3t__ quad, __line3t__ line, out __v3t__ point) { return quad.IntersectsLine(line.P0, line.P1, out point); } /// /// Returns true if the quad and the line, given by p0 and p1, intersect. /// public static bool IntersectsLine( this __quad3t__ quad, __v3t__ p0, __v3t__ p1) { __ray3t__ ray = new __ray3t__(p0, p1 - p0); if (quad.Intersects(ray, 0, 1, out _)) { return true; } else { return false; } } /// /// Returns true if the quad and the line, given by p0 and p1, intersect. /// point holds the intersection point. /// public static bool IntersectsLine( this __quad3t__ quad, __v3t__ p0, __v3t__ p1, out __v3t__ point) { __ray3t__ ray = new __ray3t__(p0, p1 - p0); if (quad.Intersects(ray, 0, 1, out __rtype__ t)) { point = ray.GetPointOnRay(t); return true; } else { point = __v3t__.NaN; return false; } } #endregion #region __quad3t__ intersects __ray3t__ (haaser) /// /// Returns true if the quad and the ray intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __quad3t__ quad, __ray3t__ ray ) { return quad.Intersects(ray, __rtype__.MinValue, __rtype__.MaxValue, out _); } /// /// Returns true if the quad and the ray intersect. /// t holds the intersection parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __quad3t__ quad, __ray3t__ ray, out __rtype__ t ) { return quad.Intersects(ray, __rtype__.MinValue, __rtype__.MaxValue, out t); } /// /// Returns true if the quad and the ray intersect /// within the given paramter range /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __quad3t__ quad, __ray3t__ ray, __rtype__ tmin, __rtype__ tmax ) { return quad.Intersects(ray, tmin, tmax, out _); } /// /// Returns true if the quad and the ray intersect /// within the given paramter range /// t holds the intersection parameter. /// public static bool Intersects( this __quad3t__ quad, __ray3t__ ray, __rtype__ tmin, __rtype__ tmax, out __rtype__ t ) { __v3t__ edge02 = quad.P2 - quad.P0; if (ray.IntersectsTrianglePointAndEdges(quad.P0, quad.Edge01, edge02, tmin, tmax, out t)) return true; if (ray.IntersectsTrianglePointAndEdges(quad.P0, edge02, quad.Edge03, tmin, tmax, out t)) return true; t = __rtype__.NaN; return false; } #endregion #region __quad3t__ intersects __triangle3t__ (haaser) /// /// Returns true if the quad and the triangle intersect. /// public static bool Intersects( this __quad3t__ quad, __triangle3t__ tri ) { if (quad.IntersectsLine(tri.P0, tri.P1)) return true; if (quad.IntersectsLine(tri.P1, tri.P2)) return true; if (quad.IntersectsLine(tri.P2, tri.P0)) return true; if (tri.IntersectsLine(quad.P0, quad.P1)) return true; if (tri.IntersectsLine(quad.P1, quad.P2)) return true; if (tri.IntersectsLine(quad.P2, quad.P3)) return true; if (tri.IntersectsLine(quad.P3, quad.P0)) return true; return false; } /// /// Returns true if the quad and the triangle, given by p0/p1/p1, intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsTriangle( this __quad3t__ quad, __v3t__ p0, __v3t__ p1, __v3t__ p2 ) { __triangle3t__ tri = new __triangle3t__(p0, p1, p2); return quad.Intersects(tri); } #endregion #region __quad3t__ intersects __quad3t__ (haaser) /// /// Returns true if the given quads intersect. /// public static bool Intersects( this __quad3t__ q0, __quad3t__ q1 ) { if (q0.IntersectsTriangle(q1.P0, q1.P1, q1.P2)) return true; if (q0.IntersectsTriangle(q1.P2, q1.P3, q1.P0)) return true; if (q1.IntersectsTriangle(q0.P0, q0.P1, q0.P2)) return true; if (q1.IntersectsTriangle(q0.P2, q0.P3, q0.P0)) return true; return false; } #endregion #region __plane3t__ intersects __line3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __plane3t__ plane, __line3t__ line) { return plane.IntersectsLine(line.P0, line.P1, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __plane3t__ plane, __line3t__ line, __rtype__ absoluteEpsilon) { return plane.IntersectsLine(line.P0, line.P1, absoluteEpsilon); } public static bool IntersectsLine(this __plane3t__ plane, __v3t__ p0, __v3t__ p1, __rtype__ absoluteEpsilon) { __rtype__ h0 = plane.Height(p0); int s0 = (h0 > absoluteEpsilon ? 1 :(h0 < -absoluteEpsilon ? -1 : 0)); if (s0 == 0) return true; __rtype__ h1 = plane.Height(p1); int s1 = (h1 > absoluteEpsilon ? 1 : (h1 < -absoluteEpsilon ? -1 : 0)); if (s1 == 0) return true; if (s0 == s1) return false; else return true; } public static bool IntersectsLine(this __plane3t__ plane, __v3t__ p0, __v3t__ p1, __rtype__ absoluteEpsilon, out __v3t__ point) { // == d // + t0* == d //t0 == (d - ) / ; __v3t__ dir = p1 - p0; __rtype__ ld = dir.Length; dir /= ld; __rtype__ nDotd = plane.Normal.Dot(dir); if (!Fun.IsTiny(nDotd)) { __rtype__ t0 = (plane.Distance - plane.Normal.Dot(p0)) / nDotd; if (t0 >= -absoluteEpsilon && t0 <= ld + absoluteEpsilon) { point = p0 + dir * t0; return true; } else { point = __v3t__.NaN; return false; } } else { point = __v3t__.NaN; return false; } } #endregion #region __plane3t__ intersects __ray3t__ /// /// Returns true if the __ray3t__ and the __plane3t__ intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __ray3t__ ray, __plane3t__ plane) => !plane.Normal.IsOrthogonalTo(ray.Direction); /// /// Returns true if the ray and the plane intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __ray3t__ ray, __plane3t__ plane, out __rtype__ t ) { __rtype__ dot = Vec.Dot(ray.Direction, plane.Normal); if (Fun.IsTiny(dot)) { t = __rtype__.PositiveInfinity; return false; } t = -plane.Height(ray.Origin) / dot; return true; } /// /// Returns the intersection point with the given plane, or __v3t__.PositiveInfinity if ray is parallel to plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ Intersect( this __ray3t__ ray, __plane3t__ plane ) { __rtype__ dot = Vec.Dot(ray.Direction, plane.Normal); if (Fun.IsTiny(dot)) return __v3t__.PositiveInfinity; return ray.GetPointOnRay(-plane.Height(ray.Origin) / dot); } /// /// Returns true if the ray and the plane intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __ray3t__ ray, __plane3t__ plane, out __rtype__ t, out __v3t__ p ) { bool result = Intersects(ray, plane, out t); p = ray.Origin + t * ray.Direction; return result; } #endregion #region __plane3t__ intersects __plane3t__ public static bool Intersects(this __plane3t__ p0, __plane3t__ p1) { bool parallel = p0.Normal.IsParallelTo(p1.Normal); if (parallel) return Fun.IsTiny(p0.Distance - p1.Distance); else return true; } public static bool Intersects(this __plane3t__ p0, __plane3t__ p1, out __ray3t__ ray) { __v3t__ dir = p0.Normal.Cross(p1.Normal); __rtype__ len = dir.Length; if (Fun.IsTiny(len)) { if (Fun.IsTiny(p0.Distance - p1.Distance)) { ray = new __ray3t__(p0.Normal * p0.Distance, __v3t__.Zero); return true; } else { ray = __ray3t__.Invalid; return false; } } dir *= 1 / len; var alu = new __rtype__[,] { { p0.Normal.X, p0.Normal.Y, p0.Normal.Z }, { p1.Normal.X, p1.Normal.Y, p1.Normal.Z }, { dir.X, dir.Y, dir.Z } }; int[] p = alu.LuFactorize(); var b = new __rtype__[] { p0.Distance, p1.Distance, 0 }; var x = alu.LuSolve(p, b); ray = new __ray3t__(new __v3t__(x), dir); return true; } #endregion #region __plane3t__ intersects __plane3t__ intersects __plane3t__ public static bool Intersects(this __plane3t__ p0, __plane3t__ p1, __plane3t__ p2, out __v3t__ point) { var alu = new __rtype__[,] { { p0.Normal.X, p0.Normal.Y, p0.Normal.Z }, { p1.Normal.X, p1.Normal.Y, p1.Normal.Z }, { p2.Normal.X, p2.Normal.Y, p2.Normal.Z } }; var p = new int[3]; if (!alu.LuFactorize(p)) { point = __v3t__.NaN; return false; } var b = new __rtype__[] { p0.Distance, p1.Distance, p2.Distance }; var x = alu.LuSolve(p, b); point = new __v3t__(x); return true; } #endregion #region __plane3t__ intersects __triangle3t__ /// /// Returns whether the given plane and triangle intersect. /// public static bool Intersects( this __plane3t__ plane, __triangle3t__ triangle ) { int sign = plane.Sign(triangle.P0); if (sign == 0) return true; if (sign != plane.Sign(triangle.P1)) return true; if (sign != plane.Sign(triangle.P2)) return true; return false; } #endregion #region __plane3t__ intersects __sphere3t__ /// /// Returns whether the given sphere and plane intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __plane3t__ plane, __sphere3t__ sphere ) { return sphere.Radius >= plane.Height(sphere.Center).Abs(); } #endregion #region __plane3t__ intersects __polygon3t__ /// /// returns true if the __plane3t__ and the __polygon3t__ intersect /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __plane3t__ plane, __polygon3t__ poly ) { return plane.Intersects(poly, Constant<__rtype__>.PositiveTinyValue); } /// /// returns true if the __plane3t__ and the polygon, intersect /// within a tolerance of absoluteEpsilon /// public static bool Intersects( this __plane3t__ plane, __polygon3t__ polygon, __rtype__ absoluteEpsilon ) { __rtype__ height = plane.Height(polygon[0]); int sign0 = height > -absoluteEpsilon ? (height < absoluteEpsilon ? 0 : 1) : -1; if (sign0 == 0) return true; int pc = polygon.PointCount; for (int i = 1; i < pc; i++) { height = plane.Height(polygon[i]); int sign = height > -absoluteEpsilon ? (height < absoluteEpsilon ? 0 : 1) : -1; if (sign != sign0) return true; } return false; } /// /// returns true if the __plane3t__ and the __polygon3t__ intersect. /// line holds the intersection line /// ATTENTION: works only with non-concave polygons! /// public static bool IntersectsConvex( this __plane3t__ plane, __polygon3t__ poly, out __line3t__ line ) { return plane.IntersectsConvex(poly, Constant<__rtype__>.PositiveTinyValue, out line); } /// /// Returns true if the __plane3t__ and the polygon, given by points, intersect /// within a tolerance of absoluteEpsilon. /// Line holds the intersection line. /// ATTENTION: works only with non-concave polygons! /// public static bool IntersectsConvex( this __plane3t__ plane, __polygon3t__ polygon, __rtype__ absoluteEpsilon, out __line3t__ line ) { int count = polygon.PointCount; int[] signs = new int[count]; int pc = 0, nc = 0, zc = 0; for (int pi = 0; pi < count; pi++) { __rtype__ h = plane.Height(polygon[pi]); if (h < -absoluteEpsilon) { nc++; signs[pi] = -1; continue; } if (h > absoluteEpsilon) { pc++; signs[pi] = 1; continue; } zc++; signs[pi] = 0; } if (zc == count) { line = new __line3t__(polygon[0], polygon[0]); return false; } else if (pc == 0 && zc == 0) { line = new __line3t__(__v3t__.NaN, __v3t__.NaN); return false; } else if (nc == 0 && zc == 0) { line = new __line3t__(__v3t__.NaN, __v3t__.NaN); return false; } else { int pointcount = 0; __v3t__[] linePoints = new __v3t__[2]; for (int i = 0; i < count; i++) { int u = (i + 1) % count; if (signs[i] != signs[u] || signs[i] == 0 || signs[u] == 0) { if (plane.IntersectsLine(polygon[i], polygon[u], absoluteEpsilon, out __v3t__ point)) { linePoints[pointcount++] = point; //If Endpoint is on Plane => Next startpoint is on plane => same intersection point // => skip all following lines which start within absoluteEpsilon (whic have a zero sign) while (signs[(i + 1) % count] == 0) i++; } } if (pointcount == 2) { // line = new __line3t__(linePoints[0], linePoints[1]); return true; } } line = new __line3t__(__v3t__.NaN, __v3t__.NaN); return false; } } #endregion #region __plane3t__ intersects __cylinder3t__ /// /// Returns whether the given sphere and cylinder intersect. /// public static bool Intersects(this __plane3t__ plane, __cylinder3t__ cylinder) { if (plane.IsParallelToAxis(cylinder)) { var distance = cylinder.P0.GetMinimalDistanceTo(plane); return distance < cylinder.Radius; } return true; } /// /// Tests if the given plane is parallel to the cylinder axis (i.e. the plane's normal is orthogonal to the axis). /// The plane will intersect the cylinder in two rays or in one tangent line. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelToAxis(this __plane3t__ plane, __cylinder3t__ cylinder) => plane.Normal.IsOrthogonalTo(cylinder.Axis.Direction.Normalized); /// /// Tests if the given plane is orthogonal to the cylinder axis (i.e. the plane's normal is parallel to the axis). /// The plane will intersect the cylinder in a circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalToAxis(this __plane3t__ plane, __cylinder3t__ cylinder) => plane.Normal.IsParallelTo(cylinder.Axis.Direction.Normalized); /// /// Returns true if the given plane and cylinder intersect in an ellipse. /// This is only true if the plane is neither orthogonal nor parallel to the cylinder axis. Otherwise the intersection methods returning a circle or rays have to be used. /// /// /// The cylinder is assumed to have infinite extent along its axis. /// public static bool Intersects(this __plane3t__ plane, __cylinder3t__ cylinder, out __ellipse3t__ ellipse) { if (plane.IsParallelToAxis(cylinder) || plane.IsOrthogonalToAxis(cylinder)) { ellipse = __ellipse3t__.Zero; return false; } var dir = cylinder.Axis.Direction.Normalized; cylinder.Axis.__ray3t__.Intersects(plane, out _, out __v3t__ center); var cosTheta = dir.Dot(plane.Normal); var eNormal = plane.Normal; var eCenter = center; var eMajor = (dir - cosTheta * eNormal).Normalized; var eMinor = (eNormal.Cross(eMajor)).Normalized; eMajor = eNormal.Cross(eMinor).Normalized; //to be sure - if ellipse is nearly a circle eMajor = eMajor * cylinder.Radius / cosTheta.Abs(); eMinor *= cylinder.Radius; ellipse = new __ellipse3t__(eCenter, eNormal, eMajor, eMinor); return true; } /// /// Returns true if the given plane and cylinder intersect in a circle. /// This is only true if the plane is orthogonal to the cylinder axis. Otherwise the intersection methods returning an ellipse or rays have to be used. /// /// /// The cylinder is assumed to have infinite extent along its axis. /// public static bool Intersects(this __plane3t__ plane, __cylinder3t__ cylinder, out __circle3t__ circle) { if (plane.IsOrthogonalToAxis(cylinder)) { circle = cylinder.GetCircle(cylinder.GetHeight(plane.Point)); return true; } circle = __circle3t__.Zero; return false; } /// /// Returns true if the given plane and cylinder intersect in one or two rays. /// This is only true if the plane is parallel to the cylinder axis. Otherwise the intersection methods returning an ellipse or a circle have to be used. /// /// /// The cylinder is assumed to have infinite extent along its axis. /// Output of intersection rays. The array contains two rays (intersection), one ray (plane is tangent to cylinder) or no ray (no intersection). public static bool Intersects(this __plane3t__ plane, __cylinder3t__ cylinder, out __ray3t__[] rays) { if (plane.IsParallelToAxis(cylinder)) { var distance = cylinder.P0.GetMinimalDistanceTo(plane); var center = cylinder.P0 - distance * plane.Normal; var axis = cylinder.Axis.Direction.Normalized; if (distance == cylinder.Radius) //one tangent line { rays = new[] { new __ray3t__(center, axis) }; return true; } else //two intersection lines { var offset = axis.Cross(plane.Normal); var extent = (cylinder.Radius.Square() - distance.Square()).Sqrt(); rays = new[] { new __ray3t__(center - extent * offset, axis), new __ray3t__(center + extent * offset, axis) }; return true; } } rays = Array.Empty<__ray3t__>(); return false; } #endregion #region __sphere3t__ intersects __sphere3t__ (sm) /// /// Returns true if the spheres intersect, or one contains the other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __sphere3t__ s0, __sphere3t__ s1) => (s0.Center - s1.Center).LengthSquared <= (s0.Radius + s1.Radius).Square(); #endregion #region __box3t__ intersects __line3t__ /// /// Returns true if the box and the line intersect. /// public static bool Intersects(this __box3t__ box, __line3t__ line) { var out0 = box.OutsideFlags(line.P0); if (out0 == 0) return true; var out1 = box.OutsideFlags(line.P1); if (out1 == 0) return true; return box.IntersectsLine(line.P0, line.P1, out0, out1); } /// /// Returns true if the box and the line intersect. /// public static bool IntersectsLine( this __box3t__ box, __v3t__ p0, __v3t__ p1) { var out0 = box.OutsideFlags(p0); if (out0 == 0) return true; var out1 = box.OutsideFlags(p1); if (out1 == 0) return true; return box.IntersectsLine(p0, p1, out0, out1); } /// /// Returns true if the box and the line intersect. The outside flags /// of the end points of the line with respect to the box have to be /// supplied, and have to be already individually tested against /// intersection with the box. /// public static bool IntersectsLine( this __box3t__ box, __v3t__ p0, __v3t__ p1, Box.Flags out0, Box.Flags out1) { if ((out0 & out1) != 0) return false; __v3t__ min = box.Min; __v3t__ max = box.Max; var bf = out0 | out1; if ((bf & Box.Flags.X) != 0) { __rtype__ dx = p1.X - p0.X; if ((bf & Box.Flags.MinX) != 0) { if (dx == 0 && p0.X < min.X) return false; __rtype__ t = (min.X - p0.X) / dx; __v3t__ p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MinX) == 0) return true; } if ((bf & Box.Flags.MaxX) != 0) { if (dx == 0 && p0.X > max.X) return false; __rtype__ t = (max.X - p0.X) / dx; __v3t__ p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MaxX) == 0) return true; } } if ((bf & Box.Flags.Y) != 0) { __rtype__ dy = p1.Y - p0.Y; if ((bf & Box.Flags.MinY) != 0) { if (dy == 0 && p0.Y < min.Y) return false; __rtype__ t = (min.Y - p0.Y) / dy; __v3t__ p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MinY) == 0) return true; } if ((bf & Box.Flags.MaxY) != 0) { if (dy == 0 && p0.Y > max.Y) return false; __rtype__ t = (max.Y - p0.Y) / dy; __v3t__ p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MaxY) == 0) return true; } } if ((bf & Box.Flags.Z) != 0) { __rtype__ dz = p1.Z - p0.Z; if ((bf & Box.Flags.MinZ) != 0) { if (dz == 0 && p0.Z < min.Z) return false; __rtype__ t = (min.Z - p0.Z) / dz; __v3t__ p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MinZ) == 0) return true; } if ((bf & Box.Flags.MaxZ) != 0) { if (dz == 0 && p0.Z > max.Z) return false; __rtype__ t = (max.Z - p0.Z) / dz; __v3t__ p = p0 + t * (p1 - p0); if ((box.OutsideFlags(p) & ~Box.Flags.MaxZ) == 0) return true; } } return false; } #endregion #region __box3t__ intersects __ray3t__ (haaser) public static bool Intersects(this __box3t__ box, __ray3t__ ray, out __rtype__ t) { Box.Flags out0 = box.OutsideFlags(ray.Origin); if (out0 == 0) { t = 0; return true; } __box3t__ largeBox = box.EnlargedByRelativeEps(__eminus5__); __rtype__ tmin = __rtype__.PositiveInfinity; __rtype__ ttemp; if ((out0 & Box.Flags.X) != 0) { if (!Fun.IsTiny(ray.Direction.X)) { if ((out0 & Box.Flags.MinX) != 0) { ttemp = (box.Min.X - ray.Origin.X) / ray.Direction.X; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } else if ((out0 & Box.Flags.MaxX) != 0) { ttemp = (box.Max.X - ray.Origin.X) / ray.Direction.X; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } } } if ((out0 & Box.Flags.Y) != 0) { if (!Fun.IsTiny(ray.Direction.Y)) { if ((out0 & Box.Flags.MinY) != 0) { ttemp = (box.Min.Y - ray.Origin.Y) / ray.Direction.Y; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } else if ((out0 & Box.Flags.MaxY) != 0) { ttemp = (box.Max.Y - ray.Origin.Y) / ray.Direction.Y; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } } } if ((out0 & Box.Flags.Z) != 0) { if (!Fun.IsTiny(ray.Direction.Z)) { if ((out0 & Box.Flags.MinZ) != 0) { ttemp = (box.Min.Z - ray.Origin.Z) / ray.Direction.Z; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } else if ((out0 & Box.Flags.MaxZ) != 0) { ttemp = (box.Max.Z - ray.Origin.Z) / ray.Direction.Z; if (ttemp.Abs() < tmin.Abs() && largeBox.Contains(ray.Origin + ttemp * ray.Direction)) tmin = ttemp; } } } if (tmin < __rtype__.PositiveInfinity) { t = tmin; return true; } t = __rtype__.NaN; return false; } #endregion #region __box3t__ intersects __plane3t__ /// /// Returns true if the box and the plane intersect or touch with a /// supplied epsilon tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __box3t__ box, __plane3t__ plane, __rtype__ eps) { var signs = box.GetIntersectionSignsWithPlane(plane, eps); return signs != Signs.Negative && signs != Signs.Positive; } /// /// Classify the position of all the eight vertices of a box with /// respect to a supplied plane. /// public static Signs GetIntersectionSignsWithPlane( this __box3t__ box, __plane3t__ plane, __rtype__ eps) { var normal = plane.Normal; var distance = plane.Distance; __rtype__ npMinX = normal.X * box.Min.X; __rtype__ npMaxX = normal.X * box.Max.X; __rtype__ npMinY = normal.Y * box.Min.Y; __rtype__ npMaxY = normal.Y * box.Max.Y; __rtype__ npMinZ = normal.Z * box.Min.Z; __rtype__ npMaxZ = normal.Z * box.Max.Z; __rtype__ hMinZ = npMinZ - distance; __rtype__ hMaxZ = npMaxZ - distance; __rtype__ hMinYMinZ = npMinY + hMinZ; __rtype__ hMaxYMinZ = npMaxY + hMinZ; __rtype__ hMinYMaxZ = npMinY + hMaxZ; __rtype__ hMaxYMaxZ = npMaxY + hMaxZ; return (npMinX + hMinYMinZ).GetSigns(eps) | (npMaxX + hMinYMinZ).GetSigns(eps) | (npMinX + hMaxYMinZ).GetSigns(eps) | (npMaxX + hMaxYMinZ).GetSigns(eps) | (npMinX + hMinYMaxZ).GetSigns(eps) | (npMaxX + hMinYMaxZ).GetSigns(eps) | (npMinX + hMaxYMaxZ).GetSigns(eps) | (npMaxX + hMaxYMaxZ).GetSigns(eps); } /// /// Returns true if the box intersects the supplied plane. The /// bounding boxes of the resulting parts are returned in the out /// parameters. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Signs GetIntersectionSigns( this __box3t__ box, __plane3t__ plane, __rtype__ eps, out __box3t__ negBox, out __box3t__ zeroBox, out __box3t__ posBox) { return box.GetIntersectionSigns(plane.Normal, plane.Distance, eps, out negBox, out zeroBox, out posBox); } /// /// Returns true if the box intersects the supplied plane. The /// bounding boxes of the resulting parts are returned in the out /// parameters. /// public static Signs GetIntersectionSigns( this __box3t__ box, __v3t__ normal, __rtype__ distance, __rtype__ eps, out __box3t__ negBox, out __box3t__ zeroBox, out __box3t__ posBox) { __rtype__ npMinX = normal.X * box.Min.X; __rtype__ npMaxX = normal.X * box.Max.X; __rtype__ npMinY = normal.Y * box.Min.Y; __rtype__ npMaxY = normal.Y * box.Max.Y; __rtype__ npMinZ = normal.Z * box.Min.Z; __rtype__ npMaxZ = normal.Z * box.Max.Z; var ha = new __rtype__[8]; __rtype__ hMinZ = npMinZ - distance; __rtype__ hMaxZ = npMaxZ - distance; __rtype__ hMinYMinZ = npMinY + hMinZ; ha[0] = npMinX + hMinYMinZ; ha[1] = npMaxX + hMinYMinZ; __rtype__ hMaxYMinZ = npMaxY + hMinZ; ha[2] = npMinX + hMaxYMinZ; ha[3] = npMaxX + hMaxYMinZ; __rtype__ hMinYMaxZ = npMinY + hMaxZ; ha[4] = npMinX + hMinYMaxZ; ha[5] = npMaxX + hMinYMaxZ; __rtype__ hMaxYMaxZ = npMaxY + hMaxZ; ha[6] = npMinX + hMaxYMaxZ; ha[7] = npMaxX + hMaxYMaxZ; Signs all = Signs.None; var sa = new Signs[8]; for (int i = 0; i < 8; i++) { sa[i] = ha[i].GetSigns(eps); all |= sa[i]; } negBox = __box3t__.Invalid; zeroBox = __box3t__.Invalid; posBox = __box3t__.Invalid; if (all == Signs.Zero) { zeroBox = box; return all; } if (all == Signs.Positive) { posBox = box; return all; } if (all == Signs.Negative) { negBox = box; return all; } var pa = box.ComputeCorners(); for (int i = 0; i < 8; i++) { if (sa[i] == Signs.Negative) negBox.ExtendBy(pa[i]); else if (sa[i] == Signs.Positive) posBox.ExtendBy(pa[i]); else { negBox.ExtendBy(pa[i]); zeroBox.ExtendBy(pa[i]); posBox.ExtendBy(pa[i]); } } if (all == Signs.NonPositive) { posBox = __box3t__.Invalid; return all; } if (all == Signs.NonNegative) { negBox = __box3t__.Invalid; return all; } for (int ei = 0; ei < 12; ei++) { int i0 = c_cubeEdgeVertex0[ei], i1 = c_cubeEdgeVertex1[ei]; if ((sa[i0] == Signs.Negative && sa[i1] == Signs.Positive) || (sa[i0] == Signs.Positive && sa[i1] == Signs.Negative)) { __rtype__ h0 = ha[i0]; __rtype__ t = h0 / (h0 - ha[i1]); __v3t__ p0 = pa[i0]; __v3t__ sp = p0 + t * (pa[i1] - p0); negBox.ExtendBy(sp); zeroBox.ExtendBy(sp); posBox.ExtendBy(sp); } } return all; } #endregion #region __box3t__ intersects __sphere3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __box3t__ box, __sphere3t__ sphere ) { __v3t__ v = sphere.Center.GetClosestPointOn(box) - sphere.Center; return sphere.RadiusSquared >= v.LengthSquared; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __box3t__ box, __cylinder3t__ cylinder ) { return box.Intersects(cylinder.BoundingBox3__tc__); //throw new NotImplementedException(); } #endregion #region __box3t__ intersects __triangle3t__ /// /// Returns true if the box and the triangle intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __box3t__ box, __triangle3t__ triangle ) { return box.IntersectsTriangle(triangle.P0, triangle.P1, triangle.P2); } /// /// Returns true if the box and the triangle intersect. /// public static bool IntersectsTriangle( this __box3t__ box, __v3t__ p0, __v3t__ p1, __v3t__ p2 ) { /* --------------------------------------------------------------- If one of the points of the triangle is inside the box, it intersects, of course. --------------------------------------------------------------- */ var out0 = box.OutsideFlags(p0); if (out0 == 0) return true; var out1 = box.OutsideFlags(p1); if (out1 == 0) return true; var out2 = box.OutsideFlags(p2); if (out2 == 0) return true; return box.IntersectsTriangle(p0, p1, p2, out0, out1, out2); } /// /// Returns true if the box and the triangle intersect. The outside /// flags of the triangle vertices with respect to the box have to be /// supplied, and already be individually tested for intersection with /// the box. /// public static bool IntersectsTriangle( this __box3t__ box, __v3t__ p0, __v3t__ p1, __v3t__ p2, Box.Flags out0, Box.Flags out1, Box.Flags out2 ) { /* --------------------------------------------------------------- If all of the points of the triangle are on the same side outside the box, no intersection is possible. --------------------------------------------------------------- */ if ((out0 & out1 & out2) != 0) return false; /* --------------------------------------------------------------- If two points of the triangle are not on the same side outside the box, it is possible that the edge between them intersects the box. The outside flags we computed are also used to optimize the intersection routine with the edge. --------------------------------------------------------------- */ if (box.IntersectsLine(p0, p1, out0, out1)) return true; if (box.IntersectsLine(p1, p2, out1, out2)) return true; if (box.IntersectsLine(p2, p0, out2, out0)) return true; /* --------------------------------------------------------------- The only case left: the edges of the triangle go outside around the box. Intersect the four space diagonals of the box with the triangle to test for intersection. --------------------------------------------------------------- */ __ray3t__ ray = new __ray3t__(box.Min, box.Size); if (ray.IntersectsTriangle(p0, p1, p2, 0, 1)) return true; ray.Origin.X = box.Max.X; ray.Direction.X = -ray.Direction.X; if (ray.IntersectsTriangle(p0, p1, p2, 0, 1)) return true; ray.Direction.X = -ray.Direction.X; ray.Origin.X = box.Min.X; ray.Origin.Y = box.Max.Y; ray.Direction.Y = -ray.Direction.Y; if (ray.IntersectsTriangle(p0, p1, p2, 0, 1)) return true; ray.Direction.Y = -ray.Direction.Y; ray.Origin.Y = box.Min.Y; ray.Origin.Z = box.Max.Z; ray.Direction.Z = -ray.Direction.Z; if (ray.IntersectsTriangle(p0, p1, p2, 0, 1)) return true; return false; } #endregion #region __box3t__ intersects __quad3t__ (haaser) public static bool Intersects( this __box3t__ box, __quad3t__ quad ) { Box.Flags out0 = box.OutsideFlags(quad.P0); if (out0 == 0) return true; Box.Flags out1 = box.OutsideFlags(quad.P1); if (out1 == 0) return true; Box.Flags out2 = box.OutsideFlags(quad.P2); if (out2 == 0) return true; Box.Flags out3 = box.OutsideFlags(quad.P3); if (out3 == 0) return true; return box.IntersectsQuad(quad.P0, quad.P1, quad.P2, quad.P3, out0, out1, out2, out3); } public static bool IntersectsQuad( this __box3t__ box, __v3t__ p0, __v3t__ p1, __v3t__ p2, __v3t__ p3 ) { var out0 = box.OutsideFlags(p0); if (out0 == 0) return true; var out1 = box.OutsideFlags(p1); if (out1 == 0) return true; var out2 = box.OutsideFlags(p2); if (out2 == 0) return true; var out3 = box.OutsideFlags(p3); if (out3 == 0) return true; return box.IntersectsQuad(p0, p1, p2, p3, out0, out1, out2, out3); } public static bool IntersectsQuad( this __box3t__ box, __v3t__ p0, __v3t__ p1, __v3t__ p2, __v3t__ p3, Box.Flags out0, Box.Flags out1, Box.Flags out2, Box.Flags out3 ) { /* --------------------------------------------------------------- If all of the points of the quad are on the same side outside the box, no intersection is possible. --------------------------------------------------------------- */ if ((out0 & out1 & out2 & out3) != 0) return false; /* --------------------------------------------------------------- If two points of the quad are not on the same side outside the box, it is possible that the edge between them intersects the box. The outside flags we computed are also used to optimize the intersection routine with the edge. --------------------------------------------------------------- */ if (box.IntersectsLine(p0, p1, out0, out1)) return true; if (box.IntersectsLine(p1, p2, out1, out2)) return true; if (box.IntersectsLine(p2, p3, out2, out3)) return true; if (box.IntersectsLine(p3, p0, out3, out0)) return true; /* --------------------------------------------------------------- The only case left: the edges of the quad go outside around the box. Intersect the four space diagonals of the box with the triangle to test for intersection. --------------------------------------------------------------- */ __ray3t__ ray = new __ray3t__(box.Min, box.Size); if (ray.IntersectsQuad(p0, p1, p2, p3, 0, 1)) return true; ray.Origin.X = box.Max.X; ray.Direction.X = -ray.Direction.X; if (ray.IntersectsQuad(p0, p1, p2, p3, 0, 1)) return true; ray.Direction.X = -ray.Direction.X; ray.Origin.X = box.Min.X; ray.Origin.Y = box.Max.Y; ray.Direction.Y = -ray.Direction.Y; if (ray.IntersectsQuad(p0, p1, p2, p3, 0, 1)) return true; ray.Direction.Y = -ray.Direction.Y; ray.Origin.Y = box.Min.Y; ray.Origin.Z = box.Max.Z; ray.Direction.Z = -ray.Direction.Z; if (ray.IntersectsQuad(p0, p1, p2, p3, 0, 1)) return true; return false; } #endregion #region __box3t__ intersects __polygon3t__ (haaser) public static bool Intersects(this __box3t__ box, __polygon3t__ poly) { int edges = poly.PointCount; Box.Flags[] outside = new Box.Flags[edges]; for (int i = 0; i < edges; i++) { outside[i] = box.OutsideFlags(poly[i]); if (outside[i] == 0) return true; } /* --------------------------------------------------------------- If all of the points of the polygon are on the same side outside the box, no intersection is possible. --------------------------------------------------------------- */ Box.Flags sum = outside[0]; for (int i = 1; i < edges; i++) sum &= outside[i]; if (sum != 0) return false; /* --------------------------------------------------------------- If two points of the polygon are not on the same side outside the box, it is possible that the edge between them intersects the box. The outside flags we computed are also used to optimize the intersection routine with the edge. --------------------------------------------------------------- */ int u; for (int i = 0; i < edges; i++) { u = (i + 1) % edges; if (box.IntersectsLine(poly[i], poly[u], outside[i], outside[u])) return true; } /* --------------------------------------------------------------- The only case left: the edges of the polygon go outside around the box. Intersect the four space diagonals of the box with the triangle to test for intersection. The polygon needs to be triangulated for this check --------------------------------------------------------------- */ int[] tris = poly.ComputeTriangulationOfConcavePolygon(__eminus5__); __ray3t__ ray = new __ray3t__(box.Min, box.Size); if (ray.Intersects(poly, tris, 0, 1)) return true; ray.Origin.X = box.Max.X; ray.Direction.X = -ray.Direction.X; if (ray.Intersects(poly, tris, 0, 1)) return true; ray.Direction.X = -ray.Direction.X; ray.Origin.X = box.Min.X; ray.Origin.Y = box.Max.Y; ray.Direction.Y = -ray.Direction.Y; if (ray.Intersects(poly, tris, 0, 1)) return true; ray.Direction.Y = -ray.Direction.Y; ray.Origin.Y = box.Min.Y; ray.Origin.Z = box.Max.Z; ray.Direction.Z = -ray.Direction.Z; if (ray.Intersects(poly, tris, 0, 1)) return true; return false; } #endregion #region __box3t__ intersects Projection-Trafo (haaser) /// /// returns true if the __box3t__ and the frustum described by the __m44t__ intersect or the frustum contains the __box3t__ /// Assumes DirectX clip-space: /// -w < x < w /// -w < y < w /// 0 < z < w /// public static bool IntersectsFrustum(this __box3t__ box, __m44t__ projection) { //Let's look at the left clip-plane //which corresponds to: //-w < x // # which can easily be transformed to: //0 < x + w // # for a given vector v this means (* is a dot product here) //0 < proj.R0 * v + proj.R3 * v // # or in other words: //0 < (proj.R0 + proj.R3) * v //therefore (proj.R0 + proj.R3) is the plane describing the left clip-plane. //The other planes can be derived in a similar way (only the near plane is a little different) //see http://fgiesen.wordpress.com/2012/08/31/frustum-planes-from-the-projection-matrix/ for a full explanation var r0 = projection.R0; var r1 = projection.R1; var r2 = projection.R2; var r3 = projection.R3; __v4t__ plane; __v3t__ n; //left plane = r3 + r0; n = plane.XYZ; box.GetMinMaxInDirection(n, out __v3t__ min, out __v3t__ max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; //right plane = r3 - r0; n = plane.XYZ; box.GetMinMaxInDirection(n, out min, out max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; //top plane = r3 + r1; n = plane.XYZ; box.GetMinMaxInDirection(n, out min, out max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; //bottom plane = r3 - r1; n = plane.XYZ; box.GetMinMaxInDirection(n, out min, out max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; //near plane = r2; n = plane.XYZ; box.GetMinMaxInDirection(n, out min, out max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; //far plane = r3 - r2; n = plane.XYZ; box.GetMinMaxInDirection(n, out min, out max); if (min.Dot(n) + plane.W < 0 && max.Dot(n) + plane.W < 0) return false; return true; } #endregion #region __hull3t__ intersects __line3t__ /// /// returns true if the __hull3t__ and the __line3t__ intersect or the __hull3t__ contains the __line3t__ /// [__hull3t__-Normals must point outside] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __hull3t__ hull, __line3t__ line ) { if (hull.Contains(line.P0)) return true; if (hull.Contains(line.P1)) return true; return hull.Intersects(line.__ray3t__, 0, 1, out _); } /// /// returns true if the __hull3t__ and the Line between p0 and p1 intersect or the __hull3t__ contains the Line /// [__hull3t__-Normals must point outside] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IntersectsLine( this __hull3t__ hull, __v3t__ p0, __v3t__ p1 ) { return hull.Intersects(new __line3t__(p0, p1)); } #endregion #region __hull3t__ intersects __ray3t__ /// /// returns true if the __hull3t__ and the __ray3t__ intersect /// [__hull3t__-Normals must point outside] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __hull3t__ hull, __ray3t__ ray ) { return hull.Intersects(ray, __rtype__.NegativeInfinity, __rtype__.PositiveInfinity, out _); } /// /// returns true if the __hull3t__ and the __ray3t__ intersect /// the out parameter t holds the ray-parameter where an intersection was found /// [__hull3t__-Normals must point outside] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects( this __hull3t__ hull, __ray3t__ ray, out __rtype__ t ) { return hull.Intersects(ray, __rtype__.NegativeInfinity, __rtype__.PositiveInfinity, out t); } /// /// returns true if the __hull3t__ and the __ray3t__ intersect and the /// ray-parameter for the intersection is between t_min and t_max /// the out parameter t holds the ray-parameter where an intersection was found /// [__hull3t__-Normals must point outside] /// public static bool Intersects( this __hull3t__ hull, __ray3t__ ray, __rtype__ t_min, __rtype__ t_max, out __rtype__ t ) { if (!__rtype__.IsInfinity(t_min) && hull.Contains(ray.GetPointOnRay(t_min))) { t = t_min; return true; } if (!__rtype__.IsInfinity(t_max) && hull.Contains(ray.GetPointOnRay(t_max))) { t = t_max; return true; } var planes = hull.PlaneArray; for (int i = 0; i < planes.Length; i++) { if (!Fun.IsTiny(planes[i].Normal.Dot(ray.Direction)) && ray.Intersects(planes[i], out __rtype__ temp_t) && temp_t >= t_min && temp_t <= t_max) { __v3t__ candidatePoint = ray.GetPointOnRay(temp_t); bool contained = true; for (int u = 0; u < planes.Length; u++) { if (u != i && planes[u].Height(candidatePoint) > Constant<__rtype__>.PositiveTinyValue) { contained = false; break; } } if (contained) { t = temp_t; return true; } } } t = __rtype__.NaN; return false; } #endregion #region __hull3t__ intersects __plane3t__ /// /// returns true if the __hull3t__ and the __plane3t__ intersect /// [__hull3t__-Normals must point outside] /// public static bool Intersects( this __hull3t__ hull, __plane3t__ plane ) { foreach (var p in hull.PlaneArray) { if (!p.Normal.IsParallelTo(plane.Normal) && p.Intersects(plane, out __ray3t__ ray)) { if (hull.Intersects(ray)) return true; } } return false; } #endregion #region __hull3t__ intersects __box3t__ /// /// Returns true if the hull and the box intersect. /// public static bool Intersects( this __hull3t__ hull, __box3t__ box ) { if (box.IsInvalid) return false; bool intersecting = false; foreach (__plane3t__ p in hull.PlaneArray) { box.GetMinMaxInDirection(p.Normal, out __v3t__ min, out __v3t__ max); if (p.Height(min) > 0) return false; // outside if (p.Height(max) >= 0) intersecting = true; } if (intersecting) return true; // intersecting return true; // inside } /// Test hull against intersection of the supplied bounding box. /// Note that this is a conservative test, since in some cases /// around the edges of the hull it may return true although the /// hull does not intersect the box. public static bool Intersects( this Fast__hull3t__ fastHull, __box3t__ box) { var planes = fastHull.Hull.PlaneArray; int count = planes.Length; bool intersecting = false; for (int pi = 0; pi < count; pi++) { int minCornerIndex = fastHull.MinCornerIndexArray[pi]; if (planes[pi].Height(box.Corner(minCornerIndex)) > 0) return false; if (planes[pi].Height(box.Corner(minCornerIndex ^ 7)) >= 0) intersecting = true; } if (intersecting) return true; return true; } #endregion #region __hull3t__ intersects __sphere3t__ /// /// Returns true if the hull and the sphere intersect. /// public static bool Intersects( this __hull3t__ hull, __sphere3t__ sphere ) { if (sphere.IsInvalid) return false; bool intersecting = false; foreach (__plane3t__ p in hull.PlaneArray) { __rtype__ height = p.Height(sphere.Center); if (height > sphere.Radius) return false; // outside if (height.Abs() < sphere.Radius) intersecting = true; } if (intersecting) return true; // intersecting return true; // inside } #endregion #region __plane3t__ intersects __box3t__ /// /// Returns true if the box and the plane intersect or touch with a /// supplied epsilon tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __plane3t__ plane, __rtype__ eps, __box3t__ box) => box.Intersects(plane, eps); #endregion //# } } } ================================================ FILE: src/Aardvark.Base/Geometry/Relations/LinearCombination_auto.cs ================================================ using System.Runtime.CompilerServices; namespace Aardvark.Base { public static class LinearCombination { // AUTO GENERATED CODE - DO NOT CHANGE! #region V3f - V3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsLinearCombinationOf(this V3f x, V3f u, V3f v) { V3f n = u.Cross(v); return n.IsOrthogonalTo(x); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsLinearCombinationOf(this V3f x, V3f u) => x.IsParallelTo(u); public static bool IsLinearCombinationOf(this V3f x, V3f u, V3f v, out float t0, out float t1) { //x == t2*u + t1*v V3f n = u.Cross(v); float[,] mat = new float[3, 3] { {u.X,v.X,n.X}, {u.Y,v.Y,n.Y}, {u.Z,v.Z,n.Z} }; float[] result = new float[3] { x.X, x.Y, x.Z }; int[] perm = mat.LuFactorize(); V3f t = new V3f(mat.LuSolve(perm, result)); if (Fun.IsTiny(t.Z)) { t0 = t.X; t1 = t.Y; return true; } else { t0 = float.NaN; t1 = float.NaN; return false; } //x == } #endregion #region V3d - V3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsLinearCombinationOf(this V3d x, V3d u, V3d v) { V3d n = u.Cross(v); return n.IsOrthogonalTo(x); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsLinearCombinationOf(this V3d x, V3d u) => x.IsParallelTo(u); public static bool IsLinearCombinationOf(this V3d x, V3d u, V3d v, out double t0, out double t1) { //x == t2*u + t1*v V3d n = u.Cross(v); double[,] mat = new double[3, 3] { {u.X,v.X,n.X}, {u.Y,v.Y,n.Y}, {u.Z,v.Z,n.Z} }; double[] result = new double[3] { x.X, x.Y, x.Z }; int[] perm = mat.LuFactorize(); V3d t = new V3d(mat.LuSolve(perm, result)); if (Fun.IsTiny(t.Z)) { t0 = t.X; t1 = t.Y; return true; } else { t0 = double.NaN; t1 = double.NaN; return false; } //x == } #endregion } } ================================================ FILE: src/Aardvark.Base/Geometry/Relations/LinearCombination_template.cs ================================================ using System.Runtime.CompilerServices; namespace Aardvark.Base { public static class LinearCombination { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var tc = isDouble ? "d" : "f"; //# var v2t = "V2" + tc; //# var v3t = "V3" + tc; //# var half = isDouble ? "0.5" : "0.5f"; #region __v3t__ - __v3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsLinearCombinationOf(this __v3t__ x, __v3t__ u, __v3t__ v) { __v3t__ n = u.Cross(v); return n.IsOrthogonalTo(x); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsLinearCombinationOf(this __v3t__ x, __v3t__ u) => x.IsParallelTo(u); public static bool IsLinearCombinationOf(this __v3t__ x, __v3t__ u, __v3t__ v, out __ftype__ t0, out __ftype__ t1) { //x == t2*u + t1*v __v3t__ n = u.Cross(v); __ftype__[,] mat = new __ftype__[3, 3] { {u.X,v.X,n.X}, {u.Y,v.Y,n.Y}, {u.Z,v.Z,n.Z} }; __ftype__[] result = new __ftype__[3] { x.X, x.Y, x.Z }; int[] perm = mat.LuFactorize(); __v3t__ t = new __v3t__(mat.LuSolve(perm, result)); if (Fun.IsTiny(t.Z)) { t0 = t.X; t1 = t.Y; return true; } else { t0 = __ftype__.NaN; t1 = __ftype__.NaN; return false; } //x == } #endregion //# } } } ================================================ FILE: src/Aardvark.Base/Geometry/Relations/Orthogonality_auto.cs ================================================ using System.Runtime.CompilerServices; namespace Aardvark.Base { /// /// Provides various methods determining normalism /// public static class Orthogonality { // 2-Dimensional #region V2f - V2f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this V2f u, V2f v) => Fun.IsTiny(u.Dot(v)); #endregion #region Ray2f - V2f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this Ray2f ray, V2f v) => ray.Direction.IsOrthogonalTo(v); #endregion #region Ray2f - Ray2f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this Ray2f r0, Ray2f r1) => r0.Direction.IsOrthogonalTo(r1.Direction); #endregion // 3-Dimensional #region V3f - V3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this V3f u, V3f v) => Fun.IsTiny(u.Dot(v)); #endregion #region Ray3f - V3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this Ray3f ray, V3f vec) => ray.Direction.IsOrthogonalTo(vec); #endregion #region Ray3f - Ray3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this Ray3f r0, Ray3f r1) => r0.Direction.IsOrthogonalTo(r1.Direction); #endregion #region Plane3f - Plane3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this Plane3f p0, Plane3f p1) => p0.Normal.IsOrthogonalTo(p1.Normal); #endregion #region Ray3f - Plane3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this Ray3f ray, Plane3f plane) => ray.Direction.IsParallelTo(plane.Normal); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNormalTo(this Plane3f plane, Ray3f ray) => ray.Direction.IsParallelTo(plane.Normal); #endregion // 2-Dimensional #region V2d - V2d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this V2d u, V2d v) => Fun.IsTiny(u.Dot(v)); #endregion #region Ray2d - V2d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this Ray2d ray, V2d v) => ray.Direction.IsOrthogonalTo(v); #endregion #region Ray2d - Ray2d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this Ray2d r0, Ray2d r1) => r0.Direction.IsOrthogonalTo(r1.Direction); #endregion // 3-Dimensional #region V3d - V3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this V3d u, V3d v) => Fun.IsTiny(u.Dot(v)); #endregion #region Ray3d - V3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this Ray3d ray, V3d vec) => ray.Direction.IsOrthogonalTo(vec); #endregion #region Ray3d - Ray3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this Ray3d r0, Ray3d r1) => r0.Direction.IsOrthogonalTo(r1.Direction); #endregion #region Plane3d - Plane3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this Plane3d p0, Plane3d p1) => p0.Normal.IsOrthogonalTo(p1.Normal); #endregion #region Ray3d - Plane3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this Ray3d ray, Plane3d plane) => ray.Direction.IsParallelTo(plane.Normal); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNormalTo(this Plane3d plane, Ray3d ray) => ray.Direction.IsParallelTo(plane.Normal); #endregion } } ================================================ FILE: src/Aardvark.Base/Geometry/Relations/Orthogonality_template.cs ================================================ using System.Runtime.CompilerServices; namespace Aardvark.Base { /// /// Provides various methods determining normalism /// public static class Orthogonality { //# foreach (var isDouble in new[] { false, true }) { //# var rtype = isDouble ? "double" : "float"; //# var tc = isDouble ? "d" : "f"; //# var v2t = "V2" + tc; //# var v3t = "V3" + tc; //# var plane3t = "Plane3" + tc; //# var ray2t = "Ray2" + tc; //# var ray3t = "Ray3" + tc; // 2-Dimensional #region __v2t__ - __v2t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this __v2t__ u, __v2t__ v) => Fun.IsTiny(u.Dot(v)); #endregion #region __ray2t__ - __v2t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this __ray2t__ ray, __v2t__ v) => ray.Direction.IsOrthogonalTo(v); #endregion #region __ray2t__ - __ray2t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this __ray2t__ r0, __ray2t__ r1) => r0.Direction.IsOrthogonalTo(r1.Direction); #endregion // 3-Dimensional #region __v3t__ - __v3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this __v3t__ u, __v3t__ v) => Fun.IsTiny(u.Dot(v)); #endregion #region __ray3t__ - __v3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this __ray3t__ ray, __v3t__ vec) => ray.Direction.IsOrthogonalTo(vec); #endregion #region __ray3t__ - __ray3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this __ray3t__ r0, __ray3t__ r1) => r0.Direction.IsOrthogonalTo(r1.Direction); #endregion #region __plane3t__ - __plane3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this __plane3t__ p0, __plane3t__ p1) => p0.Normal.IsOrthogonalTo(p1.Normal); #endregion #region __ray3t__ - __plane3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonalTo(this __ray3t__ ray, __plane3t__ plane) => ray.Direction.IsParallelTo(plane.Normal); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNormalTo(this __plane3t__ plane, __ray3t__ ray) => ray.Direction.IsParallelTo(plane.Normal); #endregion //# } } } ================================================ FILE: src/Aardvark.Base/Geometry/Relations/Parallelism_auto.cs ================================================ using System.Runtime.CompilerServices; namespace Aardvark.Base { /// /// Provides various methods determining parallelism /// public static class Parallelism { // 2-Dimensional #region V2f - V2f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this V2f u, V2f v) => Fun.IsTiny(u.X * v.Y - u.Y * v.X); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this V2f u, V2f v, float epsilon = 1e-4f) { var un = u.Normalized; var vn = v.Normalized; return (un - vn).Length < epsilon || (un + vn).Length < epsilon; } #endregion #region Ray2f - V2f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray2f ray, V2f v) => ray.Direction.IsParallelTo(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray2f ray, V2f v, float epsilon = 1e-4f) => ray.Direction.IsParallelTo(v, epsilon); #endregion #region Ray2f - Ray2f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray2f r0, Ray2f r1) => r0.Direction.IsParallelTo(r1.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray2f r0, Ray2f r1, float epsilon = 1e-4f) => r0.Direction.IsParallelTo(r1.Direction, epsilon); #endregion #region Line2f - Line2f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Line2f l0, Line2f l1) => l0.Direction.IsParallelTo(l1.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Line2f l0, Line2f l1, float epsilon = 1e-4f) => l0.Direction.IsParallelTo(l1.Direction, epsilon); #endregion // 3-Dimensional #region V3f - V3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this V3f u, V3f v) => Fun.IsTiny(u.Cross(v).Norm1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this V3f u, V3f v, float epsilon = 1e-4f) { var un = u.Normalized; var vn = v.Normalized; return (un - vn).Length < epsilon || (un + vn).Length < epsilon; } #endregion #region Ray3f - V3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray3f ray, V3f vec) => ray.Direction.IsParallelTo(vec); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray3f ray, V3f vec, float epsilon = 1e-4f) => ray.Direction.IsParallelTo(vec, epsilon); #endregion #region Ray3f - Ray3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray3f r0, Ray3f r1) => r0.Direction.IsParallelTo(r1.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray3f r0, Ray3f r1, float epsilon = 1e-4f) => r0.Direction.IsParallelTo(r1.Direction, epsilon); #endregion #region Plane3f - Plane3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Plane3f p0, Plane3f p1) => p0.Normal.IsParallelTo(p1.Normal); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Plane3f p0, Plane3f p1, float epsilon = 1e-4f) => p0.Normal.IsParallelTo(p1.Normal, epsilon); #endregion #region Ray3f - Plane3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray3f ray, Plane3f plane) => ray.Direction.IsOrthogonalTo(plane.Normal); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Plane3f plane, Ray3f ray) => ray.Direction.IsOrthogonalTo(plane.Normal); #endregion #region Line3f - Line3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Line3f l0, Line3f l1) => l0.Direction.IsParallelTo(l1.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Line3f l0, Line3f l1, float epsilon = 1e-4f) => l0.Direction.IsParallelTo(l1.Direction, epsilon); #endregion // 2-Dimensional #region V2d - V2d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this V2d u, V2d v) => Fun.IsTiny(u.X * v.Y - u.Y * v.X); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this V2d u, V2d v, double epsilon = 1e-6) { var un = u.Normalized; var vn = v.Normalized; return (un - vn).Length < epsilon || (un + vn).Length < epsilon; } #endregion #region Ray2d - V2d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray2d ray, V2d v) => ray.Direction.IsParallelTo(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray2d ray, V2d v, double epsilon = 1e-6) => ray.Direction.IsParallelTo(v, epsilon); #endregion #region Ray2d - Ray2d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray2d r0, Ray2d r1) => r0.Direction.IsParallelTo(r1.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray2d r0, Ray2d r1, double epsilon = 1e-6) => r0.Direction.IsParallelTo(r1.Direction, epsilon); #endregion #region Line2d - Line2d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Line2d l0, Line2d l1) => l0.Direction.IsParallelTo(l1.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Line2d l0, Line2d l1, double epsilon = 1e-6) => l0.Direction.IsParallelTo(l1.Direction, epsilon); #endregion // 3-Dimensional #region V3d - V3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this V3d u, V3d v) => Fun.IsTiny(u.Cross(v).Norm1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this V3d u, V3d v, double epsilon = 1e-6) { var un = u.Normalized; var vn = v.Normalized; return (un - vn).Length < epsilon || (un + vn).Length < epsilon; } #endregion #region Ray3d - V3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray3d ray, V3d vec) => ray.Direction.IsParallelTo(vec); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray3d ray, V3d vec, double epsilon = 1e-6) => ray.Direction.IsParallelTo(vec, epsilon); #endregion #region Ray3d - Ray3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray3d r0, Ray3d r1) => r0.Direction.IsParallelTo(r1.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray3d r0, Ray3d r1, double epsilon = 1e-6) => r0.Direction.IsParallelTo(r1.Direction, epsilon); #endregion #region Plane3d - Plane3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Plane3d p0, Plane3d p1) => p0.Normal.IsParallelTo(p1.Normal); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Plane3d p0, Plane3d p1, double epsilon = 1e-6) => p0.Normal.IsParallelTo(p1.Normal, epsilon); #endregion #region Ray3d - Plane3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Ray3d ray, Plane3d plane) => ray.Direction.IsOrthogonalTo(plane.Normal); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Plane3d plane, Ray3d ray) => ray.Direction.IsOrthogonalTo(plane.Normal); #endregion #region Line3d - Line3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Line3d l0, Line3d l1) => l0.Direction.IsParallelTo(l1.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this Line3d l0, Line3d l1, double epsilon = 1e-6) => l0.Direction.IsParallelTo(l1.Direction, epsilon); #endregion } } ================================================ FILE: src/Aardvark.Base/Geometry/Relations/Parallelism_template.cs ================================================ using System.Runtime.CompilerServices; namespace Aardvark.Base { /// /// Provides various methods determining parallelism /// public static class Parallelism { //# foreach (var isDouble in new[] { false, true }) { //# var rtype = isDouble ? "double" : "float"; //# var tc = isDouble ? "d" : "f"; //# var v2t = "V2" + tc; //# var v3t = "V3" + tc; //# var plane3t = "Plane3" + tc; //# var ray2t = "Ray2" + tc; //# var ray3t = "Ray3" + tc; //# var line2t = "Line2" + tc; //# var line3t = "Line3" + tc; //# var eps = isDouble ? "1e-6" : "1e-4f"; // 2-Dimensional #region __v2t__ - __v2t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __v2t__ u, __v2t__ v) => Fun.IsTiny(u.X * v.Y - u.Y * v.X); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __v2t__ u, __v2t__ v, __rtype__ epsilon = __eps__) { var un = u.Normalized; var vn = v.Normalized; return (un - vn).Length < epsilon || (un + vn).Length < epsilon; } #endregion #region __ray2t__ - __v2t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __ray2t__ ray, __v2t__ v) => ray.Direction.IsParallelTo(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __ray2t__ ray, __v2t__ v, __rtype__ epsilon = __eps__) => ray.Direction.IsParallelTo(v, epsilon); #endregion #region __ray2t__ - __ray2t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __ray2t__ r0, __ray2t__ r1) => r0.Direction.IsParallelTo(r1.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __ray2t__ r0, __ray2t__ r1, __rtype__ epsilon = __eps__) => r0.Direction.IsParallelTo(r1.Direction, epsilon); #endregion #region __line2t__ - __line2t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __line2t__ l0, __line2t__ l1) => l0.Direction.IsParallelTo(l1.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __line2t__ l0, __line2t__ l1, __rtype__ epsilon = __eps__) => l0.Direction.IsParallelTo(l1.Direction, epsilon); #endregion // 3-Dimensional #region __v3t__ - __v3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __v3t__ u, __v3t__ v) => Fun.IsTiny(u.Cross(v).Norm1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __v3t__ u, __v3t__ v, __rtype__ epsilon = __eps__) { var un = u.Normalized; var vn = v.Normalized; return (un - vn).Length < epsilon || (un + vn).Length < epsilon; } #endregion #region __ray3t__ - __v3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __ray3t__ ray, __v3t__ vec) => ray.Direction.IsParallelTo(vec); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __ray3t__ ray, __v3t__ vec, __rtype__ epsilon = __eps__) => ray.Direction.IsParallelTo(vec, epsilon); #endregion #region __ray3t__ - __ray3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __ray3t__ r0, __ray3t__ r1) => r0.Direction.IsParallelTo(r1.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __ray3t__ r0, __ray3t__ r1, __rtype__ epsilon = __eps__) => r0.Direction.IsParallelTo(r1.Direction, epsilon); #endregion #region __plane3t__ - __plane3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __plane3t__ p0, __plane3t__ p1) => p0.Normal.IsParallelTo(p1.Normal); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __plane3t__ p0, __plane3t__ p1, __rtype__ epsilon = __eps__) => p0.Normal.IsParallelTo(p1.Normal, epsilon); #endregion #region __ray3t__ - __plane3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __ray3t__ ray, __plane3t__ plane) => ray.Direction.IsOrthogonalTo(plane.Normal); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __plane3t__ plane, __ray3t__ ray) => ray.Direction.IsOrthogonalTo(plane.Normal); #endregion #region __line3t__ - __line3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __line3t__ l0, __line3t__ l1) => l0.Direction.IsParallelTo(l1.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsParallelTo(this __line3t__ l0, __line3t__ l1, __rtype__ epsilon = __eps__) => l0.Direction.IsParallelTo(l1.Direction, epsilon); #endregion //# } } } ================================================ FILE: src/Aardvark.Base/Geometry/Relations/SubPrimitives_auto.cs ================================================ using System; using System.Linq; using System.Collections.Generic; namespace Aardvark.Base { public static class SubPrimitives { #region Triangulation of Convex Polygons /// /// Compute a simple triangulation starting from the first point of /// the polygon. Note that the indices are twice indirect (once over /// pia, once over via). Returns the number of triangles (ie. two /// less than the length of the array pia). /// public static int ComputeSimpleTriangulation( this int[] pia, int[] via, int tvi, int[] tia, int[] pvibm, int[] tibm) { int fi = pia[0], fvi = via[fi]; int i1 = pia[1], vi1 = via[i1]; int count = pia.Length; for (int ii = 2; ii < count; ii++) { int vi0 = vi1, i0 = i1; vi1 = via[i1 = pia[ii]]; tia[tvi] = fvi; tia[tvi + 1] = vi0; tia[tvi + 2] = vi1; if (tibm != null) { tibm[tvi] = pvibm[fi]; tibm[tvi + 1] = pvibm[i0]; tibm[tvi + 2] = pvibm[i1]; } tvi += 3; } return count - 2; } #endregion #region Non-Concave Sub-Polygons of a Polygon2f private static int[] ComputeNonConcaveSubPolygon( this Polygon2f poly, ref int[] indices, float absoluteEpsilon) { int count = indices.Length; if (count <= 3) { var result = indices; indices = Array.Empty(); return result; } Func addFun = i => (i + 1) % count; Func subFun = i => (i + count - 1) % count; for (int vi = 0; vi < count; vi++) // we possibly have to try all vertices { int nowMinIndex = vi, nowMaxIndex = vi; var nowMinPoint = poly[indices[nowMinIndex]]; var nowMaxPoint = poly[indices[nowMaxIndex]]; var oldMinPoint = poly[indices[addFun(nowMinIndex)]]; var oldMaxPoint = poly[indices[subFun(nowMinIndex)]]; var subCount = 1; bool add = true; for (int pass = 0, goodPass = 0; pass - goodPass < 3; pass++, add = !add) { // alternate between adding a point at the two ends var nextFun = add ? addFun : subFun; int lastIndex = add ? nowMinIndex : nowMaxIndex; int newIndex = add ? addFun(nowMaxIndex) : subFun(nowMinIndex); if (newIndex == lastIndex) { var finalIndices = indices; indices = Array.Empty(); return finalIndices; } var newPoint = poly[indices[newIndex]]; var pMax = new Line2f(oldMaxPoint, nowMaxPoint).Plane2f; var pMin = new Line2f(oldMinPoint, nowMinPoint).Plane2f; var npMax = pMax.Normalized; var npMin = pMin.Normalized; var hMax = new Line2f(oldMaxPoint, nowMaxPoint).Plane2f.Normalized.Height(newPoint); var hMin = new Line2f(oldMinPoint, nowMinPoint).Plane2f.Normalized.Height(newPoint); if (hMax >= -absoluteEpsilon && hMin <= absoluteEpsilon) { bool good = true; if (nowMinIndex != nowMaxIndex) { var plane0 = new Line2f(nowMinPoint, nowMaxPoint).Plane2f.Normalized; var plane1 = new Line2f(nowMaxPoint, newPoint).Plane2f.Normalized; var plane2 = new Line2f(newPoint, nowMinPoint).Plane2f.Normalized; // check if new triangle does not contain any other points of the polygon for (int i = nextFun(newIndex); i != lastIndex; i = nextFun(i)) { var point = poly[indices[i]]; if (plane0.Height(point) > -absoluteEpsilon && plane1.Height(point) >= absoluteEpsilon && plane2.Height(point) >= absoluteEpsilon) { good = false; break; } } } if (good) { if (add) { nowMaxIndex = newIndex; oldMaxPoint = nowMaxPoint; nowMaxPoint = newPoint; } else { nowMinIndex = newIndex; oldMinPoint = nowMinPoint; nowMinPoint = newPoint; } goodPass = pass; ++subCount; } } } if (subCount < 3) continue; // build new arrays here var subIndices = new int[subCount]; for (int i = 0, ni = nowMinIndex; i < subCount; i++, ni = addFun(ni)) subIndices[i] = indices[ni]; int newCount = 2 + count - subCount; var newIndices = new int[newCount]; for (int i = 0, ni = nowMaxIndex; i < newCount; i++, ni = addFun(ni)) newIndices[i] = indices[ni]; indices = newIndices; return subIndices; } return null; } public static void AddNonConcaveSubPolygons( this List polygonList, Polygon2f poly, float absoluteEpsilon) { var indices = new int[poly.PointCount].SetByIndex(i => i); while (indices.Length > 0) { var subPoly = poly.ComputeNonConcaveSubPolygon( ref indices, absoluteEpsilon); if (subPoly == null) { Console.WriteLine("encountered degenerated polygon that cannot be easily triangulated"); break; } if (subPoly.Length < 3) { Console.WriteLine("encountered invalid subpolygon"); continue; } polygonList.Add(subPoly); } } public static List ComputeNonConcaveSubPolygons( this Polygon2f polygon, float absoluteEpsilon) { var polygonList = new List(); polygonList.AddNonConcaveSubPolygons(polygon, absoluteEpsilon); return polygonList; } #endregion #region Non-Concave Sub-Polygons of Polygons in 3d public static List ComputeNonConcaveSubPolygons( this Polygon3f polygon, float absoluteEpsilon) { V3f normal = polygon.ComputeDoubleAreaNormal(); float len2 = normal.LengthSquared; if (len2 < absoluteEpsilon * absoluteEpsilon) return new int[polygon.PointCount].SetByIndex(i => i).IntoList(); M44f.NormalFrame(V3f.Zero, normal * (1 / Fun.Sqrt(len2)), out M44f local2global, out M44f global2local); var polygon2d = polygon.ToPolygon2f(p => global2local.TransformPos(p).XY); return polygon2d.ComputeNonConcaveSubPolygons(absoluteEpsilon); } public static List ComputeNonConcaveSubPolygons( this V3f[] vertexArray, int polyCount, V3f[] normalArray, int[] firstIndices, int[] vertexIndices, List faceBackMap, float absoluteEpsilon) { var polyList = new List(); var eps2 = absoluteEpsilon * absoluteEpsilon; for (int fvi = 0, fi = 0; fi < polyCount; fi++) { int fve = firstIndices[fi+1], fvc = fve - fvi; var n = normalArray[fi]; var l2 = n.LengthSquared; if (l2 < eps2) { polyList.Add(new int[fvc].SetByIndex(i => vertexIndices[fvi + i])); if (faceBackMap != null) faceBackMap.Add(fi); fvi = fve; continue; } M44f.NormalFrame(V3f.Zero, n, out M44f local2global, out M44f global2local); var polygon = new Polygon2f(fvc, i => global2local.TransformPos(vertexArray[vertexIndices[fvi + i]]).XY); var subPolyList = polygon.ComputeNonConcaveSubPolygons(absoluteEpsilon); foreach (var poly in subPolyList) polyList.Add(poly.Map(i => fvi + i)); if (faceBackMap != null) for (int i = 0; i < subPolyList.Count; i++) faceBackMap.Add(fi); fvi = fve; } return polyList; } #endregion #region Triangulation of Non-Concave Polygons in 3d /// /// /// /// Triangle count. public static int ComputeTriangulationOfNonConcavePolygon( this int[] ia, int[] via, V3f[] va, V3f[] edgeArray, bool[] straightArray, int tvi, int[] tia, int[] pvibm, int[] tibm) { int count = ia.Length; if (count < 3) throw new ArgumentOutOfRangeException(); if (count == 3) { tia[tvi] = via[ia[0]]; tia[tvi + 1] = via[ia[1]]; tia[tvi + 2] = via[ia[2]]; if (tibm != null) { tibm[tvi] = pvibm[ia[0]]; tibm[tvi + 1] = pvibm[ia[1]]; tibm[tvi + 2] = pvibm[ia[2]]; } return 1; } int ii = 0; // search for the first non-straight corner while (ii < ia.Length && straightArray[ia[ii]]) ii++; int bii = ii; ii = (ii + 1) % count; // search for first straight corner afterwards while (ii != bii && !straightArray[ia[ii]]) ii = (ii + 1) % count; if (ii == bii) // if there is no straight corner return ia.ComputeSimpleTriangulation(via, tvi, tia, pvibm, tibm); bii = ii; // first int eii = ii; int straightCount = 0; while (straightArray[ia[ii]]) { eii = ii; ii = (ii + 1) % count; ++straightCount; } if (count - straightCount < 3) // numeric problem, cop out return ia.ComputeSimpleTriangulation(via, tvi, tia, pvibm, tibm); var hii = ii; float height = 0; var li = ia[eii]; var edge = edgeArray[li]; var vertex = va[via[li]]; int rightCount = 2; int rc = 2; ii = (ii + 1) % count; while (ii != bii) { int i = ia[ii]; var h = edge.Cross(va[via[i]] - vertex).LengthSquared; ++rc; if (h > height) { height = h; hii = ii; rightCount = rc; } ii = (ii + 1) % count; } straightArray[ia[bii]] = false; straightArray[ia[eii]] = false; straightArray[ia[hii]] = false; int leftCount = count - straightCount - rightCount + 3; var lia = new int[leftCount]; ii = hii; for (int lii = 0; lii < leftCount; lii++, ii = (ii + 1) % count) lia[lii] = ia[ii]; if (leftCount > 2) lia.ComputeTriangulationOfNonConcavePolygon(via, va, edgeArray, straightArray, tvi, tia, pvibm, tibm); tvi += 3 * (leftCount - 2); if (straightCount > 1) { int hi = ia[hii], hvi = via[hi]; int i1 = ia[bii], vi1 = via[i1]; ii = bii; for (int sii = 0; sii < straightCount - 1; sii++) { ii = (ii + 1) % count; int vi0 = vi1, i0 = i1; vi1 = via[i1 = ia[ii]]; tia[tvi] = hvi; tia[tvi + 1] = vi0; tia[tvi + 2] = vi1; if (tibm != null) { tibm[tvi] = pvibm[hi]; tibm[tvi + 1] = pvibm[i0]; tibm[tvi + 2] = pvibm[i1]; } tvi += 3; } } var ria = new int[rightCount]; ii = eii; for (int rii = 0; rii < rightCount; rii++, ii = (ii + 1) % count) ria[rii] = ia[ii]; if (rightCount > 2) ria.ComputeTriangulationOfNonConcavePolygon(via, va, edgeArray, straightArray, tvi, tia, pvibm, tibm); return count - 2; } public static void ComputeStraightVertices( this int[] via, V3f[] va, float absoluteEpsilon, V3f[] normalizedEdgeArray, bool[] straightArray) { int count = via.Length; if (straightArray == null) throw new ArgumentNullException(); if (count <= 2) throw new ArgumentException(); if (straightArray.Length != count) throw new ArgumentException(); if (normalizedEdgeArray != null && normalizedEdgeArray.Length != count) throw new ArgumentException(); float eps2 = absoluteEpsilon * absoluteEpsilon; V3f[] ea = new V3f[count]; int oi = count - 1; var oldVertex = va[via[oi]]; for (int i = 0; i < count; i++) { var vertex = va[via[i]]; ea[oi] = vertex - oldVertex; oi = i; oldVertex = vertex; } oi = count - 1; var oldEdge = ea[oi].Normalized; for (int i = 0; i < count; i++) { var edge = ea[i].Normalized; if (normalizedEdgeArray != null) normalizedEdgeArray[oi] = oldEdge; straightArray[i] = (edge - oldEdge).LengthSquared < eps2; oi = i; oldEdge = edge; } } /// /// /// /// Triangle count. public static int ComputeTriangulationOfNonConcavePolygon( this V3f[] va, int[] via, float absoluteEpsilon, int ftvi, int[] tia, int[] pvibm = null, int[] tibm = null) { int count = via.Length; var straightArray = new bool[count]; var normalizedEdgeArray = new V3f[count]; via.ComputeStraightVertices(va, absoluteEpsilon, normalizedEdgeArray, straightArray); var ia = new int[count].SetByIndex(i => i); return ia.ComputeTriangulationOfNonConcavePolygon( via, va, normalizedEdgeArray, straightArray, ftvi, tia, pvibm, tibm); } public static int[] ComputeTriangulationOfNonConcavePolygons( this V3f[] vertexArray, List nonConcavePolyList, float absoluteEpsilon) { int tc = nonConcavePolyList.Sum(p => p.Length - 2); var tia = new int[tc]; tc = 0; foreach (var pia in nonConcavePolyList) { tc += 3 * vertexArray.ComputeTriangulationOfNonConcavePolygon( pia, absoluteEpsilon, tc, tia); } return tia; } #endregion #region Triangulation of Concave Polygons /// /// Compute the triangulation of the supplied concave polygon and put /// the triangle vertex indices into the supplied array starting at /// the supplied triangle vertex index. /// /// the number of triangles in the triangulation private static int ComputeTriangulationOfConcavePolygon( this Polygon3f polygon, float absoluteEpsilon, int triangleVertexIndex, int[] triangleIndexArray) { var polyList = polygon.ComputeNonConcaveSubPolygons(absoluteEpsilon); foreach (var pia in polyList) { int tc = polygon.GetPointArray().ComputeTriangulationOfNonConcavePolygon( pia, absoluteEpsilon, triangleVertexIndex, triangleIndexArray); triangleVertexIndex += 3 * tc; } return polygon.PointCount - 2; } /// /// Compute the triangulation of the supplied concave polygon and /// return the resulting triangle index array. /// public static int[] ComputeTriangulationOfConcavePolygon( this Polygon3f polygon, float absoluteEpsilon) { int[] triangleIndexArray = new int[3 * (polygon.PointCount - 2)]; polygon.ComputeTriangulationOfConcavePolygon( absoluteEpsilon, 0, triangleIndexArray); return triangleIndexArray; } /// /// Compute the triangulation of the concave polygons supplied in /// the arrays with PolyMesh layout, and return the resulting /// triangle index array. /// public static int[] ComputeTriangulationOfConcavePolygons( this V3f[] vertexArray, int polyCount, V3f[] normalArray, int[] firstIndices, int[] vertexIndices, float absoluteEpsilon) { var polyList = vertexArray.ComputeNonConcaveSubPolygons( polyCount, normalArray, firstIndices, vertexIndices, null, absoluteEpsilon); return vertexArray.ComputeTriangulationOfNonConcavePolygons( polyList, absoluteEpsilon); } #endregion #region Non-Concave Sub-Polygons of a Polygon2d private static int[] ComputeNonConcaveSubPolygon( this Polygon2d poly, ref int[] indices, double absoluteEpsilon) { int count = indices.Length; if (count <= 3) { var result = indices; indices = Array.Empty(); return result; } Func addFun = i => (i + 1) % count; Func subFun = i => (i + count - 1) % count; for (int vi = 0; vi < count; vi++) // we possibly have to try all vertices { int nowMinIndex = vi, nowMaxIndex = vi; var nowMinPoint = poly[indices[nowMinIndex]]; var nowMaxPoint = poly[indices[nowMaxIndex]]; var oldMinPoint = poly[indices[addFun(nowMinIndex)]]; var oldMaxPoint = poly[indices[subFun(nowMinIndex)]]; var subCount = 1; bool add = true; for (int pass = 0, goodPass = 0; pass - goodPass < 3; pass++, add = !add) { // alternate between adding a point at the two ends var nextFun = add ? addFun : subFun; int lastIndex = add ? nowMinIndex : nowMaxIndex; int newIndex = add ? addFun(nowMaxIndex) : subFun(nowMinIndex); if (newIndex == lastIndex) { var finalIndices = indices; indices = Array.Empty(); return finalIndices; } var newPoint = poly[indices[newIndex]]; var pMax = new Line2d(oldMaxPoint, nowMaxPoint).Plane2d; var pMin = new Line2d(oldMinPoint, nowMinPoint).Plane2d; var npMax = pMax.Normalized; var npMin = pMin.Normalized; var hMax = new Line2d(oldMaxPoint, nowMaxPoint).Plane2d.Normalized.Height(newPoint); var hMin = new Line2d(oldMinPoint, nowMinPoint).Plane2d.Normalized.Height(newPoint); if (hMax >= -absoluteEpsilon && hMin <= absoluteEpsilon) { bool good = true; if (nowMinIndex != nowMaxIndex) { var plane0 = new Line2d(nowMinPoint, nowMaxPoint).Plane2d.Normalized; var plane1 = new Line2d(nowMaxPoint, newPoint).Plane2d.Normalized; var plane2 = new Line2d(newPoint, nowMinPoint).Plane2d.Normalized; // check if new triangle does not contain any other points of the polygon for (int i = nextFun(newIndex); i != lastIndex; i = nextFun(i)) { var point = poly[indices[i]]; if (plane0.Height(point) > -absoluteEpsilon && plane1.Height(point) >= absoluteEpsilon && plane2.Height(point) >= absoluteEpsilon) { good = false; break; } } } if (good) { if (add) { nowMaxIndex = newIndex; oldMaxPoint = nowMaxPoint; nowMaxPoint = newPoint; } else { nowMinIndex = newIndex; oldMinPoint = nowMinPoint; nowMinPoint = newPoint; } goodPass = pass; ++subCount; } } } if (subCount < 3) continue; // build new arrays here var subIndices = new int[subCount]; for (int i = 0, ni = nowMinIndex; i < subCount; i++, ni = addFun(ni)) subIndices[i] = indices[ni]; int newCount = 2 + count - subCount; var newIndices = new int[newCount]; for (int i = 0, ni = nowMaxIndex; i < newCount; i++, ni = addFun(ni)) newIndices[i] = indices[ni]; indices = newIndices; return subIndices; } return null; } public static void AddNonConcaveSubPolygons( this List polygonList, Polygon2d poly, double absoluteEpsilon) { var indices = new int[poly.PointCount].SetByIndex(i => i); while (indices.Length > 0) { var subPoly = poly.ComputeNonConcaveSubPolygon( ref indices, absoluteEpsilon); if (subPoly == null) { Console.WriteLine("encountered degenerated polygon that cannot be easily triangulated"); break; } if (subPoly.Length < 3) { Console.WriteLine("encountered invalid subpolygon"); continue; } polygonList.Add(subPoly); } } public static List ComputeNonConcaveSubPolygons( this Polygon2d polygon, double absoluteEpsilon) { var polygonList = new List(); polygonList.AddNonConcaveSubPolygons(polygon, absoluteEpsilon); return polygonList; } #endregion #region Non-Concave Sub-Polygons of Polygons in 3d public static List ComputeNonConcaveSubPolygons( this Polygon3d polygon, double absoluteEpsilon) { V3d normal = polygon.ComputeDoubleAreaNormal(); double len2 = normal.LengthSquared; if (len2 < absoluteEpsilon * absoluteEpsilon) return new int[polygon.PointCount].SetByIndex(i => i).IntoList(); M44d.NormalFrame(V3d.Zero, normal * (1 / Fun.Sqrt(len2)), out M44d local2global, out M44d global2local); var polygon2d = polygon.ToPolygon2d(p => global2local.TransformPos(p).XY); return polygon2d.ComputeNonConcaveSubPolygons(absoluteEpsilon); } public static List ComputeNonConcaveSubPolygons( this V3d[] vertexArray, int polyCount, V3d[] normalArray, int[] firstIndices, int[] vertexIndices, List faceBackMap, double absoluteEpsilon) { var polyList = new List(); var eps2 = absoluteEpsilon * absoluteEpsilon; for (int fvi = 0, fi = 0; fi < polyCount; fi++) { int fve = firstIndices[fi+1], fvc = fve - fvi; var n = normalArray[fi]; var l2 = n.LengthSquared; if (l2 < eps2) { polyList.Add(new int[fvc].SetByIndex(i => vertexIndices[fvi + i])); if (faceBackMap != null) faceBackMap.Add(fi); fvi = fve; continue; } M44d.NormalFrame(V3d.Zero, n, out M44d local2global, out M44d global2local); var polygon = new Polygon2d(fvc, i => global2local.TransformPos(vertexArray[vertexIndices[fvi + i]]).XY); var subPolyList = polygon.ComputeNonConcaveSubPolygons(absoluteEpsilon); foreach (var poly in subPolyList) polyList.Add(poly.Map(i => fvi + i)); if (faceBackMap != null) for (int i = 0; i < subPolyList.Count; i++) faceBackMap.Add(fi); fvi = fve; } return polyList; } #endregion #region Triangulation of Non-Concave Polygons in 3d /// /// /// /// Triangle count. public static int ComputeTriangulationOfNonConcavePolygon( this int[] ia, int[] via, V3d[] va, V3d[] edgeArray, bool[] straightArray, int tvi, int[] tia, int[] pvibm, int[] tibm) { int count = ia.Length; if (count < 3) throw new ArgumentOutOfRangeException(); if (count == 3) { tia[tvi] = via[ia[0]]; tia[tvi + 1] = via[ia[1]]; tia[tvi + 2] = via[ia[2]]; if (tibm != null) { tibm[tvi] = pvibm[ia[0]]; tibm[tvi + 1] = pvibm[ia[1]]; tibm[tvi + 2] = pvibm[ia[2]]; } return 1; } int ii = 0; // search for the first non-straight corner while (ii < ia.Length && straightArray[ia[ii]]) ii++; int bii = ii; ii = (ii + 1) % count; // search for first straight corner afterwards while (ii != bii && !straightArray[ia[ii]]) ii = (ii + 1) % count; if (ii == bii) // if there is no straight corner return ia.ComputeSimpleTriangulation(via, tvi, tia, pvibm, tibm); bii = ii; // first int eii = ii; int straightCount = 0; while (straightArray[ia[ii]]) { eii = ii; ii = (ii + 1) % count; ++straightCount; } if (count - straightCount < 3) // numeric problem, cop out return ia.ComputeSimpleTriangulation(via, tvi, tia, pvibm, tibm); var hii = ii; double height = 0; var li = ia[eii]; var edge = edgeArray[li]; var vertex = va[via[li]]; int rightCount = 2; int rc = 2; ii = (ii + 1) % count; while (ii != bii) { int i = ia[ii]; var h = edge.Cross(va[via[i]] - vertex).LengthSquared; ++rc; if (h > height) { height = h; hii = ii; rightCount = rc; } ii = (ii + 1) % count; } straightArray[ia[bii]] = false; straightArray[ia[eii]] = false; straightArray[ia[hii]] = false; int leftCount = count - straightCount - rightCount + 3; var lia = new int[leftCount]; ii = hii; for (int lii = 0; lii < leftCount; lii++, ii = (ii + 1) % count) lia[lii] = ia[ii]; if (leftCount > 2) lia.ComputeTriangulationOfNonConcavePolygon(via, va, edgeArray, straightArray, tvi, tia, pvibm, tibm); tvi += 3 * (leftCount - 2); if (straightCount > 1) { int hi = ia[hii], hvi = via[hi]; int i1 = ia[bii], vi1 = via[i1]; ii = bii; for (int sii = 0; sii < straightCount - 1; sii++) { ii = (ii + 1) % count; int vi0 = vi1, i0 = i1; vi1 = via[i1 = ia[ii]]; tia[tvi] = hvi; tia[tvi + 1] = vi0; tia[tvi + 2] = vi1; if (tibm != null) { tibm[tvi] = pvibm[hi]; tibm[tvi + 1] = pvibm[i0]; tibm[tvi + 2] = pvibm[i1]; } tvi += 3; } } var ria = new int[rightCount]; ii = eii; for (int rii = 0; rii < rightCount; rii++, ii = (ii + 1) % count) ria[rii] = ia[ii]; if (rightCount > 2) ria.ComputeTriangulationOfNonConcavePolygon(via, va, edgeArray, straightArray, tvi, tia, pvibm, tibm); return count - 2; } public static void ComputeStraightVertices( this int[] via, V3d[] va, double absoluteEpsilon, V3d[] normalizedEdgeArray, bool[] straightArray) { int count = via.Length; if (straightArray == null) throw new ArgumentNullException(); if (count <= 2) throw new ArgumentException(); if (straightArray.Length != count) throw new ArgumentException(); if (normalizedEdgeArray != null && normalizedEdgeArray.Length != count) throw new ArgumentException(); double eps2 = absoluteEpsilon * absoluteEpsilon; V3d[] ea = new V3d[count]; int oi = count - 1; var oldVertex = va[via[oi]]; for (int i = 0; i < count; i++) { var vertex = va[via[i]]; ea[oi] = vertex - oldVertex; oi = i; oldVertex = vertex; } oi = count - 1; var oldEdge = ea[oi].Normalized; for (int i = 0; i < count; i++) { var edge = ea[i].Normalized; if (normalizedEdgeArray != null) normalizedEdgeArray[oi] = oldEdge; straightArray[i] = (edge - oldEdge).LengthSquared < eps2; oi = i; oldEdge = edge; } } /// /// /// /// Triangle count. public static int ComputeTriangulationOfNonConcavePolygon( this V3d[] va, int[] via, double absoluteEpsilon, int ftvi, int[] tia, int[] pvibm = null, int[] tibm = null) { int count = via.Length; var straightArray = new bool[count]; var normalizedEdgeArray = new V3d[count]; via.ComputeStraightVertices(va, absoluteEpsilon, normalizedEdgeArray, straightArray); var ia = new int[count].SetByIndex(i => i); return ia.ComputeTriangulationOfNonConcavePolygon( via, va, normalizedEdgeArray, straightArray, ftvi, tia, pvibm, tibm); } public static int[] ComputeTriangulationOfNonConcavePolygons( this V3d[] vertexArray, List nonConcavePolyList, double absoluteEpsilon) { int tc = nonConcavePolyList.Sum(p => p.Length - 2); var tia = new int[tc]; tc = 0; foreach (var pia in nonConcavePolyList) { tc += 3 * vertexArray.ComputeTriangulationOfNonConcavePolygon( pia, absoluteEpsilon, tc, tia); } return tia; } #endregion #region Triangulation of Concave Polygons /// /// Compute the triangulation of the supplied concave polygon and put /// the triangle vertex indices into the supplied array starting at /// the supplied triangle vertex index. /// /// the number of triangles in the triangulation private static int ComputeTriangulationOfConcavePolygon( this Polygon3d polygon, double absoluteEpsilon, int triangleVertexIndex, int[] triangleIndexArray) { var polyList = polygon.ComputeNonConcaveSubPolygons(absoluteEpsilon); foreach (var pia in polyList) { int tc = polygon.GetPointArray().ComputeTriangulationOfNonConcavePolygon( pia, absoluteEpsilon, triangleVertexIndex, triangleIndexArray); triangleVertexIndex += 3 * tc; } return polygon.PointCount - 2; } /// /// Compute the triangulation of the supplied concave polygon and /// return the resulting triangle index array. /// public static int[] ComputeTriangulationOfConcavePolygon( this Polygon3d polygon, double absoluteEpsilon) { int[] triangleIndexArray = new int[3 * (polygon.PointCount - 2)]; polygon.ComputeTriangulationOfConcavePolygon( absoluteEpsilon, 0, triangleIndexArray); return triangleIndexArray; } /// /// Compute the triangulation of the concave polygons supplied in /// the arrays with PolyMesh layout, and return the resulting /// triangle index array. /// public static int[] ComputeTriangulationOfConcavePolygons( this V3d[] vertexArray, int polyCount, V3d[] normalArray, int[] firstIndices, int[] vertexIndices, double absoluteEpsilon) { var polyList = vertexArray.ComputeNonConcaveSubPolygons( polyCount, normalArray, firstIndices, vertexIndices, null, absoluteEpsilon); return vertexArray.ComputeTriangulationOfNonConcavePolygons( polyList, absoluteEpsilon); } #endregion } } ================================================ FILE: src/Aardvark.Base/Geometry/Relations/SubPrimitives_template.cs ================================================ using System; using System.Linq; using System.Collections.Generic; namespace Aardvark.Base { public static class SubPrimitives { #region Triangulation of Convex Polygons /// /// Compute a simple triangulation starting from the first point of /// the polygon. Note that the indices are twice indirect (once over /// pia, once over via). Returns the number of triangles (ie. two /// less than the length of the array pia). /// public static int ComputeSimpleTriangulation( this int[] pia, int[] via, int tvi, int[] tia, int[] pvibm, int[] tibm) { int fi = pia[0], fvi = via[fi]; int i1 = pia[1], vi1 = via[i1]; int count = pia.Length; for (int ii = 2; ii < count; ii++) { int vi0 = vi1, i0 = i1; vi1 = via[i1 = pia[ii]]; tia[tvi] = fvi; tia[tvi + 1] = vi0; tia[tvi + 2] = vi1; if (tibm != null) { tibm[tvi] = pvibm[fi]; tibm[tvi + 1] = pvibm[i0]; tibm[tvi + 2] = pvibm[i1]; } tvi += 3; } return count - 2; } #endregion //# foreach (var isDouble in new[] { false, true }) { //# var rtype = isDouble ? "double" : "float"; //# var tc = isDouble ? "d" : "f"; //# var v2t = "V2" + tc; //# var v3t = "V3" + tc; //# var line2t = "Line2" + tc; //# var plane2t = "Plane2" + tc; //# var polygon2t = "Polygon2" + tc; //# var polygon3t = "Polygon3" + tc; //# var m44t = "M44" + tc; #region Non-Concave Sub-Polygons of a __polygon2t__ private static int[] ComputeNonConcaveSubPolygon( this __polygon2t__ poly, ref int[] indices, __rtype__ absoluteEpsilon) { int count = indices.Length; if (count <= 3) { var result = indices; indices = Array.Empty(); return result; } Func addFun = i => (i + 1) % count; Func subFun = i => (i + count - 1) % count; for (int vi = 0; vi < count; vi++) // we possibly have to try all vertices { int nowMinIndex = vi, nowMaxIndex = vi; var nowMinPoint = poly[indices[nowMinIndex]]; var nowMaxPoint = poly[indices[nowMaxIndex]]; var oldMinPoint = poly[indices[addFun(nowMinIndex)]]; var oldMaxPoint = poly[indices[subFun(nowMinIndex)]]; var subCount = 1; bool add = true; for (int pass = 0, goodPass = 0; pass - goodPass < 3; pass++, add = !add) { // alternate between adding a point at the two ends var nextFun = add ? addFun : subFun; int lastIndex = add ? nowMinIndex : nowMaxIndex; int newIndex = add ? addFun(nowMaxIndex) : subFun(nowMinIndex); if (newIndex == lastIndex) { var finalIndices = indices; indices = Array.Empty(); return finalIndices; } var newPoint = poly[indices[newIndex]]; var pMax = new __line2t__(oldMaxPoint, nowMaxPoint).__plane2t__; var pMin = new __line2t__(oldMinPoint, nowMinPoint).__plane2t__; var npMax = pMax.Normalized; var npMin = pMin.Normalized; var hMax = new __line2t__(oldMaxPoint, nowMaxPoint).__plane2t__.Normalized.Height(newPoint); var hMin = new __line2t__(oldMinPoint, nowMinPoint).__plane2t__.Normalized.Height(newPoint); if (hMax >= -absoluteEpsilon && hMin <= absoluteEpsilon) { bool good = true; if (nowMinIndex != nowMaxIndex) { var plane0 = new __line2t__(nowMinPoint, nowMaxPoint).__plane2t__.Normalized; var plane1 = new __line2t__(nowMaxPoint, newPoint).__plane2t__.Normalized; var plane2 = new __line2t__(newPoint, nowMinPoint).__plane2t__.Normalized; // check if new triangle does not contain any other points of the polygon for (int i = nextFun(newIndex); i != lastIndex; i = nextFun(i)) { var point = poly[indices[i]]; if (plane0.Height(point) > -absoluteEpsilon && plane1.Height(point) >= absoluteEpsilon && plane2.Height(point) >= absoluteEpsilon) { good = false; break; } } } if (good) { if (add) { nowMaxIndex = newIndex; oldMaxPoint = nowMaxPoint; nowMaxPoint = newPoint; } else { nowMinIndex = newIndex; oldMinPoint = nowMinPoint; nowMinPoint = newPoint; } goodPass = pass; ++subCount; } } } if (subCount < 3) continue; // build new arrays here var subIndices = new int[subCount]; for (int i = 0, ni = nowMinIndex; i < subCount; i++, ni = addFun(ni)) subIndices[i] = indices[ni]; int newCount = 2 + count - subCount; var newIndices = new int[newCount]; for (int i = 0, ni = nowMaxIndex; i < newCount; i++, ni = addFun(ni)) newIndices[i] = indices[ni]; indices = newIndices; return subIndices; } return null; } public static void AddNonConcaveSubPolygons( this List polygonList, __polygon2t__ poly, __rtype__ absoluteEpsilon) { var indices = new int[poly.PointCount].SetByIndex(i => i); while (indices.Length > 0) { var subPoly = poly.ComputeNonConcaveSubPolygon( ref indices, absoluteEpsilon); if (subPoly == null) { Console.WriteLine("encountered degenerated polygon that cannot be easily triangulated"); break; } if (subPoly.Length < 3) { Console.WriteLine("encountered invalid subpolygon"); continue; } polygonList.Add(subPoly); } } public static List ComputeNonConcaveSubPolygons( this __polygon2t__ polygon, __rtype__ absoluteEpsilon) { var polygonList = new List(); polygonList.AddNonConcaveSubPolygons(polygon, absoluteEpsilon); return polygonList; } #endregion #region Non-Concave Sub-Polygons of Polygons in 3d public static List ComputeNonConcaveSubPolygons( this __polygon3t__ polygon, __rtype__ absoluteEpsilon) { __v3t__ normal = polygon.ComputeDoubleAreaNormal(); __rtype__ len2 = normal.LengthSquared; if (len2 < absoluteEpsilon * absoluteEpsilon) return new int[polygon.PointCount].SetByIndex(i => i).IntoList(); __m44t__.NormalFrame(__v3t__.Zero, normal * (1 / Fun.Sqrt(len2)), out __m44t__ local2global, out __m44t__ global2local); var polygon2d = polygon.To__polygon2t__(p => global2local.TransformPos(p).XY); return polygon2d.ComputeNonConcaveSubPolygons(absoluteEpsilon); } public static List ComputeNonConcaveSubPolygons( this __v3t__[] vertexArray, int polyCount, __v3t__[] normalArray, int[] firstIndices, int[] vertexIndices, List faceBackMap, __rtype__ absoluteEpsilon) { var polyList = new List(); var eps2 = absoluteEpsilon * absoluteEpsilon; for (int fvi = 0, fi = 0; fi < polyCount; fi++) { int fve = firstIndices[fi+1], fvc = fve - fvi; var n = normalArray[fi]; var l2 = n.LengthSquared; if (l2 < eps2) { polyList.Add(new int[fvc].SetByIndex(i => vertexIndices[fvi + i])); if (faceBackMap != null) faceBackMap.Add(fi); fvi = fve; continue; } __m44t__.NormalFrame(__v3t__.Zero, n, out __m44t__ local2global, out __m44t__ global2local); var polygon = new __polygon2t__(fvc, i => global2local.TransformPos(vertexArray[vertexIndices[fvi + i]]).XY); var subPolyList = polygon.ComputeNonConcaveSubPolygons(absoluteEpsilon); foreach (var poly in subPolyList) polyList.Add(poly.Map(i => fvi + i)); if (faceBackMap != null) for (int i = 0; i < subPolyList.Count; i++) faceBackMap.Add(fi); fvi = fve; } return polyList; } #endregion #region Triangulation of Non-Concave Polygons in 3d /// /// /// /// Triangle count. public static int ComputeTriangulationOfNonConcavePolygon( this int[] ia, int[] via, __v3t__[] va, __v3t__[] edgeArray, bool[] straightArray, int tvi, int[] tia, int[] pvibm, int[] tibm) { int count = ia.Length; if (count < 3) throw new ArgumentOutOfRangeException(); if (count == 3) { tia[tvi] = via[ia[0]]; tia[tvi + 1] = via[ia[1]]; tia[tvi + 2] = via[ia[2]]; if (tibm != null) { tibm[tvi] = pvibm[ia[0]]; tibm[tvi + 1] = pvibm[ia[1]]; tibm[tvi + 2] = pvibm[ia[2]]; } return 1; } int ii = 0; // search for the first non-straight corner while (ii < ia.Length && straightArray[ia[ii]]) ii++; int bii = ii; ii = (ii + 1) % count; // search for first straight corner afterwards while (ii != bii && !straightArray[ia[ii]]) ii = (ii + 1) % count; if (ii == bii) // if there is no straight corner return ia.ComputeSimpleTriangulation(via, tvi, tia, pvibm, tibm); bii = ii; // first int eii = ii; int straightCount = 0; while (straightArray[ia[ii]]) { eii = ii; ii = (ii + 1) % count; ++straightCount; } if (count - straightCount < 3) // numeric problem, cop out return ia.ComputeSimpleTriangulation(via, tvi, tia, pvibm, tibm); var hii = ii; __rtype__ height = 0; var li = ia[eii]; var edge = edgeArray[li]; var vertex = va[via[li]]; int rightCount = 2; int rc = 2; ii = (ii + 1) % count; while (ii != bii) { int i = ia[ii]; var h = edge.Cross(va[via[i]] - vertex).LengthSquared; ++rc; if (h > height) { height = h; hii = ii; rightCount = rc; } ii = (ii + 1) % count; } straightArray[ia[bii]] = false; straightArray[ia[eii]] = false; straightArray[ia[hii]] = false; int leftCount = count - straightCount - rightCount + 3; var lia = new int[leftCount]; ii = hii; for (int lii = 0; lii < leftCount; lii++, ii = (ii + 1) % count) lia[lii] = ia[ii]; if (leftCount > 2) lia.ComputeTriangulationOfNonConcavePolygon(via, va, edgeArray, straightArray, tvi, tia, pvibm, tibm); tvi += 3 * (leftCount - 2); if (straightCount > 1) { int hi = ia[hii], hvi = via[hi]; int i1 = ia[bii], vi1 = via[i1]; ii = bii; for (int sii = 0; sii < straightCount - 1; sii++) { ii = (ii + 1) % count; int vi0 = vi1, i0 = i1; vi1 = via[i1 = ia[ii]]; tia[tvi] = hvi; tia[tvi + 1] = vi0; tia[tvi + 2] = vi1; if (tibm != null) { tibm[tvi] = pvibm[hi]; tibm[tvi + 1] = pvibm[i0]; tibm[tvi + 2] = pvibm[i1]; } tvi += 3; } } var ria = new int[rightCount]; ii = eii; for (int rii = 0; rii < rightCount; rii++, ii = (ii + 1) % count) ria[rii] = ia[ii]; if (rightCount > 2) ria.ComputeTriangulationOfNonConcavePolygon(via, va, edgeArray, straightArray, tvi, tia, pvibm, tibm); return count - 2; } public static void ComputeStraightVertices( this int[] via, __v3t__[] va, __rtype__ absoluteEpsilon, __v3t__[] normalizedEdgeArray, bool[] straightArray) { int count = via.Length; if (straightArray == null) throw new ArgumentNullException(); if (count <= 2) throw new ArgumentException(); if (straightArray.Length != count) throw new ArgumentException(); if (normalizedEdgeArray != null && normalizedEdgeArray.Length != count) throw new ArgumentException(); __rtype__ eps2 = absoluteEpsilon * absoluteEpsilon; __v3t__[] ea = new __v3t__[count]; int oi = count - 1; var oldVertex = va[via[oi]]; for (int i = 0; i < count; i++) { var vertex = va[via[i]]; ea[oi] = vertex - oldVertex; oi = i; oldVertex = vertex; } oi = count - 1; var oldEdge = ea[oi].Normalized; for (int i = 0; i < count; i++) { var edge = ea[i].Normalized; if (normalizedEdgeArray != null) normalizedEdgeArray[oi] = oldEdge; straightArray[i] = (edge - oldEdge).LengthSquared < eps2; oi = i; oldEdge = edge; } } /// /// /// /// Triangle count. public static int ComputeTriangulationOfNonConcavePolygon( this __v3t__[] va, int[] via, __rtype__ absoluteEpsilon, int ftvi, int[] tia, int[] pvibm = null, int[] tibm = null) { int count = via.Length; var straightArray = new bool[count]; var normalizedEdgeArray = new __v3t__[count]; via.ComputeStraightVertices(va, absoluteEpsilon, normalizedEdgeArray, straightArray); var ia = new int[count].SetByIndex(i => i); return ia.ComputeTriangulationOfNonConcavePolygon( via, va, normalizedEdgeArray, straightArray, ftvi, tia, pvibm, tibm); } public static int[] ComputeTriangulationOfNonConcavePolygons( this __v3t__[] vertexArray, List nonConcavePolyList, __rtype__ absoluteEpsilon) { int tc = nonConcavePolyList.Sum(p => p.Length - 2); var tia = new int[tc]; tc = 0; foreach (var pia in nonConcavePolyList) { tc += 3 * vertexArray.ComputeTriangulationOfNonConcavePolygon( pia, absoluteEpsilon, tc, tia); } return tia; } #endregion #region Triangulation of Concave Polygons /// /// Compute the triangulation of the supplied concave polygon and put /// the triangle vertex indices into the supplied array starting at /// the supplied triangle vertex index. /// /// the number of triangles in the triangulation private static int ComputeTriangulationOfConcavePolygon( this __polygon3t__ polygon, __rtype__ absoluteEpsilon, int triangleVertexIndex, int[] triangleIndexArray) { var polyList = polygon.ComputeNonConcaveSubPolygons(absoluteEpsilon); foreach (var pia in polyList) { int tc = polygon.GetPointArray().ComputeTriangulationOfNonConcavePolygon( pia, absoluteEpsilon, triangleVertexIndex, triangleIndexArray); triangleVertexIndex += 3 * tc; } return polygon.PointCount - 2; } /// /// Compute the triangulation of the supplied concave polygon and /// return the resulting triangle index array. /// public static int[] ComputeTriangulationOfConcavePolygon( this __polygon3t__ polygon, __rtype__ absoluteEpsilon) { int[] triangleIndexArray = new int[3 * (polygon.PointCount - 2)]; polygon.ComputeTriangulationOfConcavePolygon( absoluteEpsilon, 0, triangleIndexArray); return triangleIndexArray; } /// /// Compute the triangulation of the concave polygons supplied in /// the arrays with PolyMesh layout, and return the resulting /// triangle index array. /// public static int[] ComputeTriangulationOfConcavePolygons( this __v3t__[] vertexArray, int polyCount, __v3t__[] normalArray, int[] firstIndices, int[] vertexIndices, __rtype__ absoluteEpsilon) { var polyList = vertexArray.ComputeNonConcaveSubPolygons( polyCount, normalArray, firstIndices, vertexIndices, null, absoluteEpsilon); return vertexArray.ComputeTriangulationOfNonConcavePolygons( polyList, absoluteEpsilon); } #endregion //# } } } ================================================ FILE: src/Aardvark.Base/Geometry/SpecialPoints_auto.cs ================================================ using System.Collections.Generic; using System.Runtime.CompilerServices; namespace Aardvark.Base { /// /// Provides various methods for middle point computations. /// public static partial class GeometryFun { /* Ray3f */ #region Ray3f - Ray3f public static V3f GetMiddlePoint(this Ray3f ray0, Ray3f ray1) { var a = ray0.Origin - ray1.Origin; var u = ray0.Direction.Normalized; var v = ray1.Direction.Normalized; var uDotv = u.Dot(v); var my = (a.Dot(u) * uDotv - a.Dot(v)) / (uDotv * uDotv - 1); var la = (my * uDotv - a.Dot(u)); var p0 = ray0.Origin + la * u; var p1 = ray1.Origin + my * v; return 0.5f*(p0 + p1); } #endregion #region IEnumerable public static V3f GetMiddlePoint(this IEnumerable rays) { var center = V3f.Zero; var count = 0; foreach(var r0 in rays) foreach (var r1 in rays) if (r0.LexicalCompare(r1) < 0) { center += r0.GetMiddlePoint(r1); ++count; } return center / (float)count; } #endregion /* Ray3d */ #region Ray3d - Ray3d public static V3d GetMiddlePoint(this Ray3d ray0, Ray3d ray1) { var a = ray0.Origin - ray1.Origin; var u = ray0.Direction.Normalized; var v = ray1.Direction.Normalized; var uDotv = u.Dot(v); var my = (a.Dot(u) * uDotv - a.Dot(v)) / (uDotv * uDotv - 1); var la = (my * uDotv - a.Dot(u)); var p0 = ray0.Origin + la * u; var p1 = ray1.Origin + my * v; return 0.5*(p0 + p1); } #endregion #region IEnumerable public static V3d GetMiddlePoint(this IEnumerable rays) { var center = V3d.Zero; var count = 0; foreach(var r0 in rays) foreach (var r1 in rays) if (r0.LexicalCompare(r1) < 0) { center += r0.GetMiddlePoint(r1); ++count; } return center / (double)count; } #endregion } /// /// Provides various methods for closest point computations. /// If the query object is an surface or volume the function /// return to closest point on the surface. /// public static partial class GeometryFun { /* V2f */ #region V2f - Line2f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetClosestPointOn(this V2f query, Line2f line) => GetClosestPointOn(query, line, out float t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetClosestPointOn(this Line2f line, V2f query) => query.GetClosestPointOn(line); public static V2f GetClosestPointOn(this V2f query, Line2f line, out float t) { var p0q = query - line.P0; t = Vec.Dot(p0q, line.Direction); if (t <= 0) { t = 0; return line.P0; } var denom = line.Direction.LengthSquared; if (t >= denom) { t = 1; return line.P1; } t /= denom; return line.P0 + t * line.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetClosestPointOn(this Line2f line, V2f query, out float t) => query.GetClosestPointOn(line, out t); #endregion #region V2f - Ray2f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetClosestPointOn(this V2f query, Ray2f ray) => GetClosestPointOn(query, ray, out float t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetClosestPointOn(this Ray2f ray, V2f query) => query.GetClosestPointOn(ray); /// /// Returns the t-parameter along at which the closest point to is. /// /// Find the closest point on the ray to this point. /// Find the closest point on this ray. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetClosestPointTOn(this V2f query, Ray2f ray) => Vec.Dot(query - ray.Origin, ray.Direction) / ray.Direction.LengthSquared; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetClosestPointOn(this V2f query, Ray2f ray, out float t) { t = GetClosestPointTOn(query, ray); return ray.Origin + t * ray.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetClosestPointOn(this Ray2f ray, V2f query, out float t) => query.GetClosestPointOn(ray, out t); /// /// Returns the t-parameter along at which the closest point to is. /// /// Find the closest point on the ray to this point. /// Find the closest point on this ray. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetClosestPointTOn(this Ray2f ray, V2f query) => query.GetClosestPointTOn(ray); #endregion #region V2f - Plane2f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetClosestPointOn(this V2f point, Plane2f line) { var lengthOfNormal2 = line.Normal.LengthSquared; return (point - (line.Normal.Dot(point - line.Point) / lengthOfNormal2) * line.Normal); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetClosestPointOn(this Plane2f line, V2f point) => point.GetClosestPointOn(line); #endregion #region V2f - Box2f public static V2f GetClosestPointOn(this V2f query, Box2f box) { var closest = query; for (var i = 0; i < 2; i++) { if (query[i] < box.Min[i]) closest[i] = box.Min[i]; if (query[i] > box.Max[i]) closest[i] = box.Max[i]; } return closest; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetClosestPointOn(this Box2f box, V2f query) => query.GetClosestPointOn(box); #endregion #region V2f - Quad2f public static V2f GetClosestPointOn(this V2f vec, Quad2f quad) { V2f closestPoint; var temp = vec.GetClosestPointOn(new Line2f(quad.P0,quad.P1)); closestPoint = temp; temp = vec.GetClosestPointOn(new Line2f(quad.P1, quad.P2)); if ((temp - vec).LengthSquared < (closestPoint - vec).LengthSquared) closestPoint = temp; temp = vec.GetClosestPointOn(new Line2f(quad.P2, quad.P3)); if ((temp - vec).LengthSquared < (closestPoint - vec).LengthSquared) closestPoint = temp; temp = vec.GetClosestPointOn(new Line2f(quad.P3, quad.P0)); if ((temp - vec).LengthSquared < (closestPoint - vec).LengthSquared) closestPoint = temp; return closestPoint; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetClosestPointOn(this Quad2f quad, V2f vec) => vec.GetClosestPointOn(quad); #endregion #region V2f - Polygon2f public static V2f GetClosestPointOn(this V2f vec, Polygon2f poly) { var closestPoint = V2f.PositiveInfinity; var i = 0; foreach (var line in poly.EdgeLines) { var temp = vec.GetClosestPointOn(line); if (i++ == 0) closestPoint = temp; else if ((temp - vec).LengthSquared < (closestPoint - vec).LengthSquared) closestPoint = temp; } return closestPoint; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetClosestPointOn(this Polygon2f poly, V2f vec) => vec.GetClosestPointOn(poly); #endregion #region V2f - Circle2f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetClosestPointOn(this V2f query, Circle2f circle) => circle.Center + circle.Radius * (query - circle.Center).Normalized; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetClosestPointOn(this Circle2f circle, V2f query) => query.GetClosestPointOn(circle); #endregion #region V2f - Triangle2f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetClosestPointOn(this V2f query, Triangle2f triangle) => query.GetClosestPointOnTriangle(triangle.P0, triangle.P1, triangle.P2); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetClosestPointOn(this Triangle2f triangle, V2f query) => query.GetClosestPointOn(triangle); public static V2f GetClosestPointOnTriangle(this V2f query, V2f a, V2f b, V2f c) { var e01 = b - a; var e02 = c - a; var p0q = query - a; var d1 = Vec.Dot(e01, p0q); var d2 = Vec.Dot(e02, p0q); if (d1 <= 0 && d2 <= 0) return a; // bary (1,0,0) var p1q = query - b; var d3 = Vec.Dot(e01, p1q); var d4 = Vec.Dot(e02, p1q); if (d3 >= 0 && d4 <= d3) return b; // bary (0,1,0) var vc = d1 * d4 - d3 * d2; if (vc <= 0 && d1 >= 0 && d3 <= 0) { var t = d1 / (d1 - d3); return a + t * e01; // bary (1-t,t,0) } var p2q = query - c; var d5 = Vec.Dot(e01, p2q); var d6 = Vec.Dot(e02, p2q); if (d6 >= 0 && d5 <= d6) return c; // bary (0,0,1) var vb = d5 * d2 - d1 * d6; if (vb <= 0 && d2 >= 0 && d6 <= 0) { var t = d2 / (d2 - d6); return a + t * e02; // bary (1-t,0,t) } var va = d3 * d6 - d5 * d4; if (va <= 0 && (d4 - d3) >= 0 && (d5 - d6) >= 0) { var t = (d4 - d3) / ((d4 - d3) + (d5 - d6)); return b + t * (c - b); // bary (0, 1-t, t) } // var denom = 1.0 / (va + vb + vc); // var v = vb * denom; // var w = vc * denom; // return triangle.P0 + v * e01 + w * e02; // bary (1-v-w, v, w) return query; } #endregion /* V3f */ #region V3f - Box3f public static float GetDistanceSquared(this V3f q, Box3f b) => (q.X < b.Min.X ? Fun.Square(b.Min.X - q.X) : q.X > b.Max.X ? Fun.Square(q.X - b.Max.X) : 0) + (q.Y < b.Min.Y ? Fun.Square(b.Min.Y - q.Y) : q.Y > b.Max.Y ? Fun.Square(q.Y - b.Max.Y) : 0) + (q.Z < b.Min.Z ? Fun.Square(b.Min.Z - q.Z) : q.Z > b.Max.Z ? Fun.Square(q.Z - b.Max.Z) : 0); public static (float, float) GetDistanceSquared( this V3f q, Box3fAndFlags boxAndFlags, Box.Flags d2Flags, V3f d2v, out Box.Flags d2Flags0, out V3f d2v0, out Box.Flags d2Flags1, out V3f d2v1) { d2Flags0 = d2Flags; d2Flags1 = d2Flags; d2v0 = d2v; d2v1 = d2v; float d0 = 0, d1 = 0; if ((d2Flags & Box.Flags.MinX) != 0) { if ((boxAndFlags.BFlags & Box.Flags.MinX0) != 0) { d2v0.X = Fun.Square(boxAndFlags.BBox.Min.X - q.X); d2Flags0 |= Box.Flags.MinX; } else if ((boxAndFlags.BFlags & Box.Flags.MinX1) != 0) { d2v1.X = Fun.Square(boxAndFlags.BBox.Min.X - q.X); d2Flags1 |= Box.Flags.MinX; } d0 += d2v0.X; d1 += d2v1.X; } else if ((d2Flags & Box.Flags.MaxX) != 0) { if ((boxAndFlags.BFlags & Box.Flags.MaxX0) != 0) { d2v0.X = Fun.Square(boxAndFlags.BBox.Max.X - q.X); d2Flags0 |= Box.Flags.MaxX; } else if ((boxAndFlags.BFlags & Box.Flags.MaxX1) != 0) { d2v1.X = Fun.Square(boxAndFlags.BBox.Max.X - q.X); d2Flags1 |= Box.Flags.MaxX; } d0 += d2v0.X; d1 += d2v1.X; } else { if ((boxAndFlags.BFlags & Box.Flags.MinX0) != 0) { if (q.X < boxAndFlags.BBox.Min.X) { d2v0.X = Fun.Square(boxAndFlags.BBox.Min.X - q.X); d2Flags0 |= Box.Flags.MinX; d0 += d2v0.X; } } else if ((boxAndFlags.BFlags & Box.Flags.MinX1) != 0) { if (q.X < boxAndFlags.BBox.Min.X) { d2v1.X = Fun.Square(boxAndFlags.BBox.Min.X - q.X); d2Flags1 |= Box.Flags.MinX; d1 += d2v1.X; } } if ((boxAndFlags.BFlags & Box.Flags.MaxX0) != 0) { if (q.X > boxAndFlags.BBox.Max.X) { d2v0.X = Fun.Square(boxAndFlags.BBox.Max.X - q.X); d2Flags0 |= Box.Flags.MaxX; d0 += d2v0.X; } } else if ((boxAndFlags.BFlags & Box.Flags.MaxX1) != 0) { if (q.X > boxAndFlags.BBox.Max.X) { d2v1.X = Fun.Square(boxAndFlags.BBox.Max.X - q.X); d2Flags1 |= Box.Flags.MaxX; d1 += d2v1.X; } } } return (d0, d1); } public static V3f GetClosestPointOn(this V3f query, Box3f box) { var closest = query; for (int i = 0; i < 3; i++) { if (query[i] < box.Min[i]) closest[i] = box.Min[i]; if (query[i] > box.Max[i]) closest[i] = box.Max[i]; } return closest; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOn(this Box3f box, V3f query) => query.GetClosestPointOn(box); #endregion #region V3f - Line3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOn(this V3f query, Line3f line) => query.GetClosestPointOnLine(line.P0, line.P1, out float t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOn(this Line3f line, V3f query) => query.GetClosestPointOn(line); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOn(this V3f query, Line3f line, out float t) => query.GetClosestPointOnLine(line.P0, line.P1, out t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOn(this Line3f line, V3f query, out float t) => query.GetClosestPointOn(line, out t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOnLine(this V3f query, V3f p0, V3f p1) => query.GetClosestPointOnLine(p0, p1, out float t); public static V3f GetClosestPointOnLine(this V3f query, V3f p0, V3f p1, out float t) { var dir = p1 - p0; var p0q = query - p0; t = Vec.Dot(p0q, dir); if (t <= 0) { t = 0; return p0; } var denom = dir.LengthSquared; if (t >= denom) { t = 1; return p1; } t /= denom; return p0 + t * dir; } #endregion #region V3f - Plane3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOn(this V3f query, Plane3f plane) => query - plane.Height(query) * plane.Normal; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOn(this Plane3f plane, V3f query) => query.GetClosestPointOn(plane); #endregion #region V3f - Ray3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOn(this V3f query, Ray3f ray) => GetClosestPointOn(query, ray, out float t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOn(this Ray3f ray, V3f query) => query.GetClosestPointOn(ray); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOn(this V3f query, Ray3f ray, out float t) { t = Vec.Dot(query - ray.Origin, ray.Direction) / ray.Direction.LengthSquared; return ray.Origin + t * ray.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOn(this Ray3f ray, V3f query, out float t) => query.GetClosestPointOn(ray, out t); #endregion #region V3f - Sphere3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOn(this V3f query, Sphere3f sphere) => sphere.Center + sphere.Radius * (query - sphere.Center).Normalized; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOn(this Sphere3f sphere, V3f query) => query.GetClosestPointOn(sphere); #endregion #region V3f - Cylinder3f /// /// get closest point on cylinder with infinite length /// public static V3f GetClosestPointOn(this V3f query, Cylinder3f cylinder) { var p = query.GetClosestPointOn(cylinder.Axis.Ray3f); var dir = (query - p).Normalized; return p + cylinder.Radius * dir; } /// /// get closest point on cylinder with infinite length /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOn(this Cylinder3f cylinder, V3f query) => query.GetClosestPointOn(cylinder); #endregion #region V3f - Triangle3f /// /// Tested by rft on 2008-08-06. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOn(this V3f query, Triangle3f triangle) => GetClosestPointOnTriangle(query, triangle.P0, triangle.P1, triangle.P2); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetClosestPointOn(this Triangle3f triangle, V3f query) => query.GetClosestPointOn(triangle); /// /// Tested by rft on 2008-08-06. /// public static V3f GetClosestPointOnTriangle(this V3f query, V3f p0, V3f p1, V3f p2) { var e01 = p1 - p0; var e02 = p2 - p0; var p0q = query - p0; var d1 = Vec.Dot(e01, p0q); var d2 = Vec.Dot(e02, p0q); if (d1 <= 0 && d2 <= 0) return p0; // bary (1,0,0) var p1q = query - p1; var d3 = Vec.Dot(e01, p1q); var d4 = Vec.Dot(e02, p1q); if (d3 >= 0 && d4 <= d3) return p1; // bary (0,1,0) var vc = d1 * d4 - d3 * d2; if (vc <= 0 && d1 >= 0 && d3 <= 0) { var t = d1 / (d1 - d3); return p0 + t * e01; // bary (1-t,t,0) } var p2q = query - p2; var d5 = Vec.Dot(e01, p2q); var d6 = Vec.Dot(e02, p2q); if (d6 >= 0 && d5 <= d6) return p2; // bary (0,0,1) var vb = d5 * d2 - d1 * d6; if (vb <= 0 && d2 >= 0 && d6 <= 0) { var t = d2 / (d2 - d6); return p0 + t * e02; // bary (1-t,0,t) } var va = d3 * d6 - d5 * d4; if (va <= 0 && (d4 - d3) >= 0 && (d5 - d6) >= 0) { var t = (d4 - d3) / ((d4 - d3) + (d5 - d6)); return p1 + t * (p2 - p1); // bary (0, 1-t, t) } float denom = 1 / (va + vb + vc); var v = vb * denom; var w = vc * denom; return p0 + v * e01 + w * e02; // bary (1-v-w, v, w) } #endregion /* Ray3f */ #region Ray3f - Ray3f public static V3f GetClosestPointOn(this Ray3f ray0, Ray3f ray1) { var a = ray0.Origin - ray1.Origin; var u = ray0.Direction.Normalized; var v = ray1.Direction.Normalized; var uDotv = u.Dot(v); var n = (uDotv * uDotv - 1); // make sure rays are not parallel if (!n.Abs().IsTiny()) { var my = (a.Dot(u) * uDotv - a.Dot(v)) / n; return ray1.Origin + my * v; } return ray1.Origin; } #endregion /* Line3f */ #region Line3f - Line3f /// /// Returns the point on line1 which is closest to line0. /// public static V3f GetClosestPointOn(this Line3f line0, Line3f line1) { var r0 = line0.Ray3f; var r1 = line1.Ray3f; if (r0.IsParallelTo(r1)) // t1 and t0 of following computation are invalid if lines are parallel { if (line0.P0.GetMinimalDistanceTo(line1) < line0.P1.GetMinimalDistanceTo(line1)) return line0.P0.GetClosestPointOn(line1); else return line0.P1.GetClosestPointOn(line1); } /* var distance = */ r0.GetMinimalDistanceTo(r1, out float t0, out float t1); if (t0 >= 0 && t0 <= 1 && t1 >= 0 && t1 <= 1) return r1.GetPointOnRay(t1); var d0 = line0.P0.GetMinimalDistanceTo(line1); var d1 = line0.P1.GetMinimalDistanceTo(line1); var d2 = line1.P0.GetMinimalDistanceTo(line0); var d3 = line1.P1.GetMinimalDistanceTo(line0); if (d0 < d1) { if (d0 < d2) return d0 < d3 ? line0.P0.GetClosestPointOn(line1) : line1.P1; else return d2 < d3 ? line1.P0 : line1.P1; } else { if (d1 < d2) return d1 < d3 ? line0.P1.GetClosestPointOn(line1) : line1.P1; else return d2 < d3 ? line1.P0 : line1.P1; } } #endregion #region Line3f - Plane3f /// /// Returns the closest point from a line to a plane (point on line). /// public static V3f GetClosestPointOn(this Plane3f plane, Line3f line) { var ray = line.Ray3f; if (ray.Intersects(plane, out float t)) { var tClamped = t.Clamp(0, 1); // clamp point to line range return ray.GetPointOnRay(tClamped); } else // plane and line are parallel { return line.P0; } } //note: reverse method is not the same (closest point on line) #endregion #region Line3f - Triangle3f /// /// Returns the closest point from a triangle to a line (point on triangle). /// Note: untested /// public static V3f GetClosestPointOn(this Line3f line, Triangle3f triangle) { // test if closest point on triangle plane is inside the triangle (we have the point), // otherwiese find closest edge and take closest point to that edge var plane = triangle.Plane; var planePoint = plane.GetClosestPointOn(line); // switch to 2d: var trafo = Trafo3f.FromNormalFrame(plane.Point, plane.Normal); var point2d = trafo.Backward.TransformPos(planePoint).XY; var triangle2d = new Triangle2f(trafo.Backward.TransformPos(triangle.P0).XY, trafo.Backward.TransformPos(triangle.P1).XY, trafo.Backward.TransformPos(triangle.P2).XY); if (triangle2d.Contains(point2d)) return trafo.Forward.TransformPos(point2d.XYO); var edgeDistances = new [] { line.GetMinimalDistanceTo(triangle.Line01), line.GetMinimalDistanceTo(triangle.Line12), line.GetMinimalDistanceTo(triangle.Line20) }; var closestEdge = triangle.GetEdgeLine(edgeDistances.IndexOfMin()); return line.GetClosestPointOn(closestEdge); } //note: reverse method is not the same (closest point on line) #endregion /* V2d */ #region V2d - Line2d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetClosestPointOn(this V2d query, Line2d line) => GetClosestPointOn(query, line, out double t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetClosestPointOn(this Line2d line, V2d query) => query.GetClosestPointOn(line); public static V2d GetClosestPointOn(this V2d query, Line2d line, out double t) { var p0q = query - line.P0; t = Vec.Dot(p0q, line.Direction); if (t <= 0) { t = 0; return line.P0; } var denom = line.Direction.LengthSquared; if (t >= denom) { t = 1; return line.P1; } t /= denom; return line.P0 + t * line.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetClosestPointOn(this Line2d line, V2d query, out double t) => query.GetClosestPointOn(line, out t); #endregion #region V2d - Ray2d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetClosestPointOn(this V2d query, Ray2d ray) => GetClosestPointOn(query, ray, out double t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetClosestPointOn(this Ray2d ray, V2d query) => query.GetClosestPointOn(ray); /// /// Returns the t-parameter along at which the closest point to is. /// /// Find the closest point on the ray to this point. /// Find the closest point on this ray. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetClosestPointTOn(this V2d query, Ray2d ray) => Vec.Dot(query - ray.Origin, ray.Direction) / ray.Direction.LengthSquared; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetClosestPointOn(this V2d query, Ray2d ray, out double t) { t = GetClosestPointTOn(query, ray); return ray.Origin + t * ray.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetClosestPointOn(this Ray2d ray, V2d query, out double t) => query.GetClosestPointOn(ray, out t); /// /// Returns the t-parameter along at which the closest point to is. /// /// Find the closest point on the ray to this point. /// Find the closest point on this ray. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetClosestPointTOn(this Ray2d ray, V2d query) => query.GetClosestPointTOn(ray); #endregion #region V2d - Plane2d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetClosestPointOn(this V2d point, Plane2d line) { var lengthOfNormal2 = line.Normal.LengthSquared; return (point - (line.Normal.Dot(point - line.Point) / lengthOfNormal2) * line.Normal); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetClosestPointOn(this Plane2d line, V2d point) => point.GetClosestPointOn(line); #endregion #region V2d - Box2d public static V2d GetClosestPointOn(this V2d query, Box2d box) { var closest = query; for (var i = 0; i < 2; i++) { if (query[i] < box.Min[i]) closest[i] = box.Min[i]; if (query[i] > box.Max[i]) closest[i] = box.Max[i]; } return closest; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetClosestPointOn(this Box2d box, V2d query) => query.GetClosestPointOn(box); #endregion #region V2d - Quad2d public static V2d GetClosestPointOn(this V2d vec, Quad2d quad) { V2d closestPoint; var temp = vec.GetClosestPointOn(new Line2d(quad.P0,quad.P1)); closestPoint = temp; temp = vec.GetClosestPointOn(new Line2d(quad.P1, quad.P2)); if ((temp - vec).LengthSquared < (closestPoint - vec).LengthSquared) closestPoint = temp; temp = vec.GetClosestPointOn(new Line2d(quad.P2, quad.P3)); if ((temp - vec).LengthSquared < (closestPoint - vec).LengthSquared) closestPoint = temp; temp = vec.GetClosestPointOn(new Line2d(quad.P3, quad.P0)); if ((temp - vec).LengthSquared < (closestPoint - vec).LengthSquared) closestPoint = temp; return closestPoint; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetClosestPointOn(this Quad2d quad, V2d vec) => vec.GetClosestPointOn(quad); #endregion #region V2d - Polygon2d public static V2d GetClosestPointOn(this V2d vec, Polygon2d poly) { var closestPoint = V2d.PositiveInfinity; var i = 0; foreach (var line in poly.EdgeLines) { var temp = vec.GetClosestPointOn(line); if (i++ == 0) closestPoint = temp; else if ((temp - vec).LengthSquared < (closestPoint - vec).LengthSquared) closestPoint = temp; } return closestPoint; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetClosestPointOn(this Polygon2d poly, V2d vec) => vec.GetClosestPointOn(poly); #endregion #region V2d - Circle2d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetClosestPointOn(this V2d query, Circle2d circle) => circle.Center + circle.Radius * (query - circle.Center).Normalized; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetClosestPointOn(this Circle2d circle, V2d query) => query.GetClosestPointOn(circle); #endregion #region V2d - Triangle2d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetClosestPointOn(this V2d query, Triangle2d triangle) => query.GetClosestPointOnTriangle(triangle.P0, triangle.P1, triangle.P2); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetClosestPointOn(this Triangle2d triangle, V2d query) => query.GetClosestPointOn(triangle); public static V2d GetClosestPointOnTriangle(this V2d query, V2d a, V2d b, V2d c) { var e01 = b - a; var e02 = c - a; var p0q = query - a; var d1 = Vec.Dot(e01, p0q); var d2 = Vec.Dot(e02, p0q); if (d1 <= 0 && d2 <= 0) return a; // bary (1,0,0) var p1q = query - b; var d3 = Vec.Dot(e01, p1q); var d4 = Vec.Dot(e02, p1q); if (d3 >= 0 && d4 <= d3) return b; // bary (0,1,0) var vc = d1 * d4 - d3 * d2; if (vc <= 0 && d1 >= 0 && d3 <= 0) { var t = d1 / (d1 - d3); return a + t * e01; // bary (1-t,t,0) } var p2q = query - c; var d5 = Vec.Dot(e01, p2q); var d6 = Vec.Dot(e02, p2q); if (d6 >= 0 && d5 <= d6) return c; // bary (0,0,1) var vb = d5 * d2 - d1 * d6; if (vb <= 0 && d2 >= 0 && d6 <= 0) { var t = d2 / (d2 - d6); return a + t * e02; // bary (1-t,0,t) } var va = d3 * d6 - d5 * d4; if (va <= 0 && (d4 - d3) >= 0 && (d5 - d6) >= 0) { var t = (d4 - d3) / ((d4 - d3) + (d5 - d6)); return b + t * (c - b); // bary (0, 1-t, t) } // var denom = 1.0 / (va + vb + vc); // var v = vb * denom; // var w = vc * denom; // return triangle.P0 + v * e01 + w * e02; // bary (1-v-w, v, w) return query; } #endregion /* V3d */ #region V3d - Box3d public static double GetDistanceSquared(this V3d q, Box3d b) => (q.X < b.Min.X ? Fun.Square(b.Min.X - q.X) : q.X > b.Max.X ? Fun.Square(q.X - b.Max.X) : 0) + (q.Y < b.Min.Y ? Fun.Square(b.Min.Y - q.Y) : q.Y > b.Max.Y ? Fun.Square(q.Y - b.Max.Y) : 0) + (q.Z < b.Min.Z ? Fun.Square(b.Min.Z - q.Z) : q.Z > b.Max.Z ? Fun.Square(q.Z - b.Max.Z) : 0); public static (double, double) GetDistanceSquared( this V3d q, Box3dAndFlags boxAndFlags, Box.Flags d2Flags, V3d d2v, out Box.Flags d2Flags0, out V3d d2v0, out Box.Flags d2Flags1, out V3d d2v1) { d2Flags0 = d2Flags; d2Flags1 = d2Flags; d2v0 = d2v; d2v1 = d2v; double d0 = 0, d1 = 0; if ((d2Flags & Box.Flags.MinX) != 0) { if ((boxAndFlags.BFlags & Box.Flags.MinX0) != 0) { d2v0.X = Fun.Square(boxAndFlags.BBox.Min.X - q.X); d2Flags0 |= Box.Flags.MinX; } else if ((boxAndFlags.BFlags & Box.Flags.MinX1) != 0) { d2v1.X = Fun.Square(boxAndFlags.BBox.Min.X - q.X); d2Flags1 |= Box.Flags.MinX; } d0 += d2v0.X; d1 += d2v1.X; } else if ((d2Flags & Box.Flags.MaxX) != 0) { if ((boxAndFlags.BFlags & Box.Flags.MaxX0) != 0) { d2v0.X = Fun.Square(boxAndFlags.BBox.Max.X - q.X); d2Flags0 |= Box.Flags.MaxX; } else if ((boxAndFlags.BFlags & Box.Flags.MaxX1) != 0) { d2v1.X = Fun.Square(boxAndFlags.BBox.Max.X - q.X); d2Flags1 |= Box.Flags.MaxX; } d0 += d2v0.X; d1 += d2v1.X; } else { if ((boxAndFlags.BFlags & Box.Flags.MinX0) != 0) { if (q.X < boxAndFlags.BBox.Min.X) { d2v0.X = Fun.Square(boxAndFlags.BBox.Min.X - q.X); d2Flags0 |= Box.Flags.MinX; d0 += d2v0.X; } } else if ((boxAndFlags.BFlags & Box.Flags.MinX1) != 0) { if (q.X < boxAndFlags.BBox.Min.X) { d2v1.X = Fun.Square(boxAndFlags.BBox.Min.X - q.X); d2Flags1 |= Box.Flags.MinX; d1 += d2v1.X; } } if ((boxAndFlags.BFlags & Box.Flags.MaxX0) != 0) { if (q.X > boxAndFlags.BBox.Max.X) { d2v0.X = Fun.Square(boxAndFlags.BBox.Max.X - q.X); d2Flags0 |= Box.Flags.MaxX; d0 += d2v0.X; } } else if ((boxAndFlags.BFlags & Box.Flags.MaxX1) != 0) { if (q.X > boxAndFlags.BBox.Max.X) { d2v1.X = Fun.Square(boxAndFlags.BBox.Max.X - q.X); d2Flags1 |= Box.Flags.MaxX; d1 += d2v1.X; } } } return (d0, d1); } public static V3d GetClosestPointOn(this V3d query, Box3d box) { var closest = query; for (int i = 0; i < 3; i++) { if (query[i] < box.Min[i]) closest[i] = box.Min[i]; if (query[i] > box.Max[i]) closest[i] = box.Max[i]; } return closest; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOn(this Box3d box, V3d query) => query.GetClosestPointOn(box); #endregion #region V3d - Line3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOn(this V3d query, Line3d line) => query.GetClosestPointOnLine(line.P0, line.P1, out double t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOn(this Line3d line, V3d query) => query.GetClosestPointOn(line); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOn(this V3d query, Line3d line, out double t) => query.GetClosestPointOnLine(line.P0, line.P1, out t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOn(this Line3d line, V3d query, out double t) => query.GetClosestPointOn(line, out t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOnLine(this V3d query, V3d p0, V3d p1) => query.GetClosestPointOnLine(p0, p1, out double t); public static V3d GetClosestPointOnLine(this V3d query, V3d p0, V3d p1, out double t) { var dir = p1 - p0; var p0q = query - p0; t = Vec.Dot(p0q, dir); if (t <= 0) { t = 0; return p0; } var denom = dir.LengthSquared; if (t >= denom) { t = 1; return p1; } t /= denom; return p0 + t * dir; } #endregion #region V3d - Plane3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOn(this V3d query, Plane3d plane) => query - plane.Height(query) * plane.Normal; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOn(this Plane3d plane, V3d query) => query.GetClosestPointOn(plane); #endregion #region V3d - Ray3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOn(this V3d query, Ray3d ray) => GetClosestPointOn(query, ray, out double t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOn(this Ray3d ray, V3d query) => query.GetClosestPointOn(ray); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOn(this V3d query, Ray3d ray, out double t) { t = Vec.Dot(query - ray.Origin, ray.Direction) / ray.Direction.LengthSquared; return ray.Origin + t * ray.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOn(this Ray3d ray, V3d query, out double t) => query.GetClosestPointOn(ray, out t); #endregion #region V3d - Sphere3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOn(this V3d query, Sphere3d sphere) => sphere.Center + sphere.Radius * (query - sphere.Center).Normalized; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOn(this Sphere3d sphere, V3d query) => query.GetClosestPointOn(sphere); #endregion #region V3d - Cylinder3d /// /// get closest point on cylinder with infinite length /// public static V3d GetClosestPointOn(this V3d query, Cylinder3d cylinder) { var p = query.GetClosestPointOn(cylinder.Axis.Ray3d); var dir = (query - p).Normalized; return p + cylinder.Radius * dir; } /// /// get closest point on cylinder with infinite length /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOn(this Cylinder3d cylinder, V3d query) => query.GetClosestPointOn(cylinder); #endregion #region V3d - Triangle3d /// /// Tested by rft on 2008-08-06. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOn(this V3d query, Triangle3d triangle) => GetClosestPointOnTriangle(query, triangle.P0, triangle.P1, triangle.P2); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetClosestPointOn(this Triangle3d triangle, V3d query) => query.GetClosestPointOn(triangle); /// /// Tested by rft on 2008-08-06. /// public static V3d GetClosestPointOnTriangle(this V3d query, V3d p0, V3d p1, V3d p2) { var e01 = p1 - p0; var e02 = p2 - p0; var p0q = query - p0; var d1 = Vec.Dot(e01, p0q); var d2 = Vec.Dot(e02, p0q); if (d1 <= 0 && d2 <= 0) return p0; // bary (1,0,0) var p1q = query - p1; var d3 = Vec.Dot(e01, p1q); var d4 = Vec.Dot(e02, p1q); if (d3 >= 0 && d4 <= d3) return p1; // bary (0,1,0) var vc = d1 * d4 - d3 * d2; if (vc <= 0 && d1 >= 0 && d3 <= 0) { var t = d1 / (d1 - d3); return p0 + t * e01; // bary (1-t,t,0) } var p2q = query - p2; var d5 = Vec.Dot(e01, p2q); var d6 = Vec.Dot(e02, p2q); if (d6 >= 0 && d5 <= d6) return p2; // bary (0,0,1) var vb = d5 * d2 - d1 * d6; if (vb <= 0 && d2 >= 0 && d6 <= 0) { var t = d2 / (d2 - d6); return p0 + t * e02; // bary (1-t,0,t) } var va = d3 * d6 - d5 * d4; if (va <= 0 && (d4 - d3) >= 0 && (d5 - d6) >= 0) { var t = (d4 - d3) / ((d4 - d3) + (d5 - d6)); return p1 + t * (p2 - p1); // bary (0, 1-t, t) } double denom = 1 / (va + vb + vc); var v = vb * denom; var w = vc * denom; return p0 + v * e01 + w * e02; // bary (1-v-w, v, w) } #endregion /* Ray3d */ #region Ray3d - Ray3d public static V3d GetClosestPointOn(this Ray3d ray0, Ray3d ray1) { var a = ray0.Origin - ray1.Origin; var u = ray0.Direction.Normalized; var v = ray1.Direction.Normalized; var uDotv = u.Dot(v); var n = (uDotv * uDotv - 1); // make sure rays are not parallel if (!n.Abs().IsTiny()) { var my = (a.Dot(u) * uDotv - a.Dot(v)) / n; return ray1.Origin + my * v; } return ray1.Origin; } #endregion /* Line3d */ #region Line3d - Line3d /// /// Returns the point on line1 which is closest to line0. /// public static V3d GetClosestPointOn(this Line3d line0, Line3d line1) { var r0 = line0.Ray3d; var r1 = line1.Ray3d; if (r0.IsParallelTo(r1)) // t1 and t0 of following computation are invalid if lines are parallel { if (line0.P0.GetMinimalDistanceTo(line1) < line0.P1.GetMinimalDistanceTo(line1)) return line0.P0.GetClosestPointOn(line1); else return line0.P1.GetClosestPointOn(line1); } /* var distance = */ r0.GetMinimalDistanceTo(r1, out double t0, out double t1); if (t0 >= 0 && t0 <= 1 && t1 >= 0 && t1 <= 1) return r1.GetPointOnRay(t1); var d0 = line0.P0.GetMinimalDistanceTo(line1); var d1 = line0.P1.GetMinimalDistanceTo(line1); var d2 = line1.P0.GetMinimalDistanceTo(line0); var d3 = line1.P1.GetMinimalDistanceTo(line0); if (d0 < d1) { if (d0 < d2) return d0 < d3 ? line0.P0.GetClosestPointOn(line1) : line1.P1; else return d2 < d3 ? line1.P0 : line1.P1; } else { if (d1 < d2) return d1 < d3 ? line0.P1.GetClosestPointOn(line1) : line1.P1; else return d2 < d3 ? line1.P0 : line1.P1; } } #endregion #region Line3d - Plane3d /// /// Returns the closest point from a line to a plane (point on line). /// public static V3d GetClosestPointOn(this Plane3d plane, Line3d line) { var ray = line.Ray3d; if (ray.Intersects(plane, out double t)) { var tClamped = t.Clamp(0, 1); // clamp point to line range return ray.GetPointOnRay(tClamped); } else // plane and line are parallel { return line.P0; } } //note: reverse method is not the same (closest point on line) #endregion #region Line3d - Triangle3d /// /// Returns the closest point from a triangle to a line (point on triangle). /// Note: untested /// public static V3d GetClosestPointOn(this Line3d line, Triangle3d triangle) { // test if closest point on triangle plane is inside the triangle (we have the point), // otherwiese find closest edge and take closest point to that edge var plane = triangle.Plane; var planePoint = plane.GetClosestPointOn(line); // switch to 2d: var trafo = Trafo3d.FromNormalFrame(plane.Point, plane.Normal); var point2d = trafo.Backward.TransformPos(planePoint).XY; var triangle2d = new Triangle2d(trafo.Backward.TransformPos(triangle.P0).XY, trafo.Backward.TransformPos(triangle.P1).XY, trafo.Backward.TransformPos(triangle.P2).XY); if (triangle2d.Contains(point2d)) return trafo.Forward.TransformPos(point2d.XYO); var edgeDistances = new [] { line.GetMinimalDistanceTo(triangle.Line01), line.GetMinimalDistanceTo(triangle.Line12), line.GetMinimalDistanceTo(triangle.Line20) }; var closestEdge = triangle.GetEdgeLine(edgeDistances.IndexOfMin()); return line.GetClosestPointOn(closestEdge); } //note: reverse method is not the same (closest point on line) #endregion } public static partial class GeometryFun { #region Range1f - Range1f public static float GetMinimalDistanceTo(this Range1f range0, Range1f range1) { if (range0.Min > range1.Max) return range0.Min - range1.Max; if (range0.Max < range1.Min) return range1.Min - range0.Max; return 0; } #endregion #region Ray2f - Ray2f /// /// returns the minimal distance between the given rays. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this Ray2f ray0, Ray2f ray1) => ray0.GetMinimalDistanceTo(ray1, out float t0, out float t1); /// /// returns the minimal distance between the given rays. /// t0 and t1 hold the correspunding ray parameters. /// if both rays are parallel the t0 and t1 are from the origin of ray1 /// public static float GetMinimalDistanceTo(this Ray2f ray0, Ray2f ray1, out float t0, out float t1) { // NOTE: copy of Ray3f to Ray3f distance var a = ray0.Origin - ray1.Origin; var u = ray0.Direction.Normalized; var v = ray1.Direction.Normalized; var uDotv = u.Dot(v); if (uDotv.Abs().ApproximateEquals(1, Constant.PositiveTinyValue)) // rays are parallel { // return origin of ray 1 t1 = 0; t0 = ray0.GetT(ray1.Origin); } else { // change by lui: added normalization (ortherwise in case the directions are not normalized t0 and t1 are wrong) t1 = (a.Dot(u) * uDotv - a.Dot(v)) / (uDotv * uDotv - 1); t0 = (t1 * uDotv - a.Dot(u)) / ray0.Direction.Length; t1 = t1 / ray1.Direction.Length; } return (t1 * ray1.Direction - a - t0 * ray0.Direction).Length; } #endregion #region Box2f - Box2f public static float GetMinimalDistanceTo(this Box2f box0, Box2f box1) { var distX = box0.RangeX.GetMinimalDistanceTo(box1.RangeX); var distY = box0.RangeY.GetMinimalDistanceTo(box1.RangeY); if (distX == 0 && distY == 0) return 0; else if (distX == 0) return distY; else if (distY == 0) return distX; if (box0.Min.X > box1.Max.X) // 1 is left { if (box0.Min.Y > box1.Max.Y) // 1 is top left return (box0.Corner(0) - box1.Corner(3)).Length; else // 1 is bottom left return (box0.Corner(2) - box1.Corner(1)).Length; } else // 1 is right { if (box0.Min.Y > box1.Max.Y) // 1 is top right return (box0.Corner(1) - box1.Corner(2)).Length; else // 1 is bottom right return (box0.Corner(3) - box1.Corner(0)).Length; } } #endregion #region V2f - Line2f /// /// returns the minimal distance between the point and the Line /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this V2f point, Line2f line) => point.DistanceToLine(line.P0, line.P1); #endregion #region V2f - Triangle2f /// /// returns the minimal distance between the point and the triangle /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this V2f point, Triangle2f t) => Triangle.Distance(t.P0, t.P1, t.P2, point); #endregion #region Line2f - Line2f /// /// returns the minimal distance between the given lines. /// public static float GetMinimalDistanceTo(this Line2f l0, Line2f l1) { var r0 = l0.Ray2f; var r1 = l1.Ray2f; if (!r0.IsParallelTo(r1)) // t1 and t0 of following computation are invalid if lines are parallel { var distance = r0.GetMinimalDistanceTo(r1, out float t0, out float t1); if (t0 >= 0 && t0 <= 1 && t1 >= 0 && t1 <= 1) return distance; } // lines are parallel or t0 and t1 are outside of the line return Fun.Min(l0.P0.GetMinimalDistanceTo(l1), l0.P1.GetMinimalDistanceTo(l1), l1.P0.GetMinimalDistanceTo(l0), l1.P1.GetMinimalDistanceTo(l0)); } #endregion #region V3f - Line3f /// /// returns the minimal distance between the point and the Line /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this V3f point, Line3f line) => point.DistanceToLine(line.P0, line.P1); /// /// Returns the minimal distance between the point and the Line. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this Line3f line, V3f point) => point.GetMinimalDistanceTo(line); #endregion #region V3f - Ray3f /* Performance Test ......................................................................... Faster Method: V3f.MinimalDistanceTo(Ray3f) V3f.MinimalDistanceTo(Ray3f): 1,841s (V3f - V3f.GetClosestPointOn(Ray3f)).Length: 3,058s Total Executions: 10000000 Errors outside tolerance(1E-7): 0 Average Squared-Distance of Results: 2,24116481902135E-32 Speedup-factor: 1,66 */ /// /// Returns the minimal distance between the point and the ray. /// public static float GetMinimalDistanceTo(this V3f point, Ray3f ray) { var a = point - ray.Origin; float lu2 = ray.Direction.LengthSquared; float acu2 = Vec.Cross(a, ray.Direction).LengthSquared; return Fun.Sqrt(acu2 / lu2); } /// /// returns the minimal distance between the point and the Ray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this Ray3f ray, V3f point) => point.GetMinimalDistanceTo(ray); /// /// returns the minimal distance between the point and the Ray. /// t holds the ray parameter for the closest point. /// public static float GetMinimalDistanceTo(this V3f point, Ray3f ray, out float t) { var a = point - ray.Origin; var lu2 = ray.Direction.LengthSquared; var acu2 = Vec.Cross(a, ray.Direction).LengthSquared; var NormalPart2 = acu2 / lu2; var ParallelPart2 = lu2 - NormalPart2; t = Fun.Sqrt(ParallelPart2 / lu2); return Fun.Sqrt(NormalPart2); } /// /// returns the minimal distance between the point and the Ray. /// t holds the ray parameter for the closest point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this Ray3f ray, V3f point, out float t) => point.GetMinimalDistanceTo(ray, out t); #endregion #region V3f - Plane3f /// /// Returns the minimal distance (unsigned) between the point and the plane. /// Use Plane3f.Height to compute the signed height of the point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this V3f point, Plane3f plane) => plane.Height(point).Abs(); /// /// Returns the minimal distance (unsigned) between the point and the plane. /// Use Plane3f.Height to compute the signed height of the point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this Plane3f plane, V3f point) => point.GetMinimalDistanceTo(plane); #endregion #region V3f - Box3f /// /// returns the minimal distance between the point and the box. /// public static float GetMinimalDistanceTo(this V3f point, Box3f box) { var outside = box.OutsideFlags(point); if (outside == 0) return 0; var d = V3f.Zero; if ((outside & Box.Flags.X) != 0) { if ((outside & Box.Flags.MaxX) != 0) d.X = point.X - box.Max.X; else if ((outside & Box.Flags.MinX) != 0) d.X = point.X - box.Min.X; } if ((outside & Box.Flags.Y) != 0) { if ((outside & Box.Flags.MaxY) != 0) d.Y = point.Y - box.Max.Y; else if ((outside & Box.Flags.MinY) != 0) d.Y = point.Y - box.Min.Y; } if ((outside & Box.Flags.Z) != 0) { if ((outside & Box.Flags.MaxZ) != 0) d.Z = point.Z - box.Max.Z; else if ((outside & Box.Flags.MinZ) != 0) d.Z = point.Z - box.Min.Z; } return d.Length; } /// /// returns the minimal distance between the point and the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this Box3f box, V3f point) => point.GetMinimalDistanceTo(box); #endregion #region V3f - Triangle3f /// /// returns the minimal distance between the point and the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this V3f point, Triangle3f triangle) => Triangle.Distance(triangle.P0, triangle.P1, triangle.P2, point); /// /// returns the minimal distance between the point and the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this Triangle3f triangle, V3f point) => point.GetMinimalDistanceTo(triangle); #endregion #region Line3f - Line3f /// /// returns the minimal distance between the given lines. /// public static float GetMinimalDistanceTo(this Line3f l0, Line3f l1) { var r0 = l0.Ray3f; var r1 = l1.Ray3f; if (!r0.IsParallelTo(r1)) // t1 and t0 of following computation are invalid if lines are parallel { var distance = r0.GetMinimalDistanceTo(r1, out float t0, out float t1); if (t0 >= 0 && t0 <= 1 && t1 >= 0 && t1 <= 1) return distance; } // lines are parallel or t0 and t1 are outside of the line return Fun.Min(l0.P0.GetMinimalDistanceTo(l1), l0.P1.GetMinimalDistanceTo(l1), l1.P0.GetMinimalDistanceTo(l0), l1.P1.GetMinimalDistanceTo(l0)); } /// /// returns the minimal distance between the given lines. /// points holds the centroid of the shortest connection between the lines /// public static float GetMinimalDistanceTo(this Line3f l0, Line3f l1, out V3f point) { var r0 = l0.Ray3f; var r1 = l1.Ray3f; var distance = r0.GetMinimalDistanceTo(r1, out float t0, out float t1); if (t0 >= 0 && t0 <= 1 && t1 >= 0 && t1 <= 1) { point = 0.5f * (r0.GetPointOnRay(t0) + r1.GetPointOnRay(t1)); return distance; } else { float t; if (t0 < 0 || t0 > 1) { if (t0 < 0) t0 = 0; else t0 = 1; distance = r0.GetPointOnRay(t0).GetMinimalDistanceTo(r1, out t); if (t >= 0 && t <= 1) { point = 0.5f * (r0.GetPointOnRay(t0) + r1.GetPointOnRay(t)); return distance; } } if (t1 < 0 || t1 > 1) { if (t1 < 0) t1 = 0; else t1 = 1; distance = r1.GetPointOnRay(t1).GetMinimalDistanceTo(r0, out t); if (t >= 0 && t <= 1) { point = 0.5f * (r0.GetPointOnRay(t) + r1.GetPointOnRay(t1)); return distance; } } } point = 0.5f * (r0.GetPointOnRay(t0) + r1.GetPointOnRay(t1)); return (r0.GetPointOnRay(t0) - r1.GetPointOnRay(t1)).Length; } #endregion #region Line3f - Plane3f [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this Line3f line, Plane3f plane) => plane.Height(GeometryFun.GetClosestPointOn(plane, line)).Abs(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this Plane3f plane, Line3f line) => line.GetMinimalDistanceTo(plane); #endregion #region Ray3f - Line3f /// /// returns the minimal distance between the ray and the line. /// public static float GetMinimalDistanceTo(this Ray3f ray, Line3f line) { var r1 = line.Ray3f; var distance = ray.GetMinimalDistanceTo(r1, out float t0, out float t1); if (t1 >= 0 && t1 <= 1) return distance; else { if (t1 < 0) t1 = 0; if (t1 > 1) t1 = 1; var p1 = r1.GetPointOnRay(t1); return p1.GetMinimalDistanceTo(ray); } } /// /// returns the minimal distance between the ray and the line. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this Line3f line, Ray3f ray) => ray.GetMinimalDistanceTo(line); /// /// returns the minimal distance between the ray and the line. /// t holds the correspoinding ray parameter. /// public static float GetMinimalDistanceTo(this Ray3f ray, Line3f line, out float t) { var r1 = line.Ray3f; var distance = ray.GetMinimalDistanceTo(r1, out float t0, out float t1); if (t1 >= 0 && t1 <= 1) { t = t0; return distance; } else { if (t1 < 0) t1 = 0; if (t1 > 1) t1 = 1; var p1 = r1.GetPointOnRay(t1); return p1.GetMinimalDistanceTo(ray, out t); } } /// /// returns the minimal distance between the ray and the line. /// t holds the correspoinding ray parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this Line3f line, Ray3f ray, out float t) => ray.GetMinimalDistanceTo(line, out t); #endregion #region Ray3f - Ray3f /// /// returns the minimal distance between the given rays. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMinimalDistanceTo(this Ray3f ray0, Ray3f ray1) => ray0.GetMinimalDistanceTo(ray1, out float t0, out float t1); /// /// returns the minimal distance between the given rays. /// t0 and t1 hold the correspunding ray parameters. /// if both rays are parallel the t0 and t1 are from the origin of ray1 /// public static float GetMinimalDistanceTo(this Ray3f ray0, Ray3f ray1, out float t0, out float t1) { // TODO: computation probalby possible without Direction.Normalized and Direction.Length var a = ray0.Origin - ray1.Origin; var u = ray0.Direction.Normalized; var v = ray1.Direction.Normalized; var uDotv = u.Dot(v); if (uDotv.Abs().ApproximateEquals(1, Constant.PositiveTinyValue)) // rays are parallel { // return origin of ray 1 t1 = 0; t0 = ray0.GetTOfProjectedPoint(ray1.Origin); } else { // change by lui: added normalization (ortherwise in case the directions are not normalized t0 and t1 are wrong) t1 = (a.Dot(u) * uDotv - a.Dot(v)) / (uDotv * uDotv - 1); t0 = (t1 * uDotv - a.Dot(u)) / ray0.Direction.Length; t1 = t1 / ray1.Direction.Length; } return (t1 * ray1.Direction - a - t0 * ray0.Direction).Length; } #endregion #region Range1d - Range1d public static double GetMinimalDistanceTo(this Range1d range0, Range1d range1) { if (range0.Min > range1.Max) return range0.Min - range1.Max; if (range0.Max < range1.Min) return range1.Min - range0.Max; return 0; } #endregion #region Ray2d - Ray2d /// /// returns the minimal distance between the given rays. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this Ray2d ray0, Ray2d ray1) => ray0.GetMinimalDistanceTo(ray1, out double t0, out double t1); /// /// returns the minimal distance between the given rays. /// t0 and t1 hold the correspunding ray parameters. /// if both rays are parallel the t0 and t1 are from the origin of ray1 /// public static double GetMinimalDistanceTo(this Ray2d ray0, Ray2d ray1, out double t0, out double t1) { // NOTE: copy of Ray3d to Ray3d distance var a = ray0.Origin - ray1.Origin; var u = ray0.Direction.Normalized; var v = ray1.Direction.Normalized; var uDotv = u.Dot(v); if (uDotv.Abs().ApproximateEquals(1, Constant.PositiveTinyValue)) // rays are parallel { // return origin of ray 1 t1 = 0; t0 = ray0.GetT(ray1.Origin); } else { // change by lui: added normalization (ortherwise in case the directions are not normalized t0 and t1 are wrong) t1 = (a.Dot(u) * uDotv - a.Dot(v)) / (uDotv * uDotv - 1); t0 = (t1 * uDotv - a.Dot(u)) / ray0.Direction.Length; t1 = t1 / ray1.Direction.Length; } return (t1 * ray1.Direction - a - t0 * ray0.Direction).Length; } #endregion #region Box2d - Box2d public static double GetMinimalDistanceTo(this Box2d box0, Box2d box1) { var distX = box0.RangeX.GetMinimalDistanceTo(box1.RangeX); var distY = box0.RangeY.GetMinimalDistanceTo(box1.RangeY); if (distX == 0 && distY == 0) return 0; else if (distX == 0) return distY; else if (distY == 0) return distX; if (box0.Min.X > box1.Max.X) // 1 is left { if (box0.Min.Y > box1.Max.Y) // 1 is top left return (box0.Corner(0) - box1.Corner(3)).Length; else // 1 is bottom left return (box0.Corner(2) - box1.Corner(1)).Length; } else // 1 is right { if (box0.Min.Y > box1.Max.Y) // 1 is top right return (box0.Corner(1) - box1.Corner(2)).Length; else // 1 is bottom right return (box0.Corner(3) - box1.Corner(0)).Length; } } #endregion #region V2d - Line2d /// /// returns the minimal distance between the point and the Line /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this V2d point, Line2d line) => point.DistanceToLine(line.P0, line.P1); #endregion #region V2d - Triangle2d /// /// returns the minimal distance between the point and the triangle /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this V2d point, Triangle2d t) => Triangle.Distance(t.P0, t.P1, t.P2, point); #endregion #region Line2d - Line2d /// /// returns the minimal distance between the given lines. /// public static double GetMinimalDistanceTo(this Line2d l0, Line2d l1) { var r0 = l0.Ray2d; var r1 = l1.Ray2d; if (!r0.IsParallelTo(r1)) // t1 and t0 of following computation are invalid if lines are parallel { var distance = r0.GetMinimalDistanceTo(r1, out double t0, out double t1); if (t0 >= 0 && t0 <= 1 && t1 >= 0 && t1 <= 1) return distance; } // lines are parallel or t0 and t1 are outside of the line return Fun.Min(l0.P0.GetMinimalDistanceTo(l1), l0.P1.GetMinimalDistanceTo(l1), l1.P0.GetMinimalDistanceTo(l0), l1.P1.GetMinimalDistanceTo(l0)); } #endregion #region V3d - Line3d /// /// returns the minimal distance between the point and the Line /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this V3d point, Line3d line) => point.DistanceToLine(line.P0, line.P1); /// /// Returns the minimal distance between the point and the Line. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this Line3d line, V3d point) => point.GetMinimalDistanceTo(line); #endregion #region V3d - Ray3d /* Performance Test ......................................................................... Faster Method: V3d.MinimalDistanceTo(Ray3d) V3d.MinimalDistanceTo(Ray3d): 1,841s (V3d - V3d.GetClosestPointOn(Ray3d)).Length: 3,058s Total Executions: 10000000 Errors outside tolerance(1E-7): 0 Average Squared-Distance of Results: 2,24116481902135E-32 Speedup-factor: 1,66 */ /// /// Returns the minimal distance between the point and the ray. /// public static double GetMinimalDistanceTo(this V3d point, Ray3d ray) { var a = point - ray.Origin; double lu2 = ray.Direction.LengthSquared; double acu2 = Vec.Cross(a, ray.Direction).LengthSquared; return Fun.Sqrt(acu2 / lu2); } /// /// returns the minimal distance between the point and the Ray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this Ray3d ray, V3d point) => point.GetMinimalDistanceTo(ray); /// /// returns the minimal distance between the point and the Ray. /// t holds the ray parameter for the closest point. /// public static double GetMinimalDistanceTo(this V3d point, Ray3d ray, out double t) { var a = point - ray.Origin; var lu2 = ray.Direction.LengthSquared; var acu2 = Vec.Cross(a, ray.Direction).LengthSquared; var NormalPart2 = acu2 / lu2; var ParallelPart2 = lu2 - NormalPart2; t = Fun.Sqrt(ParallelPart2 / lu2); return Fun.Sqrt(NormalPart2); } /// /// returns the minimal distance between the point and the Ray. /// t holds the ray parameter for the closest point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this Ray3d ray, V3d point, out double t) => point.GetMinimalDistanceTo(ray, out t); #endregion #region V3d - Plane3d /// /// Returns the minimal distance (unsigned) between the point and the plane. /// Use Plane3d.Height to compute the signed height of the point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this V3d point, Plane3d plane) => plane.Height(point).Abs(); /// /// Returns the minimal distance (unsigned) between the point and the plane. /// Use Plane3d.Height to compute the signed height of the point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this Plane3d plane, V3d point) => point.GetMinimalDistanceTo(plane); #endregion #region V3d - Box3d /// /// returns the minimal distance between the point and the box. /// public static double GetMinimalDistanceTo(this V3d point, Box3d box) { var outside = box.OutsideFlags(point); if (outside == 0) return 0; var d = V3d.Zero; if ((outside & Box.Flags.X) != 0) { if ((outside & Box.Flags.MaxX) != 0) d.X = point.X - box.Max.X; else if ((outside & Box.Flags.MinX) != 0) d.X = point.X - box.Min.X; } if ((outside & Box.Flags.Y) != 0) { if ((outside & Box.Flags.MaxY) != 0) d.Y = point.Y - box.Max.Y; else if ((outside & Box.Flags.MinY) != 0) d.Y = point.Y - box.Min.Y; } if ((outside & Box.Flags.Z) != 0) { if ((outside & Box.Flags.MaxZ) != 0) d.Z = point.Z - box.Max.Z; else if ((outside & Box.Flags.MinZ) != 0) d.Z = point.Z - box.Min.Z; } return d.Length; } /// /// returns the minimal distance between the point and the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this Box3d box, V3d point) => point.GetMinimalDistanceTo(box); #endregion #region V3d - Triangle3d /// /// returns the minimal distance between the point and the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this V3d point, Triangle3d triangle) => Triangle.Distance(triangle.P0, triangle.P1, triangle.P2, point); /// /// returns the minimal distance between the point and the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this Triangle3d triangle, V3d point) => point.GetMinimalDistanceTo(triangle); #endregion #region Line3d - Line3d /// /// returns the minimal distance between the given lines. /// public static double GetMinimalDistanceTo(this Line3d l0, Line3d l1) { var r0 = l0.Ray3d; var r1 = l1.Ray3d; if (!r0.IsParallelTo(r1)) // t1 and t0 of following computation are invalid if lines are parallel { var distance = r0.GetMinimalDistanceTo(r1, out double t0, out double t1); if (t0 >= 0 && t0 <= 1 && t1 >= 0 && t1 <= 1) return distance; } // lines are parallel or t0 and t1 are outside of the line return Fun.Min(l0.P0.GetMinimalDistanceTo(l1), l0.P1.GetMinimalDistanceTo(l1), l1.P0.GetMinimalDistanceTo(l0), l1.P1.GetMinimalDistanceTo(l0)); } /// /// returns the minimal distance between the given lines. /// points holds the centroid of the shortest connection between the lines /// public static double GetMinimalDistanceTo(this Line3d l0, Line3d l1, out V3d point) { var r0 = l0.Ray3d; var r1 = l1.Ray3d; var distance = r0.GetMinimalDistanceTo(r1, out double t0, out double t1); if (t0 >= 0 && t0 <= 1 && t1 >= 0 && t1 <= 1) { point = 0.5 * (r0.GetPointOnRay(t0) + r1.GetPointOnRay(t1)); return distance; } else { double t; if (t0 < 0 || t0 > 1) { if (t0 < 0) t0 = 0; else t0 = 1; distance = r0.GetPointOnRay(t0).GetMinimalDistanceTo(r1, out t); if (t >= 0 && t <= 1) { point = 0.5 * (r0.GetPointOnRay(t0) + r1.GetPointOnRay(t)); return distance; } } if (t1 < 0 || t1 > 1) { if (t1 < 0) t1 = 0; else t1 = 1; distance = r1.GetPointOnRay(t1).GetMinimalDistanceTo(r0, out t); if (t >= 0 && t <= 1) { point = 0.5 * (r0.GetPointOnRay(t) + r1.GetPointOnRay(t1)); return distance; } } } point = 0.5 * (r0.GetPointOnRay(t0) + r1.GetPointOnRay(t1)); return (r0.GetPointOnRay(t0) - r1.GetPointOnRay(t1)).Length; } #endregion #region Line3d - Plane3d [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this Line3d line, Plane3d plane) => plane.Height(GeometryFun.GetClosestPointOn(plane, line)).Abs(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this Plane3d plane, Line3d line) => line.GetMinimalDistanceTo(plane); #endregion #region Ray3d - Line3d /// /// returns the minimal distance between the ray and the line. /// public static double GetMinimalDistanceTo(this Ray3d ray, Line3d line) { var r1 = line.Ray3d; var distance = ray.GetMinimalDistanceTo(r1, out double t0, out double t1); if (t1 >= 0 && t1 <= 1) return distance; else { if (t1 < 0) t1 = 0; if (t1 > 1) t1 = 1; var p1 = r1.GetPointOnRay(t1); return p1.GetMinimalDistanceTo(ray); } } /// /// returns the minimal distance between the ray and the line. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this Line3d line, Ray3d ray) => ray.GetMinimalDistanceTo(line); /// /// returns the minimal distance between the ray and the line. /// t holds the correspoinding ray parameter. /// public static double GetMinimalDistanceTo(this Ray3d ray, Line3d line, out double t) { var r1 = line.Ray3d; var distance = ray.GetMinimalDistanceTo(r1, out double t0, out double t1); if (t1 >= 0 && t1 <= 1) { t = t0; return distance; } else { if (t1 < 0) t1 = 0; if (t1 > 1) t1 = 1; var p1 = r1.GetPointOnRay(t1); return p1.GetMinimalDistanceTo(ray, out t); } } /// /// returns the minimal distance between the ray and the line. /// t holds the correspoinding ray parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this Line3d line, Ray3d ray, out double t) => ray.GetMinimalDistanceTo(line, out t); #endregion #region Ray3d - Ray3d /// /// returns the minimal distance between the given rays. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetMinimalDistanceTo(this Ray3d ray0, Ray3d ray1) => ray0.GetMinimalDistanceTo(ray1, out double t0, out double t1); /// /// returns the minimal distance between the given rays. /// t0 and t1 hold the correspunding ray parameters. /// if both rays are parallel the t0 and t1 are from the origin of ray1 /// public static double GetMinimalDistanceTo(this Ray3d ray0, Ray3d ray1, out double t0, out double t1) { // TODO: computation probalby possible without Direction.Normalized and Direction.Length var a = ray0.Origin - ray1.Origin; var u = ray0.Direction.Normalized; var v = ray1.Direction.Normalized; var uDotv = u.Dot(v); if (uDotv.Abs().ApproximateEquals(1, Constant.PositiveTinyValue)) // rays are parallel { // return origin of ray 1 t1 = 0; t0 = ray0.GetTOfProjectedPoint(ray1.Origin); } else { // change by lui: added normalization (ortherwise in case the directions are not normalized t0 and t1 are wrong) t1 = (a.Dot(u) * uDotv - a.Dot(v)) / (uDotv * uDotv - 1); t0 = (t1 * uDotv - a.Dot(u)) / ray0.Direction.Length; t1 = t1 / ray1.Direction.Length; } return (t1 * ray1.Direction - a - t0 * ray0.Direction).Length; } #endregion } } ================================================ FILE: src/Aardvark.Base/Geometry/SpecialPoints_template.cs ================================================ using System.Collections.Generic; using System.Runtime.CompilerServices; namespace Aardvark.Base { /// /// Provides various methods for middle point computations. /// public static partial class GeometryFun { //# foreach (var isDouble in new[] { false, true }) { //# var rtype = isDouble ? "double" : "float"; //# var tc = isDouble ? "d" : "f"; //# var v3t = "V3" + tc; //# var ray3t = "Ray3" + tc; //# var half = isDouble ? "0.5" : "0.5f"; /* __ray3t__ */ #region __ray3t__ - __ray3t__ public static __v3t__ GetMiddlePoint(this __ray3t__ ray0, __ray3t__ ray1) { var a = ray0.Origin - ray1.Origin; var u = ray0.Direction.Normalized; var v = ray1.Direction.Normalized; var uDotv = u.Dot(v); var my = (a.Dot(u) * uDotv - a.Dot(v)) / (uDotv * uDotv - 1); var la = (my * uDotv - a.Dot(u)); var p0 = ray0.Origin + la * u; var p1 = ray1.Origin + my * v; return __half__*(p0 + p1); } #endregion #region IEnumerable<__ray3t__> public static __v3t__ GetMiddlePoint(this IEnumerable<__ray3t__> rays) { var center = __v3t__.Zero; var count = 0; foreach(var r0 in rays) foreach (var r1 in rays) if (r0.LexicalCompare(r1) < 0) { center += r0.GetMiddlePoint(r1); ++count; } return center / (__rtype__)count; } #endregion //# } } /// /// Provides various methods for closest point computations. /// If the query object is an surface or volume the function /// return to closest point on the surface. /// public static partial class GeometryFun { //# foreach (var isDouble in new[] { false, true }) { //# var rtype = isDouble ? "double" : "float"; //# var tc = isDouble ? "d" : "f"; //# var v2t = "V2" + tc; //# var v3t = "V3" + tc; //# var line2t = "Line2" + tc; //# var line3t = "Line3" + tc; //# var plane2t = "Plane2" + tc; //# var plane3t = "Plane3" + tc; //# var ray2t = "Ray2" + tc; //# var ray3t = "Ray3" + tc; //# var circle2t = "Circle2" + tc; //# var circle3t = "Circle3" + tc; //# var quad2t = "Quad2" + tc; //# var quad3t = "Quad3" + tc; //# var range1t = "Range1" + tc; //# var box2t = "Box2" + tc; //# var box3t = "Box3" + tc; //# var hull2t = "Hull2" + tc; //# var hull3t = "Hull3" + tc; //# var sphere3t = "Sphere3" + tc; //# var cylinder3t = "Cylinder3" + tc; //# var ellipse3t = "Ellipse3" + tc; //# var triangle2t = "Triangle2" + tc; //# var triangle3t = "Triangle3" + tc; //# var polygon2t = "Polygon2" + tc; //# var polygon3t = "Polygon3" + tc; //# var trafo3t = "Trafo3" + tc; //# var half = isDouble ? "0.5" : "0.5f"; /* __v2t__ */ #region __v2t__ - __line2t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ GetClosestPointOn(this __v2t__ query, __line2t__ line) => GetClosestPointOn(query, line, out __rtype__ t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ GetClosestPointOn(this __line2t__ line, __v2t__ query) => query.GetClosestPointOn(line); public static __v2t__ GetClosestPointOn(this __v2t__ query, __line2t__ line, out __rtype__ t) { var p0q = query - line.P0; t = Vec.Dot(p0q, line.Direction); if (t <= 0) { t = 0; return line.P0; } var denom = line.Direction.LengthSquared; if (t >= denom) { t = 1; return line.P1; } t /= denom; return line.P0 + t * line.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ GetClosestPointOn(this __line2t__ line, __v2t__ query, out __rtype__ t) => query.GetClosestPointOn(line, out t); #endregion #region __v2t__ - __ray2t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ GetClosestPointOn(this __v2t__ query, __ray2t__ ray) => GetClosestPointOn(query, ray, out __rtype__ t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ GetClosestPointOn(this __ray2t__ ray, __v2t__ query) => query.GetClosestPointOn(ray); /// /// Returns the t-parameter along at which the closest point to is. /// /// Find the closest point on the ray to this point. /// Find the closest point on this ray. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetClosestPointTOn(this __v2t__ query, __ray2t__ ray) => Vec.Dot(query - ray.Origin, ray.Direction) / ray.Direction.LengthSquared; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ GetClosestPointOn(this __v2t__ query, __ray2t__ ray, out __rtype__ t) { t = GetClosestPointTOn(query, ray); return ray.Origin + t * ray.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ GetClosestPointOn(this __ray2t__ ray, __v2t__ query, out __rtype__ t) => query.GetClosestPointOn(ray, out t); /// /// Returns the t-parameter along at which the closest point to is. /// /// Find the closest point on the ray to this point. /// Find the closest point on this ray. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetClosestPointTOn(this __ray2t__ ray, __v2t__ query) => query.GetClosestPointTOn(ray); #endregion #region __v2t__ - __plane2t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ GetClosestPointOn(this __v2t__ point, __plane2t__ line) { var lengthOfNormal2 = line.Normal.LengthSquared; return (point - (line.Normal.Dot(point - line.Point) / lengthOfNormal2) * line.Normal); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ GetClosestPointOn(this __plane2t__ line, __v2t__ point) => point.GetClosestPointOn(line); #endregion #region __v2t__ - __box2t__ public static __v2t__ GetClosestPointOn(this __v2t__ query, __box2t__ box) { var closest = query; for (var i = 0; i < 2; i++) { if (query[i] < box.Min[i]) closest[i] = box.Min[i]; if (query[i] > box.Max[i]) closest[i] = box.Max[i]; } return closest; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ GetClosestPointOn(this __box2t__ box, __v2t__ query) => query.GetClosestPointOn(box); #endregion #region __v2t__ - __quad2t__ public static __v2t__ GetClosestPointOn(this __v2t__ vec, __quad2t__ quad) { __v2t__ closestPoint; var temp = vec.GetClosestPointOn(new __line2t__(quad.P0,quad.P1)); closestPoint = temp; temp = vec.GetClosestPointOn(new __line2t__(quad.P1, quad.P2)); if ((temp - vec).LengthSquared < (closestPoint - vec).LengthSquared) closestPoint = temp; temp = vec.GetClosestPointOn(new __line2t__(quad.P2, quad.P3)); if ((temp - vec).LengthSquared < (closestPoint - vec).LengthSquared) closestPoint = temp; temp = vec.GetClosestPointOn(new __line2t__(quad.P3, quad.P0)); if ((temp - vec).LengthSquared < (closestPoint - vec).LengthSquared) closestPoint = temp; return closestPoint; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ GetClosestPointOn(this __quad2t__ quad, __v2t__ vec) => vec.GetClosestPointOn(quad); #endregion #region __v2t__ - __polygon2t__ public static __v2t__ GetClosestPointOn(this __v2t__ vec, __polygon2t__ poly) { var closestPoint = __v2t__.PositiveInfinity; var i = 0; foreach (var line in poly.EdgeLines) { var temp = vec.GetClosestPointOn(line); if (i++ == 0) closestPoint = temp; else if ((temp - vec).LengthSquared < (closestPoint - vec).LengthSquared) closestPoint = temp; } return closestPoint; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ GetClosestPointOn(this __polygon2t__ poly, __v2t__ vec) => vec.GetClosestPointOn(poly); #endregion #region __v2t__ - __circle2t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ GetClosestPointOn(this __v2t__ query, __circle2t__ circle) => circle.Center + circle.Radius * (query - circle.Center).Normalized; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ GetClosestPointOn(this __circle2t__ circle, __v2t__ query) => query.GetClosestPointOn(circle); #endregion #region __v2t__ - __triangle2t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ GetClosestPointOn(this __v2t__ query, __triangle2t__ triangle) => query.GetClosestPointOnTriangle(triangle.P0, triangle.P1, triangle.P2); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ GetClosestPointOn(this __triangle2t__ triangle, __v2t__ query) => query.GetClosestPointOn(triangle); public static __v2t__ GetClosestPointOnTriangle(this __v2t__ query, __v2t__ a, __v2t__ b, __v2t__ c) { var e01 = b - a; var e02 = c - a; var p0q = query - a; var d1 = Vec.Dot(e01, p0q); var d2 = Vec.Dot(e02, p0q); if (d1 <= 0 && d2 <= 0) return a; // bary (1,0,0) var p1q = query - b; var d3 = Vec.Dot(e01, p1q); var d4 = Vec.Dot(e02, p1q); if (d3 >= 0 && d4 <= d3) return b; // bary (0,1,0) var vc = d1 * d4 - d3 * d2; if (vc <= 0 && d1 >= 0 && d3 <= 0) { var t = d1 / (d1 - d3); return a + t * e01; // bary (1-t,t,0) } var p2q = query - c; var d5 = Vec.Dot(e01, p2q); var d6 = Vec.Dot(e02, p2q); if (d6 >= 0 && d5 <= d6) return c; // bary (0,0,1) var vb = d5 * d2 - d1 * d6; if (vb <= 0 && d2 >= 0 && d6 <= 0) { var t = d2 / (d2 - d6); return a + t * e02; // bary (1-t,0,t) } var va = d3 * d6 - d5 * d4; if (va <= 0 && (d4 - d3) >= 0 && (d5 - d6) >= 0) { var t = (d4 - d3) / ((d4 - d3) + (d5 - d6)); return b + t * (c - b); // bary (0, 1-t, t) } // var denom = 1.0 / (va + vb + vc); // var v = vb * denom; // var w = vc * denom; // return triangle.P0 + v * e01 + w * e02; // bary (1-v-w, v, w) return query; } #endregion /* __v3t__ */ #region __v3t__ - __box3t__ public static __rtype__ GetDistanceSquared(this __v3t__ q, __box3t__ b) => (q.X < b.Min.X ? Fun.Square(b.Min.X - q.X) : q.X > b.Max.X ? Fun.Square(q.X - b.Max.X) : 0) + (q.Y < b.Min.Y ? Fun.Square(b.Min.Y - q.Y) : q.Y > b.Max.Y ? Fun.Square(q.Y - b.Max.Y) : 0) + (q.Z < b.Min.Z ? Fun.Square(b.Min.Z - q.Z) : q.Z > b.Max.Z ? Fun.Square(q.Z - b.Max.Z) : 0); public static (__rtype__, __rtype__) GetDistanceSquared( this __v3t__ q, __box3t__AndFlags boxAndFlags, Box.Flags d2Flags, __v3t__ d2v, out Box.Flags d2Flags0, out __v3t__ d2v0, out Box.Flags d2Flags1, out __v3t__ d2v1) { d2Flags0 = d2Flags; d2Flags1 = d2Flags; d2v0 = d2v; d2v1 = d2v; __rtype__ d0 = 0, d1 = 0; if ((d2Flags & Box.Flags.MinX) != 0) { if ((boxAndFlags.BFlags & Box.Flags.MinX0) != 0) { d2v0.X = Fun.Square(boxAndFlags.BBox.Min.X - q.X); d2Flags0 |= Box.Flags.MinX; } else if ((boxAndFlags.BFlags & Box.Flags.MinX1) != 0) { d2v1.X = Fun.Square(boxAndFlags.BBox.Min.X - q.X); d2Flags1 |= Box.Flags.MinX; } d0 += d2v0.X; d1 += d2v1.X; } else if ((d2Flags & Box.Flags.MaxX) != 0) { if ((boxAndFlags.BFlags & Box.Flags.MaxX0) != 0) { d2v0.X = Fun.Square(boxAndFlags.BBox.Max.X - q.X); d2Flags0 |= Box.Flags.MaxX; } else if ((boxAndFlags.BFlags & Box.Flags.MaxX1) != 0) { d2v1.X = Fun.Square(boxAndFlags.BBox.Max.X - q.X); d2Flags1 |= Box.Flags.MaxX; } d0 += d2v0.X; d1 += d2v1.X; } else { if ((boxAndFlags.BFlags & Box.Flags.MinX0) != 0) { if (q.X < boxAndFlags.BBox.Min.X) { d2v0.X = Fun.Square(boxAndFlags.BBox.Min.X - q.X); d2Flags0 |= Box.Flags.MinX; d0 += d2v0.X; } } else if ((boxAndFlags.BFlags & Box.Flags.MinX1) != 0) { if (q.X < boxAndFlags.BBox.Min.X) { d2v1.X = Fun.Square(boxAndFlags.BBox.Min.X - q.X); d2Flags1 |= Box.Flags.MinX; d1 += d2v1.X; } } if ((boxAndFlags.BFlags & Box.Flags.MaxX0) != 0) { if (q.X > boxAndFlags.BBox.Max.X) { d2v0.X = Fun.Square(boxAndFlags.BBox.Max.X - q.X); d2Flags0 |= Box.Flags.MaxX; d0 += d2v0.X; } } else if ((boxAndFlags.BFlags & Box.Flags.MaxX1) != 0) { if (q.X > boxAndFlags.BBox.Max.X) { d2v1.X = Fun.Square(boxAndFlags.BBox.Max.X - q.X); d2Flags1 |= Box.Flags.MaxX; d1 += d2v1.X; } } } return (d0, d1); } public static __v3t__ GetClosestPointOn(this __v3t__ query, __box3t__ box) { var closest = query; for (int i = 0; i < 3; i++) { if (query[i] < box.Min[i]) closest[i] = box.Min[i]; if (query[i] > box.Max[i]) closest[i] = box.Max[i]; } return closest; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOn(this __box3t__ box, __v3t__ query) => query.GetClosestPointOn(box); #endregion #region __v3t__ - __line3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOn(this __v3t__ query, __line3t__ line) => query.GetClosestPointOnLine(line.P0, line.P1, out __rtype__ t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOn(this __line3t__ line, __v3t__ query) => query.GetClosestPointOn(line); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOn(this __v3t__ query, __line3t__ line, out __rtype__ t) => query.GetClosestPointOnLine(line.P0, line.P1, out t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOn(this __line3t__ line, __v3t__ query, out __rtype__ t) => query.GetClosestPointOn(line, out t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOnLine(this __v3t__ query, __v3t__ p0, __v3t__ p1) => query.GetClosestPointOnLine(p0, p1, out __rtype__ t); public static __v3t__ GetClosestPointOnLine(this __v3t__ query, __v3t__ p0, __v3t__ p1, out __rtype__ t) { var dir = p1 - p0; var p0q = query - p0; t = Vec.Dot(p0q, dir); if (t <= 0) { t = 0; return p0; } var denom = dir.LengthSquared; if (t >= denom) { t = 1; return p1; } t /= denom; return p0 + t * dir; } #endregion #region __v3t__ - __plane3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOn(this __v3t__ query, __plane3t__ plane) => query - plane.Height(query) * plane.Normal; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOn(this __plane3t__ plane, __v3t__ query) => query.GetClosestPointOn(plane); #endregion #region __v3t__ - __ray3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOn(this __v3t__ query, __ray3t__ ray) => GetClosestPointOn(query, ray, out __rtype__ t); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOn(this __ray3t__ ray, __v3t__ query) => query.GetClosestPointOn(ray); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOn(this __v3t__ query, __ray3t__ ray, out __rtype__ t) { t = Vec.Dot(query - ray.Origin, ray.Direction) / ray.Direction.LengthSquared; return ray.Origin + t * ray.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOn(this __ray3t__ ray, __v3t__ query, out __rtype__ t) => query.GetClosestPointOn(ray, out t); #endregion #region __v3t__ - __sphere3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOn(this __v3t__ query, __sphere3t__ sphere) => sphere.Center + sphere.Radius * (query - sphere.Center).Normalized; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOn(this __sphere3t__ sphere, __v3t__ query) => query.GetClosestPointOn(sphere); #endregion #region __v3t__ - __cylinder3t__ /// /// get closest point on cylinder with infinite length /// public static __v3t__ GetClosestPointOn(this __v3t__ query, __cylinder3t__ cylinder) { var p = query.GetClosestPointOn(cylinder.Axis.__ray3t__); var dir = (query - p).Normalized; return p + cylinder.Radius * dir; } /// /// get closest point on cylinder with infinite length /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOn(this __cylinder3t__ cylinder, __v3t__ query) => query.GetClosestPointOn(cylinder); #endregion #region __v3t__ - __triangle3t__ /// /// Tested by rft on 2008-08-06. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOn(this __v3t__ query, __triangle3t__ triangle) => GetClosestPointOnTriangle(query, triangle.P0, triangle.P1, triangle.P2); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetClosestPointOn(this __triangle3t__ triangle, __v3t__ query) => query.GetClosestPointOn(triangle); /// /// Tested by rft on 2008-08-06. /// public static __v3t__ GetClosestPointOnTriangle(this __v3t__ query, __v3t__ p0, __v3t__ p1, __v3t__ p2) { var e01 = p1 - p0; var e02 = p2 - p0; var p0q = query - p0; var d1 = Vec.Dot(e01, p0q); var d2 = Vec.Dot(e02, p0q); if (d1 <= 0 && d2 <= 0) return p0; // bary (1,0,0) var p1q = query - p1; var d3 = Vec.Dot(e01, p1q); var d4 = Vec.Dot(e02, p1q); if (d3 >= 0 && d4 <= d3) return p1; // bary (0,1,0) var vc = d1 * d4 - d3 * d2; if (vc <= 0 && d1 >= 0 && d3 <= 0) { var t = d1 / (d1 - d3); return p0 + t * e01; // bary (1-t,t,0) } var p2q = query - p2; var d5 = Vec.Dot(e01, p2q); var d6 = Vec.Dot(e02, p2q); if (d6 >= 0 && d5 <= d6) return p2; // bary (0,0,1) var vb = d5 * d2 - d1 * d6; if (vb <= 0 && d2 >= 0 && d6 <= 0) { var t = d2 / (d2 - d6); return p0 + t * e02; // bary (1-t,0,t) } var va = d3 * d6 - d5 * d4; if (va <= 0 && (d4 - d3) >= 0 && (d5 - d6) >= 0) { var t = (d4 - d3) / ((d4 - d3) + (d5 - d6)); return p1 + t * (p2 - p1); // bary (0, 1-t, t) } __rtype__ denom = 1 / (va + vb + vc); var v = vb * denom; var w = vc * denom; return p0 + v * e01 + w * e02; // bary (1-v-w, v, w) } #endregion /* __ray3t__ */ #region __ray3t__ - __ray3t__ public static __v3t__ GetClosestPointOn(this __ray3t__ ray0, __ray3t__ ray1) { var a = ray0.Origin - ray1.Origin; var u = ray0.Direction.Normalized; var v = ray1.Direction.Normalized; var uDotv = u.Dot(v); var n = (uDotv * uDotv - 1); // make sure rays are not parallel if (!n.Abs().IsTiny()) { var my = (a.Dot(u) * uDotv - a.Dot(v)) / n; return ray1.Origin + my * v; } return ray1.Origin; } #endregion /* __line3t__ */ #region __line3t__ - __line3t__ /// /// Returns the point on line1 which is closest to line0. /// public static __v3t__ GetClosestPointOn(this __line3t__ line0, __line3t__ line1) { var r0 = line0.__ray3t__; var r1 = line1.__ray3t__; if (r0.IsParallelTo(r1)) // t1 and t0 of following computation are invalid if lines are parallel { if (line0.P0.GetMinimalDistanceTo(line1) < line0.P1.GetMinimalDistanceTo(line1)) return line0.P0.GetClosestPointOn(line1); else return line0.P1.GetClosestPointOn(line1); } /* var distance = */ r0.GetMinimalDistanceTo(r1, out __rtype__ t0, out __rtype__ t1); if (t0 >= 0 && t0 <= 1 && t1 >= 0 && t1 <= 1) return r1.GetPointOnRay(t1); var d0 = line0.P0.GetMinimalDistanceTo(line1); var d1 = line0.P1.GetMinimalDistanceTo(line1); var d2 = line1.P0.GetMinimalDistanceTo(line0); var d3 = line1.P1.GetMinimalDistanceTo(line0); if (d0 < d1) { if (d0 < d2) return d0 < d3 ? line0.P0.GetClosestPointOn(line1) : line1.P1; else return d2 < d3 ? line1.P0 : line1.P1; } else { if (d1 < d2) return d1 < d3 ? line0.P1.GetClosestPointOn(line1) : line1.P1; else return d2 < d3 ? line1.P0 : line1.P1; } } #endregion #region __line3t__ - __plane3t__ /// /// Returns the closest point from a line to a plane (point on line). /// public static __v3t__ GetClosestPointOn(this __plane3t__ plane, __line3t__ line) { var ray = line.__ray3t__; if (ray.Intersects(plane, out __rtype__ t)) { var tClamped = t.Clamp(0, 1); // clamp point to line range return ray.GetPointOnRay(tClamped); } else // plane and line are parallel { return line.P0; } } //note: reverse method is not the same (closest point on line) #endregion #region __line3t__ - __triangle3t__ /// /// Returns the closest point from a triangle to a line (point on triangle). /// Note: untested /// public static __v3t__ GetClosestPointOn(this __line3t__ line, __triangle3t__ triangle) { // test if closest point on triangle plane is inside the triangle (we have the point), // otherwiese find closest edge and take closest point to that edge var plane = triangle.Plane; var planePoint = plane.GetClosestPointOn(line); // switch to 2d: var trafo = __trafo3t__.FromNormalFrame(plane.Point, plane.Normal); var point2d = trafo.Backward.TransformPos(planePoint).XY; var triangle2d = new __triangle2t__(trafo.Backward.TransformPos(triangle.P0).XY, trafo.Backward.TransformPos(triangle.P1).XY, trafo.Backward.TransformPos(triangle.P2).XY); if (triangle2d.Contains(point2d)) return trafo.Forward.TransformPos(point2d.XYO); var edgeDistances = new [] { line.GetMinimalDistanceTo(triangle.Line01), line.GetMinimalDistanceTo(triangle.Line12), line.GetMinimalDistanceTo(triangle.Line20) }; var closestEdge = triangle.GetEdgeLine(edgeDistances.IndexOfMin()); return line.GetClosestPointOn(closestEdge); } //note: reverse method is not the same (closest point on line) #endregion //# } } public static partial class GeometryFun { //# foreach (var isDouble in new[] { false, true }) { //# var rtype = isDouble ? "double" : "float"; //# var tc = isDouble ? "d" : "f"; //# var v2t = "V2" + tc; //# var v3t = "V3" + tc; //# var line2t = "Line2" + tc; //# var line3t = "Line3" + tc; //# var plane2t = "Plane2" + tc; //# var plane3t = "Plane3" + tc; //# var ray2t = "Ray2" + tc; //# var ray3t = "Ray3" + tc; //# var circle2t = "Circle2" + tc; //# var circle3t = "Circle3" + tc; //# var quad2t = "Quad2" + tc; //# var quad3t = "Quad3" + tc; //# var range1t = "Range1" + tc; //# var box2t = "Box2" + tc; //# var box3t = "Box3" + tc; //# var hull2t = "Hull2" + tc; //# var hull3t = "Hull3" + tc; //# var sphere3t = "Sphere3" + tc; //# var cylinder3t = "Cylinder3" + tc; //# var ellipse3t = "Ellipse3" + tc; //# var triangle2t = "Triangle2" + tc; //# var triangle3t = "Triangle3" + tc; //# var polygon2t = "Polygon2" + tc; //# var polygon3t = "Polygon3" + tc; //# var half = isDouble ? "0.5" : "0.5f"; #region __range1t__ - __range1t__ public static __rtype__ GetMinimalDistanceTo(this __range1t__ range0, __range1t__ range1) { if (range0.Min > range1.Max) return range0.Min - range1.Max; if (range0.Max < range1.Min) return range1.Min - range0.Max; return 0; } #endregion #region __ray2t__ - __ray2t__ /// /// returns the minimal distance between the given rays. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __ray2t__ ray0, __ray2t__ ray1) => ray0.GetMinimalDistanceTo(ray1, out __rtype__ t0, out __rtype__ t1); /// /// returns the minimal distance between the given rays. /// t0 and t1 hold the correspunding ray parameters. /// if both rays are parallel the t0 and t1 are from the origin of ray1 /// public static __rtype__ GetMinimalDistanceTo(this __ray2t__ ray0, __ray2t__ ray1, out __rtype__ t0, out __rtype__ t1) { // NOTE: copy of __ray3t__ to __ray3t__ distance var a = ray0.Origin - ray1.Origin; var u = ray0.Direction.Normalized; var v = ray1.Direction.Normalized; var uDotv = u.Dot(v); if (uDotv.Abs().ApproximateEquals(1, Constant<__rtype__>.PositiveTinyValue)) // rays are parallel { // return origin of ray 1 t1 = 0; t0 = ray0.GetT(ray1.Origin); } else { // change by lui: added normalization (ortherwise in case the directions are not normalized t0 and t1 are wrong) t1 = (a.Dot(u) * uDotv - a.Dot(v)) / (uDotv * uDotv - 1); t0 = (t1 * uDotv - a.Dot(u)) / ray0.Direction.Length; t1 = t1 / ray1.Direction.Length; } return (t1 * ray1.Direction - a - t0 * ray0.Direction).Length; } #endregion #region __box2t__ - __box2t__ public static __rtype__ GetMinimalDistanceTo(this __box2t__ box0, __box2t__ box1) { var distX = box0.RangeX.GetMinimalDistanceTo(box1.RangeX); var distY = box0.RangeY.GetMinimalDistanceTo(box1.RangeY); if (distX == 0 && distY == 0) return 0; else if (distX == 0) return distY; else if (distY == 0) return distX; if (box0.Min.X > box1.Max.X) // 1 is left { if (box0.Min.Y > box1.Max.Y) // 1 is top left return (box0.Corner(0) - box1.Corner(3)).Length; else // 1 is bottom left return (box0.Corner(2) - box1.Corner(1)).Length; } else // 1 is right { if (box0.Min.Y > box1.Max.Y) // 1 is top right return (box0.Corner(1) - box1.Corner(2)).Length; else // 1 is bottom right return (box0.Corner(3) - box1.Corner(0)).Length; } } #endregion #region __v2t__ - __line2t__ /// /// returns the minimal distance between the point and the Line /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __v2t__ point, __line2t__ line) => point.DistanceToLine(line.P0, line.P1); #endregion #region __v2t__ - __triangle2t__ /// /// returns the minimal distance between the point and the triangle /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __v2t__ point, __triangle2t__ t) => Triangle.Distance(t.P0, t.P1, t.P2, point); #endregion #region __line2t__ - __line2t__ /// /// returns the minimal distance between the given lines. /// public static __rtype__ GetMinimalDistanceTo(this __line2t__ l0, __line2t__ l1) { var r0 = l0.__ray2t__; var r1 = l1.__ray2t__; if (!r0.IsParallelTo(r1)) // t1 and t0 of following computation are invalid if lines are parallel { var distance = r0.GetMinimalDistanceTo(r1, out __rtype__ t0, out __rtype__ t1); if (t0 >= 0 && t0 <= 1 && t1 >= 0 && t1 <= 1) return distance; } // lines are parallel or t0 and t1 are outside of the line return Fun.Min(l0.P0.GetMinimalDistanceTo(l1), l0.P1.GetMinimalDistanceTo(l1), l1.P0.GetMinimalDistanceTo(l0), l1.P1.GetMinimalDistanceTo(l0)); } #endregion #region __v3t__ - __line3t__ /// /// returns the minimal distance between the point and the Line /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __v3t__ point, __line3t__ line) => point.DistanceToLine(line.P0, line.P1); /// /// Returns the minimal distance between the point and the Line. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __line3t__ line, __v3t__ point) => point.GetMinimalDistanceTo(line); #endregion #region __v3t__ - __ray3t__ /* Performance Test ......................................................................... Faster Method: __v3t__.MinimalDistanceTo(__ray3t__) __v3t__.MinimalDistanceTo(__ray3t__): 1,841s (__v3t__ - __v3t__.GetClosestPointOn(__ray3t__)).Length: 3,058s Total Executions: 10000000 Errors outside tolerance(1E-7): 0 Average Squared-Distance of Results: 2,24116481902135E-32 Speedup-factor: 1,66 */ /// /// Returns the minimal distance between the point and the ray. /// public static __rtype__ GetMinimalDistanceTo(this __v3t__ point, __ray3t__ ray) { var a = point - ray.Origin; __rtype__ lu2 = ray.Direction.LengthSquared; __rtype__ acu2 = Vec.Cross(a, ray.Direction).LengthSquared; return Fun.Sqrt(acu2 / lu2); } /// /// returns the minimal distance between the point and the Ray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __ray3t__ ray, __v3t__ point) => point.GetMinimalDistanceTo(ray); /// /// returns the minimal distance between the point and the Ray. /// t holds the ray parameter for the closest point. /// public static __rtype__ GetMinimalDistanceTo(this __v3t__ point, __ray3t__ ray, out __rtype__ t) { var a = point - ray.Origin; var lu2 = ray.Direction.LengthSquared; var acu2 = Vec.Cross(a, ray.Direction).LengthSquared; var NormalPart2 = acu2 / lu2; var ParallelPart2 = lu2 - NormalPart2; t = Fun.Sqrt(ParallelPart2 / lu2); return Fun.Sqrt(NormalPart2); } /// /// returns the minimal distance between the point and the Ray. /// t holds the ray parameter for the closest point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __ray3t__ ray, __v3t__ point, out __rtype__ t) => point.GetMinimalDistanceTo(ray, out t); #endregion #region __v3t__ - __plane3t__ /// /// Returns the minimal distance (unsigned) between the point and the plane. /// Use __plane3t__.Height to compute the signed height of the point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __v3t__ point, __plane3t__ plane) => plane.Height(point).Abs(); /// /// Returns the minimal distance (unsigned) between the point and the plane. /// Use __plane3t__.Height to compute the signed height of the point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __plane3t__ plane, __v3t__ point) => point.GetMinimalDistanceTo(plane); #endregion #region __v3t__ - __box3t__ /// /// returns the minimal distance between the point and the box. /// public static __rtype__ GetMinimalDistanceTo(this __v3t__ point, __box3t__ box) { var outside = box.OutsideFlags(point); if (outside == 0) return 0; var d = __v3t__.Zero; if ((outside & Box.Flags.X) != 0) { if ((outside & Box.Flags.MaxX) != 0) d.X = point.X - box.Max.X; else if ((outside & Box.Flags.MinX) != 0) d.X = point.X - box.Min.X; } if ((outside & Box.Flags.Y) != 0) { if ((outside & Box.Flags.MaxY) != 0) d.Y = point.Y - box.Max.Y; else if ((outside & Box.Flags.MinY) != 0) d.Y = point.Y - box.Min.Y; } if ((outside & Box.Flags.Z) != 0) { if ((outside & Box.Flags.MaxZ) != 0) d.Z = point.Z - box.Max.Z; else if ((outside & Box.Flags.MinZ) != 0) d.Z = point.Z - box.Min.Z; } return d.Length; } /// /// returns the minimal distance between the point and the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __box3t__ box, __v3t__ point) => point.GetMinimalDistanceTo(box); #endregion #region __v3t__ - __triangle3t__ /// /// returns the minimal distance between the point and the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __v3t__ point, __triangle3t__ triangle) => Triangle.Distance(triangle.P0, triangle.P1, triangle.P2, point); /// /// returns the minimal distance between the point and the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __triangle3t__ triangle, __v3t__ point) => point.GetMinimalDistanceTo(triangle); #endregion #region __line3t__ - __line3t__ /// /// returns the minimal distance between the given lines. /// public static __rtype__ GetMinimalDistanceTo(this __line3t__ l0, __line3t__ l1) { var r0 = l0.__ray3t__; var r1 = l1.__ray3t__; if (!r0.IsParallelTo(r1)) // t1 and t0 of following computation are invalid if lines are parallel { var distance = r0.GetMinimalDistanceTo(r1, out __rtype__ t0, out __rtype__ t1); if (t0 >= 0 && t0 <= 1 && t1 >= 0 && t1 <= 1) return distance; } // lines are parallel or t0 and t1 are outside of the line return Fun.Min(l0.P0.GetMinimalDistanceTo(l1), l0.P1.GetMinimalDistanceTo(l1), l1.P0.GetMinimalDistanceTo(l0), l1.P1.GetMinimalDistanceTo(l0)); } /// /// returns the minimal distance between the given lines. /// points holds the centroid of the shortest connection between the lines /// public static __rtype__ GetMinimalDistanceTo(this __line3t__ l0, __line3t__ l1, out __v3t__ point) { var r0 = l0.__ray3t__; var r1 = l1.__ray3t__; var distance = r0.GetMinimalDistanceTo(r1, out __rtype__ t0, out __rtype__ t1); if (t0 >= 0 && t0 <= 1 && t1 >= 0 && t1 <= 1) { point = __half__ * (r0.GetPointOnRay(t0) + r1.GetPointOnRay(t1)); return distance; } else { __rtype__ t; if (t0 < 0 || t0 > 1) { if (t0 < 0) t0 = 0; else t0 = 1; distance = r0.GetPointOnRay(t0).GetMinimalDistanceTo(r1, out t); if (t >= 0 && t <= 1) { point = __half__ * (r0.GetPointOnRay(t0) + r1.GetPointOnRay(t)); return distance; } } if (t1 < 0 || t1 > 1) { if (t1 < 0) t1 = 0; else t1 = 1; distance = r1.GetPointOnRay(t1).GetMinimalDistanceTo(r0, out t); if (t >= 0 && t <= 1) { point = __half__ * (r0.GetPointOnRay(t) + r1.GetPointOnRay(t1)); return distance; } } } point = __half__ * (r0.GetPointOnRay(t0) + r1.GetPointOnRay(t1)); return (r0.GetPointOnRay(t0) - r1.GetPointOnRay(t1)).Length; } #endregion #region __line3t__ - __plane3t__ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __line3t__ line, __plane3t__ plane) => plane.Height(GeometryFun.GetClosestPointOn(plane, line)).Abs(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __plane3t__ plane, __line3t__ line) => line.GetMinimalDistanceTo(plane); #endregion #region __ray3t__ - __line3t__ /// /// returns the minimal distance between the ray and the line. /// public static __rtype__ GetMinimalDistanceTo(this __ray3t__ ray, __line3t__ line) { var r1 = line.__ray3t__; var distance = ray.GetMinimalDistanceTo(r1, out __rtype__ t0, out __rtype__ t1); if (t1 >= 0 && t1 <= 1) return distance; else { if (t1 < 0) t1 = 0; if (t1 > 1) t1 = 1; var p1 = r1.GetPointOnRay(t1); return p1.GetMinimalDistanceTo(ray); } } /// /// returns the minimal distance between the ray and the line. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __line3t__ line, __ray3t__ ray) => ray.GetMinimalDistanceTo(line); /// /// returns the minimal distance between the ray and the line. /// t holds the correspoinding ray parameter. /// public static __rtype__ GetMinimalDistanceTo(this __ray3t__ ray, __line3t__ line, out __rtype__ t) { var r1 = line.__ray3t__; var distance = ray.GetMinimalDistanceTo(r1, out __rtype__ t0, out __rtype__ t1); if (t1 >= 0 && t1 <= 1) { t = t0; return distance; } else { if (t1 < 0) t1 = 0; if (t1 > 1) t1 = 1; var p1 = r1.GetPointOnRay(t1); return p1.GetMinimalDistanceTo(ray, out t); } } /// /// returns the minimal distance between the ray and the line. /// t holds the correspoinding ray parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __line3t__ line, __ray3t__ ray, out __rtype__ t) => ray.GetMinimalDistanceTo(line, out t); #endregion #region __ray3t__ - __ray3t__ /// /// returns the minimal distance between the given rays. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetMinimalDistanceTo(this __ray3t__ ray0, __ray3t__ ray1) => ray0.GetMinimalDistanceTo(ray1, out __rtype__ t0, out __rtype__ t1); /// /// returns the minimal distance between the given rays. /// t0 and t1 hold the correspunding ray parameters. /// if both rays are parallel the t0 and t1 are from the origin of ray1 /// public static __rtype__ GetMinimalDistanceTo(this __ray3t__ ray0, __ray3t__ ray1, out __rtype__ t0, out __rtype__ t1) { // TODO: computation probalby possible without Direction.Normalized and Direction.Length var a = ray0.Origin - ray1.Origin; var u = ray0.Direction.Normalized; var v = ray1.Direction.Normalized; var uDotv = u.Dot(v); if (uDotv.Abs().ApproximateEquals(1, Constant<__rtype__>.PositiveTinyValue)) // rays are parallel { // return origin of ray 1 t1 = 0; t0 = ray0.GetTOfProjectedPoint(ray1.Origin); } else { // change by lui: added normalization (ortherwise in case the directions are not normalized t0 and t1 are wrong) t1 = (a.Dot(u) * uDotv - a.Dot(v)) / (uDotv * uDotv - 1); t0 = (t1 * uDotv - a.Dot(u)) / ray0.Direction.Length; t1 = t1 / ray1.Direction.Length; } return (t1 * ray1.Direction - a - t0 * ray0.Direction).Length; } #endregion //# } } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Capsule/Capsule3_auto.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Capsule3f [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Capsule3f : IEquatable, IValidity, IBoundingBox3f { [DataMember] public V3f P0; [DataMember] public V3f P1; [DataMember] public float Radius; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public Capsule3f(V3f p0, V3f p1, float radius) { P0 = p0; P1 = p1; Radius = radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Capsule3f(Line3f axis, float radius) { P0 = axis.P0; P1 = axis.P1; Radius = radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Capsule3f(Capsule3f capsule) { P0 = capsule.P0; P1 = capsule.P1; Radius = capsule.Radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Capsule3f(Capsule3d capsule) { P0 = (V3f)capsule.P0; P1 = (V3f)capsule.P1; Radius = (float)capsule.Radius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Capsule3f(Capsule3d c) => new Capsule3f(c); #endregion #region Constants public static readonly Capsule3f Invalid = new Capsule3f(V3f.NaN, V3f.NaN, -1); #endregion #region Properties public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius >= 0.0; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius < 0.0; } public readonly Line3f Axis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Line3f(P0, P1); } public readonly Cylinder3f Cylider { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Cylinder3f(P0, P1, Radius); } #endregion #region IBoundingBox3f Members public readonly Box3f BoundingBox3f { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Box3f(new Sphere3f(P0, Radius).BoundingBox3f, new Sphere3f(P1, Radius).BoundingBox3f); } #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(P0, P1, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Capsule3f other) => P0.Equals(other.P0) && P1.Equals(other.P1) && Radius.Equals(other.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Capsule3f o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", P0, P1, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Capsule3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Capsule3f(V3f.Parse(x[0]), V3f.Parse(x[1]), float.Parse(x[2], CultureInfo.InvariantCulture)); } #endregion } #endregion #region Capsule3d [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Capsule3d : IEquatable, IValidity, IBoundingBox3d { [DataMember] public V3d P0; [DataMember] public V3d P1; [DataMember] public double Radius; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public Capsule3d(V3d p0, V3d p1, double radius) { P0 = p0; P1 = p1; Radius = radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Capsule3d(Line3d axis, double radius) { P0 = axis.P0; P1 = axis.P1; Radius = radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Capsule3d(Capsule3d capsule) { P0 = capsule.P0; P1 = capsule.P1; Radius = capsule.Radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Capsule3d(Capsule3f capsule) { P0 = (V3d)capsule.P0; P1 = (V3d)capsule.P1; Radius = (double)capsule.Radius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Capsule3d(Capsule3f c) => new Capsule3d(c); #endregion #region Constants public static readonly Capsule3d Invalid = new Capsule3d(V3d.NaN, V3d.NaN, -1); #endregion #region Properties public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius >= 0.0; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius < 0.0; } public readonly Line3d Axis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Line3d(P0, P1); } public readonly Cylinder3d Cylider { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Cylinder3d(P0, P1, Radius); } #endregion #region IBoundingBox3d Members public readonly Box3d BoundingBox3d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Box3d(new Sphere3d(P0, Radius).BoundingBox3d, new Sphere3d(P1, Radius).BoundingBox3d); } #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(P0, P1, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Capsule3d other) => P0.Equals(other.P0) && P1.Equals(other.P1) && Radius.Equals(other.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Capsule3d o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", P0, P1, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Capsule3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Capsule3d(V3d.Parse(x[0]), V3d.Parse(x[1]), double.Parse(x[2], CultureInfo.InvariantCulture)); } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Capsule/Capsule3_template.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Capsule3" + tc; //# var type2 = "Capsule3" + tc2; //# var v3t = "V3" + tc; //# var line3t = "Line3" + tc; //# var cylinder3t = "Cylinder3" + tc; //# var box3t = "Box3" + tc; //# var sphere3t = "Sphere3" + tc; //# var iboundingbox = "IBoundingBox3" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var fourbythree = isDouble ? "(4.0 / 3.0)" : "(4.0f / 3.0f)"; //# var pi = isDouble ? "Constant.Pi" : "ConstantF.Pi"; #region __type__ [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__>, IValidity, __iboundingbox__ { [DataMember] public __v3t__ P0; [DataMember] public __v3t__ P1; [DataMember] public __ftype__ Radius; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__v3t__ p0, __v3t__ p1, __ftype__ radius) { P0 = p0; P1 = p1; Radius = radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__line3t__ axis, __ftype__ radius) { P0 = axis.P0; P1 = axis.P1; Radius = radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ capsule) { P0 = capsule.P0; P1 = capsule.P1; Radius = capsule.Radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ capsule) { P0 = (__v3t__)capsule.P0; P1 = (__v3t__)capsule.P1; Radius = (__ftype__)capsule.Radius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type__(__type2__ c) => new __type__(c); #endregion #region Constants public static readonly __type__ Invalid = new __type__(__v3t__.NaN, __v3t__.NaN, -1); #endregion #region Properties public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius >= 0.0; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius < 0.0; } public readonly __line3t__ Axis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __line3t__(P0, P1); } public readonly __cylinder3t__ Cylider { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __cylinder3t__(P0, P1, Radius); } #endregion #region __iboundingbox__ Members public readonly __box3t__ BoundingBox3__tc__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __box3t__(new __sphere3t__(P0, Radius).BoundingBox3__tc__, new __sphere3t__(P1, Radius).BoundingBox3__tc__); } #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(P0, P1, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => P0.Equals(other.P0) && P1.Equals(other.P1) && Radius.Equals(other.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", P0, P1, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__(__v3t__.Parse(x[0]), __v3t__.Parse(x[1]), __ftype__.Parse(x[2], CultureInfo.InvariantCulture)); } #endregion } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Circle/Circle2_auto.cs ================================================ /* Copyright 2006-2020. The Aardvark Platform Team. https://aardvark.graphics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ using System; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Circle2f /// /// A two dimensional circle represented by center and radius. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Circle2f : IEquatable, IBoundingBox2f, IValidity { [DataMember] public V2f Center; [DataMember] public float Radius; #region Constructors /// /// Creates circle from center and radius. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Circle2f(V2f center, float radius) { Center = center; Radius = radius; } /// /// Creates circle from center and point on circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Circle2f(V2f center, V2f pointOnCircle) { Center = center; Radius = (pointOnCircle - center).Length; } /// /// Creates circle from three points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Circle2f(V2f a, V2f b, V2f c) { var l0 = new Plane2f((b - a).Normalized, (a + b) * 0.5f); var l1 = new Plane2f((c - b).Normalized, (b + c) * 0.5f); if (l0.Intersects(l1, out Center)) { Radius = (a - Center).Length; } else { throw new Exception("Cannot construct circle because given points are collinear."); } } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Circle2f(Circle2f o) { Center = o.Center; Radius = o.Radius; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Circle2f(Circle2d o) { Center = (V2f)o.Center; Radius = (float)o.Radius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Circle2f(Circle2d c) => new Circle2f(c); #endregion #region Constants public static Circle2f Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Circle2f(V2f.Zero, 0); } public static Circle2f Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Circle2f(V2f.NaN, -1); } public static Circle2f Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Circle2f(V2f.Zero, 1); } #endregion #region Properties public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius < 0.0 || float.IsNaN(Radius) || Center.IsNaN; } public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius >= 0.0 && !Center.IsNaN; } public readonly float RadiusSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius * Radius; } public readonly float Circumference { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => 2 * Radius * ConstantF.Pi; } public readonly float Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius * Radius * ConstantF.Pi; } public readonly Box2f InscribedSquare { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var a = Fun.Sqrt(RadiusSquared * 0.5f); return new Box2f(new V2f(-a), new V2f(a)); } } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Circle2f a, Circle2f b) => (a.Center == b.Center) && (a.Radius == b.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Circle2f a, Circle2f b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Center, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Circle2f other) => Center.Equals(other.Center) && Radius.Equals(other.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Circle2f o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Center, Radius); /// /// Parses Circle2f from a string created with Circle2f.ToString(). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Circle2f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Circle2f(V2f.Parse(x[0]), float.Parse(x[1], CultureInfo.InvariantCulture)); } #endregion #region IBoundingBox2f Members public readonly Box2f BoundingBox2f { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Box2f( new V2f(Center.X - Radius, Center.Y - Radius), new V2f(Center.X + Radius, Center.Y + Radius) ); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Circle2f a, Circle2f b, float tolerance) => ApproximateEquals(a.Center, b.Center, tolerance) && ApproximateEquals(a.Radius, b.Radius, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Circle2f a, Circle2f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Circle2d /// /// A two dimensional circle represented by center and radius. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Circle2d : IEquatable, IBoundingBox2d, IValidity { [DataMember] public V2d Center; [DataMember] public double Radius; #region Constructors /// /// Creates circle from center and radius. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Circle2d(V2d center, double radius) { Center = center; Radius = radius; } /// /// Creates circle from center and point on circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Circle2d(V2d center, V2d pointOnCircle) { Center = center; Radius = (pointOnCircle - center).Length; } /// /// Creates circle from three points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Circle2d(V2d a, V2d b, V2d c) { var l0 = new Plane2d((b - a).Normalized, (a + b) * 0.5); var l1 = new Plane2d((c - b).Normalized, (b + c) * 0.5); if (l0.Intersects(l1, out Center)) { Radius = (a - Center).Length; } else { throw new Exception("Cannot construct circle because given points are collinear."); } } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Circle2d(Circle2d o) { Center = o.Center; Radius = o.Radius; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Circle2d(Circle2f o) { Center = (V2d)o.Center; Radius = (double)o.Radius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Circle2d(Circle2f c) => new Circle2d(c); #endregion #region Constants public static Circle2d Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Circle2d(V2d.Zero, 0); } public static Circle2d Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Circle2d(V2d.NaN, -1); } public static Circle2d Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Circle2d(V2d.Zero, 1); } #endregion #region Properties public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius < 0.0 || double.IsNaN(Radius) || Center.IsNaN; } public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius >= 0.0 && !Center.IsNaN; } public readonly double RadiusSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius * Radius; } public readonly double Circumference { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => 2 * Radius * Constant.Pi; } public readonly double Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius * Radius * Constant.Pi; } public readonly Box2d InscribedSquare { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var a = Fun.Sqrt(RadiusSquared * 0.5); return new Box2d(new V2d(-a), new V2d(a)); } } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Circle2d a, Circle2d b) => (a.Center == b.Center) && (a.Radius == b.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Circle2d a, Circle2d b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Center, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Circle2d other) => Center.Equals(other.Center) && Radius.Equals(other.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Circle2d o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Center, Radius); /// /// Parses Circle2d from a string created with Circle2d.ToString(). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Circle2d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Circle2d(V2d.Parse(x[0]), double.Parse(x[1], CultureInfo.InvariantCulture)); } #endregion #region IBoundingBox2d Members public readonly Box2d BoundingBox2d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Box2d( new V2d(Center.X - Radius, Center.Y - Radius), new V2d(Center.X + Radius, Center.Y + Radius) ); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Circle2d a, Circle2d b, double tolerance) => ApproximateEquals(a.Center, b.Center, tolerance) && ApproximateEquals(a.Radius, b.Radius, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Circle2d a, Circle2d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Circle/Circle2_template.cs ================================================ /* Copyright 2006-2020. The Aardvark Platform Team. https://aardvark.graphics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ using System; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Circle2" + tc; //# var type2 = "Circle2" + tc2; //# var v2t = "V2" + tc; //# var box2t = "Box2" + tc; //# var plane2t = "Plane2" + tc; //# var iboundingbox = "IBoundingBox2" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var pi = isDouble ? "Constant.Pi" : "ConstantF.Pi"; #region __type__ /// /// A two dimensional circle represented by center and radius. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__>, __iboundingbox__, IValidity { [DataMember] public __v2t__ Center; [DataMember] public __ftype__ Radius; #region Constructors /// /// Creates circle from center and radius. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__v2t__ center, __ftype__ radius) { Center = center; Radius = radius; } /// /// Creates circle from center and point on circle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__v2t__ center, __v2t__ pointOnCircle) { Center = center; Radius = (pointOnCircle - center).Length; } /// /// Creates circle from three points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__v2t__ a, __v2t__ b, __v2t__ c) { var l0 = new __plane2t__((b - a).Normalized, (a + b) * __half__); var l1 = new __plane2t__((c - b).Normalized, (b + c) * __half__); if (l0.Intersects(l1, out Center)) { Radius = (a - Center).Length; } else { throw new Exception("Cannot construct circle because given points are collinear."); } } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ o) { Center = o.Center; Radius = o.Radius; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ o) { Center = (__v2t__)o.Center; Radius = (__ftype__)o.Radius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type__(__type2__ c) => new __type__(c); #endregion #region Constants public static __type__ Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(__v2t__.Zero, 0); } public static __type__ Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(__v2t__.NaN, -1); } public static __type__ Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(__v2t__.Zero, 1); } #endregion #region Properties public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius < 0.0 || __ftype__.IsNaN(Radius) || Center.IsNaN; } public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius >= 0.0 && !Center.IsNaN; } public readonly __ftype__ RadiusSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius * Radius; } public readonly __ftype__ Circumference { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => 2 * Radius * __pi__; } public readonly __ftype__ Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius * Radius * __pi__; } public readonly __box2t__ InscribedSquare { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var a = Fun.Sqrt(RadiusSquared * __half__); return new __box2t__(new __v2t__(-a), new __v2t__(a)); } } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ a, __type__ b) => (a.Center == b.Center) && (a.Radius == b.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ a, __type__ b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Center, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => Center.Equals(other.Center) && Radius.Equals(other.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Center, Radius); /// /// Parses __type__ from a string created with __type__.ToString(). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__(__v2t__.Parse(x[0]), __ftype__.Parse(x[1], CultureInfo.InvariantCulture)); } #endregion #region __iboundingbox__ Members public readonly __box2t__ BoundingBox2__tc__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __box2t__( new __v2t__(Center.X - Radius, Center.Y - Radius), new __v2t__(Center.X + Radius, Center.Y + Radius) ); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b, __ftype__ tolerance) => ApproximateEquals(a.Center, b.Center, tolerance) && ApproximateEquals(a.Radius, b.Radius, tolerance); /// /// Returns whether the given are equal within /// Constant<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b) => ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Circle/Circle3_auto.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Circle3f /// /// A circle in 3-space represented by its center, normal (normalized), and a radius. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Circle3f : IEquatable, IBoundingBox3f, IValidity { [DataMember] public V3f Center; [DataMember] public V3f Normal; [DataMember] public float Radius; #region Constructors /// /// Creates a circle from it's center, a normal vector (normalized) and a radius. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Circle3f(V3f center, V3f normal, float radius) { Center = center; Normal = normal; Radius = radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Circle3f(Circle3f circle) { Center = circle.Center; Normal = circle.Normal; Radius = circle.Radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Circle3f(Circle3d circle) { Center = (V3f)circle.Center; Normal = (V3f)circle.Normal; Radius = (float)circle.Radius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Circle3f(Circle3d c) => new Circle3f(c); #endregion #region Constants public static Circle3f Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Circle3f(V3f.Zero, V3f.ZAxis, 0); } public static Circle3f Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Circle3f(V3f.NaN, V3f.NaN, -1); } #endregion #region Properties public readonly float RadiusSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius.Square(); } public readonly float Circumference { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => 2 * Radius * ConstantF.Pi; } public readonly float Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => RadiusSquared * ConstantF.Pi; } public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius >= 0; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius < 0; } /// /// Returns a point on the circumference (AxisU). /// public readonly V3f Point { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Center + AxisU * Radius; } /// /// Returns an axis aligned vector pointing from the center to the circumference. /// public readonly V3f AxisU { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { V3f dir = Normal.Dot(V3f.XAxis).Abs() > 0.9f ? V3f.YAxis : V3f.XAxis; var pdir = Normal.Cross(dir); return pdir.Normalized * Radius; } } /// /// Returns an axis aligned vector pointing from the center to the circumference. /// public readonly V3f AxisV { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var axisU = AxisU; return AxisU.Cross(Normal).Normalized * Radius; } } /// /// Return an IEnumerable of points on the circle's circumference, optionally repeating the first point as the last. /// /// number of distinct points to generate. the actual number of points returned depends on the duplicateClosePoint parameter. must be 3 or larger. /// if true, the first point is repeated as the last /// IEnumerable of points on the circle's circumference. if diplicateClosePoint is true, tesselation+1 points are returned. public readonly IEnumerable Points(int tesselation, bool duplicateClosePoint = false) { if (tesselation < 3) throw new ArgumentOutOfRangeException("tesselation", "tesselation must be at least 3."); var off = 0; if (duplicateClosePoint) off = 1; for (int i = 0; i < tesselation + off; i++) { var angle = ((float)i) / tesselation * ConstantF.PiTimesTwo; yield return Center + AxisU * Fun.Cos(angle) + AxisV * Fun.Sin(angle); } } public readonly Plane3f Plane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3f(Normal, Center); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f GetPoint(float angle) => Center + AxisU * angle.Cos() + AxisV * angle.Sin(); #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Circle3f a, Circle3f b) => (a.Center == b.Center) && (a.Normal == b.Normal) && (a.Radius == b.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Circle3f a, Circle3f b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Center, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Circle3f other) => Center.Equals(other.Center) && Normal.Equals(other.Normal) && Radius.Equals(other.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Circle3f o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", Center, Normal, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Circle3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Circle3f(V3f.Parse(x[0]), V3f.Parse(x[1]), float.Parse(x[2], CultureInfo.InvariantCulture)); } #endregion #region IBoundingBox3f Members public readonly Box3f BoundingBox3f { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var u = AxisU; var v = AxisV; return new Box3f(Center + u, Center - u, Center + v, Center - v); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Circle3f a, Circle3f b, float tolerance) => ApproximateEquals(a.Center, b.Center, tolerance) && ApproximateEquals(a.Normal, b.Normal, tolerance) && ApproximateEquals(a.Radius, b.Radius, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Circle3f a, Circle3f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Circle3d /// /// A circle in 3-space represented by its center, normal (normalized), and a radius. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Circle3d : IEquatable, IBoundingBox3d, IValidity { [DataMember] public V3d Center; [DataMember] public V3d Normal; [DataMember] public double Radius; #region Constructors /// /// Creates a circle from it's center, a normal vector (normalized) and a radius. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Circle3d(V3d center, V3d normal, double radius) { Center = center; Normal = normal; Radius = radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Circle3d(Circle3d circle) { Center = circle.Center; Normal = circle.Normal; Radius = circle.Radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Circle3d(Circle3f circle) { Center = (V3d)circle.Center; Normal = (V3d)circle.Normal; Radius = (double)circle.Radius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Circle3d(Circle3f c) => new Circle3d(c); #endregion #region Constants public static Circle3d Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Circle3d(V3d.Zero, V3d.ZAxis, 0); } public static Circle3d Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Circle3d(V3d.NaN, V3d.NaN, -1); } #endregion #region Properties public readonly double RadiusSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius.Square(); } public readonly double Circumference { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => 2 * Radius * Constant.Pi; } public readonly double Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => RadiusSquared * Constant.Pi; } public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius >= 0; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius < 0; } /// /// Returns a point on the circumference (AxisU). /// public readonly V3d Point { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Center + AxisU * Radius; } /// /// Returns an axis aligned vector pointing from the center to the circumference. /// public readonly V3d AxisU { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { V3d dir = Normal.Dot(V3d.XAxis).Abs() > 0.9 ? V3d.YAxis : V3d.XAxis; var pdir = Normal.Cross(dir); return pdir.Normalized * Radius; } } /// /// Returns an axis aligned vector pointing from the center to the circumference. /// public readonly V3d AxisV { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var axisU = AxisU; return AxisU.Cross(Normal).Normalized * Radius; } } /// /// Return an IEnumerable of points on the circle's circumference, optionally repeating the first point as the last. /// /// number of distinct points to generate. the actual number of points returned depends on the duplicateClosePoint parameter. must be 3 or larger. /// if true, the first point is repeated as the last /// IEnumerable of points on the circle's circumference. if diplicateClosePoint is true, tesselation+1 points are returned. public readonly IEnumerable Points(int tesselation, bool duplicateClosePoint = false) { if (tesselation < 3) throw new ArgumentOutOfRangeException("tesselation", "tesselation must be at least 3."); var off = 0; if (duplicateClosePoint) off = 1; for (int i = 0; i < tesselation + off; i++) { var angle = ((double)i) / tesselation * Constant.PiTimesTwo; yield return Center + AxisU * Fun.Cos(angle) + AxisV * Fun.Sin(angle); } } public readonly Plane3d Plane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3d(Normal, Center); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d GetPoint(double angle) => Center + AxisU * angle.Cos() + AxisV * angle.Sin(); #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Circle3d a, Circle3d b) => (a.Center == b.Center) && (a.Normal == b.Normal) && (a.Radius == b.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Circle3d a, Circle3d b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Center, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Circle3d other) => Center.Equals(other.Center) && Normal.Equals(other.Normal) && Radius.Equals(other.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Circle3d o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", Center, Normal, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Circle3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Circle3d(V3d.Parse(x[0]), V3d.Parse(x[1]), double.Parse(x[2], CultureInfo.InvariantCulture)); } #endregion #region IBoundingBox3d Members public readonly Box3d BoundingBox3d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var u = AxisU; var v = AxisV; return new Box3d(Center + u, Center - u, Center + v, Center - v); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Circle3d a, Circle3d b, double tolerance) => ApproximateEquals(a.Center, b.Center, tolerance) && ApproximateEquals(a.Normal, b.Normal, tolerance) && ApproximateEquals(a.Radius, b.Radius, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Circle3d a, Circle3d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Circle/Circle3_template.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Circle3" + tc; //# var type2 = "Circle3" + tc2; //# var v3t = "V3" + tc; //# var box3t = "Box3" + tc; //# var plane3t = "Plane3" + tc; //# var iboundingbox = "IBoundingBox3" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var dotnine = isDouble ? "0.9" : "0.9f"; //# var constant = isDouble ? "Constant" : "ConstantF"; #region __type__ /// /// A circle in 3-space represented by its center, normal (normalized), and a radius. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__>, __iboundingbox__, IValidity { [DataMember] public __v3t__ Center; [DataMember] public __v3t__ Normal; [DataMember] public __ftype__ Radius; #region Constructors /// /// Creates a circle from it's center, a normal vector (normalized) and a radius. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__v3t__ center, __v3t__ normal, __ftype__ radius) { Center = center; Normal = normal; Radius = radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ circle) { Center = circle.Center; Normal = circle.Normal; Radius = circle.Radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ circle) { Center = (__v3t__)circle.Center; Normal = (__v3t__)circle.Normal; Radius = (__ftype__)circle.Radius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type__(__type2__ c) => new __type__(c); #endregion #region Constants public static __type__ Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(__v3t__.Zero, __v3t__.ZAxis, 0); } public static __type__ Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(__v3t__.NaN, __v3t__.NaN, -1); } #endregion #region Properties public readonly __ftype__ RadiusSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius.Square(); } public readonly __ftype__ Circumference { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => 2 * Radius * __constant__.Pi; } public readonly __ftype__ Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => RadiusSquared * __constant__.Pi; } public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius >= 0; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius < 0; } /// /// Returns a point on the circumference (AxisU). /// public readonly __v3t__ Point { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Center + AxisU * Radius; } /// /// Returns an axis aligned vector pointing from the center to the circumference. /// public readonly __v3t__ AxisU { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { __v3t__ dir = Normal.Dot(__v3t__.XAxis).Abs() > __dotnine__ ? __v3t__.YAxis : __v3t__.XAxis; var pdir = Normal.Cross(dir); return pdir.Normalized * Radius; } } /// /// Returns an axis aligned vector pointing from the center to the circumference. /// public readonly __v3t__ AxisV { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var axisU = AxisU; return AxisU.Cross(Normal).Normalized * Radius; } } /// /// Return an IEnumerable of points on the circle's circumference, optionally repeating the first point as the last. /// /// number of distinct points to generate. the actual number of points returned depends on the duplicateClosePoint parameter. must be 3 or larger. /// if true, the first point is repeated as the last /// IEnumerable of points on the circle's circumference. if diplicateClosePoint is true, tesselation+1 points are returned. public readonly IEnumerable<__v3t__> Points(int tesselation, bool duplicateClosePoint = false) { if (tesselation < 3) throw new ArgumentOutOfRangeException("tesselation", "tesselation must be at least 3."); var off = 0; if (duplicateClosePoint) off = 1; for (int i = 0; i < tesselation + off; i++) { var angle = ((__ftype__)i) / tesselation * __constant__.PiTimesTwo; yield return Center + AxisU * Fun.Cos(angle) + AxisV * Fun.Sin(angle); } } public readonly __plane3t__ Plane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __plane3t__(Normal, Center); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __v3t__ GetPoint(__ftype__ angle) => Center + AxisU * angle.Cos() + AxisV * angle.Sin(); #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ a, __type__ b) => (a.Center == b.Center) && (a.Normal == b.Normal) && (a.Radius == b.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ a, __type__ b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Center, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => Center.Equals(other.Center) && Normal.Equals(other.Normal) && Radius.Equals(other.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", Center, Normal, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__(__v3t__.Parse(x[0]), __v3t__.Parse(x[1]), __ftype__.Parse(x[2], CultureInfo.InvariantCulture)); } #endregion #region __iboundingbox__ Members public readonly __box3t__ BoundingBox3__tc__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var u = AxisU; var v = AxisV; return new __box3t__(Center + u, Center - u, Center + v, Center - v); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b, __ftype__ tolerance) => ApproximateEquals(a.Center, b.Center, tolerance) && ApproximateEquals(a.Normal, b.Normal, tolerance) && ApproximateEquals(a.Radius, b.Radius, tolerance); /// /// Returns whether the given are equal within /// Constant<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b) => ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Cone/Cone3_auto.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region ObliqueCone3f /// /// An oblique cone in 3-space represented by its origin (apex) and base circle. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public readonly struct ObliqueCone3f : IEquatable { [DataMember] public readonly V3f Origin; [DataMember] public readonly Circle3f Circle; #region Constructor [MethodImpl(MethodImplOptions.AggressiveInlining)] public ObliqueCone3f(V3f o, Circle3f c) { Origin = o; Circle = c; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ObliqueCone3f(ObliqueCone3f o) { Origin = o.Origin; Circle = o.Circle; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ObliqueCone3f(ObliqueCone3d o) { Origin = (V3f)o.Origin; Circle = (Circle3f)o.Circle; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ObliqueCone3f(ObliqueCone3d c) => new ObliqueCone3f(c); #endregion #region Constants public static ObliqueCone3f Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ObliqueCone3f(V3f.NaN, Circle3f.Invalid); } #endregion #region Properties public bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Circle.Radius >= 0; } public bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Circle.Radius < 0; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(ObliqueCone3f a, ObliqueCone3f b) => (a.Origin == b.Origin) && (a.Circle == b.Circle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(ObliqueCone3f a, ObliqueCone3f b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() => HashCode.GetCombined(Origin, Circle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ObliqueCone3f other) => Origin.Equals(other.Origin) && Circle.Equals(other.Circle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object other) => (other is ObliqueCone3f o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Origin, Circle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ObliqueCone3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new ObliqueCone3f(V3f.Parse(x[0]), Circle3f.Parse(x[1])); } #endregion #region Operations /// /// get circle of oblique cone where distance between cone origin and circle origin equals distance /// public Circle3f GetCircle(float distance) { var dir = Circle.Center - Origin; var pDistance = dir.Length; dir.Normalize(); var newCenter = Origin + dir * distance; var newRadius = distance / pDistance * Circle.Radius; return new Circle3f(newCenter, Circle.Normal, newRadius); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this ObliqueCone3f a, ObliqueCone3f b, float tolerance) => ApproximateEquals(a.Origin, b.Origin, tolerance) && ApproximateEquals(a.Circle, b.Circle, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this ObliqueCone3f a, ObliqueCone3f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Cone3f /// /// A cone in 3-space represented by its origin, axis of revolution (Direction), and the angle between axis and outer edge. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Cone3f : IEquatable, IValidity { [DataMember] public V3f Origin; /// /// Axis of revolution. /// [DataMember] public V3f Direction; /// /// Angle between axis and outer edge (in radians). /// [DataMember] public float Angle; #region Constructor [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cone3f(V3f origin, V3f dir, float angle) { Origin = origin; Direction = dir; Angle = angle; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cone3f(Cone3f o) { Origin = o.Origin; Direction = o.Direction; Angle = o.Angle; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cone3f(Cone3d o) { Origin = (V3f)o.Origin; Direction = (V3f)o.Direction; Angle = (float)o.Angle; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Cone3f(Cone3d c) => new Cone3f(c); #endregion #region Constants public static Cone3f Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Cone3f(V3f.NaN, V3f.Zero, 0); } #endregion #region Properties public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Direction != V3f.Zero; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Direction == V3f.Zero; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Cone3f a, Cone3f b) => (a.Origin == b.Origin) && (a.Direction == b.Direction) && (a.Angle == b.Angle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Cone3f a, Cone3f b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Origin, Direction, Angle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Cone3f other) => Origin.Equals(other.Origin) && Direction.Equals(other.Direction) && Angle.Equals(other.Angle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Cone3f o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", Origin, Direction, Angle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Cone3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Cone3f(V3f.Parse(x[0]), V3f.Parse(x[1]), float.Parse(x[2], CultureInfo.InvariantCulture)); } #endregion #region Operations /// /// if zero, point is located on cone /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float GetDistance(V3f point) => Vec.Distance(point, GetClosestPoint(point)); public readonly Circle3f GetCircle(float height) { //circle along axis var dirLength = height; var radius = GetRadius(height); var dir = Direction.Normalized * dirLength; return new Circle3f(Origin + dir, dir.Normalized, radius); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Ray3f GetAxis() => new Ray3f(Origin, Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float GetHeight(V3f position) => new Ray3f(Origin, Direction).GetTOfProjectedPoint(position); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float GetRadius(float height) => height * Angle.Sin() / Angle.Cos(); public readonly V3f GetClosestPoint(V3f point) { var ray = new Ray3f(Origin, Direction); var cp = point.GetClosestPointOn(ray); var radius = GetRadius(GetHeight(point)); var dir = (point - cp).Normalized * radius; var p0 = cp + dir; var p1 = point.GetClosestPointOn(new Ray3f(Origin, (p0 - Origin).Normalized)); return (Vec.Distance(point, p1) < Vec.Distance(point, p0)) ? p1 : p0; } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Cone3f a, Cone3f b, float tolerance) => ApproximateEquals(a.Origin, b.Origin, tolerance) && ApproximateEquals(a.Direction, b.Direction, tolerance) && ApproximateEquals(a.Angle, b.Angle, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Cone3f a, Cone3f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region ObliqueCone3d /// /// An oblique cone in 3-space represented by its origin (apex) and base circle. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public readonly struct ObliqueCone3d : IEquatable { [DataMember] public readonly V3d Origin; [DataMember] public readonly Circle3d Circle; #region Constructor [MethodImpl(MethodImplOptions.AggressiveInlining)] public ObliqueCone3d(V3d o, Circle3d c) { Origin = o; Circle = c; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ObliqueCone3d(ObliqueCone3d o) { Origin = o.Origin; Circle = o.Circle; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ObliqueCone3d(ObliqueCone3f o) { Origin = (V3d)o.Origin; Circle = (Circle3d)o.Circle; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ObliqueCone3d(ObliqueCone3f c) => new ObliqueCone3d(c); #endregion #region Constants public static ObliqueCone3d Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ObliqueCone3d(V3d.NaN, Circle3d.Invalid); } #endregion #region Properties public bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Circle.Radius >= 0; } public bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Circle.Radius < 0; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(ObliqueCone3d a, ObliqueCone3d b) => (a.Origin == b.Origin) && (a.Circle == b.Circle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(ObliqueCone3d a, ObliqueCone3d b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() => HashCode.GetCombined(Origin, Circle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ObliqueCone3d other) => Origin.Equals(other.Origin) && Circle.Equals(other.Circle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object other) => (other is ObliqueCone3d o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Origin, Circle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ObliqueCone3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new ObliqueCone3d(V3d.Parse(x[0]), Circle3d.Parse(x[1])); } #endregion #region Operations /// /// get circle of oblique cone where distance between cone origin and circle origin equals distance /// public Circle3d GetCircle(double distance) { var dir = Circle.Center - Origin; var pDistance = dir.Length; dir.Normalize(); var newCenter = Origin + dir * distance; var newRadius = distance / pDistance * Circle.Radius; return new Circle3d(newCenter, Circle.Normal, newRadius); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this ObliqueCone3d a, ObliqueCone3d b, double tolerance) => ApproximateEquals(a.Origin, b.Origin, tolerance) && ApproximateEquals(a.Circle, b.Circle, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this ObliqueCone3d a, ObliqueCone3d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Cone3d /// /// A cone in 3-space represented by its origin, axis of revolution (Direction), and the angle between axis and outer edge. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Cone3d : IEquatable, IValidity { [DataMember] public V3d Origin; /// /// Axis of revolution. /// [DataMember] public V3d Direction; /// /// Angle between axis and outer edge (in radians). /// [DataMember] public double Angle; #region Constructor [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cone3d(V3d origin, V3d dir, double angle) { Origin = origin; Direction = dir; Angle = angle; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cone3d(Cone3d o) { Origin = o.Origin; Direction = o.Direction; Angle = o.Angle; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cone3d(Cone3f o) { Origin = (V3d)o.Origin; Direction = (V3d)o.Direction; Angle = (double)o.Angle; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Cone3d(Cone3f c) => new Cone3d(c); #endregion #region Constants public static Cone3d Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Cone3d(V3d.NaN, V3d.Zero, 0); } #endregion #region Properties public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Direction != V3d.Zero; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Direction == V3d.Zero; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Cone3d a, Cone3d b) => (a.Origin == b.Origin) && (a.Direction == b.Direction) && (a.Angle == b.Angle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Cone3d a, Cone3d b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Origin, Direction, Angle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Cone3d other) => Origin.Equals(other.Origin) && Direction.Equals(other.Direction) && Angle.Equals(other.Angle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Cone3d o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", Origin, Direction, Angle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Cone3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Cone3d(V3d.Parse(x[0]), V3d.Parse(x[1]), double.Parse(x[2], CultureInfo.InvariantCulture)); } #endregion #region Operations /// /// if zero, point is located on cone /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double GetDistance(V3d point) => Vec.Distance(point, GetClosestPoint(point)); public readonly Circle3d GetCircle(double height) { //circle along axis var dirLength = height; var radius = GetRadius(height); var dir = Direction.Normalized * dirLength; return new Circle3d(Origin + dir, dir.Normalized, radius); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Ray3d GetAxis() => new Ray3d(Origin, Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double GetHeight(V3d position) => new Ray3d(Origin, Direction).GetTOfProjectedPoint(position); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double GetRadius(double height) => height * Angle.Sin() / Angle.Cos(); public readonly V3d GetClosestPoint(V3d point) { var ray = new Ray3d(Origin, Direction); var cp = point.GetClosestPointOn(ray); var radius = GetRadius(GetHeight(point)); var dir = (point - cp).Normalized * radius; var p0 = cp + dir; var p1 = point.GetClosestPointOn(new Ray3d(Origin, (p0 - Origin).Normalized)); return (Vec.Distance(point, p1) < Vec.Distance(point, p0)) ? p1 : p0; } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Cone3d a, Cone3d b, double tolerance) => ApproximateEquals(a.Origin, b.Origin, tolerance) && ApproximateEquals(a.Direction, b.Direction, tolerance) && ApproximateEquals(a.Angle, b.Angle, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Cone3d a, Cone3d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Cone/Cone3_template.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Cone3" + tc; //# var type2 = "Cone3" + tc2; //# var v3t = "V3" + tc; //# var box3t = "Box3" + tc; //# var ray3t = "Ray3" + tc; //# var plane3t = "Plane3" + tc; //# var circle3t = "Circle3" + tc; //# var sphere3t = "Sphere3" + tc; //# var iboundingsphere3t = "IBoundingSphere3" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var pi = isDouble ? "Constant.Pi" : "ConstantF.Pi"; //# var eps = isDouble ? "1e-9" : "1e-5f"; #region Oblique__type__ /// /// An oblique cone in 3-space represented by its origin (apex) and base circle. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public readonly struct Oblique__type__ : IEquatable { [DataMember] public readonly __v3t__ Origin; [DataMember] public readonly __circle3t__ Circle; #region Constructor [MethodImpl(MethodImplOptions.AggressiveInlining)] public Oblique__type__(__v3t__ o, __circle3t__ c) { Origin = o; Circle = c; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Oblique__type__(Oblique__type__ o) { Origin = o.Origin; Circle = o.Circle; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Oblique__type__(Oblique__type2__ o) { Origin = (__v3t__)o.Origin; Circle = (__circle3t__)o.Circle; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Oblique__type__(Oblique__type2__ c) => new Oblique__type__(c); #endregion #region Constants public static Oblique__type__ Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Oblique__type__(__v3t__.NaN, __circle3t__.Invalid); } #endregion #region Properties public bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Circle.Radius >= 0; } public bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Circle.Radius < 0; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Oblique__type__ a, Oblique__type__ b) => (a.Origin == b.Origin) && (a.Circle == b.Circle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Oblique__type__ a, Oblique__type__ b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() => HashCode.GetCombined(Origin, Circle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Oblique__type__ other) => Origin.Equals(other.Origin) && Circle.Equals(other.Circle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object other) => (other is Oblique__type__ o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Origin, Circle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Oblique__type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Oblique__type__(__v3t__.Parse(x[0]), __circle3t__.Parse(x[1])); } #endregion #region Operations /// /// get circle of oblique cone where distance between cone origin and circle origin equals distance /// public __circle3t__ GetCircle(__ftype__ distance) { var dir = Circle.Center - Origin; var pDistance = dir.Length; dir.Normalize(); var newCenter = Origin + dir * distance; var newRadius = distance / pDistance * Circle.Radius; return new __circle3t__(newCenter, Circle.Normal, newRadius); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Oblique__type__ a, Oblique__type__ b, __ftype__ tolerance) => ApproximateEquals(a.Origin, b.Origin, tolerance) && ApproximateEquals(a.Circle, b.Circle, tolerance); /// /// Returns whether the given are equal within /// Constant<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Oblique__type__ a, Oblique__type__ b) => ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } #endregion #region __type__ /// /// A cone in 3-space represented by its origin, axis of revolution (Direction), and the angle between axis and outer edge. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__>, IValidity { [DataMember] public __v3t__ Origin; /// /// Axis of revolution. /// [DataMember] public __v3t__ Direction; /// /// Angle between axis and outer edge (in radians). /// [DataMember] public __ftype__ Angle; #region Constructor [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__v3t__ origin, __v3t__ dir, __ftype__ angle) { Origin = origin; Direction = dir; Angle = angle; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ o) { Origin = o.Origin; Direction = o.Direction; Angle = o.Angle; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ o) { Origin = (__v3t__)o.Origin; Direction = (__v3t__)o.Direction; Angle = (__ftype__)o.Angle; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type__(__type2__ c) => new __type__(c); #endregion #region Constants public static __type__ Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(__v3t__.NaN, __v3t__.Zero, 0); } #endregion #region Properties public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Direction != __v3t__.Zero; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Direction == __v3t__.Zero; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ a, __type__ b) => (a.Origin == b.Origin) && (a.Direction == b.Direction) && (a.Angle == b.Angle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ a, __type__ b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Origin, Direction, Angle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => Origin.Equals(other.Origin) && Direction.Equals(other.Direction) && Angle.Equals(other.Angle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", Origin, Direction, Angle); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__(__v3t__.Parse(x[0]), __v3t__.Parse(x[1]), __ftype__.Parse(x[2], CultureInfo.InvariantCulture)); } #endregion #region Operations /// /// if zero, point is located on cone /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__ GetDistance(__v3t__ point) => Vec.Distance(point, GetClosestPoint(point)); public readonly __circle3t__ GetCircle(__ftype__ height) { //circle along axis var dirLength = height; var radius = GetRadius(height); var dir = Direction.Normalized * dirLength; return new __circle3t__(Origin + dir, dir.Normalized, radius); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ray3t__ GetAxis() => new __ray3t__(Origin, Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__ GetHeight(__v3t__ position) => new __ray3t__(Origin, Direction).GetTOfProjectedPoint(position); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__ GetRadius(__ftype__ height) => height * Angle.Sin() / Angle.Cos(); public readonly __v3t__ GetClosestPoint(__v3t__ point) { var ray = new __ray3t__(Origin, Direction); var cp = point.GetClosestPointOn(ray); var radius = GetRadius(GetHeight(point)); var dir = (point - cp).Normalized * radius; var p0 = cp + dir; var p1 = point.GetClosestPointOn(new __ray3t__(Origin, (p0 - Origin).Normalized)); return (Vec.Distance(point, p1) < Vec.Distance(point, p0)) ? p1 : p0; } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b, __ftype__ tolerance) => ApproximateEquals(a.Origin, b.Origin, tolerance) && ApproximateEquals(a.Direction, b.Direction, tolerance) && ApproximateEquals(a.Angle, b.Angle, tolerance); /// /// Returns whether the given are equal within /// Constant<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b) => ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Cone/Conic2_auto.cs ================================================ using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Conic2f /// /// WARNING: Sektch! /// Defines the conic section CXX x^2 + CYY y^2 + CZZ z^2 + CXY xy + CYZ yz + CYZ yz = 0 /// with (x,y,z) being homogenous coordinates. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Conic2f { [DataMember] public float CXX; [DataMember] public float CYY; [DataMember] public float CZZ; [DataMember] public float CXY; [DataMember] public float CXZ; [DataMember] public float CYZ; public Conic2f(float cxx, float cyy, float czz, float cxy, float cxz, float cyz) { CXX = cxx; CYY = cyy; CZZ = czz; CXY = cxy; CXZ = cxz; CYZ = cyz; } public readonly float Discriminant { get { return CXX * CYY - CXY * CXY; } } public readonly int ConicType { get { var d = Discriminant; return d > Constant.PositiveTinyValue ? 1 : d < Constant.NegativeTinyValue ? -1 : 0; } } } #endregion #region Conic2d /// /// WARNING: Sektch! /// Defines the conic section CXX x^2 + CYY y^2 + CZZ z^2 + CXY xy + CYZ yz + CYZ yz = 0 /// with (x,y,z) being homogenous coordinates. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Conic2d { [DataMember] public double CXX; [DataMember] public double CYY; [DataMember] public double CZZ; [DataMember] public double CXY; [DataMember] public double CXZ; [DataMember] public double CYZ; public Conic2d(double cxx, double cyy, double czz, double cxy, double cxz, double cyz) { CXX = cxx; CYY = cyy; CZZ = czz; CXY = cxy; CXZ = cxz; CYZ = cyz; } public readonly double Discriminant { get { return CXX * CYY - CXY * CXY; } } public readonly int ConicType { get { var d = Discriminant; return d > Constant.PositiveTinyValue ? 1 : d < Constant.NegativeTinyValue ? -1 : 0; } } } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Cone/Conic2_template.cs ================================================ using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Conic2" + tc; //# var type2 = "Conic2" + tc2; //# var v2t = "V2" + tc; #region __type__ /// /// WARNING: Sektch! /// Defines the conic section CXX x^2 + CYY y^2 + CZZ z^2 + CXY xy + CYZ yz + CYZ yz = 0 /// with (x,y,z) being homogenous coordinates. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ { [DataMember] public __ftype__ CXX; [DataMember] public __ftype__ CYY; [DataMember] public __ftype__ CZZ; [DataMember] public __ftype__ CXY; [DataMember] public __ftype__ CXZ; [DataMember] public __ftype__ CYZ; public __type__(__ftype__ cxx, __ftype__ cyy, __ftype__ czz, __ftype__ cxy, __ftype__ cxz, __ftype__ cyz) { CXX = cxx; CYY = cyy; CZZ = czz; CXY = cxy; CXZ = cxz; CYZ = cyz; } public readonly __ftype__ Discriminant { get { return CXX * CYY - CXY * CXY; } } public readonly int ConicType { get { var d = Discriminant; return d > Constant<__ftype__>.PositiveTinyValue ? 1 : d < Constant<__ftype__>.NegativeTinyValue ? -1 : 0; } } } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Cylinder/Cylinder3_auto.cs ================================================ using System; using System.Globalization; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Cylinder3f [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Cylinder3f : IEquatable, IBoundingBox3f, IValidity { [DataMember] public V3f P0; [DataMember] public V3f P1; [DataMember] public float Radius; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cylinder3f(V3f p0, V3f p1, float radius) { P0 = p0; P1 = p1; Radius = radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cylinder3f(Line3f axis, float radius) { P0 = axis.P0; P1 = axis.P1; Radius = radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cylinder3f(Cylinder3f c) { P0 = c.P0; P1 = c.P1; Radius = c.Radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cylinder3f(Cylinder3d c) { P0 = (V3f)c.P0; P1 = (V3f)c.P1; Radius = (float)c.Radius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Cylinder3f(Cylinder3d c) => new Cylinder3f(c); #endregion #region Constants public static Cylinder3f Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Cylinder3f(V3f.NaN, V3f.NaN, -1); } #endregion #region Properties public readonly float Height { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (P0 - P1).Length; } public readonly V3f Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (P0 + P1) * 0.5f; } public readonly Line3f Axis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Line3f(P0, P1); } public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius >= 0; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius < 0; } public readonly Circle3f Circle0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Circle3f(P0, (P0 - P1).Normalized, Radius); } public readonly Circle3f Circle1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Circle3f(P1, (P1 - P0).Normalized, Radius); } public readonly float Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius * ConstantF.PiTimesTwo * (Radius + Height); } public readonly float Volume { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius * Radius * ConstantF.Pi * Height; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Cylinder3f a, Cylinder3f b) => (a.P0 == b.P0) && (a.P1 == b.P1) && (a.Radius == b.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Cylinder3f a, Cylinder3f b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(P0, P1, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Cylinder3f other) => P0.Equals(other.P0) && P1.Equals(other.P1) && Radius.Equals(other.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Cylinder3f o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", P0, P1, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Cylinder3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Cylinder3f( V3f.Parse(x[0]), V3f.Parse(x[1]), float.Parse(x[2], CultureInfo.InvariantCulture) ); } #endregion #region Operations /// /// P0 has height 0.0, P1 has height 1.0 /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float GetHeight(V3f p) { var dir = (P1 - P0).Normalized; var pp = p.GetClosestPointOn(new Ray3f(P0, dir)); return (pp - P0).Dot(dir); } /// /// Get circle at a specific height /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Circle3f GetCircle(float height) { var dir = (P1 - P0).Normalized; return new Circle3f(P0 + height * dir, dir, Radius); } #endregion #region IBoundingBox3f Members public readonly Box3f BoundingBox3f { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Box3f(Circle0.BoundingBox3f, Circle1.BoundingBox3f); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Cylinder3f a, Cylinder3f b, float tolerance) => ApproximateEquals(a.P0, b.P0, tolerance) && ApproximateEquals(a.P1, b.P1, tolerance) && ApproximateEquals(a.Radius, b.Radius, tolerance); /// /// Returns whether the given are equal within /// ConstantF<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Cylinder3f a, Cylinder3f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Cylinder3d [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Cylinder3d : IEquatable, IBoundingBox3d, IValidity { [DataMember] public V3d P0; [DataMember] public V3d P1; [DataMember] public double Radius; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cylinder3d(V3d p0, V3d p1, double radius) { P0 = p0; P1 = p1; Radius = radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cylinder3d(Line3d axis, double radius) { P0 = axis.P0; P1 = axis.P1; Radius = radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cylinder3d(Cylinder3d c) { P0 = c.P0; P1 = c.P1; Radius = c.Radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cylinder3d(Cylinder3f c) { P0 = (V3d)c.P0; P1 = (V3d)c.P1; Radius = (double)c.Radius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Cylinder3d(Cylinder3f c) => new Cylinder3d(c); #endregion #region Constants public static Cylinder3d Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Cylinder3d(V3d.NaN, V3d.NaN, -1); } #endregion #region Properties public readonly double Height { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (P0 - P1).Length; } public readonly V3d Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (P0 + P1) * 0.5; } public readonly Line3d Axis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Line3d(P0, P1); } public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius >= 0; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius < 0; } public readonly Circle3d Circle0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Circle3d(P0, (P0 - P1).Normalized, Radius); } public readonly Circle3d Circle1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Circle3d(P1, (P1 - P0).Normalized, Radius); } public readonly double Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius * Constant.PiTimesTwo * (Radius + Height); } public readonly double Volume { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius * Radius * Constant.Pi * Height; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Cylinder3d a, Cylinder3d b) => (a.P0 == b.P0) && (a.P1 == b.P1) && (a.Radius == b.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Cylinder3d a, Cylinder3d b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(P0, P1, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Cylinder3d other) => P0.Equals(other.P0) && P1.Equals(other.P1) && Radius.Equals(other.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Cylinder3d o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", P0, P1, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Cylinder3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Cylinder3d( V3d.Parse(x[0]), V3d.Parse(x[1]), double.Parse(x[2], CultureInfo.InvariantCulture) ); } #endregion #region Operations /// /// P0 has height 0.0, P1 has height 1.0 /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double GetHeight(V3d p) { var dir = (P1 - P0).Normalized; var pp = p.GetClosestPointOn(new Ray3d(P0, dir)); return (pp - P0).Dot(dir); } /// /// Get circle at a specific height /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Circle3d GetCircle(double height) { var dir = (P1 - P0).Normalized; return new Circle3d(P0 + height * dir, dir, Radius); } #endregion #region IBoundingBox3d Members public readonly Box3d BoundingBox3d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Box3d(Circle0.BoundingBox3d, Circle1.BoundingBox3d); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Cylinder3d a, Cylinder3d b, double tolerance) => ApproximateEquals(a.P0, b.P0, tolerance) && ApproximateEquals(a.P1, b.P1, tolerance) && ApproximateEquals(a.Radius, b.Radius, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Cylinder3d a, Cylinder3d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Cylinder/Cylinder3_template.cs ================================================ using System; using System.Globalization; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Cylinder3" + tc; //# var type2 = "Cylinder3" + tc2; //# var v3t = "V3" + tc; //# var circle3t = "Circle3" + tc; //# var box3t = "Box3" + tc; //# var line3t = "Line3" + tc; //# var ray3t = "Ray3" + tc; //# var iboundingbox = "IBoundingBox3" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var dotnine = isDouble ? "0.9" : "0.9f"; //# var constant = isDouble ? "Constant" : "ConstantF"; #region __type__ [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__>, __iboundingbox__, IValidity { [DataMember] public __v3t__ P0; [DataMember] public __v3t__ P1; [DataMember] public __ftype__ Radius; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__v3t__ p0, __v3t__ p1, __ftype__ radius) { P0 = p0; P1 = p1; Radius = radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__line3t__ axis, __ftype__ radius) { P0 = axis.P0; P1 = axis.P1; Radius = radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ c) { P0 = c.P0; P1 = c.P1; Radius = c.Radius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ c) { P0 = (__v3t__)c.P0; P1 = (__v3t__)c.P1; Radius = (__ftype__)c.Radius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type__(__type2__ c) => new __type__(c); #endregion #region Constants public static __type__ Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(__v3t__.NaN, __v3t__.NaN, -1); } #endregion #region Properties public readonly __ftype__ Height { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (P0 - P1).Length; } public readonly __v3t__ Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (P0 + P1) * __half__; } public readonly __line3t__ Axis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __line3t__(P0, P1); } public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius >= 0; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius < 0; } public readonly __circle3t__ Circle0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __circle3t__(P0, (P0 - P1).Normalized, Radius); } public readonly __circle3t__ Circle1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __circle3t__(P1, (P1 - P0).Normalized, Radius); } public readonly __ftype__ Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius * __constant__.PiTimesTwo * (Radius + Height); } public readonly __ftype__ Volume { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius * Radius * __constant__.Pi * Height; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ a, __type__ b) => (a.P0 == b.P0) && (a.P1 == b.P1) && (a.Radius == b.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ a, __type__ b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(P0, P1, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => P0.Equals(other.P0) && P1.Equals(other.P1) && Radius.Equals(other.Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", P0, P1, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__( __v3t__.Parse(x[0]), __v3t__.Parse(x[1]), __ftype__.Parse(x[2], CultureInfo.InvariantCulture) ); } #endregion #region Operations /// /// P0 has height 0.0, P1 has height 1.0 /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__ GetHeight(__v3t__ p) { var dir = (P1 - P0).Normalized; var pp = p.GetClosestPointOn(new __ray3t__(P0, dir)); return (pp - P0).Dot(dir); } /// /// Get circle at a specific height /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __circle3t__ GetCircle(__ftype__ height) { var dir = (P1 - P0).Normalized; return new __circle3t__(P0 + height * dir, dir, Radius); } #endregion #region __iboundingbox__ Members public readonly __box3t__ BoundingBox3__tc__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __box3t__(Circle0.BoundingBox3__tc__, Circle1.BoundingBox3__tc__); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b, __ftype__ tolerance) => ApproximateEquals(a.P0, b.P0, tolerance) && ApproximateEquals(a.P1, b.P1, tolerance) && ApproximateEquals(a.Radius, b.Radius, tolerance); /// /// Returns whether the given are equal within /// __constant__<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b) => ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Ellipse/Ellipse2_auto.cs ================================================ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Linq; using System.Text; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Ellipse2f public partial struct Ellipse2f : IValidity { public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly float Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Abs(Axis0.X * Axis1.Y - Axis0.Y * Axis1.X) * ConstantF.Pi; } [MethodImpl(MethodImplOptions.AggressiveInlining)] static float GetArea(V2f axis0, V2f axis1) => Fun.Abs(axis0.X * axis1.Y - axis0.Y * axis1.X) * ConstantF.Pi; } #endregion #region Ellipse2d public partial struct Ellipse2d : IValidity { public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly double Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Abs(Axis0.X * Axis1.Y - Axis0.Y * Axis1.X) * Constant.Pi; } [MethodImpl(MethodImplOptions.AggressiveInlining)] static double GetArea(V2d axis0, V2d axis1) => Fun.Abs(axis0.X * axis1.Y - axis0.Y * axis1.X) * Constant.Pi; } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Ellipse/Ellipse2_template.cs ================================================ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Linq; using System.Text; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var tc = isDouble ? "d" : "f"; //# var type = "Ellipse2" + tc; //# var v2t = "V2" + tc; //# var pi = isDouble ? "Constant.Pi" : "ConstantF.Pi"; #region __type__ public partial struct __type__ : IValidity { public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly __ftype__ Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Abs(Axis0.X * Axis1.Y - Axis0.Y * Axis1.X) * __pi__; } [MethodImpl(MethodImplOptions.AggressiveInlining)] static __ftype__ GetArea(__v2t__ axis0, __v2t__ axis1) => Fun.Abs(axis0.X * axis1.Y - axis0.Y * axis1.X) * __pi__; } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Ellipse/Ellipse3_auto.cs ================================================ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Linq; using System.Text; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Ellipse3f public partial struct Ellipse3f : IValidity { public static Ellipse3f Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Ellipse3f(V3f.NaN, V3f.Zero, V3f.NaN, V3f.NaN); } public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal != V3f.Zero; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal == V3f.Zero; } public readonly float Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Vec.Cross(Axis0, Axis1).Length * ConstantF.Pi; } } #endregion #region Ellipse3d public partial struct Ellipse3d : IValidity { public static Ellipse3d Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Ellipse3d(V3d.NaN, V3d.Zero, V3d.NaN, V3d.NaN); } public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal != V3d.Zero; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal == V3d.Zero; } public readonly double Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Vec.Cross(Axis0, Axis1).Length * Constant.Pi; } } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Ellipse/Ellipse3_template.cs ================================================ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Linq; using System.Text; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var tc = isDouble ? "d" : "f"; //# var type = "Ellipse3" + tc; //# var v3t = "V3" + tc; //# var pi = isDouble ? "Constant.Pi" : "ConstantF.Pi"; #region __type__ public partial struct __type__ : IValidity { public static __type__ Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(__v3t__.NaN, __v3t__.Zero, __v3t__.NaN, __v3t__.NaN); } public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal != __v3t__.Zero; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal == __v3t__.Zero; } public readonly __ftype__ Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Vec.Cross(Axis0, Axis1).Length * __pi__; } } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Ellipse/Ellipse_auto.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Ellipse2f /// /// A 2d ellipse is defined by its center /// and two half-axes. /// Note that in principle any two conjugate half-diameters /// can be used as axes, however some algorithms require that /// the major and minor half axes are known. By convention /// in this case, axis0 is the major half axis. /// [StructLayout(LayoutKind.Sequential)] public partial struct Ellipse2f { public V2f Center; public V2f Axis0; public V2f Axis1; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ellipse2f(V2f center, V2f axis0, V2f axis1) { Center = center; Axis0 = axis0; Axis1 = axis1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ellipse2f(Ellipse2f o) { Center = o.Center; Axis0 = o.Axis0; Axis1 = o.Axis1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ellipse2f(Ellipse2d o) { Center = (V2f)o.Center; Axis0 = (V2f)o.Axis0; Axis1 = (V2f)o.Axis1; } /// /// Construct ellipse from two conjugate diameters, and set /// Axis0 to the major axis and Axis1 to the minor axis. /// The algorithm was constructed from first principles. /// public static Ellipse2f FromConjugateDiameters(V2f center, V2f a, V2f b) { var ab = Vec.Dot(a, b); float a2 = a.LengthSquared, b2 = b.LengthSquared; if (ab.IsTiny()) { if (a2 >= b2) return new Ellipse2f(center, a, b); else return new Ellipse2f(center, b, a); } else { var t = 0.5f * Fun.Atan2(2 * ab, a2 - b2); float ct = Fun.Cos(t), st = Fun.Sin(t); V2f v0 = a * ct + b * st, v1 = b * ct - a * st; if (v0.LengthSquared >= v1.LengthSquared) return new Ellipse2f(center, v0, v1); else return new Ellipse2f(center, v1, v0); } } /// /// Construct ellipse from two conjugate diameters, and set /// Axis0 to the major axis and Axis1 to the minor axis. /// The algorithm was constructed from first principles. /// Also computes the squared lengths of the major and minor /// half axis. /// public static Ellipse2f FromConjugateDiameters(V2f center, V2f a, V2f b, out float major2, out float minor2) { var ab = Vec.Dot(a, b); float a2 = a.LengthSquared, b2 = b.LengthSquared; if (ab.IsTiny()) { if (a2 >= b2) { major2 = a2; minor2 = b2; return new Ellipse2f(center, a, b); } else { major2 = b2; minor2 = a2; return new Ellipse2f(center, b, a); } } else { var t = 0.5f * Fun.Atan2(2 * ab, a2 - b2); float ct = Fun.Cos(t), st = Fun.Sin(t); V2f v0 = a * ct + b * st, v1 = b * ct - a * st; a2 = v0.LengthSquared; b2 = v1.LengthSquared; if (a2 >= b2) { major2 = a2; minor2 = b2; return new Ellipse2f(center, v0, v1); } else { major2 = b2; minor2 = a2; return new Ellipse2f(center, v1, v0); } } } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Ellipse2f(Ellipse2d o) => new Ellipse2f(o); #endregion #region Constants public static Ellipse2f Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Ellipse2f(V2f.Zero, V2f.Zero, V2f.Zero); } #endregion #region Operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f GetVector(float alpha) => Axis0 * Fun.Cos(alpha) + Axis1 * Fun.Sin(alpha); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f GetPoint(float alpha) => Center + Axis0 * Fun.Cos(alpha) + Axis1 * Fun.Sin(alpha); /// /// Perform the supplied action for each of count vectors from the center /// of the ellipse to the circumference. /// public readonly void ForEachVector(int count, Action index_vector_act) { float d = ConstantF.PiTimesTwo / count; float a = Fun.Sin(d * 0.5f).Square() * 2, b = Fun.Sin(d); // init trig. recurrence float ct = 1, st = 0; index_vector_act(0, Axis0); for (int i = 1; i < count; i++) { float dct = a * ct + b * st, dst = a * st - b * ct; ; // trig. recurrence ct -= dct; st -= dst; // cos (t + d), sin (t + d) index_vector_act(i, Axis0 * ct + Axis1 * st); } } /// /// Get count points on the circumference of the ellipse. /// public readonly V2f[] GetPoints(int count) { var array = new V2f[count]; var c = Center; ForEachVector(count, (i, v) => array[i] = c + v); return array; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Ellipse2f a, Ellipse2f b) => (a.Center == b.Center) && (a.Axis0 == b.Axis0) && (a.Axis1 == b.Axis1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Ellipse2f a, Ellipse2f b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Center, Axis0, Axis1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Ellipse2f other) => Center.Equals(other.Center) && Axis0.Equals(other.Axis0) && Axis1.Equals(other.Axis1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Ellipse2f o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", Center, Axis0, Axis1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Ellipse2f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Ellipse2f( V2f.Parse(x[0]), V2f.Parse(x[1]), V2f.Parse(x[2]) ); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Ellipse2f a, Ellipse2f b, float tolerance) => ApproximateEquals(a.Center, b.Center, tolerance) && ApproximateEquals(a.Axis0, b.Axis0, tolerance) && ApproximateEquals(a.Axis1, b.Axis1, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Ellipse2f a, Ellipse2f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Ellipse3f /// /// A 3d ellipse is defined by its center, its plane normal, /// and two half-axes. /// Note that in principle any two conjugate half-diameters /// can be used as axes, however some algorithms require that /// the major and minor half axes are known. By convention /// in this case, axis0 is the major half axis. /// [StructLayout(LayoutKind.Sequential)] public partial struct Ellipse3f { public V3f Center; public V3f Normal; public V3f Axis0; public V3f Axis1; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ellipse3f(V3f center, V3f normal, V3f axis0, V3f axis1) { Center = center; Normal = normal; Axis0 = axis0; Axis1 = axis1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ellipse3f(Ellipse3f o) { Center = o.Center; Normal = o.Normal; Axis0 = o.Axis0; Axis1 = o.Axis1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ellipse3f(Ellipse3d o) { Center = (V3f)o.Center; Normal = (V3f)o.Normal; Axis0 = (V3f)o.Axis0; Axis1 = (V3f)o.Axis1; } /// /// Construct ellipse from two conjugate diameters, and set /// Axis0 to the major axis and Axis1 to the minor axis. /// The algorithm was constructed from first principles. /// public static Ellipse3f FromConjugateDiameters(V3f center, V3f normal, V3f a, V3f b) { var ab = Vec.Dot(a, b); float a2 = a.LengthSquared, b2 = b.LengthSquared; if (ab.IsTiny()) { if (a2 >= b2) return new Ellipse3f(center, normal, a, b); else return new Ellipse3f(center, normal, b, a); } else { var t = 0.5f * Fun.Atan2(2 * ab, a2 - b2); float ct = Fun.Cos(t), st = Fun.Sin(t); V3f v0 = a * ct + b * st, v1 = b * ct - a * st; if (v0.LengthSquared >= v1.LengthSquared) return new Ellipse3f(center, normal, v0, v1); else return new Ellipse3f(center, normal, v1, v0); } } /// /// Construct ellipse from two conjugate diameters, and set /// Axis0 to the major axis and Axis1 to the minor axis. /// The algorithm was constructed from first principles. /// Also computes the squared lengths of the major and minor /// half axis. /// public static Ellipse3f FromConjugateDiameters(V3f center, V3f normal, V3f a, V3f b, out float major2, out float minor2) { var ab = Vec.Dot(a, b); float a2 = a.LengthSquared, b2 = b.LengthSquared; if (ab.IsTiny()) { if (a2 >= b2) { major2 = a2; minor2 = b2; return new Ellipse3f(center, normal, a, b); } else { major2 = b2; minor2 = a2; return new Ellipse3f(center, normal, b, a); } } else { var t = 0.5f * Fun.Atan2(2 * ab, a2 - b2); float ct = Fun.Cos(t), st = Fun.Sin(t); V3f v0 = a * ct + b * st, v1 = b * ct - a * st; a2 = v0.LengthSquared; b2 = v1.LengthSquared; if (a2 >= b2) { major2 = a2; minor2 = b2; return new Ellipse3f(center, normal, v0, v1); } else { major2 = b2; minor2 = a2; return new Ellipse3f(center, normal, v1, v0); } } } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Ellipse3f(Ellipse3d o) => new Ellipse3f(o); #endregion #region Constants public static Ellipse3f Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Ellipse3f(V3f.Zero, V3f.Zero, V3f.Zero, V3f.Zero); } #endregion #region Operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f GetVector(float alpha) => Axis0 * Fun.Cos(alpha) + Axis1 * Fun.Sin(alpha); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f GetPoint(float alpha) => Center + Axis0 * Fun.Cos(alpha) + Axis1 * Fun.Sin(alpha); /// /// Perform the supplied action for each of count vectors from the center /// of the ellipse to the circumference. /// public readonly void ForEachVector(int count, Action index_vector_act) { float d = ConstantF.PiTimesTwo / count; float a = Fun.Sin(d * 0.5f).Square() * 2, b = Fun.Sin(d); // init trig. recurrence float ct = 1, st = 0; index_vector_act(0, Axis0); for (int i = 1; i < count; i++) { float dct = a * ct + b * st, dst = a * st - b * ct; ; // trig. recurrence ct -= dct; st -= dst; // cos (t + d), sin (t + d) index_vector_act(i, Axis0 * ct + Axis1 * st); } } /// /// Get count points on the circumference of the ellipse. /// public readonly V3f[] GetPoints(int count) { var array = new V3f[count]; var c = Center; ForEachVector(count, (i, v) => array[i] = c + v); return array; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Ellipse3f a, Ellipse3f b) => (a.Center == b.Center) && (a.Normal == b.Normal) && (a.Axis0 == b.Axis0) && (a.Axis1 == b.Axis1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Ellipse3f a, Ellipse3f b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Center, Normal, Axis0, Axis1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Ellipse3f other) => Center.Equals(other.Center) && Normal.Equals(other.Normal) && Axis0.Equals(other.Axis0) && Axis1.Equals(other.Axis1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Ellipse3f o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}, {3}]", Center, Normal, Axis0, Axis1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Ellipse3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Ellipse3f( V3f.Parse(x[0]), V3f.Parse(x[1]), V3f.Parse(x[2]), V3f.Parse(x[3]) ); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Ellipse3f a, Ellipse3f b, float tolerance) => ApproximateEquals(a.Center, b.Center, tolerance) && ApproximateEquals(a.Normal, b.Normal, tolerance) && ApproximateEquals(a.Axis0, b.Axis0, tolerance) && ApproximateEquals(a.Axis1, b.Axis1, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Ellipse3f a, Ellipse3f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Ellipse2d /// /// A 2d ellipse is defined by its center /// and two half-axes. /// Note that in principle any two conjugate half-diameters /// can be used as axes, however some algorithms require that /// the major and minor half axes are known. By convention /// in this case, axis0 is the major half axis. /// [StructLayout(LayoutKind.Sequential)] public partial struct Ellipse2d { public V2d Center; public V2d Axis0; public V2d Axis1; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ellipse2d(V2d center, V2d axis0, V2d axis1) { Center = center; Axis0 = axis0; Axis1 = axis1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ellipse2d(Ellipse2d o) { Center = o.Center; Axis0 = o.Axis0; Axis1 = o.Axis1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ellipse2d(Ellipse2f o) { Center = (V2d)o.Center; Axis0 = (V2d)o.Axis0; Axis1 = (V2d)o.Axis1; } /// /// Construct ellipse from two conjugate diameters, and set /// Axis0 to the major axis and Axis1 to the minor axis. /// The algorithm was constructed from first principles. /// public static Ellipse2d FromConjugateDiameters(V2d center, V2d a, V2d b) { var ab = Vec.Dot(a, b); double a2 = a.LengthSquared, b2 = b.LengthSquared; if (ab.IsTiny()) { if (a2 >= b2) return new Ellipse2d(center, a, b); else return new Ellipse2d(center, b, a); } else { var t = 0.5 * Fun.Atan2(2 * ab, a2 - b2); double ct = Fun.Cos(t), st = Fun.Sin(t); V2d v0 = a * ct + b * st, v1 = b * ct - a * st; if (v0.LengthSquared >= v1.LengthSquared) return new Ellipse2d(center, v0, v1); else return new Ellipse2d(center, v1, v0); } } /// /// Construct ellipse from two conjugate diameters, and set /// Axis0 to the major axis and Axis1 to the minor axis. /// The algorithm was constructed from first principles. /// Also computes the squared lengths of the major and minor /// half axis. /// public static Ellipse2d FromConjugateDiameters(V2d center, V2d a, V2d b, out double major2, out double minor2) { var ab = Vec.Dot(a, b); double a2 = a.LengthSquared, b2 = b.LengthSquared; if (ab.IsTiny()) { if (a2 >= b2) { major2 = a2; minor2 = b2; return new Ellipse2d(center, a, b); } else { major2 = b2; minor2 = a2; return new Ellipse2d(center, b, a); } } else { var t = 0.5 * Fun.Atan2(2 * ab, a2 - b2); double ct = Fun.Cos(t), st = Fun.Sin(t); V2d v0 = a * ct + b * st, v1 = b * ct - a * st; a2 = v0.LengthSquared; b2 = v1.LengthSquared; if (a2 >= b2) { major2 = a2; minor2 = b2; return new Ellipse2d(center, v0, v1); } else { major2 = b2; minor2 = a2; return new Ellipse2d(center, v1, v0); } } } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Ellipse2d(Ellipse2f o) => new Ellipse2d(o); #endregion #region Constants public static Ellipse2d Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Ellipse2d(V2d.Zero, V2d.Zero, V2d.Zero); } #endregion #region Operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d GetVector(double alpha) => Axis0 * Fun.Cos(alpha) + Axis1 * Fun.Sin(alpha); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d GetPoint(double alpha) => Center + Axis0 * Fun.Cos(alpha) + Axis1 * Fun.Sin(alpha); /// /// Perform the supplied action for each of count vectors from the center /// of the ellipse to the circumference. /// public readonly void ForEachVector(int count, Action index_vector_act) { double d = Constant.PiTimesTwo / count; double a = Fun.Sin(d * 0.5).Square() * 2, b = Fun.Sin(d); // init trig. recurrence double ct = 1, st = 0; index_vector_act(0, Axis0); for (int i = 1; i < count; i++) { double dct = a * ct + b * st, dst = a * st - b * ct; ; // trig. recurrence ct -= dct; st -= dst; // cos (t + d), sin (t + d) index_vector_act(i, Axis0 * ct + Axis1 * st); } } /// /// Get count points on the circumference of the ellipse. /// public readonly V2d[] GetPoints(int count) { var array = new V2d[count]; var c = Center; ForEachVector(count, (i, v) => array[i] = c + v); return array; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Ellipse2d a, Ellipse2d b) => (a.Center == b.Center) && (a.Axis0 == b.Axis0) && (a.Axis1 == b.Axis1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Ellipse2d a, Ellipse2d b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Center, Axis0, Axis1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Ellipse2d other) => Center.Equals(other.Center) && Axis0.Equals(other.Axis0) && Axis1.Equals(other.Axis1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Ellipse2d o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", Center, Axis0, Axis1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Ellipse2d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Ellipse2d( V2d.Parse(x[0]), V2d.Parse(x[1]), V2d.Parse(x[2]) ); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Ellipse2d a, Ellipse2d b, double tolerance) => ApproximateEquals(a.Center, b.Center, tolerance) && ApproximateEquals(a.Axis0, b.Axis0, tolerance) && ApproximateEquals(a.Axis1, b.Axis1, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Ellipse2d a, Ellipse2d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Ellipse3d /// /// A 3d ellipse is defined by its center, its plane normal, /// and two half-axes. /// Note that in principle any two conjugate half-diameters /// can be used as axes, however some algorithms require that /// the major and minor half axes are known. By convention /// in this case, axis0 is the major half axis. /// [StructLayout(LayoutKind.Sequential)] public partial struct Ellipse3d { public V3d Center; public V3d Normal; public V3d Axis0; public V3d Axis1; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ellipse3d(V3d center, V3d normal, V3d axis0, V3d axis1) { Center = center; Normal = normal; Axis0 = axis0; Axis1 = axis1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ellipse3d(Ellipse3d o) { Center = o.Center; Normal = o.Normal; Axis0 = o.Axis0; Axis1 = o.Axis1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ellipse3d(Ellipse3f o) { Center = (V3d)o.Center; Normal = (V3d)o.Normal; Axis0 = (V3d)o.Axis0; Axis1 = (V3d)o.Axis1; } /// /// Construct ellipse from two conjugate diameters, and set /// Axis0 to the major axis and Axis1 to the minor axis. /// The algorithm was constructed from first principles. /// public static Ellipse3d FromConjugateDiameters(V3d center, V3d normal, V3d a, V3d b) { var ab = Vec.Dot(a, b); double a2 = a.LengthSquared, b2 = b.LengthSquared; if (ab.IsTiny()) { if (a2 >= b2) return new Ellipse3d(center, normal, a, b); else return new Ellipse3d(center, normal, b, a); } else { var t = 0.5 * Fun.Atan2(2 * ab, a2 - b2); double ct = Fun.Cos(t), st = Fun.Sin(t); V3d v0 = a * ct + b * st, v1 = b * ct - a * st; if (v0.LengthSquared >= v1.LengthSquared) return new Ellipse3d(center, normal, v0, v1); else return new Ellipse3d(center, normal, v1, v0); } } /// /// Construct ellipse from two conjugate diameters, and set /// Axis0 to the major axis and Axis1 to the minor axis. /// The algorithm was constructed from first principles. /// Also computes the squared lengths of the major and minor /// half axis. /// public static Ellipse3d FromConjugateDiameters(V3d center, V3d normal, V3d a, V3d b, out double major2, out double minor2) { var ab = Vec.Dot(a, b); double a2 = a.LengthSquared, b2 = b.LengthSquared; if (ab.IsTiny()) { if (a2 >= b2) { major2 = a2; minor2 = b2; return new Ellipse3d(center, normal, a, b); } else { major2 = b2; minor2 = a2; return new Ellipse3d(center, normal, b, a); } } else { var t = 0.5 * Fun.Atan2(2 * ab, a2 - b2); double ct = Fun.Cos(t), st = Fun.Sin(t); V3d v0 = a * ct + b * st, v1 = b * ct - a * st; a2 = v0.LengthSquared; b2 = v1.LengthSquared; if (a2 >= b2) { major2 = a2; minor2 = b2; return new Ellipse3d(center, normal, v0, v1); } else { major2 = b2; minor2 = a2; return new Ellipse3d(center, normal, v1, v0); } } } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Ellipse3d(Ellipse3f o) => new Ellipse3d(o); #endregion #region Constants public static Ellipse3d Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Ellipse3d(V3d.Zero, V3d.Zero, V3d.Zero, V3d.Zero); } #endregion #region Operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d GetVector(double alpha) => Axis0 * Fun.Cos(alpha) + Axis1 * Fun.Sin(alpha); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d GetPoint(double alpha) => Center + Axis0 * Fun.Cos(alpha) + Axis1 * Fun.Sin(alpha); /// /// Perform the supplied action for each of count vectors from the center /// of the ellipse to the circumference. /// public readonly void ForEachVector(int count, Action index_vector_act) { double d = Constant.PiTimesTwo / count; double a = Fun.Sin(d * 0.5).Square() * 2, b = Fun.Sin(d); // init trig. recurrence double ct = 1, st = 0; index_vector_act(0, Axis0); for (int i = 1; i < count; i++) { double dct = a * ct + b * st, dst = a * st - b * ct; ; // trig. recurrence ct -= dct; st -= dst; // cos (t + d), sin (t + d) index_vector_act(i, Axis0 * ct + Axis1 * st); } } /// /// Get count points on the circumference of the ellipse. /// public readonly V3d[] GetPoints(int count) { var array = new V3d[count]; var c = Center; ForEachVector(count, (i, v) => array[i] = c + v); return array; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Ellipse3d a, Ellipse3d b) => (a.Center == b.Center) && (a.Normal == b.Normal) && (a.Axis0 == b.Axis0) && (a.Axis1 == b.Axis1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Ellipse3d a, Ellipse3d b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Center, Normal, Axis0, Axis1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Ellipse3d other) => Center.Equals(other.Center) && Normal.Equals(other.Normal) && Axis0.Equals(other.Axis0) && Axis1.Equals(other.Axis1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Ellipse3d o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}, {3}]", Center, Normal, Axis0, Axis1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Ellipse3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Ellipse3d( V3d.Parse(x[0]), V3d.Parse(x[1]), V3d.Parse(x[2]), V3d.Parse(x[3]) ); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Ellipse3d a, Ellipse3d b, double tolerance) => ApproximateEquals(a.Center, b.Center, tolerance) && ApproximateEquals(a.Normal, b.Normal, tolerance) && ApproximateEquals(a.Axis0, b.Axis0, tolerance) && ApproximateEquals(a.Axis1, b.Axis1, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Ellipse3d a, Ellipse3d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Ellipse/Ellipse_template.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# { // ELLIPSES //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var half = isDouble ? "0.5" : "0.5f"; //# var constant = isDouble ? "Constant" : "ConstantF"; //# for (int d = 2; d < 4; d++) { //# var vt = "V" + d + tc; //# var vt2 = "V" + d + tc2; //# var et = "Ellipse" + d + tc; //# var et2 = "Ellipse" + d + tc2; #region __et__ /// /// A __d__d ellipse is defined by its center/*# if (d == 3) { */, its plane normal,/*# } */ /// and two half-axes. /// Note that in principle any two conjugate half-diameters /// can be used as axes, however some algorithms require that /// the major and minor half axes are known. By convention /// in this case, axis0 is the major half axis. /// [StructLayout(LayoutKind.Sequential)] public partial struct __et__ { public __vt__ Center; //# if (d == 3) { public __vt__ Normal; //# } public __vt__ Axis0; public __vt__ Axis1; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public __et__(__vt__ center, /*# if (d == 3) { */__vt__ normal, /*# } */__vt__ axis0, __vt__ axis1) { Center = center; //# if (d == 3) { Normal = normal; //# } Axis0 = axis0; Axis1 = axis1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __et__(__et__ o) { Center = o.Center; //# if (d == 3) { Normal = o.Normal; //# } Axis0 = o.Axis0; Axis1 = o.Axis1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __et__(__et2__ o) { Center = (__vt__)o.Center; //# if (d == 3) { Normal = (__vt__)o.Normal; //# } Axis0 = (__vt__)o.Axis0; Axis1 = (__vt__)o.Axis1; } /// /// Construct ellipse from two conjugate diameters, and set /// Axis0 to the major axis and Axis1 to the minor axis. /// The algorithm was constructed from first principles. /// public static __et__ FromConjugateDiameters(__vt__ center, /*# if (d == 3) { */__vt__ normal, /*# } */__vt__ a, __vt__ b) { var ab = Vec.Dot(a, b); __ftype__ a2 = a.LengthSquared, b2 = b.LengthSquared; if (ab.IsTiny()) { if (a2 >= b2) return new __et__(center, /*# if (d == 3) { */normal, /*# } */a, b); else return new __et__(center, /*# if (d == 3) { */normal, /*# } */b, a); } else { var t = __half__ * Fun.Atan2(2 * ab, a2 - b2); __ftype__ ct = Fun.Cos(t), st = Fun.Sin(t); __vt__ v0 = a * ct + b * st, v1 = b * ct - a * st; if (v0.LengthSquared >= v1.LengthSquared) return new __et__(center, /*# if (d == 3) { */normal, /*# } */v0, v1); else return new __et__(center, /*# if (d == 3) { */normal, /*# } */v1, v0); } } /// /// Construct ellipse from two conjugate diameters, and set /// Axis0 to the major axis and Axis1 to the minor axis. /// The algorithm was constructed from first principles. /// Also computes the squared lengths of the major and minor /// half axis. /// public static __et__ FromConjugateDiameters(__vt__ center, /*# if (d == 3) { */__vt__ normal, /*# } */__vt__ a, __vt__ b, out __ftype__ major2, out __ftype__ minor2) { var ab = Vec.Dot(a, b); __ftype__ a2 = a.LengthSquared, b2 = b.LengthSquared; if (ab.IsTiny()) { if (a2 >= b2) { major2 = a2; minor2 = b2; return new __et__(center, /*# if (d == 3) { */normal, /*# } */a, b); } else { major2 = b2; minor2 = a2; return new __et__(center, /*# if (d == 3) { */normal, /*# } */b, a); } } else { var t = __half__ * Fun.Atan2(2 * ab, a2 - b2); __ftype__ ct = Fun.Cos(t), st = Fun.Sin(t); __vt__ v0 = a * ct + b * st, v1 = b * ct - a * st; a2 = v0.LengthSquared; b2 = v1.LengthSquared; if (a2 >= b2) { major2 = a2; minor2 = b2; return new __et__(center, /*# if (d == 3) { */normal, /*# } */v0, v1); } else { major2 = b2; minor2 = a2; return new __et__(center, /*# if (d == 3) { */normal, /*# } */v1, v0); } } } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __et__(__et2__ o) => new __et__(o); #endregion #region Constants public static __et__ Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __et__(__vt__.Zero, /*# if (d == 3) { */__vt__.Zero, /*# } */__vt__.Zero, __vt__.Zero); } #endregion #region Operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __vt__ GetVector(__ftype__ alpha) => Axis0 * Fun.Cos(alpha) + Axis1 * Fun.Sin(alpha); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __vt__ GetPoint(__ftype__ alpha) => Center + Axis0 * Fun.Cos(alpha) + Axis1 * Fun.Sin(alpha); /// /// Perform the supplied action for each of count vectors from the center /// of the ellipse to the circumference. /// public readonly void ForEachVector(int count, Action index_vector_act) { __ftype__ d = __constant__.PiTimesTwo / count; __ftype__ a = Fun.Sin(d * __half__).Square() * 2, b = Fun.Sin(d); // init trig. recurrence __ftype__ ct = 1, st = 0; index_vector_act(0, Axis0); for (int i = 1; i < count; i++) { __ftype__ dct = a * ct + b * st, dst = a * st - b * ct; ; // trig. recurrence ct -= dct; st -= dst; // cos (t + d), sin (t + d) index_vector_act(i, Axis0 * ct + Axis1 * st); } } /// /// Get count points on the circumference of the ellipse. /// public readonly __vt__[] GetPoints(int count) { var array = new __vt__[count]; var c = Center; ForEachVector(count, (i, v) => array[i] = c + v); return array; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__et__ a, __et__ b) => (a.Center == b.Center) && //# if (d == 3) { (a.Normal == b.Normal) && //# } (a.Axis0 == b.Axis0) && (a.Axis1 == b.Axis1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__et__ a, __et__ b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Center, /*# if (d == 3) { */Normal, /*# }*/Axis0, Axis1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__et__ other) => Center.Equals(other.Center) && //# if (d == 3) { Normal.Equals(other.Normal) && //# } Axis0.Equals(other.Axis0) && Axis1.Equals(other.Axis1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is __et__ o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() { //# if (d == 3) { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}, {3}]", Center, Normal, Axis0, Axis1); //# } else { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", Center, Axis0, Axis1); //# } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __et__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __et__( __vt__.Parse(x[0]), __vt__.Parse(x[1]), __vt__.Parse(x[2])/*# if (d == 3) { */, __vt__.Parse(x[3])/*# }*/ ); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __et__ a, __et__ b, __ftype__ tolerance) => ApproximateEquals(a.Center, b.Center, tolerance) && //# if (d == 3) { ApproximateEquals(a.Normal, b.Normal, tolerance) && //# } ApproximateEquals(a.Axis0, b.Axis0, tolerance) && ApproximateEquals(a.Axis1, b.Axis1, tolerance); /// /// Returns whether the given are equal within /// Constant<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __et__ a, __et__ b) => ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } #endregion //# } // d //# } // ELLIPSES //# } // isDouble } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Geometry1i.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Aardvark.Base { #region Line1i public partial struct Line1i { #region Static Creator public static Line1i CreateSorted(int i0, int i1) { return i0 < i1 ? new Line1i(i0, i1) : new Line1i(i1, i0); } #endregion #region Properties public readonly Line1i Reversed { get { return new Line1i(I1, I0); } } #endregion } #endregion #region Triangle1i public partial struct Triangle1i { #region Static Creator public static Triangle1i CreateSorted(int i0, int i1, int i2) { if (i0 < i1) { if (i1 < i2) return new Triangle1i(i0, i1, i2); else { if (i0 < i2) return new Triangle1i(i0, i2, i1); else return new Triangle1i(i2, i0, i1); } } else { if (i2 < i1) return new Triangle1i(i2, i1, i0); else { if (i0 < i2) return new Triangle1i(i1, i0, i2); else return new Triangle1i(i1, i2, i0); } } } #endregion #region Properties public readonly Triangle1i Reversed { get { return new Triangle1i(I2, I1, I0); } } #endregion } #endregion #region Quad1i public partial struct Quad1i { #region Properties public readonly Quad1i Reversed { get { return new Quad1i(I3, I2, I1, I0); } } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Geometry1i_auto.cs ================================================ using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using System.Text; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Line1i /// /// A structure that holds the indices of the endpoints of a line. /// public partial struct Line1i : IEquatable { public int I0; public int I1; #region Constructor public Line1i(int i0, int i1) { I0 = i0; I1 = i1; } #endregion #region Properties public readonly IEnumerable Indices { get { yield return I0; yield return I1; } } #endregion #region Indexer public int this[int index] { readonly get { switch (index) { case 0: return I0; case 1: return I1; default: throw new IndexOutOfRangeException(); } } set { switch (index) { case 0: I0 = value; return; case 1: I1 = value; return; default: throw new IndexOutOfRangeException(); } } } #endregion #region Constants public static Line1i Invalid => new Line1i { I0 = -1, I1 = -1 }; #endregion #region Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Line1i a, Line1i b) { return a.I0 == b.I0 && a.I1 == b.I1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Line1i a, Line1i b) { return a.I0 != b.I0 || a.I1 != b.I1; } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(I0, I1); } public override readonly bool Equals(object other) => (other is Line1i o) ? Equals(o) : false; #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Line1i other) { return this == other; } #endregion } #endregion #region Triangle1i /// /// A structure that holds the indices of the vertices of a triangle. /// public partial struct Triangle1i : IEquatable { public int I0; public int I1; public int I2; #region Constructor public Triangle1i(int i0, int i1, int i2) { I0 = i0; I1 = i1; I2 = i2; } #endregion #region Properties public readonly IEnumerable Indices { get { yield return I0; yield return I1; yield return I2; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line01 { get { return new Line1i(I0, I1); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line02 { get { return new Line1i(I0, I2); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line10 { get { return new Line1i(I1, I0); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line12 { get { return new Line1i(I1, I2); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line20 { get { return new Line1i(I2, I0); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line21 { get { return new Line1i(I2, I1); } } #endregion #region Indexer public int this[int index] { readonly get { switch (index) { case 0: return I0; case 1: return I1; case 2: return I2; default: throw new IndexOutOfRangeException(); } } set { switch (index) { case 0: I0 = value; return; case 1: I1 = value; return; case 2: I2 = value; return; default: throw new IndexOutOfRangeException(); } } } #endregion #region Constants public static Triangle1i Invalid => new Triangle1i { I0 = -1, I1 = -1, I2 = -1 }; #endregion #region Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Triangle1i a, Triangle1i b) { return a.I0 == b.I0 && a.I1 == b.I1 && a.I2 == b.I2; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Triangle1i a, Triangle1i b) { return a.I0 != b.I0 || a.I1 != b.I1 || a.I2 != b.I2; } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(I0, I1, I2); } public override readonly bool Equals(object other) => (other is Triangle1i o) ? Equals(o) : false; #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Triangle1i other) { return this == other; } #endregion } #endregion #region Quad1i /// /// A structure that holds the indices of the vertices of a quad. /// public partial struct Quad1i : IEquatable { public int I0; public int I1; public int I2; public int I3; #region Constructor public Quad1i(int i0, int i1, int i2, int i3) { I0 = i0; I1 = i1; I2 = i2; I3 = i3; } #endregion #region Properties public readonly IEnumerable Indices { get { yield return I0; yield return I1; yield return I2; yield return I3; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line01 { get { return new Line1i(I0, I1); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line02 { get { return new Line1i(I0, I2); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line03 { get { return new Line1i(I0, I3); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line10 { get { return new Line1i(I1, I0); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line12 { get { return new Line1i(I1, I2); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line13 { get { return new Line1i(I1, I3); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line20 { get { return new Line1i(I2, I0); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line21 { get { return new Line1i(I2, I1); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line23 { get { return new Line1i(I2, I3); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line30 { get { return new Line1i(I3, I0); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line31 { get { return new Line1i(I3, I1); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line32 { get { return new Line1i(I3, I2); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle012 { get { return new Triangle1i(I0, I1, I2); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle013 { get { return new Triangle1i(I0, I1, I3); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle021 { get { return new Triangle1i(I0, I2, I1); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle023 { get { return new Triangle1i(I0, I2, I3); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle031 { get { return new Triangle1i(I0, I3, I1); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle032 { get { return new Triangle1i(I0, I3, I2); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle102 { get { return new Triangle1i(I1, I0, I2); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle103 { get { return new Triangle1i(I1, I0, I3); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle120 { get { return new Triangle1i(I1, I2, I0); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle123 { get { return new Triangle1i(I1, I2, I3); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle130 { get { return new Triangle1i(I1, I3, I0); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle132 { get { return new Triangle1i(I1, I3, I2); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle201 { get { return new Triangle1i(I2, I0, I1); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle203 { get { return new Triangle1i(I2, I0, I3); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle210 { get { return new Triangle1i(I2, I1, I0); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle213 { get { return new Triangle1i(I2, I1, I3); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle230 { get { return new Triangle1i(I2, I3, I0); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle231 { get { return new Triangle1i(I2, I3, I1); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle301 { get { return new Triangle1i(I3, I0, I1); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle302 { get { return new Triangle1i(I3, I0, I2); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle310 { get { return new Triangle1i(I3, I1, I0); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle312 { get { return new Triangle1i(I3, I1, I2); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle320 { get { return new Triangle1i(I3, I2, I0); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle321 { get { return new Triangle1i(I3, I2, I1); } } #endregion #region Indexer public int this[int index] { readonly get { switch (index) { case 0: return I0; case 1: return I1; case 2: return I2; case 3: return I3; default: throw new IndexOutOfRangeException(); } } set { switch (index) { case 0: I0 = value; return; case 1: I1 = value; return; case 2: I2 = value; return; case 3: I3 = value; return; default: throw new IndexOutOfRangeException(); } } } #endregion #region Constants public static Quad1i Invalid => new Quad1i { I0 = -1, I1 = -1, I2 = -1, I3 = -1 }; #endregion #region Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Quad1i a, Quad1i b) { return a.I0 == b.I0 && a.I1 == b.I1 && a.I2 == b.I2 && a.I3 == b.I3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Quad1i a, Quad1i b) { return a.I0 != b.I0 || a.I1 != b.I1 || a.I2 != b.I2 || a.I3 != b.I3; } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(I0, I1, I2, I3); } public override readonly bool Equals(object other) => (other is Quad1i o) ? Equals(o) : false; #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Quad1i other) { return this == other; } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Geometry1i_template.cs ================================================ using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using System.Text; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# Action comma = () => Out(", "); //# Action andand = () => Out(" && "); //# Action oror = () => Out(" || "); //# var types = new[] { null, null, "Line1i", "Triangle1i", "Quad1i" }; //# var names = new[] { null, null, "line", "triangle", "quad" }; //# var points = new[] { null, null, "endpoint", "vertex", "vertex" }; //# //# for (int d = 2; d <= 4; d++) //# { //# string type = types[d], name = names[d], point = points[d].Plural(d); //# #region __type__ /// /// A structure that holds the indices of the __point__ of a __name__. /// public partial struct __type__ : IEquatable<__type__> { //# d.ForEach(i => { public int I__i__; //# }); #region Constructor public __type__(/*# d.ForEach(i => { */int i__i__/*# }, comma); */) { /*# d.ForEach(i => { */I__i__ = i__i__; /*# }); */ } #endregion #region Properties public readonly IEnumerable Indices { get { //# d.ForEach(i => { yield return I__i__; //# }); } } //# if (d > 2) { //# d.ForEach(i0 => { //# d.ForEach(i1 => { if (i1 != i0) { [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Line1i Line__i0____i1__ { get { return new Line1i(I__i0__, I__i1__); } } //# }}); //# }); //# } //# if (d > 3) { //# d.ForEach(i0 => { //# d.ForEach(i1 => { if (i1 != i0) { //# d.ForEach(i2 => { if (i2 != i1 && i2 != i0) { [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly Triangle1i Triangle__i0____i1____i2__ { get { return new Triangle1i(I__i0__, I__i1__, I__i2__); } } //# }}); //# }}); //# }); //# } #endregion #region Indexer public int this[int index] { readonly get { switch (index) { //# d.ForEach(i => { case __i__: return I__i__; //# }); default: throw new IndexOutOfRangeException(); } } set { switch (index) { //# d.ForEach(i => { case __i__: I__i__ = value; return; //# }); default: throw new IndexOutOfRangeException(); } } } #endregion #region Constants public static __type__ Invalid => new __type__ { /*# d.ForEach(i => { */I__i__ = -1/*# }, comma); */ }; #endregion #region Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ a, __type__ b) { return /*# d.ForEach(i => { */a.I__i__ == b.I__i__/*# }, andand); */; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ a, __type__ b) { return /*# d.ForEach(i => { */a.I__i__ != b.I__i__/*# }, oror); */; } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(/*# d.ForEach(i => { */I__i__/*# }, comma); */); } public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; #endregion #region IEquatable<__type__> Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) { return this == other; } #endregion } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Geometry_auto.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Polygon2f /// /// A polygon internally represented by an array of points. Implemented /// as a structure, the validity of the polygon can be checked via its /// PointCount, which must be bigger than 0 for a polygon to hold any /// points, and bigger than 2 for a polygon to be geometrically valid. /// [StructLayout(LayoutKind.Sequential)] public partial struct Polygon2f : IEquatable, IValidity, IPolygon, IBoundingBox2f { internal int m_pointCount; internal V2f[] m_pointArray; #region Constructors /// /// Creates a polygon from given points. /// public Polygon2f(V2f[] pointArray, int pointCount) { if (pointArray != null) { if (pointCount <= pointArray.Length) { m_pointCount = pointCount; m_pointArray = pointArray; } else throw new ArgumentException( "point count must be smaller or equal array length"); } else { m_pointCount = 0; m_pointArray = null; } } /// /// Creates a polygon from given points. /// public Polygon2f(params V2f[] pointArray) { m_pointCount = pointArray != null ? pointArray.Length : 0; m_pointArray = pointArray; } /// /// Creates a polygon from given points. /// public Polygon2f(V2f[] pointArray, int startIndex, int count) { if (startIndex < 0 || startIndex >= pointArray.Length - 1) throw new ArgumentException(); if (count <= 0 || startIndex + count >= pointArray.Length) throw new ArgumentException(); m_pointCount = count; m_pointArray = new V2f[count]; for (int i = 0; i < count; i++) m_pointArray[i] = pointArray[startIndex + i]; } /// /// Creates a polygon from point count and point creator function. /// public Polygon2f(int pointCount, Func index_pointCreator) : this(new V2f[pointCount].SetByIndex(index_pointCreator)) { } /// /// Creates a polygon from a sequence of points. /// public Polygon2f(IEnumerable points) : this(points.ToArray()) { } /// /// Creates a polygon from the points of a pointArray that /// are selected by an index array. /// public Polygon2f(int[] indexArray, V2f[] pointArray) : this(indexArray.Map(i => pointArray[i])) { } /// /// Creates a polygon from a triangle. /// public Polygon2f(Triangle2f triangle) : this(triangle.GetPointArray()) { } /// /// Creates a polygon from a quad. /// public Polygon2f(Quad2f quad) : this(quad.GetPointArray()) { } /// /// Copy constructor. /// Performs deep copy of original. /// public Polygon2f(Polygon2f original) : this(original.GetPointArray()) { } #endregion #region Constants public static readonly Polygon2f Invalid = new Polygon2f(null, 0); #endregion #region Properties public readonly bool IsValid => m_pointArray != null; public readonly bool IsInvalid => m_pointArray == null; /// /// The number of points in the polygon. If this is 0, the polygon /// is invalid. /// public readonly int PointCount => m_pointCount; /// /// Enumerates points. /// public readonly IEnumerable Points { get { for (int pi = 0; pi < m_pointCount; pi++) yield return m_pointArray[pi]; } } #endregion #region Conversions /// /// Returns a copy of the polygons point array. /// public readonly V2f[] GetPointArray() { var pc = m_pointCount; var pa = new V2f[pc]; for (int pi = 0; pi < pc; pi++) pa[pi] = m_pointArray[pi]; return pa; } /// /// [P0, P1, P2] -> [P0, P1, P2, P0]. /// public readonly V2f[] GetPointArrayWithRepeatedFirstPoint() { var pc = m_pointCount; var pa = new V2f[pc + 1]; for (int pi = 0; pi < pc; pi++) pa[pi] = m_pointArray[pi]; pa[pc] = pa[0]; return pa; } /// /// Returns a transformed copy of the polygons point array. /// public readonly T[] GetPointArray(Func point_copyFun) { var pc = m_pointCount; var pa = new T[pc]; for (int pi = 0; pi < pc; pi++) pa[pi] = point_copyFun(m_pointArray[pi]); return pa; } /// /// Returns a transformed copy of the polygons point array. /// public readonly T[] GetPointArray(Func point_index_copyFun) { var pc = m_pointCount; var pa = new T[pc]; for (int pi = 0; pi < pc; pi++) pa[pi] = point_index_copyFun(m_pointArray[pi], pi); return pa; } #endregion #region Indexing /// /// Gets the index-th point of this polygon. /// public readonly V2f this[int index] { get { return m_pointArray[index]; } set { m_pointArray[index] = value; } } #endregion #region Edges and Lines /// /// Index-th edge as vector (edgeEndPos - edgeBeginPos). /// public readonly V2f Edge(int index) { var p0 = m_pointArray[index++]; var p1 = m_pointArray[index < m_pointCount ? index : 0]; return p1 - p0; } /// /// Edges as vectors (edgeEndPos - edgeBeginPos). /// public readonly IEnumerable Edges { get { var pc = m_pointCount; var p = m_pointArray[0]; var p0 = p; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; yield return p1 - p0; p0 = p1; } yield return p - p0; } } /// /// Index-th edge as line segment (edgeBeginPos, edgeEndPos). /// public readonly Line2f EdgeLine(int index) { var p0 = m_pointArray[index++]; var p1 = m_pointArray[index < m_pointCount ? index : 0]; return new Line2f(p0, p1); } /// /// Edges as line segments (edgeBeginPos, edgeEndPos). /// public readonly IEnumerable EdgeLines { get { var pc = m_pointCount; if (pc < 1) yield break; var p0 = m_pointArray[0]; var p = p0; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; yield return new Line2f(p0, p1); p0 = p1; } yield return new Line2f(p0, p); } } /// /// Edges as vectors (edgeEndPos - edgeBeginPos). /// public readonly V2f[] GetEdgeArray() { var pc = m_pointCount; if (pc < 2) return Array.Empty(); var edgeArray = new V2f[pc]; var p = m_pointArray[0]; var p0 = p; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; edgeArray[pi - 1] = p1 - p0; p0 = p1; } edgeArray[pc - 1] = p - p0; return edgeArray; } /// /// Edges as line segments (edgeBeginPos, edgeEndPos). /// public readonly Line2f[] GetEdgeLineArray() { var pc = PointCount; if (pc < 2) return Array.Empty(); var ela = new Line2f[pc]; var p = m_pointArray[0]; var p0 = p; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; ela[pi - 1] = new Line2f(p0, p1); p0 = p1; } ela[pc - 1] = new Line2f(p0, p); return ela; } #endregion #region Transformations /// /// Returns copy of polygon. Same as Map(p => p). /// public readonly Polygon2f Copy() { return new Polygon2f(m_pointArray.Copy()); } /// /// Returns transformed copy of this polygon. /// public readonly Polygon2f Map(Func point_fun) { var pc = m_pointCount; V2f[] opa = m_pointArray, npa = new V2f[pc]; for (int pi = 0; pi < pc; pi++) npa[pi] = point_fun(opa[pi]); return new Polygon2f(npa, pc); } /// /// Gets copy with reversed order of vertices. /// public readonly Polygon2f Reversed { get { var pc = m_pointCount; V2f[] opa = m_pointArray, npa = new V2f[pc]; for (int pi = 0, pj = pc - 1; pi < pc; pi++, pj--) npa[pi] = opa[pj]; return new Polygon2f(npa, pc); } } /// /// Reverses order of vertices in-place. /// public readonly void Reverse() { var pa = m_pointArray; for (int pi = 0, pj = m_pointCount - 1; pi < pj; pi++, pj--) { var t = pa[pi]; pa[pi] = pa[pj]; pa[pj] = t; } } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Polygon2f a, Polygon2f b) { if (a.m_pointCount != b.m_pointCount) return false; for (int pi = 0; pi < a.m_pointCount; pi++) if (a.m_pointArray[pi] != b.m_pointArray[pi]) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Polygon2f a, Polygon2f b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return m_pointArray.GetCombinedHashCode(m_pointCount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Polygon2f other) { if (m_pointCount != other.m_pointCount) return false; for (int pi = 0; pi < m_pointCount; pi++) if (!m_pointArray[pi].Equals(other.m_pointArray[pi])) return false; return true; } public override readonly bool Equals(object other) => (other is Polygon2f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}]", Points.Select(x => x.ToString()).Join(", ") ); } public static Polygon2f Parse(string s) { var va = s.NestedBracketSplitLevelOne().ToArray(); return new Polygon2f(va.Select(x => V2f.Parse(x))); } #endregion #region IBoundingBox2f Members /// /// Bounding box of polygon. /// public readonly Box2f BoundingBox2f { get { return new Box2f(m_pointArray, 0, m_pointCount); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Polygon2f a, Polygon2f b, float tolerance) { if (a.m_pointCount != b.m_pointCount) return false; for (int pi = 0; pi < a.m_pointCount; pi++) if (!ApproximateEquals(a.m_pointArray[pi], b.m_pointArray[pi], tolerance)) return false; return true; } /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Polygon2f a, Polygon2f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Polygon2fExtensions public static partial class Polygon2fExtensions { #region Geometric Properties /// /// The vertex centroid is the average of the vertex coordinates. /// public static V2f ComputeVertexCentroid(this Polygon2f polygon) { var sum = V2f.Zero; int pc = polygon.PointCount; for (int i = 0; i < pc; i++) sum += polygon[i]; float scale = 1 / (float)pc; return sum * scale; } public static float ComputePerimeter(this Polygon2f polygon) { var pc = polygon.PointCount; var p0 = polygon[pc - 1]; float r = 0; for (int i = 0; i < pc; i++) { var p1 = polygon[i]; r += Vec.Distance(p0, p1); p0 = p1; } return r; } #endregion #region Geometric Transformations /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. public static void Scale(this ref Polygon2f polygon, float scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f Scaled(this Polygon2f polygon, float scale) { var result = new Polygon2f(polygon); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. public static void Scale(this ref Polygon2f polygon, V2f center, float scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = center + (polygon.m_pointArray[pi] - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f Scaled(this Polygon2f polygon, V2f center, float scale) { var result = new Polygon2f(polygon); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutVertexCentroid(this ref Polygon2f polygon, float scale) { var center = polygon.ComputeVertexCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f ScaledAboutVertexCentroid(this Polygon2f polygon, float scale) { var result = new Polygon2f(polygon); result.ScaleAboutVertexCentroid(scale); return result; } /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. public static void Scale(this ref Polygon2f polygon, V2f scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f Scaled(this Polygon2f polygon, V2f scale) { var result = new Polygon2f(polygon); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. public static void Scale(this ref Polygon2f polygon, V2f center, V2f scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = center + (polygon.m_pointArray[pi] - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f Scaled(this Polygon2f polygon, V2f center, V2f scale) { var result = new Polygon2f(polygon); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutVertexCentroid(this ref Polygon2f polygon, V2f scale) { var center = polygon.ComputeVertexCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f ScaledAboutVertexCentroid(this Polygon2f polygon, V2f scale) { var result = new Polygon2f(polygon); result.ScaleAboutVertexCentroid(scale); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon2f polygon, M33f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.TransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f Transformed(this Polygon2f polygon, M33f t) { var result = new Polygon2f(polygon); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon2f polygon, Euclidean2f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.TransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f Transformed(this Polygon2f polygon, Euclidean2f t) { var result = new Polygon2f(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon2f polygon, Euclidean2f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f InvTransformed(this Polygon2f polygon, Euclidean2f t) { var result = new Polygon2f(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon2f polygon, Similarity2f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.TransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f Transformed(this Polygon2f polygon, Similarity2f t) { var result = new Polygon2f(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon2f polygon, Similarity2f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f InvTransformed(this Polygon2f polygon, Similarity2f t) { var result = new Polygon2f(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon2f polygon, Affine2f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.TransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f Transformed(this Polygon2f polygon, Affine2f t) { var result = new Polygon2f(polygon); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon2f polygon, Shift2f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Transform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f Transformed(this Polygon2f polygon, Shift2f t) { var result = new Polygon2f(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon2f polygon, Shift2f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f InvTransformed(this Polygon2f polygon, Shift2f t) { var result = new Polygon2f(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon2f polygon, Rot2f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Transform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f Transformed(this Polygon2f polygon, Rot2f t) { var result = new Polygon2f(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon2f polygon, Rot2f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f InvTransformed(this Polygon2f polygon, Rot2f t) { var result = new Polygon2f(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon2f polygon, Scale2f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Transform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f Transformed(this Polygon2f polygon, Scale2f t) { var result = new Polygon2f(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon2f polygon, Scale2f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f InvTransformed(this Polygon2f polygon, Scale2f t) { var result = new Polygon2f(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon2f polygon, M22f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Transform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f Transformed(this Polygon2f polygon, M22f t) { var result = new Polygon2f(polygon); result.Transform(t); return result; } public static Polygon2f WithoutMultiplePoints(this Polygon2f polygon, float eps = 1e-5f) { eps *= eps; var opc = polygon.PointCount; var pa = new V2f[opc]; var pc = 0; pa[0] = polygon[0]; for (int pi = 1; pi < opc; pi++) if (Vec.DistanceSquared(pa[pc], polygon[pi]) > eps) pa[++pc] = polygon[pi]; if (Vec.DistanceSquared(pa[pc], polygon[0]) > eps) ++pc; return new Polygon2f(pa, pc); } #endregion #region Clipping /// /// Clip the supplied polygon at the supplied line. The method should /// work with all non-selfintersecting polygons. Returns all parts of /// the polygon that are at the positive side of the line. /// public static Polygon2f ConvexClipped( this Polygon2f polygon, Plane2f line, float eps = 1e-5f) { var opc = polygon.PointCount; V2f[] pa = new V2f[opc + 1]; var pc = 0; var pf = polygon[0]; var hf = line.Height(pf); bool hfp = hf > eps, hfn = hf < -eps; if (hf >= -eps) pa[pc++] = pf; var p0 = pf; var h0 = hf; var h0p = hfp; var h0n = hfn; for (int vi = 1; vi < opc; vi++) { var p1 = polygon[vi]; var h1 = line.Height(p1); bool h1p = h1 > eps, h1n = h1 < -eps; if (h0p && h1n || h0n && h1p) pa[pc++] = p0 + (p1 - p0) * (h0 / (h0 - h1)); if (h1 >= -eps) pa[pc++] = p1; p0 = p1; h0 = h1; h0p = h1p; h0n = h1n; } if (h0p && hfn || h0n && hfp) pa[pc++] = p0 + (pf - p0) * (h0 / (h0 - hf)); return new Polygon2f(pa, pc); } /// /// Returns the convex polygon clipped by the set of lines (defined /// as Plane2fs), i.e. all parts of the polygon that are at the positive /// side of the lines. /// public static Polygon2f ConvexClipped( this Polygon2f polygon, Plane2f[] lines, float eps = 1e-5f) { foreach (var c in lines) { polygon = polygon.ConvexClipped(c, eps); if (polygon.PointCount == 0) break; } return polygon; } /// /// Returns the polygon clipped by the hull, i.e. all parts of the /// polygon that are at the positive side of the hull lines. /// public static Polygon2f ConvexClipped( this Polygon2f polygon, Hull2f hull, float eps = 1e-5f) { return polygon.ConvexClipped(hull.PlaneArray, eps); } /// /// TODO summary. /// public static Polygon2f ConvexClipped( this Polygon2f polygon, Box2f box, float eps = 1e-5f) { var lines = new[] { new Plane2f(V2f.XAxis, box.Min), new Plane2f(-V2f.XAxis, box.Max), new Plane2f(V2f.YAxis, box.Min), new Plane2f(-V2f.YAxis, box.Max), }; return polygon.ConvexClipped(lines); } #endregion } #endregion #region IndexPolygon2f [StructLayout(LayoutKind.Sequential)] public readonly partial struct IndexPolygon2f : IValidity, IPolygon { private readonly int m_pointCount; private readonly int m_firstIndex; private readonly int[] m_indexArray; private readonly V2f[] m_pointArray; #region Constructors public IndexPolygon2f(int[] indexArray, int firstIndex, int pointCount, V2f[] pointArray) { m_indexArray = indexArray; m_firstIndex = firstIndex; m_pointCount = pointCount; m_pointArray = pointArray; } public IndexPolygon2f(V2f[] pointArray, int firstIndex, int pointCount) : this(new int[pointCount].SetByIndex(i => firstIndex + i), 0, pointCount, pointArray) { } public IndexPolygon2f(V2f[] pointArray) : this(new int[pointArray.Length].SetByIndex(i => i), 0, pointArray.Length, pointArray) { } #endregion #region Constants public static readonly IndexPolygon2f Invalid = new IndexPolygon2f(null, 0, 0, null); #endregion #region Properties public bool IsValid { get { return m_indexArray != null && m_pointArray != null; } } public bool IsInvalid { get { return m_indexArray == null || m_pointArray == null; } } public int PointCount { get { return m_pointCount; } } public int FirstIndex { get { return m_firstIndex; } } /// /// The index array that contains the point indices of the /// index polygon at the index range [FirstIndex, FirstIndex + PointCount). /// NOTE: This is different from the array returned by GetIndexArray(). /// public int[] IndexArray { get { return m_indexArray; } } /// /// The point array that contains the points referenced by /// the index array. Note: This is different from the array /// returned by GetPointArray(). /// public V2f[] PointArray { get { return m_pointArray; } } public IEnumerable Points { get { for (int i = 0; i < m_pointCount; i++) yield return m_pointArray[m_indexArray[m_firstIndex + i]]; } } public IEnumerable Indices { get { for (int i = 0; i < m_pointCount; i++) yield return m_indexArray[m_firstIndex + i]; } } #endregion #region Indexing public V2f this[int index] { get { return m_pointArray[m_indexArray[m_firstIndex + index]]; } set { m_pointArray[m_indexArray[m_firstIndex + index]] = value; } } #endregion #region Conversions public void ForEachIndex(Action index_act) { var ia = m_indexArray; int fi = m_firstIndex; for (int i = 0; i < m_pointCount; i++) index_act(ia[fi + i]); } /// /// Returns a newly created array containing only the actual indices /// of the index polygon. NOTE: This is different from the /// IndexArray property! /// public int[] GetIndexArray() { return m_indexArray.Copy(m_firstIndex, m_pointCount); } /// /// Returns a newly created array containing only the actual points /// of the index polygon. NOTE: This is different from the /// PointArray property! /// public V2f[] GetPointArray() { var pa = m_pointArray; return m_indexArray.Map(m_firstIndex, m_pointCount, i => pa[i]); } public T[] GetPointArray(T[] pointArray) { return m_indexArray.Map(m_firstIndex, m_pointCount, i => pointArray[i]); } public T[] GetPointArray(List pointList) { return m_indexArray.Map(m_firstIndex, m_pointCount, i => pointList[i]); } #endregion } #endregion #region IndexPolygon2fExtensions public static partial class IndexPolygon2fExtensions { #region Conversions public static Polygon2f ToPolygon2f(this IndexPolygon2f polygon) { return new Polygon2f(polygon.GetPointArray()); } #endregion #region Geometric Properties /// /// The vertex centroid is the average of the vertex coordinates. /// public static V2f ComputeVertexCentroid(this IndexPolygon2f polygon) { var sum = V2f.Zero; int pc = polygon.PointCount; for (int i = 0; i < pc; i++) sum += polygon[i]; float scale = 1 / (float)pc; return sum * scale; } public static float ComputePerimeter(this IndexPolygon2f polygon) { var pc = polygon.PointCount; var p0 = polygon[pc - 1]; float r = 0; for (int i = 0; i < pc; i++) { var p1 = polygon[i]; r += Vec.Distance(p0, p1); p0 = p1; } return r; } #endregion } #endregion #region Line2f [StructLayout(LayoutKind.Sequential)] public partial struct Line2f : IEquatable, IValidity, IPolygon, IBoundingBox2f { public V2f P0, P1; #region Constructors /// /// Creates line from 2 points. /// public Line2f(V2f p0, V2f p1) { P0 = p0; P1 = p1; } /// /// Creates line from first 2 points in the sequence. /// public Line2f(IEnumerable points) { var pa = points.TakeToArray(2); P0 = pa[0]; P1 = pa[1]; } #endregion #region Properties public readonly bool IsValid { get { return true; } } public readonly bool IsInvalid { get { return false; } } public readonly int PointCount { get { return 2; } } public readonly IEnumerable Points { get { yield return P0; yield return P1; } } public readonly Line2f Reversed { get { return new Line2f(P1, P0); } } #endregion #region Indexer public V2f this[int index] { readonly get { switch (index) { case 0: return P0; case 1: return P1; default: throw new IndexOutOfRangeException(); } } set { switch (index) { case 0: P0 = value; return; case 1: P1 = value; return; default: throw new IndexOutOfRangeException(); } } } #endregion #region Transformations public readonly Line2f Copy(Func point_copyFun) { return new Line2f(point_copyFun(P0), point_copyFun(P1)); } public readonly Line3d ToLine3d(Func point_copyFun) { return new Line3d(point_copyFun(P0), point_copyFun(P1)); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Line2f a, Line2f b) => (a.P0 == b.P0) && (a.P1 == b.P1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Line2f a, Line2f b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(P0, P1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Line2f other) => P0.Equals(other.P0) && P1.Equals(other.P1); public override readonly bool Equals(object other) => (other is Line2f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", P0, P1); } public static Line2f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Line2f(V2f.Parse(x[0]), V2f.Parse(x[1])); } #endregion #region IBoundingBox2f Members public readonly Box2f BoundingBox2f { get { return new Box2f(P0, P1).Repair(); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Line2f a, Line2f b, float tolerance) => ApproximateEquals(a.P0, b.P0, tolerance) && ApproximateEquals(a.P1, b.P1, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Line2f a, Line2f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Line2fExtensions public static partial class Line2fExtensions { #region Geometric Transformations /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Line2f polygon, float scale) { polygon.P0 *= scale; polygon.P1 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f Scaled(this Line2f polygon, float scale) { var result = new Line2f(polygon.P0, polygon.P1); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Line2f polygon, V2f center, float scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f Scaled(this Line2f polygon, V2f center, float scale) { var result = new Line2f(polygon.P0, polygon.P1); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Line2f polygon, float scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f ScaledAboutCentroid(this Line2f polygon, float scale) { var result = new Line2f(polygon.P0, polygon.P1); result.ScaleAboutCentroid(scale); return result; } /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Line2f polygon, V2f scale) { polygon.P0 *= scale; polygon.P1 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f Scaled(this Line2f polygon, V2f scale) { var result = new Line2f(polygon.P0, polygon.P1); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Line2f polygon, V2f center, V2f scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f Scaled(this Line2f polygon, V2f center, V2f scale) { var result = new Line2f(polygon.P0, polygon.P1); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Line2f polygon, V2f scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f ScaledAboutCentroid(this Line2f polygon, V2f scale) { var result = new Line2f(polygon.P0, polygon.P1); result.ScaleAboutCentroid(scale); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line2f polygon, M33f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f Transformed(this Line2f polygon, M33f t) { var result = new Line2f(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line2f polygon, Euclidean2f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f Transformed(this Line2f polygon, Euclidean2f t) { var result = new Line2f(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line2f polygon, Euclidean2f t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f InvTransformed(this Line2f polygon, Euclidean2f t) { var result = new Line2f(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line2f polygon, Similarity2f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f Transformed(this Line2f polygon, Similarity2f t) { var result = new Line2f(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line2f polygon, Similarity2f t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f InvTransformed(this Line2f polygon, Similarity2f t) { var result = new Line2f(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line2f polygon, Affine2f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f Transformed(this Line2f polygon, Affine2f t) { var result = new Line2f(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line2f polygon, Shift2f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f Transformed(this Line2f polygon, Shift2f t) { var result = new Line2f(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line2f polygon, Shift2f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f InvTransformed(this Line2f polygon, Shift2f t) { var result = new Line2f(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line2f polygon, Rot2f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f Transformed(this Line2f polygon, Rot2f t) { var result = new Line2f(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line2f polygon, Rot2f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f InvTransformed(this Line2f polygon, Rot2f t) { var result = new Line2f(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line2f polygon, Scale2f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f Transformed(this Line2f polygon, Scale2f t) { var result = new Line2f(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line2f polygon, Scale2f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f InvTransformed(this Line2f polygon, Scale2f t) { var result = new Line2f(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line2f polygon, M22f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2f Transformed(this Line2f polygon, M22f t) { var result = new Line2f(polygon.P0, polygon.P1); result.Transform(t); return result; } #endregion public static V2f[] GetPointArray(this Line2f line) { var pa = new V2f[2]; pa[0] = line.P0; pa[1] = line.P1; return pa; } public static V2f ComputeCentroid(this Line2f line) { return 0.5f * (line.P0 + line.P1); } } #endregion #region Triangle2f [StructLayout(LayoutKind.Sequential)] public partial struct Triangle2f : IEquatable, IValidity, IPolygon, IBoundingBox2f { public V2f P0, P1, P2; #region Constructors /// /// Creates triangle from 3 points. /// public Triangle2f(V2f p0, V2f p1, V2f p2) { P0 = p0; P1 = p1; P2 = p2; } /// /// Creates triangle from first 3 points in the sequence. /// public Triangle2f(IEnumerable points) { var pa = points.TakeToArray(3); P0 = pa[0]; P1 = pa[1]; P2 = pa[2]; } #endregion #region Properties public readonly bool IsValid { get { return true; } } public readonly bool IsInvalid { get { return false; } } /// /// Edge P1 - P0 /// public readonly V2f Edge01 { get { return P1 - P0; } } /// /// Edge P2 - P0 /// public readonly V2f Edge02 { get { return P2 - P0; } } /// /// Edge P2 - P1 /// public readonly V2f Edge12 { get { return P2 - P1; } } /// /// Edge P0 - P1 /// public readonly V2f Edge10 { get { return P0 - P1; } } /// /// Edge P0 - P2 /// public readonly V2f Edge20 { get { return P0 - P2; } } /// /// Edge P1 - P2 /// public readonly V2f Edge21 { get { return P1 - P2; } } public readonly IEnumerable Edges { get { yield return P1 - P0; yield return P2 - P1; yield return P0 - P2; } } public readonly V2f[] EdgeArray { get { var a = new V2f[3]; a[0] = P1 - P0; a[1] = P2 - P1; a[2] = P0 - P2; return a; } } public readonly IEnumerable EdgeLines { get { yield return new Line2f(P0, P1); yield return new Line2f(P1, P2); yield return new Line2f(P2, P0); } } public readonly Line2f[] EdgeLineArray { get { var a = new Line2f[3]; a[0] = new Line2f(P0, P1); a[1] = new Line2f(P1, P2); a[2] = new Line2f(P2, P0); return a; } } public readonly Line2f GetEdgeLine(int index) { switch (index) { case 0: return new Line2f(P0, P1); case 1: return new Line2f(P1, P2); case 2: return new Line2f(P2, P0); } throw new InvalidOperationException(); } public readonly V2f GetEdge(int index) { switch (index) { case 0: return P1 - P0; case 1: return P2 - P1; case 2: return P0 - P2; } throw new InvalidOperationException(); } public readonly Line2f Line01 { get { return new Line2f(P0, P1); } } public readonly Line2f Line02 { get { return new Line2f(P0, P2); } } public readonly Line2f Line12 { get { return new Line2f(P1, P2); } } public readonly Line2f Line10 { get { return new Line2f(P1, P0); } } public readonly Line2f Line20 { get { return new Line2f(P2, P0); } } public readonly Line2f Line21 { get { return new Line2f(P2, P1); } } public readonly int PointCount { get { return 3; } } public readonly IEnumerable Points { get { yield return P0; yield return P1; yield return P2; } } public readonly Triangle2f Reversed { get { return new Triangle2f(P2, P1, P0); } } #endregion #region Indexer public V2f this[int index] { readonly get { switch (index) { case 0: return P0; case 1: return P1; case 2: return P2; default: throw new IndexOutOfRangeException(); } } set { switch (index) { case 0: P0 = value; return; case 1: P1 = value; return; case 2: P2 = value; return; default: throw new IndexOutOfRangeException(); } } } #endregion #region Transformations public readonly Triangle2f Copy(Func point_copyFun) { return new Triangle2f(point_copyFun(P0), point_copyFun(P1), point_copyFun(P2)); } public readonly Triangle3d ToTriangle3d(Func point_copyFun) { return new Triangle3d(point_copyFun(P0), point_copyFun(P1), point_copyFun(P2)); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Triangle2f a, Triangle2f b) => (a.P0 == b.P0) && (a.P1 == b.P1) && (a.P2 == b.P2); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Triangle2f a, Triangle2f b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(P0, P1, P2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Triangle2f other) => P0.Equals(other.P0) && P1.Equals(other.P1) && P2.Equals(other.P2); public override readonly bool Equals(object other) => (other is Triangle2f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", P0, P1, P2); } public static Triangle2f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Triangle2f(V2f.Parse(x[0]), V2f.Parse(x[1]), V2f.Parse(x[2])); } #endregion #region IBoundingBox2f Members public readonly Box2f BoundingBox2f { get { return new Box2f(P0, P1, P2); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Triangle2f a, Triangle2f b, float tolerance) => ApproximateEquals(a.P0, b.P0, tolerance) && ApproximateEquals(a.P1, b.P1, tolerance) && ApproximateEquals(a.P2, b.P2, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Triangle2f a, Triangle2f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Triangle2fExtensions public static partial class Triangle2fExtensions { #region Geometric Transformations /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Triangle2f polygon, float scale) { polygon.P0 *= scale; polygon.P1 *= scale; polygon.P2 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f Scaled(this Triangle2f polygon, float scale) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Triangle2f polygon, V2f center, float scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; polygon.P2 = center + (polygon.P2 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f Scaled(this Triangle2f polygon, V2f center, float scale) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Triangle2f polygon, float scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f ScaledAboutCentroid(this Triangle2f polygon, float scale) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.ScaleAboutCentroid(scale); return result; } /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Triangle2f polygon, V2f scale) { polygon.P0 *= scale; polygon.P1 *= scale; polygon.P2 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f Scaled(this Triangle2f polygon, V2f scale) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Triangle2f polygon, V2f center, V2f scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; polygon.P2 = center + (polygon.P2 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f Scaled(this Triangle2f polygon, V2f center, V2f scale) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Triangle2f polygon, V2f scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f ScaledAboutCentroid(this Triangle2f polygon, V2f scale) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.ScaleAboutCentroid(scale); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle2f polygon, M33f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f Transformed(this Triangle2f polygon, M33f t) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle2f polygon, Euclidean2f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f Transformed(this Triangle2f polygon, Euclidean2f t) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle2f polygon, Euclidean2f t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); polygon.P2 = t.InvTransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f InvTransformed(this Triangle2f polygon, Euclidean2f t) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle2f polygon, Similarity2f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f Transformed(this Triangle2f polygon, Similarity2f t) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle2f polygon, Similarity2f t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); polygon.P2 = t.InvTransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f InvTransformed(this Triangle2f polygon, Similarity2f t) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle2f polygon, Affine2f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f Transformed(this Triangle2f polygon, Affine2f t) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle2f polygon, Shift2f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f Transformed(this Triangle2f polygon, Shift2f t) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle2f polygon, Shift2f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f InvTransformed(this Triangle2f polygon, Shift2f t) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle2f polygon, Rot2f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f Transformed(this Triangle2f polygon, Rot2f t) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle2f polygon, Rot2f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f InvTransformed(this Triangle2f polygon, Rot2f t) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle2f polygon, Scale2f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f Transformed(this Triangle2f polygon, Scale2f t) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle2f polygon, Scale2f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f InvTransformed(this Triangle2f polygon, Scale2f t) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle2f polygon, M22f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2f Transformed(this Triangle2f polygon, M22f t) { var result = new Triangle2f(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } #endregion public static V2f[] GetPointArray(this Triangle2f triangle) { var pa = new V2f[3]; pa[0] = triangle.P0; pa[1] = triangle.P1; pa[2] = triangle.P2; return pa; } public static V2f ComputeCentroid(this Triangle2f triangle) { return ConstantF.OneThird * (triangle.P0 + triangle.P1 + triangle.P2); } } #endregion #region Quad2f [StructLayout(LayoutKind.Sequential)] public partial struct Quad2f : IEquatable, IValidity, IPolygon, IBoundingBox2f { public V2f P0, P1, P2, P3; #region Constructors /// /// Creates quad from 4 points. /// public Quad2f(V2f p0, V2f p1, V2f p2, V2f p3) { P0 = p0; P1 = p1; P2 = p2; P3 = p3; } /// /// Creates quad from first 4 points in the sequence. /// public Quad2f(IEnumerable points) { var pa = points.TakeToArray(4); P0 = pa[0]; P1 = pa[1]; P2 = pa[2]; P3 = pa[3]; } /// /// Creates quad from point and two vectors representing edges. /// public Quad2f(V2f p0, V2f edge01, V2f edge03) { P0 = p0; P1 = p0 + edge01; P2 = P1 + edge03; P3 = p0 + edge03; } #endregion #region Properties public readonly bool IsValid { get { return true; } } public readonly bool IsInvalid { get { return false; } } /// /// Edge P1 - P0 /// public readonly V2f Edge01 { get { return P1 - P0; } } /// /// Edge P3 - P0 /// public readonly V2f Edge03 { get { return P3 - P0; } } /// /// Edge P2 - P1 /// public readonly V2f Edge12 { get { return P2 - P1; } } /// /// Edge P0 - P1 /// public readonly V2f Edge10 { get { return P0 - P1; } } /// /// Edge P3 - P2 /// public readonly V2f Edge23 { get { return P3 - P2; } } /// /// Edge P1 - P2 /// public readonly V2f Edge21 { get { return P1 - P2; } } /// /// Edge P0 - P3 /// public readonly V2f Edge30 { get { return P0 - P3; } } /// /// Edge P2 - P3 /// public readonly V2f Edge32 { get { return P2 - P3; } } public readonly IEnumerable Edges { get { yield return P1 - P0; yield return P2 - P1; yield return P3 - P2; yield return P0 - P3; } } public readonly V2f[] EdgeArray { get { var a = new V2f[4]; a[0] = P1 - P0; a[1] = P2 - P1; a[2] = P3 - P2; a[3] = P0 - P3; return a; } } public readonly IEnumerable EdgeLines { get { yield return new Line2f(P0, P1); yield return new Line2f(P1, P2); yield return new Line2f(P2, P3); yield return new Line2f(P3, P0); } } public readonly Line2f[] EdgeLineArray { get { var a = new Line2f[4]; a[0] = new Line2f(P0, P1); a[1] = new Line2f(P1, P2); a[2] = new Line2f(P2, P3); a[3] = new Line2f(P3, P0); return a; } } public readonly Line2f GetEdgeLine(int index) { switch (index) { case 0: return new Line2f(P0, P1); case 1: return new Line2f(P1, P2); case 2: return new Line2f(P2, P3); case 3: return new Line2f(P3, P0); } throw new InvalidOperationException(); } public readonly V2f GetEdge(int index) { switch (index) { case 0: return P1 - P0; case 1: return P2 - P1; case 2: return P3 - P2; case 3: return P0 - P3; } throw new InvalidOperationException(); } public readonly Line2f Line01 { get { return new Line2f(P0, P1); } } public readonly Line2f Line03 { get { return new Line2f(P0, P3); } } public readonly Line2f Line12 { get { return new Line2f(P1, P2); } } public readonly Line2f Line10 { get { return new Line2f(P1, P0); } } public readonly Line2f Line23 { get { return new Line2f(P2, P3); } } public readonly Line2f Line21 { get { return new Line2f(P2, P1); } } public readonly Line2f Line30 { get { return new Line2f(P3, P0); } } public readonly Line2f Line32 { get { return new Line2f(P3, P2); } } public readonly int PointCount { get { return 4; } } public readonly IEnumerable Points { get { yield return P0; yield return P1; yield return P2; yield return P3; } } public readonly Quad2f Reversed { get { return new Quad2f(P3, P2, P1, P0); } } #endregion #region Indexer public V2f this[int index] { readonly get { switch (index) { case 0: return P0; case 1: return P1; case 2: return P2; case 3: return P3; default: throw new IndexOutOfRangeException(); } } set { switch (index) { case 0: P0 = value; return; case 1: P1 = value; return; case 2: P2 = value; return; case 3: P3 = value; return; default: throw new IndexOutOfRangeException(); } } } #endregion #region Transformations public readonly Quad2f Copy(Func point_copyFun) { return new Quad2f(point_copyFun(P0), point_copyFun(P1), point_copyFun(P2), point_copyFun(P3)); } public readonly Quad3d ToQuad3d(Func point_copyFun) { return new Quad3d(point_copyFun(P0), point_copyFun(P1), point_copyFun(P2), point_copyFun(P3)); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Quad2f a, Quad2f b) => (a.P0 == b.P0) && (a.P1 == b.P1) && (a.P2 == b.P2) && (a.P3 == b.P3); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Quad2f a, Quad2f b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(P0, P1, P2, P3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Quad2f other) => P0.Equals(other.P0) && P1.Equals(other.P1) && P2.Equals(other.P2) && P3.Equals(other.P3); public override readonly bool Equals(object other) => (other is Quad2f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}, {3}]", P0, P1, P2, P3); } public static Quad2f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Quad2f(V2f.Parse(x[0]), V2f.Parse(x[1]), V2f.Parse(x[2]), V2f.Parse(x[3])); } #endregion #region IBoundingBox2f Members public readonly Box2f BoundingBox2f { get { return new Box2f(P0, P1, P2, P3); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Quad2f a, Quad2f b, float tolerance) => ApproximateEquals(a.P0, b.P0, tolerance) && ApproximateEquals(a.P1, b.P1, tolerance) && ApproximateEquals(a.P2, b.P2, tolerance) && ApproximateEquals(a.P3, b.P3, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Quad2f a, Quad2f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Quad2fExtensions public static partial class Quad2fExtensions { #region Geometric Transformations /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Quad2f polygon, float scale) { polygon.P0 *= scale; polygon.P1 *= scale; polygon.P2 *= scale; polygon.P3 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f Scaled(this Quad2f polygon, float scale) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Quad2f polygon, V2f center, float scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; polygon.P2 = center + (polygon.P2 - center) * scale; polygon.P3 = center + (polygon.P3 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f Scaled(this Quad2f polygon, V2f center, float scale) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Quad2f polygon, float scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f ScaledAboutCentroid(this Quad2f polygon, float scale) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.ScaleAboutCentroid(scale); return result; } /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Quad2f polygon, V2f scale) { polygon.P0 *= scale; polygon.P1 *= scale; polygon.P2 *= scale; polygon.P3 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f Scaled(this Quad2f polygon, V2f scale) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Quad2f polygon, V2f center, V2f scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; polygon.P2 = center + (polygon.P2 - center) * scale; polygon.P3 = center + (polygon.P3 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f Scaled(this Quad2f polygon, V2f center, V2f scale) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Quad2f polygon, V2f scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f ScaledAboutCentroid(this Quad2f polygon, V2f scale) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.ScaleAboutCentroid(scale); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad2f polygon, M33f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); polygon.P3 = t.TransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f Transformed(this Quad2f polygon, M33f t) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad2f polygon, Euclidean2f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); polygon.P3 = t.TransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f Transformed(this Quad2f polygon, Euclidean2f t) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad2f polygon, Euclidean2f t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); polygon.P2 = t.InvTransformPos(polygon.P2); polygon.P3 = t.InvTransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f InvTransformed(this Quad2f polygon, Euclidean2f t) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad2f polygon, Similarity2f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); polygon.P3 = t.TransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f Transformed(this Quad2f polygon, Similarity2f t) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad2f polygon, Similarity2f t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); polygon.P2 = t.InvTransformPos(polygon.P2); polygon.P3 = t.InvTransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f InvTransformed(this Quad2f polygon, Similarity2f t) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad2f polygon, Affine2f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); polygon.P3 = t.TransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f Transformed(this Quad2f polygon, Affine2f t) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad2f polygon, Shift2f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); polygon.P3 = t.Transform(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f Transformed(this Quad2f polygon, Shift2f t) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad2f polygon, Shift2f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); polygon.P3 = t.InvTransform(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f InvTransformed(this Quad2f polygon, Shift2f t) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad2f polygon, Rot2f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); polygon.P3 = t.Transform(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f Transformed(this Quad2f polygon, Rot2f t) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad2f polygon, Rot2f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); polygon.P3 = t.InvTransform(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f InvTransformed(this Quad2f polygon, Rot2f t) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad2f polygon, Scale2f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); polygon.P3 = t.Transform(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f Transformed(this Quad2f polygon, Scale2f t) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad2f polygon, Scale2f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); polygon.P3 = t.InvTransform(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f InvTransformed(this Quad2f polygon, Scale2f t) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad2f polygon, M22f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); polygon.P3 = t.Transform(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad2f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2f Transformed(this Quad2f polygon, M22f t) { var result = new Quad2f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } #endregion public static V2f[] GetPointArray(this Quad2f quad) { var pa = new V2f[4]; pa[0] = quad.P0; pa[1] = quad.P1; pa[2] = quad.P2; pa[3] = quad.P3; return pa; } public static V2f ComputeCentroid(this Quad2f quad) { return 0.25f * (quad.P0 + quad.P1 + quad.P2 + quad.P3); } } #endregion #region Polygon3f /// /// A polygon internally represented by an array of points. Implemented /// as a structure, the validity of the polygon can be checked via its /// PointCount, which must be bigger than 0 for a polygon to hold any /// points, and bigger than 2 for a polygon to be geometrically valid. /// [StructLayout(LayoutKind.Sequential)] public partial struct Polygon3f : IEquatable, IValidity, IPolygon, IBoundingBox3f { internal int m_pointCount; internal V3f[] m_pointArray; #region Constructors /// /// Creates a polygon from given points. /// public Polygon3f(V3f[] pointArray, int pointCount) { if (pointArray != null) { if (pointCount <= pointArray.Length) { m_pointCount = pointCount; m_pointArray = pointArray; } else throw new ArgumentException( "point count must be smaller or equal array length"); } else { m_pointCount = 0; m_pointArray = null; } } /// /// Creates a polygon from given points. /// public Polygon3f(params V3f[] pointArray) { m_pointCount = pointArray != null ? pointArray.Length : 0; m_pointArray = pointArray; } /// /// Creates a polygon from given points. /// public Polygon3f(V3f[] pointArray, int startIndex, int count) { if (startIndex < 0 || startIndex >= pointArray.Length - 1) throw new ArgumentException(); if (count <= 0 || startIndex + count >= pointArray.Length) throw new ArgumentException(); m_pointCount = count; m_pointArray = new V3f[count]; for (int i = 0; i < count; i++) m_pointArray[i] = pointArray[startIndex + i]; } /// /// Creates a polygon from point count and point creator function. /// public Polygon3f(int pointCount, Func index_pointCreator) : this(new V3f[pointCount].SetByIndex(index_pointCreator)) { } /// /// Creates a polygon from a sequence of points. /// public Polygon3f(IEnumerable points) : this(points.ToArray()) { } /// /// Creates a polygon from the points of a pointArray that /// are selected by an index array. /// public Polygon3f(int[] indexArray, V3f[] pointArray) : this(indexArray.Map(i => pointArray[i])) { } /// /// Creates a polygon from a triangle. /// public Polygon3f(Triangle3f triangle) : this(triangle.GetPointArray()) { } /// /// Creates a polygon from a quad. /// public Polygon3f(Quad3f quad) : this(quad.GetPointArray()) { } /// /// Copy constructor. /// Performs deep copy of original. /// public Polygon3f(Polygon3f original) : this(original.GetPointArray()) { } #endregion #region Constants public static readonly Polygon3f Invalid = new Polygon3f(null, 0); #endregion #region Properties public readonly bool IsValid => m_pointArray != null; public readonly bool IsInvalid => m_pointArray == null; /// /// The number of points in the polygon. If this is 0, the polygon /// is invalid. /// public readonly int PointCount => m_pointCount; /// /// Enumerates points. /// public readonly IEnumerable Points { get { for (int pi = 0; pi < m_pointCount; pi++) yield return m_pointArray[pi]; } } #endregion #region Conversions /// /// Returns a copy of the polygons point array. /// public readonly V3f[] GetPointArray() { var pc = m_pointCount; var pa = new V3f[pc]; for (int pi = 0; pi < pc; pi++) pa[pi] = m_pointArray[pi]; return pa; } /// /// [P0, P1, P2] -> [P0, P1, P2, P0]. /// public readonly V3f[] GetPointArrayWithRepeatedFirstPoint() { var pc = m_pointCount; var pa = new V3f[pc + 1]; for (int pi = 0; pi < pc; pi++) pa[pi] = m_pointArray[pi]; pa[pc] = pa[0]; return pa; } /// /// Returns a transformed copy of the polygons point array. /// public readonly T[] GetPointArray(Func point_copyFun) { var pc = m_pointCount; var pa = new T[pc]; for (int pi = 0; pi < pc; pi++) pa[pi] = point_copyFun(m_pointArray[pi]); return pa; } /// /// Returns a transformed copy of the polygons point array. /// public readonly T[] GetPointArray(Func point_index_copyFun) { var pc = m_pointCount; var pa = new T[pc]; for (int pi = 0; pi < pc; pi++) pa[pi] = point_index_copyFun(m_pointArray[pi], pi); return pa; } #endregion #region Indexing /// /// Gets the index-th point of this polygon. /// public readonly V3f this[int index] { get { return m_pointArray[index]; } set { m_pointArray[index] = value; } } #endregion #region Edges and Lines /// /// Index-th edge as vector (edgeEndPos - edgeBeginPos). /// public readonly V3f Edge(int index) { var p0 = m_pointArray[index++]; var p1 = m_pointArray[index < m_pointCount ? index : 0]; return p1 - p0; } /// /// Edges as vectors (edgeEndPos - edgeBeginPos). /// public readonly IEnumerable Edges { get { var pc = m_pointCount; var p = m_pointArray[0]; var p0 = p; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; yield return p1 - p0; p0 = p1; } yield return p - p0; } } /// /// Index-th edge as line segment (edgeBeginPos, edgeEndPos). /// public readonly Line3f EdgeLine(int index) { var p0 = m_pointArray[index++]; var p1 = m_pointArray[index < m_pointCount ? index : 0]; return new Line3f(p0, p1); } /// /// Edges as line segments (edgeBeginPos, edgeEndPos). /// public readonly IEnumerable EdgeLines { get { var pc = m_pointCount; if (pc < 1) yield break; var p0 = m_pointArray[0]; var p = p0; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; yield return new Line3f(p0, p1); p0 = p1; } yield return new Line3f(p0, p); } } /// /// Edges as vectors (edgeEndPos - edgeBeginPos). /// public readonly V3f[] GetEdgeArray() { var pc = m_pointCount; if (pc < 2) return Array.Empty(); var edgeArray = new V3f[pc]; var p = m_pointArray[0]; var p0 = p; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; edgeArray[pi - 1] = p1 - p0; p0 = p1; } edgeArray[pc - 1] = p - p0; return edgeArray; } /// /// Edges as line segments (edgeBeginPos, edgeEndPos). /// public readonly Line3f[] GetEdgeLineArray() { var pc = PointCount; if (pc < 2) return Array.Empty(); var ela = new Line3f[pc]; var p = m_pointArray[0]; var p0 = p; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; ela[pi - 1] = new Line3f(p0, p1); p0 = p1; } ela[pc - 1] = new Line3f(p0, p); return ela; } #endregion #region Transformations /// /// Returns copy of polygon. Same as Map(p => p). /// public readonly Polygon3f Copy() { return new Polygon3f(m_pointArray.Copy()); } /// /// Returns transformed copy of this polygon. /// public readonly Polygon3f Map(Func point_fun) { var pc = m_pointCount; V3f[] opa = m_pointArray, npa = new V3f[pc]; for (int pi = 0; pi < pc; pi++) npa[pi] = point_fun(opa[pi]); return new Polygon3f(npa, pc); } /// /// Gets copy with reversed order of vertices. /// public readonly Polygon3f Reversed { get { var pc = m_pointCount; V3f[] opa = m_pointArray, npa = new V3f[pc]; for (int pi = 0, pj = pc - 1; pi < pc; pi++, pj--) npa[pi] = opa[pj]; return new Polygon3f(npa, pc); } } /// /// Reverses order of vertices in-place. /// public readonly void Reverse() { var pa = m_pointArray; for (int pi = 0, pj = m_pointCount - 1; pi < pj; pi++, pj--) { var t = pa[pi]; pa[pi] = pa[pj]; pa[pj] = t; } } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Polygon3f a, Polygon3f b) { if (a.m_pointCount != b.m_pointCount) return false; for (int pi = 0; pi < a.m_pointCount; pi++) if (a.m_pointArray[pi] != b.m_pointArray[pi]) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Polygon3f a, Polygon3f b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return m_pointArray.GetCombinedHashCode(m_pointCount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Polygon3f other) { if (m_pointCount != other.m_pointCount) return false; for (int pi = 0; pi < m_pointCount; pi++) if (!m_pointArray[pi].Equals(other.m_pointArray[pi])) return false; return true; } public override readonly bool Equals(object other) => (other is Polygon3f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}]", Points.Select(x => x.ToString()).Join(", ") ); } public static Polygon3f Parse(string s) { var va = s.NestedBracketSplitLevelOne().ToArray(); return new Polygon3f(va.Select(x => V3f.Parse(x))); } #endregion #region IBoundingBox3f Members /// /// Bounding box of polygon. /// public readonly Box3f BoundingBox3f { get { return new Box3f(m_pointArray, 0, m_pointCount); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Polygon3f a, Polygon3f b, float tolerance) { if (a.m_pointCount != b.m_pointCount) return false; for (int pi = 0; pi < a.m_pointCount; pi++) if (!ApproximateEquals(a.m_pointArray[pi], b.m_pointArray[pi], tolerance)) return false; return true; } /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Polygon3f a, Polygon3f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Polygon3fExtensions public static partial class Polygon3fExtensions { #region Geometric Properties /// /// The vertex centroid is the average of the vertex coordinates. /// public static V3f ComputeVertexCentroid(this Polygon3f polygon) { var sum = V3f.Zero; int pc = polygon.PointCount; for (int i = 0; i < pc; i++) sum += polygon[i]; float scale = 1 / (float)pc; return sum * scale; } public static float ComputePerimeter(this Polygon3f polygon) { var pc = polygon.PointCount; var p0 = polygon[pc - 1]; float r = 0; for (int i = 0; i < pc; i++) { var p1 = polygon[i]; r += Vec.Distance(p0, p1); p0 = p1; } return r; } #endregion #region Geometric Transformations /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. public static void Scale(this ref Polygon3f polygon, float scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f Scaled(this Polygon3f polygon, float scale) { var result = new Polygon3f(polygon); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. public static void Scale(this ref Polygon3f polygon, V3f center, float scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = center + (polygon.m_pointArray[pi] - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f Scaled(this Polygon3f polygon, V3f center, float scale) { var result = new Polygon3f(polygon); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutVertexCentroid(this ref Polygon3f polygon, float scale) { var center = polygon.ComputeVertexCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f ScaledAboutVertexCentroid(this Polygon3f polygon, float scale) { var result = new Polygon3f(polygon); result.ScaleAboutVertexCentroid(scale); return result; } /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. public static void Scale(this ref Polygon3f polygon, V3f scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f Scaled(this Polygon3f polygon, V3f scale) { var result = new Polygon3f(polygon); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. public static void Scale(this ref Polygon3f polygon, V3f center, V3f scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = center + (polygon.m_pointArray[pi] - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f Scaled(this Polygon3f polygon, V3f center, V3f scale) { var result = new Polygon3f(polygon); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutVertexCentroid(this ref Polygon3f polygon, V3f scale) { var center = polygon.ComputeVertexCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f ScaledAboutVertexCentroid(this Polygon3f polygon, V3f scale) { var result = new Polygon3f(polygon); result.ScaleAboutVertexCentroid(scale); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon3f polygon, M44f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.TransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f Transformed(this Polygon3f polygon, M44f t) { var result = new Polygon3f(polygon); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon3f polygon, Euclidean3f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.TransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f Transformed(this Polygon3f polygon, Euclidean3f t) { var result = new Polygon3f(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon3f polygon, Euclidean3f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f InvTransformed(this Polygon3f polygon, Euclidean3f t) { var result = new Polygon3f(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon3f polygon, Similarity3f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.TransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f Transformed(this Polygon3f polygon, Similarity3f t) { var result = new Polygon3f(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon3f polygon, Similarity3f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f InvTransformed(this Polygon3f polygon, Similarity3f t) { var result = new Polygon3f(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon3f polygon, Affine3f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.TransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f Transformed(this Polygon3f polygon, Affine3f t) { var result = new Polygon3f(polygon); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon3f polygon, Shift3f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Transform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f Transformed(this Polygon3f polygon, Shift3f t) { var result = new Polygon3f(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon3f polygon, Shift3f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f InvTransformed(this Polygon3f polygon, Shift3f t) { var result = new Polygon3f(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon3f polygon, Rot3f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Transform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f Transformed(this Polygon3f polygon, Rot3f t) { var result = new Polygon3f(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon3f polygon, Rot3f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f InvTransformed(this Polygon3f polygon, Rot3f t) { var result = new Polygon3f(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon3f polygon, Scale3f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Transform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f Transformed(this Polygon3f polygon, Scale3f t) { var result = new Polygon3f(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon3f polygon, Scale3f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f InvTransformed(this Polygon3f polygon, Scale3f t) { var result = new Polygon3f(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon3f polygon, M33f t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Transform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3f Transformed(this Polygon3f polygon, M33f t) { var result = new Polygon3f(polygon); result.Transform(t); return result; } public static Polygon3f WithoutMultiplePoints(this Polygon3f polygon, float eps = 1e-5f) { eps *= eps; var opc = polygon.PointCount; var pa = new V3f[opc]; var pc = 0; pa[0] = polygon[0]; for (int pi = 1; pi < opc; pi++) if (Vec.DistanceSquared(pa[pc], polygon[pi]) > eps) pa[++pc] = polygon[pi]; if (Vec.DistanceSquared(pa[pc], polygon[0]) > eps) ++pc; return new Polygon3f(pa, pc); } #endregion #region Clipping /// /// Clip the supplied polygon at the supplied plane. The method should /// work with all non-selfintersecting polygons. Returns all parts of /// the polygon that are at the positive side of the plane. /// public static Polygon3f ConvexClipped( this Polygon3f polygon, Plane3f plane, float eps = 1e-5f) { var opc = polygon.PointCount; V3f[] pa = new V3f[opc + 1]; var pc = 0; var pf = polygon[0]; var hf = plane.Height(pf); bool hfp = hf > eps, hfn = hf < -eps; if (hf >= -eps) pa[pc++] = pf; var p0 = pf; var h0 = hf; var h0p = hfp; var h0n = hfn; for (int vi = 1; vi < opc; vi++) { var p1 = polygon[vi]; var h1 = plane.Height(p1); bool h1p = h1 > eps, h1n = h1 < -eps; if (h0p && h1n || h0n && h1p) pa[pc++] = p0 + (p1 - p0) * (h0 / (h0 - h1)); if (h1 >= -eps) pa[pc++] = p1; p0 = p1; h0 = h1; h0p = h1p; h0n = h1n; } if (h0p && hfn || h0n && hfp) pa[pc++] = p0 + (pf - p0) * (h0 / (h0 - hf)); return new Polygon3f(pa, pc); } /// /// Returns the convex polygon clipped by the set of planes (defined /// as Plane3fs), i.e. all parts of the polygon that are at the positive /// side of the planes. /// public static Polygon3f ConvexClipped( this Polygon3f polygon, Plane3f[] planes, float eps = 1e-5f) { foreach (var c in planes) { polygon = polygon.ConvexClipped(c, eps); if (polygon.PointCount == 0) break; } return polygon; } /// /// Returns the polygon clipped by the hull, i.e. all parts of the /// polygon that are at the positive side of the hull planes. /// public static Polygon3f ConvexClipped( this Polygon3f polygon, Hull3f hull, float eps = 1e-5f) { return polygon.ConvexClipped(hull.PlaneArray, eps); } /// /// TODO summary. /// public static Polygon3f ConvexClipped( this Polygon3f polygon, Box3f box, float eps = 1e-5f) { var planes = new[] { new Plane3f(V3f.XAxis, box.Min), new Plane3f(-V3f.XAxis, box.Max), new Plane3f(V3f.YAxis, box.Min), new Plane3f(-V3f.YAxis, box.Max), new Plane3f(V3f.ZAxis, box.Min), new Plane3f(-V3f.ZAxis, box.Max), }; return polygon.ConvexClipped(planes); } #endregion } #endregion #region IndexPolygon3f [StructLayout(LayoutKind.Sequential)] public readonly partial struct IndexPolygon3f : IValidity, IPolygon { private readonly int m_pointCount; private readonly int m_firstIndex; private readonly int[] m_indexArray; private readonly V3f[] m_pointArray; #region Constructors public IndexPolygon3f(int[] indexArray, int firstIndex, int pointCount, V3f[] pointArray) { m_indexArray = indexArray; m_firstIndex = firstIndex; m_pointCount = pointCount; m_pointArray = pointArray; } public IndexPolygon3f(V3f[] pointArray, int firstIndex, int pointCount) : this(new int[pointCount].SetByIndex(i => firstIndex + i), 0, pointCount, pointArray) { } public IndexPolygon3f(V3f[] pointArray) : this(new int[pointArray.Length].SetByIndex(i => i), 0, pointArray.Length, pointArray) { } #endregion #region Constants public static readonly IndexPolygon3f Invalid = new IndexPolygon3f(null, 0, 0, null); #endregion #region Properties public bool IsValid { get { return m_indexArray != null && m_pointArray != null; } } public bool IsInvalid { get { return m_indexArray == null || m_pointArray == null; } } public int PointCount { get { return m_pointCount; } } public int FirstIndex { get { return m_firstIndex; } } /// /// The index array that contains the point indices of the /// index polygon at the index range [FirstIndex, FirstIndex + PointCount). /// NOTE: This is different from the array returned by GetIndexArray(). /// public int[] IndexArray { get { return m_indexArray; } } /// /// The point array that contains the points referenced by /// the index array. Note: This is different from the array /// returned by GetPointArray(). /// public V3f[] PointArray { get { return m_pointArray; } } public IEnumerable Points { get { for (int i = 0; i < m_pointCount; i++) yield return m_pointArray[m_indexArray[m_firstIndex + i]]; } } public IEnumerable Indices { get { for (int i = 0; i < m_pointCount; i++) yield return m_indexArray[m_firstIndex + i]; } } #endregion #region Indexing public V3f this[int index] { get { return m_pointArray[m_indexArray[m_firstIndex + index]]; } set { m_pointArray[m_indexArray[m_firstIndex + index]] = value; } } #endregion #region Conversions public void ForEachIndex(Action index_act) { var ia = m_indexArray; int fi = m_firstIndex; for (int i = 0; i < m_pointCount; i++) index_act(ia[fi + i]); } /// /// Returns a newly created array containing only the actual indices /// of the index polygon. NOTE: This is different from the /// IndexArray property! /// public int[] GetIndexArray() { return m_indexArray.Copy(m_firstIndex, m_pointCount); } /// /// Returns a newly created array containing only the actual points /// of the index polygon. NOTE: This is different from the /// PointArray property! /// public V3f[] GetPointArray() { var pa = m_pointArray; return m_indexArray.Map(m_firstIndex, m_pointCount, i => pa[i]); } public T[] GetPointArray(T[] pointArray) { return m_indexArray.Map(m_firstIndex, m_pointCount, i => pointArray[i]); } public T[] GetPointArray(List pointList) { return m_indexArray.Map(m_firstIndex, m_pointCount, i => pointList[i]); } #endregion } #endregion #region IndexPolygon3fExtensions public static partial class IndexPolygon3fExtensions { #region Conversions public static Polygon3f ToPolygon3f(this IndexPolygon3f polygon) { return new Polygon3f(polygon.GetPointArray()); } #endregion #region Geometric Properties /// /// The vertex centroid is the average of the vertex coordinates. /// public static V3f ComputeVertexCentroid(this IndexPolygon3f polygon) { var sum = V3f.Zero; int pc = polygon.PointCount; for (int i = 0; i < pc; i++) sum += polygon[i]; float scale = 1 / (float)pc; return sum * scale; } public static float ComputePerimeter(this IndexPolygon3f polygon) { var pc = polygon.PointCount; var p0 = polygon[pc - 1]; float r = 0; for (int i = 0; i < pc; i++) { var p1 = polygon[i]; r += Vec.Distance(p0, p1); p0 = p1; } return r; } #endregion } #endregion #region Line3f [StructLayout(LayoutKind.Sequential)] public partial struct Line3f : IEquatable, IValidity, IPolygon, IBoundingBox3f { public V3f P0, P1; #region Constructors /// /// Creates line from 2 points. /// public Line3f(V3f p0, V3f p1) { P0 = p0; P1 = p1; } /// /// Creates line from first 2 points in the sequence. /// public Line3f(IEnumerable points) { var pa = points.TakeToArray(2); P0 = pa[0]; P1 = pa[1]; } #endregion #region Properties public readonly bool IsValid { get { return true; } } public readonly bool IsInvalid { get { return false; } } public readonly int PointCount { get { return 2; } } public readonly IEnumerable Points { get { yield return P0; yield return P1; } } public readonly Line3f Reversed { get { return new Line3f(P1, P0); } } #endregion #region Indexer public V3f this[int index] { readonly get { switch (index) { case 0: return P0; case 1: return P1; default: throw new IndexOutOfRangeException(); } } set { switch (index) { case 0: P0 = value; return; case 1: P1 = value; return; default: throw new IndexOutOfRangeException(); } } } #endregion #region Transformations public readonly Line3f Copy(Func point_copyFun) { return new Line3f(point_copyFun(P0), point_copyFun(P1)); } public readonly Line2d ToLine2d(Func point_copyFun) { return new Line2d(point_copyFun(P0), point_copyFun(P1)); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Line3f a, Line3f b) => (a.P0 == b.P0) && (a.P1 == b.P1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Line3f a, Line3f b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(P0, P1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Line3f other) => P0.Equals(other.P0) && P1.Equals(other.P1); public override readonly bool Equals(object other) => (other is Line3f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", P0, P1); } public static Line3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Line3f(V3f.Parse(x[0]), V3f.Parse(x[1])); } #endregion #region IBoundingBox3f Members public readonly Box3f BoundingBox3f { get { return new Box3f(P0, P1).Repair(); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Line3f a, Line3f b, float tolerance) => ApproximateEquals(a.P0, b.P0, tolerance) && ApproximateEquals(a.P1, b.P1, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Line3f a, Line3f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Line3fExtensions public static partial class Line3fExtensions { #region Geometric Transformations /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Line3f polygon, float scale) { polygon.P0 *= scale; polygon.P1 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f Scaled(this Line3f polygon, float scale) { var result = new Line3f(polygon.P0, polygon.P1); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Line3f polygon, V3f center, float scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f Scaled(this Line3f polygon, V3f center, float scale) { var result = new Line3f(polygon.P0, polygon.P1); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Line3f polygon, float scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f ScaledAboutCentroid(this Line3f polygon, float scale) { var result = new Line3f(polygon.P0, polygon.P1); result.ScaleAboutCentroid(scale); return result; } /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Line3f polygon, V3f scale) { polygon.P0 *= scale; polygon.P1 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f Scaled(this Line3f polygon, V3f scale) { var result = new Line3f(polygon.P0, polygon.P1); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Line3f polygon, V3f center, V3f scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f Scaled(this Line3f polygon, V3f center, V3f scale) { var result = new Line3f(polygon.P0, polygon.P1); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Line3f polygon, V3f scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f ScaledAboutCentroid(this Line3f polygon, V3f scale) { var result = new Line3f(polygon.P0, polygon.P1); result.ScaleAboutCentroid(scale); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line3f polygon, M44f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f Transformed(this Line3f polygon, M44f t) { var result = new Line3f(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line3f polygon, Euclidean3f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f Transformed(this Line3f polygon, Euclidean3f t) { var result = new Line3f(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line3f polygon, Euclidean3f t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f InvTransformed(this Line3f polygon, Euclidean3f t) { var result = new Line3f(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line3f polygon, Similarity3f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f Transformed(this Line3f polygon, Similarity3f t) { var result = new Line3f(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line3f polygon, Similarity3f t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f InvTransformed(this Line3f polygon, Similarity3f t) { var result = new Line3f(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line3f polygon, Affine3f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f Transformed(this Line3f polygon, Affine3f t) { var result = new Line3f(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line3f polygon, Shift3f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f Transformed(this Line3f polygon, Shift3f t) { var result = new Line3f(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line3f polygon, Shift3f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f InvTransformed(this Line3f polygon, Shift3f t) { var result = new Line3f(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line3f polygon, Rot3f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f Transformed(this Line3f polygon, Rot3f t) { var result = new Line3f(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line3f polygon, Rot3f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f InvTransformed(this Line3f polygon, Rot3f t) { var result = new Line3f(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line3f polygon, Scale3f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f Transformed(this Line3f polygon, Scale3f t) { var result = new Line3f(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line3f polygon, Scale3f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f InvTransformed(this Line3f polygon, Scale3f t) { var result = new Line3f(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line3f polygon, M33f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3f Transformed(this Line3f polygon, M33f t) { var result = new Line3f(polygon.P0, polygon.P1); result.Transform(t); return result; } #endregion public static V3f[] GetPointArray(this Line3f line) { var pa = new V3f[2]; pa[0] = line.P0; pa[1] = line.P1; return pa; } public static V3f ComputeCentroid(this Line3f line) { return 0.5f * (line.P0 + line.P1); } } #endregion #region Triangle3f [StructLayout(LayoutKind.Sequential)] public partial struct Triangle3f : IEquatable, IValidity, IPolygon, IBoundingBox3f { public V3f P0, P1, P2; #region Constructors /// /// Creates triangle from 3 points. /// public Triangle3f(V3f p0, V3f p1, V3f p2) { P0 = p0; P1 = p1; P2 = p2; } /// /// Creates triangle from first 3 points in the sequence. /// public Triangle3f(IEnumerable points) { var pa = points.TakeToArray(3); P0 = pa[0]; P1 = pa[1]; P2 = pa[2]; } #endregion #region Properties public readonly bool IsValid { get { return true; } } public readonly bool IsInvalid { get { return false; } } /// /// Edge P1 - P0 /// public readonly V3f Edge01 { get { return P1 - P0; } } /// /// Edge P2 - P0 /// public readonly V3f Edge02 { get { return P2 - P0; } } /// /// Edge P2 - P1 /// public readonly V3f Edge12 { get { return P2 - P1; } } /// /// Edge P0 - P1 /// public readonly V3f Edge10 { get { return P0 - P1; } } /// /// Edge P0 - P2 /// public readonly V3f Edge20 { get { return P0 - P2; } } /// /// Edge P1 - P2 /// public readonly V3f Edge21 { get { return P1 - P2; } } public readonly IEnumerable Edges { get { yield return P1 - P0; yield return P2 - P1; yield return P0 - P2; } } public readonly V3f[] EdgeArray { get { var a = new V3f[3]; a[0] = P1 - P0; a[1] = P2 - P1; a[2] = P0 - P2; return a; } } public readonly IEnumerable EdgeLines { get { yield return new Line3f(P0, P1); yield return new Line3f(P1, P2); yield return new Line3f(P2, P0); } } public readonly Line3f[] EdgeLineArray { get { var a = new Line3f[3]; a[0] = new Line3f(P0, P1); a[1] = new Line3f(P1, P2); a[2] = new Line3f(P2, P0); return a; } } public readonly Line3f GetEdgeLine(int index) { switch (index) { case 0: return new Line3f(P0, P1); case 1: return new Line3f(P1, P2); case 2: return new Line3f(P2, P0); } throw new InvalidOperationException(); } public readonly V3f GetEdge(int index) { switch (index) { case 0: return P1 - P0; case 1: return P2 - P1; case 2: return P0 - P2; } throw new InvalidOperationException(); } public readonly Line3f Line01 { get { return new Line3f(P0, P1); } } public readonly Line3f Line02 { get { return new Line3f(P0, P2); } } public readonly Line3f Line12 { get { return new Line3f(P1, P2); } } public readonly Line3f Line10 { get { return new Line3f(P1, P0); } } public readonly Line3f Line20 { get { return new Line3f(P2, P0); } } public readonly Line3f Line21 { get { return new Line3f(P2, P1); } } public readonly int PointCount { get { return 3; } } public readonly IEnumerable Points { get { yield return P0; yield return P1; yield return P2; } } public readonly Triangle3f Reversed { get { return new Triangle3f(P2, P1, P0); } } #endregion #region Indexer public V3f this[int index] { readonly get { switch (index) { case 0: return P0; case 1: return P1; case 2: return P2; default: throw new IndexOutOfRangeException(); } } set { switch (index) { case 0: P0 = value; return; case 1: P1 = value; return; case 2: P2 = value; return; default: throw new IndexOutOfRangeException(); } } } #endregion #region Transformations public readonly Triangle3f Copy(Func point_copyFun) { return new Triangle3f(point_copyFun(P0), point_copyFun(P1), point_copyFun(P2)); } public readonly Triangle2d ToTriangle2d(Func point_copyFun) { return new Triangle2d(point_copyFun(P0), point_copyFun(P1), point_copyFun(P2)); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Triangle3f a, Triangle3f b) => (a.P0 == b.P0) && (a.P1 == b.P1) && (a.P2 == b.P2); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Triangle3f a, Triangle3f b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(P0, P1, P2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Triangle3f other) => P0.Equals(other.P0) && P1.Equals(other.P1) && P2.Equals(other.P2); public override readonly bool Equals(object other) => (other is Triangle3f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", P0, P1, P2); } public static Triangle3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Triangle3f(V3f.Parse(x[0]), V3f.Parse(x[1]), V3f.Parse(x[2])); } #endregion #region IBoundingBox3f Members public readonly Box3f BoundingBox3f { get { return new Box3f(P0, P1, P2); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Triangle3f a, Triangle3f b, float tolerance) => ApproximateEquals(a.P0, b.P0, tolerance) && ApproximateEquals(a.P1, b.P1, tolerance) && ApproximateEquals(a.P2, b.P2, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Triangle3f a, Triangle3f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Triangle3fExtensions public static partial class Triangle3fExtensions { #region Geometric Transformations /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Triangle3f polygon, float scale) { polygon.P0 *= scale; polygon.P1 *= scale; polygon.P2 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f Scaled(this Triangle3f polygon, float scale) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Triangle3f polygon, V3f center, float scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; polygon.P2 = center + (polygon.P2 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f Scaled(this Triangle3f polygon, V3f center, float scale) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Triangle3f polygon, float scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f ScaledAboutCentroid(this Triangle3f polygon, float scale) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.ScaleAboutCentroid(scale); return result; } /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Triangle3f polygon, V3f scale) { polygon.P0 *= scale; polygon.P1 *= scale; polygon.P2 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f Scaled(this Triangle3f polygon, V3f scale) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Triangle3f polygon, V3f center, V3f scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; polygon.P2 = center + (polygon.P2 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f Scaled(this Triangle3f polygon, V3f center, V3f scale) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Triangle3f polygon, V3f scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f ScaledAboutCentroid(this Triangle3f polygon, V3f scale) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.ScaleAboutCentroid(scale); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle3f polygon, M44f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f Transformed(this Triangle3f polygon, M44f t) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle3f polygon, Euclidean3f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f Transformed(this Triangle3f polygon, Euclidean3f t) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle3f polygon, Euclidean3f t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); polygon.P2 = t.InvTransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f InvTransformed(this Triangle3f polygon, Euclidean3f t) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle3f polygon, Similarity3f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f Transformed(this Triangle3f polygon, Similarity3f t) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle3f polygon, Similarity3f t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); polygon.P2 = t.InvTransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f InvTransformed(this Triangle3f polygon, Similarity3f t) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle3f polygon, Affine3f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f Transformed(this Triangle3f polygon, Affine3f t) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle3f polygon, Shift3f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f Transformed(this Triangle3f polygon, Shift3f t) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle3f polygon, Shift3f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f InvTransformed(this Triangle3f polygon, Shift3f t) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle3f polygon, Rot3f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f Transformed(this Triangle3f polygon, Rot3f t) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle3f polygon, Rot3f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f InvTransformed(this Triangle3f polygon, Rot3f t) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle3f polygon, Scale3f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f Transformed(this Triangle3f polygon, Scale3f t) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle3f polygon, Scale3f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f InvTransformed(this Triangle3f polygon, Scale3f t) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle3f polygon, M33f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3f Transformed(this Triangle3f polygon, M33f t) { var result = new Triangle3f(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } #endregion public static V3f[] GetPointArray(this Triangle3f triangle) { var pa = new V3f[3]; pa[0] = triangle.P0; pa[1] = triangle.P1; pa[2] = triangle.P2; return pa; } public static V3f ComputeCentroid(this Triangle3f triangle) { return ConstantF.OneThird * (triangle.P0 + triangle.P1 + triangle.P2); } } #endregion #region Quad3f [StructLayout(LayoutKind.Sequential)] public partial struct Quad3f : IEquatable, IValidity, IPolygon, IBoundingBox3f { public V3f P0, P1, P2, P3; #region Constructors /// /// Creates quad from 4 points. /// public Quad3f(V3f p0, V3f p1, V3f p2, V3f p3) { P0 = p0; P1 = p1; P2 = p2; P3 = p3; } /// /// Creates quad from first 4 points in the sequence. /// public Quad3f(IEnumerable points) { var pa = points.TakeToArray(4); P0 = pa[0]; P1 = pa[1]; P2 = pa[2]; P3 = pa[3]; } /// /// Creates quad from point and two vectors representing edges. /// public Quad3f(V3f p0, V3f edge01, V3f edge03) { P0 = p0; P1 = p0 + edge01; P2 = P1 + edge03; P3 = p0 + edge03; } #endregion #region Properties public readonly bool IsValid { get { return true; } } public readonly bool IsInvalid { get { return false; } } /// /// Edge P1 - P0 /// public readonly V3f Edge01 { get { return P1 - P0; } } /// /// Edge P3 - P0 /// public readonly V3f Edge03 { get { return P3 - P0; } } /// /// Edge P2 - P1 /// public readonly V3f Edge12 { get { return P2 - P1; } } /// /// Edge P0 - P1 /// public readonly V3f Edge10 { get { return P0 - P1; } } /// /// Edge P3 - P2 /// public readonly V3f Edge23 { get { return P3 - P2; } } /// /// Edge P1 - P2 /// public readonly V3f Edge21 { get { return P1 - P2; } } /// /// Edge P0 - P3 /// public readonly V3f Edge30 { get { return P0 - P3; } } /// /// Edge P2 - P3 /// public readonly V3f Edge32 { get { return P2 - P3; } } public readonly IEnumerable Edges { get { yield return P1 - P0; yield return P2 - P1; yield return P3 - P2; yield return P0 - P3; } } public readonly V3f[] EdgeArray { get { var a = new V3f[4]; a[0] = P1 - P0; a[1] = P2 - P1; a[2] = P3 - P2; a[3] = P0 - P3; return a; } } public readonly IEnumerable EdgeLines { get { yield return new Line3f(P0, P1); yield return new Line3f(P1, P2); yield return new Line3f(P2, P3); yield return new Line3f(P3, P0); } } public readonly Line3f[] EdgeLineArray { get { var a = new Line3f[4]; a[0] = new Line3f(P0, P1); a[1] = new Line3f(P1, P2); a[2] = new Line3f(P2, P3); a[3] = new Line3f(P3, P0); return a; } } public readonly Line3f GetEdgeLine(int index) { switch (index) { case 0: return new Line3f(P0, P1); case 1: return new Line3f(P1, P2); case 2: return new Line3f(P2, P3); case 3: return new Line3f(P3, P0); } throw new InvalidOperationException(); } public readonly V3f GetEdge(int index) { switch (index) { case 0: return P1 - P0; case 1: return P2 - P1; case 2: return P3 - P2; case 3: return P0 - P3; } throw new InvalidOperationException(); } public readonly Line3f Line01 { get { return new Line3f(P0, P1); } } public readonly Line3f Line03 { get { return new Line3f(P0, P3); } } public readonly Line3f Line12 { get { return new Line3f(P1, P2); } } public readonly Line3f Line10 { get { return new Line3f(P1, P0); } } public readonly Line3f Line23 { get { return new Line3f(P2, P3); } } public readonly Line3f Line21 { get { return new Line3f(P2, P1); } } public readonly Line3f Line30 { get { return new Line3f(P3, P0); } } public readonly Line3f Line32 { get { return new Line3f(P3, P2); } } public readonly int PointCount { get { return 4; } } public readonly IEnumerable Points { get { yield return P0; yield return P1; yield return P2; yield return P3; } } public readonly Quad3f Reversed { get { return new Quad3f(P3, P2, P1, P0); } } #endregion #region Indexer public V3f this[int index] { readonly get { switch (index) { case 0: return P0; case 1: return P1; case 2: return P2; case 3: return P3; default: throw new IndexOutOfRangeException(); } } set { switch (index) { case 0: P0 = value; return; case 1: P1 = value; return; case 2: P2 = value; return; case 3: P3 = value; return; default: throw new IndexOutOfRangeException(); } } } #endregion #region Transformations public readonly Quad3f Copy(Func point_copyFun) { return new Quad3f(point_copyFun(P0), point_copyFun(P1), point_copyFun(P2), point_copyFun(P3)); } public readonly Quad2d ToQuad2d(Func point_copyFun) { return new Quad2d(point_copyFun(P0), point_copyFun(P1), point_copyFun(P2), point_copyFun(P3)); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Quad3f a, Quad3f b) => (a.P0 == b.P0) && (a.P1 == b.P1) && (a.P2 == b.P2) && (a.P3 == b.P3); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Quad3f a, Quad3f b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(P0, P1, P2, P3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Quad3f other) => P0.Equals(other.P0) && P1.Equals(other.P1) && P2.Equals(other.P2) && P3.Equals(other.P3); public override readonly bool Equals(object other) => (other is Quad3f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}, {3}]", P0, P1, P2, P3); } public static Quad3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Quad3f(V3f.Parse(x[0]), V3f.Parse(x[1]), V3f.Parse(x[2]), V3f.Parse(x[3])); } #endregion #region IBoundingBox3f Members public readonly Box3f BoundingBox3f { get { return new Box3f(P0, P1, P2, P3); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Quad3f a, Quad3f b, float tolerance) => ApproximateEquals(a.P0, b.P0, tolerance) && ApproximateEquals(a.P1, b.P1, tolerance) && ApproximateEquals(a.P2, b.P2, tolerance) && ApproximateEquals(a.P3, b.P3, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Quad3f a, Quad3f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Quad3fExtensions public static partial class Quad3fExtensions { #region Geometric Transformations /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Quad3f polygon, float scale) { polygon.P0 *= scale; polygon.P1 *= scale; polygon.P2 *= scale; polygon.P3 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f Scaled(this Quad3f polygon, float scale) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Quad3f polygon, V3f center, float scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; polygon.P2 = center + (polygon.P2 - center) * scale; polygon.P3 = center + (polygon.P3 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f Scaled(this Quad3f polygon, V3f center, float scale) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Quad3f polygon, float scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f ScaledAboutCentroid(this Quad3f polygon, float scale) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.ScaleAboutCentroid(scale); return result; } /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Quad3f polygon, V3f scale) { polygon.P0 *= scale; polygon.P1 *= scale; polygon.P2 *= scale; polygon.P3 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f Scaled(this Quad3f polygon, V3f scale) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Quad3f polygon, V3f center, V3f scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; polygon.P2 = center + (polygon.P2 - center) * scale; polygon.P3 = center + (polygon.P3 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f Scaled(this Quad3f polygon, V3f center, V3f scale) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Quad3f polygon, V3f scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f ScaledAboutCentroid(this Quad3f polygon, V3f scale) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.ScaleAboutCentroid(scale); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad3f polygon, M44f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); polygon.P3 = t.TransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f Transformed(this Quad3f polygon, M44f t) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad3f polygon, Euclidean3f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); polygon.P3 = t.TransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f Transformed(this Quad3f polygon, Euclidean3f t) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad3f polygon, Euclidean3f t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); polygon.P2 = t.InvTransformPos(polygon.P2); polygon.P3 = t.InvTransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f InvTransformed(this Quad3f polygon, Euclidean3f t) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad3f polygon, Similarity3f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); polygon.P3 = t.TransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f Transformed(this Quad3f polygon, Similarity3f t) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad3f polygon, Similarity3f t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); polygon.P2 = t.InvTransformPos(polygon.P2); polygon.P3 = t.InvTransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f InvTransformed(this Quad3f polygon, Similarity3f t) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad3f polygon, Affine3f t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); polygon.P3 = t.TransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f Transformed(this Quad3f polygon, Affine3f t) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad3f polygon, Shift3f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); polygon.P3 = t.Transform(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f Transformed(this Quad3f polygon, Shift3f t) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad3f polygon, Shift3f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); polygon.P3 = t.InvTransform(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f InvTransformed(this Quad3f polygon, Shift3f t) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad3f polygon, Rot3f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); polygon.P3 = t.Transform(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f Transformed(this Quad3f polygon, Rot3f t) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad3f polygon, Rot3f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); polygon.P3 = t.InvTransform(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f InvTransformed(this Quad3f polygon, Rot3f t) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad3f polygon, Scale3f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); polygon.P3 = t.Transform(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f Transformed(this Quad3f polygon, Scale3f t) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad3f polygon, Scale3f t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); polygon.P3 = t.InvTransform(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f InvTransformed(this Quad3f polygon, Scale3f t) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad3f polygon, M33f t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); polygon.P3 = t.Transform(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad3f to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3f Transformed(this Quad3f polygon, M33f t) { var result = new Quad3f(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } #endregion public static V3f[] GetPointArray(this Quad3f quad) { var pa = new V3f[4]; pa[0] = quad.P0; pa[1] = quad.P1; pa[2] = quad.P2; pa[3] = quad.P3; return pa; } public static V3f ComputeCentroid(this Quad3f quad) { return 0.25f * (quad.P0 + quad.P1 + quad.P2 + quad.P3); } } #endregion #region Polygon2d /// /// A polygon internally represented by an array of points. Implemented /// as a structure, the validity of the polygon can be checked via its /// PointCount, which must be bigger than 0 for a polygon to hold any /// points, and bigger than 2 for a polygon to be geometrically valid. /// [StructLayout(LayoutKind.Sequential)] public partial struct Polygon2d : IEquatable, IValidity, IPolygon, IBoundingBox2d { internal int m_pointCount; internal V2d[] m_pointArray; #region Constructors /// /// Creates a polygon from given points. /// public Polygon2d(V2d[] pointArray, int pointCount) { if (pointArray != null) { if (pointCount <= pointArray.Length) { m_pointCount = pointCount; m_pointArray = pointArray; } else throw new ArgumentException( "point count must be smaller or equal array length"); } else { m_pointCount = 0; m_pointArray = null; } } /// /// Creates a polygon from given points. /// public Polygon2d(params V2d[] pointArray) { m_pointCount = pointArray != null ? pointArray.Length : 0; m_pointArray = pointArray; } /// /// Creates a polygon from given points. /// public Polygon2d(V2d[] pointArray, int startIndex, int count) { if (startIndex < 0 || startIndex >= pointArray.Length - 1) throw new ArgumentException(); if (count <= 0 || startIndex + count >= pointArray.Length) throw new ArgumentException(); m_pointCount = count; m_pointArray = new V2d[count]; for (int i = 0; i < count; i++) m_pointArray[i] = pointArray[startIndex + i]; } /// /// Creates a polygon from point count and point creator function. /// public Polygon2d(int pointCount, Func index_pointCreator) : this(new V2d[pointCount].SetByIndex(index_pointCreator)) { } /// /// Creates a polygon from a sequence of points. /// public Polygon2d(IEnumerable points) : this(points.ToArray()) { } /// /// Creates a polygon from the points of a pointArray that /// are selected by an index array. /// public Polygon2d(int[] indexArray, V2d[] pointArray) : this(indexArray.Map(i => pointArray[i])) { } /// /// Creates a polygon from a triangle. /// public Polygon2d(Triangle2d triangle) : this(triangle.GetPointArray()) { } /// /// Creates a polygon from a quad. /// public Polygon2d(Quad2d quad) : this(quad.GetPointArray()) { } /// /// Copy constructor. /// Performs deep copy of original. /// public Polygon2d(Polygon2d original) : this(original.GetPointArray()) { } #endregion #region Constants public static readonly Polygon2d Invalid = new Polygon2d(null, 0); #endregion #region Properties public readonly bool IsValid => m_pointArray != null; public readonly bool IsInvalid => m_pointArray == null; /// /// The number of points in the polygon. If this is 0, the polygon /// is invalid. /// public readonly int PointCount => m_pointCount; /// /// Enumerates points. /// public readonly IEnumerable Points { get { for (int pi = 0; pi < m_pointCount; pi++) yield return m_pointArray[pi]; } } #endregion #region Conversions /// /// Returns a copy of the polygons point array. /// public readonly V2d[] GetPointArray() { var pc = m_pointCount; var pa = new V2d[pc]; for (int pi = 0; pi < pc; pi++) pa[pi] = m_pointArray[pi]; return pa; } /// /// [P0, P1, P2] -> [P0, P1, P2, P0]. /// public readonly V2d[] GetPointArrayWithRepeatedFirstPoint() { var pc = m_pointCount; var pa = new V2d[pc + 1]; for (int pi = 0; pi < pc; pi++) pa[pi] = m_pointArray[pi]; pa[pc] = pa[0]; return pa; } /// /// Returns a transformed copy of the polygons point array. /// public readonly T[] GetPointArray(Func point_copyFun) { var pc = m_pointCount; var pa = new T[pc]; for (int pi = 0; pi < pc; pi++) pa[pi] = point_copyFun(m_pointArray[pi]); return pa; } /// /// Returns a transformed copy of the polygons point array. /// public readonly T[] GetPointArray(Func point_index_copyFun) { var pc = m_pointCount; var pa = new T[pc]; for (int pi = 0; pi < pc; pi++) pa[pi] = point_index_copyFun(m_pointArray[pi], pi); return pa; } #endregion #region Indexing /// /// Gets the index-th point of this polygon. /// public readonly V2d this[int index] { get { return m_pointArray[index]; } set { m_pointArray[index] = value; } } #endregion #region Edges and Lines /// /// Index-th edge as vector (edgeEndPos - edgeBeginPos). /// public readonly V2d Edge(int index) { var p0 = m_pointArray[index++]; var p1 = m_pointArray[index < m_pointCount ? index : 0]; return p1 - p0; } /// /// Edges as vectors (edgeEndPos - edgeBeginPos). /// public readonly IEnumerable Edges { get { var pc = m_pointCount; var p = m_pointArray[0]; var p0 = p; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; yield return p1 - p0; p0 = p1; } yield return p - p0; } } /// /// Index-th edge as line segment (edgeBeginPos, edgeEndPos). /// public readonly Line2d EdgeLine(int index) { var p0 = m_pointArray[index++]; var p1 = m_pointArray[index < m_pointCount ? index : 0]; return new Line2d(p0, p1); } /// /// Edges as line segments (edgeBeginPos, edgeEndPos). /// public readonly IEnumerable EdgeLines { get { var pc = m_pointCount; if (pc < 1) yield break; var p0 = m_pointArray[0]; var p = p0; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; yield return new Line2d(p0, p1); p0 = p1; } yield return new Line2d(p0, p); } } /// /// Edges as vectors (edgeEndPos - edgeBeginPos). /// public readonly V2d[] GetEdgeArray() { var pc = m_pointCount; if (pc < 2) return Array.Empty(); var edgeArray = new V2d[pc]; var p = m_pointArray[0]; var p0 = p; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; edgeArray[pi - 1] = p1 - p0; p0 = p1; } edgeArray[pc - 1] = p - p0; return edgeArray; } /// /// Edges as line segments (edgeBeginPos, edgeEndPos). /// public readonly Line2d[] GetEdgeLineArray() { var pc = PointCount; if (pc < 2) return Array.Empty(); var ela = new Line2d[pc]; var p = m_pointArray[0]; var p0 = p; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; ela[pi - 1] = new Line2d(p0, p1); p0 = p1; } ela[pc - 1] = new Line2d(p0, p); return ela; } #endregion #region Transformations /// /// Returns copy of polygon. Same as Map(p => p). /// public readonly Polygon2d Copy() { return new Polygon2d(m_pointArray.Copy()); } /// /// Returns transformed copy of this polygon. /// public readonly Polygon2d Map(Func point_fun) { var pc = m_pointCount; V2d[] opa = m_pointArray, npa = new V2d[pc]; for (int pi = 0; pi < pc; pi++) npa[pi] = point_fun(opa[pi]); return new Polygon2d(npa, pc); } /// /// Gets copy with reversed order of vertices. /// public readonly Polygon2d Reversed { get { var pc = m_pointCount; V2d[] opa = m_pointArray, npa = new V2d[pc]; for (int pi = 0, pj = pc - 1; pi < pc; pi++, pj--) npa[pi] = opa[pj]; return new Polygon2d(npa, pc); } } /// /// Reverses order of vertices in-place. /// public readonly void Reverse() { var pa = m_pointArray; for (int pi = 0, pj = m_pointCount - 1; pi < pj; pi++, pj--) { var t = pa[pi]; pa[pi] = pa[pj]; pa[pj] = t; } } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Polygon2d a, Polygon2d b) { if (a.m_pointCount != b.m_pointCount) return false; for (int pi = 0; pi < a.m_pointCount; pi++) if (a.m_pointArray[pi] != b.m_pointArray[pi]) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Polygon2d a, Polygon2d b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return m_pointArray.GetCombinedHashCode(m_pointCount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Polygon2d other) { if (m_pointCount != other.m_pointCount) return false; for (int pi = 0; pi < m_pointCount; pi++) if (!m_pointArray[pi].Equals(other.m_pointArray[pi])) return false; return true; } public override readonly bool Equals(object other) => (other is Polygon2d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}]", Points.Select(x => x.ToString()).Join(", ") ); } public static Polygon2d Parse(string s) { var va = s.NestedBracketSplitLevelOne().ToArray(); return new Polygon2d(va.Select(x => V2d.Parse(x))); } #endregion #region IBoundingBox2d Members /// /// Bounding box of polygon. /// public readonly Box2d BoundingBox2d { get { return new Box2d(m_pointArray, 0, m_pointCount); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Polygon2d a, Polygon2d b, double tolerance) { if (a.m_pointCount != b.m_pointCount) return false; for (int pi = 0; pi < a.m_pointCount; pi++) if (!ApproximateEquals(a.m_pointArray[pi], b.m_pointArray[pi], tolerance)) return false; return true; } /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Polygon2d a, Polygon2d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Polygon2dExtensions public static partial class Polygon2dExtensions { #region Geometric Properties /// /// The vertex centroid is the average of the vertex coordinates. /// public static V2d ComputeVertexCentroid(this Polygon2d polygon) { var sum = V2d.Zero; int pc = polygon.PointCount; for (int i = 0; i < pc; i++) sum += polygon[i]; double scale = 1 / (double)pc; return sum * scale; } public static double ComputePerimeter(this Polygon2d polygon) { var pc = polygon.PointCount; var p0 = polygon[pc - 1]; double r = 0; for (int i = 0; i < pc; i++) { var p1 = polygon[i]; r += Vec.Distance(p0, p1); p0 = p1; } return r; } #endregion #region Geometric Transformations /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. public static void Scale(this ref Polygon2d polygon, double scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d Scaled(this Polygon2d polygon, double scale) { var result = new Polygon2d(polygon); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. public static void Scale(this ref Polygon2d polygon, V2d center, double scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = center + (polygon.m_pointArray[pi] - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d Scaled(this Polygon2d polygon, V2d center, double scale) { var result = new Polygon2d(polygon); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutVertexCentroid(this ref Polygon2d polygon, double scale) { var center = polygon.ComputeVertexCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d ScaledAboutVertexCentroid(this Polygon2d polygon, double scale) { var result = new Polygon2d(polygon); result.ScaleAboutVertexCentroid(scale); return result; } /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. public static void Scale(this ref Polygon2d polygon, V2d scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d Scaled(this Polygon2d polygon, V2d scale) { var result = new Polygon2d(polygon); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. public static void Scale(this ref Polygon2d polygon, V2d center, V2d scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = center + (polygon.m_pointArray[pi] - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d Scaled(this Polygon2d polygon, V2d center, V2d scale) { var result = new Polygon2d(polygon); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutVertexCentroid(this ref Polygon2d polygon, V2d scale) { var center = polygon.ComputeVertexCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d ScaledAboutVertexCentroid(this Polygon2d polygon, V2d scale) { var result = new Polygon2d(polygon); result.ScaleAboutVertexCentroid(scale); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon2d polygon, M33d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.TransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d Transformed(this Polygon2d polygon, M33d t) { var result = new Polygon2d(polygon); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon2d polygon, Euclidean2d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.TransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d Transformed(this Polygon2d polygon, Euclidean2d t) { var result = new Polygon2d(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon2d polygon, Euclidean2d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d InvTransformed(this Polygon2d polygon, Euclidean2d t) { var result = new Polygon2d(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon2d polygon, Similarity2d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.TransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d Transformed(this Polygon2d polygon, Similarity2d t) { var result = new Polygon2d(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon2d polygon, Similarity2d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d InvTransformed(this Polygon2d polygon, Similarity2d t) { var result = new Polygon2d(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon2d polygon, Affine2d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.TransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d Transformed(this Polygon2d polygon, Affine2d t) { var result = new Polygon2d(polygon); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon2d polygon, Shift2d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Transform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d Transformed(this Polygon2d polygon, Shift2d t) { var result = new Polygon2d(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon2d polygon, Shift2d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d InvTransformed(this Polygon2d polygon, Shift2d t) { var result = new Polygon2d(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon2d polygon, Rot2d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Transform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d Transformed(this Polygon2d polygon, Rot2d t) { var result = new Polygon2d(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon2d polygon, Rot2d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d InvTransformed(this Polygon2d polygon, Rot2d t) { var result = new Polygon2d(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon2d polygon, Scale2d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Transform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d Transformed(this Polygon2d polygon, Scale2d t) { var result = new Polygon2d(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon2d polygon, Scale2d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d InvTransformed(this Polygon2d polygon, Scale2d t) { var result = new Polygon2d(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon2d polygon, M22d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Transform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d Transformed(this Polygon2d polygon, M22d t) { var result = new Polygon2d(polygon); result.Transform(t); return result; } public static Polygon2d WithoutMultiplePoints(this Polygon2d polygon, double eps = 1e-8) { eps *= eps; var opc = polygon.PointCount; var pa = new V2d[opc]; var pc = 0; pa[0] = polygon[0]; for (int pi = 1; pi < opc; pi++) if (Vec.DistanceSquared(pa[pc], polygon[pi]) > eps) pa[++pc] = polygon[pi]; if (Vec.DistanceSquared(pa[pc], polygon[0]) > eps) ++pc; return new Polygon2d(pa, pc); } #endregion #region Clipping /// /// Clip the supplied polygon at the supplied line. The method should /// work with all non-selfintersecting polygons. Returns all parts of /// the polygon that are at the positive side of the line. /// public static Polygon2d ConvexClipped( this Polygon2d polygon, Plane2d line, double eps = 1e-8) { var opc = polygon.PointCount; V2d[] pa = new V2d[opc + 1]; var pc = 0; var pf = polygon[0]; var hf = line.Height(pf); bool hfp = hf > eps, hfn = hf < -eps; if (hf >= -eps) pa[pc++] = pf; var p0 = pf; var h0 = hf; var h0p = hfp; var h0n = hfn; for (int vi = 1; vi < opc; vi++) { var p1 = polygon[vi]; var h1 = line.Height(p1); bool h1p = h1 > eps, h1n = h1 < -eps; if (h0p && h1n || h0n && h1p) pa[pc++] = p0 + (p1 - p0) * (h0 / (h0 - h1)); if (h1 >= -eps) pa[pc++] = p1; p0 = p1; h0 = h1; h0p = h1p; h0n = h1n; } if (h0p && hfn || h0n && hfp) pa[pc++] = p0 + (pf - p0) * (h0 / (h0 - hf)); return new Polygon2d(pa, pc); } /// /// Returns the convex polygon clipped by the set of lines (defined /// as Plane2ds), i.e. all parts of the polygon that are at the positive /// side of the lines. /// public static Polygon2d ConvexClipped( this Polygon2d polygon, Plane2d[] lines, double eps = 1e-8) { foreach (var c in lines) { polygon = polygon.ConvexClipped(c, eps); if (polygon.PointCount == 0) break; } return polygon; } /// /// Returns the polygon clipped by the hull, i.e. all parts of the /// polygon that are at the positive side of the hull lines. /// public static Polygon2d ConvexClipped( this Polygon2d polygon, Hull2d hull, double eps = 1e-8) { return polygon.ConvexClipped(hull.PlaneArray, eps); } /// /// TODO summary. /// public static Polygon2d ConvexClipped( this Polygon2d polygon, Box2d box, double eps = 1e-8) { var lines = new[] { new Plane2d(V2d.XAxis, box.Min), new Plane2d(-V2d.XAxis, box.Max), new Plane2d(V2d.YAxis, box.Min), new Plane2d(-V2d.YAxis, box.Max), }; return polygon.ConvexClipped(lines); } #endregion } #endregion #region IndexPolygon2d [StructLayout(LayoutKind.Sequential)] public readonly partial struct IndexPolygon2d : IValidity, IPolygon { private readonly int m_pointCount; private readonly int m_firstIndex; private readonly int[] m_indexArray; private readonly V2d[] m_pointArray; #region Constructors public IndexPolygon2d(int[] indexArray, int firstIndex, int pointCount, V2d[] pointArray) { m_indexArray = indexArray; m_firstIndex = firstIndex; m_pointCount = pointCount; m_pointArray = pointArray; } public IndexPolygon2d(V2d[] pointArray, int firstIndex, int pointCount) : this(new int[pointCount].SetByIndex(i => firstIndex + i), 0, pointCount, pointArray) { } public IndexPolygon2d(V2d[] pointArray) : this(new int[pointArray.Length].SetByIndex(i => i), 0, pointArray.Length, pointArray) { } #endregion #region Constants public static readonly IndexPolygon2d Invalid = new IndexPolygon2d(null, 0, 0, null); #endregion #region Properties public bool IsValid { get { return m_indexArray != null && m_pointArray != null; } } public bool IsInvalid { get { return m_indexArray == null || m_pointArray == null; } } public int PointCount { get { return m_pointCount; } } public int FirstIndex { get { return m_firstIndex; } } /// /// The index array that contains the point indices of the /// index polygon at the index range [FirstIndex, FirstIndex + PointCount). /// NOTE: This is different from the array returned by GetIndexArray(). /// public int[] IndexArray { get { return m_indexArray; } } /// /// The point array that contains the points referenced by /// the index array. Note: This is different from the array /// returned by GetPointArray(). /// public V2d[] PointArray { get { return m_pointArray; } } public IEnumerable Points { get { for (int i = 0; i < m_pointCount; i++) yield return m_pointArray[m_indexArray[m_firstIndex + i]]; } } public IEnumerable Indices { get { for (int i = 0; i < m_pointCount; i++) yield return m_indexArray[m_firstIndex + i]; } } #endregion #region Indexing public V2d this[int index] { get { return m_pointArray[m_indexArray[m_firstIndex + index]]; } set { m_pointArray[m_indexArray[m_firstIndex + index]] = value; } } #endregion #region Conversions public void ForEachIndex(Action index_act) { var ia = m_indexArray; int fi = m_firstIndex; for (int i = 0; i < m_pointCount; i++) index_act(ia[fi + i]); } /// /// Returns a newly created array containing only the actual indices /// of the index polygon. NOTE: This is different from the /// IndexArray property! /// public int[] GetIndexArray() { return m_indexArray.Copy(m_firstIndex, m_pointCount); } /// /// Returns a newly created array containing only the actual points /// of the index polygon. NOTE: This is different from the /// PointArray property! /// public V2d[] GetPointArray() { var pa = m_pointArray; return m_indexArray.Map(m_firstIndex, m_pointCount, i => pa[i]); } public T[] GetPointArray(T[] pointArray) { return m_indexArray.Map(m_firstIndex, m_pointCount, i => pointArray[i]); } public T[] GetPointArray(List pointList) { return m_indexArray.Map(m_firstIndex, m_pointCount, i => pointList[i]); } #endregion } #endregion #region IndexPolygon2dExtensions public static partial class IndexPolygon2dExtensions { #region Conversions public static Polygon2d ToPolygon2d(this IndexPolygon2d polygon) { return new Polygon2d(polygon.GetPointArray()); } #endregion #region Geometric Properties /// /// The vertex centroid is the average of the vertex coordinates. /// public static V2d ComputeVertexCentroid(this IndexPolygon2d polygon) { var sum = V2d.Zero; int pc = polygon.PointCount; for (int i = 0; i < pc; i++) sum += polygon[i]; double scale = 1 / (double)pc; return sum * scale; } public static double ComputePerimeter(this IndexPolygon2d polygon) { var pc = polygon.PointCount; var p0 = polygon[pc - 1]; double r = 0; for (int i = 0; i < pc; i++) { var p1 = polygon[i]; r += Vec.Distance(p0, p1); p0 = p1; } return r; } #endregion } #endregion #region Line2d [StructLayout(LayoutKind.Sequential)] public partial struct Line2d : IEquatable, IValidity, IPolygon, IBoundingBox2d { public V2d P0, P1; #region Constructors /// /// Creates line from 2 points. /// public Line2d(V2d p0, V2d p1) { P0 = p0; P1 = p1; } /// /// Creates line from first 2 points in the sequence. /// public Line2d(IEnumerable points) { var pa = points.TakeToArray(2); P0 = pa[0]; P1 = pa[1]; } #endregion #region Properties public readonly bool IsValid { get { return true; } } public readonly bool IsInvalid { get { return false; } } public readonly int PointCount { get { return 2; } } public readonly IEnumerable Points { get { yield return P0; yield return P1; } } public readonly Line2d Reversed { get { return new Line2d(P1, P0); } } #endregion #region Indexer public V2d this[int index] { readonly get { switch (index) { case 0: return P0; case 1: return P1; default: throw new IndexOutOfRangeException(); } } set { switch (index) { case 0: P0 = value; return; case 1: P1 = value; return; default: throw new IndexOutOfRangeException(); } } } #endregion #region Transformations public readonly Line2d Copy(Func point_copyFun) { return new Line2d(point_copyFun(P0), point_copyFun(P1)); } public readonly Line3d ToLine3d(Func point_copyFun) { return new Line3d(point_copyFun(P0), point_copyFun(P1)); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Line2d a, Line2d b) => (a.P0 == b.P0) && (a.P1 == b.P1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Line2d a, Line2d b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(P0, P1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Line2d other) => P0.Equals(other.P0) && P1.Equals(other.P1); public override readonly bool Equals(object other) => (other is Line2d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", P0, P1); } public static Line2d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Line2d(V2d.Parse(x[0]), V2d.Parse(x[1])); } #endregion #region IBoundingBox2d Members public readonly Box2d BoundingBox2d { get { return new Box2d(P0, P1).Repair(); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Line2d a, Line2d b, double tolerance) => ApproximateEquals(a.P0, b.P0, tolerance) && ApproximateEquals(a.P1, b.P1, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Line2d a, Line2d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Line2dExtensions public static partial class Line2dExtensions { #region Geometric Transformations /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Line2d polygon, double scale) { polygon.P0 *= scale; polygon.P1 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d Scaled(this Line2d polygon, double scale) { var result = new Line2d(polygon.P0, polygon.P1); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Line2d polygon, V2d center, double scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d Scaled(this Line2d polygon, V2d center, double scale) { var result = new Line2d(polygon.P0, polygon.P1); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Line2d polygon, double scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d ScaledAboutCentroid(this Line2d polygon, double scale) { var result = new Line2d(polygon.P0, polygon.P1); result.ScaleAboutCentroid(scale); return result; } /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Line2d polygon, V2d scale) { polygon.P0 *= scale; polygon.P1 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d Scaled(this Line2d polygon, V2d scale) { var result = new Line2d(polygon.P0, polygon.P1); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Line2d polygon, V2d center, V2d scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d Scaled(this Line2d polygon, V2d center, V2d scale) { var result = new Line2d(polygon.P0, polygon.P1); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Line2d polygon, V2d scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d ScaledAboutCentroid(this Line2d polygon, V2d scale) { var result = new Line2d(polygon.P0, polygon.P1); result.ScaleAboutCentroid(scale); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line2d polygon, M33d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d Transformed(this Line2d polygon, M33d t) { var result = new Line2d(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line2d polygon, Euclidean2d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d Transformed(this Line2d polygon, Euclidean2d t) { var result = new Line2d(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line2d polygon, Euclidean2d t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d InvTransformed(this Line2d polygon, Euclidean2d t) { var result = new Line2d(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line2d polygon, Similarity2d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d Transformed(this Line2d polygon, Similarity2d t) { var result = new Line2d(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line2d polygon, Similarity2d t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d InvTransformed(this Line2d polygon, Similarity2d t) { var result = new Line2d(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line2d polygon, Affine2d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d Transformed(this Line2d polygon, Affine2d t) { var result = new Line2d(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line2d polygon, Shift2d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d Transformed(this Line2d polygon, Shift2d t) { var result = new Line2d(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line2d polygon, Shift2d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d InvTransformed(this Line2d polygon, Shift2d t) { var result = new Line2d(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line2d polygon, Rot2d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d Transformed(this Line2d polygon, Rot2d t) { var result = new Line2d(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line2d polygon, Rot2d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d InvTransformed(this Line2d polygon, Rot2d t) { var result = new Line2d(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line2d polygon, Scale2d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d Transformed(this Line2d polygon, Scale2d t) { var result = new Line2d(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line2d polygon, Scale2d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d InvTransformed(this Line2d polygon, Scale2d t) { var result = new Line2d(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line2d polygon, M22d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line2d Transformed(this Line2d polygon, M22d t) { var result = new Line2d(polygon.P0, polygon.P1); result.Transform(t); return result; } #endregion public static V2d[] GetPointArray(this Line2d line) { var pa = new V2d[2]; pa[0] = line.P0; pa[1] = line.P1; return pa; } public static V2d ComputeCentroid(this Line2d line) { return 0.5 * (line.P0 + line.P1); } } #endregion #region Triangle2d [StructLayout(LayoutKind.Sequential)] public partial struct Triangle2d : IEquatable, IValidity, IPolygon, IBoundingBox2d { public V2d P0, P1, P2; #region Constructors /// /// Creates triangle from 3 points. /// public Triangle2d(V2d p0, V2d p1, V2d p2) { P0 = p0; P1 = p1; P2 = p2; } /// /// Creates triangle from first 3 points in the sequence. /// public Triangle2d(IEnumerable points) { var pa = points.TakeToArray(3); P0 = pa[0]; P1 = pa[1]; P2 = pa[2]; } #endregion #region Properties public readonly bool IsValid { get { return true; } } public readonly bool IsInvalid { get { return false; } } /// /// Edge P1 - P0 /// public readonly V2d Edge01 { get { return P1 - P0; } } /// /// Edge P2 - P0 /// public readonly V2d Edge02 { get { return P2 - P0; } } /// /// Edge P2 - P1 /// public readonly V2d Edge12 { get { return P2 - P1; } } /// /// Edge P0 - P1 /// public readonly V2d Edge10 { get { return P0 - P1; } } /// /// Edge P0 - P2 /// public readonly V2d Edge20 { get { return P0 - P2; } } /// /// Edge P1 - P2 /// public readonly V2d Edge21 { get { return P1 - P2; } } public readonly IEnumerable Edges { get { yield return P1 - P0; yield return P2 - P1; yield return P0 - P2; } } public readonly V2d[] EdgeArray { get { var a = new V2d[3]; a[0] = P1 - P0; a[1] = P2 - P1; a[2] = P0 - P2; return a; } } public readonly IEnumerable EdgeLines { get { yield return new Line2d(P0, P1); yield return new Line2d(P1, P2); yield return new Line2d(P2, P0); } } public readonly Line2d[] EdgeLineArray { get { var a = new Line2d[3]; a[0] = new Line2d(P0, P1); a[1] = new Line2d(P1, P2); a[2] = new Line2d(P2, P0); return a; } } public readonly Line2d GetEdgeLine(int index) { switch (index) { case 0: return new Line2d(P0, P1); case 1: return new Line2d(P1, P2); case 2: return new Line2d(P2, P0); } throw new InvalidOperationException(); } public readonly V2d GetEdge(int index) { switch (index) { case 0: return P1 - P0; case 1: return P2 - P1; case 2: return P0 - P2; } throw new InvalidOperationException(); } public readonly Line2d Line01 { get { return new Line2d(P0, P1); } } public readonly Line2d Line02 { get { return new Line2d(P0, P2); } } public readonly Line2d Line12 { get { return new Line2d(P1, P2); } } public readonly Line2d Line10 { get { return new Line2d(P1, P0); } } public readonly Line2d Line20 { get { return new Line2d(P2, P0); } } public readonly Line2d Line21 { get { return new Line2d(P2, P1); } } public readonly int PointCount { get { return 3; } } public readonly IEnumerable Points { get { yield return P0; yield return P1; yield return P2; } } public readonly Triangle2d Reversed { get { return new Triangle2d(P2, P1, P0); } } #endregion #region Indexer public V2d this[int index] { readonly get { switch (index) { case 0: return P0; case 1: return P1; case 2: return P2; default: throw new IndexOutOfRangeException(); } } set { switch (index) { case 0: P0 = value; return; case 1: P1 = value; return; case 2: P2 = value; return; default: throw new IndexOutOfRangeException(); } } } #endregion #region Transformations public readonly Triangle2d Copy(Func point_copyFun) { return new Triangle2d(point_copyFun(P0), point_copyFun(P1), point_copyFun(P2)); } public readonly Triangle3d ToTriangle3d(Func point_copyFun) { return new Triangle3d(point_copyFun(P0), point_copyFun(P1), point_copyFun(P2)); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Triangle2d a, Triangle2d b) => (a.P0 == b.P0) && (a.P1 == b.P1) && (a.P2 == b.P2); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Triangle2d a, Triangle2d b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(P0, P1, P2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Triangle2d other) => P0.Equals(other.P0) && P1.Equals(other.P1) && P2.Equals(other.P2); public override readonly bool Equals(object other) => (other is Triangle2d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", P0, P1, P2); } public static Triangle2d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Triangle2d(V2d.Parse(x[0]), V2d.Parse(x[1]), V2d.Parse(x[2])); } #endregion #region IBoundingBox2d Members public readonly Box2d BoundingBox2d { get { return new Box2d(P0, P1, P2); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Triangle2d a, Triangle2d b, double tolerance) => ApproximateEquals(a.P0, b.P0, tolerance) && ApproximateEquals(a.P1, b.P1, tolerance) && ApproximateEquals(a.P2, b.P2, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Triangle2d a, Triangle2d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Triangle2dExtensions public static partial class Triangle2dExtensions { #region Geometric Transformations /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Triangle2d polygon, double scale) { polygon.P0 *= scale; polygon.P1 *= scale; polygon.P2 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d Scaled(this Triangle2d polygon, double scale) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Triangle2d polygon, V2d center, double scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; polygon.P2 = center + (polygon.P2 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d Scaled(this Triangle2d polygon, V2d center, double scale) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Triangle2d polygon, double scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d ScaledAboutCentroid(this Triangle2d polygon, double scale) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.ScaleAboutCentroid(scale); return result; } /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Triangle2d polygon, V2d scale) { polygon.P0 *= scale; polygon.P1 *= scale; polygon.P2 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d Scaled(this Triangle2d polygon, V2d scale) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Triangle2d polygon, V2d center, V2d scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; polygon.P2 = center + (polygon.P2 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d Scaled(this Triangle2d polygon, V2d center, V2d scale) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Triangle2d polygon, V2d scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d ScaledAboutCentroid(this Triangle2d polygon, V2d scale) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.ScaleAboutCentroid(scale); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle2d polygon, M33d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d Transformed(this Triangle2d polygon, M33d t) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle2d polygon, Euclidean2d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d Transformed(this Triangle2d polygon, Euclidean2d t) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle2d polygon, Euclidean2d t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); polygon.P2 = t.InvTransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d InvTransformed(this Triangle2d polygon, Euclidean2d t) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle2d polygon, Similarity2d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d Transformed(this Triangle2d polygon, Similarity2d t) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle2d polygon, Similarity2d t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); polygon.P2 = t.InvTransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d InvTransformed(this Triangle2d polygon, Similarity2d t) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle2d polygon, Affine2d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d Transformed(this Triangle2d polygon, Affine2d t) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle2d polygon, Shift2d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d Transformed(this Triangle2d polygon, Shift2d t) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle2d polygon, Shift2d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d InvTransformed(this Triangle2d polygon, Shift2d t) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle2d polygon, Rot2d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d Transformed(this Triangle2d polygon, Rot2d t) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle2d polygon, Rot2d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d InvTransformed(this Triangle2d polygon, Rot2d t) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle2d polygon, Scale2d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d Transformed(this Triangle2d polygon, Scale2d t) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle2d polygon, Scale2d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d InvTransformed(this Triangle2d polygon, Scale2d t) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle2d polygon, M22d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle2d Transformed(this Triangle2d polygon, M22d t) { var result = new Triangle2d(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } #endregion public static V2d[] GetPointArray(this Triangle2d triangle) { var pa = new V2d[3]; pa[0] = triangle.P0; pa[1] = triangle.P1; pa[2] = triangle.P2; return pa; } public static V2d ComputeCentroid(this Triangle2d triangle) { return Constant.OneThird * (triangle.P0 + triangle.P1 + triangle.P2); } } #endregion #region Quad2d [StructLayout(LayoutKind.Sequential)] public partial struct Quad2d : IEquatable, IValidity, IPolygon, IBoundingBox2d { public V2d P0, P1, P2, P3; #region Constructors /// /// Creates quad from 4 points. /// public Quad2d(V2d p0, V2d p1, V2d p2, V2d p3) { P0 = p0; P1 = p1; P2 = p2; P3 = p3; } /// /// Creates quad from first 4 points in the sequence. /// public Quad2d(IEnumerable points) { var pa = points.TakeToArray(4); P0 = pa[0]; P1 = pa[1]; P2 = pa[2]; P3 = pa[3]; } /// /// Creates quad from point and two vectors representing edges. /// public Quad2d(V2d p0, V2d edge01, V2d edge03) { P0 = p0; P1 = p0 + edge01; P2 = P1 + edge03; P3 = p0 + edge03; } #endregion #region Properties public readonly bool IsValid { get { return true; } } public readonly bool IsInvalid { get { return false; } } /// /// Edge P1 - P0 /// public readonly V2d Edge01 { get { return P1 - P0; } } /// /// Edge P3 - P0 /// public readonly V2d Edge03 { get { return P3 - P0; } } /// /// Edge P2 - P1 /// public readonly V2d Edge12 { get { return P2 - P1; } } /// /// Edge P0 - P1 /// public readonly V2d Edge10 { get { return P0 - P1; } } /// /// Edge P3 - P2 /// public readonly V2d Edge23 { get { return P3 - P2; } } /// /// Edge P1 - P2 /// public readonly V2d Edge21 { get { return P1 - P2; } } /// /// Edge P0 - P3 /// public readonly V2d Edge30 { get { return P0 - P3; } } /// /// Edge P2 - P3 /// public readonly V2d Edge32 { get { return P2 - P3; } } public readonly IEnumerable Edges { get { yield return P1 - P0; yield return P2 - P1; yield return P3 - P2; yield return P0 - P3; } } public readonly V2d[] EdgeArray { get { var a = new V2d[4]; a[0] = P1 - P0; a[1] = P2 - P1; a[2] = P3 - P2; a[3] = P0 - P3; return a; } } public readonly IEnumerable EdgeLines { get { yield return new Line2d(P0, P1); yield return new Line2d(P1, P2); yield return new Line2d(P2, P3); yield return new Line2d(P3, P0); } } public readonly Line2d[] EdgeLineArray { get { var a = new Line2d[4]; a[0] = new Line2d(P0, P1); a[1] = new Line2d(P1, P2); a[2] = new Line2d(P2, P3); a[3] = new Line2d(P3, P0); return a; } } public readonly Line2d GetEdgeLine(int index) { switch (index) { case 0: return new Line2d(P0, P1); case 1: return new Line2d(P1, P2); case 2: return new Line2d(P2, P3); case 3: return new Line2d(P3, P0); } throw new InvalidOperationException(); } public readonly V2d GetEdge(int index) { switch (index) { case 0: return P1 - P0; case 1: return P2 - P1; case 2: return P3 - P2; case 3: return P0 - P3; } throw new InvalidOperationException(); } public readonly Line2d Line01 { get { return new Line2d(P0, P1); } } public readonly Line2d Line03 { get { return new Line2d(P0, P3); } } public readonly Line2d Line12 { get { return new Line2d(P1, P2); } } public readonly Line2d Line10 { get { return new Line2d(P1, P0); } } public readonly Line2d Line23 { get { return new Line2d(P2, P3); } } public readonly Line2d Line21 { get { return new Line2d(P2, P1); } } public readonly Line2d Line30 { get { return new Line2d(P3, P0); } } public readonly Line2d Line32 { get { return new Line2d(P3, P2); } } public readonly int PointCount { get { return 4; } } public readonly IEnumerable Points { get { yield return P0; yield return P1; yield return P2; yield return P3; } } public readonly Quad2d Reversed { get { return new Quad2d(P3, P2, P1, P0); } } #endregion #region Indexer public V2d this[int index] { readonly get { switch (index) { case 0: return P0; case 1: return P1; case 2: return P2; case 3: return P3; default: throw new IndexOutOfRangeException(); } } set { switch (index) { case 0: P0 = value; return; case 1: P1 = value; return; case 2: P2 = value; return; case 3: P3 = value; return; default: throw new IndexOutOfRangeException(); } } } #endregion #region Transformations public readonly Quad2d Copy(Func point_copyFun) { return new Quad2d(point_copyFun(P0), point_copyFun(P1), point_copyFun(P2), point_copyFun(P3)); } public readonly Quad3d ToQuad3d(Func point_copyFun) { return new Quad3d(point_copyFun(P0), point_copyFun(P1), point_copyFun(P2), point_copyFun(P3)); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Quad2d a, Quad2d b) => (a.P0 == b.P0) && (a.P1 == b.P1) && (a.P2 == b.P2) && (a.P3 == b.P3); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Quad2d a, Quad2d b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(P0, P1, P2, P3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Quad2d other) => P0.Equals(other.P0) && P1.Equals(other.P1) && P2.Equals(other.P2) && P3.Equals(other.P3); public override readonly bool Equals(object other) => (other is Quad2d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}, {3}]", P0, P1, P2, P3); } public static Quad2d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Quad2d(V2d.Parse(x[0]), V2d.Parse(x[1]), V2d.Parse(x[2]), V2d.Parse(x[3])); } #endregion #region IBoundingBox2d Members public readonly Box2d BoundingBox2d { get { return new Box2d(P0, P1, P2, P3); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Quad2d a, Quad2d b, double tolerance) => ApproximateEquals(a.P0, b.P0, tolerance) && ApproximateEquals(a.P1, b.P1, tolerance) && ApproximateEquals(a.P2, b.P2, tolerance) && ApproximateEquals(a.P3, b.P3, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Quad2d a, Quad2d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Quad2dExtensions public static partial class Quad2dExtensions { #region Geometric Transformations /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Quad2d polygon, double scale) { polygon.P0 *= scale; polygon.P1 *= scale; polygon.P2 *= scale; polygon.P3 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d Scaled(this Quad2d polygon, double scale) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Quad2d polygon, V2d center, double scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; polygon.P2 = center + (polygon.P2 - center) * scale; polygon.P3 = center + (polygon.P3 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d Scaled(this Quad2d polygon, V2d center, double scale) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Quad2d polygon, double scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d ScaledAboutCentroid(this Quad2d polygon, double scale) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.ScaleAboutCentroid(scale); return result; } /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Quad2d polygon, V2d scale) { polygon.P0 *= scale; polygon.P1 *= scale; polygon.P2 *= scale; polygon.P3 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d Scaled(this Quad2d polygon, V2d scale) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Quad2d polygon, V2d center, V2d scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; polygon.P2 = center + (polygon.P2 - center) * scale; polygon.P3 = center + (polygon.P3 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d Scaled(this Quad2d polygon, V2d center, V2d scale) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Quad2d polygon, V2d scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d ScaledAboutCentroid(this Quad2d polygon, V2d scale) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.ScaleAboutCentroid(scale); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad2d polygon, M33d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); polygon.P3 = t.TransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d Transformed(this Quad2d polygon, M33d t) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad2d polygon, Euclidean2d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); polygon.P3 = t.TransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d Transformed(this Quad2d polygon, Euclidean2d t) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad2d polygon, Euclidean2d t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); polygon.P2 = t.InvTransformPos(polygon.P2); polygon.P3 = t.InvTransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d InvTransformed(this Quad2d polygon, Euclidean2d t) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad2d polygon, Similarity2d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); polygon.P3 = t.TransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d Transformed(this Quad2d polygon, Similarity2d t) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad2d polygon, Similarity2d t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); polygon.P2 = t.InvTransformPos(polygon.P2); polygon.P3 = t.InvTransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d InvTransformed(this Quad2d polygon, Similarity2d t) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad2d polygon, Affine2d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); polygon.P3 = t.TransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d Transformed(this Quad2d polygon, Affine2d t) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad2d polygon, Shift2d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); polygon.P3 = t.Transform(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d Transformed(this Quad2d polygon, Shift2d t) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad2d polygon, Shift2d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); polygon.P3 = t.InvTransform(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d InvTransformed(this Quad2d polygon, Shift2d t) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad2d polygon, Rot2d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); polygon.P3 = t.Transform(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d Transformed(this Quad2d polygon, Rot2d t) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad2d polygon, Rot2d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); polygon.P3 = t.InvTransform(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d InvTransformed(this Quad2d polygon, Rot2d t) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad2d polygon, Scale2d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); polygon.P3 = t.Transform(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d Transformed(this Quad2d polygon, Scale2d t) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad2d polygon, Scale2d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); polygon.P3 = t.InvTransform(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d InvTransformed(this Quad2d polygon, Scale2d t) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad2d polygon, M22d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); polygon.P3 = t.Transform(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad2d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad2d Transformed(this Quad2d polygon, M22d t) { var result = new Quad2d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } #endregion public static V2d[] GetPointArray(this Quad2d quad) { var pa = new V2d[4]; pa[0] = quad.P0; pa[1] = quad.P1; pa[2] = quad.P2; pa[3] = quad.P3; return pa; } public static V2d ComputeCentroid(this Quad2d quad) { return 0.25 * (quad.P0 + quad.P1 + quad.P2 + quad.P3); } } #endregion #region Polygon3d /// /// A polygon internally represented by an array of points. Implemented /// as a structure, the validity of the polygon can be checked via its /// PointCount, which must be bigger than 0 for a polygon to hold any /// points, and bigger than 2 for a polygon to be geometrically valid. /// [StructLayout(LayoutKind.Sequential)] public partial struct Polygon3d : IEquatable, IValidity, IPolygon, IBoundingBox3d { internal int m_pointCount; internal V3d[] m_pointArray; #region Constructors /// /// Creates a polygon from given points. /// public Polygon3d(V3d[] pointArray, int pointCount) { if (pointArray != null) { if (pointCount <= pointArray.Length) { m_pointCount = pointCount; m_pointArray = pointArray; } else throw new ArgumentException( "point count must be smaller or equal array length"); } else { m_pointCount = 0; m_pointArray = null; } } /// /// Creates a polygon from given points. /// public Polygon3d(params V3d[] pointArray) { m_pointCount = pointArray != null ? pointArray.Length : 0; m_pointArray = pointArray; } /// /// Creates a polygon from given points. /// public Polygon3d(V3d[] pointArray, int startIndex, int count) { if (startIndex < 0 || startIndex >= pointArray.Length - 1) throw new ArgumentException(); if (count <= 0 || startIndex + count >= pointArray.Length) throw new ArgumentException(); m_pointCount = count; m_pointArray = new V3d[count]; for (int i = 0; i < count; i++) m_pointArray[i] = pointArray[startIndex + i]; } /// /// Creates a polygon from point count and point creator function. /// public Polygon3d(int pointCount, Func index_pointCreator) : this(new V3d[pointCount].SetByIndex(index_pointCreator)) { } /// /// Creates a polygon from a sequence of points. /// public Polygon3d(IEnumerable points) : this(points.ToArray()) { } /// /// Creates a polygon from the points of a pointArray that /// are selected by an index array. /// public Polygon3d(int[] indexArray, V3d[] pointArray) : this(indexArray.Map(i => pointArray[i])) { } /// /// Creates a polygon from a triangle. /// public Polygon3d(Triangle3d triangle) : this(triangle.GetPointArray()) { } /// /// Creates a polygon from a quad. /// public Polygon3d(Quad3d quad) : this(quad.GetPointArray()) { } /// /// Copy constructor. /// Performs deep copy of original. /// public Polygon3d(Polygon3d original) : this(original.GetPointArray()) { } #endregion #region Constants public static readonly Polygon3d Invalid = new Polygon3d(null, 0); #endregion #region Properties public readonly bool IsValid => m_pointArray != null; public readonly bool IsInvalid => m_pointArray == null; /// /// The number of points in the polygon. If this is 0, the polygon /// is invalid. /// public readonly int PointCount => m_pointCount; /// /// Enumerates points. /// public readonly IEnumerable Points { get { for (int pi = 0; pi < m_pointCount; pi++) yield return m_pointArray[pi]; } } #endregion #region Conversions /// /// Returns a copy of the polygons point array. /// public readonly V3d[] GetPointArray() { var pc = m_pointCount; var pa = new V3d[pc]; for (int pi = 0; pi < pc; pi++) pa[pi] = m_pointArray[pi]; return pa; } /// /// [P0, P1, P2] -> [P0, P1, P2, P0]. /// public readonly V3d[] GetPointArrayWithRepeatedFirstPoint() { var pc = m_pointCount; var pa = new V3d[pc + 1]; for (int pi = 0; pi < pc; pi++) pa[pi] = m_pointArray[pi]; pa[pc] = pa[0]; return pa; } /// /// Returns a transformed copy of the polygons point array. /// public readonly T[] GetPointArray(Func point_copyFun) { var pc = m_pointCount; var pa = new T[pc]; for (int pi = 0; pi < pc; pi++) pa[pi] = point_copyFun(m_pointArray[pi]); return pa; } /// /// Returns a transformed copy of the polygons point array. /// public readonly T[] GetPointArray(Func point_index_copyFun) { var pc = m_pointCount; var pa = new T[pc]; for (int pi = 0; pi < pc; pi++) pa[pi] = point_index_copyFun(m_pointArray[pi], pi); return pa; } #endregion #region Indexing /// /// Gets the index-th point of this polygon. /// public readonly V3d this[int index] { get { return m_pointArray[index]; } set { m_pointArray[index] = value; } } #endregion #region Edges and Lines /// /// Index-th edge as vector (edgeEndPos - edgeBeginPos). /// public readonly V3d Edge(int index) { var p0 = m_pointArray[index++]; var p1 = m_pointArray[index < m_pointCount ? index : 0]; return p1 - p0; } /// /// Edges as vectors (edgeEndPos - edgeBeginPos). /// public readonly IEnumerable Edges { get { var pc = m_pointCount; var p = m_pointArray[0]; var p0 = p; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; yield return p1 - p0; p0 = p1; } yield return p - p0; } } /// /// Index-th edge as line segment (edgeBeginPos, edgeEndPos). /// public readonly Line3d EdgeLine(int index) { var p0 = m_pointArray[index++]; var p1 = m_pointArray[index < m_pointCount ? index : 0]; return new Line3d(p0, p1); } /// /// Edges as line segments (edgeBeginPos, edgeEndPos). /// public readonly IEnumerable EdgeLines { get { var pc = m_pointCount; if (pc < 1) yield break; var p0 = m_pointArray[0]; var p = p0; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; yield return new Line3d(p0, p1); p0 = p1; } yield return new Line3d(p0, p); } } /// /// Edges as vectors (edgeEndPos - edgeBeginPos). /// public readonly V3d[] GetEdgeArray() { var pc = m_pointCount; if (pc < 2) return Array.Empty(); var edgeArray = new V3d[pc]; var p = m_pointArray[0]; var p0 = p; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; edgeArray[pi - 1] = p1 - p0; p0 = p1; } edgeArray[pc - 1] = p - p0; return edgeArray; } /// /// Edges as line segments (edgeBeginPos, edgeEndPos). /// public readonly Line3d[] GetEdgeLineArray() { var pc = PointCount; if (pc < 2) return Array.Empty(); var ela = new Line3d[pc]; var p = m_pointArray[0]; var p0 = p; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; ela[pi - 1] = new Line3d(p0, p1); p0 = p1; } ela[pc - 1] = new Line3d(p0, p); return ela; } #endregion #region Transformations /// /// Returns copy of polygon. Same as Map(p => p). /// public readonly Polygon3d Copy() { return new Polygon3d(m_pointArray.Copy()); } /// /// Returns transformed copy of this polygon. /// public readonly Polygon3d Map(Func point_fun) { var pc = m_pointCount; V3d[] opa = m_pointArray, npa = new V3d[pc]; for (int pi = 0; pi < pc; pi++) npa[pi] = point_fun(opa[pi]); return new Polygon3d(npa, pc); } /// /// Gets copy with reversed order of vertices. /// public readonly Polygon3d Reversed { get { var pc = m_pointCount; V3d[] opa = m_pointArray, npa = new V3d[pc]; for (int pi = 0, pj = pc - 1; pi < pc; pi++, pj--) npa[pi] = opa[pj]; return new Polygon3d(npa, pc); } } /// /// Reverses order of vertices in-place. /// public readonly void Reverse() { var pa = m_pointArray; for (int pi = 0, pj = m_pointCount - 1; pi < pj; pi++, pj--) { var t = pa[pi]; pa[pi] = pa[pj]; pa[pj] = t; } } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Polygon3d a, Polygon3d b) { if (a.m_pointCount != b.m_pointCount) return false; for (int pi = 0; pi < a.m_pointCount; pi++) if (a.m_pointArray[pi] != b.m_pointArray[pi]) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Polygon3d a, Polygon3d b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return m_pointArray.GetCombinedHashCode(m_pointCount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Polygon3d other) { if (m_pointCount != other.m_pointCount) return false; for (int pi = 0; pi < m_pointCount; pi++) if (!m_pointArray[pi].Equals(other.m_pointArray[pi])) return false; return true; } public override readonly bool Equals(object other) => (other is Polygon3d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}]", Points.Select(x => x.ToString()).Join(", ") ); } public static Polygon3d Parse(string s) { var va = s.NestedBracketSplitLevelOne().ToArray(); return new Polygon3d(va.Select(x => V3d.Parse(x))); } #endregion #region IBoundingBox3d Members /// /// Bounding box of polygon. /// public readonly Box3d BoundingBox3d { get { return new Box3d(m_pointArray, 0, m_pointCount); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Polygon3d a, Polygon3d b, double tolerance) { if (a.m_pointCount != b.m_pointCount) return false; for (int pi = 0; pi < a.m_pointCount; pi++) if (!ApproximateEquals(a.m_pointArray[pi], b.m_pointArray[pi], tolerance)) return false; return true; } /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Polygon3d a, Polygon3d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Polygon3dExtensions public static partial class Polygon3dExtensions { #region Geometric Properties /// /// The vertex centroid is the average of the vertex coordinates. /// public static V3d ComputeVertexCentroid(this Polygon3d polygon) { var sum = V3d.Zero; int pc = polygon.PointCount; for (int i = 0; i < pc; i++) sum += polygon[i]; double scale = 1 / (double)pc; return sum * scale; } public static double ComputePerimeter(this Polygon3d polygon) { var pc = polygon.PointCount; var p0 = polygon[pc - 1]; double r = 0; for (int i = 0; i < pc; i++) { var p1 = polygon[i]; r += Vec.Distance(p0, p1); p0 = p1; } return r; } #endregion #region Geometric Transformations /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. public static void Scale(this ref Polygon3d polygon, double scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d Scaled(this Polygon3d polygon, double scale) { var result = new Polygon3d(polygon); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. public static void Scale(this ref Polygon3d polygon, V3d center, double scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = center + (polygon.m_pointArray[pi] - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d Scaled(this Polygon3d polygon, V3d center, double scale) { var result = new Polygon3d(polygon); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutVertexCentroid(this ref Polygon3d polygon, double scale) { var center = polygon.ComputeVertexCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d ScaledAboutVertexCentroid(this Polygon3d polygon, double scale) { var result = new Polygon3d(polygon); result.ScaleAboutVertexCentroid(scale); return result; } /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. public static void Scale(this ref Polygon3d polygon, V3d scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d Scaled(this Polygon3d polygon, V3d scale) { var result = new Polygon3d(polygon); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. public static void Scale(this ref Polygon3d polygon, V3d center, V3d scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = center + (polygon.m_pointArray[pi] - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d Scaled(this Polygon3d polygon, V3d center, V3d scale) { var result = new Polygon3d(polygon); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutVertexCentroid(this ref Polygon3d polygon, V3d scale) { var center = polygon.ComputeVertexCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d ScaledAboutVertexCentroid(this Polygon3d polygon, V3d scale) { var result = new Polygon3d(polygon); result.ScaleAboutVertexCentroid(scale); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon3d polygon, M44d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.TransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d Transformed(this Polygon3d polygon, M44d t) { var result = new Polygon3d(polygon); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon3d polygon, Euclidean3d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.TransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d Transformed(this Polygon3d polygon, Euclidean3d t) { var result = new Polygon3d(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon3d polygon, Euclidean3d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d InvTransformed(this Polygon3d polygon, Euclidean3d t) { var result = new Polygon3d(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon3d polygon, Similarity3d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.TransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d Transformed(this Polygon3d polygon, Similarity3d t) { var result = new Polygon3d(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon3d polygon, Similarity3d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d InvTransformed(this Polygon3d polygon, Similarity3d t) { var result = new Polygon3d(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon3d polygon, Affine3d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.TransformPos(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d Transformed(this Polygon3d polygon, Affine3d t) { var result = new Polygon3d(polygon); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon3d polygon, Shift3d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Transform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d Transformed(this Polygon3d polygon, Shift3d t) { var result = new Polygon3d(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon3d polygon, Shift3d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d InvTransformed(this Polygon3d polygon, Shift3d t) { var result = new Polygon3d(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon3d polygon, Rot3d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Transform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d Transformed(this Polygon3d polygon, Rot3d t) { var result = new Polygon3d(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon3d polygon, Rot3d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d InvTransformed(this Polygon3d polygon, Rot3d t) { var result = new Polygon3d(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon3d polygon, Scale3d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Transform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d Transformed(this Polygon3d polygon, Scale3d t) { var result = new Polygon3d(polygon); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref Polygon3d polygon, Scale3d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.InvTransform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Polygon3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d InvTransformed(this Polygon3d polygon, Scale3d t) { var result = new Polygon3d(polygon); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref Polygon3d polygon, M33d t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Transform(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Polygon3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon3d Transformed(this Polygon3d polygon, M33d t) { var result = new Polygon3d(polygon); result.Transform(t); return result; } public static Polygon3d WithoutMultiplePoints(this Polygon3d polygon, double eps = 1e-8) { eps *= eps; var opc = polygon.PointCount; var pa = new V3d[opc]; var pc = 0; pa[0] = polygon[0]; for (int pi = 1; pi < opc; pi++) if (Vec.DistanceSquared(pa[pc], polygon[pi]) > eps) pa[++pc] = polygon[pi]; if (Vec.DistanceSquared(pa[pc], polygon[0]) > eps) ++pc; return new Polygon3d(pa, pc); } #endregion #region Clipping /// /// Clip the supplied polygon at the supplied plane. The method should /// work with all non-selfintersecting polygons. Returns all parts of /// the polygon that are at the positive side of the plane. /// public static Polygon3d ConvexClipped( this Polygon3d polygon, Plane3d plane, double eps = 1e-8) { var opc = polygon.PointCount; V3d[] pa = new V3d[opc + 1]; var pc = 0; var pf = polygon[0]; var hf = plane.Height(pf); bool hfp = hf > eps, hfn = hf < -eps; if (hf >= -eps) pa[pc++] = pf; var p0 = pf; var h0 = hf; var h0p = hfp; var h0n = hfn; for (int vi = 1; vi < opc; vi++) { var p1 = polygon[vi]; var h1 = plane.Height(p1); bool h1p = h1 > eps, h1n = h1 < -eps; if (h0p && h1n || h0n && h1p) pa[pc++] = p0 + (p1 - p0) * (h0 / (h0 - h1)); if (h1 >= -eps) pa[pc++] = p1; p0 = p1; h0 = h1; h0p = h1p; h0n = h1n; } if (h0p && hfn || h0n && hfp) pa[pc++] = p0 + (pf - p0) * (h0 / (h0 - hf)); return new Polygon3d(pa, pc); } /// /// Returns the convex polygon clipped by the set of planes (defined /// as Plane3ds), i.e. all parts of the polygon that are at the positive /// side of the planes. /// public static Polygon3d ConvexClipped( this Polygon3d polygon, Plane3d[] planes, double eps = 1e-8) { foreach (var c in planes) { polygon = polygon.ConvexClipped(c, eps); if (polygon.PointCount == 0) break; } return polygon; } /// /// Returns the polygon clipped by the hull, i.e. all parts of the /// polygon that are at the positive side of the hull planes. /// public static Polygon3d ConvexClipped( this Polygon3d polygon, Hull3d hull, double eps = 1e-8) { return polygon.ConvexClipped(hull.PlaneArray, eps); } /// /// TODO summary. /// public static Polygon3d ConvexClipped( this Polygon3d polygon, Box3d box, double eps = 1e-8) { var planes = new[] { new Plane3d(V3d.XAxis, box.Min), new Plane3d(-V3d.XAxis, box.Max), new Plane3d(V3d.YAxis, box.Min), new Plane3d(-V3d.YAxis, box.Max), new Plane3d(V3d.ZAxis, box.Min), new Plane3d(-V3d.ZAxis, box.Max), }; return polygon.ConvexClipped(planes); } #endregion } #endregion #region IndexPolygon3d [StructLayout(LayoutKind.Sequential)] public readonly partial struct IndexPolygon3d : IValidity, IPolygon { private readonly int m_pointCount; private readonly int m_firstIndex; private readonly int[] m_indexArray; private readonly V3d[] m_pointArray; #region Constructors public IndexPolygon3d(int[] indexArray, int firstIndex, int pointCount, V3d[] pointArray) { m_indexArray = indexArray; m_firstIndex = firstIndex; m_pointCount = pointCount; m_pointArray = pointArray; } public IndexPolygon3d(V3d[] pointArray, int firstIndex, int pointCount) : this(new int[pointCount].SetByIndex(i => firstIndex + i), 0, pointCount, pointArray) { } public IndexPolygon3d(V3d[] pointArray) : this(new int[pointArray.Length].SetByIndex(i => i), 0, pointArray.Length, pointArray) { } #endregion #region Constants public static readonly IndexPolygon3d Invalid = new IndexPolygon3d(null, 0, 0, null); #endregion #region Properties public bool IsValid { get { return m_indexArray != null && m_pointArray != null; } } public bool IsInvalid { get { return m_indexArray == null || m_pointArray == null; } } public int PointCount { get { return m_pointCount; } } public int FirstIndex { get { return m_firstIndex; } } /// /// The index array that contains the point indices of the /// index polygon at the index range [FirstIndex, FirstIndex + PointCount). /// NOTE: This is different from the array returned by GetIndexArray(). /// public int[] IndexArray { get { return m_indexArray; } } /// /// The point array that contains the points referenced by /// the index array. Note: This is different from the array /// returned by GetPointArray(). /// public V3d[] PointArray { get { return m_pointArray; } } public IEnumerable Points { get { for (int i = 0; i < m_pointCount; i++) yield return m_pointArray[m_indexArray[m_firstIndex + i]]; } } public IEnumerable Indices { get { for (int i = 0; i < m_pointCount; i++) yield return m_indexArray[m_firstIndex + i]; } } #endregion #region Indexing public V3d this[int index] { get { return m_pointArray[m_indexArray[m_firstIndex + index]]; } set { m_pointArray[m_indexArray[m_firstIndex + index]] = value; } } #endregion #region Conversions public void ForEachIndex(Action index_act) { var ia = m_indexArray; int fi = m_firstIndex; for (int i = 0; i < m_pointCount; i++) index_act(ia[fi + i]); } /// /// Returns a newly created array containing only the actual indices /// of the index polygon. NOTE: This is different from the /// IndexArray property! /// public int[] GetIndexArray() { return m_indexArray.Copy(m_firstIndex, m_pointCount); } /// /// Returns a newly created array containing only the actual points /// of the index polygon. NOTE: This is different from the /// PointArray property! /// public V3d[] GetPointArray() { var pa = m_pointArray; return m_indexArray.Map(m_firstIndex, m_pointCount, i => pa[i]); } public T[] GetPointArray(T[] pointArray) { return m_indexArray.Map(m_firstIndex, m_pointCount, i => pointArray[i]); } public T[] GetPointArray(List pointList) { return m_indexArray.Map(m_firstIndex, m_pointCount, i => pointList[i]); } #endregion } #endregion #region IndexPolygon3dExtensions public static partial class IndexPolygon3dExtensions { #region Conversions public static Polygon3d ToPolygon3d(this IndexPolygon3d polygon) { return new Polygon3d(polygon.GetPointArray()); } #endregion #region Geometric Properties /// /// The vertex centroid is the average of the vertex coordinates. /// public static V3d ComputeVertexCentroid(this IndexPolygon3d polygon) { var sum = V3d.Zero; int pc = polygon.PointCount; for (int i = 0; i < pc; i++) sum += polygon[i]; double scale = 1 / (double)pc; return sum * scale; } public static double ComputePerimeter(this IndexPolygon3d polygon) { var pc = polygon.PointCount; var p0 = polygon[pc - 1]; double r = 0; for (int i = 0; i < pc; i++) { var p1 = polygon[i]; r += Vec.Distance(p0, p1); p0 = p1; } return r; } #endregion } #endregion #region Line3d [StructLayout(LayoutKind.Sequential)] public partial struct Line3d : IEquatable, IValidity, IPolygon, IBoundingBox3d { public V3d P0, P1; #region Constructors /// /// Creates line from 2 points. /// public Line3d(V3d p0, V3d p1) { P0 = p0; P1 = p1; } /// /// Creates line from first 2 points in the sequence. /// public Line3d(IEnumerable points) { var pa = points.TakeToArray(2); P0 = pa[0]; P1 = pa[1]; } #endregion #region Properties public readonly bool IsValid { get { return true; } } public readonly bool IsInvalid { get { return false; } } public readonly int PointCount { get { return 2; } } public readonly IEnumerable Points { get { yield return P0; yield return P1; } } public readonly Line3d Reversed { get { return new Line3d(P1, P0); } } #endregion #region Indexer public V3d this[int index] { readonly get { switch (index) { case 0: return P0; case 1: return P1; default: throw new IndexOutOfRangeException(); } } set { switch (index) { case 0: P0 = value; return; case 1: P1 = value; return; default: throw new IndexOutOfRangeException(); } } } #endregion #region Transformations public readonly Line3d Copy(Func point_copyFun) { return new Line3d(point_copyFun(P0), point_copyFun(P1)); } public readonly Line2d ToLine2d(Func point_copyFun) { return new Line2d(point_copyFun(P0), point_copyFun(P1)); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Line3d a, Line3d b) => (a.P0 == b.P0) && (a.P1 == b.P1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Line3d a, Line3d b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(P0, P1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Line3d other) => P0.Equals(other.P0) && P1.Equals(other.P1); public override readonly bool Equals(object other) => (other is Line3d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", P0, P1); } public static Line3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Line3d(V3d.Parse(x[0]), V3d.Parse(x[1])); } #endregion #region IBoundingBox3d Members public readonly Box3d BoundingBox3d { get { return new Box3d(P0, P1).Repair(); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Line3d a, Line3d b, double tolerance) => ApproximateEquals(a.P0, b.P0, tolerance) && ApproximateEquals(a.P1, b.P1, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Line3d a, Line3d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Line3dExtensions public static partial class Line3dExtensions { #region Geometric Transformations /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Line3d polygon, double scale) { polygon.P0 *= scale; polygon.P1 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d Scaled(this Line3d polygon, double scale) { var result = new Line3d(polygon.P0, polygon.P1); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Line3d polygon, V3d center, double scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d Scaled(this Line3d polygon, V3d center, double scale) { var result = new Line3d(polygon.P0, polygon.P1); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Line3d polygon, double scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d ScaledAboutCentroid(this Line3d polygon, double scale) { var result = new Line3d(polygon.P0, polygon.P1); result.ScaleAboutCentroid(scale); return result; } /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Line3d polygon, V3d scale) { polygon.P0 *= scale; polygon.P1 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d Scaled(this Line3d polygon, V3d scale) { var result = new Line3d(polygon.P0, polygon.P1); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Line3d polygon, V3d center, V3d scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d Scaled(this Line3d polygon, V3d center, V3d scale) { var result = new Line3d(polygon.P0, polygon.P1); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Line3d polygon, V3d scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d ScaledAboutCentroid(this Line3d polygon, V3d scale) { var result = new Line3d(polygon.P0, polygon.P1); result.ScaleAboutCentroid(scale); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line3d polygon, M44d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d Transformed(this Line3d polygon, M44d t) { var result = new Line3d(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line3d polygon, Euclidean3d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d Transformed(this Line3d polygon, Euclidean3d t) { var result = new Line3d(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line3d polygon, Euclidean3d t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d InvTransformed(this Line3d polygon, Euclidean3d t) { var result = new Line3d(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line3d polygon, Similarity3d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d Transformed(this Line3d polygon, Similarity3d t) { var result = new Line3d(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line3d polygon, Similarity3d t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d InvTransformed(this Line3d polygon, Similarity3d t) { var result = new Line3d(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line3d polygon, Affine3d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d Transformed(this Line3d polygon, Affine3d t) { var result = new Line3d(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line3d polygon, Shift3d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d Transformed(this Line3d polygon, Shift3d t) { var result = new Line3d(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line3d polygon, Shift3d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d InvTransformed(this Line3d polygon, Shift3d t) { var result = new Line3d(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line3d polygon, Rot3d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d Transformed(this Line3d polygon, Rot3d t) { var result = new Line3d(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line3d polygon, Rot3d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d InvTransformed(this Line3d polygon, Rot3d t) { var result = new Line3d(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line3d polygon, Scale3d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d Transformed(this Line3d polygon, Scale3d t) { var result = new Line3d(polygon.P0, polygon.P1); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Line3d polygon, Scale3d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Line3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d InvTransformed(this Line3d polygon, Scale3d t) { var result = new Line3d(polygon.P0, polygon.P1); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Line3d polygon, M33d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Line3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Line3d Transformed(this Line3d polygon, M33d t) { var result = new Line3d(polygon.P0, polygon.P1); result.Transform(t); return result; } #endregion public static V3d[] GetPointArray(this Line3d line) { var pa = new V3d[2]; pa[0] = line.P0; pa[1] = line.P1; return pa; } public static V3d ComputeCentroid(this Line3d line) { return 0.5 * (line.P0 + line.P1); } } #endregion #region Triangle3d [StructLayout(LayoutKind.Sequential)] public partial struct Triangle3d : IEquatable, IValidity, IPolygon, IBoundingBox3d { public V3d P0, P1, P2; #region Constructors /// /// Creates triangle from 3 points. /// public Triangle3d(V3d p0, V3d p1, V3d p2) { P0 = p0; P1 = p1; P2 = p2; } /// /// Creates triangle from first 3 points in the sequence. /// public Triangle3d(IEnumerable points) { var pa = points.TakeToArray(3); P0 = pa[0]; P1 = pa[1]; P2 = pa[2]; } #endregion #region Properties public readonly bool IsValid { get { return true; } } public readonly bool IsInvalid { get { return false; } } /// /// Edge P1 - P0 /// public readonly V3d Edge01 { get { return P1 - P0; } } /// /// Edge P2 - P0 /// public readonly V3d Edge02 { get { return P2 - P0; } } /// /// Edge P2 - P1 /// public readonly V3d Edge12 { get { return P2 - P1; } } /// /// Edge P0 - P1 /// public readonly V3d Edge10 { get { return P0 - P1; } } /// /// Edge P0 - P2 /// public readonly V3d Edge20 { get { return P0 - P2; } } /// /// Edge P1 - P2 /// public readonly V3d Edge21 { get { return P1 - P2; } } public readonly IEnumerable Edges { get { yield return P1 - P0; yield return P2 - P1; yield return P0 - P2; } } public readonly V3d[] EdgeArray { get { var a = new V3d[3]; a[0] = P1 - P0; a[1] = P2 - P1; a[2] = P0 - P2; return a; } } public readonly IEnumerable EdgeLines { get { yield return new Line3d(P0, P1); yield return new Line3d(P1, P2); yield return new Line3d(P2, P0); } } public readonly Line3d[] EdgeLineArray { get { var a = new Line3d[3]; a[0] = new Line3d(P0, P1); a[1] = new Line3d(P1, P2); a[2] = new Line3d(P2, P0); return a; } } public readonly Line3d GetEdgeLine(int index) { switch (index) { case 0: return new Line3d(P0, P1); case 1: return new Line3d(P1, P2); case 2: return new Line3d(P2, P0); } throw new InvalidOperationException(); } public readonly V3d GetEdge(int index) { switch (index) { case 0: return P1 - P0; case 1: return P2 - P1; case 2: return P0 - P2; } throw new InvalidOperationException(); } public readonly Line3d Line01 { get { return new Line3d(P0, P1); } } public readonly Line3d Line02 { get { return new Line3d(P0, P2); } } public readonly Line3d Line12 { get { return new Line3d(P1, P2); } } public readonly Line3d Line10 { get { return new Line3d(P1, P0); } } public readonly Line3d Line20 { get { return new Line3d(P2, P0); } } public readonly Line3d Line21 { get { return new Line3d(P2, P1); } } public readonly int PointCount { get { return 3; } } public readonly IEnumerable Points { get { yield return P0; yield return P1; yield return P2; } } public readonly Triangle3d Reversed { get { return new Triangle3d(P2, P1, P0); } } #endregion #region Indexer public V3d this[int index] { readonly get { switch (index) { case 0: return P0; case 1: return P1; case 2: return P2; default: throw new IndexOutOfRangeException(); } } set { switch (index) { case 0: P0 = value; return; case 1: P1 = value; return; case 2: P2 = value; return; default: throw new IndexOutOfRangeException(); } } } #endregion #region Transformations public readonly Triangle3d Copy(Func point_copyFun) { return new Triangle3d(point_copyFun(P0), point_copyFun(P1), point_copyFun(P2)); } public readonly Triangle2d ToTriangle2d(Func point_copyFun) { return new Triangle2d(point_copyFun(P0), point_copyFun(P1), point_copyFun(P2)); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Triangle3d a, Triangle3d b) => (a.P0 == b.P0) && (a.P1 == b.P1) && (a.P2 == b.P2); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Triangle3d a, Triangle3d b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(P0, P1, P2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Triangle3d other) => P0.Equals(other.P0) && P1.Equals(other.P1) && P2.Equals(other.P2); public override readonly bool Equals(object other) => (other is Triangle3d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", P0, P1, P2); } public static Triangle3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Triangle3d(V3d.Parse(x[0]), V3d.Parse(x[1]), V3d.Parse(x[2])); } #endregion #region IBoundingBox3d Members public readonly Box3d BoundingBox3d { get { return new Box3d(P0, P1, P2); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Triangle3d a, Triangle3d b, double tolerance) => ApproximateEquals(a.P0, b.P0, tolerance) && ApproximateEquals(a.P1, b.P1, tolerance) && ApproximateEquals(a.P2, b.P2, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Triangle3d a, Triangle3d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Triangle3dExtensions public static partial class Triangle3dExtensions { #region Geometric Transformations /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Triangle3d polygon, double scale) { polygon.P0 *= scale; polygon.P1 *= scale; polygon.P2 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d Scaled(this Triangle3d polygon, double scale) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Triangle3d polygon, V3d center, double scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; polygon.P2 = center + (polygon.P2 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d Scaled(this Triangle3d polygon, V3d center, double scale) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Triangle3d polygon, double scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d ScaledAboutCentroid(this Triangle3d polygon, double scale) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.ScaleAboutCentroid(scale); return result; } /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Triangle3d polygon, V3d scale) { polygon.P0 *= scale; polygon.P1 *= scale; polygon.P2 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d Scaled(this Triangle3d polygon, V3d scale) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Triangle3d polygon, V3d center, V3d scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; polygon.P2 = center + (polygon.P2 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d Scaled(this Triangle3d polygon, V3d center, V3d scale) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Triangle3d polygon, V3d scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d ScaledAboutCentroid(this Triangle3d polygon, V3d scale) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.ScaleAboutCentroid(scale); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle3d polygon, M44d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d Transformed(this Triangle3d polygon, M44d t) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle3d polygon, Euclidean3d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d Transformed(this Triangle3d polygon, Euclidean3d t) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle3d polygon, Euclidean3d t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); polygon.P2 = t.InvTransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d InvTransformed(this Triangle3d polygon, Euclidean3d t) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle3d polygon, Similarity3d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d Transformed(this Triangle3d polygon, Similarity3d t) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle3d polygon, Similarity3d t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); polygon.P2 = t.InvTransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d InvTransformed(this Triangle3d polygon, Similarity3d t) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle3d polygon, Affine3d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d Transformed(this Triangle3d polygon, Affine3d t) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle3d polygon, Shift3d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d Transformed(this Triangle3d polygon, Shift3d t) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle3d polygon, Shift3d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d InvTransformed(this Triangle3d polygon, Shift3d t) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle3d polygon, Rot3d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d Transformed(this Triangle3d polygon, Rot3d t) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle3d polygon, Rot3d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d InvTransformed(this Triangle3d polygon, Rot3d t) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle3d polygon, Scale3d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d Transformed(this Triangle3d polygon, Scale3d t) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Triangle3d polygon, Scale3d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Triangle3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d InvTransformed(this Triangle3d polygon, Scale3d t) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Triangle3d polygon, M33d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Triangle3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Triangle3d Transformed(this Triangle3d polygon, M33d t) { var result = new Triangle3d(polygon.P0, polygon.P1, polygon.P2); result.Transform(t); return result; } #endregion public static V3d[] GetPointArray(this Triangle3d triangle) { var pa = new V3d[3]; pa[0] = triangle.P0; pa[1] = triangle.P1; pa[2] = triangle.P2; return pa; } public static V3d ComputeCentroid(this Triangle3d triangle) { return Constant.OneThird * (triangle.P0 + triangle.P1 + triangle.P2); } } #endregion #region Quad3d [StructLayout(LayoutKind.Sequential)] public partial struct Quad3d : IEquatable, IValidity, IPolygon, IBoundingBox3d { public V3d P0, P1, P2, P3; #region Constructors /// /// Creates quad from 4 points. /// public Quad3d(V3d p0, V3d p1, V3d p2, V3d p3) { P0 = p0; P1 = p1; P2 = p2; P3 = p3; } /// /// Creates quad from first 4 points in the sequence. /// public Quad3d(IEnumerable points) { var pa = points.TakeToArray(4); P0 = pa[0]; P1 = pa[1]; P2 = pa[2]; P3 = pa[3]; } /// /// Creates quad from point and two vectors representing edges. /// public Quad3d(V3d p0, V3d edge01, V3d edge03) { P0 = p0; P1 = p0 + edge01; P2 = P1 + edge03; P3 = p0 + edge03; } #endregion #region Properties public readonly bool IsValid { get { return true; } } public readonly bool IsInvalid { get { return false; } } /// /// Edge P1 - P0 /// public readonly V3d Edge01 { get { return P1 - P0; } } /// /// Edge P3 - P0 /// public readonly V3d Edge03 { get { return P3 - P0; } } /// /// Edge P2 - P1 /// public readonly V3d Edge12 { get { return P2 - P1; } } /// /// Edge P0 - P1 /// public readonly V3d Edge10 { get { return P0 - P1; } } /// /// Edge P3 - P2 /// public readonly V3d Edge23 { get { return P3 - P2; } } /// /// Edge P1 - P2 /// public readonly V3d Edge21 { get { return P1 - P2; } } /// /// Edge P0 - P3 /// public readonly V3d Edge30 { get { return P0 - P3; } } /// /// Edge P2 - P3 /// public readonly V3d Edge32 { get { return P2 - P3; } } public readonly IEnumerable Edges { get { yield return P1 - P0; yield return P2 - P1; yield return P3 - P2; yield return P0 - P3; } } public readonly V3d[] EdgeArray { get { var a = new V3d[4]; a[0] = P1 - P0; a[1] = P2 - P1; a[2] = P3 - P2; a[3] = P0 - P3; return a; } } public readonly IEnumerable EdgeLines { get { yield return new Line3d(P0, P1); yield return new Line3d(P1, P2); yield return new Line3d(P2, P3); yield return new Line3d(P3, P0); } } public readonly Line3d[] EdgeLineArray { get { var a = new Line3d[4]; a[0] = new Line3d(P0, P1); a[1] = new Line3d(P1, P2); a[2] = new Line3d(P2, P3); a[3] = new Line3d(P3, P0); return a; } } public readonly Line3d GetEdgeLine(int index) { switch (index) { case 0: return new Line3d(P0, P1); case 1: return new Line3d(P1, P2); case 2: return new Line3d(P2, P3); case 3: return new Line3d(P3, P0); } throw new InvalidOperationException(); } public readonly V3d GetEdge(int index) { switch (index) { case 0: return P1 - P0; case 1: return P2 - P1; case 2: return P3 - P2; case 3: return P0 - P3; } throw new InvalidOperationException(); } public readonly Line3d Line01 { get { return new Line3d(P0, P1); } } public readonly Line3d Line03 { get { return new Line3d(P0, P3); } } public readonly Line3d Line12 { get { return new Line3d(P1, P2); } } public readonly Line3d Line10 { get { return new Line3d(P1, P0); } } public readonly Line3d Line23 { get { return new Line3d(P2, P3); } } public readonly Line3d Line21 { get { return new Line3d(P2, P1); } } public readonly Line3d Line30 { get { return new Line3d(P3, P0); } } public readonly Line3d Line32 { get { return new Line3d(P3, P2); } } public readonly int PointCount { get { return 4; } } public readonly IEnumerable Points { get { yield return P0; yield return P1; yield return P2; yield return P3; } } public readonly Quad3d Reversed { get { return new Quad3d(P3, P2, P1, P0); } } #endregion #region Indexer public V3d this[int index] { readonly get { switch (index) { case 0: return P0; case 1: return P1; case 2: return P2; case 3: return P3; default: throw new IndexOutOfRangeException(); } } set { switch (index) { case 0: P0 = value; return; case 1: P1 = value; return; case 2: P2 = value; return; case 3: P3 = value; return; default: throw new IndexOutOfRangeException(); } } } #endregion #region Transformations public readonly Quad3d Copy(Func point_copyFun) { return new Quad3d(point_copyFun(P0), point_copyFun(P1), point_copyFun(P2), point_copyFun(P3)); } public readonly Quad2d ToQuad2d(Func point_copyFun) { return new Quad2d(point_copyFun(P0), point_copyFun(P1), point_copyFun(P2), point_copyFun(P3)); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Quad3d a, Quad3d b) => (a.P0 == b.P0) && (a.P1 == b.P1) && (a.P2 == b.P2) && (a.P3 == b.P3); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Quad3d a, Quad3d b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(P0, P1, P2, P3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Quad3d other) => P0.Equals(other.P0) && P1.Equals(other.P1) && P2.Equals(other.P2) && P3.Equals(other.P3); public override readonly bool Equals(object other) => (other is Quad3d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}, {3}]", P0, P1, P2, P3); } public static Quad3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Quad3d(V3d.Parse(x[0]), V3d.Parse(x[1]), V3d.Parse(x[2]), V3d.Parse(x[3])); } #endregion #region IBoundingBox3d Members public readonly Box3d BoundingBox3d { get { return new Box3d(P0, P1, P2, P3); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Quad3d a, Quad3d b, double tolerance) => ApproximateEquals(a.P0, b.P0, tolerance) && ApproximateEquals(a.P1, b.P1, tolerance) && ApproximateEquals(a.P2, b.P2, tolerance) && ApproximateEquals(a.P3, b.P3, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Quad3d a, Quad3d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Quad3dExtensions public static partial class Quad3dExtensions { #region Geometric Transformations /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Quad3d polygon, double scale) { polygon.P0 *= scale; polygon.P1 *= scale; polygon.P2 *= scale; polygon.P3 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d Scaled(this Quad3d polygon, double scale) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Quad3d polygon, V3d center, double scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; polygon.P2 = center + (polygon.P2 - center) * scale; polygon.P3 = center + (polygon.P3 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d Scaled(this Quad3d polygon, V3d center, double scale) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Quad3d polygon, double scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d ScaledAboutCentroid(this Quad3d polygon, double scale) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.ScaleAboutCentroid(scale); return result; } /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Quad3d polygon, V3d scale) { polygon.P0 *= scale; polygon.P1 *= scale; polygon.P2 *= scale; polygon.P3 *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d Scaled(this Quad3d polygon, V3d scale) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref Quad3d polygon, V3d center, V3d scale) { polygon.P0 = center + (polygon.P0 - center) * scale; polygon.P1 = center + (polygon.P1 - center) * scale; polygon.P2 = center + (polygon.P2 - center) * scale; polygon.P3 = center + (polygon.P3 - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d Scaled(this Quad3d polygon, V3d center, V3d scale) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref Quad3d polygon, V3d scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d ScaledAboutCentroid(this Quad3d polygon, V3d scale) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.ScaleAboutCentroid(scale); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad3d polygon, M44d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); polygon.P3 = t.TransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d Transformed(this Quad3d polygon, M44d t) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad3d polygon, Euclidean3d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); polygon.P3 = t.TransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d Transformed(this Quad3d polygon, Euclidean3d t) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad3d polygon, Euclidean3d t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); polygon.P2 = t.InvTransformPos(polygon.P2); polygon.P3 = t.InvTransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d InvTransformed(this Quad3d polygon, Euclidean3d t) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad3d polygon, Similarity3d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); polygon.P3 = t.TransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d Transformed(this Quad3d polygon, Similarity3d t) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad3d polygon, Similarity3d t) { polygon.P0 = t.InvTransformPos(polygon.P0); polygon.P1 = t.InvTransformPos(polygon.P1); polygon.P2 = t.InvTransformPos(polygon.P2); polygon.P3 = t.InvTransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d InvTransformed(this Quad3d polygon, Similarity3d t) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad3d polygon, Affine3d t) { polygon.P0 = t.TransformPos(polygon.P0); polygon.P1 = t.TransformPos(polygon.P1); polygon.P2 = t.TransformPos(polygon.P2); polygon.P3 = t.TransformPos(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d Transformed(this Quad3d polygon, Affine3d t) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad3d polygon, Shift3d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); polygon.P3 = t.Transform(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d Transformed(this Quad3d polygon, Shift3d t) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad3d polygon, Shift3d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); polygon.P3 = t.InvTransform(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d InvTransformed(this Quad3d polygon, Shift3d t) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad3d polygon, Rot3d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); polygon.P3 = t.Transform(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d Transformed(this Quad3d polygon, Rot3d t) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad3d polygon, Rot3d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); polygon.P3 = t.InvTransform(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d InvTransformed(this Quad3d polygon, Rot3d t) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad3d polygon, Scale3d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); polygon.P3 = t.Transform(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d Transformed(this Quad3d polygon, Scale3d t) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref Quad3d polygon, Scale3d t) { polygon.P0 = t.InvTransform(polygon.P0); polygon.P1 = t.InvTransform(polygon.P1); polygon.P2 = t.InvTransform(polygon.P2); polygon.P3 = t.InvTransform(polygon.P3); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The Quad3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d InvTransformed(this Quad3d polygon, Scale3d t) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.InvTransform(t); return result; } /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref Quad3d polygon, M33d t) { polygon.P0 = t.Transform(polygon.P0); polygon.P1 = t.Transform(polygon.P1); polygon.P2 = t.Transform(polygon.P2); polygon.P3 = t.Transform(polygon.P3); } /// /// Returns a copy of the transformed by the given transformation. /// /// The Quad3d to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Quad3d Transformed(this Quad3d polygon, M33d t) { var result = new Quad3d(polygon.P0, polygon.P1, polygon.P2, polygon.P3); result.Transform(t); return result; } #endregion public static V3d[] GetPointArray(this Quad3d quad) { var pa = new V3d[4]; pa[0] = quad.P0; pa[1] = quad.P1; pa[2] = quad.P2; pa[3] = quad.P3; return pa; } public static V3d ComputeCentroid(this Quad3d quad) { return 0.25 * (quad.P0 + quad.P1 + quad.P2 + quad.P3); } } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Geometry_template.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# Func Sep = s => () => Out(s); //# Action comma = () => Out(", "); //# { // POLYGONS //# var planeArray = new[] { "", "", "line", "plane" }; //# var typeArray = new[] { "", "Polygon", "Line", "Triangle", "Quad" }; //# var nameArray = new[] { "", "polygon", "line", "triangle", "quad" }; //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var scaleArray = isDouble ? new[] { "", "", "0.5", "Constant.OneThird", "0.25" } //# : new[] { "", "", "0.5f", "ConstantF.OneThird", "0.25f" }; //# var eps = isDouble ? "1e-8" : "1e-5f"; //# for (int d = 2; d < 4; d++) { //# var dp1 = d + 1; //# var dt = d.ToString() + tc; //# var di = d.ToString() + "i"; //# var tvec = "V" + dt; //# var tveci = "V" + di; //# var tmat = "M" + d + dt; //# var tmat1 = "M" + dp1 + dp1 + tc; //# var teucl = "Euclidean" + dt; //# var tsimi = "Similarity" + dt; //# var taffi = "Affine" + dt; //# var tshif = "Shift" + dt; //# var trot = "Rot" + dt; //# var tscale = "Scale" + dt; //# var plane = planeArray[d]; //# var tplane = "Plane" + dt; //# var tline = "Line" + dt; //# var tbox = "Box" + dt; //# var thull = "Hull" + dt; //# var ttriangle = "Triangle" + dt; //# var tquad = "Quad" + dt; //# //# for (int pc = 1; pc < 5; pc++) { //# var pcsub1 = pc - 1; //# var type = typeArray[pc] + dt; //# var name = nameArray[pc]; //# var isPoly = pc == 1; //# var scale = scaleArray[pc]; //# //# foreach (var isIndexed in new[] { false, true }) { //# if (isIndexed && !isPoly) continue; //# var indextype = isIndexed ? "Index" + type : type; //# //# if (isPoly) { //# if (!isIndexed) { #region __type__ /// /// A polygon internally represented by an array of points. Implemented /// as a structure, the validity of the polygon can be checked via its /// PointCount, which must be bigger than 0 for a polygon to hold any /// points, and bigger than 2 for a polygon to be geometrically valid. /// [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__>, IValidity, IPolygon<__tvec__>, IBounding__tbox__ { internal int m_pointCount; internal __tvec__[] m_pointArray; #region Constructors /// /// Creates a polygon from given points. /// public __type__(__tvec__[] pointArray, int pointCount) { if (pointArray != null) { if (pointCount <= pointArray.Length) { m_pointCount = pointCount; m_pointArray = pointArray; } else throw new ArgumentException( "point count must be smaller or equal array length"); } else { m_pointCount = 0; m_pointArray = null; } } /// /// Creates a polygon from given points. /// public __type__(params __tvec__[] pointArray) { m_pointCount = pointArray != null ? pointArray.Length : 0; m_pointArray = pointArray; } /// /// Creates a polygon from given points. /// public __type__(__tvec__[] pointArray, int startIndex, int count) { if (startIndex < 0 || startIndex >= pointArray.Length - 1) throw new ArgumentException(); if (count <= 0 || startIndex + count >= pointArray.Length) throw new ArgumentException(); m_pointCount = count; m_pointArray = new __tvec__[count]; for (int i = 0; i < count; i++) m_pointArray[i] = pointArray[startIndex + i]; } /// /// Creates a polygon from point count and point creator function. /// public __type__(int pointCount, Func index_pointCreator) : this(new __tvec__[pointCount].SetByIndex(index_pointCreator)) { } /// /// Creates a polygon from a sequence of points. /// public __type__(IEnumerable<__tvec__> points) : this(points.ToArray()) { } /// /// Creates a polygon from the points of a pointArray that /// are selected by an index array. /// public __type__(int[] indexArray, __tvec__[] pointArray) : this(indexArray.Map(i => pointArray[i])) { } /// /// Creates a polygon from a triangle. /// public __type__(__ttriangle__ triangle) : this(triangle.GetPointArray()) { } /// /// Creates a polygon from a quad. /// public __type__(__tquad__ quad) : this(quad.GetPointArray()) { } /// /// Copy constructor. /// Performs deep copy of original. /// public __type__(__type__ original) : this(original.GetPointArray()) { } #endregion #region Constants public static readonly __type__ Invalid = new __type__(null, 0); #endregion #region Properties public readonly bool IsValid => m_pointArray != null; public readonly bool IsInvalid => m_pointArray == null; /// /// The number of points in the polygon. If this is 0, the polygon /// is invalid. /// public readonly int PointCount => m_pointCount; /// /// Enumerates points. /// public readonly IEnumerable<__tvec__> Points { get { for (int pi = 0; pi < m_pointCount; pi++) yield return m_pointArray[pi]; } } #endregion #region Conversions /// /// Returns a copy of the polygons point array. /// public readonly __tvec__[] GetPointArray() { var pc = m_pointCount; var pa = new __tvec__[pc]; for (int pi = 0; pi < pc; pi++) pa[pi] = m_pointArray[pi]; return pa; } /// /// [P0, P1, P2] -> [P0, P1, P2, P0]. /// public readonly __tvec__[] GetPointArrayWithRepeatedFirstPoint() { var pc = m_pointCount; var pa = new __tvec__[pc + 1]; for (int pi = 0; pi < pc; pi++) pa[pi] = m_pointArray[pi]; pa[pc] = pa[0]; return pa; } /// /// Returns a transformed copy of the polygons point array. /// public readonly T[] GetPointArray(Func<__tvec__, T> point_copyFun) { var pc = m_pointCount; var pa = new T[pc]; for (int pi = 0; pi < pc; pi++) pa[pi] = point_copyFun(m_pointArray[pi]); return pa; } /// /// Returns a transformed copy of the polygons point array. /// public readonly T[] GetPointArray(Func<__tvec__, int, T> point_index_copyFun) { var pc = m_pointCount; var pa = new T[pc]; for (int pi = 0; pi < pc; pi++) pa[pi] = point_index_copyFun(m_pointArray[pi], pi); return pa; } #endregion #region Indexing /// /// Gets the index-th point of this polygon. /// public readonly __tvec__ this[int index] { get { return m_pointArray[index]; } set { m_pointArray[index] = value; } } #endregion #region Edges and Lines /// /// Index-th edge as vector (edgeEndPos - edgeBeginPos). /// public readonly __tvec__ Edge(int index) { var p0 = m_pointArray[index++]; var p1 = m_pointArray[index < m_pointCount ? index : 0]; return p1 - p0; } /// /// Edges as vectors (edgeEndPos - edgeBeginPos). /// public readonly IEnumerable<__tvec__> Edges { get { var pc = m_pointCount; var p = m_pointArray[0]; var p0 = p; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; yield return p1 - p0; p0 = p1; } yield return p - p0; } } /// /// Index-th edge as line segment (edgeBeginPos, edgeEndPos). /// public readonly __tline__ EdgeLine(int index) { var p0 = m_pointArray[index++]; var p1 = m_pointArray[index < m_pointCount ? index : 0]; return new __tline__(p0, p1); } /// /// Edges as line segments (edgeBeginPos, edgeEndPos). /// public readonly IEnumerable<__tline__> EdgeLines { get { var pc = m_pointCount; if (pc < 1) yield break; var p0 = m_pointArray[0]; var p = p0; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; yield return new __tline__(p0, p1); p0 = p1; } yield return new __tline__(p0, p); } } /// /// Edges as vectors (edgeEndPos - edgeBeginPos). /// public readonly __tvec__[] GetEdgeArray() { var pc = m_pointCount; if (pc < 2) return Array.Empty<__tvec__>(); var edgeArray = new __tvec__[pc]; var p = m_pointArray[0]; var p0 = p; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; edgeArray[pi - 1] = p1 - p0; p0 = p1; } edgeArray[pc - 1] = p - p0; return edgeArray; } /// /// Edges as line segments (edgeBeginPos, edgeEndPos). /// public readonly __tline__[] GetEdgeLineArray() { var pc = PointCount; if (pc < 2) return Array.Empty<__tline__>(); var ela = new __tline__[pc]; var p = m_pointArray[0]; var p0 = p; for (int pi = 1; pi < pc; pi++) { var p1 = m_pointArray[pi]; ela[pi - 1] = new __tline__(p0, p1); p0 = p1; } ela[pc - 1] = new __tline__(p0, p); return ela; } #endregion #region Transformations /// /// Returns copy of polygon. Same as Map(p => p). /// public readonly __type__ Copy() { return new __type__(m_pointArray.Copy()); } /// /// Returns transformed copy of this polygon. /// public readonly __type__ Map(Func<__tvec__, __tvec__> point_fun) { var pc = m_pointCount; __tvec__[] opa = m_pointArray, npa = new __tvec__[pc]; for (int pi = 0; pi < pc; pi++) npa[pi] = point_fun(opa[pi]); return new __type__(npa, pc); } /// /// Gets copy with reversed order of vertices. /// public readonly __type__ Reversed { get { var pc = m_pointCount; __tvec__[] opa = m_pointArray, npa = new __tvec__[pc]; for (int pi = 0, pj = pc - 1; pi < pc; pi++, pj--) npa[pi] = opa[pj]; return new __type__(npa, pc); } } /// /// Reverses order of vertices in-place. /// public readonly void Reverse() { var pa = m_pointArray; for (int pi = 0, pj = m_pointCount - 1; pi < pj; pi++, pj--) { var t = pa[pi]; pa[pi] = pa[pj]; pa[pj] = t; } } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ a, __type__ b) { if (a.m_pointCount != b.m_pointCount) return false; for (int pi = 0; pi < a.m_pointCount; pi++) if (a.m_pointArray[pi] != b.m_pointArray[pi]) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ a, __type__ b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return m_pointArray.GetCombinedHashCode(m_pointCount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) { if (m_pointCount != other.m_pointCount) return false; for (int pi = 0; pi < m_pointCount; pi++) if (!m_pointArray[pi].Equals(other.m_pointArray[pi])) return false; return true; } public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}]", Points.Select(x => x.ToString()).Join(", ") ); } public static __type__ Parse(string s) { var va = s.NestedBracketSplitLevelOne().ToArray(); return new __type__(va.Select(x => __tvec__.Parse(x))); } #endregion #region IBounding__tbox__ Members /// /// Bounding box of polygon. /// public readonly __tbox__ Bounding__tbox__ { get { return new __tbox__(m_pointArray, 0, m_pointCount); } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b, __ftype__ tolerance) { if (a.m_pointCount != b.m_pointCount) return false; for (int pi = 0; pi < a.m_pointCount; pi++) if (!ApproximateEquals(a.m_pointArray[pi], b.m_pointArray[pi], tolerance)) return false; return true; } /// /// Returns whether the given are equal within /// Constant<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b) => ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } #endregion //# } // !isIndexed //# if (isIndexed) { #region __indextype__ [StructLayout(LayoutKind.Sequential)] public readonly partial struct __indextype__ : IValidity, IPolygon<__tvec__> { private readonly int m_pointCount; private readonly int m_firstIndex; private readonly int[] m_indexArray; private readonly __tvec__[] m_pointArray; #region Constructors public __indextype__(int[] indexArray, int firstIndex, int pointCount, __tvec__[] pointArray) { m_indexArray = indexArray; m_firstIndex = firstIndex; m_pointCount = pointCount; m_pointArray = pointArray; } public __indextype__(__tvec__[] pointArray, int firstIndex, int pointCount) : this(new int[pointCount].SetByIndex(i => firstIndex + i), 0, pointCount, pointArray) { } public __indextype__(__tvec__[] pointArray) : this(new int[pointArray.Length].SetByIndex(i => i), 0, pointArray.Length, pointArray) { } #endregion #region Constants public static readonly __indextype__ Invalid = new __indextype__(null, 0, 0, null); #endregion #region Properties public bool IsValid { get { return m_indexArray != null && m_pointArray != null; } } public bool IsInvalid { get { return m_indexArray == null || m_pointArray == null; } } public int PointCount { get { return m_pointCount; } } public int FirstIndex { get { return m_firstIndex; } } /// /// The index array that contains the point indices of the /// index polygon at the index range [FirstIndex, FirstIndex + PointCount). /// NOTE: This is different from the array returned by GetIndexArray(). /// public int[] IndexArray { get { return m_indexArray; } } /// /// The point array that contains the points referenced by /// the index array. Note: This is different from the array /// returned by GetPointArray(). /// public __tvec__[] PointArray { get { return m_pointArray; } } public IEnumerable<__tvec__> Points { get { for (int i = 0; i < m_pointCount; i++) yield return m_pointArray[m_indexArray[m_firstIndex + i]]; } } public IEnumerable Indices { get { for (int i = 0; i < m_pointCount; i++) yield return m_indexArray[m_firstIndex + i]; } } #endregion #region Indexing public __tvec__ this[int index] { get { return m_pointArray[m_indexArray[m_firstIndex + index]]; } set { m_pointArray[m_indexArray[m_firstIndex + index]] = value; } } #endregion #region Conversions public void ForEachIndex(Action index_act) { var ia = m_indexArray; int fi = m_firstIndex; for (int i = 0; i < m_pointCount; i++) index_act(ia[fi + i]); } /// /// Returns a newly created array containing only the actual indices /// of the index polygon. NOTE: This is different from the /// IndexArray property! /// public int[] GetIndexArray() { return m_indexArray.Copy(m_firstIndex, m_pointCount); } /// /// Returns a newly created array containing only the actual points /// of the index polygon. NOTE: This is different from the /// PointArray property! /// public __tvec__[] GetPointArray() { var pa = m_pointArray; return m_indexArray.Map(m_firstIndex, m_pointCount, i => pa[i]); } public T[] GetPointArray(T[] pointArray) { return m_indexArray.Map(m_firstIndex, m_pointCount, i => pointArray[i]); } public T[] GetPointArray(List pointList) { return m_indexArray.Map(m_firstIndex, m_pointCount, i => pointList[i]); } #endregion } #endregion //# } // isIndexed #region __indextype__Extensions public static partial class __indextype__Extensions { //# if (isIndexed) { #region Conversions public static __type__ To__type__(this __indextype__ polygon) { return new __type__(polygon.GetPointArray()); } #endregion //# } // isIndexed #region Geometric Properties /// /// The vertex centroid is the average of the vertex coordinates. /// public static __tvec__ ComputeVertexCentroid(this __indextype__ polygon) { var sum = __tvec__.Zero; int pc = polygon.PointCount; for (int i = 0; i < pc; i++) sum += polygon[i]; __ftype__ scale = 1 / (__ftype__)pc; return sum * scale; } public static __ftype__ ComputePerimeter(this __indextype__ polygon) { var pc = polygon.PointCount; var p0 = polygon[pc - 1]; __ftype__ r = 0; for (int i = 0; i < pc; i++) { var p1 = polygon[i]; r += Vec.Distance(p0, p1); p0 = p1; } return r; } #endregion //# if (!isIndexed) { #region Geometric Transformations //# var scales = new string [] { ftype, tvec }; //# foreach (string tscalefactor in scales) { /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. public static void Scale(this ref __type__ polygon, __tscalefactor__ scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] *= scale; } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Scaled(this __type__ polygon, __tscalefactor__ scale) { var result = new __type__(polygon); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. public static void Scale(this ref __type__ polygon, __tvec__ center, __tscalefactor__ scale) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = center + (polygon.m_pointArray[pi] - center) * scale; } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Scaled(this __type__ polygon, __tvec__ center, __tscalefactor__ scale) { var result = new __type__(polygon); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutVertexCentroid(this ref __type__ polygon, __tscalefactor__ scale) { var center = polygon.ComputeVertexCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ ScaledAboutVertexCentroid(this __type__ polygon, __tscalefactor__ scale) { var result = new __type__(polygon); result.ScaleAboutVertexCentroid(scale); return result; } //# } //# var transforms = new string [] { tmat1, teucl, tsimi, taffi, tshif, trot, tscale, tmat }; //# for (int i = 0; i < transforms.Length; i++) { //# var ttrafo = transforms[i]; //# var transform = (i < 4) ? "TransformPos" : "Transform"; //# var hasInv = (i != 0 && i != 3 && i != 7); /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. public static void Transform(this ref __type__ polygon, __ttrafo__ t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.__transform__(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the given transformation. /// /// The __type__ to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Transformed(this __type__ polygon, __ttrafo__ t) { var result = new __type__(polygon); result.Transform(t); return result; } //# if (hasInv) { /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. public static void InvTransform(this ref __type__ polygon, __ttrafo__ t) { for (int pi = 0; pi < polygon.m_pointCount; pi++) polygon.m_pointArray[pi] = t.Inv__transform__(polygon.m_pointArray[pi]); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The __type__ to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ InvTransformed(this __type__ polygon, __ttrafo__ t) { var result = new __type__(polygon); result.InvTransform(t); return result; } //# } //# } public static __type__ WithoutMultiplePoints(this __type__ polygon, __ftype__ eps = __eps__) { eps *= eps; var opc = polygon.PointCount; var pa = new __tvec__[opc]; var pc = 0; pa[0] = polygon[0]; for (int pi = 1; pi < opc; pi++) if (Vec.DistanceSquared(pa[pc], polygon[pi]) > eps) pa[++pc] = polygon[pi]; if (Vec.DistanceSquared(pa[pc], polygon[0]) > eps) ++pc; return new __type__(pa, pc); } #endregion #region Clipping /// /// Clip the supplied polygon at the supplied __plane__. The method should /// work with all non-selfintersecting polygons. Returns all parts of /// the polygon that are at the positive side of the __plane__. /// public static __type__ ConvexClipped( this __type__ polygon, __tplane__ __plane__, __ftype__ eps = __eps__) { var opc = polygon.PointCount; __tvec__[] pa = new __tvec__[opc + 1]; var pc = 0; var pf = polygon[0]; var hf = __plane__.Height(pf); bool hfp = hf > eps, hfn = hf < -eps; if (hf >= -eps) pa[pc++] = pf; var p0 = pf; var h0 = hf; var h0p = hfp; var h0n = hfn; for (int vi = 1; vi < opc; vi++) { var p1 = polygon[vi]; var h1 = __plane__.Height(p1); bool h1p = h1 > eps, h1n = h1 < -eps; if (h0p && h1n || h0n && h1p) pa[pc++] = p0 + (p1 - p0) * (h0 / (h0 - h1)); if (h1 >= -eps) pa[pc++] = p1; p0 = p1; h0 = h1; h0p = h1p; h0n = h1n; } if (h0p && hfn || h0n && hfp) pa[pc++] = p0 + (pf - p0) * (h0 / (h0 - hf)); return new __type__(pa, pc); } /// /// Returns the convex polygon clipped by the set of __plane__s (defined /// as __tplane__s), i.e. all parts of the polygon that are at the positive /// side of the __plane__s. /// public static __type__ ConvexClipped( this __type__ polygon, __tplane__[] __plane__s, __ftype__ eps = __eps__) { foreach (var c in __plane__s) { polygon = polygon.ConvexClipped(c, eps); if (polygon.PointCount == 0) break; } return polygon; } /// /// Returns the polygon clipped by the hull, i.e. all parts of the /// polygon that are at the positive side of the hull __plane__s. /// public static __type__ ConvexClipped( this __type__ polygon, __thull__ hull, __ftype__ eps = __eps__) { return polygon.ConvexClipped(hull.PlaneArray, eps); } /// /// TODO summary. /// public static __type__ ConvexClipped( this __type__ polygon, __tbox__ box, __ftype__ eps = __eps__) { var __plane__s = new[] { //# Meta.VecFields.Take(d).ForEach(axis => { new __tplane__(__tvec__.__axis__Axis, box.Min), new __tplane__(-__tvec__.__axis__Axis, box.Max), //# }); }; return polygon.ConvexClipped(__plane__s); } #endregion //# } // !isIndexed } #endregion //# } else { // !isPoly #region __type__ [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__>, IValidity, IPolygon<__tvec__>, IBounding__tbox__ { public __tvec__ /*# pc.ForEach(i => { */P__i__/*# }, Sep(", ")); */; #region Constructors /// /// Creates __name__ from __pc__ points. /// public __type__(/*# pc.ForEach(i => { */__tvec__ p__i__/*# }, Sep(", ")); */) { /*# pc.ForEach(i => { */P__i__ = p__i__/*# }, Sep("; ")); */; } /// /// Creates __name__ from first __pc__ points in the sequence. /// public __type__(IEnumerable<__tvec__> points) { var pa = points.TakeToArray(__pc__); /*# pc.ForEach(i => { */P__i__ = pa[__i__]/*# }, Sep("; ")); */; } //# if (pc == 4) { /// /// Creates quad from point and two vectors representing edges. /// public __type__(__tvec__ p0, __tvec__ edge01, __tvec__ edge03) { P0 = p0; P1 = p0 + edge01; P2 = P1 + edge03; P3 = p0 + edge03; } //# } #endregion #region Properties public readonly bool IsValid { get { return true; } } public readonly bool IsInvalid { get { return false; } } //# if (pc > 2) { //# pc.ForEach(i => { foreach (var j in new[] { (i + 1) % pc, (i + pcsub1) % pc }) { /// /// Edge P__j__ - P__i__ /// public readonly __tvec__ Edge__i____j__ { get { return P__j__ - P__i__; } } //# } }); public readonly IEnumerable<__tvec__> Edges { get { //# pc.ForEach(i => { var j = (i + 1) % pc; yield return P__j__ - P__i__; //# }); } } public readonly __tvec__[] EdgeArray { get { var a = new __tvec__[__pc__]; //# pc.ForEach(i => { var j = (i + 1) % pc; a[__i__] = P__j__ - P__i__; //# }); return a; } } public readonly IEnumerable<__tline__> EdgeLines { get { //# pc.ForEach(i => { var j = (i + 1) % pc; yield return new __tline__(P__i__, P__j__); //# }); } } public readonly __tline__[] EdgeLineArray { get { var a = new __tline__[__pc__]; //# pc.ForEach(i => { var j = (i + 1) % pc; a[__i__] = new __tline__(P__i__, P__j__); //# }); return a; } } public readonly __tline__ GetEdgeLine(int index) { switch (index) { //# pc.ForEach(i => { var j = (i + 1) % pc; case __i__: return new __tline__(P__i__, P__j__); //# }); } throw new InvalidOperationException(); } public readonly __tvec__ GetEdge(int index) { switch (index) { //# pc.ForEach(i => { var j = (i + 1) % pc; case __i__: return P__j__ - P__i__; //# }); } throw new InvalidOperationException(); } //# pc.ForEach(i => { foreach (var j in new[] { (i + 1) % pc, (i + pcsub1) % pc }) { public readonly __tline__ Line__i____j__ { get { return new __tline__(P__i__, P__j__); } } //# } }); //# } // pc > 2 public readonly int PointCount { get { return __pc__; } } public readonly IEnumerable<__tvec__> Points { get { /*# pc.ForEach(i => { */yield return P__i__/*# }, Sep("; ")); */; } } public readonly __type__ Reversed { get { return new __type__(/*# pc.ForEach(i => { var j = pcsub1 - i; */P__j__/*# }, Sep(", ")); */); } } #endregion #region Indexer public __tvec__ this[int index] { readonly get { switch (index) { //# pc.ForEach(i => { case __i__: return P__i__; //# }); default: throw new IndexOutOfRangeException(); } } set { switch (index) { //# pc.ForEach(i => { case __i__: P__i__ = value; return; //# }); default: throw new IndexOutOfRangeException(); } } } #endregion #region Transformations public readonly __type__ Copy(Func<__tvec__, __tvec__> point_copyFun) { return new __type__(/*# pc.ForEach(i => { */point_copyFun(P__i__)/*# }, Sep(", ")); */); } //# for (int od = 2; od < 4; od++) { if (d == od) continue; //# var otype = typeArray[pc] + od + "d"; var otvec = "V" + od + "d"; public readonly __otype__ To__otype__(Func<__tvec__, __otvec__> point_copyFun) { return new __otype__(/*# pc.ForEach(i => { */point_copyFun(P__i__)/*# }, Sep(", ")); */); } //# } // od #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ a, __type__ b) => /*# pc.ForEach(i => { */(a.P__i__ == b.P__i__)/*# }, Sep(" && ")); */; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ a, __type__ b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(/*# pc.ForEach(i => { */P__i__/*# }, Sep(", ")); */); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => /*# pc.ForEach(i => { */P__i__.Equals(other.P__i__)/*# }, Sep(" && ")); */; public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; public override readonly string ToString() { //# var format = "["; pc.ForEach(i => format += "{" + i + "}", () => format += ", "); format += "]"; return string.Format(CultureInfo.InvariantCulture, "__format__", /*# pc.ForEach(i => { */P__i__/*# }, Sep(", ")); */); } public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__(/*# pc.ForEach(i => { */__tvec__.Parse(x[__i__])/*# }, Sep(", ")); */); } #endregion #region IBounding__tbox__ Members public readonly __tbox__ Bounding__tbox__ { get { return new __tbox__(/*# pc.ForEach(i => { */P__i__/*# }, Sep(", ")); */)/*#if (pc == 2) {*/.Repair()/*# } */; } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b, __ftype__ tolerance) => /*# pc.ForEach(i => { */ApproximateEquals(a.P__i__, b.P__i__, tolerance)/*# }, Sep(" && ")); */; /// /// Returns whether the given are equal within /// Constant<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b) => ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } #endregion #region __type__Extensions public static partial class __type__Extensions { #region Geometric Transformations //# var scales = new string [] { ftype, tvec }; //# foreach (string tscalefactor in scales) { /// /// Scales the by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref __type__ polygon, __tscalefactor__ scale) { //# pc.ForEach(i => { polygon.P__i__ *= scale; //# }); } /// /// Returns a copy of the scaled by the given factor. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Scaled(this __type__ polygon, __tscalefactor__ scale) { var result = new __type__(/*# pc.ForEach(i => {*/polygon.P__i__/*#}, comma);*/); result.Scale(scale); return result; } /// /// Scales the by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Scale(this ref __type__ polygon, __tvec__ center, __tscalefactor__ scale) { //# pc.ForEach(i => { polygon.P__i__ = center + (polygon.P__i__ - center) * scale; //# }); } /// /// Returns a copy of the scaled by the given factor about the given center. /// /// The to scale. /// The scaling center. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Scaled(this __type__ polygon, __tvec__ center, __tscalefactor__ scale) { var result = new __type__(/*# pc.ForEach(i => {*/polygon.P__i__/*#}, comma);*/); result.Scale(center, scale); return result; } /// /// Scales the by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ScaleAboutCentroid(this ref __type__ polygon, __tscalefactor__ scale) { var center = polygon.ComputeCentroid(); polygon.Scale(center, scale); } /// /// Returns a copy of the scaled by the given factor about the centroid. /// /// The to scale. /// The scale factor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ ScaledAboutCentroid(this __type__ polygon, __tscalefactor__ scale) { var result = new __type__(/*# pc.ForEach(i => {*/polygon.P__i__/*#}, comma);*/); result.ScaleAboutCentroid(scale); return result; } //# } //# var transforms = new string [] { tmat1, teucl, tsimi, taffi, tshif, trot, tscale, tmat }; //# for (int j = 0; j < transforms.Length; j++) { //# var ttrafo = transforms[j]; //# var transform = (j < 4) ? "TransformPos" : "Transform"; //# var hasInv = (j != 0 && j != 3 && j != 7); /// /// Transforms the by the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transform(this ref __type__ polygon, __ttrafo__ t) { //# pc.ForEach(i => { polygon.P__i__ = t.__transform__(polygon.P__i__); //# }); } /// /// Returns a copy of the transformed by the given transformation. /// /// The __type__ to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Transformed(this __type__ polygon, __ttrafo__ t) { var result = new __type__(/*# pc.ForEach(i => {*/polygon.P__i__/*#}, comma);*/); result.Transform(t); return result; } //# if (hasInv) { /// /// Transforms the by the inverse of the given transformation. /// /// The to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvTransform(this ref __type__ polygon, __ttrafo__ t) { //# pc.ForEach(i => { polygon.P__i__ = t.Inv__transform__(polygon.P__i__); //# }); } /// /// Returns a copy of the transformed by the inverse of the given transformation. /// /// The __type__ to transform. /// The transformation to apply. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ InvTransformed(this __type__ polygon, __ttrafo__ t) { var result = new __type__(/*# pc.ForEach(i => {*/polygon.P__i__/*#}, comma);*/); result.InvTransform(t); return result; } //# } //# } #endregion public static __tvec__[] GetPointArray(this __type__ __name__) { var pa = new __tvec__[__pc__]; //# pc.ForEach(i => { pa[__i__] = __name__.P__i__; //# }); return pa; } public static __tvec__ ComputeCentroid(this __type__ __name__) { return __scale__ * (/*# pc.ForEach(i => { */__name__.P__i__/*# }, Sep(" + ")); */); } } #endregion //# } // !isPoly //# } // isIndexed //# } // pc //# } // d //# } // isDouble //# } // POLYGONS } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Hull/Hull2_auto.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Hull2f /// /// A hull is an alternative representation of a convex polygon. /// public partial struct Hull2f : IEquatable, IValidity { public Plane2f[] PlaneArray; #region Constructors /// /// Create an empty Hull3d with count planes. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull2f(int count) { PlaneArray = new Plane2f[count]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull2f(Plane2f[] planeArray) { PlaneArray = planeArray; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull2f(Box2f box) { PlaneArray = new[] { new Plane2f(V2f.XAxis, box.Min), new Plane2f(V2f.YAxis, box.Min), new Plane2f(-V2f.XAxis, box.Max), new Plane2f(-V2f.YAxis, box.Max), }; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull2f(Hull2f hull) { PlaneArray = hull.PlaneArray.Copy(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull2f(Hull2d hull) { PlaneArray = hull.PlaneArray.Map(p => new Plane2f(p)); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Hull2f(Hull2d h) => new Hull2f(h); #endregion #region Constants public static Hull2f Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Hull2f(null); } #endregion #region Properties public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray != null; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray == null; } public readonly int PlaneCount { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray.Length; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Hull2f a, Hull2f b) => a.Equals(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Hull2f a, Hull2f b) => !a.Equals(b); #endregion #region Override [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() { if (PlaneArray == null || PlaneArray.Length == 0) return 0; var h = PlaneArray[0].GetHashCode(); for (var i = 1; i < PlaneArray.Length; i++) HashCode.GetCombined(h, PlaneArray[i].GetHashCode()); return h; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Hull2f other) { if (PlaneArray == null || other.PlaneArray == null) return false; for (var i = 0; i < PlaneArray.Length; i++) if (PlaneArray[i] != other.PlaneArray[i]) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Hull2f o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => PlaneArray != null ? string.Format(CultureInfo.InvariantCulture, "[{0}]", string.Join(",", PlaneArray.Map(x => x.ToString()))) : "[null]" ; /// /// Parses Hull2f from a string created with Hull2f.ToString(). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Hull2f Parse(string s) { if (s == "[null]") return Hull2f.Invalid; var planes = s.NestedBracketSplitLevelOne().Select(Plane2f.Parse).ToArray(); return new Hull2f(planes); } #endregion #region Transformation public readonly Hull2f Transformed(Trafo2f trafo) { int count = PlaneCount; var hull = new Hull2f(new Plane2f[count]); var invTr = trafo.Backward.Transposed; for (int i = 0; i < count; i++) hull.PlaneArray[i] = new Plane2f( invTr.TransformDir(PlaneArray[i].Normal).Normalized, trafo.Forward.TransformPos(PlaneArray[i].Point)); return hull; } public readonly void TransformInto(Trafo2f trafo, ref Hull2f hull) { int count = PlaneCount; var invTr = trafo.Backward.Transposed; for (int i = 0; i < count; i++) hull.PlaneArray[i] = new Plane2f( invTr.TransformDir(PlaneArray[i].Normal).Normalized, trafo.Forward.TransformPos(PlaneArray[i].Point)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Hull2f Reversed() => new Hull2f(PlaneArray.Map(p => p.Reversed)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void Reverse() => PlaneArray.Apply(p => p.Reversed); #endregion } public static class Hull2fExtensions { /// /// Creates an inward hull (i.e. a hull whose normal vectors point /// inside) from a counter-clockwise enumerated array of polygon /// points. /// public static Hull2f ToInwardHull(this V2f[] polygon, int pointCount = 0) { if (pointCount == 0) pointCount = polygon.Length; var planeArray = new Plane2f[pointCount]; var p0 = polygon[pointCount - 1]; for (int i = 0; i < pointCount; i++) { var p1 = polygon[i]; planeArray[i] = new Plane2f((p1 - p0).Rot90.Normalized, p0); p0 = p1; } return new Hull2f(planeArray); } /// /// Returns true if the supplied point is inside a hull with /// planes whose normal vectors point to the inside of the hull. /// The optional offset parameter is measured in normal direction, /// i.e. a positive offset makes the hull smaller. /// public static bool IsInsideInwardHull(this V2f point, Hull2f hull, float offset = 0) { for (int i = 0; i < hull.PlaneCount; i++) if (hull.PlaneArray[i].Height(point) < offset) return false; return true; } /// /// Returns unordered set of corners of this hull. /// public static HashSet ComputeCorners(this Hull2f hull) { var corners = new HashSet(); int count = hull.PlaneArray.Length; for (var i0 = 0; i0 < count; i0++) { for (var i1 = i0 + 1; i1 < count; i1++) { if (hull.PlaneArray[i0].Intersects(hull.PlaneArray[i1], out V2f temp)) { if (temp.IsNaN || temp.AnyInfinity) continue; var inside = true; for (var j = 0; j < count; j++) { if (j == i0 || j == i1) continue; var h = hull.PlaneArray[j].Height(temp); if (h > 0) { inside = false; break; } } if (inside) { corners.Add(temp); } } } } return corners; } } #endregion #region Hull2d /// /// A hull is an alternative representation of a convex polygon. /// public partial struct Hull2d : IEquatable, IValidity { public Plane2d[] PlaneArray; #region Constructors /// /// Create an empty Hull3d with count planes. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull2d(int count) { PlaneArray = new Plane2d[count]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull2d(Plane2d[] planeArray) { PlaneArray = planeArray; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull2d(Box2d box) { PlaneArray = new[] { new Plane2d(V2d.XAxis, box.Min), new Plane2d(V2d.YAxis, box.Min), new Plane2d(-V2d.XAxis, box.Max), new Plane2d(-V2d.YAxis, box.Max), }; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull2d(Hull2d hull) { PlaneArray = hull.PlaneArray.Copy(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull2d(Hull2f hull) { PlaneArray = hull.PlaneArray.Map(p => new Plane2d(p)); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Hull2d(Hull2f h) => new Hull2d(h); #endregion #region Constants public static Hull2d Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Hull2d(null); } #endregion #region Properties public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray != null; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray == null; } public readonly int PlaneCount { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray.Length; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Hull2d a, Hull2d b) => a.Equals(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Hull2d a, Hull2d b) => !a.Equals(b); #endregion #region Override [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() { if (PlaneArray == null || PlaneArray.Length == 0) return 0; var h = PlaneArray[0].GetHashCode(); for (var i = 1; i < PlaneArray.Length; i++) HashCode.GetCombined(h, PlaneArray[i].GetHashCode()); return h; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Hull2d other) { if (PlaneArray == null || other.PlaneArray == null) return false; for (var i = 0; i < PlaneArray.Length; i++) if (PlaneArray[i] != other.PlaneArray[i]) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Hull2d o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => PlaneArray != null ? string.Format(CultureInfo.InvariantCulture, "[{0}]", string.Join(",", PlaneArray.Map(x => x.ToString()))) : "[null]" ; /// /// Parses Hull2d from a string created with Hull2d.ToString(). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Hull2d Parse(string s) { if (s == "[null]") return Hull2d.Invalid; var planes = s.NestedBracketSplitLevelOne().Select(Plane2d.Parse).ToArray(); return new Hull2d(planes); } #endregion #region Transformation public readonly Hull2d Transformed(Trafo2d trafo) { int count = PlaneCount; var hull = new Hull2d(new Plane2d[count]); var invTr = trafo.Backward.Transposed; for (int i = 0; i < count; i++) hull.PlaneArray[i] = new Plane2d( invTr.TransformDir(PlaneArray[i].Normal).Normalized, trafo.Forward.TransformPos(PlaneArray[i].Point)); return hull; } public readonly void TransformInto(Trafo2d trafo, ref Hull2d hull) { int count = PlaneCount; var invTr = trafo.Backward.Transposed; for (int i = 0; i < count; i++) hull.PlaneArray[i] = new Plane2d( invTr.TransformDir(PlaneArray[i].Normal).Normalized, trafo.Forward.TransformPos(PlaneArray[i].Point)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Hull2d Reversed() => new Hull2d(PlaneArray.Map(p => p.Reversed)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void Reverse() => PlaneArray.Apply(p => p.Reversed); #endregion } public static class Hull2dExtensions { /// /// Creates an inward hull (i.e. a hull whose normal vectors point /// inside) from a counter-clockwise enumerated array of polygon /// points. /// public static Hull2d ToInwardHull(this V2d[] polygon, int pointCount = 0) { if (pointCount == 0) pointCount = polygon.Length; var planeArray = new Plane2d[pointCount]; var p0 = polygon[pointCount - 1]; for (int i = 0; i < pointCount; i++) { var p1 = polygon[i]; planeArray[i] = new Plane2d((p1 - p0).Rot90.Normalized, p0); p0 = p1; } return new Hull2d(planeArray); } /// /// Returns true if the supplied point is inside a hull with /// planes whose normal vectors point to the inside of the hull. /// The optional offset parameter is measured in normal direction, /// i.e. a positive offset makes the hull smaller. /// public static bool IsInsideInwardHull(this V2d point, Hull2d hull, double offset = 0) { for (int i = 0; i < hull.PlaneCount; i++) if (hull.PlaneArray[i].Height(point) < offset) return false; return true; } /// /// Returns unordered set of corners of this hull. /// public static HashSet ComputeCorners(this Hull2d hull) { var corners = new HashSet(); int count = hull.PlaneArray.Length; for (var i0 = 0; i0 < count; i0++) { for (var i1 = i0 + 1; i1 < count; i1++) { if (hull.PlaneArray[i0].Intersects(hull.PlaneArray[i1], out V2d temp)) { if (temp.IsNaN || temp.AnyInfinity) continue; var inside = true; for (var j = 0; j < count; j++) { if (j == i0 || j == i1) continue; var h = hull.PlaneArray[j].Height(temp); if (h > 0) { inside = false; break; } } if (inside) { corners.Add(temp); } } } } return corners; } } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Hull/Hull2_template.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Hull2" + tc; //# var type2 = "Hull2" + tc2; //# var v2t = "V2" + tc; //# var box2t = "Box2" + tc; //# var plane2t = "Plane2" + tc; //# var plane2t2 = "Plane2" + tc2; //# var trafo2t = "Trafo2" + tc; //# var iboundingbox = "IBoundingBox2" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var pi = isDouble ? "Constant.Pi" : "ConstantF.Pi"; #region __type__ /// /// A hull is an alternative representation of a convex polygon. /// public partial struct __type__ : IEquatable<__type__>, IValidity { public __plane2t__[] PlaneArray; #region Constructors /// /// Create an empty Hull3d with count planes. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(int count) { PlaneArray = new __plane2t__[count]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__plane2t__[] planeArray) { PlaneArray = planeArray; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__box2t__ box) { PlaneArray = new[] { new __plane2t__(__v2t__.XAxis, box.Min), new __plane2t__(__v2t__.YAxis, box.Min), new __plane2t__(-__v2t__.XAxis, box.Max), new __plane2t__(-__v2t__.YAxis, box.Max), }; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ hull) { PlaneArray = hull.PlaneArray.Copy(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ hull) { PlaneArray = hull.PlaneArray.Map(p => new __plane2t__(p)); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type__(__type2__ h) => new __type__(h); #endregion #region Constants public static __type__ Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(null); } #endregion #region Properties public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray != null; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray == null; } public readonly int PlaneCount { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray.Length; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ a, __type__ b) => a.Equals(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ a, __type__ b) => !a.Equals(b); #endregion #region Override [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() { if (PlaneArray == null || PlaneArray.Length == 0) return 0; var h = PlaneArray[0].GetHashCode(); for (var i = 1; i < PlaneArray.Length; i++) HashCode.GetCombined(h, PlaneArray[i].GetHashCode()); return h; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) { if (PlaneArray == null || other.PlaneArray == null) return false; for (var i = 0; i < PlaneArray.Length; i++) if (PlaneArray[i] != other.PlaneArray[i]) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => PlaneArray != null ? string.Format(CultureInfo.InvariantCulture, "[{0}]", string.Join(",", PlaneArray.Map(x => x.ToString()))) : "[null]" ; /// /// Parses __type__ from a string created with __type__.ToString(). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Parse(string s) { if (s == "[null]") return __type__.Invalid; var planes = s.NestedBracketSplitLevelOne().Select(__plane2t__.Parse).ToArray(); return new __type__(planes); } #endregion #region Transformation public readonly __type__ Transformed(__trafo2t__ trafo) { int count = PlaneCount; var hull = new __type__(new __plane2t__[count]); var invTr = trafo.Backward.Transposed; for (int i = 0; i < count; i++) hull.PlaneArray[i] = new __plane2t__( invTr.TransformDir(PlaneArray[i].Normal).Normalized, trafo.Forward.TransformPos(PlaneArray[i].Point)); return hull; } public readonly void TransformInto(__trafo2t__ trafo, ref __type__ hull) { int count = PlaneCount; var invTr = trafo.Backward.Transposed; for (int i = 0; i < count; i++) hull.PlaneArray[i] = new __plane2t__( invTr.TransformDir(PlaneArray[i].Normal).Normalized, trafo.Forward.TransformPos(PlaneArray[i].Point)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ Reversed() => new __type__(PlaneArray.Map(p => p.Reversed)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void Reverse() => PlaneArray.Apply(p => p.Reversed); #endregion } public static class __type__Extensions { /// /// Creates an inward hull (i.e. a hull whose normal vectors point /// inside) from a counter-clockwise enumerated array of polygon /// points. /// public static __type__ ToInwardHull(this __v2t__[] polygon, int pointCount = 0) { if (pointCount == 0) pointCount = polygon.Length; var planeArray = new __plane2t__[pointCount]; var p0 = polygon[pointCount - 1]; for (int i = 0; i < pointCount; i++) { var p1 = polygon[i]; planeArray[i] = new __plane2t__((p1 - p0).Rot90.Normalized, p0); p0 = p1; } return new __type__(planeArray); } /// /// Returns true if the supplied point is inside a hull with /// planes whose normal vectors point to the inside of the hull. /// The optional offset parameter is measured in normal direction, /// i.e. a positive offset makes the hull smaller. /// public static bool IsInsideInwardHull(this __v2t__ point, __type__ hull, __ftype__ offset = 0) { for (int i = 0; i < hull.PlaneCount; i++) if (hull.PlaneArray[i].Height(point) < offset) return false; return true; } /// /// Returns unordered set of corners of this hull. /// public static HashSet<__v2t__> ComputeCorners(this __type__ hull) { var corners = new HashSet<__v2t__>(); int count = hull.PlaneArray.Length; for (var i0 = 0; i0 < count; i0++) { for (var i1 = i0 + 1; i1 < count; i1++) { if (hull.PlaneArray[i0].Intersects(hull.PlaneArray[i1], out __v2t__ temp)) { if (temp.IsNaN || temp.AnyInfinity) continue; var inside = true; for (var j = 0; j < count; j++) { if (j == i0 || j == i1) continue; var h = hull.PlaneArray[j].Height(temp); if (h > 0) { inside = false; break; } } if (inside) { corners.Add(temp); } } } } return corners; } } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Hull/Hull3_auto.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! public static class Hull { #region Flags32 [Flags] public enum Flags32 { None = 0x00000000, Plane00 = 0x00000001, Plane01 = 0x00000002, Plane02 = 0x00000004, Plane03 = 0x00000008, Plane04 = 0x00000010, Plane05 = 0x00000020, Plane06 = 0x00000040, Plane07 = 0x00000080, Plane08 = 0x00000100, Plane09 = 0x00000200, Plane10 = 0x00000400, Plane11 = 0x00000800, Plane12 = 0x00001000, Plane13 = 0x00002000, Plane14 = 0x00004000, Plane15 = 0x00008000, Plane16 = 0x00010000, Plane17 = 0x00020000, Plane18 = 0x00040000, Plane19 = 0x00080000, Plane20 = 0x00100000, Plane21 = 0x00200000, Plane22 = 0x00400000, Plane23 = 0x00800000, Plane24 = 0x01000000, Plane25 = 0x02000000, Plane26 = 0x04000000, Plane27 = 0x08000000, Plane28 = 0x10000000, Plane29 = 0x20000000, Plane30 = 0x40000000, Plane31 = (int)-0x80000000, } public static Flags32 OrPlane(this Flags32 flags, int i) { return flags | (Flags32)((int)flags | (int)Flags32.Plane00 << i); } public static Flags32 AndNotPlane(this Flags32 flags, int i) { return flags & (Flags32)~((int)flags | (int)Flags32.Plane00 << i); } #endregion } #region Hull3f /// /// A hull is a set of planes that bounds a convex polyhedron. /// Normals are expected to point outside. /// public partial struct Hull3f : IEquatable, IValidity { public Plane3f[] PlaneArray; #region Constructors /// /// Create an empty Hull3f with count planes. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull3f(int count) { PlaneArray = new Plane3f[count]; } /// /// Creates a Hull3f from the given planes. /// The plane normals are expected to point outside. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull3f(Plane3f[] planes) { PlaneArray = planes; } /// /// Creates a Hull3f from the given box where plane normals point outside. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull3f(Box3f box) { PlaneArray = new[] { new Plane3f(-V3f.XAxis, box.Min), new Plane3f(-V3f.YAxis, box.Min), new Plane3f(-V3f.ZAxis, box.Min), new Plane3f(V3f.XAxis, box.Max), new Plane3f(V3f.YAxis, box.Max), new Plane3f(V3f.ZAxis, box.Max) }; } /// /// Creates a Hull3f from another Hull3f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull3f(Hull3f hull) { PlaneArray = hull.PlaneArray.Copy(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull3f(Hull3d hull) { PlaneArray = hull.PlaneArray.Map(p => new Plane3f(p)); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Hull3f(Hull3d h) => new Hull3f(h); #endregion #region Constants public static Hull3f Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Hull3f(null); } #endregion #region Properties public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray != null; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray == null; } public readonly int PlaneCount { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray.Length; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Hull3f a, Hull3f b) => a.Equals(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Hull3f a, Hull3f b) => !a.Equals(b); #endregion #region Override [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() { if (PlaneArray == null || PlaneArray.Length == 0) return 0; var h = PlaneArray[0].GetHashCode(); for (var i = 1; i < PlaneArray.Length; i++) HashCode.GetCombined(h, PlaneArray[i].GetHashCode()); return h; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Hull3f other) { if (PlaneArray == null || other.PlaneArray == null) return false; for (var i = 0; i < PlaneArray.Length; i++) if (PlaneArray[i] != other.PlaneArray[i]) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Hull3f o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => PlaneArray != null ? string.Format(CultureInfo.InvariantCulture, "[{0}]", string.Join(",", PlaneArray.Map(x => x.ToString()))) : "[null]" ; /// /// Parses Hull3f from a string created with Hull3f.ToString(). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Hull3f Parse(string s) { if (s == "[null]") return Hull3f.Invalid; var planes = s.NestedBracketSplitLevelOne().Select(Plane3f.Parse).ToArray(); return new Hull3f(planes); } #endregion #region Transformation public readonly Hull3f Transformed(Trafo3f trafo) { int count = PlaneCount; var hull = new Hull3f(count); var invTr = trafo.Backward.Transposed; for (int i = 0; i < count; i++) hull.PlaneArray[i] = new Plane3f( invTr.TransformDir(PlaneArray[i].Normal).Normalized, trafo.Forward.TransformPos(PlaneArray[i].Point)); return hull; } public readonly void TransformInto(Trafo3f trafo, ref Hull3f hull) { int count = PlaneCount; var invTr = trafo.Backward.Transposed; for (int i = 0; i < count; i++) hull.PlaneArray[i] = new Plane3f( invTr.TransformDir(PlaneArray[i].Normal).Normalized, trafo.Forward.TransformPos(PlaneArray[i].Point)); } #endregion #region Reversal [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Hull3f Reversed() => new Hull3f(PlaneArray.Map(p => p.Reversed)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void Reverse() => PlaneArray.Apply(p => p.Reversed); #endregion } /// /// A fast hull is a set of planes bounding a convex polyhedron, /// that can be quickly tested against intersection of an axis- /// aligned bounding box. /// public struct FastHull3f { public Hull3f Hull; public int[] MinCornerIndexArray; #region Constructor /// /// Create an empty FastHull3f with count planes. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public FastHull3f(int count) { Hull = new Hull3f(count); MinCornerIndexArray = new int[count]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FastHull3f(FastHull3f fastHull) { Hull = new Hull3f(fastHull.Hull); MinCornerIndexArray = fastHull.MinCornerIndexArray.Copy(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FastHull3f(Hull3f hull) { Hull = hull; MinCornerIndexArray = ComputeMinCornerIndexArray(Hull.PlaneArray); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FastHull3f(FastHull3d fastHull) { Hull = new Hull3f(fastHull.Hull); MinCornerIndexArray = fastHull.MinCornerIndexArray.Copy(); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator FastHull3f(FastHull3d h) => new FastHull3f(h); #endregion #region Private Helper Methods private static int[] ComputeMinCornerIndexArray(Plane3f[] planeArray) { int count = planeArray.Length; var minCornerIndices = new int[count]; for (int pi = 0; pi < count; pi++) { int minCorner = 0; if (planeArray[pi].Normal.X < 0) minCorner |= 1; if (planeArray[pi].Normal.Y < 0) minCorner |= 2; if (planeArray[pi].Normal.Z < 0) minCorner |= 4; minCornerIndices[pi] = minCorner; } return minCornerIndices; } private static void ComputeMinCornerIndexArrayInto( Plane3f[] planeArray, int[] minCornerIndexArray) { int count = planeArray.Length; for (int pi = 0; pi < count; pi++) { int minCorner = 0; if (planeArray[pi].Normal.X < 0) minCorner |= 1; if (planeArray[pi].Normal.Y < 0) minCorner |= 2; if (planeArray[pi].Normal.Z < 0) minCorner |= 4; minCornerIndexArray[pi] = minCorner; } } #endregion #region Intersection Methods /// /// Test hull against intersection of the supplied bounding box /// specified by an array of its eight corner vertices, that must /// be ordered as returned by the /// call of the axis aligned bounding box. The avaibility of this /// corner array slightly improves the performance of the test. /// Note that this is a conservative test, since in some cases /// around the edges of the hull it may return true although the /// hull does not intersect the box. /// public readonly bool IntersectsAxisAlignedBox( V3f[] corners) { var planes = Hull.PlaneArray; int count = planes.Length; bool intersecting = false; for (int pi = 0; pi < count; pi++) { int minCornerIndex = MinCornerIndexArray[pi]; if (planes[pi].Height(corners[minCornerIndex]) > 0) return false; if (planes[pi].Height(corners[minCornerIndex ^ 7]) >= 0) intersecting = true; } if (intersecting) return true; return true; } #endregion #region Transformations public readonly FastHull3f Transformed(Trafo3f trafo) { var newFastHull = new FastHull3f() { Hull = this.Hull.Transformed(trafo) }; newFastHull.MinCornerIndexArray = ComputeMinCornerIndexArray(newFastHull.Hull.PlaneArray); return newFastHull; } public readonly void TransformInto(Trafo3f trafo, ref FastHull3f fastHull) { Hull.TransformInto(trafo, ref fastHull.Hull); ComputeMinCornerIndexArrayInto(fastHull.Hull.PlaneArray, fastHull.MinCornerIndexArray); } #endregion } public static class Hull3fExtensions { /// /// Returns unordered set of corners of this hull. /// public static HashSet ComputeCorners(this Hull3f hull) { var corners = new HashSet(); int count = hull.PlaneArray.Length; for (var i0 = 0; i0 < count; i0++) { for (var i1 = i0 + 1; i1 < count; i1++) { for (var i2 = i1 + 1; i2 < count; i2++) { if (hull.PlaneArray[i0].Intersects(hull.PlaneArray[i1], hull.PlaneArray[i2], out V3f temp)) { if (temp.IsNaN || temp.AnyInfinity) continue; var inside = true; for (var j = 0; j < count; j++) { if (j == i0 || j == i1 || j == i2) continue; var h = hull.PlaneArray[j].Height(temp); if (h > 0) { inside = false; break; } } if (inside) { corners.Add(temp); } } } } } return corners; } } #endregion #region Hull3d /// /// A hull is a set of planes that bounds a convex polyhedron. /// Normals are expected to point outside. /// public partial struct Hull3d : IEquatable, IValidity { public Plane3d[] PlaneArray; #region Constructors /// /// Create an empty Hull3d with count planes. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull3d(int count) { PlaneArray = new Plane3d[count]; } /// /// Creates a Hull3d from the given planes. /// The plane normals are expected to point outside. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull3d(Plane3d[] planes) { PlaneArray = planes; } /// /// Creates a Hull3d from the given box where plane normals point outside. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull3d(Box3d box) { PlaneArray = new[] { new Plane3d(-V3d.XAxis, box.Min), new Plane3d(-V3d.YAxis, box.Min), new Plane3d(-V3d.ZAxis, box.Min), new Plane3d(V3d.XAxis, box.Max), new Plane3d(V3d.YAxis, box.Max), new Plane3d(V3d.ZAxis, box.Max) }; } /// /// Creates a Hull3d from another Hull3d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull3d(Hull3d hull) { PlaneArray = hull.PlaneArray.Copy(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hull3d(Hull3f hull) { PlaneArray = hull.PlaneArray.Map(p => new Plane3d(p)); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Hull3d(Hull3f h) => new Hull3d(h); #endregion #region Constants public static Hull3d Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Hull3d(null); } #endregion #region Properties public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray != null; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray == null; } public readonly int PlaneCount { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray.Length; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Hull3d a, Hull3d b) => a.Equals(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Hull3d a, Hull3d b) => !a.Equals(b); #endregion #region Override [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() { if (PlaneArray == null || PlaneArray.Length == 0) return 0; var h = PlaneArray[0].GetHashCode(); for (var i = 1; i < PlaneArray.Length; i++) HashCode.GetCombined(h, PlaneArray[i].GetHashCode()); return h; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Hull3d other) { if (PlaneArray == null || other.PlaneArray == null) return false; for (var i = 0; i < PlaneArray.Length; i++) if (PlaneArray[i] != other.PlaneArray[i]) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Hull3d o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => PlaneArray != null ? string.Format(CultureInfo.InvariantCulture, "[{0}]", string.Join(",", PlaneArray.Map(x => x.ToString()))) : "[null]" ; /// /// Parses Hull3d from a string created with Hull3d.ToString(). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Hull3d Parse(string s) { if (s == "[null]") return Hull3d.Invalid; var planes = s.NestedBracketSplitLevelOne().Select(Plane3d.Parse).ToArray(); return new Hull3d(planes); } #endregion #region Transformation public readonly Hull3d Transformed(Trafo3d trafo) { int count = PlaneCount; var hull = new Hull3d(count); var invTr = trafo.Backward.Transposed; for (int i = 0; i < count; i++) hull.PlaneArray[i] = new Plane3d( invTr.TransformDir(PlaneArray[i].Normal).Normalized, trafo.Forward.TransformPos(PlaneArray[i].Point)); return hull; } public readonly void TransformInto(Trafo3d trafo, ref Hull3d hull) { int count = PlaneCount; var invTr = trafo.Backward.Transposed; for (int i = 0; i < count; i++) hull.PlaneArray[i] = new Plane3d( invTr.TransformDir(PlaneArray[i].Normal).Normalized, trafo.Forward.TransformPos(PlaneArray[i].Point)); } #endregion #region Reversal [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Hull3d Reversed() => new Hull3d(PlaneArray.Map(p => p.Reversed)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void Reverse() => PlaneArray.Apply(p => p.Reversed); #endregion } /// /// A fast hull is a set of planes bounding a convex polyhedron, /// that can be quickly tested against intersection of an axis- /// aligned bounding box. /// public struct FastHull3d { public Hull3d Hull; public int[] MinCornerIndexArray; #region Constructor /// /// Create an empty FastHull3d with count planes. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public FastHull3d(int count) { Hull = new Hull3d(count); MinCornerIndexArray = new int[count]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FastHull3d(FastHull3d fastHull) { Hull = new Hull3d(fastHull.Hull); MinCornerIndexArray = fastHull.MinCornerIndexArray.Copy(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FastHull3d(Hull3d hull) { Hull = hull; MinCornerIndexArray = ComputeMinCornerIndexArray(Hull.PlaneArray); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FastHull3d(FastHull3f fastHull) { Hull = new Hull3d(fastHull.Hull); MinCornerIndexArray = fastHull.MinCornerIndexArray.Copy(); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator FastHull3d(FastHull3f h) => new FastHull3d(h); #endregion #region Private Helper Methods private static int[] ComputeMinCornerIndexArray(Plane3d[] planeArray) { int count = planeArray.Length; var minCornerIndices = new int[count]; for (int pi = 0; pi < count; pi++) { int minCorner = 0; if (planeArray[pi].Normal.X < 0) minCorner |= 1; if (planeArray[pi].Normal.Y < 0) minCorner |= 2; if (planeArray[pi].Normal.Z < 0) minCorner |= 4; minCornerIndices[pi] = minCorner; } return minCornerIndices; } private static void ComputeMinCornerIndexArrayInto( Plane3d[] planeArray, int[] minCornerIndexArray) { int count = planeArray.Length; for (int pi = 0; pi < count; pi++) { int minCorner = 0; if (planeArray[pi].Normal.X < 0) minCorner |= 1; if (planeArray[pi].Normal.Y < 0) minCorner |= 2; if (planeArray[pi].Normal.Z < 0) minCorner |= 4; minCornerIndexArray[pi] = minCorner; } } #endregion #region Intersection Methods /// /// Test hull against intersection of the supplied bounding box /// specified by an array of its eight corner vertices, that must /// be ordered as returned by the /// call of the axis aligned bounding box. The avaibility of this /// corner array slightly improves the performance of the test. /// Note that this is a conservative test, since in some cases /// around the edges of the hull it may return true although the /// hull does not intersect the box. /// public readonly bool IntersectsAxisAlignedBox( V3d[] corners) { var planes = Hull.PlaneArray; int count = planes.Length; bool intersecting = false; for (int pi = 0; pi < count; pi++) { int minCornerIndex = MinCornerIndexArray[pi]; if (planes[pi].Height(corners[minCornerIndex]) > 0) return false; if (planes[pi].Height(corners[minCornerIndex ^ 7]) >= 0) intersecting = true; } if (intersecting) return true; return true; } #endregion #region Transformations public readonly FastHull3d Transformed(Trafo3d trafo) { var newFastHull = new FastHull3d() { Hull = this.Hull.Transformed(trafo) }; newFastHull.MinCornerIndexArray = ComputeMinCornerIndexArray(newFastHull.Hull.PlaneArray); return newFastHull; } public readonly void TransformInto(Trafo3d trafo, ref FastHull3d fastHull) { Hull.TransformInto(trafo, ref fastHull.Hull); ComputeMinCornerIndexArrayInto(fastHull.Hull.PlaneArray, fastHull.MinCornerIndexArray); } #endregion } public static class Hull3dExtensions { /// /// Returns unordered set of corners of this hull. /// public static HashSet ComputeCorners(this Hull3d hull) { var corners = new HashSet(); int count = hull.PlaneArray.Length; for (var i0 = 0; i0 < count; i0++) { for (var i1 = i0 + 1; i1 < count; i1++) { for (var i2 = i1 + 1; i2 < count; i2++) { if (hull.PlaneArray[i0].Intersects(hull.PlaneArray[i1], hull.PlaneArray[i2], out V3d temp)) { if (temp.IsNaN || temp.AnyInfinity) continue; var inside = true; for (var j = 0; j < count; j++) { if (j == i0 || j == i1 || j == i2) continue; var h = hull.PlaneArray[j].Height(temp); if (h > 0) { inside = false; break; } } if (inside) { corners.Add(temp); } } } } } return corners; } } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Hull/Hull3_template.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! public static class Hull { #region Flags32 [Flags] public enum Flags32 { None = 0x00000000, Plane00 = 0x00000001, Plane01 = 0x00000002, Plane02 = 0x00000004, Plane03 = 0x00000008, Plane04 = 0x00000010, Plane05 = 0x00000020, Plane06 = 0x00000040, Plane07 = 0x00000080, Plane08 = 0x00000100, Plane09 = 0x00000200, Plane10 = 0x00000400, Plane11 = 0x00000800, Plane12 = 0x00001000, Plane13 = 0x00002000, Plane14 = 0x00004000, Plane15 = 0x00008000, Plane16 = 0x00010000, Plane17 = 0x00020000, Plane18 = 0x00040000, Plane19 = 0x00080000, Plane20 = 0x00100000, Plane21 = 0x00200000, Plane22 = 0x00400000, Plane23 = 0x00800000, Plane24 = 0x01000000, Plane25 = 0x02000000, Plane26 = 0x04000000, Plane27 = 0x08000000, Plane28 = 0x10000000, Plane29 = 0x20000000, Plane30 = 0x40000000, Plane31 = (int)-0x80000000, } public static Flags32 OrPlane(this Flags32 flags, int i) { return flags | (Flags32)((int)flags | (int)Flags32.Plane00 << i); } public static Flags32 AndNotPlane(this Flags32 flags, int i) { return flags & (Flags32)~((int)flags | (int)Flags32.Plane00 << i); } #endregion } //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Hull3" + tc; //# var type2 = "Hull3" + tc2; //# var v3t = "V3" + tc; //# var box3t = "Box3" + tc; //# var plane3t = "Plane3" + tc; //# var trafo3t = "Trafo3" + tc; //# var iboundingbox = "IBoundingBox3" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var dotnine = isDouble ? "0.9" : "0.9f"; //# var constant = isDouble ? "Constant" : "ConstantF"; #region __type__ /// /// A hull is a set of planes that bounds a convex polyhedron. /// Normals are expected to point outside. /// public partial struct __type__ : IEquatable<__type__>, IValidity { public __plane3t__[] PlaneArray; #region Constructors /// /// Create an empty __type__ with count planes. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(int count) { PlaneArray = new __plane3t__[count]; } /// /// Creates a __type__ from the given planes. /// The plane normals are expected to point outside. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__plane3t__[] planes) { PlaneArray = planes; } /// /// Creates a __type__ from the given box where plane normals point outside. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__box3t__ box) { PlaneArray = new[] { new __plane3t__(-__v3t__.XAxis, box.Min), new __plane3t__(-__v3t__.YAxis, box.Min), new __plane3t__(-__v3t__.ZAxis, box.Min), new __plane3t__(__v3t__.XAxis, box.Max), new __plane3t__(__v3t__.YAxis, box.Max), new __plane3t__(__v3t__.ZAxis, box.Max) }; } /// /// Creates a __type__ from another __type__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ hull) { PlaneArray = hull.PlaneArray.Copy(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ hull) { PlaneArray = hull.PlaneArray.Map(p => new __plane3t__(p)); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type__(__type2__ h) => new __type__(h); #endregion #region Constants public static __type__ Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(null); } #endregion #region Properties public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray != null; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray == null; } public readonly int PlaneCount { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => PlaneArray.Length; } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ a, __type__ b) => a.Equals(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ a, __type__ b) => !a.Equals(b); #endregion #region Override [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() { if (PlaneArray == null || PlaneArray.Length == 0) return 0; var h = PlaneArray[0].GetHashCode(); for (var i = 1; i < PlaneArray.Length; i++) HashCode.GetCombined(h, PlaneArray[i].GetHashCode()); return h; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) { if (PlaneArray == null || other.PlaneArray == null) return false; for (var i = 0; i < PlaneArray.Length; i++) if (PlaneArray[i] != other.PlaneArray[i]) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => PlaneArray != null ? string.Format(CultureInfo.InvariantCulture, "[{0}]", string.Join(",", PlaneArray.Map(x => x.ToString()))) : "[null]" ; /// /// Parses __type__ from a string created with __type__.ToString(). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Parse(string s) { if (s == "[null]") return __type__.Invalid; var planes = s.NestedBracketSplitLevelOne().Select(__plane3t__.Parse).ToArray(); return new __type__(planes); } #endregion #region Transformation public readonly __type__ Transformed(__trafo3t__ trafo) { int count = PlaneCount; var hull = new __type__(count); var invTr = trafo.Backward.Transposed; for (int i = 0; i < count; i++) hull.PlaneArray[i] = new __plane3t__( invTr.TransformDir(PlaneArray[i].Normal).Normalized, trafo.Forward.TransformPos(PlaneArray[i].Point)); return hull; } public readonly void TransformInto(__trafo3t__ trafo, ref __type__ hull) { int count = PlaneCount; var invTr = trafo.Backward.Transposed; for (int i = 0; i < count; i++) hull.PlaneArray[i] = new __plane3t__( invTr.TransformDir(PlaneArray[i].Normal).Normalized, trafo.Forward.TransformPos(PlaneArray[i].Point)); } #endregion #region Reversal [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ Reversed() => new __type__(PlaneArray.Map(p => p.Reversed)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void Reverse() => PlaneArray.Apply(p => p.Reversed); #endregion } /// /// A fast hull is a set of planes bounding a convex polyhedron, /// that can be quickly tested against intersection of an axis- /// aligned bounding box. /// public struct Fast__type__ { public __type__ Hull; public int[] MinCornerIndexArray; #region Constructor /// /// Create an empty Fast__type__ with count planes. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Fast__type__(int count) { Hull = new __type__(count); MinCornerIndexArray = new int[count]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Fast__type__(Fast__type__ fastHull) { Hull = new __type__(fastHull.Hull); MinCornerIndexArray = fastHull.MinCornerIndexArray.Copy(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Fast__type__(__type__ hull) { Hull = hull; MinCornerIndexArray = ComputeMinCornerIndexArray(Hull.PlaneArray); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Fast__type__(Fast__type2__ fastHull) { Hull = new __type__(fastHull.Hull); MinCornerIndexArray = fastHull.MinCornerIndexArray.Copy(); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Fast__type__(Fast__type2__ h) => new Fast__type__(h); #endregion #region Private Helper Methods private static int[] ComputeMinCornerIndexArray(__plane3t__[] planeArray) { int count = planeArray.Length; var minCornerIndices = new int[count]; for (int pi = 0; pi < count; pi++) { int minCorner = 0; if (planeArray[pi].Normal.X < 0) minCorner |= 1; if (planeArray[pi].Normal.Y < 0) minCorner |= 2; if (planeArray[pi].Normal.Z < 0) minCorner |= 4; minCornerIndices[pi] = minCorner; } return minCornerIndices; } private static void ComputeMinCornerIndexArrayInto( __plane3t__[] planeArray, int[] minCornerIndexArray) { int count = planeArray.Length; for (int pi = 0; pi < count; pi++) { int minCorner = 0; if (planeArray[pi].Normal.X < 0) minCorner |= 1; if (planeArray[pi].Normal.Y < 0) minCorner |= 2; if (planeArray[pi].Normal.Z < 0) minCorner |= 4; minCornerIndexArray[pi] = minCorner; } } #endregion #region Intersection Methods /// /// Test hull against intersection of the supplied bounding box /// specified by an array of its eight corner vertices, that must /// be ordered as returned by the /// call of the axis aligned bounding box. The avaibility of this /// corner array slightly improves the performance of the test. /// Note that this is a conservative test, since in some cases /// around the edges of the hull it may return true although the /// hull does not intersect the box. /// public readonly bool IntersectsAxisAlignedBox( __v3t__[] corners) { var planes = Hull.PlaneArray; int count = planes.Length; bool intersecting = false; for (int pi = 0; pi < count; pi++) { int minCornerIndex = MinCornerIndexArray[pi]; if (planes[pi].Height(corners[minCornerIndex]) > 0) return false; if (planes[pi].Height(corners[minCornerIndex ^ 7]) >= 0) intersecting = true; } if (intersecting) return true; return true; } #endregion #region Transformations public readonly Fast__type__ Transformed(__trafo3t__ trafo) { var newFastHull = new Fast__type__() { Hull = this.Hull.Transformed(trafo) }; newFastHull.MinCornerIndexArray = ComputeMinCornerIndexArray(newFastHull.Hull.PlaneArray); return newFastHull; } public readonly void TransformInto(__trafo3t__ trafo, ref Fast__type__ fastHull) { Hull.TransformInto(trafo, ref fastHull.Hull); ComputeMinCornerIndexArrayInto(fastHull.Hull.PlaneArray, fastHull.MinCornerIndexArray); } #endregion } public static class __type__Extensions { /// /// Returns unordered set of corners of this hull. /// public static HashSet<__v3t__> ComputeCorners(this __type__ hull) { var corners = new HashSet<__v3t__>(); int count = hull.PlaneArray.Length; for (var i0 = 0; i0 < count; i0++) { for (var i1 = i0 + 1; i1 < count; i1++) { for (var i2 = i1 + 1; i2 < count; i2++) { if (hull.PlaneArray[i0].Intersects(hull.PlaneArray[i1], hull.PlaneArray[i2], out __v3t__ temp)) { if (temp.IsNaN || temp.AnyInfinity) continue; var inside = true; for (var j = 0; j < count; j++) { if (j == i0 || j == i1 || j == i2) continue; var h = hull.PlaneArray[j].Height(temp); if (h > 0) { inside = false; break; } } if (inside) { corners.Add(temp); } } } } } return corners; } } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Line/Line2_auto.cs ================================================ using System.Xml.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Line2f /// /// A two dimensional line with specified start and end points. /// public partial struct Line2f : IBoundingCircle2f { #region Geometric Properties public readonly V2f Center => (P0 + P1) * 0.5f; /// /// P0 /// [XmlIgnore] public V2f Origin { readonly get { return P0; } set { P0 = value; } } /// /// P1 - P0 /// [XmlIgnore] public V2f Direction { readonly get { return P1 - P0; } set { P1 = P0 + value; } } public readonly Ray2f Ray2f => new Ray2f(P0, P1 - P0); public readonly Plane2f Plane2f => Ray2f.Plane2f; public readonly float LeftValueOfDir(V2f v) => v.X * (P0.Y - P1.Y) + v.Y * (P1.X - P0.X); public readonly float RightValueOfDir(V2f v) => v.X * (P1.Y - P0.Y) + v.Y * (P0.X - P1.X); public readonly float LeftValueOfPos(V2f p) => (p.X - P0.X) * (P0.Y - P1.Y) + (p.Y - P0.Y) * (P1.X - P0.X); public readonly float RightValueOfPos(V2f p) => (p.X - P0.X) * (P1.Y - P0.Y) + (p.Y - P0.Y) * (P0.X - P1.X); public readonly bool IsDegenerated => Direction.AllTiny; #endregion #region IBoundingCircle2f Members public readonly Circle2f BoundingCircle2f => new Circle2f(Center, 0.5f * Direction.Length); #endregion #region Geometric Computations public readonly V2f GetClosestPointOnLine(V2f p) { var d = P0 - P1; var l = d.LengthSquared; if(Fun.IsTiny(l)) return P0; //it does not matter which of the two points we choose var t = (P0.Dot(d) - p.Dot(d)) / l; //parametric distance from P0 to P1, where closest point to p is if (t <= 0) return P0; if (t >= 1) return P1; return P0 - t * d; } public readonly float GetDistanceToLine(V2f p) { var f = GetClosestPointOnLine(p); return (f - p).Length; } public readonly bool IsDistanceToPointSmallerThan(V2f p, float maxDist) { //speed-up by first checking the bounding box var box = BoundingBox2f; box.EnlargeBy(maxDist); if (!box.Contains(p)) return false; return GetDistanceToLine(p) <= maxDist; } public readonly Line2f Flipped => new Line2f(P1, P0); #endregion /// /// Returns true if points a, b and c are exactly collinear. /// public static bool IsCollinear(V2f a, V2f b, V2f c) => (b.Y - a.Y) * (c.X - b.X) == (c.Y - b.Y) * (b.X - a.X); /// /// Returns true if points a, b and c are collinear within eps. /// public static bool IsCollinear(V2f a, V2f b, V2f c, float eps = 1e-5f) => Fun.ApproximateEquals((b.Y - a.Y) * (c.X - b.X), (c.Y - b.Y) * (b.X - a.X), eps); } #endregion #region Line2d /// /// A two dimensional line with specified start and end points. /// public partial struct Line2d : IBoundingCircle2d { #region Geometric Properties public readonly V2d Center => (P0 + P1) * 0.5; /// /// P0 /// [XmlIgnore] public V2d Origin { readonly get { return P0; } set { P0 = value; } } /// /// P1 - P0 /// [XmlIgnore] public V2d Direction { readonly get { return P1 - P0; } set { P1 = P0 + value; } } public readonly Ray2d Ray2d => new Ray2d(P0, P1 - P0); public readonly Plane2d Plane2d => Ray2d.Plane2d; public readonly double LeftValueOfDir(V2d v) => v.X * (P0.Y - P1.Y) + v.Y * (P1.X - P0.X); public readonly double RightValueOfDir(V2d v) => v.X * (P1.Y - P0.Y) + v.Y * (P0.X - P1.X); public readonly double LeftValueOfPos(V2d p) => (p.X - P0.X) * (P0.Y - P1.Y) + (p.Y - P0.Y) * (P1.X - P0.X); public readonly double RightValueOfPos(V2d p) => (p.X - P0.X) * (P1.Y - P0.Y) + (p.Y - P0.Y) * (P0.X - P1.X); public readonly bool IsDegenerated => Direction.AllTiny; #endregion #region IBoundingCircle2d Members public readonly Circle2d BoundingCircle2d => new Circle2d(Center, 0.5 * Direction.Length); #endregion #region Geometric Computations public readonly V2d GetClosestPointOnLine(V2d p) { var d = P0 - P1; var l = d.LengthSquared; if(Fun.IsTiny(l)) return P0; //it does not matter which of the two points we choose var t = (P0.Dot(d) - p.Dot(d)) / l; //parametric distance from P0 to P1, where closest point to p is if (t <= 0) return P0; if (t >= 1) return P1; return P0 - t * d; } public readonly double GetDistanceToLine(V2d p) { var f = GetClosestPointOnLine(p); return (f - p).Length; } public readonly bool IsDistanceToPointSmallerThan(V2d p, double maxDist) { //speed-up by first checking the bounding box var box = BoundingBox2d; box.EnlargeBy(maxDist); if (!box.Contains(p)) return false; return GetDistanceToLine(p) <= maxDist; } public readonly Line2d Flipped => new Line2d(P1, P0); #endregion /// /// Returns true if points a, b and c are exactly collinear. /// public static bool IsCollinear(V2d a, V2d b, V2d c) => (b.Y - a.Y) * (c.X - b.X) == (c.Y - b.Y) * (b.X - a.X); /// /// Returns true if points a, b and c are collinear within eps. /// public static bool IsCollinear(V2d a, V2d b, V2d c, double eps = 1e-9) => Fun.ApproximateEquals((b.Y - a.Y) * (c.X - b.X), (c.Y - b.Y) * (b.X - a.X), eps); } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Line/Line2_template.cs ================================================ using System.Xml.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Line2" + tc; //# var type2 = "Line2" + tc2; //# var v2t = "V2" + tc; //# var ray2t = "Ray2" + tc; //# var plane2t = "Plane2" + tc; //# var circle2t = "Circle2" + tc; //# var v3t = "V3" + tc; //# var boundingbox2t = "BoundingBox2" + tc; //# var iboundingcircle = "IBoundingCircle2" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var eps = isDouble ? "1e-9" : "1e-5f"; #region __type__ /// /// A two dimensional line with specified start and end points. /// public partial struct __type__ : __iboundingcircle__ { #region Geometric Properties public readonly __v2t__ Center => (P0 + P1) * __half__; /// /// P0 /// [XmlIgnore] public __v2t__ Origin { readonly get { return P0; } set { P0 = value; } } /// /// P1 - P0 /// [XmlIgnore] public __v2t__ Direction { readonly get { return P1 - P0; } set { P1 = P0 + value; } } public readonly __ray2t__ __ray2t__ => new __ray2t__(P0, P1 - P0); public readonly __plane2t__ __plane2t__ => __ray2t__.__plane2t__; public readonly __ftype__ LeftValueOfDir(__v2t__ v) => v.X * (P0.Y - P1.Y) + v.Y * (P1.X - P0.X); public readonly __ftype__ RightValueOfDir(__v2t__ v) => v.X * (P1.Y - P0.Y) + v.Y * (P0.X - P1.X); public readonly __ftype__ LeftValueOfPos(__v2t__ p) => (p.X - P0.X) * (P0.Y - P1.Y) + (p.Y - P0.Y) * (P1.X - P0.X); public readonly __ftype__ RightValueOfPos(__v2t__ p) => (p.X - P0.X) * (P1.Y - P0.Y) + (p.Y - P0.Y) * (P0.X - P1.X); public readonly bool IsDegenerated => Direction.AllTiny; #endregion #region __iboundingcircle__ Members public readonly __circle2t__ BoundingCircle2__tc__ => new __circle2t__(Center, __half__ * Direction.Length); #endregion #region Geometric Computations public readonly __v2t__ GetClosestPointOnLine(__v2t__ p) { var d = P0 - P1; var l = d.LengthSquared; if(Fun.IsTiny(l)) return P0; //it does not matter which of the two points we choose var t = (P0.Dot(d) - p.Dot(d)) / l; //parametric distance from P0 to P1, where closest point to p is if (t <= 0) return P0; if (t >= 1) return P1; return P0 - t * d; } public readonly __ftype__ GetDistanceToLine(__v2t__ p) { var f = GetClosestPointOnLine(p); return (f - p).Length; } public readonly bool IsDistanceToPointSmallerThan(__v2t__ p, __ftype__ maxDist) { //speed-up by first checking the bounding box var box = __boundingbox2t__; box.EnlargeBy(maxDist); if (!box.Contains(p)) return false; return GetDistanceToLine(p) <= maxDist; } public readonly __type__ Flipped => new __type__(P1, P0); #endregion /// /// Returns true if points a, b and c are exactly collinear. /// public static bool IsCollinear(__v2t__ a, __v2t__ b, __v2t__ c) => (b.Y - a.Y) * (c.X - b.X) == (c.Y - b.Y) * (b.X - a.X); /// /// Returns true if points a, b and c are collinear within eps. /// public static bool IsCollinear(__v2t__ a, __v2t__ b, __v2t__ c, __ftype__ eps = __eps__) => Fun.ApproximateEquals((b.Y - a.Y) * (c.X - b.X), (c.Y - b.Y) * (b.X - a.X), eps); } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Line/Line3_auto.cs ================================================ using System; using System.Xml.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Line3f /// /// A three-dimensional line with specified start and end points. /// [Serializable] public partial struct Line3f : IBoundingSphere3f { #region Geometric Properties /// /// P0 /// [XmlIgnore] public V3f Origin { readonly get { return P0; } set { P0 = value; } } /// /// P1 - P0 /// [XmlIgnore] public V3f Direction { readonly get { return P1 - P0; } set { P1 = P0 + value; } } public readonly Ray3f Ray3f => new Ray3f(P0, P1 - P0); public readonly bool IsDegenerated => !Direction.Abs().AnyGreater(Constant.PositiveTinyValue); #endregion #region IBoundingSphere3f Members public readonly Sphere3f BoundingSphere3f => new Sphere3f(this.ComputeCentroid(), 0.5f * Direction.Length); #endregion public readonly Line3f Flipped => new Line3f(P1, P0); } #endregion #region Line3d /// /// A three-dimensional line with specified start and end points. /// [Serializable] public partial struct Line3d : IBoundingSphere3d { #region Geometric Properties /// /// P0 /// [XmlIgnore] public V3d Origin { readonly get { return P0; } set { P0 = value; } } /// /// P1 - P0 /// [XmlIgnore] public V3d Direction { readonly get { return P1 - P0; } set { P1 = P0 + value; } } public readonly Ray3d Ray3d => new Ray3d(P0, P1 - P0); public readonly bool IsDegenerated => !Direction.Abs().AnyGreater(Constant.PositiveTinyValue); #endregion #region IBoundingSphere3d Members public readonly Sphere3d BoundingSphere3d => new Sphere3d(this.ComputeCentroid(), 0.5 * Direction.Length); #endregion public readonly Line3d Flipped => new Line3d(P1, P0); } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Line/Line3_template.cs ================================================ using System; using System.Xml.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Line3" + tc; //# var type2 = "Line3" + tc2; //# var v2t = "V2" + tc; //# var ray3t = "Ray3" + tc; //# var plane3t = "Plane3" + tc; //# var sphere3t = "Sphere3" + tc; //# var v3t = "V3" + tc; //# var boundingbox3t = "BoundingBox3" + tc; //# var iboundingsphere = "IBoundingSphere3" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var eps = isDouble ? "1e-9" : "1e-5f"; #region __type__ /// /// A three-dimensional line with specified start and end points. /// [Serializable] public partial struct __type__ : __iboundingsphere__ { #region Geometric Properties /// /// P0 /// [XmlIgnore] public __v3t__ Origin { readonly get { return P0; } set { P0 = value; } } /// /// P1 - P0 /// [XmlIgnore] public __v3t__ Direction { readonly get { return P1 - P0; } set { P1 = P0 + value; } } public readonly __ray3t__ __ray3t__ => new __ray3t__(P0, P1 - P0); public readonly bool IsDegenerated => !Direction.Abs().AnyGreater(Constant<__ftype__>.PositiveTinyValue); #endregion #region __iboundingsphere__ Members public readonly __sphere3t__ BoundingSphere3__tc__ => new __sphere3t__(this.ComputeCentroid(), __half__ * Direction.Length); #endregion public readonly __type__ Flipped => new __type__(P1, P0); } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Line1iPoint.cs ================================================ namespace Aardvark.Base { /// /// Represents a value at an interpolated point between two indexed /// values of an indexable set of values. This is implemented as a /// class in order to avoid duplicating interpolated points in some /// algorithms. /// public class Line1iPoint { public readonly Line1i Line; public readonly double T; #region Constructor public Line1iPoint( int i0, int i1, double t) { Line.I0 = i0; Line.I1 = i1; T = t; } #endregion } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Plane/Plane2_auto.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Plane2f /// /// A line represented by a (possibly) normalized normal vector and the /// distance to the origin. Note that the plane does not enforce the /// normalized normal vector. /// Equation for points p on the plane: Normal dot p == Distance /// public partial struct Plane2f : IEquatable, IValidity // should be InfiniteLine2d { public V2f Normal; public float Distance; #region Constructors /// /// Creates plane from normal vector and constant. IMPORTANT: The /// supplied vector has to be normalized in order for all methods /// to work correctly, however if only relative height computations /// using the method are necessary, the normal /// vector need not be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane2f(V2f normalizedNormal, float distance) { Normal = normalizedNormal; Distance = distance; } /// /// Creates plane from point and normal vector. IMPORTANT: The /// supplied vector has to be normalized in order for all methods /// to work correctly, however if only relative height computations /// using the method are necessary, the normal /// vector need not be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane2f(V2f normalizedNormal, V2f point) { Normal = normalizedNormal; Distance = Vec.Dot(normalizedNormal, point); } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane2f(Plane2f o) { Normal = o.Normal; Distance = o.Distance; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane2f(Plane2d o) { Normal = (V2f)o.Normal; Distance = (float)o.Distance; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Plane2f(Plane2d o) => new Plane2f(o); #endregion #region Constants public static Plane2f XAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane2f(V2f.OI, 0); } public static Plane2f YAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane2f(-V2f.IO, 0); } public static Plane2f Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane2f(V2f.Zero, 0); } #endregion #region Properties /// /// The point on the plane which is closest to the origin. /// [XmlIgnore] public V2f Point { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Normal * Distance; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Distance = Vec.Dot(Normal, value); } } /// /// Returns true if the normal of the plane is not the zero-vector. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal != V2f.Zero; } /// /// Returns true if the normal of the plane is the zero-vector. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal == V2f.Zero; } /// /// Returns a Plane3f whose cutting-line with the XY-Plane /// is represented by the Plane2f /// public readonly Plane3f PlaneXY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3f(Normal.XYO, Distance); } /// /// Returns a Plane3f whose cutting-line with the XZ-Plane /// is represented by the Plane2f /// public readonly Plane3f PlaneXZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3f(Normal.XOY, Distance); } /// /// Returns a Plane3f whose cutting-line with the YZ-Plane /// is represented by the Plane2f /// public readonly Plane3f PlaneYZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3f(Normal.OXY, Distance); } #endregion #region Plane Arithmetics /// /// Returns the normalized as new . /// public readonly Plane2f Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { float scale = Normal.Length; return new Plane2f(Normal / scale, Distance / scale); } } /// /// Calculates the nomalized plane of this . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Normalize() { float scale = Normal.Length; Normal /= scale; Distance /= scale; } /// /// Changes sign of normal vector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Reverse() { Normal = -Normal; Distance = -Distance; } /// /// Returns with normal vector in opposing direction. /// /// public readonly Plane2f Reversed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane2f(-Normal, -Distance); } /// /// The signed height of the supplied point over the plane. /// IMPORTANT: If the plane is not normalized the returned height is scaled with the magnitued of the plane normal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float Height(V2f p) => Vec.Dot(Normal, p) - Distance; /// /// The sign of the height of the point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int Sign(V2f p) => Height(p).Sign(); /// /// Projets the given point x perpendicular on the plane /// and returns the nearest point on the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f NearestPoint(V2f x) { var p = Point; return (x - Normal.Dot(x - p) * Normal); } /// /// Returns the coefficients (a, b, c, d) of the normal equation. /// public readonly V3f Coefficients { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V3f(Normal, -Distance); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Plane2f a, Plane2f b) => (a.Normal == b.Normal) && (a.Distance == b.Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Plane2f a, Plane2f b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Normal, Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Plane2f other) => Normal.Equals(other.Normal) && Distance.Equals(other.Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Plane2f o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Normal, Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Plane2f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Plane2f(V2f.Parse(x[0]), float.Parse(x[1], CultureInfo.InvariantCulture)); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Plane2f a, Plane2f b, float tolerance) => ApproximateEquals(a.Normal, b.Normal, tolerance) && ApproximateEquals(a.Distance, b.Distance, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Plane2f a, Plane2f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Plane2d /// /// A line represented by a (possibly) normalized normal vector and the /// distance to the origin. Note that the plane does not enforce the /// normalized normal vector. /// Equation for points p on the plane: Normal dot p == Distance /// public partial struct Plane2d : IEquatable, IValidity // should be InfiniteLine2d { public V2d Normal; public double Distance; #region Constructors /// /// Creates plane from normal vector and constant. IMPORTANT: The /// supplied vector has to be normalized in order for all methods /// to work correctly, however if only relative height computations /// using the method are necessary, the normal /// vector need not be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane2d(V2d normalizedNormal, double distance) { Normal = normalizedNormal; Distance = distance; } /// /// Creates plane from point and normal vector. IMPORTANT: The /// supplied vector has to be normalized in order for all methods /// to work correctly, however if only relative height computations /// using the method are necessary, the normal /// vector need not be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane2d(V2d normalizedNormal, V2d point) { Normal = normalizedNormal; Distance = Vec.Dot(normalizedNormal, point); } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane2d(Plane2d o) { Normal = o.Normal; Distance = o.Distance; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane2d(Plane2f o) { Normal = (V2d)o.Normal; Distance = (double)o.Distance; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Plane2d(Plane2f o) => new Plane2d(o); #endregion #region Constants public static Plane2d XAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane2d(V2d.OI, 0); } public static Plane2d YAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane2d(-V2d.IO, 0); } public static Plane2d Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane2d(V2d.Zero, 0); } #endregion #region Properties /// /// The point on the plane which is closest to the origin. /// [XmlIgnore] public V2d Point { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Normal * Distance; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Distance = Vec.Dot(Normal, value); } } /// /// Returns true if the normal of the plane is not the zero-vector. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal != V2d.Zero; } /// /// Returns true if the normal of the plane is the zero-vector. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal == V2d.Zero; } /// /// Returns a Plane3d whose cutting-line with the XY-Plane /// is represented by the Plane2d /// public readonly Plane3d PlaneXY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3d(Normal.XYO, Distance); } /// /// Returns a Plane3d whose cutting-line with the XZ-Plane /// is represented by the Plane2d /// public readonly Plane3d PlaneXZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3d(Normal.XOY, Distance); } /// /// Returns a Plane3d whose cutting-line with the YZ-Plane /// is represented by the Plane2d /// public readonly Plane3d PlaneYZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3d(Normal.OXY, Distance); } #endregion #region Plane Arithmetics /// /// Returns the normalized as new . /// public readonly Plane2d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { double scale = Normal.Length; return new Plane2d(Normal / scale, Distance / scale); } } /// /// Calculates the nomalized plane of this . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Normalize() { double scale = Normal.Length; Normal /= scale; Distance /= scale; } /// /// Changes sign of normal vector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Reverse() { Normal = -Normal; Distance = -Distance; } /// /// Returns with normal vector in opposing direction. /// /// public readonly Plane2d Reversed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane2d(-Normal, -Distance); } /// /// The signed height of the supplied point over the plane. /// IMPORTANT: If the plane is not normalized the returned height is scaled with the magnitued of the plane normal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double Height(V2d p) => Vec.Dot(Normal, p) - Distance; /// /// The sign of the height of the point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int Sign(V2d p) => Height(p).Sign(); /// /// Projets the given point x perpendicular on the plane /// and returns the nearest point on the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d NearestPoint(V2d x) { var p = Point; return (x - Normal.Dot(x - p) * Normal); } /// /// Returns the coefficients (a, b, c, d) of the normal equation. /// public readonly V3d Coefficients { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V3d(Normal, -Distance); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Plane2d a, Plane2d b) => (a.Normal == b.Normal) && (a.Distance == b.Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Plane2d a, Plane2d b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Normal, Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Plane2d other) => Normal.Equals(other.Normal) && Distance.Equals(other.Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Plane2d o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Normal, Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Plane2d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Plane2d(V2d.Parse(x[0]), double.Parse(x[1], CultureInfo.InvariantCulture)); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Plane2d a, Plane2d b, double tolerance) => ApproximateEquals(a.Normal, b.Normal, tolerance) && ApproximateEquals(a.Distance, b.Distance, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Plane2d a, Plane2d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Plane/Plane2_template.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var plane2t = "Plane2" + tc; //# var plane3t = "Plane3" + tc; //# var plane2t2 = "Plane2" + tc2; //# var v2t = "V2" + tc; //# var v3t = "V3" + tc; #region __plane2t__ /// /// A line represented by a (possibly) normalized normal vector and the /// distance to the origin. Note that the plane does not enforce the /// normalized normal vector. /// Equation for points p on the plane: Normal dot p == Distance /// public partial struct __plane2t__ : IEquatable<__plane2t__>, IValidity // should be InfiniteLine2d { public __v2t__ Normal; public __ftype__ Distance; #region Constructors /// /// Creates plane from normal vector and constant. IMPORTANT: The /// supplied vector has to be normalized in order for all methods /// to work correctly, however if only relative height computations /// using the method are necessary, the normal /// vector need not be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __plane2t__(__v2t__ normalizedNormal, __ftype__ distance) { Normal = normalizedNormal; Distance = distance; } /// /// Creates plane from point and normal vector. IMPORTANT: The /// supplied vector has to be normalized in order for all methods /// to work correctly, however if only relative height computations /// using the method are necessary, the normal /// vector need not be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __plane2t__(__v2t__ normalizedNormal, __v2t__ point) { Normal = normalizedNormal; Distance = Vec.Dot(normalizedNormal, point); } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __plane2t__(__plane2t__ o) { Normal = o.Normal; Distance = o.Distance; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __plane2t__(__plane2t2__ o) { Normal = (__v2t__)o.Normal; Distance = (__ftype__)o.Distance; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __plane2t__(__plane2t2__ o) => new __plane2t__(o); #endregion #region Constants public static __plane2t__ XAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __plane2t__(__v2t__.OI, 0); } public static __plane2t__ YAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __plane2t__(-__v2t__.IO, 0); } public static __plane2t__ Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __plane2t__(__v2t__.Zero, 0); } #endregion #region Properties /// /// The point on the plane which is closest to the origin. /// [XmlIgnore] public __v2t__ Point { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Normal * Distance; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Distance = Vec.Dot(Normal, value); } } /// /// Returns true if the normal of the plane is not the zero-vector. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal != __v2t__.Zero; } /// /// Returns true if the normal of the plane is the zero-vector. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal == __v2t__.Zero; } /// /// Returns a __plane3t__ whose cutting-line with the XY-Plane /// is represented by the __plane2t__ /// public readonly __plane3t__ PlaneXY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __plane3t__(Normal.XYO, Distance); } /// /// Returns a __plane3t__ whose cutting-line with the XZ-Plane /// is represented by the __plane2t__ /// public readonly __plane3t__ PlaneXZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __plane3t__(Normal.XOY, Distance); } /// /// Returns a __plane3t__ whose cutting-line with the YZ-Plane /// is represented by the __plane2t__ /// public readonly __plane3t__ PlaneYZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __plane3t__(Normal.OXY, Distance); } #endregion #region Plane Arithmetics /// /// Returns the normalized as new . /// public readonly __plane2t__ Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { __ftype__ scale = Normal.Length; return new __plane2t__(Normal / scale, Distance / scale); } } /// /// Calculates the nomalized plane of this . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Normalize() { __ftype__ scale = Normal.Length; Normal /= scale; Distance /= scale; } /// /// Changes sign of normal vector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Reverse() { Normal = -Normal; Distance = -Distance; } /// /// Returns with normal vector in opposing direction. /// /// public readonly __plane2t__ Reversed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __plane2t__(-Normal, -Distance); } /// /// The signed height of the supplied point over the plane. /// IMPORTANT: If the plane is not normalized the returned height is scaled with the magnitued of the plane normal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__ Height(__v2t__ p) => Vec.Dot(Normal, p) - Distance; /// /// The sign of the height of the point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int Sign(__v2t__ p) => Height(p).Sign(); /// /// Projets the given point x perpendicular on the plane /// and returns the nearest point on the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __v2t__ NearestPoint(__v2t__ x) { var p = Point; return (x - Normal.Dot(x - p) * Normal); } /// /// Returns the coefficients (a, b, c, d) of the normal equation. /// public readonly __v3t__ Coefficients { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __v3t__(Normal, -Distance); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__plane2t__ a, __plane2t__ b) => (a.Normal == b.Normal) && (a.Distance == b.Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__plane2t__ a, __plane2t__ b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Normal, Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__plane2t__ other) => Normal.Equals(other.Normal) && Distance.Equals(other.Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is __plane2t__ o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Normal, Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __plane2t__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __plane2t__(__v2t__.Parse(x[0]), __ftype__.Parse(x[1], CultureInfo.InvariantCulture)); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __plane2t__ a, __plane2t__ b, __ftype__ tolerance) => ApproximateEquals(a.Normal, b.Normal, tolerance) && ApproximateEquals(a.Distance, b.Distance, tolerance); /// /// Returns whether the given are equal within /// Constant<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __plane2t__ a, __plane2t__ b) => ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Plane/Plane3_auto.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Plane3f /// /// A plane represented by a (possibly) normalized normal vector and the /// distance to the origin. Note that the plane does not enforce the /// normalized normal vector. /// Equation for points p on the plane: Normal dot p == Distance /// public partial struct Plane3f : IEquatable, IValidity, IBoundingBox3f { /// /// Plane normal. /// public V3f Normal; /// /// Distance from origin to plane. /// public float Distance; #region Constructors /// /// Creates plane from normal vector and distance to origin. /// IMPORTANT: The normal has to be normalized in order for all methods /// to work correctly, however if only relative height computations /// using the method are necessary, the normal /// vector need not be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane3f(V3f normalizedNormal, float distance) { Normal = normalizedNormal; Distance = distance; } /// /// Creates plane from normal vector and point. /// IMPORTANT: The normal has to be normalized in order for all methods /// to work correctly, however if only relative height computations /// using the method are necessary, the normal /// vector need not be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane3f(V3f normalizedNormal, V3f point) { Normal = normalizedNormal; Distance = Vec.Dot(normalizedNormal, point); } /// /// Creates a plane from 3 independent points. /// A normalized normal vector is computed and stored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane3f(V3f p0, V3f p1, V3f p2) { Normal = Vec.Cross(p1 - p0, p2 - p0).Normalized; Distance = Vec.Dot(Normal, p0); } /// /// Create a plane from coefficients (a, b, c, d) of the normal equation: ax + by + cz + d = 0 /// Normal = [a, b, c]; Distance = -d /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane3f(V4f coefficients) { Normal = coefficients.XYZ; Distance = -coefficients.W; } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane3f(Plane3f o) { Normal = o.Normal; Distance = o.Distance; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane3f(Plane3d o) { Normal = (V3f)o.Normal; Distance = (float)o.Distance; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Plane3f(Plane3d o) => new Plane3f(o); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Plane3f(PlaneWithPoint3f o) => new Plane3f(o.Normal, o.Point); #endregion #region Constants /// YZ plane. public static Plane3f XPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3f(V3f.XAxis, V3f.Zero); } /// XZ plane. public static Plane3f YPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3f(V3f.YAxis, V3f.Zero); } /// XY plane. public static Plane3f ZPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3f(V3f.ZAxis, V3f.Zero); } /// Invalid plane. public static Plane3f Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3f(V3f.Zero, 0); } #endregion #region Properties /// /// The point on the plane which is closest to the origin. /// [XmlIgnore] public V3f Point { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Normal * Distance / Normal.LengthSquared; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Distance = Vec.Dot(Normal, value); } } /// /// Returns true if the normal of the plane is not the zero-vector. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal != V3f.Zero; } /// /// Returns true if the normal of the plane is the zero-vector. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal == V3f.Zero; } /// /// Returns the normalized as new . /// public readonly Plane3f Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { float scale = Normal.Length; return new Plane3f(Normal / scale, Distance / scale); } } /// /// Returns the coefficients (a, b, c, d) of the normal equation: ax + by + cz + d = 0 /// public readonly V4f Coefficients { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V4f(Normal, -Distance); } #endregion #region Arithmetics /// /// Normalizes this . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Normalize() { float scale = Normal.Length; Normal /= scale; Distance /= scale; } /// /// Changes sign of normal vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Reverse() { Normal = -Normal; Distance = -Distance; } /// /// Returns with normal vector in opposing direction. /// public readonly Plane3f Reversed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3f(-Normal, -Distance); } /// /// The signed height of the supplied point over the plane. /// IMPORTANT: If the plane is not normalized the returned height is scaled by the magnitued of the plane normal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float Height(V3f p) => Vec.Dot(Normal, p) - Distance; /// /// The sign of the height of the point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int Sign(V3f p) => Height(p).Sign(); /// /// Projets the given point x perpendicular on the plane /// and returns the nearest point on the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f NearestPoint(V3f x) { var p = Point; return (x - Normal.Dot(x - p) * Normal); } /// /// Transforms the plane with a given trafo using the inverse /// transposed matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Plane3f Transformed(Trafo3f trafo) { return new Plane3f( new V3f( trafo.Backward.M00 * Normal.X + trafo.Backward.M10 * Normal.Y + trafo.Backward.M20 * Normal.Z - trafo.Backward.M30 * Distance, trafo.Backward.M01 * Normal.X + trafo.Backward.M11 * Normal.Y + trafo.Backward.M21 * Normal.Z - trafo.Backward.M31 * Distance, trafo.Backward.M02 * Normal.X + trafo.Backward.M12 * Normal.Y + trafo.Backward.M22 * Normal.Z - trafo.Backward.M32 * Distance ), trafo.Backward.M33 * Distance - trafo.Backward.M03 * Normal.X - trafo.Backward.M13 * Normal.Y - trafo.Backward.M23 * Normal.Z ); } /// /// Transforms the plane with a given matrix. The matrix is assumed /// to represent a euclidean transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Plane3f Transformed(M44f trafo) { var n = trafo.TransformDir(Normal); var d = Distance + trafo.C0.Dot(trafo.C3) * Normal.X + trafo.C1.Dot(trafo.C3) * Normal.Y + trafo.C2.Dot(trafo.C3) * Normal.Z; return new Plane3f(n, d); } /// /// Transforms the plane with a given Euclidean3f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Plane3f Transformed(Euclidean3f trafo) { var n1 = trafo.TransformDir(Normal); return new Plane3f(n1, Distance + trafo.Trans.Dot(n1)); } #endregion #region Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Plane3f a, Plane3f b) => a.Normal == b.Normal && a.Distance == b.Distance; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Plane3f a, Plane3f b) => a.Normal != b.Normal || a.Distance != b.Distance; #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Normal, Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Plane3f other) => Normal.Equals(other.Normal) && Distance.Equals(other.Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Plane3f o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Normal, Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Plane3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Plane3f(V3f.Parse(x[0]), float.Parse(x[1], CultureInfo.InvariantCulture)); } #endregion #region IBoundingBox3f Members /// /// Gets entire float space as bounding box. /// public readonly Box3f BoundingBox3f { get { var box = new Box3f(V3f.MinValue, V3f.MaxValue); if (Normal == V3f.XAxis) { box.Min.X = Distance; box.Max.X = Distance; return box; } if (Normal == V3f.YAxis) { box.Min.Y = Distance; box.Max.Y = Distance; return box; } if (Normal == V3f.ZAxis) { box.Min.Z = Distance; box.Max.Z = Distance; return box; } return box; } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Plane3f a, Plane3f b, float tolerance) => ApproximateEquals(a.Normal, b.Normal, tolerance) && ApproximateEquals(a.Distance, b.Distance, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Plane3f a, Plane3f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region PlaneWithPoint3f /// /// A plane with a specific point that can be retrieved later. /// public struct PlaneWithPoint3f : IBoundingBox3f { public V3f Normal; public V3f Point; #region Constructors /// /// Creates plane from normal vector and point. IMPORTANT: The /// supplied vector has to be normalized in order for all methods /// to work correctly, however if only relative height computations /// using the method are necessary, the normal /// vector need not be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlaneWithPoint3f(V3f normalizedNormal, V3f point) { Normal = normalizedNormal; Point = point; } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlaneWithPoint3f(PlaneWithPoint3f o) { Normal = o.Normal; Point = o.Point; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlaneWithPoint3f(PlaneWithPoint3d o) { Normal = (V3f)o.Normal; Point = (V3f)o.Point; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator PlaneWithPoint3f(PlaneWithPoint3d o) => new PlaneWithPoint3f(o); #endregion #region Constants public static PlaneWithPoint3f XPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlaneWithPoint3f(V3f.XAxis, V3f.Zero); } public static PlaneWithPoint3f YPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlaneWithPoint3f(V3f.YAxis, V3f.Zero); } public static PlaneWithPoint3f ZPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlaneWithPoint3f(V3f.ZAxis, V3f.Zero); } public static PlaneWithPoint3f Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlaneWithPoint3f(V3f.Zero, V3f.Zero); } #endregion #region Properties public readonly PlaneWithPoint3f Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlaneWithPoint3f(Normal.Normalized, Point); } public readonly Plane3f Plane3f { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3f(Normal, Point); } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal == V3f.Zero; } public readonly PlaneWithPoint3f Reversed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlaneWithPoint3f(-Normal, Point); } #endregion #region Arithmetics [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Normalize() => Normal.Normalize(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Reverse() => Normal = -Normal; /// /// The signed height of the supplied point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float Height(V3f p) => Vec.Dot(Normal, p - Point); /// /// The sign of the height of the point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int Sign(V3f p) => Height(p).Sign(); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Normal, Point); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(PlaneWithPoint3f other) => Normal.Equals(other.Normal) && Point.Equals(other.Point); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is PlaneWithPoint3f o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Normal, Point); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PlaneWithPoint3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new PlaneWithPoint3f(V3f.Parse(x[0]), V3f.Parse(x[1])); } #endregion #region IBoundingBox3f Members /// /// Gets entire float space as bounding box. /// public readonly Box3f BoundingBox3f { get { var box = new Box3f(V3f.MinValue, V3f.MaxValue); if (Normal == V3f.XAxis) { box.Min.X = Point.X; box.Max.X = Point.X; return box; } if (Normal == V3f.YAxis) { box.Min.Y = Point.Y; box.Max.Y = Point.Y; return box; } if (Normal == V3f.ZAxis) { box.Min.Z = Point.Z; box.Max.Z = Point.Z; return box; } return box; } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this PlaneWithPoint3f a, PlaneWithPoint3f b, float tolerance) => ApproximateEquals(a.Normal, b.Normal, tolerance) && ApproximateEquals(a.Point, b.Point, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this PlaneWithPoint3f a, PlaneWithPoint3f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region PlanePair3f /// /// A plane pair defines a ray at their intersection. /// public struct PlanePair3f { public Plane3f Plane0; public Plane3f Plane1; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlanePair3f(Plane3f plane0, Plane3f plane1) { Plane0 = plane0; Plane1 = plane1; } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlanePair3f(PlanePair3f o) { Plane0 = o.Plane0; Plane1 = o.Plane1; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlanePair3f(PlanePair3d o) { Plane0 = (Plane3f)o.Plane0; Plane1 = (Plane3f)o.Plane1; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator PlanePair3f(PlanePair3d o) => new PlanePair3f(o); #endregion #region Arithmetics [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Ray3f GetRay3f() { Plane0.Intersects(Plane1, out Ray3f ray); return ray; } #endregion } #endregion #region PlaneTriple3f /// /// A plane triple defines a point at their intersection. /// public struct PlaneTriple3f { public Plane3f Plane0; public Plane3f Plane1; public Plane3f Plane2; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlaneTriple3f(Plane3f plane0, Plane3f plane1, Plane3f plane2) { Plane0 = plane0; Plane1 = plane1; Plane2 = plane2; } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlaneTriple3f(PlaneTriple3f o) { Plane0 = o.Plane0; Plane1 = o.Plane1; Plane2 = o.Plane2; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlaneTriple3f(PlaneTriple3d o) { Plane0 = (Plane3f)o.Plane0; Plane1 = (Plane3f)o.Plane1; Plane2 = (Plane3f)o.Plane2; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator PlaneTriple3f(PlaneTriple3d o) => new PlaneTriple3f(o); #endregion #region Properties public readonly PlanePair3f Pair01 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlanePair3f(Plane0, Plane1); } public readonly PlanePair3f Pair02 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlanePair3f(Plane0, Plane2); } public readonly PlanePair3f Pair12 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlanePair3f(Plane1, Plane2); } public readonly PlanePair3f Pair10 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlanePair3f(Plane1, Plane0); } public readonly PlanePair3f Pair20 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlanePair3f(Plane2, Plane0); } public readonly PlanePair3f Pair21 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlanePair3f(Plane2, Plane1); } #endregion #region Arithmetics public readonly V3f GetPoint() { Plane0.Intersects(Plane1, Plane2, out V3f point); return point; } #endregion } #endregion #region Plane3fExtensions public static class Plane3fExtensions { /// /// Returns a transformation of an orthonormal basis in Plane- to WorldSpace. /// public static Trafo3f GetPlaneSpaceTransform(this Plane3f self) => Trafo3f.FromNormalFrame(self.Point, self.Normal); /// /// 3D world space to 2D plane space. /// Plane space is defined by a normal-frame from Point and Normal of the plane. /// public static M44f GetWorldToPlane(this Plane3f self) { M44f.NormalFrame(self.Point, self.Normal, out M44f _, out M44f global2local); return global2local; } /// /// 2D plane space to 3D world space. /// Plane space is defined by a normal-frame from Point and Normal of the plane. /// public static M44f GetPlaneToWorld(this Plane3f self) { M44f.NormalFrame(self.Point, self.Normal, out M44f local2global, out M44f _); return local2global; } /// /// Projects a point onto the plane (shortest distance). /// public static V3f Project(this Plane3f plane, V3f p) => p - plane.Height(p) * plane.Normal; /// /// Projects a point onto the plane along given direction. /// public static V3f Project(this Plane3f plane, V3f p, V3f direction) { var r = new Ray3f(p, direction); if (r.Intersects(plane, out float t)) { return r.GetPointOnRay(t); } else { throw new Exception(string.Format( "Failed to project point {0} onto plane {1} along direction {2}.", p, plane, direction) ); } } /// /// Projects points onto plane (shortest distance). /// public static V3f[] Project(this Plane3f plane, V3f[] pointArray, int startIndex = 0, int count = 0) { if (pointArray == null) throw new ArgumentNullException(); if (startIndex < 0 || startIndex >= pointArray.Length) throw new ArgumentOutOfRangeException(); if (count < 0) throw new ArgumentOutOfRangeException(); if (count == 0) count = pointArray.Length - startIndex; if (count > pointArray.Length - startIndex) throw new ArgumentOutOfRangeException(); var normal = plane.Normal; var result = new V3f[count]; for (int i = startIndex, j = 0; j < count; i++, j++) { var p = pointArray[i]; var height = plane.Height(p); result[j] = p - height * normal; } return result; } /// /// Projects points onto plane along given direction. /// public static V3f[] Project(this Plane3f plane, V3f[] pointArray, V3f direction, int startIndex = 0, int count = 0) { if (pointArray == null) throw new ArgumentNullException(); if (startIndex < 0 || startIndex >= pointArray.Length) throw new ArgumentOutOfRangeException(); if (count < 0) throw new ArgumentOutOfRangeException(); if (count == 0) count = pointArray.Length - startIndex; if (count > pointArray.Length - startIndex) throw new ArgumentOutOfRangeException(); var result = new V3f[count]; for (int i = startIndex, j = 0; j < count; i++, j++) { var r = new Ray3f(pointArray[i], direction); if (r.Intersects(plane, out float t)) { result[j] = r.GetPointOnRay(t); } else { throw new Exception(string.Format( "Failed to project point {0} onto plane {1} along direction {2}.", pointArray[i], plane, direction) ); } }; return result; } /// /// Projects a point from world space to plane space (shortest distance). /// public static V2f ProjectToPlaneSpace(this Plane3f plane, V3f p) => plane.GetWorldToPlane().TransformPos(p).XY; /// /// Projects points from world space to plane space (shortest distance). /// public static V2f[] ProjectToPlaneSpace(this Plane3f plane, V3f[] points) { var global2local = plane.GetWorldToPlane(); return points.Map(p => global2local.TransformPos(p).XY); } /// /// Transforms point from plane space to world space. /// public static V3f Unproject(this Plane3f plane, V2f point) { var local2global = plane.GetPlaneToWorld(); return local2global.TransformPos(point.XYO); } /// /// Transforms points from plane space to world space. /// public static V3f[] Unproject(this Plane3f plane, V2f[] points) { var local2global = plane.GetPlaneToWorld(); return points.Map(p => local2global.TransformPos(p.XYO)); } /// /// Transforms points from plane space to world space. /// public static V3f[] Unproject(this Plane3f plane, IReadOnlyList points) { var local2global = plane.GetPlaneToWorld(); var xs = new V3f[points.Count]; for (var i = 0; i < points.Count; i++) xs[i] = local2global.TransformPos(points[i].XYO); return xs; } } #endregion #region Plane3d /// /// A plane represented by a (possibly) normalized normal vector and the /// distance to the origin. Note that the plane does not enforce the /// normalized normal vector. /// Equation for points p on the plane: Normal dot p == Distance /// public partial struct Plane3d : IEquatable, IValidity, IBoundingBox3d { /// /// Plane normal. /// public V3d Normal; /// /// Distance from origin to plane. /// public double Distance; #region Constructors /// /// Creates plane from normal vector and distance to origin. /// IMPORTANT: The normal has to be normalized in order for all methods /// to work correctly, however if only relative height computations /// using the method are necessary, the normal /// vector need not be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane3d(V3d normalizedNormal, double distance) { Normal = normalizedNormal; Distance = distance; } /// /// Creates plane from normal vector and point. /// IMPORTANT: The normal has to be normalized in order for all methods /// to work correctly, however if only relative height computations /// using the method are necessary, the normal /// vector need not be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane3d(V3d normalizedNormal, V3d point) { Normal = normalizedNormal; Distance = Vec.Dot(normalizedNormal, point); } /// /// Creates a plane from 3 independent points. /// A normalized normal vector is computed and stored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane3d(V3d p0, V3d p1, V3d p2) { Normal = Vec.Cross(p1 - p0, p2 - p0).Normalized; Distance = Vec.Dot(Normal, p0); } /// /// Create a plane from coefficients (a, b, c, d) of the normal equation: ax + by + cz + d = 0 /// Normal = [a, b, c]; Distance = -d /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane3d(V4d coefficients) { Normal = coefficients.XYZ; Distance = -coefficients.W; } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane3d(Plane3d o) { Normal = o.Normal; Distance = o.Distance; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Plane3d(Plane3f o) { Normal = (V3d)o.Normal; Distance = (double)o.Distance; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Plane3d(Plane3f o) => new Plane3d(o); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Plane3d(PlaneWithPoint3d o) => new Plane3d(o.Normal, o.Point); #endregion #region Constants /// YZ plane. public static Plane3d XPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3d(V3d.XAxis, V3d.Zero); } /// XZ plane. public static Plane3d YPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3d(V3d.YAxis, V3d.Zero); } /// XY plane. public static Plane3d ZPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3d(V3d.ZAxis, V3d.Zero); } /// Invalid plane. public static Plane3d Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3d(V3d.Zero, 0); } #endregion #region Properties /// /// The point on the plane which is closest to the origin. /// [XmlIgnore] public V3d Point { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Normal * Distance / Normal.LengthSquared; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Distance = Vec.Dot(Normal, value); } } /// /// Returns true if the normal of the plane is not the zero-vector. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal != V3d.Zero; } /// /// Returns true if the normal of the plane is the zero-vector. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal == V3d.Zero; } /// /// Returns the normalized as new . /// public readonly Plane3d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { double scale = Normal.Length; return new Plane3d(Normal / scale, Distance / scale); } } /// /// Returns the coefficients (a, b, c, d) of the normal equation: ax + by + cz + d = 0 /// public readonly V4d Coefficients { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V4d(Normal, -Distance); } #endregion #region Arithmetics /// /// Normalizes this . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Normalize() { double scale = Normal.Length; Normal /= scale; Distance /= scale; } /// /// Changes sign of normal vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Reverse() { Normal = -Normal; Distance = -Distance; } /// /// Returns with normal vector in opposing direction. /// public readonly Plane3d Reversed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3d(-Normal, -Distance); } /// /// The signed height of the supplied point over the plane. /// IMPORTANT: If the plane is not normalized the returned height is scaled by the magnitued of the plane normal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double Height(V3d p) => Vec.Dot(Normal, p) - Distance; /// /// The sign of the height of the point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int Sign(V3d p) => Height(p).Sign(); /// /// Projets the given point x perpendicular on the plane /// and returns the nearest point on the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d NearestPoint(V3d x) { var p = Point; return (x - Normal.Dot(x - p) * Normal); } /// /// Transforms the plane with a given trafo using the inverse /// transposed matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Plane3d Transformed(Trafo3d trafo) { return new Plane3d( new V3d( trafo.Backward.M00 * Normal.X + trafo.Backward.M10 * Normal.Y + trafo.Backward.M20 * Normal.Z - trafo.Backward.M30 * Distance, trafo.Backward.M01 * Normal.X + trafo.Backward.M11 * Normal.Y + trafo.Backward.M21 * Normal.Z - trafo.Backward.M31 * Distance, trafo.Backward.M02 * Normal.X + trafo.Backward.M12 * Normal.Y + trafo.Backward.M22 * Normal.Z - trafo.Backward.M32 * Distance ), trafo.Backward.M33 * Distance - trafo.Backward.M03 * Normal.X - trafo.Backward.M13 * Normal.Y - trafo.Backward.M23 * Normal.Z ); } /// /// Transforms the plane with a given matrix. The matrix is assumed /// to represent a euclidean transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Plane3d Transformed(M44d trafo) { var n = trafo.TransformDir(Normal); var d = Distance + trafo.C0.Dot(trafo.C3) * Normal.X + trafo.C1.Dot(trafo.C3) * Normal.Y + trafo.C2.Dot(trafo.C3) * Normal.Z; return new Plane3d(n, d); } /// /// Transforms the plane with a given Euclidean3d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Plane3d Transformed(Euclidean3d trafo) { var n1 = trafo.TransformDir(Normal); return new Plane3d(n1, Distance + trafo.Trans.Dot(n1)); } #endregion #region Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Plane3d a, Plane3d b) => a.Normal == b.Normal && a.Distance == b.Distance; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Plane3d a, Plane3d b) => a.Normal != b.Normal || a.Distance != b.Distance; #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Normal, Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Plane3d other) => Normal.Equals(other.Normal) && Distance.Equals(other.Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Plane3d o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Normal, Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Plane3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Plane3d(V3d.Parse(x[0]), double.Parse(x[1], CultureInfo.InvariantCulture)); } #endregion #region IBoundingBox3d Members /// /// Gets entire double space as bounding box. /// public readonly Box3d BoundingBox3d { get { var box = new Box3d(V3d.MinValue, V3d.MaxValue); if (Normal == V3d.XAxis) { box.Min.X = Distance; box.Max.X = Distance; return box; } if (Normal == V3d.YAxis) { box.Min.Y = Distance; box.Max.Y = Distance; return box; } if (Normal == V3d.ZAxis) { box.Min.Z = Distance; box.Max.Z = Distance; return box; } return box; } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Plane3d a, Plane3d b, double tolerance) => ApproximateEquals(a.Normal, b.Normal, tolerance) && ApproximateEquals(a.Distance, b.Distance, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Plane3d a, Plane3d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region PlaneWithPoint3d /// /// A plane with a specific point that can be retrieved later. /// public struct PlaneWithPoint3d : IBoundingBox3d { public V3d Normal; public V3d Point; #region Constructors /// /// Creates plane from normal vector and point. IMPORTANT: The /// supplied vector has to be normalized in order for all methods /// to work correctly, however if only relative height computations /// using the method are necessary, the normal /// vector need not be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlaneWithPoint3d(V3d normalizedNormal, V3d point) { Normal = normalizedNormal; Point = point; } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlaneWithPoint3d(PlaneWithPoint3d o) { Normal = o.Normal; Point = o.Point; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlaneWithPoint3d(PlaneWithPoint3f o) { Normal = (V3d)o.Normal; Point = (V3d)o.Point; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator PlaneWithPoint3d(PlaneWithPoint3f o) => new PlaneWithPoint3d(o); #endregion #region Constants public static PlaneWithPoint3d XPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlaneWithPoint3d(V3d.XAxis, V3d.Zero); } public static PlaneWithPoint3d YPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlaneWithPoint3d(V3d.YAxis, V3d.Zero); } public static PlaneWithPoint3d ZPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlaneWithPoint3d(V3d.ZAxis, V3d.Zero); } public static PlaneWithPoint3d Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlaneWithPoint3d(V3d.Zero, V3d.Zero); } #endregion #region Properties public readonly PlaneWithPoint3d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlaneWithPoint3d(Normal.Normalized, Point); } public readonly Plane3d Plane3d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane3d(Normal, Point); } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal == V3d.Zero; } public readonly PlaneWithPoint3d Reversed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlaneWithPoint3d(-Normal, Point); } #endregion #region Arithmetics [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Normalize() => Normal.Normalize(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Reverse() => Normal = -Normal; /// /// The signed height of the supplied point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double Height(V3d p) => Vec.Dot(Normal, p - Point); /// /// The sign of the height of the point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int Sign(V3d p) => Height(p).Sign(); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Normal, Point); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(PlaneWithPoint3d other) => Normal.Equals(other.Normal) && Point.Equals(other.Point); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is PlaneWithPoint3d o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Normal, Point); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PlaneWithPoint3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new PlaneWithPoint3d(V3d.Parse(x[0]), V3d.Parse(x[1])); } #endregion #region IBoundingBox3d Members /// /// Gets entire double space as bounding box. /// public readonly Box3d BoundingBox3d { get { var box = new Box3d(V3d.MinValue, V3d.MaxValue); if (Normal == V3d.XAxis) { box.Min.X = Point.X; box.Max.X = Point.X; return box; } if (Normal == V3d.YAxis) { box.Min.Y = Point.Y; box.Max.Y = Point.Y; return box; } if (Normal == V3d.ZAxis) { box.Min.Z = Point.Z; box.Max.Z = Point.Z; return box; } return box; } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this PlaneWithPoint3d a, PlaneWithPoint3d b, double tolerance) => ApproximateEquals(a.Normal, b.Normal, tolerance) && ApproximateEquals(a.Point, b.Point, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this PlaneWithPoint3d a, PlaneWithPoint3d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region PlanePair3d /// /// A plane pair defines a ray at their intersection. /// public struct PlanePair3d { public Plane3d Plane0; public Plane3d Plane1; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlanePair3d(Plane3d plane0, Plane3d plane1) { Plane0 = plane0; Plane1 = plane1; } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlanePair3d(PlanePair3d o) { Plane0 = o.Plane0; Plane1 = o.Plane1; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlanePair3d(PlanePair3f o) { Plane0 = (Plane3d)o.Plane0; Plane1 = (Plane3d)o.Plane1; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator PlanePair3d(PlanePair3f o) => new PlanePair3d(o); #endregion #region Arithmetics [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Ray3d GetRay3d() { Plane0.Intersects(Plane1, out Ray3d ray); return ray; } #endregion } #endregion #region PlaneTriple3d /// /// A plane triple defines a point at their intersection. /// public struct PlaneTriple3d { public Plane3d Plane0; public Plane3d Plane1; public Plane3d Plane2; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlaneTriple3d(Plane3d plane0, Plane3d plane1, Plane3d plane2) { Plane0 = plane0; Plane1 = plane1; Plane2 = plane2; } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlaneTriple3d(PlaneTriple3d o) { Plane0 = o.Plane0; Plane1 = o.Plane1; Plane2 = o.Plane2; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public PlaneTriple3d(PlaneTriple3f o) { Plane0 = (Plane3d)o.Plane0; Plane1 = (Plane3d)o.Plane1; Plane2 = (Plane3d)o.Plane2; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator PlaneTriple3d(PlaneTriple3f o) => new PlaneTriple3d(o); #endregion #region Properties public readonly PlanePair3d Pair01 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlanePair3d(Plane0, Plane1); } public readonly PlanePair3d Pair02 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlanePair3d(Plane0, Plane2); } public readonly PlanePair3d Pair12 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlanePair3d(Plane1, Plane2); } public readonly PlanePair3d Pair10 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlanePair3d(Plane1, Plane0); } public readonly PlanePair3d Pair20 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlanePair3d(Plane2, Plane0); } public readonly PlanePair3d Pair21 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new PlanePair3d(Plane2, Plane1); } #endregion #region Arithmetics public readonly V3d GetPoint() { Plane0.Intersects(Plane1, Plane2, out V3d point); return point; } #endregion } #endregion #region Plane3dExtensions public static class Plane3dExtensions { /// /// Returns a transformation of an orthonormal basis in Plane- to WorldSpace. /// public static Trafo3d GetPlaneSpaceTransform(this Plane3d self) => Trafo3d.FromNormalFrame(self.Point, self.Normal); /// /// 3D world space to 2D plane space. /// Plane space is defined by a normal-frame from Point and Normal of the plane. /// public static M44d GetWorldToPlane(this Plane3d self) { M44d.NormalFrame(self.Point, self.Normal, out M44d _, out M44d global2local); return global2local; } /// /// 2D plane space to 3D world space. /// Plane space is defined by a normal-frame from Point and Normal of the plane. /// public static M44d GetPlaneToWorld(this Plane3d self) { M44d.NormalFrame(self.Point, self.Normal, out M44d local2global, out M44d _); return local2global; } /// /// Projects a point onto the plane (shortest distance). /// public static V3d Project(this Plane3d plane, V3d p) => p - plane.Height(p) * plane.Normal; /// /// Projects a point onto the plane along given direction. /// public static V3d Project(this Plane3d plane, V3d p, V3d direction) { var r = new Ray3d(p, direction); if (r.Intersects(plane, out double t)) { return r.GetPointOnRay(t); } else { throw new Exception(string.Format( "Failed to project point {0} onto plane {1} along direction {2}.", p, plane, direction) ); } } /// /// Projects points onto plane (shortest distance). /// public static V3d[] Project(this Plane3d plane, V3d[] pointArray, int startIndex = 0, int count = 0) { if (pointArray == null) throw new ArgumentNullException(); if (startIndex < 0 || startIndex >= pointArray.Length) throw new ArgumentOutOfRangeException(); if (count < 0) throw new ArgumentOutOfRangeException(); if (count == 0) count = pointArray.Length - startIndex; if (count > pointArray.Length - startIndex) throw new ArgumentOutOfRangeException(); var normal = plane.Normal; var result = new V3d[count]; for (int i = startIndex, j = 0; j < count; i++, j++) { var p = pointArray[i]; var height = plane.Height(p); result[j] = p - height * normal; } return result; } /// /// Projects points onto plane along given direction. /// public static V3d[] Project(this Plane3d plane, V3d[] pointArray, V3d direction, int startIndex = 0, int count = 0) { if (pointArray == null) throw new ArgumentNullException(); if (startIndex < 0 || startIndex >= pointArray.Length) throw new ArgumentOutOfRangeException(); if (count < 0) throw new ArgumentOutOfRangeException(); if (count == 0) count = pointArray.Length - startIndex; if (count > pointArray.Length - startIndex) throw new ArgumentOutOfRangeException(); var result = new V3d[count]; for (int i = startIndex, j = 0; j < count; i++, j++) { var r = new Ray3d(pointArray[i], direction); if (r.Intersects(plane, out double t)) { result[j] = r.GetPointOnRay(t); } else { throw new Exception(string.Format( "Failed to project point {0} onto plane {1} along direction {2}.", pointArray[i], plane, direction) ); } }; return result; } /// /// Projects a point from world space to plane space (shortest distance). /// public static V2d ProjectToPlaneSpace(this Plane3d plane, V3d p) => plane.GetWorldToPlane().TransformPos(p).XY; /// /// Projects points from world space to plane space (shortest distance). /// public static V2d[] ProjectToPlaneSpace(this Plane3d plane, V3d[] points) { var global2local = plane.GetWorldToPlane(); return points.Map(p => global2local.TransformPos(p).XY); } /// /// Transforms point from plane space to world space. /// public static V3d Unproject(this Plane3d plane, V2d point) { var local2global = plane.GetPlaneToWorld(); return local2global.TransformPos(point.XYO); } /// /// Transforms points from plane space to world space. /// public static V3d[] Unproject(this Plane3d plane, V2d[] points) { var local2global = plane.GetPlaneToWorld(); return points.Map(p => local2global.TransformPos(p.XYO)); } /// /// Transforms points from plane space to world space. /// public static V3d[] Unproject(this Plane3d plane, IReadOnlyList points) { var local2global = plane.GetPlaneToWorld(); var xs = new V3d[points.Count]; for (var i = 0; i < points.Count; i++) xs[i] = local2global.TransformPos(points[i].XYO); return xs; } } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Plane/Plane3_template.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var plane2t = "Plane2" + tc; //# var plane3t = "Plane3" + tc; //# var plane3t2 = "Plane3" + tc2; //# var planewithpoint3t = "PlaneWithPoint3" + tc; //# var planewithpoint3t2 = "PlaneWithPoint3" + tc2; //# var planepair3t = "PlanePair3" + tc; //# var planepair3t2 = "PlanePair3" + tc2; //# var planetriple3t = "PlaneTriple3" + tc; //# var planetriple3t2 = "PlaneTriple3" + tc2; //# var v2t = "V2" + tc; //# var v3t = "V3" + tc; //# var v4t = "V4" + tc; //# var m44t = "M44" + tc; //# var euclidean3t = "Euclidean3" + tc; //# var trafo3t = "Trafo3" + tc; //# var box3t = "Box3" + tc; //# var ray3t = "Ray3" + tc; //# var iboundingbox3t = "IBoundingBox3" + tc; #region __plane3t__ /// /// A plane represented by a (possibly) normalized normal vector and the /// distance to the origin. Note that the plane does not enforce the /// normalized normal vector. /// Equation for points p on the plane: Normal dot p == Distance /// public partial struct __plane3t__ : IEquatable<__plane3t__>, IValidity, __iboundingbox3t__ { /// /// Plane normal. /// public __v3t__ Normal; /// /// Distance from origin to plane. /// public __ftype__ Distance; #region Constructors /// /// Creates plane from normal vector and distance to origin. /// IMPORTANT: The normal has to be normalized in order for all methods /// to work correctly, however if only relative height computations /// using the method are necessary, the normal /// vector need not be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __plane3t__(__v3t__ normalizedNormal, __ftype__ distance) { Normal = normalizedNormal; Distance = distance; } /// /// Creates plane from normal vector and point. /// IMPORTANT: The normal has to be normalized in order for all methods /// to work correctly, however if only relative height computations /// using the method are necessary, the normal /// vector need not be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __plane3t__(__v3t__ normalizedNormal, __v3t__ point) { Normal = normalizedNormal; Distance = Vec.Dot(normalizedNormal, point); } /// /// Creates a plane from 3 independent points. /// A normalized normal vector is computed and stored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __plane3t__(__v3t__ p0, __v3t__ p1, __v3t__ p2) { Normal = Vec.Cross(p1 - p0, p2 - p0).Normalized; Distance = Vec.Dot(Normal, p0); } /// /// Create a plane from coefficients (a, b, c, d) of the normal equation: ax + by + cz + d = 0 /// Normal = [a, b, c]; Distance = -d /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __plane3t__(__v4t__ coefficients) { Normal = coefficients.XYZ; Distance = -coefficients.W; } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __plane3t__(__plane3t__ o) { Normal = o.Normal; Distance = o.Distance; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __plane3t__(__plane3t2__ o) { Normal = (__v3t__)o.Normal; Distance = (__ftype__)o.Distance; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __plane3t__(__plane3t2__ o) => new __plane3t__(o); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __plane3t__(__planewithpoint3t__ o) => new __plane3t__(o.Normal, o.Point); #endregion #region Constants /// YZ plane. public static __plane3t__ XPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __plane3t__(__v3t__.XAxis, __v3t__.Zero); } /// XZ plane. public static __plane3t__ YPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __plane3t__(__v3t__.YAxis, __v3t__.Zero); } /// XY plane. public static __plane3t__ ZPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __plane3t__(__v3t__.ZAxis, __v3t__.Zero); } /// Invalid plane. public static __plane3t__ Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __plane3t__(__v3t__.Zero, 0); } #endregion #region Properties /// /// The point on the plane which is closest to the origin. /// [XmlIgnore] public __v3t__ Point { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Normal * Distance / Normal.LengthSquared; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Distance = Vec.Dot(Normal, value); } } /// /// Returns true if the normal of the plane is not the zero-vector. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal != __v3t__.Zero; } /// /// Returns true if the normal of the plane is the zero-vector. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal == __v3t__.Zero; } /// /// Returns the normalized as new . /// public readonly __plane3t__ Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { __ftype__ scale = Normal.Length; return new __plane3t__(Normal / scale, Distance / scale); } } /// /// Returns the coefficients (a, b, c, d) of the normal equation: ax + by + cz + d = 0 /// public readonly __v4t__ Coefficients { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __v4t__(Normal, -Distance); } #endregion #region Arithmetics /// /// Normalizes this . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Normalize() { __ftype__ scale = Normal.Length; Normal /= scale; Distance /= scale; } /// /// Changes sign of normal vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Reverse() { Normal = -Normal; Distance = -Distance; } /// /// Returns with normal vector in opposing direction. /// public readonly __plane3t__ Reversed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __plane3t__(-Normal, -Distance); } /// /// The signed height of the supplied point over the plane. /// IMPORTANT: If the plane is not normalized the returned height is scaled by the magnitued of the plane normal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__ Height(__v3t__ p) => Vec.Dot(Normal, p) - Distance; /// /// The sign of the height of the point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int Sign(__v3t__ p) => Height(p).Sign(); /// /// Projets the given point x perpendicular on the plane /// and returns the nearest point on the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __v3t__ NearestPoint(__v3t__ x) { var p = Point; return (x - Normal.Dot(x - p) * Normal); } /// /// Transforms the plane with a given trafo using the inverse /// transposed matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __plane3t__ Transformed(__trafo3t__ trafo) { return new __plane3t__( new __v3t__( trafo.Backward.M00 * Normal.X + trafo.Backward.M10 * Normal.Y + trafo.Backward.M20 * Normal.Z - trafo.Backward.M30 * Distance, trafo.Backward.M01 * Normal.X + trafo.Backward.M11 * Normal.Y + trafo.Backward.M21 * Normal.Z - trafo.Backward.M31 * Distance, trafo.Backward.M02 * Normal.X + trafo.Backward.M12 * Normal.Y + trafo.Backward.M22 * Normal.Z - trafo.Backward.M32 * Distance ), trafo.Backward.M33 * Distance - trafo.Backward.M03 * Normal.X - trafo.Backward.M13 * Normal.Y - trafo.Backward.M23 * Normal.Z ); } /// /// Transforms the plane with a given matrix. The matrix is assumed /// to represent a euclidean transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __plane3t__ Transformed(__m44t__ trafo) { var n = trafo.TransformDir(Normal); var d = Distance + trafo.C0.Dot(trafo.C3) * Normal.X + trafo.C1.Dot(trafo.C3) * Normal.Y + trafo.C2.Dot(trafo.C3) * Normal.Z; return new __plane3t__(n, d); } /// /// Transforms the plane with a given __euclidean3t__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __plane3t__ Transformed(__euclidean3t__ trafo) { var n1 = trafo.TransformDir(Normal); return new __plane3t__(n1, Distance + trafo.Trans.Dot(n1)); } #endregion #region Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__plane3t__ a, __plane3t__ b) => a.Normal == b.Normal && a.Distance == b.Distance; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__plane3t__ a, __plane3t__ b) => a.Normal != b.Normal || a.Distance != b.Distance; #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Normal, Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__plane3t__ other) => Normal.Equals(other.Normal) && Distance.Equals(other.Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is __plane3t__ o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Normal, Distance); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __plane3t__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __plane3t__(__v3t__.Parse(x[0]), __ftype__.Parse(x[1], CultureInfo.InvariantCulture)); } #endregion #region __iboundingbox3t__ Members /// /// Gets entire __ftype__ space as bounding box. /// public readonly __box3t__ BoundingBox3__tc__ { get { var box = new __box3t__(__v3t__.MinValue, __v3t__.MaxValue); if (Normal == __v3t__.XAxis) { box.Min.X = Distance; box.Max.X = Distance; return box; } if (Normal == __v3t__.YAxis) { box.Min.Y = Distance; box.Max.Y = Distance; return box; } if (Normal == __v3t__.ZAxis) { box.Min.Z = Distance; box.Max.Z = Distance; return box; } return box; } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __plane3t__ a, __plane3t__ b, __ftype__ tolerance) => ApproximateEquals(a.Normal, b.Normal, tolerance) && ApproximateEquals(a.Distance, b.Distance, tolerance); /// /// Returns whether the given are equal within /// Constant<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __plane3t__ a, __plane3t__ b) => ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } #endregion #region __planewithpoint3t__ /// /// A plane with a specific point that can be retrieved later. /// public struct __planewithpoint3t__ : __iboundingbox3t__ { public __v3t__ Normal; public __v3t__ Point; #region Constructors /// /// Creates plane from normal vector and point. IMPORTANT: The /// supplied vector has to be normalized in order for all methods /// to work correctly, however if only relative height computations /// using the method are necessary, the normal /// vector need not be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __planewithpoint3t__(__v3t__ normalizedNormal, __v3t__ point) { Normal = normalizedNormal; Point = point; } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __planewithpoint3t__(__planewithpoint3t__ o) { Normal = o.Normal; Point = o.Point; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __planewithpoint3t__(__planewithpoint3t2__ o) { Normal = (__v3t__)o.Normal; Point = (__v3t__)o.Point; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __planewithpoint3t__(__planewithpoint3t2__ o) => new __planewithpoint3t__(o); #endregion #region Constants public static __planewithpoint3t__ XPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __planewithpoint3t__(__v3t__.XAxis, __v3t__.Zero); } public static __planewithpoint3t__ YPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __planewithpoint3t__(__v3t__.YAxis, __v3t__.Zero); } public static __planewithpoint3t__ ZPlane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __planewithpoint3t__(__v3t__.ZAxis, __v3t__.Zero); } public static __planewithpoint3t__ Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __planewithpoint3t__(__v3t__.Zero, __v3t__.Zero); } #endregion #region Properties public readonly __planewithpoint3t__ Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __planewithpoint3t__(Normal.Normalized, Point); } public readonly __plane3t__ __plane3t__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __plane3t__(Normal, Point); } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Normal == __v3t__.Zero; } public readonly __planewithpoint3t__ Reversed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __planewithpoint3t__(-Normal, Point); } #endregion #region Arithmetics [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Normalize() => Normal.Normalize(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Reverse() => Normal = -Normal; /// /// The signed height of the supplied point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__ Height(__v3t__ p) => Vec.Dot(Normal, p - Point); /// /// The sign of the height of the point over the plane. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int Sign(__v3t__ p) => Height(p).Sign(); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Normal, Point); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__planewithpoint3t__ other) => Normal.Equals(other.Normal) && Point.Equals(other.Point); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is __planewithpoint3t__ o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Normal, Point); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __planewithpoint3t__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __planewithpoint3t__(__v3t__.Parse(x[0]), __v3t__.Parse(x[1])); } #endregion #region __iboundingbox3t__ Members /// /// Gets entire __ftype__ space as bounding box. /// public readonly __box3t__ BoundingBox3__tc__ { get { var box = new __box3t__(__v3t__.MinValue, __v3t__.MaxValue); if (Normal == __v3t__.XAxis) { box.Min.X = Point.X; box.Max.X = Point.X; return box; } if (Normal == __v3t__.YAxis) { box.Min.Y = Point.Y; box.Max.Y = Point.Y; return box; } if (Normal == __v3t__.ZAxis) { box.Min.Z = Point.Z; box.Max.Z = Point.Z; return box; } return box; } } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __planewithpoint3t__ a, __planewithpoint3t__ b, __ftype__ tolerance) => ApproximateEquals(a.Normal, b.Normal, tolerance) && ApproximateEquals(a.Point, b.Point, tolerance); /// /// Returns whether the given are equal within /// Constant<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __planewithpoint3t__ a, __planewithpoint3t__ b) => ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } #endregion #region __planepair3t__ /// /// A plane pair defines a ray at their intersection. /// public struct __planepair3t__ { public __plane3t__ Plane0; public __plane3t__ Plane1; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public __planepair3t__(__plane3t__ plane0, __plane3t__ plane1) { Plane0 = plane0; Plane1 = plane1; } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __planepair3t__(__planepair3t__ o) { Plane0 = o.Plane0; Plane1 = o.Plane1; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __planepair3t__(__planepair3t2__ o) { Plane0 = (__plane3t__)o.Plane0; Plane1 = (__plane3t__)o.Plane1; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __planepair3t__(__planepair3t2__ o) => new __planepair3t__(o); #endregion #region Arithmetics [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ray3t__ Get__ray3t__() { Plane0.Intersects(Plane1, out __ray3t__ ray); return ray; } #endregion } #endregion #region __planetriple3t__ /// /// A plane triple defines a point at their intersection. /// public struct __planetriple3t__ { public __plane3t__ Plane0; public __plane3t__ Plane1; public __plane3t__ Plane2; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public __planetriple3t__(__plane3t__ plane0, __plane3t__ plane1, __plane3t__ plane2) { Plane0 = plane0; Plane1 = plane1; Plane2 = plane2; } /// /// Creates a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __planetriple3t__(__planetriple3t__ o) { Plane0 = o.Plane0; Plane1 = o.Plane1; Plane2 = o.Plane2; } /// /// Creates a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __planetriple3t__(__planetriple3t2__ o) { Plane0 = (__plane3t__)o.Plane0; Plane1 = (__plane3t__)o.Plane1; Plane2 = (__plane3t__)o.Plane2; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __planetriple3t__(__planetriple3t2__ o) => new __planetriple3t__(o); #endregion #region Properties public readonly __planepair3t__ Pair01 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __planepair3t__(Plane0, Plane1); } public readonly __planepair3t__ Pair02 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __planepair3t__(Plane0, Plane2); } public readonly __planepair3t__ Pair12 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __planepair3t__(Plane1, Plane2); } public readonly __planepair3t__ Pair10 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __planepair3t__(Plane1, Plane0); } public readonly __planepair3t__ Pair20 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __planepair3t__(Plane2, Plane0); } public readonly __planepair3t__ Pair21 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __planepair3t__(Plane2, Plane1); } #endregion #region Arithmetics public readonly __v3t__ GetPoint() { Plane0.Intersects(Plane1, Plane2, out __v3t__ point); return point; } #endregion } #endregion #region __plane3t__Extensions public static class __plane3t__Extensions { /// /// Returns a transformation of an orthonormal basis in Plane- to WorldSpace. /// public static __trafo3t__ GetPlaneSpaceTransform(this __plane3t__ self) => __trafo3t__.FromNormalFrame(self.Point, self.Normal); /// /// 3D world space to 2D plane space. /// Plane space is defined by a normal-frame from Point and Normal of the plane. /// public static __m44t__ GetWorldToPlane(this __plane3t__ self) { __m44t__.NormalFrame(self.Point, self.Normal, out __m44t__ _, out __m44t__ global2local); return global2local; } /// /// 2D plane space to 3D world space. /// Plane space is defined by a normal-frame from Point and Normal of the plane. /// public static __m44t__ GetPlaneToWorld(this __plane3t__ self) { __m44t__.NormalFrame(self.Point, self.Normal, out __m44t__ local2global, out __m44t__ _); return local2global; } /// /// Projects a point onto the plane (shortest distance). /// public static __v3t__ Project(this __plane3t__ plane, __v3t__ p) => p - plane.Height(p) * plane.Normal; /// /// Projects a point onto the plane along given direction. /// public static __v3t__ Project(this __plane3t__ plane, __v3t__ p, __v3t__ direction) { var r = new __ray3t__(p, direction); if (r.Intersects(plane, out __ftype__ t)) { return r.GetPointOnRay(t); } else { throw new Exception(string.Format( "Failed to project point {0} onto plane {1} along direction {2}.", p, plane, direction) ); } } /// /// Projects points onto plane (shortest distance). /// public static __v3t__[] Project(this __plane3t__ plane, __v3t__[] pointArray, int startIndex = 0, int count = 0) { if (pointArray == null) throw new ArgumentNullException(); if (startIndex < 0 || startIndex >= pointArray.Length) throw new ArgumentOutOfRangeException(); if (count < 0) throw new ArgumentOutOfRangeException(); if (count == 0) count = pointArray.Length - startIndex; if (count > pointArray.Length - startIndex) throw new ArgumentOutOfRangeException(); var normal = plane.Normal; var result = new __v3t__[count]; for (int i = startIndex, j = 0; j < count; i++, j++) { var p = pointArray[i]; var height = plane.Height(p); result[j] = p - height * normal; } return result; } /// /// Projects points onto plane along given direction. /// public static __v3t__[] Project(this __plane3t__ plane, __v3t__[] pointArray, __v3t__ direction, int startIndex = 0, int count = 0) { if (pointArray == null) throw new ArgumentNullException(); if (startIndex < 0 || startIndex >= pointArray.Length) throw new ArgumentOutOfRangeException(); if (count < 0) throw new ArgumentOutOfRangeException(); if (count == 0) count = pointArray.Length - startIndex; if (count > pointArray.Length - startIndex) throw new ArgumentOutOfRangeException(); var result = new __v3t__[count]; for (int i = startIndex, j = 0; j < count; i++, j++) { var r = new __ray3t__(pointArray[i], direction); if (r.Intersects(plane, out __ftype__ t)) { result[j] = r.GetPointOnRay(t); } else { throw new Exception(string.Format( "Failed to project point {0} onto plane {1} along direction {2}.", pointArray[i], plane, direction) ); } }; return result; } /// /// Projects a point from world space to plane space (shortest distance). /// public static __v2t__ ProjectToPlaneSpace(this __plane3t__ plane, __v3t__ p) => plane.GetWorldToPlane().TransformPos(p).XY; /// /// Projects points from world space to plane space (shortest distance). /// public static __v2t__[] ProjectToPlaneSpace(this __plane3t__ plane, __v3t__[] points) { var global2local = plane.GetWorldToPlane(); return points.Map(p => global2local.TransformPos(p).XY); } /// /// Transforms point from plane space to world space. /// public static __v3t__ Unproject(this __plane3t__ plane, __v2t__ point) { var local2global = plane.GetPlaneToWorld(); return local2global.TransformPos(point.XYO); } /// /// Transforms points from plane space to world space. /// public static __v3t__[] Unproject(this __plane3t__ plane, __v2t__[] points) { var local2global = plane.GetPlaneToWorld(); return points.Map(p => local2global.TransformPos(p.XYO)); } /// /// Transforms points from plane space to world space. /// public static __v3t__[] Unproject(this __plane3t__ plane, IReadOnlyList<__v2t__> points) { var local2global = plane.GetPlaneToWorld(); var xs = new __v3t__[points.Count]; for (var i = 0; i < points.Count; i++) xs[i] = local2global.TransformPos(points[i].XYO); return xs; } } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Polygon/IImmutablePolygonExtensions_auto.cs ================================================ using System; using System.Linq; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! public static class IImmutablePolygonExtensions { /// /// Maps index into range [0, count). /// internal static int RepairIndex(int count, int index) { if (index >= 0) { return (index < count) ? index : (index % count); } else { if (index >= -count) { return count + index; } else { return count - 1 + (index + 1) % count; } } } /// /// Maps arbitrary index into valid range. /// public static int RepairIndex(this IImmutablePolygon self, int index) => RepairIndex(self.Count, index); } #region IImmutablePolygon2fExtensions /// /// Extensions for IImmutablePolygon(of T). /// public static class IImmutablePolygon2fExtensions { /// /// Converts this IImmutablePolygon(of V2f) to a Polygon2f. /// public static Polygon2f ToPolygon2f(this IImmutablePolygon self) => new Polygon2f(self.Points); /// /// Returns the index and distance of the polygon's closest point to the given query point. /// public static Tuple QueryNearestVertex(this IImmutablePolygon self, V2f queryPoint) { if (self.Count == 0) return null; int bestIndex = 0; double bestDist = double.MaxValue; for (int i = 0; i < self.Count; i++) { var d = (queryPoint - self.Points[i]).LengthSquared; if (d < bestDist) { bestDist = d; bestIndex = i; } } return Tuple.Create(bestIndex, bestDist.Sqrt()); } /// /// Returns new polygon with point moved. /// public static IImmutablePolygon MovePoint(this IImmutablePolygon self, int index, V2f delta) => self.SetPoint(index, self.Points[index] + delta); /// /// Returns new polygon with point transformed. /// public static IImmutablePolygon TransformPoint(this IImmutablePolygon self, int index, M33f trafo) => self.SetPoint(index, trafo.TransformPos(self.Points[index])); /// /// Gets the index-th edge of this polygon. /// public static Line2f GetEdge(this IImmutablePolygon self, int index) { index = self.RepairIndex(index); var p0 = self.Points[index++]; var p1 = self.Points[index < self.Count ? index : 0]; return new Line2f(p0, p1); } /// /// Sets the index-th edge of this polygon. /// public static IImmutablePolygon SetEdge(this IImmutablePolygon self, int index, Line2f edge) { index = self.RepairIndex(index); var i0 = index++; var i1 = index < self.Count ? index : 0; return self.SetPoint(i0, edge.P0).SetPoint(i1, edge.P1); } /// /// Maps arbitrary index into valid range. /// public static int RepairIndex(this Polygon2f self, int index) => IImmutablePolygonExtensions.RepairIndex(self.PointCount, index); /// /// Maps arbitrary index into valid range. /// public static int RepairIndex(this Polygon3f self, int index) => IImmutablePolygonExtensions.RepairIndex(self.PointCount, index); /// /// Makes index-th edge parallel to x- or y-axis. /// public static IImmutablePolygon AlignEdge(this IImmutablePolygon self, int index) { var e = self.GetEdge(index); if ((Math.Abs(e.P0.X - e.P1.X) < Math.Abs(e.P0.Y - e.P1.Y))) { var x = (e.P0.X + e.P1.X) * 0.5; return self.SetEdge(index, new Line2f(new V2f(x, e.P0.Y), new V2f(x, e.P1.Y))); } else { var y = (e.P0.Y + e.P1.Y) * 0.5; return self.SetEdge(index, new Line2f(new V2f(e.P0.X, y), new V2f(e.P1.X, y))); } } /// /// Ensures that the outline is oriented counter-clockwise. /// public static IImmutablePolygon ToCounterClockwise(this IImmutablePolygon self) => self.ToPolygon2f().IsCcw() ? self : new ImmutablePolygon(self.Points.Reverse()); /// /// Ensures that the outline is oriented clockwise. /// public static IImmutablePolygon ToClockwise(this IImmutablePolygon self) => self.ToPolygon2f().IsCcw() ? new ImmutablePolygon(self.Points.Reverse()) : self; } #endregion #region IImmutablePolygon2dExtensions /// /// Extensions for IImmutablePolygon(of T). /// public static class IImmutablePolygon2dExtensions { /// /// Converts this IImmutablePolygon(of V2d) to a Polygon2d. /// public static Polygon2d ToPolygon2d(this IImmutablePolygon self) => new Polygon2d(self.Points); /// /// Returns the index and distance of the polygon's closest point to the given query point. /// public static Tuple QueryNearestVertex(this IImmutablePolygon self, V2d queryPoint) { if (self.Count == 0) return null; int bestIndex = 0; double bestDist = double.MaxValue; for (int i = 0; i < self.Count; i++) { var d = (queryPoint - self.Points[i]).LengthSquared; if (d < bestDist) { bestDist = d; bestIndex = i; } } return Tuple.Create(bestIndex, bestDist.Sqrt()); } /// /// Returns new polygon with point moved. /// public static IImmutablePolygon MovePoint(this IImmutablePolygon self, int index, V2d delta) => self.SetPoint(index, self.Points[index] + delta); /// /// Returns new polygon with point transformed. /// public static IImmutablePolygon TransformPoint(this IImmutablePolygon self, int index, M33d trafo) => self.SetPoint(index, trafo.TransformPos(self.Points[index])); /// /// Gets the index-th edge of this polygon. /// public static Line2d GetEdge(this IImmutablePolygon self, int index) { index = self.RepairIndex(index); var p0 = self.Points[index++]; var p1 = self.Points[index < self.Count ? index : 0]; return new Line2d(p0, p1); } /// /// Sets the index-th edge of this polygon. /// public static IImmutablePolygon SetEdge(this IImmutablePolygon self, int index, Line2d edge) { index = self.RepairIndex(index); var i0 = index++; var i1 = index < self.Count ? index : 0; return self.SetPoint(i0, edge.P0).SetPoint(i1, edge.P1); } /// /// Maps arbitrary index into valid range. /// public static int RepairIndex(this Polygon2d self, int index) => IImmutablePolygonExtensions.RepairIndex(self.PointCount, index); /// /// Maps arbitrary index into valid range. /// public static int RepairIndex(this Polygon3d self, int index) => IImmutablePolygonExtensions.RepairIndex(self.PointCount, index); /// /// Makes index-th edge parallel to x- or y-axis. /// public static IImmutablePolygon AlignEdge(this IImmutablePolygon self, int index) { var e = self.GetEdge(index); if ((Math.Abs(e.P0.X - e.P1.X) < Math.Abs(e.P0.Y - e.P1.Y))) { var x = (e.P0.X + e.P1.X) * 0.5; return self.SetEdge(index, new Line2d(new V2d(x, e.P0.Y), new V2d(x, e.P1.Y))); } else { var y = (e.P0.Y + e.P1.Y) * 0.5; return self.SetEdge(index, new Line2d(new V2d(e.P0.X, y), new V2d(e.P1.X, y))); } } /// /// Ensures that the outline is oriented counter-clockwise. /// public static IImmutablePolygon ToCounterClockwise(this IImmutablePolygon self) => self.ToPolygon2d().IsCcw() ? self : new ImmutablePolygon(self.Points.Reverse()); /// /// Ensures that the outline is oriented clockwise. /// public static IImmutablePolygon ToClockwise(this IImmutablePolygon self) => self.ToPolygon2d().IsCcw() ? new ImmutablePolygon(self.Points.Reverse()) : self; } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Polygon/IImmutablePolygonExtensions_template.cs ================================================ using System; using System.Linq; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! public static class IImmutablePolygonExtensions { /// /// Maps index into range [0, count). /// internal static int RepairIndex(int count, int index) { if (index >= 0) { return (index < count) ? index : (index % count); } else { if (index >= -count) { return count + index; } else { return count - 1 + (index + 1) % count; } } } /// /// Maps arbitrary index into valid range. /// public static int RepairIndex(this IImmutablePolygon self, int index) => RepairIndex(self.Count, index); } //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Circle2" + tc; //# var type2 = "Circle2" + tc2; //# var v2t = "V2" + tc; //# var m33t = "M33" + tc; //# var box2t = "Box2" + tc; //# var plane2t = "Plane2" + tc; //# var line2t = "Line2" + tc; //# var polygon2t = "Polygon2" + tc; //# var polygon3t = "Polygon3" + tc; //# var half = isDouble ? "0.5" : "0.5f"; #region IImmutable__polygon2t__Extensions /// /// Extensions for IImmutablePolygon(of T). /// public static class IImmutable__polygon2t__Extensions { /// /// Converts this IImmutablePolygon(of __v2t__) to a __polygon2t__. /// public static __polygon2t__ To__polygon2t__(this IImmutablePolygon<__v2t__> self) => new __polygon2t__(self.Points); /// /// Returns the index and distance of the polygon's closest point to the given query point. /// public static Tuple QueryNearestVertex(this IImmutablePolygon<__v2t__> self, __v2t__ queryPoint) { if (self.Count == 0) return null; int bestIndex = 0; double bestDist = double.MaxValue; for (int i = 0; i < self.Count; i++) { var d = (queryPoint - self.Points[i]).LengthSquared; if (d < bestDist) { bestDist = d; bestIndex = i; } } return Tuple.Create(bestIndex, bestDist.Sqrt()); } /// /// Returns new polygon with point moved. /// public static IImmutablePolygon<__v2t__> MovePoint(this IImmutablePolygon<__v2t__> self, int index, __v2t__ delta) => self.SetPoint(index, self.Points[index] + delta); /// /// Returns new polygon with point transformed. /// public static IImmutablePolygon<__v2t__> TransformPoint(this IImmutablePolygon<__v2t__> self, int index, __m33t__ trafo) => self.SetPoint(index, trafo.TransformPos(self.Points[index])); /// /// Gets the index-th edge of this polygon. /// public static __line2t__ GetEdge(this IImmutablePolygon<__v2t__> self, int index) { index = self.RepairIndex(index); var p0 = self.Points[index++]; var p1 = self.Points[index < self.Count ? index : 0]; return new __line2t__(p0, p1); } /// /// Sets the index-th edge of this polygon. /// public static IImmutablePolygon<__v2t__> SetEdge(this IImmutablePolygon<__v2t__> self, int index, __line2t__ edge) { index = self.RepairIndex(index); var i0 = index++; var i1 = index < self.Count ? index : 0; return self.SetPoint(i0, edge.P0).SetPoint(i1, edge.P1); } /// /// Maps arbitrary index into valid range. /// public static int RepairIndex(this __polygon2t__ self, int index) => IImmutablePolygonExtensions.RepairIndex(self.PointCount, index); /// /// Maps arbitrary index into valid range. /// public static int RepairIndex(this __polygon3t__ self, int index) => IImmutablePolygonExtensions.RepairIndex(self.PointCount, index); /// /// Makes index-th edge parallel to x- or y-axis. /// public static IImmutablePolygon<__v2t__> AlignEdge(this IImmutablePolygon<__v2t__> self, int index) { var e = self.GetEdge(index); if ((Math.Abs(e.P0.X - e.P1.X) < Math.Abs(e.P0.Y - e.P1.Y))) { var x = (e.P0.X + e.P1.X) * 0.5; return self.SetEdge(index, new __line2t__(new __v2t__(x, e.P0.Y), new __v2t__(x, e.P1.Y))); } else { var y = (e.P0.Y + e.P1.Y) * 0.5; return self.SetEdge(index, new __line2t__(new __v2t__(e.P0.X, y), new __v2t__(e.P1.X, y))); } } /// /// Ensures that the outline is oriented counter-clockwise. /// public static IImmutablePolygon<__v2t__> ToCounterClockwise(this IImmutablePolygon<__v2t__> self) => self.To__polygon2t__().IsCcw() ? self : new ImmutablePolygon<__v2t__>(self.Points.Reverse()); /// /// Ensures that the outline is oriented clockwise. /// public static IImmutablePolygon<__v2t__> ToClockwise(this IImmutablePolygon<__v2t__> self) => self.To__polygon2t__().IsCcw() ? new ImmutablePolygon<__v2t__>(self.Points.Reverse()) : self; } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Polygon/ImmutablePolygon.cs ================================================ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Globalization; using System.Linq; namespace Aardvark.Base { /// /// An immutable polygon. /// public class ImmutablePolygon: IImmutablePolygon { /// /// The empty polygon (no points). /// public static readonly IImmutablePolygon Empty = new ImmutablePolygon(Array.Empty()); /// /// Vertices. /// private readonly ImmutableList m_ps = ImmutableList.Empty; /// /// Creates an immutable polygon from given outline. /// public ImmutablePolygon(IEnumerable outline) { if (outline == null) throw new ArgumentNullException(); m_ps = ImmutableList.CreateRange(outline); } /// /// Creates an immutable polygon from given outline. /// public ImmutablePolygon(ImmutableList outline) { m_ps = outline ?? throw new ArgumentNullException(); } /// /// Gets index-th point. /// Index will be wrapped around if not in range [0, count). /// public T GetPoint(int index) => m_ps[this.RepairIndex(index)]; /// /// Returns a string that represents the current object. /// public override string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}]", string.Join(", ", m_ps.Select(x => x.ToString()))); #region IImmutablePolygon /// /// Polygon outline. /// public IReadOnlyList Points => m_ps; /// /// Gets number of vertices. /// public int Count => m_ps.Count; /// /// Returns new polygon with point added. /// public IImmutablePolygon AddPoint(T p) => new ImmutablePolygon(m_ps.Add(p)); /// /// Returns new polygon with points added. /// public IImmutablePolygon AddPoints(IEnumerable points) => new ImmutablePolygon(m_ps.AddRange(points)); /// /// Returns new polygon with point replaced. /// public IImmutablePolygon SetPoint(int index, T p) => new ImmutablePolygon(m_ps.SetItem(index, p)); /// /// Returns new polygon with point p inserted at given index. /// public IImmutablePolygon InsertPoint(int index, T p) => new ImmutablePolygon(m_ps.Insert(index, p)); /// /// Returns new polygon with point removed. /// public IImmutablePolygon RemovePoint(int index) => new ImmutablePolygon(m_ps.RemoveAt(index)); /// /// Returns new polygon with points removed. /// public IImmutablePolygon RemovePoints(IEnumerable indexes) { var builder = m_ps.ToBuilder(); foreach (var index in indexes.OrderByDescending(i => i)) { builder.RemoveAt(index); } return new ImmutablePolygon(builder.ToImmutable()); } /// /// Returns new polygon with transformed points. /// public IImmutablePolygon Transform(Func transform) => new ImmutablePolygon(m_ps.Select(x => transform(x))); #endregion } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Polygon/Polygon2_auto.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Polygon2fExtensions public static partial class Polygon2fExtensions { #region Conversions public static Polygon2f ToPolygon2fCCW(this Box2f self) => new Polygon2f(self.Min, new V2f(self.Max.X, self.Min.Y), self.Max, new V2f(self.Min.X, self.Max.Y)); public static Polygon3f ToPolygon3f(this Polygon2f polygon, Func point_copyFun) => new Polygon3f(polygon.GetPointArray(point_copyFun)); public static Polygon3f ToPolygon3f(this Polygon2f polygon, Func point_index_copyFun) => new Polygon3f(polygon.GetPointArray(point_index_copyFun)); #endregion #region Transformations /// /// Transforms a 2d polygon into 3d. /// The z-coordinate is assumed to be zero. /// public static Polygon3f Transformed(this Polygon2f polygon, M44f transform) { return new Polygon3f(polygon.GetPointArray(p => transform.TransformPos(p.XYO))); } #endregion #region Geometric Properties /// /// The geometric center of the polygon. /// public static V2f ComputeCentroid(this Polygon2f polygon) { var pc = polygon.PointCount; float area = 0; var centroid = V2f.Zero; // signed area as weight for center of edge line var p0 = polygon[pc - 1]; for (int i = 0; i < pc; i++) { var p1 = polygon[i]; var a = p0.X * p1.Y - p0.Y * p1.X; area += a; centroid += (p0 + p1) * a; // center point would be /2 p0 = p1; } area *= 0.5f; // /2 moved outside loop return area > 0 ? centroid / (area * 6) : V2f.Zero; // normalization by area/6 } /// /// Computes the area of the polygon according to /// "Fast Polygon Area and Newell Normal Computation" /// journal of graphics tools, 7(2):9-13, 2002 /// public static float ComputeSignedArea(this Polygon2f polygon) { var pc = polygon.PointCount; if (pc < 3) return 0; float area = polygon[pc - 1].X * (polygon[0].Y - polygon[pc - 2].Y); area += polygon[0].X * (polygon[1].Y - polygon[pc - 1].Y); for (int pi = 2; pi < pc; pi++) area += polygon[pi - 1].X * (polygon[pi].Y - polygon[pi - 2].Y); return area / 2; } /// /// Computes the area of the polygon according to /// "Fast Polygon Area and Newell Normal Computation" /// journal of graphics tools, 7(2):9-13, 2002. The /// absolute value is returned (i.e. area >= 0.0). /// public static float ComputeArea(this Polygon2f polygon) => polygon.ComputeSignedArea().Abs(); /// /// Returns the rotation of the supplied counter clockwise enumerated /// convex polygon that results in the minimum area enclosing box. /// If multiple rotations are within epsilon in their area, the one /// that is closest to an axis-aligned rotation (0, 90, 180, 270) is /// returned. O(n). /// public static M22f ComputeMinAreaEnclosingBoxRotation( this Polygon2f polygon, float epsilon = 1e-4f) { polygon = polygon.WithoutMultiplePoints(epsilon); var pc = polygon.PointCount; if (pc < 2) return M22f.Identity; var ea = polygon.GetEdgeArray(); ea.Apply(v => v.Normalized); int i0 = 0, i1 = 0; int i2 = 0, i3 = 0; var min = polygon[0]; var max = polygon[0]; for (int pi = 1; pi < pc; pi++) { var p = polygon[pi]; if (p.Y < min.Y) { i0 = pi; min.Y = p.Y; } else if (p.Y > max.Y) { i2 = pi; max.Y = p.Y; } if (p.X > max.X) { i1 = pi; max.X = p.X; } else if (p.X < min.X) { i3 = pi; min.X = p.X; } } V2f p0 = polygon[i0], e0 = ea[i0], p1 = polygon[i1], e1 = ea[i1]; V2f p2 = polygon[i2], e2 = ea[i2], p3 = polygon[i3], e3 = ea[i3]; int end0 = (i0 + 1) % pc, end1 = (i1 + 1) % pc; int end2 = (i2 + 1) % pc, end3 = (i3 + 1) % pc; var dir = V2f.XAxis; var best = dir; var bestArea = float.MaxValue; var bestValue = float.MaxValue; while (true) { var s0 = Fun.FastAtan2(e0.Dot90(dir), e0.Dot(dir)); var s1 = Fun.FastAtan2(e1.Dot180(dir), e1.Dot90(dir)); var s2 = Fun.FastAtan2(e2.Dot270(dir), e2.Dot180(dir)); var s3 = Fun.FastAtan2(e3.Dot(dir), e3.Dot270(dir)); int si, si01, si23; float s01, s23; if (s0 < s1) { s01 = s0; si01 = 0; } else { s01 = s1; si01 = 1; } if (s2 < s3) { s23 = s2; si23 = 2; } else { s23 = s3; si23 = 3; } if (s01 < s23) { si = si01; } else { si = si23; } if (si == 0) dir = ea[i0]; else if (si == 1) dir = ea[i1].Rot270; else if (si == 2) dir = ea[i2].Rot180; else dir = ea[i3].Rot90; float sx = (p2 - p0).Dot90(dir), sy = (p1 - p3).Dot(dir); float area = sx * sy; float value = Fun.Min(Fun.Abs(dir.X), Fun.Abs(dir.Y)); if (area < bestArea - epsilon || (area < bestArea + epsilon && value < bestValue)) { bestArea = area; bestValue = value; best = dir; } if (si == 0) { if (++i0 >= pc) i0 -= pc; if (i0 == end1) break; p0 = polygon[i0]; e0 = ea[i0]; } else if (si == 1) { if (++i1 >= pc) i1 -= pc; if (i1 == end2) break; p1 = polygon[i1]; e1 = ea[i1]; } else if (si == 2) { if (++i2 >= pc) i2 -= pc; if (i2 == end3) break; p2 = polygon[i2]; e2 = ea[i2]; } else { if (++i3 >= pc) i3 -= pc; if (i3 == end0) break; p3 = polygon[i3]; e3 = ea[i3]; } } return new M22f(best.X, best.Y, -best.Y, best.X); } /// /// Gets oriented bounding box of this polygon /// public static Polygon2f ComputeOrientedBoundingBox(this Polygon2f polygon) { var rot = polygon.ComputeMinAreaEnclosingBoxRotation(); var rotInv = rot.Transposed; var bbGlobal = new Box2f(polygon.Points.Select(p => rot * p)); return new Polygon2f(bbGlobal.ComputeCornersCCW().Apply(p => rotInv * p)); } /// /// Computes the winding number of the polyon. /// The winding number is positive for counter- /// clockwise polygons, negative for clockwise polygons. /// public static int ComputeWindingNumber(this Polygon2f polygon) { int pc = polygon.PointCount; V2f e = polygon[0] - polygon[pc - 1]; var a = Fun.Atan2(e.Y, e.X); var a0 = a; var radians = 0.0; for (int pi = 0; pi < pc - 1; pi++) { V2f e1 = polygon[pi + 1] - polygon[pi]; var a1 = Fun.Atan2(e1.Y, e1.X); var alpha = a1 - a0; if (alpha >= ConstantF.Pi) alpha -= ConstantF.PiTimesTwo; else if (alpha < -ConstantF.Pi) alpha += ConstantF.PiTimesTwo; radians += alpha; a0 = a1; } var alpha0 = a - a0; if (alpha0 >= ConstantF.Pi) alpha0 -= ConstantF.PiTimesTwo; else if (alpha0 < -ConstantF.Pi) alpha0 += ConstantF.PiTimesTwo; radians += alpha0; var winding = radians >= 0 ? (int)((ConstantF.Pi + radians) / ConstantF.PiTimesTwo) : -(int)((ConstantF.Pi - radians) / ConstantF.PiTimesTwo); return winding; } private const int V = 1; private static readonly Func c_ccwFun = (a, b) => (a.X * b.Y - a.Y * b.X) >= 0; private static readonly Func c_cwFun = (a, b) => (a.X * b.Y - a.Y * b.X) <= 0; /// /// Check if a polygon has a specified winding. /// public static bool HasWinding( this Polygon2f polygon, Winding winding) { var winFun = winding == Winding.CCW ? c_ccwFun : c_cwFun; var ef = polygon.Edge(0); var e0 = polygon.Edge(1); var orientation = winFun(ef, e0); for (int i = 2; i < polygon.PointCount; i++) { var e1 = polygon.Edge(i); if (winFun(e0, e1) != orientation) return false; e0 = e1; } return winFun(e0, ef) == orientation; } /// /// Returns true if polygon points are oriented in counter-clockwise order. /// public static bool IsCcw(this Polygon2f polygon) => polygon.ComputeWindingNumber() >= 0; public static bool IsConcave(this Polygon2f polygon) => polygon.HasWinding(Winding.CW); public static bool IsConvex(this Polygon2f polygon) => polygon.HasWinding(Winding.CCW); #endregion #region Convex Hull /// /// Returns convex hull of this polygon. /// public static IndexPolygon2f ComputeConvexHullIndexPolygon(this Polygon2f polygon) => polygon.m_pointArray.ConvexHullIndexPolygon(polygon.m_pointCount); #endregion #region Intersection /// /// Returns: /// 1 if the Polygon created by poly has no self-intersections /// 0 if one point of the polygon lies close to a line (absoluteEpsilon) /// -1 if the Polygon created by poly has a real self-intersection /// public static int HasSelfIntersections( this Polygon2f poly, float absoluteEpsilon) { var pointCount = poly.PointCount; if (absoluteEpsilon < 0) throw new ArgumentOutOfRangeException(); int worst = V; V2f n0; //Triangles cannot have self-intersections if (pointCount == 3) return 1; Line2f line; int i; for (i = 0; i < pointCount - 1; i++) { //line between i and i+1 line = new Line2f(poly[i], poly[i + 1]); n0 = line.Direction.Normalized; n0 = new V2f(-n0.Y, n0.X); for (int u = i + 2; u < pointCount && (u + 1) % pointCount != i; u++) { //Polygon not degenerated -> Line cannot intersect with line directly before and directly after //All lines prior to (u,u1) have already been tested with (i,i+1) int u1 = (u + 1) % pointCount; if (line.IntersectsLine(poly[u], poly[u1])) { //One Point of (u,u1) lies on line (within absoluteEpsilon) if (n0.Dot(poly[u1] - line.P0).Abs() < absoluteEpsilon || n0.Dot(poly[u] - line.P0).Abs() < absoluteEpsilon) { worst = 0; } else return -1; } } } return worst; } /// /// Returns true if this polygon is fully contained inside the 'other' polygon. /// public static bool IsFullyContainedInside(this Polygon2f self, Polygon2f other) { // check if all my vertices are inside the other polygon foreach (var v in self.Points) { if (!other.Contains(v)) return false; } // check if all my edges do NOT intersect with edges of the other polygon foreach (var e in self.EdgeLines) { foreach (var x in other.EdgeLines) { if (x.Intersects(e)) return false; } } // :-) return true; } #endregion #region Relations /// /// Returns the minimal distance between the polygon and the /// other supplied polygon. O(n). /// public static float MinDistanceTo(this Polygon2f polygon, Polygon2f polygon1) => polygon.MinDistanceTo(polygon1, out _, out _, out _); /// /// Returns the minimal distance between the polygon and the non- /// overlapping other supplied polygon. The minimal distance is /// always computed as the distance between a line segment and a /// point. The indices of the minimal distance configuration are /// returned in the out parameter, as the indices of points on the /// two polygons, and wether the line segement was on this or the /// other polygon. O(n). The returned index of the line segment is /// the lower point index (except in case of wraparound). /// public static float MinDistanceTo( this Polygon2f polygon, Polygon2f polygon1, out int pi0, out int pi1, out bool lineOnThis) { var p0a = polygon.m_pointArray; var p1a = polygon1.m_pointArray; var p0c = polygon.m_pointCount; var p1c = polygon1.m_pointCount; var e0a = polygon.GetEdgeArray(); var e1a = polygon1.GetEdgeArray(); int i0 = p0a.IndexOfMinY(p0c), i1 = p1a.IndexOfMaxY(p1c); V2f p0 = p0a[i0], e0 = e0a[i0], p1 = p1a[i1], e1 = e1a[i1]; int start0 = i0, start1 = i1; var dir = V2f.XAxis; var d = Vec.Distance(p0, p1); var bestValue = float.MaxValue; int bpi0 = -1, bpi1 = -1; var bLineOnThis = true; do { var s0 = Fun.Atan2(e0.Dot90(dir), e0.Dot(dir)); var s1 = Fun.Atan2(e1.Dot270(dir), e1.Dot180(dir)); if (s0 <= s1) { dir = e0a[i0]; int i0n = (i0 + 1) % p0c; var p0n = p0a[i0]; var dn = Vec.Distance(p0n, p1); var dist = DistanceToLine(p1, p0, p0n, d, dn); if (dist < bestValue) { bestValue = dist; bLineOnThis = true; bpi0 = i0; bpi1 = i1; } i0 = i0n; p0 = p0n; e0 = e0a[i0]; d = dn; } else { dir = e0a[i1].Rot180; int i1n = (i1 + 1) % p1c; var p1n = p1a[i1]; var dn = Vec.Distance(p0, p1n); var dist = DistanceToLine(p0, p1, p1n, d, dn); if (dist < bestValue) { bestValue = dist; bLineOnThis = false; bpi0 = i0; bpi1 = i1; } i1 = i1n; p1 = p1n; e1 = e1a[i1]; d = dn; } } while (i0 != start0 || i1 != start1); lineOnThis = bLineOnThis; pi0 = bpi0; pi1 = bpi1; return bestValue; } private static float DistanceToLine(V2f query, V2f p0, V2f p1, float d0, float d1) { var p0p1 = p1 - p0; var p0q = query - p0; var t = Vec.Dot(p0q, p0p1); if (t <= 0) { return d0; } var denom = p0p1.LengthSquared; if (t >= denom) { return d1; } t /= denom; return Vec.Distance(query, p0 + t * p0p1); } #endregion #region Degenerated parts of a Polygon2f #region Polygon2f-Extensions /// /// Returns true if the Polygon contains a degenerated part /// public static bool HasDegeneratedPart(this Polygon2f poly) => poly.PolygonHasDegeneratedPart(); /// /// Returns true if the Polygon contains a degenerated part /// public static bool HasDegeneratedPart(this Polygon2f poly, float absoluteEpsilon) => poly.PolygonHasDegeneratedPart(absoluteEpsilon); /// /// Returns true if the Polygon contains a degenerated part /// NonDegenerated holds the Non-Degenerated part of the polygon /// public static bool HasDegeneratedPart(this Polygon2f poly, out Polygon2f NonDegenerated) { bool result = poly.PolygonHasDegeneratedPart(out int[] temp); NonDegenerated = new Polygon2f((from i in temp select poly[i]).ToArray()); return result; } /// /// Returns true if the Polygon contains a degenerated part /// NonDegenerated holds the Non-Degenerated part of the polygon /// public static bool HasDegeneratedPart(this Polygon2f poly, out int[] NonDegenerated) => poly.PolygonHasDegeneratedPart(out NonDegenerated); /// /// Returns true if the Polygon contains a degenerated part /// NonDegenerated holds the Non-Degenerated part of the polygon /// public static bool HasDegeneratedPart(this Polygon2f poly, float absoluteEpsilon, out int[] NonDegenerated) => poly.PolygonHasDegeneratedPart(absoluteEpsilon, out NonDegenerated); #endregion #region V2f[]-Extension /// /// Returns true if the Polygon contains a degenerated part /// public static bool PolygonHasDegeneratedPart(this Polygon2f poly) => poly.PolygonHasDegeneratedPart(4 * float.Epsilon); /// /// Returns true if the Polygon contains a degenerated part /// public static bool PolygonHasDegeneratedPart(this Polygon2f poly, float absoluteEpsilon) { if (absoluteEpsilon < 0) throw new ArgumentOutOfRangeException(); int i = 0; int count = poly.PointCount; V2f e0; V2f e1; float l0 = 0; float l1 = 0; while (i < count - 1) { if ((poly[i + 1] - poly[i]).Length < absoluteEpsilon) return true; e0 = (poly[i + 1] - poly[i]); e1 = (poly[(i + 2) % count] - poly[i + 1]); l0 = e0.Length; l1 = e1.Length; e0 = e0 / l0; //e1 = e1 / l1; if ((e0.X * e1.Y - e0.Y * e1.X).Abs() > absoluteEpsilon) return true; } return false; } /// /// Returns true if the Polygon contains a degenerated part /// NonDegenerated holds the Non-Degenerated part of the polygon /// public static bool PolygonHasDegeneratedPart(this Polygon2f poly, out int[] NonDegenerated) => poly.PolygonHasDegeneratedPart(4 * float.Epsilon, out NonDegenerated); /// /// Returns true if the Polygon contains a degenerated part /// NonDegenerated holds the Non-Degenerated part of the polygon /// public static bool PolygonHasDegeneratedPart(this Polygon2f poly, float absoluteEpsilon, out int[] NonDegenerated) { if (absoluteEpsilon < 0) throw new ArgumentOutOfRangeException(); int i = 0; int u = 1; int start = 0; V2f e0; V2f e1; bool found = false; int count = poly.PointCount; List newPoints = new List(); newPoints.Add(0); float l0 = 0; while (i < count - 1) { e0 = (poly[i + 1] - poly[i]); l0 = e0.Length; e0 = e0 / l0; u = i + 1; V2f e = poly[(u + 1) % count] - poly[u]; while ( (((e0.X * e.Y - e0.Y * e.X).Abs() < absoluteEpsilon && e.Dot(e0) > 0) || (poly[(u + 1) % count] - poly[i + 1]).Length < absoluteEpsilon) && u < count - 1) { if ((poly[(u + 1) % count] - poly[i + 1]).Length < absoluteEpsilon) found = true; u++; e0 = (poly[u] - poly[i]).Normalized; e = poly[(u + 1) % count] - poly[u]; } u--; start = u; do { u++; e1 = (poly[(u + 1) % count] - poly[u]); } while (u < count && ((e0.X * e1.Y - e0.Y * e1.X).Abs() < absoluteEpsilon && e.Dot(e0) < 0)); if (u != start + 1) found = true; newPoints.Add(u); i = u; } NonDegenerated = newPoints.ToArray(); return found; } #endregion #endregion } public static partial class IndexPolygon2fExtensions { #region Conversions public static Polygon3f ToPolygon3f(this IndexPolygon2f polygon, V3f[] pointArray) => new Polygon3f(polygon.GetPointArray(pointArray)); public static Polygon3f ToPolygon3f(this IndexPolygon2f polygon, List pointList) => new Polygon3f(polygon.GetPointArray(pointList)); #endregion } #endregion #region Polygon2dExtensions public static partial class Polygon2dExtensions { #region Conversions public static Polygon2d ToPolygon2dCCW(this Box2d self) => new Polygon2d(self.Min, new V2d(self.Max.X, self.Min.Y), self.Max, new V2d(self.Min.X, self.Max.Y)); public static Polygon3d ToPolygon3d(this Polygon2d polygon, Func point_copyFun) => new Polygon3d(polygon.GetPointArray(point_copyFun)); public static Polygon3d ToPolygon3d(this Polygon2d polygon, Func point_index_copyFun) => new Polygon3d(polygon.GetPointArray(point_index_copyFun)); #endregion #region Transformations /// /// Transforms a 2d polygon into 3d. /// The z-coordinate is assumed to be zero. /// public static Polygon3d Transformed(this Polygon2d polygon, M44d transform) { return new Polygon3d(polygon.GetPointArray(p => transform.TransformPos(p.XYO))); } #endregion #region Geometric Properties /// /// The geometric center of the polygon. /// public static V2d ComputeCentroid(this Polygon2d polygon) { var pc = polygon.PointCount; double area = 0; var centroid = V2d.Zero; // signed area as weight for center of edge line var p0 = polygon[pc - 1]; for (int i = 0; i < pc; i++) { var p1 = polygon[i]; var a = p0.X * p1.Y - p0.Y * p1.X; area += a; centroid += (p0 + p1) * a; // center point would be /2 p0 = p1; } area *= 0.5; // /2 moved outside loop return area > 0 ? centroid / (area * 6) : V2d.Zero; // normalization by area/6 } /// /// Computes the area of the polygon according to /// "Fast Polygon Area and Newell Normal Computation" /// journal of graphics tools, 7(2):9-13, 2002 /// public static double ComputeSignedArea(this Polygon2d polygon) { var pc = polygon.PointCount; if (pc < 3) return 0; double area = polygon[pc - 1].X * (polygon[0].Y - polygon[pc - 2].Y); area += polygon[0].X * (polygon[1].Y - polygon[pc - 1].Y); for (int pi = 2; pi < pc; pi++) area += polygon[pi - 1].X * (polygon[pi].Y - polygon[pi - 2].Y); return area / 2; } /// /// Computes the area of the polygon according to /// "Fast Polygon Area and Newell Normal Computation" /// journal of graphics tools, 7(2):9-13, 2002. The /// absolute value is returned (i.e. area >= 0.0). /// public static double ComputeArea(this Polygon2d polygon) => polygon.ComputeSignedArea().Abs(); /// /// Returns the rotation of the supplied counter clockwise enumerated /// convex polygon that results in the minimum area enclosing box. /// If multiple rotations are within epsilon in their area, the one /// that is closest to an axis-aligned rotation (0, 90, 180, 270) is /// returned. O(n). /// public static M22d ComputeMinAreaEnclosingBoxRotation( this Polygon2d polygon, double epsilon = 1e-6) { polygon = polygon.WithoutMultiplePoints(epsilon); var pc = polygon.PointCount; if (pc < 2) return M22d.Identity; var ea = polygon.GetEdgeArray(); ea.Apply(v => v.Normalized); int i0 = 0, i1 = 0; int i2 = 0, i3 = 0; var min = polygon[0]; var max = polygon[0]; for (int pi = 1; pi < pc; pi++) { var p = polygon[pi]; if (p.Y < min.Y) { i0 = pi; min.Y = p.Y; } else if (p.Y > max.Y) { i2 = pi; max.Y = p.Y; } if (p.X > max.X) { i1 = pi; max.X = p.X; } else if (p.X < min.X) { i3 = pi; min.X = p.X; } } V2d p0 = polygon[i0], e0 = ea[i0], p1 = polygon[i1], e1 = ea[i1]; V2d p2 = polygon[i2], e2 = ea[i2], p3 = polygon[i3], e3 = ea[i3]; int end0 = (i0 + 1) % pc, end1 = (i1 + 1) % pc; int end2 = (i2 + 1) % pc, end3 = (i3 + 1) % pc; var dir = V2d.XAxis; var best = dir; var bestArea = double.MaxValue; var bestValue = double.MaxValue; while (true) { var s0 = Fun.FastAtan2(e0.Dot90(dir), e0.Dot(dir)); var s1 = Fun.FastAtan2(e1.Dot180(dir), e1.Dot90(dir)); var s2 = Fun.FastAtan2(e2.Dot270(dir), e2.Dot180(dir)); var s3 = Fun.FastAtan2(e3.Dot(dir), e3.Dot270(dir)); int si, si01, si23; double s01, s23; if (s0 < s1) { s01 = s0; si01 = 0; } else { s01 = s1; si01 = 1; } if (s2 < s3) { s23 = s2; si23 = 2; } else { s23 = s3; si23 = 3; } if (s01 < s23) { si = si01; } else { si = si23; } if (si == 0) dir = ea[i0]; else if (si == 1) dir = ea[i1].Rot270; else if (si == 2) dir = ea[i2].Rot180; else dir = ea[i3].Rot90; double sx = (p2 - p0).Dot90(dir), sy = (p1 - p3).Dot(dir); double area = sx * sy; double value = Fun.Min(Fun.Abs(dir.X), Fun.Abs(dir.Y)); if (area < bestArea - epsilon || (area < bestArea + epsilon && value < bestValue)) { bestArea = area; bestValue = value; best = dir; } if (si == 0) { if (++i0 >= pc) i0 -= pc; if (i0 == end1) break; p0 = polygon[i0]; e0 = ea[i0]; } else if (si == 1) { if (++i1 >= pc) i1 -= pc; if (i1 == end2) break; p1 = polygon[i1]; e1 = ea[i1]; } else if (si == 2) { if (++i2 >= pc) i2 -= pc; if (i2 == end3) break; p2 = polygon[i2]; e2 = ea[i2]; } else { if (++i3 >= pc) i3 -= pc; if (i3 == end0) break; p3 = polygon[i3]; e3 = ea[i3]; } } return new M22d(best.X, best.Y, -best.Y, best.X); } /// /// Gets oriented bounding box of this polygon /// public static Polygon2d ComputeOrientedBoundingBox(this Polygon2d polygon) { var rot = polygon.ComputeMinAreaEnclosingBoxRotation(); var rotInv = rot.Transposed; var bbGlobal = new Box2d(polygon.Points.Select(p => rot * p)); return new Polygon2d(bbGlobal.ComputeCornersCCW().Apply(p => rotInv * p)); } /// /// Computes the winding number of the polyon. /// The winding number is positive for counter- /// clockwise polygons, negative for clockwise polygons. /// public static int ComputeWindingNumber(this Polygon2d polygon) { int pc = polygon.PointCount; V2d e = polygon[0] - polygon[pc - 1]; var a = Fun.Atan2(e.Y, e.X); var a0 = a; var radians = 0.0; for (int pi = 0; pi < pc - 1; pi++) { V2d e1 = polygon[pi + 1] - polygon[pi]; var a1 = Fun.Atan2(e1.Y, e1.X); var alpha = a1 - a0; if (alpha >= Constant.Pi) alpha -= Constant.PiTimesTwo; else if (alpha < -Constant.Pi) alpha += Constant.PiTimesTwo; radians += alpha; a0 = a1; } var alpha0 = a - a0; if (alpha0 >= Constant.Pi) alpha0 -= Constant.PiTimesTwo; else if (alpha0 < -Constant.Pi) alpha0 += Constant.PiTimesTwo; radians += alpha0; var winding = radians >= 0 ? (int)((Constant.Pi + radians) / Constant.PiTimesTwo) : -(int)((Constant.Pi - radians) / Constant.PiTimesTwo); return winding; } private const int V = 1; private static readonly Func c_ccwFun = (a, b) => (a.X * b.Y - a.Y * b.X) >= 0; private static readonly Func c_cwFun = (a, b) => (a.X * b.Y - a.Y * b.X) <= 0; /// /// Check if a polygon has a specified winding. /// public static bool HasWinding( this Polygon2d polygon, Winding winding) { var winFun = winding == Winding.CCW ? c_ccwFun : c_cwFun; var ef = polygon.Edge(0); var e0 = polygon.Edge(1); var orientation = winFun(ef, e0); for (int i = 2; i < polygon.PointCount; i++) { var e1 = polygon.Edge(i); if (winFun(e0, e1) != orientation) return false; e0 = e1; } return winFun(e0, ef) == orientation; } /// /// Returns true if polygon points are oriented in counter-clockwise order. /// public static bool IsCcw(this Polygon2d polygon) => polygon.ComputeWindingNumber() >= 0; public static bool IsConcave(this Polygon2d polygon) => polygon.HasWinding(Winding.CW); public static bool IsConvex(this Polygon2d polygon) => polygon.HasWinding(Winding.CCW); #endregion #region Convex Hull /// /// Returns convex hull of this polygon. /// public static IndexPolygon2d ComputeConvexHullIndexPolygon(this Polygon2d polygon) => polygon.m_pointArray.ConvexHullIndexPolygon(polygon.m_pointCount); #endregion #region Intersection /// /// Returns: /// 1 if the Polygon created by poly has no self-intersections /// 0 if one point of the polygon lies close to a line (absoluteEpsilon) /// -1 if the Polygon created by poly has a real self-intersection /// public static int HasSelfIntersections( this Polygon2d poly, double absoluteEpsilon) { var pointCount = poly.PointCount; if (absoluteEpsilon < 0) throw new ArgumentOutOfRangeException(); int worst = V; V2d n0; //Triangles cannot have self-intersections if (pointCount == 3) return 1; Line2d line; int i; for (i = 0; i < pointCount - 1; i++) { //line between i and i+1 line = new Line2d(poly[i], poly[i + 1]); n0 = line.Direction.Normalized; n0 = new V2d(-n0.Y, n0.X); for (int u = i + 2; u < pointCount && (u + 1) % pointCount != i; u++) { //Polygon not degenerated -> Line cannot intersect with line directly before and directly after //All lines prior to (u,u1) have already been tested with (i,i+1) int u1 = (u + 1) % pointCount; if (line.IntersectsLine(poly[u], poly[u1])) { //One Point of (u,u1) lies on line (within absoluteEpsilon) if (n0.Dot(poly[u1] - line.P0).Abs() < absoluteEpsilon || n0.Dot(poly[u] - line.P0).Abs() < absoluteEpsilon) { worst = 0; } else return -1; } } } return worst; } /// /// Returns true if this polygon is fully contained inside the 'other' polygon. /// public static bool IsFullyContainedInside(this Polygon2d self, Polygon2d other) { // check if all my vertices are inside the other polygon foreach (var v in self.Points) { if (!other.Contains(v)) return false; } // check if all my edges do NOT intersect with edges of the other polygon foreach (var e in self.EdgeLines) { foreach (var x in other.EdgeLines) { if (x.Intersects(e)) return false; } } // :-) return true; } #endregion #region Relations /// /// Returns the minimal distance between the polygon and the /// other supplied polygon. O(n). /// public static double MinDistanceTo(this Polygon2d polygon, Polygon2d polygon1) => polygon.MinDistanceTo(polygon1, out _, out _, out _); /// /// Returns the minimal distance between the polygon and the non- /// overlapping other supplied polygon. The minimal distance is /// always computed as the distance between a line segment and a /// point. The indices of the minimal distance configuration are /// returned in the out parameter, as the indices of points on the /// two polygons, and wether the line segement was on this or the /// other polygon. O(n). The returned index of the line segment is /// the lower point index (except in case of wraparound). /// public static double MinDistanceTo( this Polygon2d polygon, Polygon2d polygon1, out int pi0, out int pi1, out bool lineOnThis) { var p0a = polygon.m_pointArray; var p1a = polygon1.m_pointArray; var p0c = polygon.m_pointCount; var p1c = polygon1.m_pointCount; var e0a = polygon.GetEdgeArray(); var e1a = polygon1.GetEdgeArray(); int i0 = p0a.IndexOfMinY(p0c), i1 = p1a.IndexOfMaxY(p1c); V2d p0 = p0a[i0], e0 = e0a[i0], p1 = p1a[i1], e1 = e1a[i1]; int start0 = i0, start1 = i1; var dir = V2d.XAxis; var d = Vec.Distance(p0, p1); var bestValue = double.MaxValue; int bpi0 = -1, bpi1 = -1; var bLineOnThis = true; do { var s0 = Fun.Atan2(e0.Dot90(dir), e0.Dot(dir)); var s1 = Fun.Atan2(e1.Dot270(dir), e1.Dot180(dir)); if (s0 <= s1) { dir = e0a[i0]; int i0n = (i0 + 1) % p0c; var p0n = p0a[i0]; var dn = Vec.Distance(p0n, p1); var dist = DistanceToLine(p1, p0, p0n, d, dn); if (dist < bestValue) { bestValue = dist; bLineOnThis = true; bpi0 = i0; bpi1 = i1; } i0 = i0n; p0 = p0n; e0 = e0a[i0]; d = dn; } else { dir = e0a[i1].Rot180; int i1n = (i1 + 1) % p1c; var p1n = p1a[i1]; var dn = Vec.Distance(p0, p1n); var dist = DistanceToLine(p0, p1, p1n, d, dn); if (dist < bestValue) { bestValue = dist; bLineOnThis = false; bpi0 = i0; bpi1 = i1; } i1 = i1n; p1 = p1n; e1 = e1a[i1]; d = dn; } } while (i0 != start0 || i1 != start1); lineOnThis = bLineOnThis; pi0 = bpi0; pi1 = bpi1; return bestValue; } private static double DistanceToLine(V2d query, V2d p0, V2d p1, double d0, double d1) { var p0p1 = p1 - p0; var p0q = query - p0; var t = Vec.Dot(p0q, p0p1); if (t <= 0) { return d0; } var denom = p0p1.LengthSquared; if (t >= denom) { return d1; } t /= denom; return Vec.Distance(query, p0 + t * p0p1); } #endregion #region Degenerated parts of a Polygon2d #region Polygon2d-Extensions /// /// Returns true if the Polygon contains a degenerated part /// public static bool HasDegeneratedPart(this Polygon2d poly) => poly.PolygonHasDegeneratedPart(); /// /// Returns true if the Polygon contains a degenerated part /// public static bool HasDegeneratedPart(this Polygon2d poly, double absoluteEpsilon) => poly.PolygonHasDegeneratedPart(absoluteEpsilon); /// /// Returns true if the Polygon contains a degenerated part /// NonDegenerated holds the Non-Degenerated part of the polygon /// public static bool HasDegeneratedPart(this Polygon2d poly, out Polygon2d NonDegenerated) { bool result = poly.PolygonHasDegeneratedPart(out int[] temp); NonDegenerated = new Polygon2d((from i in temp select poly[i]).ToArray()); return result; } /// /// Returns true if the Polygon contains a degenerated part /// NonDegenerated holds the Non-Degenerated part of the polygon /// public static bool HasDegeneratedPart(this Polygon2d poly, out int[] NonDegenerated) => poly.PolygonHasDegeneratedPart(out NonDegenerated); /// /// Returns true if the Polygon contains a degenerated part /// NonDegenerated holds the Non-Degenerated part of the polygon /// public static bool HasDegeneratedPart(this Polygon2d poly, double absoluteEpsilon, out int[] NonDegenerated) => poly.PolygonHasDegeneratedPart(absoluteEpsilon, out NonDegenerated); #endregion #region V2d[]-Extension /// /// Returns true if the Polygon contains a degenerated part /// public static bool PolygonHasDegeneratedPart(this Polygon2d poly) => poly.PolygonHasDegeneratedPart(4 * double.Epsilon); /// /// Returns true if the Polygon contains a degenerated part /// public static bool PolygonHasDegeneratedPart(this Polygon2d poly, double absoluteEpsilon) { if (absoluteEpsilon < 0) throw new ArgumentOutOfRangeException(); int i = 0; int count = poly.PointCount; V2d e0; V2d e1; double l0 = 0; double l1 = 0; while (i < count - 1) { if ((poly[i + 1] - poly[i]).Length < absoluteEpsilon) return true; e0 = (poly[i + 1] - poly[i]); e1 = (poly[(i + 2) % count] - poly[i + 1]); l0 = e0.Length; l1 = e1.Length; e0 = e0 / l0; //e1 = e1 / l1; if ((e0.X * e1.Y - e0.Y * e1.X).Abs() > absoluteEpsilon) return true; } return false; } /// /// Returns true if the Polygon contains a degenerated part /// NonDegenerated holds the Non-Degenerated part of the polygon /// public static bool PolygonHasDegeneratedPart(this Polygon2d poly, out int[] NonDegenerated) => poly.PolygonHasDegeneratedPart(4 * double.Epsilon, out NonDegenerated); /// /// Returns true if the Polygon contains a degenerated part /// NonDegenerated holds the Non-Degenerated part of the polygon /// public static bool PolygonHasDegeneratedPart(this Polygon2d poly, double absoluteEpsilon, out int[] NonDegenerated) { if (absoluteEpsilon < 0) throw new ArgumentOutOfRangeException(); int i = 0; int u = 1; int start = 0; V2d e0; V2d e1; bool found = false; int count = poly.PointCount; List newPoints = new List(); newPoints.Add(0); double l0 = 0; while (i < count - 1) { e0 = (poly[i + 1] - poly[i]); l0 = e0.Length; e0 = e0 / l0; u = i + 1; V2d e = poly[(u + 1) % count] - poly[u]; while ( (((e0.X * e.Y - e0.Y * e.X).Abs() < absoluteEpsilon && e.Dot(e0) > 0) || (poly[(u + 1) % count] - poly[i + 1]).Length < absoluteEpsilon) && u < count - 1) { if ((poly[(u + 1) % count] - poly[i + 1]).Length < absoluteEpsilon) found = true; u++; e0 = (poly[u] - poly[i]).Normalized; e = poly[(u + 1) % count] - poly[u]; } u--; start = u; do { u++; e1 = (poly[(u + 1) % count] - poly[u]); } while (u < count && ((e0.X * e1.Y - e0.Y * e1.X).Abs() < absoluteEpsilon && e.Dot(e0) < 0)); if (u != start + 1) found = true; newPoints.Add(u); i = u; } NonDegenerated = newPoints.ToArray(); return found; } #endregion #endregion } public static partial class IndexPolygon2dExtensions { #region Conversions public static Polygon3d ToPolygon3d(this IndexPolygon2d polygon, V3d[] pointArray) => new Polygon3d(polygon.GetPointArray(pointArray)); public static Polygon3d ToPolygon3d(this IndexPolygon2d polygon, List pointList) => new Polygon3d(polygon.GetPointArray(pointList)); #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Polygon/Polygon2_template.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var polygon2t = "Polygon2" + tc; //# var polygon3t = "Polygon3" + tc; //# var v2t = "V2" + tc; //# var v3t = "V3" + tc; //# var m22t = "M22" + tc; //# var m44t = "M44" + tc; //# var box2t = "Box2" + tc; //# var plane2t = "Plane2" + tc; //# var line2t = "Line2" + tc; //# var iboundingbox = "IBoundingBox2" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var constant = isDouble ? "Constant" : "ConstantF"; //# var eps = isDouble ? "1e-6" : "1e-4f"; #region __polygon2t__Extensions public static partial class __polygon2t__Extensions { #region Conversions public static __polygon2t__ To__polygon2t__CCW(this __box2t__ self) => new __polygon2t__(self.Min, new __v2t__(self.Max.X, self.Min.Y), self.Max, new __v2t__(self.Min.X, self.Max.Y)); public static __polygon3t__ To__polygon3t__(this __polygon2t__ polygon, Func<__v2t__, __v3t__> point_copyFun) => new __polygon3t__(polygon.GetPointArray(point_copyFun)); public static __polygon3t__ To__polygon3t__(this __polygon2t__ polygon, Func<__v2t__, int, __v3t__> point_index_copyFun) => new __polygon3t__(polygon.GetPointArray(point_index_copyFun)); #endregion #region Transformations /// /// Transforms a 2d polygon into 3d. /// The z-coordinate is assumed to be zero. /// public static __polygon3t__ Transformed(this __polygon2t__ polygon, __m44t__ transform) { return new __polygon3t__(polygon.GetPointArray(p => transform.TransformPos(p.XYO))); } #endregion #region Geometric Properties /// /// The geometric center of the polygon. /// public static __v2t__ ComputeCentroid(this __polygon2t__ polygon) { var pc = polygon.PointCount; __ftype__ area = 0; var centroid = __v2t__.Zero; // signed area as weight for center of edge line var p0 = polygon[pc - 1]; for (int i = 0; i < pc; i++) { var p1 = polygon[i]; var a = p0.X * p1.Y - p0.Y * p1.X; area += a; centroid += (p0 + p1) * a; // center point would be /2 p0 = p1; } area *= __half__; // /2 moved outside loop return area > 0 ? centroid / (area * 6) : __v2t__.Zero; // normalization by area/6 } /// /// Computes the area of the polygon according to /// "Fast Polygon Area and Newell Normal Computation" /// journal of graphics tools, 7(2):9-13, 2002 /// public static __ftype__ ComputeSignedArea(this __polygon2t__ polygon) { var pc = polygon.PointCount; if (pc < 3) return 0; __ftype__ area = polygon[pc - 1].X * (polygon[0].Y - polygon[pc - 2].Y); area += polygon[0].X * (polygon[1].Y - polygon[pc - 1].Y); for (int pi = 2; pi < pc; pi++) area += polygon[pi - 1].X * (polygon[pi].Y - polygon[pi - 2].Y); return area / 2; } /// /// Computes the area of the polygon according to /// "Fast Polygon Area and Newell Normal Computation" /// journal of graphics tools, 7(2):9-13, 2002. The /// absolute value is returned (i.e. area >= 0.0). /// public static __ftype__ ComputeArea(this __polygon2t__ polygon) => polygon.ComputeSignedArea().Abs(); /// /// Returns the rotation of the supplied counter clockwise enumerated /// convex polygon that results in the minimum area enclosing box. /// If multiple rotations are within epsilon in their area, the one /// that is closest to an axis-aligned rotation (0, 90, 180, 270) is /// returned. O(n). /// public static __m22t__ ComputeMinAreaEnclosingBoxRotation( this __polygon2t__ polygon, __ftype__ epsilon = __eps__) { polygon = polygon.WithoutMultiplePoints(epsilon); var pc = polygon.PointCount; if (pc < 2) return __m22t__.Identity; var ea = polygon.GetEdgeArray(); ea.Apply(v => v.Normalized); int i0 = 0, i1 = 0; int i2 = 0, i3 = 0; var min = polygon[0]; var max = polygon[0]; for (int pi = 1; pi < pc; pi++) { var p = polygon[pi]; if (p.Y < min.Y) { i0 = pi; min.Y = p.Y; } else if (p.Y > max.Y) { i2 = pi; max.Y = p.Y; } if (p.X > max.X) { i1 = pi; max.X = p.X; } else if (p.X < min.X) { i3 = pi; min.X = p.X; } } __v2t__ p0 = polygon[i0], e0 = ea[i0], p1 = polygon[i1], e1 = ea[i1]; __v2t__ p2 = polygon[i2], e2 = ea[i2], p3 = polygon[i3], e3 = ea[i3]; int end0 = (i0 + 1) % pc, end1 = (i1 + 1) % pc; int end2 = (i2 + 1) % pc, end3 = (i3 + 1) % pc; var dir = __v2t__.XAxis; var best = dir; var bestArea = __ftype__.MaxValue; var bestValue = __ftype__.MaxValue; while (true) { var s0 = Fun.FastAtan2(e0.Dot90(dir), e0.Dot(dir)); var s1 = Fun.FastAtan2(e1.Dot180(dir), e1.Dot90(dir)); var s2 = Fun.FastAtan2(e2.Dot270(dir), e2.Dot180(dir)); var s3 = Fun.FastAtan2(e3.Dot(dir), e3.Dot270(dir)); int si, si01, si23; __ftype__ s01, s23; if (s0 < s1) { s01 = s0; si01 = 0; } else { s01 = s1; si01 = 1; } if (s2 < s3) { s23 = s2; si23 = 2; } else { s23 = s3; si23 = 3; } if (s01 < s23) { si = si01; } else { si = si23; } if (si == 0) dir = ea[i0]; else if (si == 1) dir = ea[i1].Rot270; else if (si == 2) dir = ea[i2].Rot180; else dir = ea[i3].Rot90; __ftype__ sx = (p2 - p0).Dot90(dir), sy = (p1 - p3).Dot(dir); __ftype__ area = sx * sy; __ftype__ value = Fun.Min(Fun.Abs(dir.X), Fun.Abs(dir.Y)); if (area < bestArea - epsilon || (area < bestArea + epsilon && value < bestValue)) { bestArea = area; bestValue = value; best = dir; } if (si == 0) { if (++i0 >= pc) i0 -= pc; if (i0 == end1) break; p0 = polygon[i0]; e0 = ea[i0]; } else if (si == 1) { if (++i1 >= pc) i1 -= pc; if (i1 == end2) break; p1 = polygon[i1]; e1 = ea[i1]; } else if (si == 2) { if (++i2 >= pc) i2 -= pc; if (i2 == end3) break; p2 = polygon[i2]; e2 = ea[i2]; } else { if (++i3 >= pc) i3 -= pc; if (i3 == end0) break; p3 = polygon[i3]; e3 = ea[i3]; } } return new __m22t__(best.X, best.Y, -best.Y, best.X); } /// /// Gets oriented bounding box of this polygon /// public static __polygon2t__ ComputeOrientedBoundingBox(this __polygon2t__ polygon) { var rot = polygon.ComputeMinAreaEnclosingBoxRotation(); var rotInv = rot.Transposed; var bbGlobal = new __box2t__(polygon.Points.Select(p => rot * p)); return new __polygon2t__(bbGlobal.ComputeCornersCCW().Apply(p => rotInv * p)); } /// /// Computes the winding number of the polyon. /// The winding number is positive for counter- /// clockwise polygons, negative for clockwise polygons. /// public static int ComputeWindingNumber(this __polygon2t__ polygon) { int pc = polygon.PointCount; __v2t__ e = polygon[0] - polygon[pc - 1]; var a = Fun.Atan2(e.Y, e.X); var a0 = a; var radians = 0.0; for (int pi = 0; pi < pc - 1; pi++) { __v2t__ e1 = polygon[pi + 1] - polygon[pi]; var a1 = Fun.Atan2(e1.Y, e1.X); var alpha = a1 - a0; if (alpha >= __constant__.Pi) alpha -= __constant__.PiTimesTwo; else if (alpha < -__constant__.Pi) alpha += __constant__.PiTimesTwo; radians += alpha; a0 = a1; } var alpha0 = a - a0; if (alpha0 >= __constant__.Pi) alpha0 -= __constant__.PiTimesTwo; else if (alpha0 < -__constant__.Pi) alpha0 += __constant__.PiTimesTwo; radians += alpha0; var winding = radians >= 0 ? (int)((__constant__.Pi + radians) / __constant__.PiTimesTwo) : -(int)((__constant__.Pi - radians) / __constant__.PiTimesTwo); return winding; } private const int V = 1; private static readonly Func<__v2t__, __v2t__, bool> c_ccwFun = (a, b) => (a.X * b.Y - a.Y * b.X) >= 0; private static readonly Func<__v2t__, __v2t__, bool> c_cwFun = (a, b) => (a.X * b.Y - a.Y * b.X) <= 0; /// /// Check if a polygon has a specified winding. /// public static bool HasWinding( this __polygon2t__ polygon, Winding winding) { var winFun = winding == Winding.CCW ? c_ccwFun : c_cwFun; var ef = polygon.Edge(0); var e0 = polygon.Edge(1); var orientation = winFun(ef, e0); for (int i = 2; i < polygon.PointCount; i++) { var e1 = polygon.Edge(i); if (winFun(e0, e1) != orientation) return false; e0 = e1; } return winFun(e0, ef) == orientation; } /// /// Returns true if polygon points are oriented in counter-clockwise order. /// public static bool IsCcw(this __polygon2t__ polygon) => polygon.ComputeWindingNumber() >= 0; public static bool IsConcave(this __polygon2t__ polygon) => polygon.HasWinding(Winding.CW); public static bool IsConvex(this __polygon2t__ polygon) => polygon.HasWinding(Winding.CCW); #endregion #region Convex Hull /// /// Returns convex hull of this polygon. /// public static Index__polygon2t__ ComputeConvexHullIndexPolygon(this __polygon2t__ polygon) => polygon.m_pointArray.ConvexHullIndexPolygon(polygon.m_pointCount); #endregion #region Intersection /// /// Returns: /// 1 if the Polygon created by poly has no self-intersections /// 0 if one point of the polygon lies close to a line (absoluteEpsilon) /// -1 if the Polygon created by poly has a real self-intersection /// public static int HasSelfIntersections( this __polygon2t__ poly, __ftype__ absoluteEpsilon) { var pointCount = poly.PointCount; if (absoluteEpsilon < 0) throw new ArgumentOutOfRangeException(); int worst = V; __v2t__ n0; //Triangles cannot have self-intersections if (pointCount == 3) return 1; __line2t__ line; int i; for (i = 0; i < pointCount - 1; i++) { //line between i and i+1 line = new __line2t__(poly[i], poly[i + 1]); n0 = line.Direction.Normalized; n0 = new __v2t__(-n0.Y, n0.X); for (int u = i + 2; u < pointCount && (u + 1) % pointCount != i; u++) { //Polygon not degenerated -> Line cannot intersect with line directly before and directly after //All lines prior to (u,u1) have already been tested with (i,i+1) int u1 = (u + 1) % pointCount; if (line.IntersectsLine(poly[u], poly[u1])) { //One Point of (u,u1) lies on line (within absoluteEpsilon) if (n0.Dot(poly[u1] - line.P0).Abs() < absoluteEpsilon || n0.Dot(poly[u] - line.P0).Abs() < absoluteEpsilon) { worst = 0; } else return -1; } } } return worst; } /// /// Returns true if this polygon is fully contained inside the 'other' polygon. /// public static bool IsFullyContainedInside(this __polygon2t__ self, __polygon2t__ other) { // check if all my vertices are inside the other polygon foreach (var v in self.Points) { if (!other.Contains(v)) return false; } // check if all my edges do NOT intersect with edges of the other polygon foreach (var e in self.EdgeLines) { foreach (var x in other.EdgeLines) { if (x.Intersects(e)) return false; } } // :-) return true; } #endregion #region Relations /// /// Returns the minimal distance between the polygon and the /// other supplied polygon. O(n). /// public static __ftype__ MinDistanceTo(this __polygon2t__ polygon, __polygon2t__ polygon1) => polygon.MinDistanceTo(polygon1, out _, out _, out _); /// /// Returns the minimal distance between the polygon and the non- /// overlapping other supplied polygon. The minimal distance is /// always computed as the distance between a line segment and a /// point. The indices of the minimal distance configuration are /// returned in the out parameter, as the indices of points on the /// two polygons, and wether the line segement was on this or the /// other polygon. O(n). The returned index of the line segment is /// the lower point index (except in case of wraparound). /// public static __ftype__ MinDistanceTo( this __polygon2t__ polygon, __polygon2t__ polygon1, out int pi0, out int pi1, out bool lineOnThis) { var p0a = polygon.m_pointArray; var p1a = polygon1.m_pointArray; var p0c = polygon.m_pointCount; var p1c = polygon1.m_pointCount; var e0a = polygon.GetEdgeArray(); var e1a = polygon1.GetEdgeArray(); int i0 = p0a.IndexOfMinY(p0c), i1 = p1a.IndexOfMaxY(p1c); __v2t__ p0 = p0a[i0], e0 = e0a[i0], p1 = p1a[i1], e1 = e1a[i1]; int start0 = i0, start1 = i1; var dir = __v2t__.XAxis; var d = Vec.Distance(p0, p1); var bestValue = __ftype__.MaxValue; int bpi0 = -1, bpi1 = -1; var bLineOnThis = true; do { var s0 = Fun.Atan2(e0.Dot90(dir), e0.Dot(dir)); var s1 = Fun.Atan2(e1.Dot270(dir), e1.Dot180(dir)); if (s0 <= s1) { dir = e0a[i0]; int i0n = (i0 + 1) % p0c; var p0n = p0a[i0]; var dn = Vec.Distance(p0n, p1); var dist = DistanceToLine(p1, p0, p0n, d, dn); if (dist < bestValue) { bestValue = dist; bLineOnThis = true; bpi0 = i0; bpi1 = i1; } i0 = i0n; p0 = p0n; e0 = e0a[i0]; d = dn; } else { dir = e0a[i1].Rot180; int i1n = (i1 + 1) % p1c; var p1n = p1a[i1]; var dn = Vec.Distance(p0, p1n); var dist = DistanceToLine(p0, p1, p1n, d, dn); if (dist < bestValue) { bestValue = dist; bLineOnThis = false; bpi0 = i0; bpi1 = i1; } i1 = i1n; p1 = p1n; e1 = e1a[i1]; d = dn; } } while (i0 != start0 || i1 != start1); lineOnThis = bLineOnThis; pi0 = bpi0; pi1 = bpi1; return bestValue; } private static __ftype__ DistanceToLine(__v2t__ query, __v2t__ p0, __v2t__ p1, __ftype__ d0, __ftype__ d1) { var p0p1 = p1 - p0; var p0q = query - p0; var t = Vec.Dot(p0q, p0p1); if (t <= 0) { return d0; } var denom = p0p1.LengthSquared; if (t >= denom) { return d1; } t /= denom; return Vec.Distance(query, p0 + t * p0p1); } #endregion #region Degenerated parts of a __polygon2t__ #region __polygon2t__-Extensions /// /// Returns true if the Polygon contains a degenerated part /// public static bool HasDegeneratedPart(this __polygon2t__ poly) => poly.PolygonHasDegeneratedPart(); /// /// Returns true if the Polygon contains a degenerated part /// public static bool HasDegeneratedPart(this __polygon2t__ poly, __ftype__ absoluteEpsilon) => poly.PolygonHasDegeneratedPart(absoluteEpsilon); /// /// Returns true if the Polygon contains a degenerated part /// NonDegenerated holds the Non-Degenerated part of the polygon /// public static bool HasDegeneratedPart(this __polygon2t__ poly, out __polygon2t__ NonDegenerated) { bool result = poly.PolygonHasDegeneratedPart(out int[] temp); NonDegenerated = new __polygon2t__((from i in temp select poly[i]).ToArray<__v2t__>()); return result; } /// /// Returns true if the Polygon contains a degenerated part /// NonDegenerated holds the Non-Degenerated part of the polygon /// public static bool HasDegeneratedPart(this __polygon2t__ poly, out int[] NonDegenerated) => poly.PolygonHasDegeneratedPart(out NonDegenerated); /// /// Returns true if the Polygon contains a degenerated part /// NonDegenerated holds the Non-Degenerated part of the polygon /// public static bool HasDegeneratedPart(this __polygon2t__ poly, __ftype__ absoluteEpsilon, out int[] NonDegenerated) => poly.PolygonHasDegeneratedPart(absoluteEpsilon, out NonDegenerated); #endregion #region __v2t__[]-Extension /// /// Returns true if the Polygon contains a degenerated part /// public static bool PolygonHasDegeneratedPart(this __polygon2t__ poly) => poly.PolygonHasDegeneratedPart(4 * __ftype__.Epsilon); /// /// Returns true if the Polygon contains a degenerated part /// public static bool PolygonHasDegeneratedPart(this __polygon2t__ poly, __ftype__ absoluteEpsilon) { if (absoluteEpsilon < 0) throw new ArgumentOutOfRangeException(); int i = 0; int count = poly.PointCount; __v2t__ e0; __v2t__ e1; __ftype__ l0 = 0; __ftype__ l1 = 0; while (i < count - 1) { if ((poly[i + 1] - poly[i]).Length < absoluteEpsilon) return true; e0 = (poly[i + 1] - poly[i]); e1 = (poly[(i + 2) % count] - poly[i + 1]); l0 = e0.Length; l1 = e1.Length; e0 = e0 / l0; //e1 = e1 / l1; if ((e0.X * e1.Y - e0.Y * e1.X).Abs() > absoluteEpsilon) return true; } return false; } /// /// Returns true if the Polygon contains a degenerated part /// NonDegenerated holds the Non-Degenerated part of the polygon /// public static bool PolygonHasDegeneratedPart(this __polygon2t__ poly, out int[] NonDegenerated) => poly.PolygonHasDegeneratedPart(4 * __ftype__.Epsilon, out NonDegenerated); /// /// Returns true if the Polygon contains a degenerated part /// NonDegenerated holds the Non-Degenerated part of the polygon /// public static bool PolygonHasDegeneratedPart(this __polygon2t__ poly, __ftype__ absoluteEpsilon, out int[] NonDegenerated) { if (absoluteEpsilon < 0) throw new ArgumentOutOfRangeException(); int i = 0; int u = 1; int start = 0; __v2t__ e0; __v2t__ e1; bool found = false; int count = poly.PointCount; List newPoints = new List(); newPoints.Add(0); __ftype__ l0 = 0; while (i < count - 1) { e0 = (poly[i + 1] - poly[i]); l0 = e0.Length; e0 = e0 / l0; u = i + 1; __v2t__ e = poly[(u + 1) % count] - poly[u]; while ( (((e0.X * e.Y - e0.Y * e.X).Abs() < absoluteEpsilon && e.Dot(e0) > 0) || (poly[(u + 1) % count] - poly[i + 1]).Length < absoluteEpsilon) && u < count - 1) { if ((poly[(u + 1) % count] - poly[i + 1]).Length < absoluteEpsilon) found = true; u++; e0 = (poly[u] - poly[i]).Normalized; e = poly[(u + 1) % count] - poly[u]; } u--; start = u; do { u++; e1 = (poly[(u + 1) % count] - poly[u]); } while (u < count && ((e0.X * e1.Y - e0.Y * e1.X).Abs() < absoluteEpsilon && e.Dot(e0) < 0)); if (u != start + 1) found = true; newPoints.Add(u); i = u; } NonDegenerated = newPoints.ToArray(); return found; } #endregion #endregion } public static partial class Index__polygon2t__Extensions { #region Conversions public static __polygon3t__ To__polygon3t__(this Index__polygon2t__ polygon, __v3t__[] pointArray) => new __polygon3t__(polygon.GetPointArray(pointArray)); public static __polygon3t__ To__polygon3t__(this Index__polygon2t__ polygon, List<__v3t__> pointList) => new __polygon3t__(polygon.GetPointArray(pointList)); #endregion } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Polygon/Polygon3_auto.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Polygon3fExtensions public static partial class Polygon3fExtensions { #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f ToPolygon2f(this Polygon3f polygon, Func point_copyFun) => new Polygon2f(polygon.GetPointArray(point_copyFun)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f ToPolygon2f( this Polygon3f polygon, Func point_index_copyFun ) => new Polygon2f(polygon.GetPointArray(point_index_copyFun)); #endregion #region Geometric Properties /// /// Computes the area as the length of the sum of the simple /// triangulation cross-product normals. /// NOTE: This has been tested to be slightly faster and slightly more /// accurate than the computation via the 3d Newell normal /// (see Math.Tests/GeometryTests, rft 2013-05-04). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ComputeArea(this Polygon3f polygon) => 0.5f * polygon.ComputeDoubleAreaNormal().Length; /// /// Computes the normalized normal as the sum of the simple /// triangulation cross-product normals. /// NOTE: This has been tested to be slightly faster and slightly more /// accurate than the computation via the 3d Newell normal /// (see Math.Tests/GeometryTests, rft 2013-05-04). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f ComputeNormal(this Polygon3f polygon) => polygon.ComputeDoubleAreaNormal().Normalized; /// /// The geometric center of a 3-dimensional, flat polygon. /// WARNING: UNTESTED! /// public static V3f ComputeCentroid(this Polygon3f polygon) { var pc = polygon.PointCount; if (pc < 3) return V3f.Zero; V3f p0 = polygon[0], p1 = polygon[1]; V3f e0 = p1 - p0; var p2 = polygon[2]; var e1 = p2 - p0; var normal = e0.Cross(e1); var area2 = normal.Length; var centroid = area2 * (p0 + p1 + p2); p1 = p2; e0 = e1; for (int pi = 3; pi < pc; pi++) { p2 = polygon[pi]; e1 = p2 - p0; var n = e0.Cross(e1); var a2 = Fun.Sign(normal.Dot(n)) * n.Length; area2 += a2; centroid += a2 * (p0 + p1 + p2); p1 = p2; e0 = e1; } if (area2 > Constant.PositiveTinyValue) return centroid * (ConstantF.OneThird / area2); else if (area2 < Constant.NegativeTinyValue) return centroid * (-ConstantF.OneThird / area2); else return V3f.Zero; } /// /// Computes the normal with the length of twice the polygon area as /// the sum of the simple triangulation cross-product normals. /// NOTE: This has been tested to be slightly faster and slightly more /// accurate than the computation via the 3d Newell normal /// (see Math.Tests/GeometryTests, rft 2013-05-04). /// public static V3f ComputeDoubleAreaNormal(this Polygon3f polygon) { var pc = polygon.PointCount; if (pc < 3) return V3f.Zero; V3f p0 = polygon[0]; V3f e0 = polygon[1] - p0; V3f normal = V3f.Zero; for (int pi = 2; pi < pc; pi++) { var e1 = polygon[pi] - p0; normal += e0.Cross(e1); e0 = e1; } return normal; } /// /// Computes the supporting plane of the polygon via the vertex centroid /// and the sum of the simple triangulation cross-product normals. /// NOTE: This has been tested to be slightly faster and slightly more /// accurate than the computation via the 3d Newell normal /// (see Math.Tests/GeometryTests, rft 2013-05-04). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Plane3f ComputePlane3f(this Polygon3f polygon) => new Plane3f(polygon.ComputeNormal(), polygon.ComputeVertexCentroid()); /// /// Returns the plane through the first 3 points of the polygon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Plane3f GetPlane3f(this Polygon3f polygon) => new Plane3f(polygon[0], polygon[1], polygon[2]); #endregion #region FormFactor [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ComputeToPointFormFactor( this Polygon3f sourcePolygon, float polygonArea, V3f targetPoint, V3f targetNormal, float eps = 1e-4f) { return sourcePolygon.ComputeUnscaledFormFactor( targetPoint, targetNormal, eps) / (ConstantF.PiTimesTwo * polygonArea); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ComputeFromPointFormFactor( this Polygon3f targetPolygon, V3f sourcePoint, V3f sourceNormal, float eps = 1e-4f) { return targetPolygon.ComputeUnscaledFormFactor( sourcePoint, sourceNormal, eps) / ConstantF.PiTimesTwo; } public static float ComputeUnscaledFormFactor( this Polygon3f polygon, V3f p, V3f n, float eps = 1e-4f) { var vc = polygon.PointCount; V3f[] cpa = new V3f[vc + 1]; var cc = 0; var pb = polygon[0] - p; var hb = Vec.Dot(pb, n); bool hbp = hb > eps, hbn = hb < -eps; if (hb >= -eps) cpa[cc++] = pb; var p0 = pb; var h0 = hb; var h0p = hbp; var h0n = hbn; for (int vi = 1; vi < vc; vi++) { var p1 = polygon[vi] - p; var h1 = Vec.Dot(p1, n); bool h1p = h1 > eps, h1n = h1 < -eps; if (h0p && h1n || h0n && h1p) cpa[cc++] = p0 + (p1 - p0) * (h0 / (h0 - h1)); if (h1 >= -eps) cpa[cc++] = p1; p0 = p1; h0 = h1; h0p = h1p; h0n = h1n; } if (h0p && hbn || h0n && hbp) cpa[cc++] = p0 + (pb - p0) * (h0 / (h0 - hb)); var cpr = cpa.Map(cc, v => v.Length); var cv = Vec.Cross(cpa[0], cpa[cc - 1]); float ff = Vec.Dot(n, cv) * Fun.AcosClamped(Vec.Dot(cpa[0], cpa[cc - 1]) / (cpr[0] * cpr[cc - 1])) / cv.Length; for (int ci = 0; ci < cc - 1; ci++) { cv = Vec.Cross(cpa[ci + 1], cpa[ci]); ff += Vec.Dot(n, cv) * Fun.AcosClamped(Vec.Dot(cpa[ci + 1], cpa[ci]) / (cpr[ci + 1] * cpr[ci])) / cv.Length; } return ff; } #endregion #region Shape Analysis /// /// Enumerates all pairs of coincident vertices (as pairs of vertex indices). /// public static IEnumerable<(int, int)> GetCoincidentPoints( this Polygon3f polygon, float toleranceAbsolute) { if (toleranceAbsolute < 0) throw new ArgumentOutOfRangeException(); var pc = polygon.PointCount; for (int pi = 0; pi < pc; pi++) { for (int pj = pi + 1; pj < pc; pj++) { if (polygon[pi].ApproximateEquals(polygon[pj], toleranceAbsolute)) yield return (pi, pj); } } } /// /// Returns true if at least two vertices are coincident. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool HasCoincidentPoints( this Polygon3f polygon, float toleranceAbsolute) { return GetCoincidentPoints(polygon, toleranceAbsolute).Any(); } /// /// Enumerates all pairs of edges that intersect (as pairs of edge indices). /// public static IEnumerable<(int, int)> GetSelfIntersections( this Polygon3f polygon, float toleranceAbsolute) { if (toleranceAbsolute < 0) throw new ArgumentOutOfRangeException(); var pc = polygon.PointCount; var la = polygon.GetEdgeLineArray(); for (int i = 0; i < pc; i++) { int jmax = (i > 0) ? pc : pc - 1; for (int j = i + 2; j < jmax; j++) { if (la[i].Intersects(la[j], toleranceAbsolute)) yield return (i, j); } } } /// /// Returns true if at least two edges intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsSelfIntersecting( this Polygon3f self, float toleranceAbsolute = 1e-5f) { return GetSelfIntersections(self, toleranceAbsolute).Any(); } /// /// Enumerates all vertex indexes at which /// both outgoing edges meet at an angle that /// is less than the given threshold. /// public static IEnumerable GetSpikes( this Polygon3f self, float toleranceInDegrees = 0.1f) { if (toleranceInDegrees < 0) throw new ArgumentOutOfRangeException(); var threshold = Conversion.RadiansFromDegrees(toleranceInDegrees).Cos(); var edges = self.GetEdgeArray(); edges.Apply(e => e.Normalized); var ec = edges.Length; if (Vec.Dot(-edges[ec - 1], edges[0]) > threshold) yield return 0; for (int i = 1; i < ec; i++) { if (Vec.Dot(-edges[i - 1], edges[i]) > threshold) yield return i; } } /// /// Returns true if at least one vertex /// both outgoing edges meet at an angle that /// is less than the given threshold. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool HasSpikes( this Polygon3f self, float toleranceInDegrees = 0.1f) { return GetSpikes(self, toleranceInDegrees).Any(); } #endregion } #endregion #region IndexPolygon3fExtensions public static partial class IndexPolygon3fExtensions { #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f ToPolygon3f(this IndexPolygon3f polygon, V2f[] pointArray) => new Polygon2f(polygon.GetPointArray(pointArray)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2f ToPolygon3f(this IndexPolygon3f polygon, List pointList) => new Polygon2f(polygon.GetPointArray(pointList)); #endregion } #endregion #region Polygon3dExtensions public static partial class Polygon3dExtensions { #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d ToPolygon2d(this Polygon3d polygon, Func point_copyFun) => new Polygon2d(polygon.GetPointArray(point_copyFun)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d ToPolygon2d( this Polygon3d polygon, Func point_index_copyFun ) => new Polygon2d(polygon.GetPointArray(point_index_copyFun)); #endregion #region Geometric Properties /// /// Computes the area as the length of the sum of the simple /// triangulation cross-product normals. /// NOTE: This has been tested to be slightly faster and slightly more /// accurate than the computation via the 3d Newell normal /// (see Math.Tests/GeometryTests, rft 2013-05-04). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ComputeArea(this Polygon3d polygon) => 0.5 * polygon.ComputeDoubleAreaNormal().Length; /// /// Computes the normalized normal as the sum of the simple /// triangulation cross-product normals. /// NOTE: This has been tested to be slightly faster and slightly more /// accurate than the computation via the 3d Newell normal /// (see Math.Tests/GeometryTests, rft 2013-05-04). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d ComputeNormal(this Polygon3d polygon) => polygon.ComputeDoubleAreaNormal().Normalized; /// /// The geometric center of a 3-dimensional, flat polygon. /// WARNING: UNTESTED! /// public static V3d ComputeCentroid(this Polygon3d polygon) { var pc = polygon.PointCount; if (pc < 3) return V3d.Zero; V3d p0 = polygon[0], p1 = polygon[1]; V3d e0 = p1 - p0; var p2 = polygon[2]; var e1 = p2 - p0; var normal = e0.Cross(e1); var area2 = normal.Length; var centroid = area2 * (p0 + p1 + p2); p1 = p2; e0 = e1; for (int pi = 3; pi < pc; pi++) { p2 = polygon[pi]; e1 = p2 - p0; var n = e0.Cross(e1); var a2 = Fun.Sign(normal.Dot(n)) * n.Length; area2 += a2; centroid += a2 * (p0 + p1 + p2); p1 = p2; e0 = e1; } if (area2 > Constant.PositiveTinyValue) return centroid * (Constant.OneThird / area2); else if (area2 < Constant.NegativeTinyValue) return centroid * (-Constant.OneThird / area2); else return V3d.Zero; } /// /// Computes the normal with the length of twice the polygon area as /// the sum of the simple triangulation cross-product normals. /// NOTE: This has been tested to be slightly faster and slightly more /// accurate than the computation via the 3d Newell normal /// (see Math.Tests/GeometryTests, rft 2013-05-04). /// public static V3d ComputeDoubleAreaNormal(this Polygon3d polygon) { var pc = polygon.PointCount; if (pc < 3) return V3d.Zero; V3d p0 = polygon[0]; V3d e0 = polygon[1] - p0; V3d normal = V3d.Zero; for (int pi = 2; pi < pc; pi++) { var e1 = polygon[pi] - p0; normal += e0.Cross(e1); e0 = e1; } return normal; } /// /// Computes the supporting plane of the polygon via the vertex centroid /// and the sum of the simple triangulation cross-product normals. /// NOTE: This has been tested to be slightly faster and slightly more /// accurate than the computation via the 3d Newell normal /// (see Math.Tests/GeometryTests, rft 2013-05-04). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Plane3d ComputePlane3d(this Polygon3d polygon) => new Plane3d(polygon.ComputeNormal(), polygon.ComputeVertexCentroid()); /// /// Returns the plane through the first 3 points of the polygon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Plane3d GetPlane3d(this Polygon3d polygon) => new Plane3d(polygon[0], polygon[1], polygon[2]); #endregion #region FormFactor [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ComputeToPointFormFactor( this Polygon3d sourcePolygon, double polygonArea, V3d targetPoint, V3d targetNormal, double eps = 1e-6) { return sourcePolygon.ComputeUnscaledFormFactor( targetPoint, targetNormal, eps) / (Constant.PiTimesTwo * polygonArea); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ComputeFromPointFormFactor( this Polygon3d targetPolygon, V3d sourcePoint, V3d sourceNormal, double eps = 1e-6) { return targetPolygon.ComputeUnscaledFormFactor( sourcePoint, sourceNormal, eps) / Constant.PiTimesTwo; } public static double ComputeUnscaledFormFactor( this Polygon3d polygon, V3d p, V3d n, double eps = 1e-6) { var vc = polygon.PointCount; V3d[] cpa = new V3d[vc + 1]; var cc = 0; var pb = polygon[0] - p; var hb = Vec.Dot(pb, n); bool hbp = hb > eps, hbn = hb < -eps; if (hb >= -eps) cpa[cc++] = pb; var p0 = pb; var h0 = hb; var h0p = hbp; var h0n = hbn; for (int vi = 1; vi < vc; vi++) { var p1 = polygon[vi] - p; var h1 = Vec.Dot(p1, n); bool h1p = h1 > eps, h1n = h1 < -eps; if (h0p && h1n || h0n && h1p) cpa[cc++] = p0 + (p1 - p0) * (h0 / (h0 - h1)); if (h1 >= -eps) cpa[cc++] = p1; p0 = p1; h0 = h1; h0p = h1p; h0n = h1n; } if (h0p && hbn || h0n && hbp) cpa[cc++] = p0 + (pb - p0) * (h0 / (h0 - hb)); var cpr = cpa.Map(cc, v => v.Length); var cv = Vec.Cross(cpa[0], cpa[cc - 1]); double ff = Vec.Dot(n, cv) * Fun.AcosClamped(Vec.Dot(cpa[0], cpa[cc - 1]) / (cpr[0] * cpr[cc - 1])) / cv.Length; for (int ci = 0; ci < cc - 1; ci++) { cv = Vec.Cross(cpa[ci + 1], cpa[ci]); ff += Vec.Dot(n, cv) * Fun.AcosClamped(Vec.Dot(cpa[ci + 1], cpa[ci]) / (cpr[ci + 1] * cpr[ci])) / cv.Length; } return ff; } #endregion #region Shape Analysis /// /// Enumerates all pairs of coincident vertices (as pairs of vertex indices). /// public static IEnumerable<(int, int)> GetCoincidentPoints( this Polygon3d polygon, double toleranceAbsolute) { if (toleranceAbsolute < 0) throw new ArgumentOutOfRangeException(); var pc = polygon.PointCount; for (int pi = 0; pi < pc; pi++) { for (int pj = pi + 1; pj < pc; pj++) { if (polygon[pi].ApproximateEquals(polygon[pj], toleranceAbsolute)) yield return (pi, pj); } } } /// /// Returns true if at least two vertices are coincident. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool HasCoincidentPoints( this Polygon3d polygon, double toleranceAbsolute) { return GetCoincidentPoints(polygon, toleranceAbsolute).Any(); } /// /// Enumerates all pairs of edges that intersect (as pairs of edge indices). /// public static IEnumerable<(int, int)> GetSelfIntersections( this Polygon3d polygon, double toleranceAbsolute) { if (toleranceAbsolute < 0) throw new ArgumentOutOfRangeException(); var pc = polygon.PointCount; var la = polygon.GetEdgeLineArray(); for (int i = 0; i < pc; i++) { int jmax = (i > 0) ? pc : pc - 1; for (int j = i + 2; j < jmax; j++) { if (la[i].Intersects(la[j], toleranceAbsolute)) yield return (i, j); } } } /// /// Returns true if at least two edges intersect. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsSelfIntersecting( this Polygon3d self, double toleranceAbsolute = 1e-10) { return GetSelfIntersections(self, toleranceAbsolute).Any(); } /// /// Enumerates all vertex indexes at which /// both outgoing edges meet at an angle that /// is less than the given threshold. /// public static IEnumerable GetSpikes( this Polygon3d self, double toleranceInDegrees = 0.1) { if (toleranceInDegrees < 0) throw new ArgumentOutOfRangeException(); var threshold = Conversion.RadiansFromDegrees(toleranceInDegrees).Cos(); var edges = self.GetEdgeArray(); edges.Apply(e => e.Normalized); var ec = edges.Length; if (Vec.Dot(-edges[ec - 1], edges[0]) > threshold) yield return 0; for (int i = 1; i < ec; i++) { if (Vec.Dot(-edges[i - 1], edges[i]) > threshold) yield return i; } } /// /// Returns true if at least one vertex /// both outgoing edges meet at an angle that /// is less than the given threshold. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool HasSpikes( this Polygon3d self, double toleranceInDegrees = 0.1) { return GetSpikes(self, toleranceInDegrees).Any(); } #endregion } #endregion #region IndexPolygon3dExtensions public static partial class IndexPolygon3dExtensions { #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d ToPolygon3d(this IndexPolygon3d polygon, V2d[] pointArray) => new Polygon2d(polygon.GetPointArray(pointArray)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Polygon2d ToPolygon3d(this IndexPolygon3d polygon, List pointList) => new Polygon2d(polygon.GetPointArray(pointList)); #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Polygon/Polygon3_template.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var polygon2t = "Polygon2" + tc; //# var polygon3t = "Polygon3" + tc; //# var v2t = "V2" + tc; //# var v3t = "V3" + tc; //# var m22t = "M22" + tc; //# var m44t = "M44" + tc; //# var box2t = "Box2" + tc; //# var plane2t = "Plane2" + tc; //# var plane3t = "Plane3" + tc; //# var line2t = "Line2" + tc; //# var iboundingbox = "IBoundingBox2" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var zerodotone = isDouble ? "0.1" : "0.1f"; //# var constant = isDouble ? "Constant" : "ConstantF"; //# var eps = isDouble ? "1e-6" : "1e-4f"; #region __polygon3t__Extensions public static partial class __polygon3t__Extensions { #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __polygon2t__ To__polygon2t__(this __polygon3t__ polygon, Func<__v3t__, __v2t__> point_copyFun) => new __polygon2t__(polygon.GetPointArray(point_copyFun)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __polygon2t__ To__polygon2t__( this __polygon3t__ polygon, Func<__v3t__, int, __v2t__> point_index_copyFun ) => new __polygon2t__(polygon.GetPointArray(point_index_copyFun)); #endregion #region Geometric Properties /// /// Computes the area as the length of the sum of the simple /// triangulation cross-product normals. /// NOTE: This has been tested to be slightly faster and slightly more /// accurate than the computation via the 3d Newell normal /// (see Math.Tests/GeometryTests, rft 2013-05-04). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ ComputeArea(this __polygon3t__ polygon) => __half__ * polygon.ComputeDoubleAreaNormal().Length; /// /// Computes the normalized normal as the sum of the simple /// triangulation cross-product normals. /// NOTE: This has been tested to be slightly faster and slightly more /// accurate than the computation via the 3d Newell normal /// (see Math.Tests/GeometryTests, rft 2013-05-04). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ ComputeNormal(this __polygon3t__ polygon) => polygon.ComputeDoubleAreaNormal().Normalized; /// /// The geometric center of a 3-dimensional, flat polygon. /// WARNING: UNTESTED! /// public static __v3t__ ComputeCentroid(this __polygon3t__ polygon) { var pc = polygon.PointCount; if (pc < 3) return __v3t__.Zero; __v3t__ p0 = polygon[0], p1 = polygon[1]; __v3t__ e0 = p1 - p0; var p2 = polygon[2]; var e1 = p2 - p0; var normal = e0.Cross(e1); var area2 = normal.Length; var centroid = area2 * (p0 + p1 + p2); p1 = p2; e0 = e1; for (int pi = 3; pi < pc; pi++) { p2 = polygon[pi]; e1 = p2 - p0; var n = e0.Cross(e1); var a2 = Fun.Sign(normal.Dot(n)) * n.Length; area2 += a2; centroid += a2 * (p0 + p1 + p2); p1 = p2; e0 = e1; } if (area2 > Constant<__ftype__>.PositiveTinyValue) return centroid * (__constant__.OneThird / area2); else if (area2 < Constant<__ftype__>.NegativeTinyValue) return centroid * (-__constant__.OneThird / area2); else return __v3t__.Zero; } /// /// Computes the normal with the length of twice the polygon area as /// the sum of the simple triangulation cross-product normals. /// NOTE: This has been tested to be slightly faster and slightly more /// accurate than the computation via the 3d Newell normal /// (see Math.Tests/GeometryTests, rft 2013-05-04). /// public static __v3t__ ComputeDoubleAreaNormal(this __polygon3t__ polygon) { var pc = polygon.PointCount; if (pc < 3) return __v3t__.Zero; __v3t__ p0 = polygon[0]; __v3t__ e0 = polygon[1] - p0; __v3t__ normal = __v3t__.Zero; for (int pi = 2; pi < pc; pi++) { var e1 = polygon[pi] - p0; normal += e0.Cross(e1); e0 = e1; } return normal; } /// /// Computes the supporting plane of the polygon via the vertex centroid /// and the sum of the simple triangulation cross-product normals. /// NOTE: This has been tested to be slightly faster and slightly more /// accurate than the computation via the 3d Newell normal /// (see Math.Tests/GeometryTests, rft 2013-05-04). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __plane3t__ Compute__plane3t__(this __polygon3t__ polygon) => new __plane3t__(polygon.ComputeNormal(), polygon.ComputeVertexCentroid()); /// /// Returns the plane through the first 3 points of the polygon. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __plane3t__ Get__plane3t__(this __polygon3t__ polygon) => new __plane3t__(polygon[0], polygon[1], polygon[2]); #endregion #region FormFactor [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ ComputeToPointFormFactor( this __polygon3t__ sourcePolygon, __ftype__ polygonArea, __v3t__ targetPoint, __v3t__ targetNormal, __ftype__ eps = __eps__) { return sourcePolygon.ComputeUnscaledFormFactor( targetPoint, targetNormal, eps) / (__constant__.PiTimesTwo * polygonArea); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ ComputeFromPointFormFactor( this __polygon3t__ targetPolygon, __v3t__ sourcePoint, __v3t__ sourceNormal, __ftype__ eps = __eps__) { return targetPolygon.ComputeUnscaledFormFactor( sourcePoint, sourceNormal, eps) / __constant__.PiTimesTwo; } public static __ftype__ ComputeUnscaledFormFactor( this __polygon3t__ polygon, __v3t__ p, __v3t__ n, __ftype__ eps = __eps__) { var vc = polygon.PointCount; __v3t__[] cpa = new __v3t__[vc + 1]; var cc = 0; var pb = polygon[0] - p; var hb = Vec.Dot(pb, n); bool hbp = hb > eps, hbn = hb < -eps; if (hb >= -eps) cpa[cc++] = pb; var p0 = pb; var h0 = hb; var h0p = hbp; var h0n = hbn; for (int vi = 1; vi < vc; vi++) { var p1 = polygon[vi] - p; var h1 = Vec.Dot(p1, n); bool h1p = h1 > eps, h1n = h1 < -eps; if (h0p && h1n || h0n && h1p) cpa[cc++] = p0 + (p1 - p0) * (h0 / (h0 - h1)); if (h1 >= -eps) cpa[cc++] = p1; p0 = p1; h0 = h1; h0p = h1p; h0n = h1n; } if (h0p && hbn || h0n && hbp) cpa[cc++] = p0 + (pb - p0) * (h0 / (h0 - hb)); var cpr = cpa.Map(cc, v => v.Length); var cv = Vec.Cross(cpa[0], cpa[cc - 1]); __ftype__ ff = Vec.Dot(n, cv) * Fun.AcosClamped(Vec.Dot(cpa[0], cpa[cc - 1]) / (cpr[0] * cpr[cc - 1])) / cv.Length; for (int ci = 0; ci < cc - 1; ci++) { cv = Vec.Cross(cpa[ci + 1], cpa[ci]); ff += Vec.Dot(n, cv) * Fun.AcosClamped(Vec.Dot(cpa[ci + 1], cpa[ci]) / (cpr[ci + 1] * cpr[ci])) / cv.Length; } return ff; } #endregion #region Shape Analysis /// /// Enumerates all pairs of coincident vertices (as pairs of vertex indices). /// public static IEnumerable<(int, int)> GetCoincidentPoints( this __polygon3t__ polygon, __ftype__ toleranceAbsolute) { if (toleranceAbsolute < 0) throw new ArgumentOutOfRangeException(); var pc = polygon.PointCount; for (int pi = 0; pi < pc; pi++) { for (int pj = pi + 1; pj < pc; pj++) { if (polygon[pi].ApproximateEquals(polygon[pj], toleranceAbsolute)) yield return (pi, pj); } } } /// /// Returns true if at least two vertices are coincident. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool HasCoincidentPoints( this __polygon3t__ polygon, __ftype__ toleranceAbsolute) { return GetCoincidentPoints(polygon, toleranceAbsolute).Any(); } /// /// Enumerates all pairs of edges that intersect (as pairs of edge indices). /// public static IEnumerable<(int, int)> GetSelfIntersections( this __polygon3t__ polygon, __ftype__ toleranceAbsolute) { if (toleranceAbsolute < 0) throw new ArgumentOutOfRangeException(); var pc = polygon.PointCount; var la = polygon.GetEdgeLineArray(); for (int i = 0; i < pc; i++) { int jmax = (i > 0) ? pc : pc - 1; for (int j = i + 2; j < jmax; j++) { if (la[i].Intersects(la[j], toleranceAbsolute)) yield return (i, j); } } } /// /// Returns true if at least two edges intersect. /// //# var toleranceAbsolute = isDouble ? "1e-10" : "1e-5f"; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsSelfIntersecting( this __polygon3t__ self, __ftype__ toleranceAbsolute = __toleranceAbsolute__) { return GetSelfIntersections(self, toleranceAbsolute).Any(); } /// /// Enumerates all vertex indexes at which /// both outgoing edges meet at an angle that /// is less than the given threshold. /// public static IEnumerable GetSpikes( this __polygon3t__ self, __ftype__ toleranceInDegrees = __zerodotone__) { if (toleranceInDegrees < 0) throw new ArgumentOutOfRangeException(); var threshold = Conversion.RadiansFromDegrees(toleranceInDegrees).Cos(); var edges = self.GetEdgeArray(); edges.Apply(e => e.Normalized); var ec = edges.Length; if (Vec.Dot(-edges[ec - 1], edges[0]) > threshold) yield return 0; for (int i = 1; i < ec; i++) { if (Vec.Dot(-edges[i - 1], edges[i]) > threshold) yield return i; } } /// /// Returns true if at least one vertex /// both outgoing edges meet at an angle that /// is less than the given threshold. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool HasSpikes( this __polygon3t__ self, __ftype__ toleranceInDegrees = __zerodotone__) { return GetSpikes(self, toleranceInDegrees).Any(); } #endregion } #endregion #region Index__polygon3t__Extensions public static partial class Index__polygon3t__Extensions { #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __polygon2t__ To__polygon3t__(this Index__polygon3t__ polygon, __v2t__[] pointArray) => new __polygon2t__(polygon.GetPointArray(pointArray)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __polygon2t__ To__polygon3t__(this Index__polygon3t__ polygon, List<__v2t__> pointList) => new __polygon2t__(polygon.GetPointArray(pointList)); #endregion } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Polygon/PolygonExtensions_auto.cs ================================================ using System; using System.Collections.Generic; namespace Aardvark.Base { public static class IPolygonExtensions { // AUTO GENERATED CODE - DO NOT CHANGE! #region Conversions public static IEnumerable GetPoints(this IPolygon polygon) { var pc = polygon.PointCount; for (int pi = 0; pi < pc; pi++) yield return polygon[pi]; } public static T[] GetPointArray(this IPolygon polygon) { var pc = polygon.PointCount; var pointArray = new T[pc]; for (int pi = 0; pi < pc; pi++) pointArray[pi] = polygon[pi]; return pointArray; } public static TCopy[] GetPointArray( this IPolygon polygon, Func point_copyFun) { var pc = polygon.PointCount; var pointArray = new TCopy[pc]; for (int pi = 0; pi < pc; pi++) pointArray[pi] = point_copyFun(polygon[pi]); return pointArray; } #region Polygon2f public static Polygon2f ToPolygon2f( this IPolygon polygon, Func point_copyFun) { var pc = polygon.PointCount; var pointArray = new V2f[pc]; for (int pi = 0; pi < pc; pi++) pointArray[pi] = point_copyFun(polygon[pi]); return new Polygon2f(pointArray); } public static Polygon2f ToPolygon2f( this IPolygon polygon, Func point_index_copyFun) { var pc = polygon.PointCount; var pointArray = new V2f[pc]; for (int pi = 0; pi < pc; pi++) pointArray[pi] = point_index_copyFun(polygon[pi], pi); return new Polygon2f(pointArray); } #endregion #region Polygon3f public static Polygon3f ToPolygon3f( this IPolygon polygon, Func point_copyFun) { var pc = polygon.PointCount; var pointArray = new V3f[pc]; for (int pi = 0; pi < pc; pi++) pointArray[pi] = point_copyFun(polygon[pi]); return new Polygon3f(pointArray); } public static Polygon3f ToPolygon3f( this IPolygon polygon, Func point_index_copyFun) { var pc = polygon.PointCount; var pointArray = new V3f[pc]; for (int pi = 0; pi < pc; pi++) pointArray[pi] = point_index_copyFun(polygon[pi], pi); return new Polygon3f(pointArray); } #endregion #region Polygon2d public static Polygon2d ToPolygon2d( this IPolygon polygon, Func point_copyFun) { var pc = polygon.PointCount; var pointArray = new V2d[pc]; for (int pi = 0; pi < pc; pi++) pointArray[pi] = point_copyFun(polygon[pi]); return new Polygon2d(pointArray); } public static Polygon2d ToPolygon2d( this IPolygon polygon, Func point_index_copyFun) { var pc = polygon.PointCount; var pointArray = new V2d[pc]; for (int pi = 0; pi < pc; pi++) pointArray[pi] = point_index_copyFun(polygon[pi], pi); return new Polygon2d(pointArray); } #endregion #region Polygon3d public static Polygon3d ToPolygon3d( this IPolygon polygon, Func point_copyFun) { var pc = polygon.PointCount; var pointArray = new V3d[pc]; for (int pi = 0; pi < pc; pi++) pointArray[pi] = point_copyFun(polygon[pi]); return new Polygon3d(pointArray); } public static Polygon3d ToPolygon3d( this IPolygon polygon, Func point_index_copyFun) { var pc = polygon.PointCount; var pointArray = new V3d[pc]; for (int pi = 0; pi < pc; pi++) pointArray[pi] = point_index_copyFun(polygon[pi], pi); return new Polygon3d(pointArray); } #endregion #endregion } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Polygon/PolygonExtensions_template.cs ================================================ using System; using System.Collections.Generic; namespace Aardvark.Base { public static class IPolygonExtensions { // AUTO GENERATED CODE - DO NOT CHANGE! #region Conversions public static IEnumerable GetPoints(this IPolygon polygon) { var pc = polygon.PointCount; for (int pi = 0; pi < pc; pi++) yield return polygon[pi]; } public static T[] GetPointArray(this IPolygon polygon) { var pc = polygon.PointCount; var pointArray = new T[pc]; for (int pi = 0; pi < pc; pi++) pointArray[pi] = polygon[pi]; return pointArray; } public static TCopy[] GetPointArray( this IPolygon polygon, Func point_copyFun) { var pc = polygon.PointCount; var pointArray = new TCopy[pc]; for (int pi = 0; pi < pc; pi++) pointArray[pi] = point_copyFun(polygon[pi]); return pointArray; } //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var tc = isDouble ? "d" : "f"; //# var polygon2t = "Polygon2" + tc; //# var polygon3t = "Polygon3" + tc; //# var v2t = "V2" + tc; //# var v3t = "V3" + tc; #region __polygon2t__ public static __polygon2t__ To__polygon2t__( this IPolygon polygon, Func point_copyFun) { var pc = polygon.PointCount; var pointArray = new __v2t__[pc]; for (int pi = 0; pi < pc; pi++) pointArray[pi] = point_copyFun(polygon[pi]); return new __polygon2t__(pointArray); } public static __polygon2t__ To__polygon2t__( this IPolygon polygon, Func point_index_copyFun) { var pc = polygon.PointCount; var pointArray = new __v2t__[pc]; for (int pi = 0; pi < pc; pi++) pointArray[pi] = point_index_copyFun(polygon[pi], pi); return new __polygon2t__(pointArray); } #endregion #region __polygon3t__ public static __polygon3t__ To__polygon3t__( this IPolygon polygon, Func point_copyFun) { var pc = polygon.PointCount; var pointArray = new __v3t__[pc]; for (int pi = 0; pi < pc; pi++) pointArray[pi] = point_copyFun(polygon[pi]); return new __polygon3t__(pointArray); } public static __polygon3t__ To__polygon3t__( this IPolygon polygon, Func point_index_copyFun) { var pc = polygon.PointCount; var pointArray = new __v3t__[pc]; for (int pi = 0; pi < pc; pi++) pointArray[pi] = point_index_copyFun(polygon[pi], pi); return new __polygon3t__(pointArray); } #endregion //# } #endregion } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Quad/Quad2_auto.cs ================================================ using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Quad2f /// /// A two-dimensional quadrangle specified by its four points. /// public partial struct Quad2f { #region Geometric Properties public readonly float Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => 0.5f * ((P2.X - P0.X) * (P3.Y - P1.Y) - (P3.X - P1.X) * (P2.Y - P0.Y)).Abs(); } public readonly bool IsDegenerated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (P1 - P0).AllTiny || (P2 - P1).AllTiny || (P3 - P2).AllTiny || (P0 - P3).AllTiny || WindingOrder.IsTiny(); } /// /// Returns a value less than zero for ccw and greater than zero for cw. /// The magnitude magnitude is twice the area. /// public readonly float WindingOrder { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (P2.X - P0.X) * (P3.Y - P1.Y) - (P3.X - P1.X) * (P2.Y - P0.Y); } #endregion } #endregion #region Quad2d /// /// A two-dimensional quadrangle specified by its four points. /// public partial struct Quad2d { #region Geometric Properties public readonly double Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => 0.5 * ((P2.X - P0.X) * (P3.Y - P1.Y) - (P3.X - P1.X) * (P2.Y - P0.Y)).Abs(); } public readonly bool IsDegenerated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (P1 - P0).AllTiny || (P2 - P1).AllTiny || (P3 - P2).AllTiny || (P0 - P3).AllTiny || WindingOrder.IsTiny(); } /// /// Returns a value less than zero for ccw and greater than zero for cw. /// The magnitude magnitude is twice the area. /// public readonly double WindingOrder { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (P2.X - P0.X) * (P3.Y - P1.Y) - (P3.X - P1.X) * (P2.Y - P0.Y); } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Quad/Quad2_template.cs ================================================ using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var tc = isDouble ? "d" : "f"; //# var type = "Quad2" + tc; //# var v2t = "V2" + tc; //# var pi = isDouble ? "Constant.Pi" : "ConstantF.Pi"; //# var half = isDouble ? "0.5" : "0.5f"; #region __type__ /// /// A two-dimensional quadrangle specified by its four points. /// public partial struct __type__ { #region Geometric Properties public readonly __ftype__ Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => __half__ * ((P2.X - P0.X) * (P3.Y - P1.Y) - (P3.X - P1.X) * (P2.Y - P0.Y)).Abs(); } public readonly bool IsDegenerated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (P1 - P0).AllTiny || (P2 - P1).AllTiny || (P3 - P2).AllTiny || (P0 - P3).AllTiny || WindingOrder.IsTiny(); } /// /// Returns a value less than zero for ccw and greater than zero for cw. /// The magnitude magnitude is twice the area. /// public readonly __ftype__ WindingOrder { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (P2.X - P0.X) * (P3.Y - P1.Y) - (P3.X - P1.X) * (P2.Y - P0.Y); } #endregion } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Quad/Quad3_auto.cs ================================================ using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Quad3f /// /// A three-dimensional quadrangle specified by its four points. /// The points are not required to lie on the same plane. /// public partial struct Quad3f { #region Geometric Properties /// /// Returns the area when projected onto a plane normal to the area /// weighted average normal of the triangles (P0,P1,P2) and (P0,P2,P3). /// public readonly float Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var v02 = P2 - P0; return 0.5f * ((P1 - P0).Cross(v02) + v02.Cross(P3 - P0)).Length; } } public readonly bool IsDegenerated { get { var v01 = P1 - P0; if (v01.AllTiny) return true; var v03 = P3 - P0; if (v03.AllTiny) return true; if ((P2 - P1).AllTiny || (P3 - P2).AllTiny) return true; var v02 = P2 - P0; return (v01.Cross(v02) + v02.Cross(v03)).AllTiny; } } public readonly V3f Normal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var v02 = P2 - P0; return ((P1 - P0).Cross(v02) + v02.Cross(P3 - P0)).Normalized; } } #endregion } #endregion #region Quad3d /// /// A three-dimensional quadrangle specified by its four points. /// The points are not required to lie on the same plane. /// public partial struct Quad3d { #region Geometric Properties /// /// Returns the area when projected onto a plane normal to the area /// weighted average normal of the triangles (P0,P1,P2) and (P0,P2,P3). /// public readonly double Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var v02 = P2 - P0; return 0.5 * ((P1 - P0).Cross(v02) + v02.Cross(P3 - P0)).Length; } } public readonly bool IsDegenerated { get { var v01 = P1 - P0; if (v01.AllTiny) return true; var v03 = P3 - P0; if (v03.AllTiny) return true; if ((P2 - P1).AllTiny || (P3 - P2).AllTiny) return true; var v02 = P2 - P0; return (v01.Cross(v02) + v02.Cross(v03)).AllTiny; } } public readonly V3d Normal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var v02 = P2 - P0; return ((P1 - P0).Cross(v02) + v02.Cross(P3 - P0)).Normalized; } } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Quad/Quad3_template.cs ================================================ using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var tc = isDouble ? "d" : "f"; //# var type = "Quad3" + tc; //# var v3t = "V3" + tc; //# var pi = isDouble ? "Constant.Pi" : "ConstantF.Pi"; //# var half = isDouble ? "0.5" : "0.5f"; #region __type__ /// /// A three-dimensional quadrangle specified by its four points. /// The points are not required to lie on the same plane. /// public partial struct __type__ { #region Geometric Properties /// /// Returns the area when projected onto a plane normal to the area /// weighted average normal of the triangles (P0,P1,P2) and (P0,P2,P3). /// public readonly __ftype__ Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var v02 = P2 - P0; return __half__ * ((P1 - P0).Cross(v02) + v02.Cross(P3 - P0)).Length; } } public readonly bool IsDegenerated { get { var v01 = P1 - P0; if (v01.AllTiny) return true; var v03 = P3 - P0; if (v03.AllTiny) return true; if ((P2 - P1).AllTiny || (P3 - P2).AllTiny) return true; var v02 = P2 - P0; return (v01.Cross(v02) + v02.Cross(v03)).AllTiny; } } public readonly __v3t__ Normal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var v02 = P2 - P0; return ((P1 - P0).Cross(v02) + v02.Cross(P3 - P0)).Normalized; } } #endregion } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Quadric/Quadric_auto.cs ================================================ using System; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region QuadricF public struct QuadricF { V3f m_normal; M44f m_errorQuadric; #region Properties public V3f Normal { readonly get { return m_normal.Normalized; } set { m_normal = value; } } public M44f ErrorQuadric { readonly get { return m_errorQuadric; } set { m_errorQuadric = value; } } public readonly float ErrorOffset => ErrorQuadric.M33; public M44f ErrorHeuristic { readonly get; set; } #endregion public void Create(Plane3f plane) { CreateQuadric(plane); CreateHeuristic(); } #region Create QuadricF/Heuristic public void CreateQuadric(Plane3f plane) { Normal = plane.Normal; float a = Normal.X; float b = Normal.Y; float c = Normal.Z; // Garland uses "ax + by + cz + d = 0" // Aardvark uses "ax + by + cz - d = 0" float d = -plane.Distance; m_errorQuadric.M00 = a * a; m_errorQuadric.M11 = b * b; m_errorQuadric.M22 = c * c; m_errorQuadric.M33 = d * d; m_errorQuadric.M01 = m_errorQuadric.M10 = a * b; m_errorQuadric.M02 = m_errorQuadric.M20 = a * c; m_errorQuadric.M03 = m_errorQuadric.M30 = a * d; m_errorQuadric.M12 = m_errorQuadric.M21 = b * c; m_errorQuadric.M13 = m_errorQuadric.M31 = b * d; m_errorQuadric.M23 = m_errorQuadric.M32 = c * d; } public void CreateHeuristic() { if (m_errorQuadric == M44f.Zero) { throw new InvalidOperationException("Must call CreateQuadric(...) first"); } ErrorHeuristic = ToHeuristic(ErrorQuadric); } #endregion #region Operator Overload public static QuadricF operator +(QuadricF lhs, QuadricF rhs) { var result = new QuadricF { ErrorQuadric = lhs.ErrorQuadric + rhs.ErrorQuadric, Normal = lhs.Normal + rhs.Normal }; result.ErrorHeuristic = ToHeuristic(result.ErrorQuadric); return result; } //public static QuadricF operator -(QuadricF lhs, QuadricF rhs) //{ // QuadricF result = new QuadricF(); // result.ErrorQuadric = lhs.ErrorQuadric - rhs.ErrorQuadric; // result.ErrorHeuristic = QuadricF.ToHeuristic(result.ErrorQuadric); // return result; //} #endregion #region Static Methods static M44f ToHeuristic(M44f quadric) { var result = new M44f(); result = quadric; result.R3 = new V4f(0, 0, 0, 1); return result; } #endregion } #endregion #region QuadricD public struct QuadricD { V3d m_normal; M44d m_errorQuadric; #region Properties public V3d Normal { readonly get { return m_normal.Normalized; } set { m_normal = value; } } public M44d ErrorQuadric { readonly get { return m_errorQuadric; } set { m_errorQuadric = value; } } public readonly double ErrorOffset => ErrorQuadric.M33; public M44d ErrorHeuristic { readonly get; set; } #endregion public void Create(Plane3d plane) { CreateQuadric(plane); CreateHeuristic(); } #region Create QuadricD/Heuristic public void CreateQuadric(Plane3d plane) { Normal = plane.Normal; double a = Normal.X; double b = Normal.Y; double c = Normal.Z; // Garland uses "ax + by + cz + d = 0" // Aardvark uses "ax + by + cz - d = 0" double d = -plane.Distance; m_errorQuadric.M00 = a * a; m_errorQuadric.M11 = b * b; m_errorQuadric.M22 = c * c; m_errorQuadric.M33 = d * d; m_errorQuadric.M01 = m_errorQuadric.M10 = a * b; m_errorQuadric.M02 = m_errorQuadric.M20 = a * c; m_errorQuadric.M03 = m_errorQuadric.M30 = a * d; m_errorQuadric.M12 = m_errorQuadric.M21 = b * c; m_errorQuadric.M13 = m_errorQuadric.M31 = b * d; m_errorQuadric.M23 = m_errorQuadric.M32 = c * d; } public void CreateHeuristic() { if (m_errorQuadric == M44d.Zero) { throw new InvalidOperationException("Must call CreateQuadric(...) first"); } ErrorHeuristic = ToHeuristic(ErrorQuadric); } #endregion #region Operator Overload public static QuadricD operator +(QuadricD lhs, QuadricD rhs) { var result = new QuadricD { ErrorQuadric = lhs.ErrorQuadric + rhs.ErrorQuadric, Normal = lhs.Normal + rhs.Normal }; result.ErrorHeuristic = ToHeuristic(result.ErrorQuadric); return result; } //public static QuadricD operator -(QuadricD lhs, QuadricD rhs) //{ // QuadricD result = new QuadricD(); // result.ErrorQuadric = lhs.ErrorQuadric - rhs.ErrorQuadric; // result.ErrorHeuristic = QuadricD.ToHeuristic(result.ErrorQuadric); // return result; //} #endregion #region Static Methods static M44d ToHeuristic(M44d quadric) { var result = new M44d(); result = quadric; result.R3 = new V4d(0, 0, 0, 1); return result; } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Quadric/Quadric_template.cs ================================================ using System; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var tccaps = tc.ToUpper(); //# var tccaps2 = tc2.ToUpper(); //# var type = "Quadric" + tccaps; //# var type2 = "Quadric" + tccaps2; //# var v3t = "V3" + tc; //# var v4t = "V4" + tc; //# var plane3t = "Plane3" + tc; //# var m44t = "M44" + tc; //# var pi = isDouble ? "Constant.Pi" : "ConstantF.Pi"; //# var half = isDouble ? "0.5" : "0.5f"; #region __type__ public struct __type__ { __v3t__ m_normal; __m44t__ m_errorQuadric; #region Properties public __v3t__ Normal { readonly get { return m_normal.Normalized; } set { m_normal = value; } } public __m44t__ ErrorQuadric { readonly get { return m_errorQuadric; } set { m_errorQuadric = value; } } public readonly __ftype__ ErrorOffset => ErrorQuadric.M33; public __m44t__ ErrorHeuristic { readonly get; set; } #endregion public void Create(__plane3t__ plane) { CreateQuadric(plane); CreateHeuristic(); } #region Create __type__/Heuristic public void CreateQuadric(__plane3t__ plane) { Normal = plane.Normal; __ftype__ a = Normal.X; __ftype__ b = Normal.Y; __ftype__ c = Normal.Z; // Garland uses "ax + by + cz + d = 0" // Aardvark uses "ax + by + cz - d = 0" __ftype__ d = -plane.Distance; m_errorQuadric.M00 = a * a; m_errorQuadric.M11 = b * b; m_errorQuadric.M22 = c * c; m_errorQuadric.M33 = d * d; m_errorQuadric.M01 = m_errorQuadric.M10 = a * b; m_errorQuadric.M02 = m_errorQuadric.M20 = a * c; m_errorQuadric.M03 = m_errorQuadric.M30 = a * d; m_errorQuadric.M12 = m_errorQuadric.M21 = b * c; m_errorQuadric.M13 = m_errorQuadric.M31 = b * d; m_errorQuadric.M23 = m_errorQuadric.M32 = c * d; } public void CreateHeuristic() { if (m_errorQuadric == __m44t__.Zero) { throw new InvalidOperationException("Must call CreateQuadric(...) first"); } ErrorHeuristic = ToHeuristic(ErrorQuadric); } #endregion #region Operator Overload public static __type__ operator +(__type__ lhs, __type__ rhs) { var result = new __type__ { ErrorQuadric = lhs.ErrorQuadric + rhs.ErrorQuadric, Normal = lhs.Normal + rhs.Normal }; result.ErrorHeuristic = ToHeuristic(result.ErrorQuadric); return result; } //public static __type__ operator -(__type__ lhs, __type__ rhs) //{ // __type__ result = new __type__(); // result.ErrorQuadric = lhs.ErrorQuadric - rhs.ErrorQuadric; // result.ErrorHeuristic = __type__.ToHeuristic(result.ErrorQuadric); // return result; //} #endregion #region Static Methods static __m44t__ ToHeuristic(__m44t__ quadric) { var result = new __m44t__(); result = quadric; result.R3 = new __v4t__(0, 0, 0, 1); return result; } #endregion } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Ray/Ray2_auto.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Ray2f /// /// A two-dimensional ray with an origin and a direction. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Ray2f : IEquatable, IValidity, IBoundingBox2f { [DataMember] public V2f Origin; [DataMember] public V2f Direction; #region Constructors /// /// Creates Ray from origin point and directional vector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ray2f(V2f origin, V2f direction) { Origin = origin; Direction = direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ray2f(Ray2f o) { Origin = o.Origin; Direction = o.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ray2f(Ray2d o) { Origin = (V2f)o.Origin; Direction = (V2f)o.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Ray2f FromEndPoints(V2f origin, V2f target) => new Ray2f(origin, target - origin); #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Ray2f(Ray2d c) => new Ray2f(c); #endregion #region Constants /// /// An invalid ray has a zero direction. /// public static Ray2f Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Ray2f(V2f.NaN, V2f.Zero); } #endregion #region Properties /// /// A ray is valid if its direction is non-zero. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Direction != V2f.Zero; } /// /// A ray is invalid if its direction is zero. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Direction == V2f.Zero; } /// /// Returns true if either the origin or the direction contains any NaN value. /// public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Origin.AnyNaN || Direction.AnyNaN; } public readonly Line2f Line2f { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Line2f(Origin, Origin + Direction); } public readonly Plane2f Plane2f { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane2f(new V2f(-Direction.Y, Direction.X), Origin); // Direction.Rot90 } public readonly Ray2f Reversed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Ray2f(Origin, -Direction); } /// /// Returns the ray with its directional normalized. /// public readonly Ray2f Normalized => new(Origin, Direction.Normalized); #endregion #region Ray Arithmetics /// /// Gets the point on the ray that is t * direction from origin. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f GetPointOnRay(float t) => (Origin + Direction * t); /// /// Gets segment on the ray starting at range.Min * direction from origin /// and ending at range.Max * direction from origin. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Line2f GetLine2fOnRay(Range1f range) => new Line2f(Origin + Direction * range.Min, Origin + Direction * range.Max); /// /// Gets segment on the ray starting at tMin * direction from origin /// and ending at tMax * direction from origin. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Line2f GetLine2fOnRay(float tMin, float tMax) => new Line2f(Origin + Direction * tMin, Origin + Direction * tMax); /// /// Gets the t for a point p on this ray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float GetT(V2f p) { var v = p - Origin; return (Direction.X.Abs() > Direction.Y.Abs()) ? (v.X / Direction.X) : (v.Y / Direction.Y); } /// /// Gets the point on the ray that is closest to the given point. /// Ray direction must be normalized (length 1). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f GetClosestPointOnRay(V2f p) => Origin + Direction * Direction.Dot(p - Origin); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float GetDistanceToRay(V2f p) { var f = GetClosestPointOnRay(p); return (f - p).Length; } public readonly V2f Intersect(Ray2f r) { V2f a = r.Origin - Origin; if (a.Abs().AllSmaller(Constant.PositiveTinyValue)) return Origin; // Early exit when rays have same origin float cross = Direction.Dot270(r.Direction); if (!Fun.IsTiny(cross)) // Rays not parallel return Origin + Direction * r.Direction.Dot90(a) / cross; else // Rays are parallel return V2f.NaN; } public readonly V2f Intersect(V2f dirVector) { if (Origin.Abs().AllSmaller(Constant.PositiveTinyValue)) return Origin; // Early exit when rays have same origin float cross = Direction.Dot270(dirVector); if (!Fun.IsTiny(cross)) // Rays not parallel return Origin + Direction * dirVector.Dot270(Origin) / cross; else // Rays are parallel return V2f.NaN; } /// /// Returns the angle between this and the given in radians. /// The direction vectors of the input rays have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float AngleBetweenFast(Ray2f r) => Direction.AngleBetweenFast(r.Direction); /// /// Returns the angle between this and the given in radians using a numerically stable algorithm. /// The direction vectors of the input rays have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float AngleBetween(Ray2f r) => Direction.AngleBetween(r.Direction); /// /// Returns the signed angle between this and the given in radians. /// The direction vectors of the input rays have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float AngleBetweenSigned(Ray2f r) => Direction.AngleBetweenSigned(r.Direction); /// /// Returns a signed value where left is negative and right positive. /// The magnitude is equal to the float size of the triangle the ray + direction and p. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float GetPointSide(V2f p) => Direction.Dot90(p - Origin); #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Ray2f a, Ray2f b) => (a.Origin == b.Origin) && (a.Direction == b.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Ray2f a, Ray2f b) => !((a.Origin == b.Origin) && (a.Direction == b.Direction)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int LexicalCompare(Ray2f other) { var cmp = Origin.LexicalCompare(other.Origin); if (cmp != 0) return cmp; return Direction.LexicalCompare(other.Direction); } #endregion #region Overrides /// /// Calculates Hash-code of the given ray. /// /// Hash-code. [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Origin, Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Ray2f other) => Origin.Equals(other.Origin) && Direction.Equals(other.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Ray2f o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Origin, Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Ray2f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Ray2f(V2f.Parse(x[0]), V2f.Parse(x[1])); } #endregion #region IBoundingBox2f public readonly Box2f BoundingBox2f { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Box2f.FromPoints(Origin, Direction + Origin); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Ray2f a, Ray2f b, float tolerance) => ApproximateEquals(a.Origin, b.Origin, tolerance) && ApproximateEquals(a.Direction, b.Direction, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Ray2f a, Ray2f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region FastRay2f /// /// A fast ray contains a ray and a number of precomputed flags and /// fields for fast intersection computation with bounding boxes and /// other axis-aligned sturctures such as kd-Trees. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public readonly partial struct FastRay2f { [DataMember] public readonly Ray2f Ray; [DataMember] public readonly DirFlags DirFlags; [DataMember] public readonly V2f InvDir; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public FastRay2f(Ray2f ray) { Ray = ray; DirFlags = ray.Direction.DirFlags(); InvDir = 1 / ray.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FastRay2f(V2f origin, V2f direction) : this(new Ray2f(origin, direction)) { } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FastRay2f(FastRay2f o) { Ray = o.Ray; DirFlags = o.DirFlags; InvDir = o.InvDir; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FastRay2f(FastRay2d o) { Ray = (Ray2f)o.Ray; DirFlags = o.DirFlags; InvDir = (V2f)o.InvDir; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator FastRay2f(FastRay2d r) => new FastRay2f(r); #endregion #region Ray Arithmetics public bool Intersects( Box2f box, ref float tmin, ref float tmax ) { var dirFlags = DirFlags; if ((dirFlags & DirFlags.PositiveX) != 0) { { float t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } { float t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeX) != 0) { { float t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } { float t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to X-plane { if (Ray.Origin.X < box.Min.X || Ray.Origin.X > box.Max.X) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { { float t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } { float t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeY) != 0) { { float t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } { float t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to Y-plane { if (Ray.Origin.Y < box.Min.Y || Ray.Origin.Y > box.Max.Y) return false; } if (tmin > tmax) return false; return true; } /// /// This variant of the intersection method returns the affected /// planes of the box if the box was hit. /// public bool Intersects( Box2f box, ref float tmin, ref float tmax, out Box.Flags tminFlags, out Box.Flags tmaxFlags ) { var dirFlags = DirFlags; tminFlags = Box.Flags.None; tmaxFlags = Box.Flags.None; if ((dirFlags & DirFlags.PositiveX) != 0) { { float t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxX; } } { float t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinX; } } } else if ((dirFlags & DirFlags.NegativeX) != 0) { { float t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinX; } } { float t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxX; } } } else // ray parallel to X-plane { if (Ray.Origin.X < box.Min.X || Ray.Origin.X > box.Max.X) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { { float t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxY; } } { float t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinY; } } } else if ((dirFlags & DirFlags.NegativeY) != 0) { { float t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinY; } } { float t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxY; } } } else // ray parallel to Y-plane { if (Ray.Origin.Y < box.Min.Y || Ray.Origin.Y > box.Max.Y) return false; } if (tmin > tmax) return false; return true; } #endregion } #endregion #region Ray2d /// /// A two-dimensional ray with an origin and a direction. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Ray2d : IEquatable, IValidity, IBoundingBox2d { [DataMember] public V2d Origin; [DataMember] public V2d Direction; #region Constructors /// /// Creates Ray from origin point and directional vector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ray2d(V2d origin, V2d direction) { Origin = origin; Direction = direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ray2d(Ray2d o) { Origin = o.Origin; Direction = o.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Ray2d(Ray2f o) { Origin = (V2d)o.Origin; Direction = (V2d)o.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Ray2d FromEndPoints(V2d origin, V2d target) => new Ray2d(origin, target - origin); #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Ray2d(Ray2f c) => new Ray2d(c); #endregion #region Constants /// /// An invalid ray has a zero direction. /// public static Ray2d Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Ray2d(V2d.NaN, V2d.Zero); } #endregion #region Properties /// /// A ray is valid if its direction is non-zero. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Direction != V2d.Zero; } /// /// A ray is invalid if its direction is zero. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Direction == V2d.Zero; } /// /// Returns true if either the origin or the direction contains any NaN value. /// public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Origin.AnyNaN || Direction.AnyNaN; } public readonly Line2d Line2d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Line2d(Origin, Origin + Direction); } public readonly Plane2d Plane2d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Plane2d(new V2d(-Direction.Y, Direction.X), Origin); // Direction.Rot90 } public readonly Ray2d Reversed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Ray2d(Origin, -Direction); } /// /// Returns the ray with its directional normalized. /// public readonly Ray2d Normalized => new(Origin, Direction.Normalized); #endregion #region Ray Arithmetics /// /// Gets the point on the ray that is t * direction from origin. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d GetPointOnRay(double t) => (Origin + Direction * t); /// /// Gets segment on the ray starting at range.Min * direction from origin /// and ending at range.Max * direction from origin. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Line2d GetLine2dOnRay(Range1d range) => new Line2d(Origin + Direction * range.Min, Origin + Direction * range.Max); /// /// Gets segment on the ray starting at tMin * direction from origin /// and ending at tMax * direction from origin. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Line2d GetLine2dOnRay(double tMin, double tMax) => new Line2d(Origin + Direction * tMin, Origin + Direction * tMax); /// /// Gets the t for a point p on this ray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double GetT(V2d p) { var v = p - Origin; return (Direction.X.Abs() > Direction.Y.Abs()) ? (v.X / Direction.X) : (v.Y / Direction.Y); } /// /// Gets the point on the ray that is closest to the given point. /// Ray direction must be normalized (length 1). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d GetClosestPointOnRay(V2d p) => Origin + Direction * Direction.Dot(p - Origin); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double GetDistanceToRay(V2d p) { var f = GetClosestPointOnRay(p); return (f - p).Length; } public readonly V2d Intersect(Ray2d r) { V2d a = r.Origin - Origin; if (a.Abs().AllSmaller(Constant.PositiveTinyValue)) return Origin; // Early exit when rays have same origin double cross = Direction.Dot270(r.Direction); if (!Fun.IsTiny(cross)) // Rays not parallel return Origin + Direction * r.Direction.Dot90(a) / cross; else // Rays are parallel return V2d.NaN; } public readonly V2d Intersect(V2d dirVector) { if (Origin.Abs().AllSmaller(Constant.PositiveTinyValue)) return Origin; // Early exit when rays have same origin double cross = Direction.Dot270(dirVector); if (!Fun.IsTiny(cross)) // Rays not parallel return Origin + Direction * dirVector.Dot270(Origin) / cross; else // Rays are parallel return V2d.NaN; } /// /// Returns the angle between this and the given in radians. /// The direction vectors of the input rays have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double AngleBetweenFast(Ray2d r) => Direction.AngleBetweenFast(r.Direction); /// /// Returns the angle between this and the given in radians using a numerically stable algorithm. /// The direction vectors of the input rays have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double AngleBetween(Ray2d r) => Direction.AngleBetween(r.Direction); /// /// Returns the signed angle between this and the given in radians. /// The direction vectors of the input rays have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double AngleBetweenSigned(Ray2d r) => Direction.AngleBetweenSigned(r.Direction); /// /// Returns a signed value where left is negative and right positive. /// The magnitude is equal to the double size of the triangle the ray + direction and p. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double GetPointSide(V2d p) => Direction.Dot90(p - Origin); #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Ray2d a, Ray2d b) => (a.Origin == b.Origin) && (a.Direction == b.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Ray2d a, Ray2d b) => !((a.Origin == b.Origin) && (a.Direction == b.Direction)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int LexicalCompare(Ray2d other) { var cmp = Origin.LexicalCompare(other.Origin); if (cmp != 0) return cmp; return Direction.LexicalCompare(other.Direction); } #endregion #region Overrides /// /// Calculates Hash-code of the given ray. /// /// Hash-code. [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Origin, Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Ray2d other) => Origin.Equals(other.Origin) && Direction.Equals(other.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Ray2d o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Origin, Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Ray2d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Ray2d(V2d.Parse(x[0]), V2d.Parse(x[1])); } #endregion #region IBoundingBox2d public readonly Box2d BoundingBox2d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Box2d.FromPoints(Origin, Direction + Origin); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Ray2d a, Ray2d b, double tolerance) => ApproximateEquals(a.Origin, b.Origin, tolerance) && ApproximateEquals(a.Direction, b.Direction, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Ray2d a, Ray2d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region FastRay2d /// /// A fast ray contains a ray and a number of precomputed flags and /// fields for fast intersection computation with bounding boxes and /// other axis-aligned sturctures such as kd-Trees. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public readonly partial struct FastRay2d { [DataMember] public readonly Ray2d Ray; [DataMember] public readonly DirFlags DirFlags; [DataMember] public readonly V2d InvDir; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public FastRay2d(Ray2d ray) { Ray = ray; DirFlags = ray.Direction.DirFlags(); InvDir = 1 / ray.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FastRay2d(V2d origin, V2d direction) : this(new Ray2d(origin, direction)) { } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FastRay2d(FastRay2d o) { Ray = o.Ray; DirFlags = o.DirFlags; InvDir = o.InvDir; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public FastRay2d(FastRay2f o) { Ray = (Ray2d)o.Ray; DirFlags = o.DirFlags; InvDir = (V2d)o.InvDir; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator FastRay2d(FastRay2f r) => new FastRay2d(r); #endregion #region Ray Arithmetics public bool Intersects( Box2d box, ref double tmin, ref double tmax ) { var dirFlags = DirFlags; if ((dirFlags & DirFlags.PositiveX) != 0) { { double t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } { double t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeX) != 0) { { double t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } { double t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to X-plane { if (Ray.Origin.X < box.Min.X || Ray.Origin.X > box.Max.X) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { { double t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } { double t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeY) != 0) { { double t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } { double t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to Y-plane { if (Ray.Origin.Y < box.Min.Y || Ray.Origin.Y > box.Max.Y) return false; } if (tmin > tmax) return false; return true; } /// /// This variant of the intersection method returns the affected /// planes of the box if the box was hit. /// public bool Intersects( Box2d box, ref double tmin, ref double tmax, out Box.Flags tminFlags, out Box.Flags tmaxFlags ) { var dirFlags = DirFlags; tminFlags = Box.Flags.None; tmaxFlags = Box.Flags.None; if ((dirFlags & DirFlags.PositiveX) != 0) { { double t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxX; } } { double t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinX; } } } else if ((dirFlags & DirFlags.NegativeX) != 0) { { double t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinX; } } { double t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxX; } } } else // ray parallel to X-plane { if (Ray.Origin.X < box.Min.X || Ray.Origin.X > box.Max.X) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { { double t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxY; } } { double t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinY; } } } else if ((dirFlags & DirFlags.NegativeY) != 0) { { double t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinY; } } { double t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxY; } } } else // ray parallel to Y-plane { if (Ray.Origin.Y < box.Min.Y || Ray.Origin.Y > box.Max.Y) return false; } if (tmin > tmax) return false; return true; } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Ray/Ray2_template.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var ray2t = "Ray2" + tc; //# var ray2t2 = "Ray2" + tc2; //# var fastray2t = "FastRay2" + tc; //# var fastray2t2 = "FastRay2" + tc2; //# var v2t = "V2" + tc; //# var range1t = "Range1" + tc; //# var box2t = "Box2" + tc; //# var plane2t = "Plane2" + tc; //# var line2t = "Line2" + tc; //# var iboundingbox = "IBoundingBox2" + tc; //# var half = isDouble ? "0.5" : "0.5f"; #region __ray2t__ /// /// A two-dimensional ray with an origin and a direction. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __ray2t__ : IEquatable<__ray2t__>, IValidity, __iboundingbox__ { [DataMember] public __v2t__ Origin; [DataMember] public __v2t__ Direction; #region Constructors /// /// Creates Ray from origin point and directional vector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __ray2t__(__v2t__ origin, __v2t__ direction) { Origin = origin; Direction = direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __ray2t__(__ray2t__ o) { Origin = o.Origin; Direction = o.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __ray2t__(__ray2t2__ o) { Origin = (__v2t__)o.Origin; Direction = (__v2t__)o.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ray2t__ FromEndPoints(__v2t__ origin, __v2t__ target) => new __ray2t__(origin, target - origin); #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __ray2t__(__ray2t2__ c) => new __ray2t__(c); #endregion #region Constants /// /// An invalid ray has a zero direction. /// public static __ray2t__ Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __ray2t__(__v2t__.NaN, __v2t__.Zero); } #endregion #region Properties /// /// A ray is valid if its direction is non-zero. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Direction != __v2t__.Zero; } /// /// A ray is invalid if its direction is zero. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Direction == __v2t__.Zero; } /// /// Returns true if either the origin or the direction contains any NaN value. /// public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Origin.AnyNaN || Direction.AnyNaN; } public readonly __line2t__ __line2t__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __line2t__(Origin, Origin + Direction); } public readonly __plane2t__ __plane2t__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __plane2t__(new __v2t__(-Direction.Y, Direction.X), Origin); // Direction.Rot90 } public readonly __ray2t__ Reversed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __ray2t__(Origin, -Direction); } /// /// Returns the ray with its directional normalized. /// public readonly __ray2t__ Normalized => new(Origin, Direction.Normalized); #endregion #region Ray Arithmetics /// /// Gets the point on the ray that is t * direction from origin. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __v2t__ GetPointOnRay(__ftype__ t) => (Origin + Direction * t); /// /// Gets segment on the ray starting at range.Min * direction from origin /// and ending at range.Max * direction from origin. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __line2t__ Get__line2t__OnRay(__range1t__ range) => new __line2t__(Origin + Direction * range.Min, Origin + Direction * range.Max); /// /// Gets segment on the ray starting at tMin * direction from origin /// and ending at tMax * direction from origin. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __line2t__ Get__line2t__OnRay(__ftype__ tMin, __ftype__ tMax) => new __line2t__(Origin + Direction * tMin, Origin + Direction * tMax); /// /// Gets the t for a point p on this ray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__ GetT(__v2t__ p) { var v = p - Origin; return (Direction.X.Abs() > Direction.Y.Abs()) ? (v.X / Direction.X) : (v.Y / Direction.Y); } /// /// Gets the point on the ray that is closest to the given point. /// Ray direction must be normalized (length 1). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __v2t__ GetClosestPointOnRay(__v2t__ p) => Origin + Direction * Direction.Dot(p - Origin); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__ GetDistanceToRay(__v2t__ p) { var f = GetClosestPointOnRay(p); return (f - p).Length; } public readonly __v2t__ Intersect(__ray2t__ r) { __v2t__ a = r.Origin - Origin; if (a.Abs().AllSmaller(Constant<__ftype__>.PositiveTinyValue)) return Origin; // Early exit when rays have same origin __ftype__ cross = Direction.Dot270(r.Direction); if (!Fun.IsTiny(cross)) // Rays not parallel return Origin + Direction * r.Direction.Dot90(a) / cross; else // Rays are parallel return __v2t__.NaN; } public readonly __v2t__ Intersect(__v2t__ dirVector) { if (Origin.Abs().AllSmaller(Constant<__ftype__>.PositiveTinyValue)) return Origin; // Early exit when rays have same origin __ftype__ cross = Direction.Dot270(dirVector); if (!Fun.IsTiny(cross)) // Rays not parallel return Origin + Direction * dirVector.Dot270(Origin) / cross; else // Rays are parallel return __v2t__.NaN; } /// /// Returns the angle between this and the given in radians. /// The direction vectors of the input rays have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__ AngleBetweenFast(__ray2t__ r) => Direction.AngleBetweenFast(r.Direction); /// /// Returns the angle between this and the given in radians using a numerically stable algorithm. /// The direction vectors of the input rays have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__ AngleBetween(__ray2t__ r) => Direction.AngleBetween(r.Direction); /// /// Returns the signed angle between this and the given in radians. /// The direction vectors of the input rays have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__ AngleBetweenSigned(__ray2t__ r) => Direction.AngleBetweenSigned(r.Direction); /// /// Returns a signed value where left is negative and right positive. /// The magnitude is equal to the __ftype__ size of the triangle the ray + direction and p. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__ GetPointSide(__v2t__ p) => Direction.Dot90(p - Origin); #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__ray2t__ a, __ray2t__ b) => (a.Origin == b.Origin) && (a.Direction == b.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__ray2t__ a, __ray2t__ b) => !((a.Origin == b.Origin) && (a.Direction == b.Direction)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int LexicalCompare(__ray2t__ other) { var cmp = Origin.LexicalCompare(other.Origin); if (cmp != 0) return cmp; return Direction.LexicalCompare(other.Direction); } #endregion #region Overrides /// /// Calculates Hash-code of the given ray. /// /// Hash-code. [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Origin, Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__ray2t__ other) => Origin.Equals(other.Origin) && Direction.Equals(other.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is __ray2t__ o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Origin, Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ray2t__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __ray2t__(__v2t__.Parse(x[0]), __v2t__.Parse(x[1])); } #endregion #region __iboundingbox__ public readonly __box2t__ BoundingBox2__tc__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => __box2t__.FromPoints(Origin, Direction + Origin); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __ray2t__ a, __ray2t__ b, __ftype__ tolerance) => ApproximateEquals(a.Origin, b.Origin, tolerance) && ApproximateEquals(a.Direction, b.Direction, tolerance); /// /// Returns whether the given are equal within /// Constant<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __ray2t__ a, __ray2t__ b) => ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } #endregion #region __fastray2t__ /// /// A fast ray contains a ray and a number of precomputed flags and /// fields for fast intersection computation with bounding boxes and /// other axis-aligned sturctures such as kd-Trees. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public readonly partial struct Fast__ray2t__ { [DataMember] public readonly __ray2t__ Ray; [DataMember] public readonly DirFlags DirFlags; [DataMember] public readonly __v2t__ InvDir; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public Fast__ray2t__(__ray2t__ ray) { Ray = ray; DirFlags = ray.Direction.DirFlags(); InvDir = 1 / ray.Direction; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Fast__ray2t__(__v2t__ origin, __v2t__ direction) : this(new __ray2t__(origin, direction)) { } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Fast__ray2t__(Fast__ray2t__ o) { Ray = o.Ray; DirFlags = o.DirFlags; InvDir = o.InvDir; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Fast__ray2t__(Fast__ray2t2__ o) { Ray = (__ray2t__)o.Ray; DirFlags = o.DirFlags; InvDir = (__v2t__)o.InvDir; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Fast__ray2t__(Fast__ray2t2__ r) => new Fast__ray2t__(r); #endregion #region Ray Arithmetics public bool Intersects( __box2t__ box, ref __ftype__ tmin, ref __ftype__ tmax ) { var dirFlags = DirFlags; if ((dirFlags & DirFlags.PositiveX) != 0) { { __ftype__ t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } { __ftype__ t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeX) != 0) { { __ftype__ t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } { __ftype__ t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to X-plane { if (Ray.Origin.X < box.Min.X || Ray.Origin.X > box.Max.X) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { { __ftype__ t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } { __ftype__ t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeY) != 0) { { __ftype__ t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } { __ftype__ t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to Y-plane { if (Ray.Origin.Y < box.Min.Y || Ray.Origin.Y > box.Max.Y) return false; } if (tmin > tmax) return false; return true; } /// /// This variant of the intersection method returns the affected /// planes of the box if the box was hit. /// public bool Intersects( __box2t__ box, ref __ftype__ tmin, ref __ftype__ tmax, out Box.Flags tminFlags, out Box.Flags tmaxFlags ) { var dirFlags = DirFlags; tminFlags = Box.Flags.None; tmaxFlags = Box.Flags.None; if ((dirFlags & DirFlags.PositiveX) != 0) { { __ftype__ t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxX; } } { __ftype__ t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinX; } } } else if ((dirFlags & DirFlags.NegativeX) != 0) { { __ftype__ t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinX; } } { __ftype__ t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxX; } } } else // ray parallel to X-plane { if (Ray.Origin.X < box.Min.X || Ray.Origin.X > box.Max.X) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { { __ftype__ t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxY; } } { __ftype__ t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinY; } } } else if ((dirFlags & DirFlags.NegativeY) != 0) { { __ftype__ t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinY; } } { __ftype__ t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxY; } } } else // ray parallel to Y-plane { if (Ray.Origin.Y < box.Min.Y || Ray.Origin.Y > box.Max.Y) return false; } if (tmin > tmax) return false; return true; } #endregion } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Ray/Ray3_auto.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Ray3f /// /// A three-dimensional ray with an origin and a direction. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Ray3f : IEquatable, IValidity, IBoundingBox3f { [DataMember] public V3f Origin; [DataMember] public V3f Direction; #region Constructors /// /// Creates Ray from origin point and directional vector /// public Ray3f(V3f origin, V3f direction) { Origin = origin; Direction = direction; } public static Ray3f FromEndPoints(V3f origin, V3f target) => new Ray3f(origin, target - origin); #endregion #region Constants /// /// An invalid ray has a zero direction. /// public static readonly Ray3f Invalid = new Ray3f(V3f.NaN, V3f.Zero); #endregion #region Properties /// /// A ray is valid if its direction is non-zero. /// public readonly bool IsValid { get { return Direction != V3f.Zero; } } /// /// A ray is invalid if its direction is zero. /// public readonly bool IsInvalid { get { return Direction == V3f.Zero; } } /// /// Returns true if either the origin or the direction contains any NaN value. /// public readonly bool AnyNaN { get { return Origin.AnyNaN || Direction.AnyNaN; } } /// /// Line segment from origin to origin + direction. /// public readonly Line3f Line3f => new Line3f(Origin, Origin + Direction); /// /// Returns new ray with flipped direction. /// public readonly Ray3f Reversed => new Ray3f(Origin, -Direction); /// /// Returns the ray with its directional normalized. /// public readonly Ray3f Normalized => new(Origin, Direction.Normalized); #endregion #region Ray Arithmetics /// /// Gets the point on the ray that is t * Direction from Origin. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f GetPointOnRay(float t) => Origin + Direction * t; /// /// Gets the t for a point p on this ray. /// public readonly float GetT(V3f p) { var v = p - Origin; var d = Direction.Abs(); if (d.X > d.Y) return (d.X > d.Z) ? (v.X / Direction.X) : (v.Z / Direction.Z); else return (d.Y > d.Z) ? (v.Y / Direction.Y) : (v.Z / Direction.Z); } /// /// Gets the t of the closest point on the ray for any point p. /// public readonly float GetTOfProjectedPoint(V3f p) { var v = p - Origin; return v.Dot(Direction) / Direction.LengthSquared; } /// /// Returns the ray transformed with the given matrix. /// This method is only valid for similarity transformations (uniform scale). /// public readonly Ray3f Transformed(M44f mat) => new(mat.TransformPos(Origin), mat.TransformDir(Direction)); /// /// Returns the ray transformed with the given transformation. /// public readonly Ray3f Transformed(Rot3f transform) => new(transform.Transform(Origin), transform.Transform(Direction)); /// /// Returns the ray transformed with the given transformation. /// public readonly Ray3f Transformed(Scale3f transform) => new(transform.Transform(Origin), transform.Transform(Direction)); /// /// Returns the ray transformed with the given transformation. /// public readonly Ray3f Transformed(Shift3f transform) => new(transform.Transform(Origin), Direction); /// /// Returns the ray transformed with the given transformation. /// public readonly Ray3f Transformed(Euclidean3f transform) => new(transform.TransformPos(Origin), transform.TransformDir(Direction)); /// /// Returns the ray transformed with the given transformation. /// public readonly Ray3f Transformed(Similarity3f transform) => new(transform.TransformPos(Origin), transform.TransformDir(Direction)); /// /// Returns the ray transformed with the given transformation. /// public readonly Ray3f Transformed(Affine3f transform) => new(transform.TransformPos(Origin), transform.TransformDir(Direction)); /// /// Returns the angle between this and the given in radians. /// The direction vectors of the input rays have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float AngleBetweenFast(Ray3f r) => Direction.AngleBetweenFast(r.Direction); /// /// Returns the angle between this and the given in radians using a numerically stable algorithm. /// The direction vectors of the input rays have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float AngleBetween(Ray3f r) => Direction.AngleBetween(r.Direction); #endregion #region Ray hit intersections #region Private functions private readonly bool ComputeHit( float t, float tmin, float tmax, ref RayHit3f hit) { if (t >= tmin) { if (t < tmax && t < hit.T) { hit.T = t; hit.Point = GetPointOnRay(t); hit.Coord = V2d.NaN; hit.BackSide = false; return true; } return false; } return false; } private readonly bool GetClosestHit( float t1, float t2, float tmin, float tmax, ref RayHit3f hit) { return t1 < t2 ? ProcessHits(t1, t2, tmin, tmax, ref hit) : ProcessHits(t2, t1, tmin, tmax, ref hit); } private readonly bool ProcessHits( float t1, float t2, float tmin, float tmax, ref RayHit3f hit) { if (t1 >= tmin) { if (t1 < tmax && t1 < hit.T) { hit.T = t1; hit.Point = GetPointOnRay(t1); hit.Coord = V2d.NaN; hit.BackSide = false; return true; } return false; } if (t2 >= tmin) { if (t2 < tmax && t2 < hit.T) { hit.T = t2; hit.Point = GetPointOnRay(t2); hit.Coord = V2d.NaN; hit.BackSide = true; return true; } } return false; } #endregion #region Ray-Ray hit intersection /// /// Returns true if the ray hits the other ray before the parameter /// value contained in the supplied hit. Detailed information about /// the hit is returned in the supplied hit. A hit with this /// overload is considered for t in [0, float.MaxValue]. /// public readonly bool Hits(Ray3f ray, ref RayHit3f hit) => HitsRay(ray, 0, float.MaxValue, ref hit); /// /// Returns true if the ray hits the other ray before the parameter /// value contained in the supplied hit. Detailed information about /// the hit is returned in the supplied hit. /// public readonly bool Hits(Ray3f ray, float tmin, float tmax, ref RayHit3f hit) => HitsRay(ray, tmin, tmax, ref hit); /// /// Returns true if the ray hits the other ray before the parameter /// value contained in the supplied hit. Detailed information about /// the hit is returned in the supplied hit. /// public readonly bool HitsRay(Ray3f ray, float tmin, float tmax, ref RayHit3f hit) { V3f d = Origin - ray.Origin; V3f u = Direction; V3f v = ray.Direction; V3f n = u.Cross(v); if (Fun.IsTiny(d.Length)) return true; else if (Fun.IsTiny(u.Cross(v).Length)) return false; else { //-t0*u + t1*v + t2*n == d //M = {-u,v,n} //M*{t0,t1,t2}T == d //{t0,t1,t2}T == M^-1 * d M33f M = new M33f { C0 = -u, C1 = v, C2 = n }; if (M.Invertible) { V3f t = M.Inverse * d; if (Fun.IsTiny(t.Z)) { ProcessHits(t.X, float.MaxValue, tmin, tmax, ref hit); return true; } else return false; } else return false; } } #endregion #region Ray-Triangle hit intersection /// /// Returns true if the ray hits the triangle before the parameter /// value contained in the supplied hit. Detailed information about /// the hit is returned in the supplied hit. A hit with this /// overload is considered for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Triangle3f triangle, ref RayHit3f hit) => HitsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, 0, float.MaxValue, ref hit); /// /// Returns true if the ray hits the triangle. A hit with this /// overload is considered for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Triangle3f triangle, out float t) => HitsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, 0, float.MaxValue, out t); /// /// Returns true if the ray hits the triangle within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. Detailed information about the hit is /// returned in the supplied hit. In order to obtain all potential /// hits, the supplied hit can be initialized with RayHit3f.MaxRange. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Triangle3f triangle, float tmin, float tmax, ref RayHit3f hit) => HitsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, tmin, tmax, ref hit); /// /// Returns true if the ray hits the triangle within [0, float.MaxValue] /// and before the parameter value contained in the supplied hit. Detailed /// information about the hit is returned in the supplied hit. In order to /// obtain all potential hits, the supplied hit can be initialized with /// RayHit3f.MaxRange. Degenerated triangles will not result in an intersection /// even if any edge is hit exactly. /// public readonly bool HitsTriangle(V3f p0, V3f p1, V3f p2, ref RayHit3f hit) => HitsTriangle(p0, p1, p2, 0, float.MaxValue, ref hit); /// /// Returns true if the ray hits the triangle within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. Detailed information about the hit is /// returned in the supplied hit. In order to obtain all potential /// hits, the supplied hit can be initialized with RayHit3f.MaxRange. /// Degenerated triangles will not result in an intersection even if /// any edge is hit exactly. /// public readonly bool HitsTriangle( V3f p0, V3f p1, V3f p2, float tmin, float tmax, ref RayHit3f hit ) { V3f edge01 = p1 - p0; V3f edge02 = p2 - p0; V3f plane = Vec.Cross(Direction, edge02); float det = Vec.Dot(edge01, plane); if (det > -1e-4f && det < 1e-4f) return false; // ray ~= paralell / Triangle V3f tv = Origin - p0; det = 1 / det; // det is now inverse det float u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) return false; plane = Vec.Cross(tv, edge01); // plane is now qv float v = Vec.Dot(Direction, plane) * det; if (v < 0 || u + v > 1) return false; float t = Vec.Dot(edge02, plane) * det; if (t < tmin || t >= tmax || t >= hit.T) return false; hit.T = t; hit.Point = Origin + t * Direction; hit.Coord.X = u; hit.Coord.Y = v; hit.BackSide = (det < 0); return true; } /// /// Returns true if the ray hits the triangle. Degenerated triangles /// will not result in an intersection even if any edge is hit exactly. /// A hit with this overload is considered for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsTriangle(V3f p0, V3f p1, V3f p2, out float t) => HitsTriangle(p0, p1, p2, 0, float.MaxValue, out t); /// /// Returns true if the ray hits the triangle within the supplied /// parameter interval. Degenerated triangles will not result in an /// intersection even if any edge is hit exactly. /// public readonly bool HitsTriangle( V3f p0, V3f p1, V3f p2, float tmin, float tmax, out float t ) { V3f edge01 = p1 - p0; V3f edge02 = p2 - p0; V3f plane = Vec.Cross(Direction, edge02); float det = Vec.Dot(edge01, plane); t = float.NaN; if (det > -1e-4f && det < 1e-4f) return false; // ray ~= paralell / Triangle V3f tv = Origin - p0; det = 1 / det; // det is now inverse det float u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) return false; plane = Vec.Cross(tv, edge01); // plane is now qv float v = Vec.Dot(Direction, plane) * det; if (v < 0 || u + v > 1) return false; t = Vec.Dot(edge02, plane) * det; return t >= tmin && t <= tmax; } /// /// Returns true if the ray hits the triangle within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. Detailed information about the hit is /// returned in the supplied hit. In order to obtain all potential /// hits, the supplied hit can be initialized with RayHit3f.MaxRange. /// public readonly bool HitsTrianglePointAndEdges( V3f p0, V3f edge01, V3f edge02, float tmin, float tmax, ref RayHit3f hit ) { V3f plane = Vec.Cross(Direction, edge02); float det = Vec.Dot(edge01, plane); if (det > -1e-4f && det < 1e-4f) return false; // ray ~= paralell / Triangle V3f tv = Origin - p0; det = 1 / det; // det is now inverse det float u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) return false; plane = Vec.Cross(tv, edge01); // plane is now qv float v = Vec.Dot(Direction, plane) * det; if (v < 0 || u + v > 1) return false; float t = Vec.Dot(edge02, plane) * det; if (t < tmin || t >= tmax || t >= hit.T) return false; hit.T = t; hit.Point = Origin + t * Direction; hit.Coord.X = u; hit.Coord.Y = v; hit.BackSide = (det < 0); return true; } /// /// Returns true if the ray hits the triangle within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. Detailed information about the hit is /// returned in the supplied hit. In order to obtain all potential /// hits, the supplied hit can be initialized with RayHit3f.MaxRange. /// public readonly bool HitsTrianglePointAndEdges( V3f p0, V3f edge01, V3f edge02, float tmin, float tmax, out float t ) { V3f plane = Vec.Cross(Direction, edge02); float det = Vec.Dot(edge01, plane); t = float.NaN; if (det > -1e-4f && det < 1e-4f) return false; // ray ~= paralell / Triangle V3f tv = Origin - p0; det = 1 / det; // det is now inverse det float u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) return false; plane = Vec.Cross(tv, edge01); // plane is now qv float v = Vec.Dot(Direction, plane) * det; if (v < 0 || u + v > 1) return false; t = Vec.Dot(edge02, plane) * det; return t >= tmin && t <= tmax; } #endregion #region Ray-Quad hit intersection /// /// Returns true if the ray hits the quad before the parameter /// value contained in the supplied hit. Detailed information about /// the hit is returned in the supplied hit. In order to obtain all /// potential hits, the supplied hit can be initialized with /// RayHit3f.MaxRange. A hit with this overload is considered /// for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Quad3f quad, ref RayHit3f hit) => HitsQuad( quad.P0, quad.P1, quad.P2, quad.P3, 0, float.MaxValue, ref hit); /// /// Returns true if the ray hits the quad within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. Detailed information about the hit is /// returned in the supplied hit. In order to obtain all potential /// hits, the supplied hit can be initialized with RayHit3f.MaxRange. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Quad3f quad, float tmin, float tmax, ref RayHit3f hit) => HitsQuad( quad.P0, quad.P1, quad.P2, quad.P3, tmin, tmax, ref hit); /// /// Returns true if the ray hits the quad within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. The quad is considered to consist of the /// two triangles [p0,p1,p2] and [p0,p2,p3]. Detailed information /// about the hit is returned in the supplied hit. In order to obtain /// all potential hits, the supplied hit can be initialized with /// RayHit3f.MaxRange. /// public readonly bool HitsQuad( V3f p0, V3f p1, V3f p2, V3f p3, float tmin, float tmax, ref RayHit3f hit ) { V3f e02 = p2 - p0; bool result = false; if (HitsTrianglePointAndEdges(p0, p1 - p0, e02, tmin, tmax, ref hit)) { hit.Coord.X += hit.Coord.Y; result = true; } if (HitsTrianglePointAndEdges(p0, e02, p3 - p0, tmin, tmax, ref hit)) { hit.Coord.Y += hit.Coord.X; result = true; } return result; } /// /// Returns true if the ray hits the quad within the supplied parameter interval. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Quad3f quad, float tmin, float tmax, out float t) => HitsQuad(quad.P0, quad.P1, quad.P2, quad.P3, tmin, tmax, out t); /// /// Returns true if the ray hits the quad within the supplied parameter interval. /// A hit with this overload is considered for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Quad3f quad, out float t) => HitsQuad(quad.P0, quad.P1, quad.P2, quad.P3, 0, float.MaxValue, out t); /// /// Returns true if the ray hits the quad within the supplied parameter interval. /// A hit with this overload is considered for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsQuad(V3f p0, V3f p1, V3f p2, V3f p3, out float t) => HitsQuad(p0, p1, p2, p3, 0, float.MaxValue, out t); /// /// Returns true if the ray hits the quad within the supplied parameter interval. /// public readonly bool HitsQuad(V3f p0, V3f p1, V3f p2, V3f p3, float tmin, float tmax, out float t) { V3f e02 = p2 - p0; return HitsTrianglePointAndEdges(p0, p1 - p0, e02, tmin, tmax, out t) || HitsTrianglePointAndEdges(p0, e02, p3 - p0, tmin, tmax, out t); } #endregion #region Ray-Sphere hit intersection /// /// Returns true if the ray hits the sphere given by center and /// radius within the supplied parameter interval and before the /// parameter value contained in the supplied hit. Note that a /// hit is only registered if the front or the backsurface is /// encountered within the interval. If there are two valid solutions, the /// closest will be returned. /// public readonly bool HitsSphere( V3f center, float radius, float tmin, float tmax, ref RayHit3f hit) { V3f originSubCenter = Origin - center; float a = Direction.LengthSquared; float b = Direction.Dot(originSubCenter); float c = originSubCenter.LengthSquared - radius * radius; // --------------------- quadric equation : a t^2 + 2b t + c = 0 float d = b * b - a * c; // factor 2 was eliminated if (d < float.Epsilon) // no root ? return false; // then exit if (b > 0) // stable way to calculate d = -Fun.Sqrt(d) - b; // the roots of a quadratic else // equation d = Fun.Sqrt(d) - b; float t1 = d / a; float t2 = c / d; // Vieta : t1 * t2 == c/a // typically two solutions, either both positive, both negative or mixed // -> take closest (if valid) first return t1.Abs() < t2.Abs() ? ProcessHits(t1, t2, tmin, tmax, ref hit) : ProcessHits(t2, t1, tmin, tmax, ref hit); } /// /// Returns true if the ray hits the supplied sphere within the /// supplied parameter interval and before the parameter value /// contained in the supplied hit. Note that a hit is only /// registered if the front or the backsurface is encountered /// within the interval. If there are two valid solutions, the /// closest will be returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Sphere3f sphere, float tmin, float tmax, ref RayHit3f hit) => HitsSphere(sphere.Center, sphere.Radius, tmin, tmax, ref hit); /// /// Returns true if the ray hits the supplied sphere within the /// supplied parameter interval and before the parameter value /// contained in the supplied hit. Note that a hit is only /// registered if the front or the backsurface is encountered /// within the interval. If there are two valid solutions, the /// closest will be returned. A hit with this overload is /// considered for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Sphere3f sphere, ref RayHit3f hit) => HitsSphere(sphere.Center, sphere.Radius, 0, float.MaxValue, ref hit); /// /// Returns true if the ray hits the supplied sphere within the /// supplied parameter interval. Note that a hit is only /// registered if the front or the backsurface is encountered /// within the interval. If there are two valid solutions, the /// closest will be returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Sphere3f sphere, float tmin, float tmax, out float t) => HitsSphere(sphere.Center, sphere.Radius, tmin, tmax, out t); /// /// Returns true if the ray hits the supplied sphere. Note that a hit is /// registered if the front or the backsurface is encountered. If there /// are two valid solutions, the closest will be returned. A hit with this /// overload is considered for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Sphere3f sphere, out float t) => HitsSphere(sphere.Center, sphere.Radius, 0, float.MaxValue, out t); /// /// Returns true if the ray hits the supplied sphere within the supplied parameter interval. /// Note that a hit is registered if the front or the backsurface is encountered within the /// interval. If there are two valid solutions, the closest will be returned. A hit with this /// overload is considered for t in [0, float.MaxValue]. /// public readonly bool HitsSphere(V3f center, float radius, out float t) => HitsSphere(center, radius, 0, float.MaxValue, out t); /// /// Returns true if the ray hits the supplied sphere within the supplied parameter interval. /// Note that a hit is registered if the front or the backsurface is encountered within the /// interval. If there are two valid solutions, the closest will be returned. /// public readonly bool HitsSphere(V3f center, float radius, float tmin, float tmax, out float t) { var originSubCenter = Origin - center; var a = Direction.LengthSquared; var b = Direction.Dot(originSubCenter); var c = originSubCenter.LengthSquared - radius * radius; // --------------------- quadric equation : a t^2 + 2b t + c = 0 var d = b * b - a * c; // factor 2 was eliminated if (d >= float.Epsilon) // no root ? -> exit { if (b > 0) // stable way to calculate d = -Fun.Sqrt(d) - b; // the roots of a quadratic else // equation d = Fun.Sqrt(d) - b; var t1 = d / a; var t2 = c / d; // Vieta : t1 * t2 == c/a // typically two solutions, either both positive, both negative or mixed // -> take closest (if valid) first if (t2.Abs() < t1.Abs()) Fun.Swap(ref t1, ref t2); if (t1 >= tmin) { if (t1 < tmax) { t = t1; return true; } // return false } else if (t2 >= tmin) { if (t2 < tmax) { t = t2; return true; } // return false } } t = float.NaN; return false; } #endregion #region Ray-Plane hit intersection /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsPlane(Plane3f plane, ref RayHit3f hit) => HitsPlane(plane, 0, float.MaxValue, ref hit); public readonly bool HitsPlane(Plane3f plane, float tmin, float tmax, ref RayHit3f hit) { var dc = plane.Normal.Dot(Direction); // If parallel to plane if (dc == 0) return false; var dw = plane.Distance - plane.Normal.Dot(Origin); var t = dw / dc; return ComputeHit(t, tmin, tmax, ref hit); } /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsPlane(Plane3f plane, out float t) => HitsPlane(plane, 0, float.MaxValue, out t); public readonly bool HitsPlane(Plane3f plane, float tmin, float tmax, out float t) { var dc = plane.Normal.Dot(Direction); // If parallel to plane if (dc == 0) { t = float.NaN; return false; } var dw = plane.Distance - plane.Normal.Dot(Origin); t = dw / dc; return t >= tmin && t <= tmax; } #endregion #region Ray-Circle hit intersection /// /// Returns true if the ray intersects with the primitive. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Circle3f circle, float tmin, float tmax, ref RayHit3f hit) => HitsCircle(circle.Center, circle.Normal, circle.Radius, tmin, tmax, ref hit); /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Circle3f circle, ref RayHit3f hit) => HitsCircle(circle.Center, circle.Normal, circle.Radius, 0, float.MaxValue, ref hit); /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsCircle(V3f center, V3f normal, float radius, ref RayHit3f hit) => HitsCircle(center, normal, radius, 0, float.MaxValue, ref hit); /// /// Returns true if the ray intersects with the primitive. /// public readonly bool HitsCircle(V3f center, V3f normal, float radius, float tmin, float tmax, ref RayHit3f hit) { var dc = normal.Dot(Direction); var dw = normal.Dot(center - Origin); // If parallel to plane if (dc == 0) return false; var t = dw / dc; if (!ComputeHit(t, tmin, tmax, ref hit)) return false; if (Vec.DistanceSquared(hit.Point, center) > radius * radius) { hit.Point = V3f.NaN; hit.T = tmax; return false; } return true; } /// /// Returns true if the ray intersects with the primitive. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Circle3f circle, float tmin, float tmax, out float t) => HitsCircle(circle.Center, circle.Normal, circle.Radius, tmin, tmax, out t); /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Circle3f circle, out float t) => HitsCircle(circle.Center, circle.Normal, circle.Radius, 0, float.MaxValue, out t); /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsCircle(V3f center, V3f normal, float radius, out float t) => HitsCircle(center, normal, radius, 0, float.MaxValue, out t); /// /// Returns true if the ray intersects with the primitive. /// public readonly bool HitsCircle(V3f center, V3f normal, float radius, float tmin, float tmax, out float t) { var dc = normal.Dot(Direction); var dw = normal.Dot(center - Origin); // If parallel to plane if (dc == 0) { t = float.NaN; return false; } t = dw / dc; if (t < tmin || t > tmax) return false; var point = GetPointOnRay(t); // add point as out parameter? return Vec.DistanceSquared(point, center) <= radius * radius; } #endregion #region Ray-Cylinder hit intersection /// /// Returns true if the ray intersects with the primitive. /// public readonly bool HitsCylinder(V3f p0, V3f p1, float radius, float tmin, float tmax, ref RayHit3f hit) { var axis = new Line3f(p0, p1); var axisDir = axis.Direction.Normalized; // Vector Cyl.P0 -> Ray.Origin var op = Origin - p0; // normal RayDirection - CylinderAxis var normal = Direction.Cross(axisDir); var unitNormal = normal.Normalized; // normal (Vec Cyl.P0 -> Ray.Origin) - CylinderAxis var normal2 = op.Cross(axisDir); var t = -normal2.Dot(unitNormal) / normal.Length; // between enitre rays (caps are ignored) var shortestDistance = Fun.Abs(op.Dot(unitNormal)); if (shortestDistance <= radius) { var s = Fun.Abs(Fun.Sqrt(radius.Square() - shortestDistance.Square()) / Direction.Length); var t1 = t - s; // first hit of Cylinder shell var t2 = t + s; // second hit of Cylinder shell if (t1 > tmin && t1 < tmax) tmin = t1; if (t2 < tmax && t2 > tmin) tmax = t2; hit.T = t1; hit.Point = GetPointOnRay(t1); // check if found point is outside of Cylinder Caps var bottomPlane = new Plane3f(-axisDir, p0); var topPlane = new Plane3f(axisDir, p1); var heightBottom = bottomPlane.Height(hit.Point); var heightTop = topPlane.Height(hit.Point); // t1 lies outside of caps => find closest cap hit if (heightBottom > 0 || heightTop > 0) { hit.T = tmax; // intersect with bottom Cylinder Cap var bottomHit = HitsPlane(bottomPlane, tmin, tmax, ref hit); // intersect with top Cylinder Cap var topHit = HitsPlane(topPlane, tmin, tmax, ref hit); // hit still close enough to cylinder axis? var distance = axis.Ray3f.GetMinimalDistanceTo(hit.Point); if (distance <= radius && (bottomHit || topHit)) return true; } else return true; } hit.T = tmax; hit.Point = V3f.NaN; return false; } /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsCylinder(V3f p0, V3f p1, float radius, ref RayHit3f hit) => HitsCylinder(p0, p1, radius, 0, float.MaxValue, ref hit); public readonly bool HitsCylinder(V3f p0, V3f p1, float radius, float tmin, float tmax, out float t) { var axis = new Line3f(p0, p1); var axisDir = axis.Direction.Normalized; // Vector Cyl.P0 -> Ray.Origin var op = Origin - p0; // normal RayDirection - CylinderAxis var normal = Direction.Cross(axisDir); var unitNormal = normal.Normalized; // normal (Vec Cyl.P0 -> Ray.Origin) - CylinderAxis var normal2 = op.Cross(axisDir); t = -normal2.Dot(unitNormal) / normal.Length; // between entire rays (caps are ignored) var shortestDistance = Fun.Abs(op.Dot(unitNormal)); if (shortestDistance <= radius) { var s = Fun.Abs(Fun.Sqrt(radius.Square() - shortestDistance.Square()) / Direction.Length); var t1 = t - s; // first hit of Cylinder shell var t2 = t + s; // second hit of Cylinder shell if (t1 > tmin && t1 < tmax) tmin = t1; if (t2 < tmax && t2 > tmin) tmax = t2; t = t1; var point = GetPointOnRay(t1); // check if found point is outside of Cylinder Caps var bottomPlane = new Plane3f(-axisDir, p0); var topPlane = new Plane3f(axisDir, p1); var heightBottom = bottomPlane.Height(point); var heightTop = topPlane.Height(point); // t1 lies outside of caps => find closest cap hit if (heightBottom > 0 || heightTop > 0) { // intersect with bottom Cylinder Cap var bottomHit = HitsCircle(p0, -axisDir, radius, tmin, tmax, out t); // intersect with top Cylinder Cap var topHit = HitsCircle(p1, axisDir, radius, tmin, tmax, out float ttop); if (topHit) { if (bottomHit) { if (ttop.Abs() < t) t = ttop; } else t = ttop; } return topHit || bottomHit; } else return true; } t = float.NaN; return false; } /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsCylinder(V3f p0, V3f p1, float radius, out float t) => HitsCylinder(p0, p1, radius, 0, float.MaxValue, out t); /// /// Returns true if the ray intersects with the primitive. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Cylinder3f cylinder, float tmin, float tmax, ref RayHit3f hit) => Hits(cylinder, tmin, tmax, 0, ref hit); /// /// Returns true if the ray intersects with the primitive. /// public readonly bool Hits(Cylinder3f cylinder, float tmin, float tmax, float distanceScale, ref RayHit3f hit) { var axisDir = cylinder.Axis.Direction.Normalized; // Vector Cyl.P0 -> Ray.Origin var op = Origin - cylinder.P0; // normal RayDirection - CylinderAxis var normal = Direction.Cross(axisDir); var unitNormal = normal.Normalized; // normal (Vec Cyl.P0 -> Ray.Origin) - CylinderAxis var normal2 = op.Cross(axisDir); var t = -normal2.Dot(unitNormal) / normal.Length; var radius = cylinder.Radius; if (distanceScale != 0) { // cylinder gets bigger, the further away it is var pnt = GetPointOnRay(t); var dis = Vec.Distance(pnt, this.Origin); radius = ((cylinder.Radius / distanceScale) * dis) * 2; } // between enitre rays (caps are ignored) var shortestDistance = Fun.Abs(op.Dot(unitNormal)); if (shortestDistance <= radius) { var s = Fun.Abs(Fun.Sqrt(radius.Square() - shortestDistance.Square()) / Direction.Length); var t1 = t - s; // first hit of Cylinder shell var t2 = t + s; // second hit of Cylinder shell if (t1 > tmin && t1 < tmax) tmin = t1; if (t2 < tmax && t2 > tmin) tmax = t2; hit.T = t1; hit.Point = GetPointOnRay(t1); // check if found point is outside of Cylinder Caps var bottomPlane = new Plane3f(cylinder.Circle0.Normal, cylinder.Circle0.Center); var topPlane = new Plane3f(cylinder.Circle1.Normal, cylinder.Circle1.Center); var heightBottom = bottomPlane.Height(hit.Point); var heightTop = topPlane.Height(hit.Point); // t1 lies outside of caps => find closest cap hit if (heightBottom > 0 || heightTop > 0) { hit.T = tmax; // intersect with bottom Cylinder Cap var bottomHit = HitsPlane(bottomPlane, tmin, tmax, ref hit); // intersect with top Cylinder Cap var topHit = HitsPlane(topPlane, tmin, tmax, ref hit); // hit still close enough to cylinder axis? var distance = cylinder.Axis.Ray3f.GetMinimalDistanceTo(hit.Point); if (distance <= radius && (bottomHit || topHit)) return true; } else return true; } hit.T = tmax; hit.Point = V3f.NaN; return false; } /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, float.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Cylinder3f cylinder, ref RayHit3f hit) => Hits(cylinder, 0, float.MaxValue, ref hit); #endregion #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Ray3f a, Ray3f b) => (a.Origin == b.Origin) && (a.Direction == b.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Ray3f a, Ray3f b) => !((a.Origin == b.Origin) && (a.Direction == b.Direction)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int LexicalCompare(Ray3f other) { var cmp = Origin.LexicalCompare(other.Origin); if (cmp != 0) return cmp; return Direction.LexicalCompare(other.Direction); } #endregion #region Overrides /// /// Calculates Hash-code of the given ray. /// /// Hash-code. public override readonly int GetHashCode() => HashCode.GetCombined(Origin, Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Ray3f other) => Origin.Equals(other.Origin) && Direction.Equals(other.Direction); public override readonly bool Equals(object other) => (other is Ray3f o) ? Equals(o) : false; public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Origin, Direction); public static Ray3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Ray3f(V3f.Parse(x[0]), V3f.Parse(x[1])); } #endregion #region IBoundingBox3f public readonly Box3f BoundingBox3f => Box3f.FromPoints(Origin, Direction + Origin); #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Ray3f a, Ray3f b, float tolerance) => ApproximateEquals(a.Origin, b.Origin, tolerance) && ApproximateEquals(a.Direction, b.Direction, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Ray3f a, Ray3f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region RayHit3f /// /// A ray hit represents the hit of a ray on a primitive object such as /// a triangle. It stores the ray parameter of the hit, the hit point, /// the hit point's coordinates, and a flag indicating if the backside /// of the primitive was hit. Optionally the part field can be used to /// store which part of a multi-part object was hit. If no multi-part /// objects are used, this field remains 0. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public struct RayHit3f { [DataMember] public float T; [DataMember] public V3f Point; [DataMember] public V2d Coord; [DataMember] public bool BackSide; [DataMember] public int Part; #region Constructor public RayHit3f(float tMax) { T = tMax; Point = V3f.NaN; Coord = V2d.NaN; BackSide = false; Part = 0; } #endregion #region Constants public static readonly RayHit3f MaxRange = new RayHit3f(float.MaxValue); #endregion } #endregion #region FastRay3f /// /// A fast ray contains a ray and a number of precomputed flags and /// fields for fast intersection computation with bounding boxes and /// other axis-aligned sturctures such as kd-Trees. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public readonly struct FastRay3f { [DataMember] public readonly Ray3f Ray; [DataMember] public readonly DirFlags DirFlags; [DataMember] public readonly V3f InvDir; #region Constructors public FastRay3f(Ray3f ray) { Ray = ray; DirFlags = ray.Direction.DirFlags(); InvDir = 1 / ray.Direction; } public FastRay3f(V3f origin, V3f direction) : this(new Ray3f(origin, direction)) { } #endregion #region Ray Arithmetics public readonly bool Intersects( Box3f box, ref float tmin, ref float tmax ) { var dirFlags = DirFlags; if ((dirFlags & DirFlags.PositiveX) != 0) { { float t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } { float t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeX) != 0) { { float t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } { float t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to X-plane { if (Ray.Origin.X < box.Min.X || Ray.Origin.X > box.Max.X) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { { float t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } { float t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeY) != 0) { { float t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } { float t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to Y-plane { if (Ray.Origin.Y < box.Min.Y || Ray.Origin.Y > box.Max.Y) return false; } if ((dirFlags & DirFlags.PositiveZ) != 0) { { float t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) tmax = t; } { float t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeZ) != 0) { { float t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) tmax = t; } { float t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to Z-plane { if (Ray.Origin.Z < box.Min.Z || Ray.Origin.Z > box.Max.Z) return false; } if (tmin > tmax) return false; return true; } /// /// This variant of the intersection method only tests with the /// faces of the box indicated by the supplied boxFlags. /// public readonly bool Intersects( Box3f box, Box.Flags boxFlags, ref float tmin, ref float tmax ) { var dirFlags = DirFlags; if ((dirFlags & DirFlags.PositiveX) != 0) { if ((boxFlags & Box.Flags.MaxX) != 0) { float t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MinX) != 0) { float t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeX) != 0) { if ((boxFlags & Box.Flags.MinX) != 0) { float t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MaxX) != 0) { float t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to X-plane { if ((boxFlags & Box.Flags.MinX) != 0 && (Ray.Origin.X < box.Min.X) || (boxFlags & Box.Flags.MaxX) != 0 && (Ray.Origin.X > box.Max.X)) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { if ((boxFlags & Box.Flags.MaxY) != 0) { float t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MinY) != 0) { float t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeY) != 0) { if ((boxFlags & Box.Flags.MinY) != 0) { float t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MaxY) != 0) { float t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to Y-plane { if ((boxFlags & Box.Flags.MinY) != 0 && (Ray.Origin.Y < box.Min.Y) || (boxFlags & Box.Flags.MaxY) != 0 && (Ray.Origin.Y > box.Max.Y)) return false; } if ((dirFlags & DirFlags.PositiveZ) != 0) { if ((boxFlags & Box.Flags.MaxZ) != 0) { float t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MinZ) != 0) { float t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeZ) != 0) { if ((boxFlags & Box.Flags.MinZ) != 0) { float t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MaxZ) != 0) { float t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to Z-plane { if ((boxFlags & Box.Flags.MinZ) != 0 && (Ray.Origin.Z < box.Min.Z) || (boxFlags & Box.Flags.MaxZ) != 0 && (Ray.Origin.Z > box.Max.Z)) return false; } if (tmin > tmax) return false; return true; } /// /// This variant of the intersection method returns the affected /// planes of the box if the box was hit. /// public readonly bool Intersects( Box3f box, ref float tmin, ref float tmax, out Box.Flags tminFlags, out Box.Flags tmaxFlags ) { var dirFlags = DirFlags; tminFlags = Box.Flags.None; tmaxFlags = Box.Flags.None; if ((dirFlags & DirFlags.PositiveX) != 0) { { float t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxX; } } { float t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinX; } } } else if ((dirFlags & DirFlags.NegativeX) != 0) { { float t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinX; } } { float t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxX; } } } else // ray parallel to X-plane { if (Ray.Origin.X < box.Min.X || Ray.Origin.X > box.Max.X) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { { float t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxY; } } { float t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinY; } } } else if ((dirFlags & DirFlags.NegativeY) != 0) { { float t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinY; } } { float t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxY; } } } else // ray parallel to Y-plane { if (Ray.Origin.Y < box.Min.Y || Ray.Origin.Y > box.Max.Y) return false; } if ((dirFlags & DirFlags.PositiveZ) != 0) { { float t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxZ; } } { float t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinZ; } } } else if ((dirFlags & DirFlags.NegativeZ) != 0) { { float t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinZ; } } { float t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxZ; } } } else // ray parallel to Z-plane { if (Ray.Origin.Z < box.Min.Z || Ray.Origin.Z > box.Max.Z) return false; } if (tmin > tmax) return false; return true; } /// /// This variant of the intersection method only tests with the /// faces of the box indicated by the supplied boxFlags and /// returns the affected planes of the box if the box was hit. /// public readonly bool Intersects( Box3f box, Box.Flags boxFlags, ref float tmin, ref float tmax, out Box.Flags tminFlags, out Box.Flags tmaxFlags ) { var dirFlags = DirFlags; tminFlags = Box.Flags.None; tmaxFlags = Box.Flags.None; if ((dirFlags & DirFlags.PositiveX) != 0) { if ((boxFlags & Box.Flags.MaxX) != 0) { float t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxX; } } if ((boxFlags & Box.Flags.MinX) != 0) { float t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinX; } } } else if ((dirFlags & DirFlags.NegativeX) != 0) { if ((boxFlags & Box.Flags.MinX) != 0) { float t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinX; } } if ((boxFlags & Box.Flags.MaxX) != 0) { float t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxX; } } } else // ray parallel to X-plane { if ((boxFlags & Box.Flags.MinX) != 0 && (Ray.Origin.X < box.Min.X) || (boxFlags & Box.Flags.MaxX) != 0 && (Ray.Origin.X > box.Max.X)) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { if ((boxFlags & Box.Flags.MaxY) != 0) { float t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxY; } } if ((boxFlags & Box.Flags.MinY) != 0) { float t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinY; } } } else if ((dirFlags & DirFlags.NegativeY) != 0) { if ((boxFlags & Box.Flags.MinY) != 0) { float t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinY; } } if ((boxFlags & Box.Flags.MaxY) != 0) { float t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxY; } } } else // ray parallel to Y-plane { if ((boxFlags & Box.Flags.MinY) != 0 && (Ray.Origin.Y < box.Min.Y) || (boxFlags & Box.Flags.MaxY) != 0 && (Ray.Origin.Y > box.Max.Y)) return false; } if ((dirFlags & DirFlags.PositiveZ) != 0) { if ((boxFlags & Box.Flags.MaxZ) != 0) { float t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxZ; } } if ((boxFlags & Box.Flags.MinZ) != 0) { float t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinZ; } } } else if ((dirFlags & DirFlags.NegativeZ) != 0) { if ((boxFlags & Box.Flags.MinZ) != 0) { float t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinZ; } } if ((boxFlags & Box.Flags.MaxZ) != 0) { float t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxZ; } } } else // ray parallel to Z-plane { if ((boxFlags & Box.Flags.MinZ) != 0 && (Ray.Origin.Z < box.Min.Z) || (boxFlags & Box.Flags.MaxZ) != 0 && (Ray.Origin.Z > box.Max.Z)) return false; } if (tmin > tmax) return false; return true; } #endregion } #endregion #region Ray3d /// /// A three-dimensional ray with an origin and a direction. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Ray3d : IEquatable, IValidity, IBoundingBox3d { [DataMember] public V3d Origin; [DataMember] public V3d Direction; #region Constructors /// /// Creates Ray from origin point and directional vector /// public Ray3d(V3d origin, V3d direction) { Origin = origin; Direction = direction; } public static Ray3d FromEndPoints(V3d origin, V3d target) => new Ray3d(origin, target - origin); #endregion #region Constants /// /// An invalid ray has a zero direction. /// public static readonly Ray3d Invalid = new Ray3d(V3d.NaN, V3d.Zero); #endregion #region Properties /// /// A ray is valid if its direction is non-zero. /// public readonly bool IsValid { get { return Direction != V3d.Zero; } } /// /// A ray is invalid if its direction is zero. /// public readonly bool IsInvalid { get { return Direction == V3d.Zero; } } /// /// Returns true if either the origin or the direction contains any NaN value. /// public readonly bool AnyNaN { get { return Origin.AnyNaN || Direction.AnyNaN; } } /// /// Line segment from origin to origin + direction. /// public readonly Line3d Line3d => new Line3d(Origin, Origin + Direction); /// /// Returns new ray with flipped direction. /// public readonly Ray3d Reversed => new Ray3d(Origin, -Direction); /// /// Returns the ray with its directional normalized. /// public readonly Ray3d Normalized => new(Origin, Direction.Normalized); #endregion #region Ray Arithmetics /// /// Gets the point on the ray that is t * Direction from Origin. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d GetPointOnRay(double t) => Origin + Direction * t; /// /// Gets the t for a point p on this ray. /// public readonly double GetT(V3d p) { var v = p - Origin; var d = Direction.Abs(); if (d.X > d.Y) return (d.X > d.Z) ? (v.X / Direction.X) : (v.Z / Direction.Z); else return (d.Y > d.Z) ? (v.Y / Direction.Y) : (v.Z / Direction.Z); } /// /// Gets the t of the closest point on the ray for any point p. /// public readonly double GetTOfProjectedPoint(V3d p) { var v = p - Origin; return v.Dot(Direction) / Direction.LengthSquared; } /// /// Returns the ray transformed with the given matrix. /// This method is only valid for similarity transformations (uniform scale). /// public readonly Ray3d Transformed(M44d mat) => new(mat.TransformPos(Origin), mat.TransformDir(Direction)); /// /// Returns the ray transformed with the given transformation. /// public readonly Ray3d Transformed(Rot3d transform) => new(transform.Transform(Origin), transform.Transform(Direction)); /// /// Returns the ray transformed with the given transformation. /// public readonly Ray3d Transformed(Scale3d transform) => new(transform.Transform(Origin), transform.Transform(Direction)); /// /// Returns the ray transformed with the given transformation. /// public readonly Ray3d Transformed(Shift3d transform) => new(transform.Transform(Origin), Direction); /// /// Returns the ray transformed with the given transformation. /// public readonly Ray3d Transformed(Euclidean3d transform) => new(transform.TransformPos(Origin), transform.TransformDir(Direction)); /// /// Returns the ray transformed with the given transformation. /// public readonly Ray3d Transformed(Similarity3d transform) => new(transform.TransformPos(Origin), transform.TransformDir(Direction)); /// /// Returns the ray transformed with the given transformation. /// public readonly Ray3d Transformed(Affine3d transform) => new(transform.TransformPos(Origin), transform.TransformDir(Direction)); /// /// Returns the angle between this and the given in radians. /// The direction vectors of the input rays have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double AngleBetweenFast(Ray3d r) => Direction.AngleBetweenFast(r.Direction); /// /// Returns the angle between this and the given in radians using a numerically stable algorithm. /// The direction vectors of the input rays have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double AngleBetween(Ray3d r) => Direction.AngleBetween(r.Direction); #endregion #region Ray hit intersections #region Private functions private readonly bool ComputeHit( double t, double tmin, double tmax, ref RayHit3d hit) { if (t >= tmin) { if (t < tmax && t < hit.T) { hit.T = t; hit.Point = GetPointOnRay(t); hit.Coord = V2d.NaN; hit.BackSide = false; return true; } return false; } return false; } private readonly bool GetClosestHit( double t1, double t2, double tmin, double tmax, ref RayHit3d hit) { return t1 < t2 ? ProcessHits(t1, t2, tmin, tmax, ref hit) : ProcessHits(t2, t1, tmin, tmax, ref hit); } private readonly bool ProcessHits( double t1, double t2, double tmin, double tmax, ref RayHit3d hit) { if (t1 >= tmin) { if (t1 < tmax && t1 < hit.T) { hit.T = t1; hit.Point = GetPointOnRay(t1); hit.Coord = V2d.NaN; hit.BackSide = false; return true; } return false; } if (t2 >= tmin) { if (t2 < tmax && t2 < hit.T) { hit.T = t2; hit.Point = GetPointOnRay(t2); hit.Coord = V2d.NaN; hit.BackSide = true; return true; } } return false; } #endregion #region Ray-Ray hit intersection /// /// Returns true if the ray hits the other ray before the parameter /// value contained in the supplied hit. Detailed information about /// the hit is returned in the supplied hit. A hit with this /// overload is considered for t in [0, double.MaxValue]. /// public readonly bool Hits(Ray3d ray, ref RayHit3d hit) => HitsRay(ray, 0, double.MaxValue, ref hit); /// /// Returns true if the ray hits the other ray before the parameter /// value contained in the supplied hit. Detailed information about /// the hit is returned in the supplied hit. /// public readonly bool Hits(Ray3d ray, double tmin, double tmax, ref RayHit3d hit) => HitsRay(ray, tmin, tmax, ref hit); /// /// Returns true if the ray hits the other ray before the parameter /// value contained in the supplied hit. Detailed information about /// the hit is returned in the supplied hit. /// public readonly bool HitsRay(Ray3d ray, double tmin, double tmax, ref RayHit3d hit) { V3d d = Origin - ray.Origin; V3d u = Direction; V3d v = ray.Direction; V3d n = u.Cross(v); if (Fun.IsTiny(d.Length)) return true; else if (Fun.IsTiny(u.Cross(v).Length)) return false; else { //-t0*u + t1*v + t2*n == d //M = {-u,v,n} //M*{t0,t1,t2}T == d //{t0,t1,t2}T == M^-1 * d M33d M = new M33d { C0 = -u, C1 = v, C2 = n }; if (M.Invertible) { V3d t = M.Inverse * d; if (Fun.IsTiny(t.Z)) { ProcessHits(t.X, double.MaxValue, tmin, tmax, ref hit); return true; } else return false; } else return false; } } #endregion #region Ray-Triangle hit intersection /// /// Returns true if the ray hits the triangle before the parameter /// value contained in the supplied hit. Detailed information about /// the hit is returned in the supplied hit. A hit with this /// overload is considered for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Triangle3d triangle, ref RayHit3d hit) => HitsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, 0, double.MaxValue, ref hit); /// /// Returns true if the ray hits the triangle. A hit with this /// overload is considered for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Triangle3d triangle, out double t) => HitsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, 0, double.MaxValue, out t); /// /// Returns true if the ray hits the triangle within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. Detailed information about the hit is /// returned in the supplied hit. In order to obtain all potential /// hits, the supplied hit can be initialized with RayHit3d.MaxRange. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Triangle3d triangle, double tmin, double tmax, ref RayHit3d hit) => HitsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, tmin, tmax, ref hit); /// /// Returns true if the ray hits the triangle within [0, double.MaxValue] /// and before the parameter value contained in the supplied hit. Detailed /// information about the hit is returned in the supplied hit. In order to /// obtain all potential hits, the supplied hit can be initialized with /// RayHit3d.MaxRange. Degenerated triangles will not result in an intersection /// even if any edge is hit exactly. /// public readonly bool HitsTriangle(V3d p0, V3d p1, V3d p2, ref RayHit3d hit) => HitsTriangle(p0, p1, p2, 0, double.MaxValue, ref hit); /// /// Returns true if the ray hits the triangle within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. Detailed information about the hit is /// returned in the supplied hit. In order to obtain all potential /// hits, the supplied hit can be initialized with RayHit3d.MaxRange. /// Degenerated triangles will not result in an intersection even if /// any edge is hit exactly. /// public readonly bool HitsTriangle( V3d p0, V3d p1, V3d p2, double tmin, double tmax, ref RayHit3d hit ) { V3d edge01 = p1 - p0; V3d edge02 = p2 - p0; V3d plane = Vec.Cross(Direction, edge02); double det = Vec.Dot(edge01, plane); if (det > -1e-7 && det < 1e-7) return false; // ray ~= paralell / Triangle V3d tv = Origin - p0; det = 1 / det; // det is now inverse det double u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) return false; plane = Vec.Cross(tv, edge01); // plane is now qv double v = Vec.Dot(Direction, plane) * det; if (v < 0 || u + v > 1) return false; double t = Vec.Dot(edge02, plane) * det; if (t < tmin || t >= tmax || t >= hit.T) return false; hit.T = t; hit.Point = Origin + t * Direction; hit.Coord.X = u; hit.Coord.Y = v; hit.BackSide = (det < 0); return true; } /// /// Returns true if the ray hits the triangle. Degenerated triangles /// will not result in an intersection even if any edge is hit exactly. /// A hit with this overload is considered for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsTriangle(V3d p0, V3d p1, V3d p2, out double t) => HitsTriangle(p0, p1, p2, 0, double.MaxValue, out t); /// /// Returns true if the ray hits the triangle within the supplied /// parameter interval. Degenerated triangles will not result in an /// intersection even if any edge is hit exactly. /// public readonly bool HitsTriangle( V3d p0, V3d p1, V3d p2, double tmin, double tmax, out double t ) { V3d edge01 = p1 - p0; V3d edge02 = p2 - p0; V3d plane = Vec.Cross(Direction, edge02); double det = Vec.Dot(edge01, plane); t = double.NaN; if (det > -1e-7 && det < 1e-7) return false; // ray ~= paralell / Triangle V3d tv = Origin - p0; det = 1 / det; // det is now inverse det double u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) return false; plane = Vec.Cross(tv, edge01); // plane is now qv double v = Vec.Dot(Direction, plane) * det; if (v < 0 || u + v > 1) return false; t = Vec.Dot(edge02, plane) * det; return t >= tmin && t <= tmax; } /// /// Returns true if the ray hits the triangle within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. Detailed information about the hit is /// returned in the supplied hit. In order to obtain all potential /// hits, the supplied hit can be initialized with RayHit3d.MaxRange. /// public readonly bool HitsTrianglePointAndEdges( V3d p0, V3d edge01, V3d edge02, double tmin, double tmax, ref RayHit3d hit ) { V3d plane = Vec.Cross(Direction, edge02); double det = Vec.Dot(edge01, plane); if (det > -1e-7 && det < 1e-7) return false; // ray ~= paralell / Triangle V3d tv = Origin - p0; det = 1 / det; // det is now inverse det double u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) return false; plane = Vec.Cross(tv, edge01); // plane is now qv double v = Vec.Dot(Direction, plane) * det; if (v < 0 || u + v > 1) return false; double t = Vec.Dot(edge02, plane) * det; if (t < tmin || t >= tmax || t >= hit.T) return false; hit.T = t; hit.Point = Origin + t * Direction; hit.Coord.X = u; hit.Coord.Y = v; hit.BackSide = (det < 0); return true; } /// /// Returns true if the ray hits the triangle within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. Detailed information about the hit is /// returned in the supplied hit. In order to obtain all potential /// hits, the supplied hit can be initialized with RayHit3d.MaxRange. /// public readonly bool HitsTrianglePointAndEdges( V3d p0, V3d edge01, V3d edge02, double tmin, double tmax, out double t ) { V3d plane = Vec.Cross(Direction, edge02); double det = Vec.Dot(edge01, plane); t = double.NaN; if (det > -1e-7 && det < 1e-7) return false; // ray ~= paralell / Triangle V3d tv = Origin - p0; det = 1 / det; // det is now inverse det double u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) return false; plane = Vec.Cross(tv, edge01); // plane is now qv double v = Vec.Dot(Direction, plane) * det; if (v < 0 || u + v > 1) return false; t = Vec.Dot(edge02, plane) * det; return t >= tmin && t <= tmax; } #endregion #region Ray-Quad hit intersection /// /// Returns true if the ray hits the quad before the parameter /// value contained in the supplied hit. Detailed information about /// the hit is returned in the supplied hit. In order to obtain all /// potential hits, the supplied hit can be initialized with /// RayHit3d.MaxRange. A hit with this overload is considered /// for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Quad3d quad, ref RayHit3d hit) => HitsQuad( quad.P0, quad.P1, quad.P2, quad.P3, 0, double.MaxValue, ref hit); /// /// Returns true if the ray hits the quad within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. Detailed information about the hit is /// returned in the supplied hit. In order to obtain all potential /// hits, the supplied hit can be initialized with RayHit3d.MaxRange. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Quad3d quad, double tmin, double tmax, ref RayHit3d hit) => HitsQuad( quad.P0, quad.P1, quad.P2, quad.P3, tmin, tmax, ref hit); /// /// Returns true if the ray hits the quad within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. The quad is considered to consist of the /// two triangles [p0,p1,p2] and [p0,p2,p3]. Detailed information /// about the hit is returned in the supplied hit. In order to obtain /// all potential hits, the supplied hit can be initialized with /// RayHit3d.MaxRange. /// public readonly bool HitsQuad( V3d p0, V3d p1, V3d p2, V3d p3, double tmin, double tmax, ref RayHit3d hit ) { V3d e02 = p2 - p0; bool result = false; if (HitsTrianglePointAndEdges(p0, p1 - p0, e02, tmin, tmax, ref hit)) { hit.Coord.X += hit.Coord.Y; result = true; } if (HitsTrianglePointAndEdges(p0, e02, p3 - p0, tmin, tmax, ref hit)) { hit.Coord.Y += hit.Coord.X; result = true; } return result; } /// /// Returns true if the ray hits the quad within the supplied parameter interval. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Quad3d quad, double tmin, double tmax, out double t) => HitsQuad(quad.P0, quad.P1, quad.P2, quad.P3, tmin, tmax, out t); /// /// Returns true if the ray hits the quad within the supplied parameter interval. /// A hit with this overload is considered for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Quad3d quad, out double t) => HitsQuad(quad.P0, quad.P1, quad.P2, quad.P3, 0, double.MaxValue, out t); /// /// Returns true if the ray hits the quad within the supplied parameter interval. /// A hit with this overload is considered for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsQuad(V3d p0, V3d p1, V3d p2, V3d p3, out double t) => HitsQuad(p0, p1, p2, p3, 0, double.MaxValue, out t); /// /// Returns true if the ray hits the quad within the supplied parameter interval. /// public readonly bool HitsQuad(V3d p0, V3d p1, V3d p2, V3d p3, double tmin, double tmax, out double t) { V3d e02 = p2 - p0; return HitsTrianglePointAndEdges(p0, p1 - p0, e02, tmin, tmax, out t) || HitsTrianglePointAndEdges(p0, e02, p3 - p0, tmin, tmax, out t); } #endregion #region Ray-Sphere hit intersection /// /// Returns true if the ray hits the sphere given by center and /// radius within the supplied parameter interval and before the /// parameter value contained in the supplied hit. Note that a /// hit is only registered if the front or the backsurface is /// encountered within the interval. If there are two valid solutions, the /// closest will be returned. /// public readonly bool HitsSphere( V3d center, double radius, double tmin, double tmax, ref RayHit3d hit) { V3d originSubCenter = Origin - center; double a = Direction.LengthSquared; double b = Direction.Dot(originSubCenter); double c = originSubCenter.LengthSquared - radius * radius; // --------------------- quadric equation : a t^2 + 2b t + c = 0 double d = b * b - a * c; // factor 2 was eliminated if (d < double.Epsilon) // no root ? return false; // then exit if (b > 0) // stable way to calculate d = -Fun.Sqrt(d) - b; // the roots of a quadratic else // equation d = Fun.Sqrt(d) - b; double t1 = d / a; double t2 = c / d; // Vieta : t1 * t2 == c/a // typically two solutions, either both positive, both negative or mixed // -> take closest (if valid) first return t1.Abs() < t2.Abs() ? ProcessHits(t1, t2, tmin, tmax, ref hit) : ProcessHits(t2, t1, tmin, tmax, ref hit); } /// /// Returns true if the ray hits the supplied sphere within the /// supplied parameter interval and before the parameter value /// contained in the supplied hit. Note that a hit is only /// registered if the front or the backsurface is encountered /// within the interval. If there are two valid solutions, the /// closest will be returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Sphere3d sphere, double tmin, double tmax, ref RayHit3d hit) => HitsSphere(sphere.Center, sphere.Radius, tmin, tmax, ref hit); /// /// Returns true if the ray hits the supplied sphere within the /// supplied parameter interval and before the parameter value /// contained in the supplied hit. Note that a hit is only /// registered if the front or the backsurface is encountered /// within the interval. If there are two valid solutions, the /// closest will be returned. A hit with this overload is /// considered for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Sphere3d sphere, ref RayHit3d hit) => HitsSphere(sphere.Center, sphere.Radius, 0, double.MaxValue, ref hit); /// /// Returns true if the ray hits the supplied sphere within the /// supplied parameter interval. Note that a hit is only /// registered if the front or the backsurface is encountered /// within the interval. If there are two valid solutions, the /// closest will be returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Sphere3d sphere, double tmin, double tmax, out double t) => HitsSphere(sphere.Center, sphere.Radius, tmin, tmax, out t); /// /// Returns true if the ray hits the supplied sphere. Note that a hit is /// registered if the front or the backsurface is encountered. If there /// are two valid solutions, the closest will be returned. A hit with this /// overload is considered for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Sphere3d sphere, out double t) => HitsSphere(sphere.Center, sphere.Radius, 0, double.MaxValue, out t); /// /// Returns true if the ray hits the supplied sphere within the supplied parameter interval. /// Note that a hit is registered if the front or the backsurface is encountered within the /// interval. If there are two valid solutions, the closest will be returned. A hit with this /// overload is considered for t in [0, double.MaxValue]. /// public readonly bool HitsSphere(V3d center, double radius, out double t) => HitsSphere(center, radius, 0, double.MaxValue, out t); /// /// Returns true if the ray hits the supplied sphere within the supplied parameter interval. /// Note that a hit is registered if the front or the backsurface is encountered within the /// interval. If there are two valid solutions, the closest will be returned. /// public readonly bool HitsSphere(V3d center, double radius, double tmin, double tmax, out double t) { var originSubCenter = Origin - center; var a = Direction.LengthSquared; var b = Direction.Dot(originSubCenter); var c = originSubCenter.LengthSquared - radius * radius; // --------------------- quadric equation : a t^2 + 2b t + c = 0 var d = b * b - a * c; // factor 2 was eliminated if (d >= double.Epsilon) // no root ? -> exit { if (b > 0) // stable way to calculate d = -Fun.Sqrt(d) - b; // the roots of a quadratic else // equation d = Fun.Sqrt(d) - b; var t1 = d / a; var t2 = c / d; // Vieta : t1 * t2 == c/a // typically two solutions, either both positive, both negative or mixed // -> take closest (if valid) first if (t2.Abs() < t1.Abs()) Fun.Swap(ref t1, ref t2); if (t1 >= tmin) { if (t1 < tmax) { t = t1; return true; } // return false } else if (t2 >= tmin) { if (t2 < tmax) { t = t2; return true; } // return false } } t = double.NaN; return false; } #endregion #region Ray-Plane hit intersection /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsPlane(Plane3d plane, ref RayHit3d hit) => HitsPlane(plane, 0, double.MaxValue, ref hit); public readonly bool HitsPlane(Plane3d plane, double tmin, double tmax, ref RayHit3d hit) { var dc = plane.Normal.Dot(Direction); // If parallel to plane if (dc == 0) return false; var dw = plane.Distance - plane.Normal.Dot(Origin); var t = dw / dc; return ComputeHit(t, tmin, tmax, ref hit); } /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsPlane(Plane3d plane, out double t) => HitsPlane(plane, 0, double.MaxValue, out t); public readonly bool HitsPlane(Plane3d plane, double tmin, double tmax, out double t) { var dc = plane.Normal.Dot(Direction); // If parallel to plane if (dc == 0) { t = double.NaN; return false; } var dw = plane.Distance - plane.Normal.Dot(Origin); t = dw / dc; return t >= tmin && t <= tmax; } #endregion #region Ray-Circle hit intersection /// /// Returns true if the ray intersects with the primitive. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Circle3d circle, double tmin, double tmax, ref RayHit3d hit) => HitsCircle(circle.Center, circle.Normal, circle.Radius, tmin, tmax, ref hit); /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Circle3d circle, ref RayHit3d hit) => HitsCircle(circle.Center, circle.Normal, circle.Radius, 0, double.MaxValue, ref hit); /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsCircle(V3d center, V3d normal, double radius, ref RayHit3d hit) => HitsCircle(center, normal, radius, 0, double.MaxValue, ref hit); /// /// Returns true if the ray intersects with the primitive. /// public readonly bool HitsCircle(V3d center, V3d normal, double radius, double tmin, double tmax, ref RayHit3d hit) { var dc = normal.Dot(Direction); var dw = normal.Dot(center - Origin); // If parallel to plane if (dc == 0) return false; var t = dw / dc; if (!ComputeHit(t, tmin, tmax, ref hit)) return false; if (Vec.DistanceSquared(hit.Point, center) > radius * radius) { hit.Point = V3d.NaN; hit.T = tmax; return false; } return true; } /// /// Returns true if the ray intersects with the primitive. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Circle3d circle, double tmin, double tmax, out double t) => HitsCircle(circle.Center, circle.Normal, circle.Radius, tmin, tmax, out t); /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Circle3d circle, out double t) => HitsCircle(circle.Center, circle.Normal, circle.Radius, 0, double.MaxValue, out t); /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsCircle(V3d center, V3d normal, double radius, out double t) => HitsCircle(center, normal, radius, 0, double.MaxValue, out t); /// /// Returns true if the ray intersects with the primitive. /// public readonly bool HitsCircle(V3d center, V3d normal, double radius, double tmin, double tmax, out double t) { var dc = normal.Dot(Direction); var dw = normal.Dot(center - Origin); // If parallel to plane if (dc == 0) { t = double.NaN; return false; } t = dw / dc; if (t < tmin || t > tmax) return false; var point = GetPointOnRay(t); // add point as out parameter? return Vec.DistanceSquared(point, center) <= radius * radius; } #endregion #region Ray-Cylinder hit intersection /// /// Returns true if the ray intersects with the primitive. /// public readonly bool HitsCylinder(V3d p0, V3d p1, double radius, double tmin, double tmax, ref RayHit3d hit) { var axis = new Line3d(p0, p1); var axisDir = axis.Direction.Normalized; // Vector Cyl.P0 -> Ray.Origin var op = Origin - p0; // normal RayDirection - CylinderAxis var normal = Direction.Cross(axisDir); var unitNormal = normal.Normalized; // normal (Vec Cyl.P0 -> Ray.Origin) - CylinderAxis var normal2 = op.Cross(axisDir); var t = -normal2.Dot(unitNormal) / normal.Length; // between enitre rays (caps are ignored) var shortestDistance = Fun.Abs(op.Dot(unitNormal)); if (shortestDistance <= radius) { var s = Fun.Abs(Fun.Sqrt(radius.Square() - shortestDistance.Square()) / Direction.Length); var t1 = t - s; // first hit of Cylinder shell var t2 = t + s; // second hit of Cylinder shell if (t1 > tmin && t1 < tmax) tmin = t1; if (t2 < tmax && t2 > tmin) tmax = t2; hit.T = t1; hit.Point = GetPointOnRay(t1); // check if found point is outside of Cylinder Caps var bottomPlane = new Plane3d(-axisDir, p0); var topPlane = new Plane3d(axisDir, p1); var heightBottom = bottomPlane.Height(hit.Point); var heightTop = topPlane.Height(hit.Point); // t1 lies outside of caps => find closest cap hit if (heightBottom > 0 || heightTop > 0) { hit.T = tmax; // intersect with bottom Cylinder Cap var bottomHit = HitsPlane(bottomPlane, tmin, tmax, ref hit); // intersect with top Cylinder Cap var topHit = HitsPlane(topPlane, tmin, tmax, ref hit); // hit still close enough to cylinder axis? var distance = axis.Ray3d.GetMinimalDistanceTo(hit.Point); if (distance <= radius && (bottomHit || topHit)) return true; } else return true; } hit.T = tmax; hit.Point = V3d.NaN; return false; } /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsCylinder(V3d p0, V3d p1, double radius, ref RayHit3d hit) => HitsCylinder(p0, p1, radius, 0, double.MaxValue, ref hit); public readonly bool HitsCylinder(V3d p0, V3d p1, double radius, double tmin, double tmax, out double t) { var axis = new Line3d(p0, p1); var axisDir = axis.Direction.Normalized; // Vector Cyl.P0 -> Ray.Origin var op = Origin - p0; // normal RayDirection - CylinderAxis var normal = Direction.Cross(axisDir); var unitNormal = normal.Normalized; // normal (Vec Cyl.P0 -> Ray.Origin) - CylinderAxis var normal2 = op.Cross(axisDir); t = -normal2.Dot(unitNormal) / normal.Length; // between entire rays (caps are ignored) var shortestDistance = Fun.Abs(op.Dot(unitNormal)); if (shortestDistance <= radius) { var s = Fun.Abs(Fun.Sqrt(radius.Square() - shortestDistance.Square()) / Direction.Length); var t1 = t - s; // first hit of Cylinder shell var t2 = t + s; // second hit of Cylinder shell if (t1 > tmin && t1 < tmax) tmin = t1; if (t2 < tmax && t2 > tmin) tmax = t2; t = t1; var point = GetPointOnRay(t1); // check if found point is outside of Cylinder Caps var bottomPlane = new Plane3d(-axisDir, p0); var topPlane = new Plane3d(axisDir, p1); var heightBottom = bottomPlane.Height(point); var heightTop = topPlane.Height(point); // t1 lies outside of caps => find closest cap hit if (heightBottom > 0 || heightTop > 0) { // intersect with bottom Cylinder Cap var bottomHit = HitsCircle(p0, -axisDir, radius, tmin, tmax, out t); // intersect with top Cylinder Cap var topHit = HitsCircle(p1, axisDir, radius, tmin, tmax, out double ttop); if (topHit) { if (bottomHit) { if (ttop.Abs() < t) t = ttop; } else t = ttop; } return topHit || bottomHit; } else return true; } t = double.NaN; return false; } /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsCylinder(V3d p0, V3d p1, double radius, out double t) => HitsCylinder(p0, p1, radius, 0, double.MaxValue, out t); /// /// Returns true if the ray intersects with the primitive. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Cylinder3d cylinder, double tmin, double tmax, ref RayHit3d hit) => Hits(cylinder, tmin, tmax, 0, ref hit); /// /// Returns true if the ray intersects with the primitive. /// public readonly bool Hits(Cylinder3d cylinder, double tmin, double tmax, double distanceScale, ref RayHit3d hit) { var axisDir = cylinder.Axis.Direction.Normalized; // Vector Cyl.P0 -> Ray.Origin var op = Origin - cylinder.P0; // normal RayDirection - CylinderAxis var normal = Direction.Cross(axisDir); var unitNormal = normal.Normalized; // normal (Vec Cyl.P0 -> Ray.Origin) - CylinderAxis var normal2 = op.Cross(axisDir); var t = -normal2.Dot(unitNormal) / normal.Length; var radius = cylinder.Radius; if (distanceScale != 0) { // cylinder gets bigger, the further away it is var pnt = GetPointOnRay(t); var dis = Vec.Distance(pnt, this.Origin); radius = ((cylinder.Radius / distanceScale) * dis) * 2; } // between enitre rays (caps are ignored) var shortestDistance = Fun.Abs(op.Dot(unitNormal)); if (shortestDistance <= radius) { var s = Fun.Abs(Fun.Sqrt(radius.Square() - shortestDistance.Square()) / Direction.Length); var t1 = t - s; // first hit of Cylinder shell var t2 = t + s; // second hit of Cylinder shell if (t1 > tmin && t1 < tmax) tmin = t1; if (t2 < tmax && t2 > tmin) tmax = t2; hit.T = t1; hit.Point = GetPointOnRay(t1); // check if found point is outside of Cylinder Caps var bottomPlane = new Plane3d(cylinder.Circle0.Normal, cylinder.Circle0.Center); var topPlane = new Plane3d(cylinder.Circle1.Normal, cylinder.Circle1.Center); var heightBottom = bottomPlane.Height(hit.Point); var heightTop = topPlane.Height(hit.Point); // t1 lies outside of caps => find closest cap hit if (heightBottom > 0 || heightTop > 0) { hit.T = tmax; // intersect with bottom Cylinder Cap var bottomHit = HitsPlane(bottomPlane, tmin, tmax, ref hit); // intersect with top Cylinder Cap var topHit = HitsPlane(topPlane, tmin, tmax, ref hit); // hit still close enough to cylinder axis? var distance = cylinder.Axis.Ray3d.GetMinimalDistanceTo(hit.Point); if (distance <= radius && (bottomHit || topHit)) return true; } else return true; } hit.T = tmax; hit.Point = V3d.NaN; return false; } /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, double.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(Cylinder3d cylinder, ref RayHit3d hit) => Hits(cylinder, 0, double.MaxValue, ref hit); #endregion #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Ray3d a, Ray3d b) => (a.Origin == b.Origin) && (a.Direction == b.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Ray3d a, Ray3d b) => !((a.Origin == b.Origin) && (a.Direction == b.Direction)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int LexicalCompare(Ray3d other) { var cmp = Origin.LexicalCompare(other.Origin); if (cmp != 0) return cmp; return Direction.LexicalCompare(other.Direction); } #endregion #region Overrides /// /// Calculates Hash-code of the given ray. /// /// Hash-code. public override readonly int GetHashCode() => HashCode.GetCombined(Origin, Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Ray3d other) => Origin.Equals(other.Origin) && Direction.Equals(other.Direction); public override readonly bool Equals(object other) => (other is Ray3d o) ? Equals(o) : false; public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Origin, Direction); public static Ray3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Ray3d(V3d.Parse(x[0]), V3d.Parse(x[1])); } #endregion #region IBoundingBox3d public readonly Box3d BoundingBox3d => Box3d.FromPoints(Origin, Direction + Origin); #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Ray3d a, Ray3d b, double tolerance) => ApproximateEquals(a.Origin, b.Origin, tolerance) && ApproximateEquals(a.Direction, b.Direction, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Ray3d a, Ray3d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region RayHit3d /// /// A ray hit represents the hit of a ray on a primitive object such as /// a triangle. It stores the ray parameter of the hit, the hit point, /// the hit point's coordinates, and a flag indicating if the backside /// of the primitive was hit. Optionally the part field can be used to /// store which part of a multi-part object was hit. If no multi-part /// objects are used, this field remains 0. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public struct RayHit3d { [DataMember] public double T; [DataMember] public V3d Point; [DataMember] public V2d Coord; [DataMember] public bool BackSide; [DataMember] public int Part; #region Constructor public RayHit3d(double tMax) { T = tMax; Point = V3d.NaN; Coord = V2d.NaN; BackSide = false; Part = 0; } #endregion #region Constants public static readonly RayHit3d MaxRange = new RayHit3d(double.MaxValue); #endregion } #endregion #region FastRay3d /// /// A fast ray contains a ray and a number of precomputed flags and /// fields for fast intersection computation with bounding boxes and /// other axis-aligned sturctures such as kd-Trees. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public readonly struct FastRay3d { [DataMember] public readonly Ray3d Ray; [DataMember] public readonly DirFlags DirFlags; [DataMember] public readonly V3d InvDir; #region Constructors public FastRay3d(Ray3d ray) { Ray = ray; DirFlags = ray.Direction.DirFlags(); InvDir = 1 / ray.Direction; } public FastRay3d(V3d origin, V3d direction) : this(new Ray3d(origin, direction)) { } #endregion #region Ray Arithmetics public readonly bool Intersects( Box3d box, ref double tmin, ref double tmax ) { var dirFlags = DirFlags; if ((dirFlags & DirFlags.PositiveX) != 0) { { double t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } { double t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeX) != 0) { { double t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } { double t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to X-plane { if (Ray.Origin.X < box.Min.X || Ray.Origin.X > box.Max.X) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { { double t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } { double t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeY) != 0) { { double t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } { double t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to Y-plane { if (Ray.Origin.Y < box.Min.Y || Ray.Origin.Y > box.Max.Y) return false; } if ((dirFlags & DirFlags.PositiveZ) != 0) { { double t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) tmax = t; } { double t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeZ) != 0) { { double t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) tmax = t; } { double t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to Z-plane { if (Ray.Origin.Z < box.Min.Z || Ray.Origin.Z > box.Max.Z) return false; } if (tmin > tmax) return false; return true; } /// /// This variant of the intersection method only tests with the /// faces of the box indicated by the supplied boxFlags. /// public readonly bool Intersects( Box3d box, Box.Flags boxFlags, ref double tmin, ref double tmax ) { var dirFlags = DirFlags; if ((dirFlags & DirFlags.PositiveX) != 0) { if ((boxFlags & Box.Flags.MaxX) != 0) { double t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MinX) != 0) { double t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeX) != 0) { if ((boxFlags & Box.Flags.MinX) != 0) { double t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MaxX) != 0) { double t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to X-plane { if ((boxFlags & Box.Flags.MinX) != 0 && (Ray.Origin.X < box.Min.X) || (boxFlags & Box.Flags.MaxX) != 0 && (Ray.Origin.X > box.Max.X)) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { if ((boxFlags & Box.Flags.MaxY) != 0) { double t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MinY) != 0) { double t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeY) != 0) { if ((boxFlags & Box.Flags.MinY) != 0) { double t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MaxY) != 0) { double t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to Y-plane { if ((boxFlags & Box.Flags.MinY) != 0 && (Ray.Origin.Y < box.Min.Y) || (boxFlags & Box.Flags.MaxY) != 0 && (Ray.Origin.Y > box.Max.Y)) return false; } if ((dirFlags & DirFlags.PositiveZ) != 0) { if ((boxFlags & Box.Flags.MaxZ) != 0) { double t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MinZ) != 0) { double t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeZ) != 0) { if ((boxFlags & Box.Flags.MinZ) != 0) { double t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MaxZ) != 0) { double t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to Z-plane { if ((boxFlags & Box.Flags.MinZ) != 0 && (Ray.Origin.Z < box.Min.Z) || (boxFlags & Box.Flags.MaxZ) != 0 && (Ray.Origin.Z > box.Max.Z)) return false; } if (tmin > tmax) return false; return true; } /// /// This variant of the intersection method returns the affected /// planes of the box if the box was hit. /// public readonly bool Intersects( Box3d box, ref double tmin, ref double tmax, out Box.Flags tminFlags, out Box.Flags tmaxFlags ) { var dirFlags = DirFlags; tminFlags = Box.Flags.None; tmaxFlags = Box.Flags.None; if ((dirFlags & DirFlags.PositiveX) != 0) { { double t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxX; } } { double t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinX; } } } else if ((dirFlags & DirFlags.NegativeX) != 0) { { double t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinX; } } { double t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxX; } } } else // ray parallel to X-plane { if (Ray.Origin.X < box.Min.X || Ray.Origin.X > box.Max.X) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { { double t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxY; } } { double t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinY; } } } else if ((dirFlags & DirFlags.NegativeY) != 0) { { double t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinY; } } { double t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxY; } } } else // ray parallel to Y-plane { if (Ray.Origin.Y < box.Min.Y || Ray.Origin.Y > box.Max.Y) return false; } if ((dirFlags & DirFlags.PositiveZ) != 0) { { double t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxZ; } } { double t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinZ; } } } else if ((dirFlags & DirFlags.NegativeZ) != 0) { { double t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinZ; } } { double t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxZ; } } } else // ray parallel to Z-plane { if (Ray.Origin.Z < box.Min.Z || Ray.Origin.Z > box.Max.Z) return false; } if (tmin > tmax) return false; return true; } /// /// This variant of the intersection method only tests with the /// faces of the box indicated by the supplied boxFlags and /// returns the affected planes of the box if the box was hit. /// public readonly bool Intersects( Box3d box, Box.Flags boxFlags, ref double tmin, ref double tmax, out Box.Flags tminFlags, out Box.Flags tmaxFlags ) { var dirFlags = DirFlags; tminFlags = Box.Flags.None; tmaxFlags = Box.Flags.None; if ((dirFlags & DirFlags.PositiveX) != 0) { if ((boxFlags & Box.Flags.MaxX) != 0) { double t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxX; } } if ((boxFlags & Box.Flags.MinX) != 0) { double t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinX; } } } else if ((dirFlags & DirFlags.NegativeX) != 0) { if ((boxFlags & Box.Flags.MinX) != 0) { double t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinX; } } if ((boxFlags & Box.Flags.MaxX) != 0) { double t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxX; } } } else // ray parallel to X-plane { if ((boxFlags & Box.Flags.MinX) != 0 && (Ray.Origin.X < box.Min.X) || (boxFlags & Box.Flags.MaxX) != 0 && (Ray.Origin.X > box.Max.X)) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { if ((boxFlags & Box.Flags.MaxY) != 0) { double t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxY; } } if ((boxFlags & Box.Flags.MinY) != 0) { double t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinY; } } } else if ((dirFlags & DirFlags.NegativeY) != 0) { if ((boxFlags & Box.Flags.MinY) != 0) { double t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinY; } } if ((boxFlags & Box.Flags.MaxY) != 0) { double t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxY; } } } else // ray parallel to Y-plane { if ((boxFlags & Box.Flags.MinY) != 0 && (Ray.Origin.Y < box.Min.Y) || (boxFlags & Box.Flags.MaxY) != 0 && (Ray.Origin.Y > box.Max.Y)) return false; } if ((dirFlags & DirFlags.PositiveZ) != 0) { if ((boxFlags & Box.Flags.MaxZ) != 0) { double t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxZ; } } if ((boxFlags & Box.Flags.MinZ) != 0) { double t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinZ; } } } else if ((dirFlags & DirFlags.NegativeZ) != 0) { if ((boxFlags & Box.Flags.MinZ) != 0) { double t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinZ; } } if ((boxFlags & Box.Flags.MaxZ) != 0) { double t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxZ; } } } else // ray parallel to Z-plane { if ((boxFlags & Box.Flags.MinZ) != 0 && (Ray.Origin.Z < box.Min.Z) || (boxFlags & Box.Flags.MaxZ) != 0 && (Ray.Origin.Z > box.Max.Z)) return false; } if (tmin > tmax) return false; return true; } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Ray/Ray3_template.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var ray3t = "Ray3" + tc; //# var ray3t2 = "Ray3" + tc2; //# var rayhit3t = "RayHit3" + tc; //# var rayhit3t2 = "RayHit3" + tc2; //# var v3t = "V3" + tc; //# var m33t = "M33" + tc; //# var m44t = "M44" + tc; //# var box3t = "Box3" + tc; //# var plane3t = "Plane3" + tc; //# var line3t = "Line3" + tc; //# var triangle3t = "Triangle3" + tc; //# var quad3t = "Quad3" + tc; //# var sphere3t = "Sphere3" + tc; //# var circle3t = "Circle3" + tc; //# var cylinder3t = "Cylinder3" + tc; //# var iboundingbox = "IBoundingBox3" + tc; //# var rot3t = "Rot3" + tc; //# var scale3t = "Scale3" + tc; //# var shift3t = "Shift3" + tc; //# var euclidean3t = "Euclidean3" + tc; //# var similarity3t = "Similarity3" + tc; //# var affine3t = "Affine3" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var eps = isDouble ? "1e-7" : "1e-4f"; #region __ray3t__ /// /// A three-dimensional ray with an origin and a direction. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __ray3t__ : IEquatable<__ray3t__>, IValidity, __iboundingbox__ { [DataMember] public __v3t__ Origin; [DataMember] public __v3t__ Direction; #region Constructors /// /// Creates Ray from origin point and directional vector /// public __ray3t__(__v3t__ origin, __v3t__ direction) { Origin = origin; Direction = direction; } public static __ray3t__ FromEndPoints(__v3t__ origin, __v3t__ target) => new __ray3t__(origin, target - origin); #endregion #region Constants /// /// An invalid ray has a zero direction. /// public static readonly __ray3t__ Invalid = new __ray3t__(__v3t__.NaN, __v3t__.Zero); #endregion #region Properties /// /// A ray is valid if its direction is non-zero. /// public readonly bool IsValid { get { return Direction != __v3t__.Zero; } } /// /// A ray is invalid if its direction is zero. /// public readonly bool IsInvalid { get { return Direction == __v3t__.Zero; } } /// /// Returns true if either the origin or the direction contains any NaN value. /// public readonly bool AnyNaN { get { return Origin.AnyNaN || Direction.AnyNaN; } } /// /// Line segment from origin to origin + direction. /// public readonly __line3t__ __line3t__ => new __line3t__(Origin, Origin + Direction); /// /// Returns new ray with flipped direction. /// public readonly __ray3t__ Reversed => new __ray3t__(Origin, -Direction); /// /// Returns the ray with its directional normalized. /// public readonly __ray3t__ Normalized => new(Origin, Direction.Normalized); #endregion #region Ray Arithmetics /// /// Gets the point on the ray that is t * Direction from Origin. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __v3t__ GetPointOnRay(__ftype__ t) => Origin + Direction * t; /// /// Gets the t for a point p on this ray. /// public readonly __ftype__ GetT(__v3t__ p) { var v = p - Origin; var d = Direction.Abs(); if (d.X > d.Y) return (d.X > d.Z) ? (v.X / Direction.X) : (v.Z / Direction.Z); else return (d.Y > d.Z) ? (v.Y / Direction.Y) : (v.Z / Direction.Z); } /// /// Gets the t of the closest point on the ray for any point p. /// public readonly __ftype__ GetTOfProjectedPoint(__v3t__ p) { var v = p - Origin; return v.Dot(Direction) / Direction.LengthSquared; } /// /// Returns the ray transformed with the given matrix. /// This method is only valid for similarity transformations (uniform scale). /// public readonly __ray3t__ Transformed(__m44t__ mat) => new(mat.TransformPos(Origin), mat.TransformDir(Direction)); /// /// Returns the ray transformed with the given transformation. /// public readonly __ray3t__ Transformed(__rot3t__ transform) => new(transform.Transform(Origin), transform.Transform(Direction)); /// /// Returns the ray transformed with the given transformation. /// public readonly __ray3t__ Transformed(__scale3t__ transform) => new(transform.Transform(Origin), transform.Transform(Direction)); /// /// Returns the ray transformed with the given transformation. /// public readonly __ray3t__ Transformed(__shift3t__ transform) => new(transform.Transform(Origin), Direction); /// /// Returns the ray transformed with the given transformation. /// public readonly __ray3t__ Transformed(__euclidean3t__ transform) => new(transform.TransformPos(Origin), transform.TransformDir(Direction)); /// /// Returns the ray transformed with the given transformation. /// public readonly __ray3t__ Transformed(__similarity3t__ transform) => new(transform.TransformPos(Origin), transform.TransformDir(Direction)); /// /// Returns the ray transformed with the given transformation. /// public readonly __ray3t__ Transformed(__affine3t__ transform) => new(transform.TransformPos(Origin), transform.TransformDir(Direction)); /// /// Returns the angle between this and the given in radians. /// The direction vectors of the input rays have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__ AngleBetweenFast(__ray3t__ r) => Direction.AngleBetweenFast(r.Direction); /// /// Returns the angle between this and the given in radians using a numerically stable algorithm. /// The direction vectors of the input rays have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__ AngleBetween(__ray3t__ r) => Direction.AngleBetween(r.Direction); #endregion #region Ray hit intersections #region Private functions private readonly bool ComputeHit( __ftype__ t, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit) { if (t >= tmin) { if (t < tmax && t < hit.T) { hit.T = t; hit.Point = GetPointOnRay(t); hit.Coord = V2d.NaN; hit.BackSide = false; return true; } return false; } return false; } private readonly bool GetClosestHit( __ftype__ t1, __ftype__ t2, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit) { return t1 < t2 ? ProcessHits(t1, t2, tmin, tmax, ref hit) : ProcessHits(t2, t1, tmin, tmax, ref hit); } private readonly bool ProcessHits( __ftype__ t1, __ftype__ t2, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit) { if (t1 >= tmin) { if (t1 < tmax && t1 < hit.T) { hit.T = t1; hit.Point = GetPointOnRay(t1); hit.Coord = V2d.NaN; hit.BackSide = false; return true; } return false; } if (t2 >= tmin) { if (t2 < tmax && t2 < hit.T) { hit.T = t2; hit.Point = GetPointOnRay(t2); hit.Coord = V2d.NaN; hit.BackSide = true; return true; } } return false; } #endregion #region Ray-Ray hit intersection /// /// Returns true if the ray hits the other ray before the parameter /// value contained in the supplied hit. Detailed information about /// the hit is returned in the supplied hit. A hit with this /// overload is considered for t in [0, __ftype__.MaxValue]. /// public readonly bool Hits(__ray3t__ ray, ref __rayhit3t__ hit) => HitsRay(ray, 0, __ftype__.MaxValue, ref hit); /// /// Returns true if the ray hits the other ray before the parameter /// value contained in the supplied hit. Detailed information about /// the hit is returned in the supplied hit. /// public readonly bool Hits(__ray3t__ ray, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit) => HitsRay(ray, tmin, tmax, ref hit); /// /// Returns true if the ray hits the other ray before the parameter /// value contained in the supplied hit. Detailed information about /// the hit is returned in the supplied hit. /// public readonly bool HitsRay(__ray3t__ ray, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit) { __v3t__ d = Origin - ray.Origin; __v3t__ u = Direction; __v3t__ v = ray.Direction; __v3t__ n = u.Cross(v); if (Fun.IsTiny(d.Length)) return true; else if (Fun.IsTiny(u.Cross(v).Length)) return false; else { //-t0*u + t1*v + t2*n == d //M = {-u,v,n} //M*{t0,t1,t2}T == d //{t0,t1,t2}T == M^-1 * d __m33t__ M = new __m33t__ { C0 = -u, C1 = v, C2 = n }; if (M.Invertible) { __v3t__ t = M.Inverse * d; if (Fun.IsTiny(t.Z)) { ProcessHits(t.X, __ftype__.MaxValue, tmin, tmax, ref hit); return true; } else return false; } else return false; } } #endregion #region Ray-Triangle hit intersection /// /// Returns true if the ray hits the triangle before the parameter /// value contained in the supplied hit. Detailed information about /// the hit is returned in the supplied hit. A hit with this /// overload is considered for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__triangle3t__ triangle, ref __rayhit3t__ hit) => HitsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, 0, __ftype__.MaxValue, ref hit); /// /// Returns true if the ray hits the triangle. A hit with this /// overload is considered for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__triangle3t__ triangle, out __ftype__ t) => HitsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, 0, __ftype__.MaxValue, out t); /// /// Returns true if the ray hits the triangle within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. Detailed information about the hit is /// returned in the supplied hit. In order to obtain all potential /// hits, the supplied hit can be initialized with __rayhit3t__.MaxRange. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__triangle3t__ triangle, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit) => HitsTrianglePointAndEdges( triangle.P0, triangle.Edge01, triangle.Edge02, tmin, tmax, ref hit); /// /// Returns true if the ray hits the triangle within [0, __ftype__.MaxValue] /// and before the parameter value contained in the supplied hit. Detailed /// information about the hit is returned in the supplied hit. In order to /// obtain all potential hits, the supplied hit can be initialized with /// __rayhit3t__.MaxRange. Degenerated triangles will not result in an intersection /// even if any edge is hit exactly. /// public readonly bool HitsTriangle(__v3t__ p0, __v3t__ p1, __v3t__ p2, ref __rayhit3t__ hit) => HitsTriangle(p0, p1, p2, 0, __ftype__.MaxValue, ref hit); /// /// Returns true if the ray hits the triangle within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. Detailed information about the hit is /// returned in the supplied hit. In order to obtain all potential /// hits, the supplied hit can be initialized with __rayhit3t__.MaxRange. /// Degenerated triangles will not result in an intersection even if /// any edge is hit exactly. /// public readonly bool HitsTriangle( __v3t__ p0, __v3t__ p1, __v3t__ p2, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit ) { __v3t__ edge01 = p1 - p0; __v3t__ edge02 = p2 - p0; __v3t__ plane = Vec.Cross(Direction, edge02); __ftype__ det = Vec.Dot(edge01, plane); if (det > -__eps__ && det < __eps__) return false; // ray ~= paralell / Triangle __v3t__ tv = Origin - p0; det = 1 / det; // det is now inverse det __ftype__ u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) return false; plane = Vec.Cross(tv, edge01); // plane is now qv __ftype__ v = Vec.Dot(Direction, plane) * det; if (v < 0 || u + v > 1) return false; __ftype__ t = Vec.Dot(edge02, plane) * det; if (t < tmin || t >= tmax || t >= hit.T) return false; hit.T = t; hit.Point = Origin + t * Direction; hit.Coord.X = u; hit.Coord.Y = v; hit.BackSide = (det < 0); return true; } /// /// Returns true if the ray hits the triangle. Degenerated triangles /// will not result in an intersection even if any edge is hit exactly. /// A hit with this overload is considered for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsTriangle(__v3t__ p0, __v3t__ p1, __v3t__ p2, out __ftype__ t) => HitsTriangle(p0, p1, p2, 0, __ftype__.MaxValue, out t); /// /// Returns true if the ray hits the triangle within the supplied /// parameter interval. Degenerated triangles will not result in an /// intersection even if any edge is hit exactly. /// public readonly bool HitsTriangle( __v3t__ p0, __v3t__ p1, __v3t__ p2, __ftype__ tmin, __ftype__ tmax, out __ftype__ t ) { __v3t__ edge01 = p1 - p0; __v3t__ edge02 = p2 - p0; __v3t__ plane = Vec.Cross(Direction, edge02); __ftype__ det = Vec.Dot(edge01, plane); t = __ftype__.NaN; if (det > -__eps__ && det < __eps__) return false; // ray ~= paralell / Triangle __v3t__ tv = Origin - p0; det = 1 / det; // det is now inverse det __ftype__ u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) return false; plane = Vec.Cross(tv, edge01); // plane is now qv __ftype__ v = Vec.Dot(Direction, plane) * det; if (v < 0 || u + v > 1) return false; t = Vec.Dot(edge02, plane) * det; return t >= tmin && t <= tmax; } /// /// Returns true if the ray hits the triangle within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. Detailed information about the hit is /// returned in the supplied hit. In order to obtain all potential /// hits, the supplied hit can be initialized with __rayhit3t__.MaxRange. /// public readonly bool HitsTrianglePointAndEdges( __v3t__ p0, __v3t__ edge01, __v3t__ edge02, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit ) { __v3t__ plane = Vec.Cross(Direction, edge02); __ftype__ det = Vec.Dot(edge01, plane); if (det > -__eps__ && det < __eps__) return false; // ray ~= paralell / Triangle __v3t__ tv = Origin - p0; det = 1 / det; // det is now inverse det __ftype__ u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) return false; plane = Vec.Cross(tv, edge01); // plane is now qv __ftype__ v = Vec.Dot(Direction, plane) * det; if (v < 0 || u + v > 1) return false; __ftype__ t = Vec.Dot(edge02, plane) * det; if (t < tmin || t >= tmax || t >= hit.T) return false; hit.T = t; hit.Point = Origin + t * Direction; hit.Coord.X = u; hit.Coord.Y = v; hit.BackSide = (det < 0); return true; } /// /// Returns true if the ray hits the triangle within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. Detailed information about the hit is /// returned in the supplied hit. In order to obtain all potential /// hits, the supplied hit can be initialized with __rayhit3t__.MaxRange. /// public readonly bool HitsTrianglePointAndEdges( __v3t__ p0, __v3t__ edge01, __v3t__ edge02, __ftype__ tmin, __ftype__ tmax, out __ftype__ t ) { __v3t__ plane = Vec.Cross(Direction, edge02); __ftype__ det = Vec.Dot(edge01, plane); t = __ftype__.NaN; if (det > -__eps__ && det < __eps__) return false; // ray ~= paralell / Triangle __v3t__ tv = Origin - p0; det = 1 / det; // det is now inverse det __ftype__ u = Vec.Dot(tv, plane) * det; if (u < 0 || u > 1) return false; plane = Vec.Cross(tv, edge01); // plane is now qv __ftype__ v = Vec.Dot(Direction, plane) * det; if (v < 0 || u + v > 1) return false; t = Vec.Dot(edge02, plane) * det; return t >= tmin && t <= tmax; } #endregion #region Ray-Quad hit intersection /// /// Returns true if the ray hits the quad before the parameter /// value contained in the supplied hit. Detailed information about /// the hit is returned in the supplied hit. In order to obtain all /// potential hits, the supplied hit can be initialized with /// __rayhit3t__.MaxRange. A hit with this overload is considered /// for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__quad3t__ quad, ref __rayhit3t__ hit) => HitsQuad( quad.P0, quad.P1, quad.P2, quad.P3, 0, __ftype__.MaxValue, ref hit); /// /// Returns true if the ray hits the quad within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. Detailed information about the hit is /// returned in the supplied hit. In order to obtain all potential /// hits, the supplied hit can be initialized with __rayhit3t__.MaxRange. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__quad3t__ quad, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit) => HitsQuad( quad.P0, quad.P1, quad.P2, quad.P3, tmin, tmax, ref hit); /// /// Returns true if the ray hits the quad within the supplied /// parameter interval and before the parameter value contained /// in the supplied hit. The quad is considered to consist of the /// two triangles [p0,p1,p2] and [p0,p2,p3]. Detailed information /// about the hit is returned in the supplied hit. In order to obtain /// all potential hits, the supplied hit can be initialized with /// __rayhit3t__.MaxRange. /// public readonly bool HitsQuad( __v3t__ p0, __v3t__ p1, __v3t__ p2, __v3t__ p3, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit ) { __v3t__ e02 = p2 - p0; bool result = false; if (HitsTrianglePointAndEdges(p0, p1 - p0, e02, tmin, tmax, ref hit)) { hit.Coord.X += hit.Coord.Y; result = true; } if (HitsTrianglePointAndEdges(p0, e02, p3 - p0, tmin, tmax, ref hit)) { hit.Coord.Y += hit.Coord.X; result = true; } return result; } /// /// Returns true if the ray hits the quad within the supplied parameter interval. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__quad3t__ quad, __ftype__ tmin, __ftype__ tmax, out __ftype__ t) => HitsQuad(quad.P0, quad.P1, quad.P2, quad.P3, tmin, tmax, out t); /// /// Returns true if the ray hits the quad within the supplied parameter interval. /// A hit with this overload is considered for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__quad3t__ quad, out __ftype__ t) => HitsQuad(quad.P0, quad.P1, quad.P2, quad.P3, 0, __ftype__.MaxValue, out t); /// /// Returns true if the ray hits the quad within the supplied parameter interval. /// A hit with this overload is considered for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsQuad(__v3t__ p0, __v3t__ p1, __v3t__ p2, __v3t__ p3, out __ftype__ t) => HitsQuad(p0, p1, p2, p3, 0, __ftype__.MaxValue, out t); /// /// Returns true if the ray hits the quad within the supplied parameter interval. /// public readonly bool HitsQuad(__v3t__ p0, __v3t__ p1, __v3t__ p2, __v3t__ p3, __ftype__ tmin, __ftype__ tmax, out __ftype__ t) { __v3t__ e02 = p2 - p0; return HitsTrianglePointAndEdges(p0, p1 - p0, e02, tmin, tmax, out t) || HitsTrianglePointAndEdges(p0, e02, p3 - p0, tmin, tmax, out t); } #endregion #region Ray-Sphere hit intersection /// /// Returns true if the ray hits the sphere given by center and /// radius within the supplied parameter interval and before the /// parameter value contained in the supplied hit. Note that a /// hit is only registered if the front or the backsurface is /// encountered within the interval. If there are two valid solutions, the /// closest will be returned. /// public readonly bool HitsSphere( __v3t__ center, __ftype__ radius, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit) { __v3t__ originSubCenter = Origin - center; __ftype__ a = Direction.LengthSquared; __ftype__ b = Direction.Dot(originSubCenter); __ftype__ c = originSubCenter.LengthSquared - radius * radius; // --------------------- quadric equation : a t^2 + 2b t + c = 0 __ftype__ d = b * b - a * c; // factor 2 was eliminated if (d < __ftype__.Epsilon) // no root ? return false; // then exit if (b > 0) // stable way to calculate d = -Fun.Sqrt(d) - b; // the roots of a quadratic else // equation d = Fun.Sqrt(d) - b; __ftype__ t1 = d / a; __ftype__ t2 = c / d; // Vieta : t1 * t2 == c/a // typically two solutions, either both positive, both negative or mixed // -> take closest (if valid) first return t1.Abs() < t2.Abs() ? ProcessHits(t1, t2, tmin, tmax, ref hit) : ProcessHits(t2, t1, tmin, tmax, ref hit); } /// /// Returns true if the ray hits the supplied sphere within the /// supplied parameter interval and before the parameter value /// contained in the supplied hit. Note that a hit is only /// registered if the front or the backsurface is encountered /// within the interval. If there are two valid solutions, the /// closest will be returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__sphere3t__ sphere, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit) => HitsSphere(sphere.Center, sphere.Radius, tmin, tmax, ref hit); /// /// Returns true if the ray hits the supplied sphere within the /// supplied parameter interval and before the parameter value /// contained in the supplied hit. Note that a hit is only /// registered if the front or the backsurface is encountered /// within the interval. If there are two valid solutions, the /// closest will be returned. A hit with this overload is /// considered for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__sphere3t__ sphere, ref __rayhit3t__ hit) => HitsSphere(sphere.Center, sphere.Radius, 0, __ftype__.MaxValue, ref hit); /// /// Returns true if the ray hits the supplied sphere within the /// supplied parameter interval. Note that a hit is only /// registered if the front or the backsurface is encountered /// within the interval. If there are two valid solutions, the /// closest will be returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__sphere3t__ sphere, __ftype__ tmin, __ftype__ tmax, out __ftype__ t) => HitsSphere(sphere.Center, sphere.Radius, tmin, tmax, out t); /// /// Returns true if the ray hits the supplied sphere. Note that a hit is /// registered if the front or the backsurface is encountered. If there /// are two valid solutions, the closest will be returned. A hit with this /// overload is considered for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__sphere3t__ sphere, out __ftype__ t) => HitsSphere(sphere.Center, sphere.Radius, 0, __ftype__.MaxValue, out t); /// /// Returns true if the ray hits the supplied sphere within the supplied parameter interval. /// Note that a hit is registered if the front or the backsurface is encountered within the /// interval. If there are two valid solutions, the closest will be returned. A hit with this /// overload is considered for t in [0, __ftype__.MaxValue]. /// public readonly bool HitsSphere(__v3t__ center, __ftype__ radius, out __ftype__ t) => HitsSphere(center, radius, 0, __ftype__.MaxValue, out t); /// /// Returns true if the ray hits the supplied sphere within the supplied parameter interval. /// Note that a hit is registered if the front or the backsurface is encountered within the /// interval. If there are two valid solutions, the closest will be returned. /// public readonly bool HitsSphere(__v3t__ center, __ftype__ radius, __ftype__ tmin, __ftype__ tmax, out __ftype__ t) { var originSubCenter = Origin - center; var a = Direction.LengthSquared; var b = Direction.Dot(originSubCenter); var c = originSubCenter.LengthSquared - radius * radius; // --------------------- quadric equation : a t^2 + 2b t + c = 0 var d = b * b - a * c; // factor 2 was eliminated if (d >= __ftype__.Epsilon) // no root ? -> exit { if (b > 0) // stable way to calculate d = -Fun.Sqrt(d) - b; // the roots of a quadratic else // equation d = Fun.Sqrt(d) - b; var t1 = d / a; var t2 = c / d; // Vieta : t1 * t2 == c/a // typically two solutions, either both positive, both negative or mixed // -> take closest (if valid) first if (t2.Abs() < t1.Abs()) Fun.Swap(ref t1, ref t2); if (t1 >= tmin) { if (t1 < tmax) { t = t1; return true; } // return false } else if (t2 >= tmin) { if (t2 < tmax) { t = t2; return true; } // return false } } t = __ftype__.NaN; return false; } #endregion #region Ray-Plane hit intersection /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsPlane(__plane3t__ plane, ref __rayhit3t__ hit) => HitsPlane(plane, 0, __ftype__.MaxValue, ref hit); public readonly bool HitsPlane(__plane3t__ plane, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit) { var dc = plane.Normal.Dot(Direction); // If parallel to plane if (dc == 0) return false; var dw = plane.Distance - plane.Normal.Dot(Origin); var t = dw / dc; return ComputeHit(t, tmin, tmax, ref hit); } /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsPlane(__plane3t__ plane, out __ftype__ t) => HitsPlane(plane, 0, __ftype__.MaxValue, out t); public readonly bool HitsPlane(__plane3t__ plane, __ftype__ tmin, __ftype__ tmax, out __ftype__ t) { var dc = plane.Normal.Dot(Direction); // If parallel to plane if (dc == 0) { t = __ftype__.NaN; return false; } var dw = plane.Distance - plane.Normal.Dot(Origin); t = dw / dc; return t >= tmin && t <= tmax; } #endregion #region Ray-Circle hit intersection /// /// Returns true if the ray intersects with the primitive. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__circle3t__ circle, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit) => HitsCircle(circle.Center, circle.Normal, circle.Radius, tmin, tmax, ref hit); /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__circle3t__ circle, ref __rayhit3t__ hit) => HitsCircle(circle.Center, circle.Normal, circle.Radius, 0, __ftype__.MaxValue, ref hit); /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsCircle(__v3t__ center, __v3t__ normal, __ftype__ radius, ref __rayhit3t__ hit) => HitsCircle(center, normal, radius, 0, __ftype__.MaxValue, ref hit); /// /// Returns true if the ray intersects with the primitive. /// public readonly bool HitsCircle(__v3t__ center, __v3t__ normal, __ftype__ radius, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit) { var dc = normal.Dot(Direction); var dw = normal.Dot(center - Origin); // If parallel to plane if (dc == 0) return false; var t = dw / dc; if (!ComputeHit(t, tmin, tmax, ref hit)) return false; if (Vec.DistanceSquared(hit.Point, center) > radius * radius) { hit.Point = __v3t__.NaN; hit.T = tmax; return false; } return true; } /// /// Returns true if the ray intersects with the primitive. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__circle3t__ circle, __ftype__ tmin, __ftype__ tmax, out __ftype__ t) => HitsCircle(circle.Center, circle.Normal, circle.Radius, tmin, tmax, out t); /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__circle3t__ circle, out __ftype__ t) => HitsCircle(circle.Center, circle.Normal, circle.Radius, 0, __ftype__.MaxValue, out t); /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsCircle(__v3t__ center, __v3t__ normal, __ftype__ radius, out __ftype__ t) => HitsCircle(center, normal, radius, 0, __ftype__.MaxValue, out t); /// /// Returns true if the ray intersects with the primitive. /// public readonly bool HitsCircle(__v3t__ center, __v3t__ normal, __ftype__ radius, __ftype__ tmin, __ftype__ tmax, out __ftype__ t) { var dc = normal.Dot(Direction); var dw = normal.Dot(center - Origin); // If parallel to plane if (dc == 0) { t = __ftype__.NaN; return false; } t = dw / dc; if (t < tmin || t > tmax) return false; var point = GetPointOnRay(t); // add point as out parameter? return Vec.DistanceSquared(point, center) <= radius * radius; } #endregion #region Ray-Cylinder hit intersection /// /// Returns true if the ray intersects with the primitive. /// public readonly bool HitsCylinder(__v3t__ p0, __v3t__ p1, __ftype__ radius, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit) { var axis = new __line3t__(p0, p1); var axisDir = axis.Direction.Normalized; // Vector Cyl.P0 -> Ray.Origin var op = Origin - p0; // normal RayDirection - CylinderAxis var normal = Direction.Cross(axisDir); var unitNormal = normal.Normalized; // normal (Vec Cyl.P0 -> Ray.Origin) - CylinderAxis var normal2 = op.Cross(axisDir); var t = -normal2.Dot(unitNormal) / normal.Length; // between enitre rays (caps are ignored) var shortestDistance = Fun.Abs(op.Dot(unitNormal)); if (shortestDistance <= radius) { var s = Fun.Abs(Fun.Sqrt(radius.Square() - shortestDistance.Square()) / Direction.Length); var t1 = t - s; // first hit of Cylinder shell var t2 = t + s; // second hit of Cylinder shell if (t1 > tmin && t1 < tmax) tmin = t1; if (t2 < tmax && t2 > tmin) tmax = t2; hit.T = t1; hit.Point = GetPointOnRay(t1); // check if found point is outside of Cylinder Caps var bottomPlane = new __plane3t__(-axisDir, p0); var topPlane = new __plane3t__(axisDir, p1); var heightBottom = bottomPlane.Height(hit.Point); var heightTop = topPlane.Height(hit.Point); // t1 lies outside of caps => find closest cap hit if (heightBottom > 0 || heightTop > 0) { hit.T = tmax; // intersect with bottom Cylinder Cap var bottomHit = HitsPlane(bottomPlane, tmin, tmax, ref hit); // intersect with top Cylinder Cap var topHit = HitsPlane(topPlane, tmin, tmax, ref hit); // hit still close enough to cylinder axis? var distance = axis.__ray3t__.GetMinimalDistanceTo(hit.Point); if (distance <= radius && (bottomHit || topHit)) return true; } else return true; } hit.T = tmax; hit.Point = __v3t__.NaN; return false; } /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsCylinder(__v3t__ p0, __v3t__ p1, __ftype__ radius, ref __rayhit3t__ hit) => HitsCylinder(p0, p1, radius, 0, __ftype__.MaxValue, ref hit); public readonly bool HitsCylinder(__v3t__ p0, __v3t__ p1, __ftype__ radius, __ftype__ tmin, __ftype__ tmax, out __ftype__ t) { var axis = new __line3t__(p0, p1); var axisDir = axis.Direction.Normalized; // Vector Cyl.P0 -> Ray.Origin var op = Origin - p0; // normal RayDirection - CylinderAxis var normal = Direction.Cross(axisDir); var unitNormal = normal.Normalized; // normal (Vec Cyl.P0 -> Ray.Origin) - CylinderAxis var normal2 = op.Cross(axisDir); t = -normal2.Dot(unitNormal) / normal.Length; // between entire rays (caps are ignored) var shortestDistance = Fun.Abs(op.Dot(unitNormal)); if (shortestDistance <= radius) { var s = Fun.Abs(Fun.Sqrt(radius.Square() - shortestDistance.Square()) / Direction.Length); var t1 = t - s; // first hit of Cylinder shell var t2 = t + s; // second hit of Cylinder shell if (t1 > tmin && t1 < tmax) tmin = t1; if (t2 < tmax && t2 > tmin) tmax = t2; t = t1; var point = GetPointOnRay(t1); // check if found point is outside of Cylinder Caps var bottomPlane = new __plane3t__(-axisDir, p0); var topPlane = new __plane3t__(axisDir, p1); var heightBottom = bottomPlane.Height(point); var heightTop = topPlane.Height(point); // t1 lies outside of caps => find closest cap hit if (heightBottom > 0 || heightTop > 0) { // intersect with bottom Cylinder Cap var bottomHit = HitsCircle(p0, -axisDir, radius, tmin, tmax, out t); // intersect with top Cylinder Cap var topHit = HitsCircle(p1, axisDir, radius, tmin, tmax, out __ftype__ ttop); if (topHit) { if (bottomHit) { if (ttop.Abs() < t) t = ttop; } else t = ttop; } return topHit || bottomHit; } else return true; } t = __ftype__.NaN; return false; } /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool HitsCylinder(__v3t__ p0, __v3t__ p1, __ftype__ radius, out __ftype__ t) => HitsCylinder(p0, p1, radius, 0, __ftype__.MaxValue, out t); /// /// Returns true if the ray intersects with the primitive. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__cylinder3t__ cylinder, __ftype__ tmin, __ftype__ tmax, ref __rayhit3t__ hit) => Hits(cylinder, tmin, tmax, 0, ref hit); /// /// Returns true if the ray intersects with the primitive. /// public readonly bool Hits(__cylinder3t__ cylinder, __ftype__ tmin, __ftype__ tmax, __ftype__ distanceScale, ref __rayhit3t__ hit) { var axisDir = cylinder.Axis.Direction.Normalized; // Vector Cyl.P0 -> Ray.Origin var op = Origin - cylinder.P0; // normal RayDirection - CylinderAxis var normal = Direction.Cross(axisDir); var unitNormal = normal.Normalized; // normal (Vec Cyl.P0 -> Ray.Origin) - CylinderAxis var normal2 = op.Cross(axisDir); var t = -normal2.Dot(unitNormal) / normal.Length; var radius = cylinder.Radius; if (distanceScale != 0) { // cylinder gets bigger, the further away it is var pnt = GetPointOnRay(t); var dis = Vec.Distance(pnt, this.Origin); radius = ((cylinder.Radius / distanceScale) * dis) * 2; } // between enitre rays (caps are ignored) var shortestDistance = Fun.Abs(op.Dot(unitNormal)); if (shortestDistance <= radius) { var s = Fun.Abs(Fun.Sqrt(radius.Square() - shortestDistance.Square()) / Direction.Length); var t1 = t - s; // first hit of Cylinder shell var t2 = t + s; // second hit of Cylinder shell if (t1 > tmin && t1 < tmax) tmin = t1; if (t2 < tmax && t2 > tmin) tmax = t2; hit.T = t1; hit.Point = GetPointOnRay(t1); // check if found point is outside of Cylinder Caps var bottomPlane = new __plane3t__(cylinder.Circle0.Normal, cylinder.Circle0.Center); var topPlane = new __plane3t__(cylinder.Circle1.Normal, cylinder.Circle1.Center); var heightBottom = bottomPlane.Height(hit.Point); var heightTop = topPlane.Height(hit.Point); // t1 lies outside of caps => find closest cap hit if (heightBottom > 0 || heightTop > 0) { hit.T = tmax; // intersect with bottom Cylinder Cap var bottomHit = HitsPlane(bottomPlane, tmin, tmax, ref hit); // intersect with top Cylinder Cap var topHit = HitsPlane(topPlane, tmin, tmax, ref hit); // hit still close enough to cylinder axis? var distance = cylinder.Axis.__ray3t__.GetMinimalDistanceTo(hit.Point); if (distance <= radius && (bottomHit || topHit)) return true; } else return true; } hit.T = tmax; hit.Point = __v3t__.NaN; return false; } /// /// Returns true if the ray intersects with the primitive. A hit with this /// overload is considered for t in [0, __ftype__.MaxValue]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Hits(__cylinder3t__ cylinder, ref __rayhit3t__ hit) => Hits(cylinder, 0, __ftype__.MaxValue, ref hit); #endregion #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__ray3t__ a, __ray3t__ b) => (a.Origin == b.Origin) && (a.Direction == b.Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__ray3t__ a, __ray3t__ b) => !((a.Origin == b.Origin) && (a.Direction == b.Direction)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int LexicalCompare(__ray3t__ other) { var cmp = Origin.LexicalCompare(other.Origin); if (cmp != 0) return cmp; return Direction.LexicalCompare(other.Direction); } #endregion #region Overrides /// /// Calculates Hash-code of the given ray. /// /// Hash-code. public override readonly int GetHashCode() => HashCode.GetCombined(Origin, Direction); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__ray3t__ other) => Origin.Equals(other.Origin) && Direction.Equals(other.Direction); public override readonly bool Equals(object other) => (other is __ray3t__ o) ? Equals(o) : false; public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Origin, Direction); public static __ray3t__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __ray3t__(__v3t__.Parse(x[0]), __v3t__.Parse(x[1])); } #endregion #region __iboundingbox__ public readonly __box3t__ BoundingBox3__tc__ => __box3t__.FromPoints(Origin, Direction + Origin); #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __ray3t__ a, __ray3t__ b, __ftype__ tolerance) => ApproximateEquals(a.Origin, b.Origin, tolerance) && ApproximateEquals(a.Direction, b.Direction, tolerance); /// /// Returns whether the given are equal within /// Constant<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __ray3t__ a, __ray3t__ b) => ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } #endregion #region __rayhit3t__ /// /// A ray hit represents the hit of a ray on a primitive object such as /// a triangle. It stores the ray parameter of the hit, the hit point, /// the hit point's coordinates, and a flag indicating if the backside /// of the primitive was hit. Optionally the part field can be used to /// store which part of a multi-part object was hit. If no multi-part /// objects are used, this field remains 0. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public struct __rayhit3t__ { [DataMember] public __ftype__ T; [DataMember] public __v3t__ Point; [DataMember] public V2d Coord; [DataMember] public bool BackSide; [DataMember] public int Part; #region Constructor public __rayhit3t__(__ftype__ tMax) { T = tMax; Point = __v3t__.NaN; Coord = V2d.NaN; BackSide = false; Part = 0; } #endregion #region Constants public static readonly __rayhit3t__ MaxRange = new __rayhit3t__(__ftype__.MaxValue); #endregion } #endregion #region Fast__ray3t__ /// /// A fast ray contains a ray and a number of precomputed flags and /// fields for fast intersection computation with bounding boxes and /// other axis-aligned sturctures such as kd-Trees. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public readonly struct Fast__ray3t__ { [DataMember] public readonly __ray3t__ Ray; [DataMember] public readonly DirFlags DirFlags; [DataMember] public readonly __v3t__ InvDir; #region Constructors public Fast__ray3t__(__ray3t__ ray) { Ray = ray; DirFlags = ray.Direction.DirFlags(); InvDir = 1 / ray.Direction; } public Fast__ray3t__(__v3t__ origin, __v3t__ direction) : this(new __ray3t__(origin, direction)) { } #endregion #region Ray Arithmetics public readonly bool Intersects( __box3t__ box, ref __ftype__ tmin, ref __ftype__ tmax ) { var dirFlags = DirFlags; if ((dirFlags & DirFlags.PositiveX) != 0) { { __ftype__ t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } { __ftype__ t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeX) != 0) { { __ftype__ t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } { __ftype__ t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to X-plane { if (Ray.Origin.X < box.Min.X || Ray.Origin.X > box.Max.X) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { { __ftype__ t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } { __ftype__ t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeY) != 0) { { __ftype__ t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } { __ftype__ t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to Y-plane { if (Ray.Origin.Y < box.Min.Y || Ray.Origin.Y > box.Max.Y) return false; } if ((dirFlags & DirFlags.PositiveZ) != 0) { { __ftype__ t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) tmax = t; } { __ftype__ t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeZ) != 0) { { __ftype__ t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) tmax = t; } { __ftype__ t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to Z-plane { if (Ray.Origin.Z < box.Min.Z || Ray.Origin.Z > box.Max.Z) return false; } if (tmin > tmax) return false; return true; } /// /// This variant of the intersection method only tests with the /// faces of the box indicated by the supplied boxFlags. /// public readonly bool Intersects( __box3t__ box, Box.Flags boxFlags, ref __ftype__ tmin, ref __ftype__ tmax ) { var dirFlags = DirFlags; if ((dirFlags & DirFlags.PositiveX) != 0) { if ((boxFlags & Box.Flags.MaxX) != 0) { __ftype__ t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MinX) != 0) { __ftype__ t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeX) != 0) { if ((boxFlags & Box.Flags.MinX) != 0) { __ftype__ t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MaxX) != 0) { __ftype__ t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to X-plane { if ((boxFlags & Box.Flags.MinX) != 0 && (Ray.Origin.X < box.Min.X) || (boxFlags & Box.Flags.MaxX) != 0 && (Ray.Origin.X > box.Max.X)) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { if ((boxFlags & Box.Flags.MaxY) != 0) { __ftype__ t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MinY) != 0) { __ftype__ t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeY) != 0) { if ((boxFlags & Box.Flags.MinY) != 0) { __ftype__ t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MaxY) != 0) { __ftype__ t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to Y-plane { if ((boxFlags & Box.Flags.MinY) != 0 && (Ray.Origin.Y < box.Min.Y) || (boxFlags & Box.Flags.MaxY) != 0 && (Ray.Origin.Y > box.Max.Y)) return false; } if ((dirFlags & DirFlags.PositiveZ) != 0) { if ((boxFlags & Box.Flags.MaxZ) != 0) { __ftype__ t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MinZ) != 0) { __ftype__ t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else if ((dirFlags & DirFlags.NegativeZ) != 0) { if ((boxFlags & Box.Flags.MinZ) != 0) { __ftype__ t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) tmax = t; } if ((boxFlags & Box.Flags.MaxZ) != 0) { __ftype__ t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) tmin = t; } } else // ray parallel to Z-plane { if ((boxFlags & Box.Flags.MinZ) != 0 && (Ray.Origin.Z < box.Min.Z) || (boxFlags & Box.Flags.MaxZ) != 0 && (Ray.Origin.Z > box.Max.Z)) return false; } if (tmin > tmax) return false; return true; } /// /// This variant of the intersection method returns the affected /// planes of the box if the box was hit. /// public readonly bool Intersects( __box3t__ box, ref __ftype__ tmin, ref __ftype__ tmax, out Box.Flags tminFlags, out Box.Flags tmaxFlags ) { var dirFlags = DirFlags; tminFlags = Box.Flags.None; tmaxFlags = Box.Flags.None; if ((dirFlags & DirFlags.PositiveX) != 0) { { __ftype__ t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxX; } } { __ftype__ t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinX; } } } else if ((dirFlags & DirFlags.NegativeX) != 0) { { __ftype__ t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinX; } } { __ftype__ t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxX; } } } else // ray parallel to X-plane { if (Ray.Origin.X < box.Min.X || Ray.Origin.X > box.Max.X) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { { __ftype__ t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxY; } } { __ftype__ t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinY; } } } else if ((dirFlags & DirFlags.NegativeY) != 0) { { __ftype__ t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinY; } } { __ftype__ t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxY; } } } else // ray parallel to Y-plane { if (Ray.Origin.Y < box.Min.Y || Ray.Origin.Y > box.Max.Y) return false; } if ((dirFlags & DirFlags.PositiveZ) != 0) { { __ftype__ t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxZ; } } { __ftype__ t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinZ; } } } else if ((dirFlags & DirFlags.NegativeZ) != 0) { { __ftype__ t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinZ; } } { __ftype__ t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxZ; } } } else // ray parallel to Z-plane { if (Ray.Origin.Z < box.Min.Z || Ray.Origin.Z > box.Max.Z) return false; } if (tmin > tmax) return false; return true; } /// /// This variant of the intersection method only tests with the /// faces of the box indicated by the supplied boxFlags and /// returns the affected planes of the box if the box was hit. /// public readonly bool Intersects( __box3t__ box, Box.Flags boxFlags, ref __ftype__ tmin, ref __ftype__ tmax, out Box.Flags tminFlags, out Box.Flags tmaxFlags ) { var dirFlags = DirFlags; tminFlags = Box.Flags.None; tmaxFlags = Box.Flags.None; if ((dirFlags & DirFlags.PositiveX) != 0) { if ((boxFlags & Box.Flags.MaxX) != 0) { __ftype__ t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxX; } } if ((boxFlags & Box.Flags.MinX) != 0) { __ftype__ t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinX; } } } else if ((dirFlags & DirFlags.NegativeX) != 0) { if ((boxFlags & Box.Flags.MinX) != 0) { __ftype__ t = (box.Min.X - Ray.Origin.X) * InvDir.X; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinX; } } if ((boxFlags & Box.Flags.MaxX) != 0) { __ftype__ t = (box.Max.X - Ray.Origin.X) * InvDir.X; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxX; } } } else // ray parallel to X-plane { if ((boxFlags & Box.Flags.MinX) != 0 && (Ray.Origin.X < box.Min.X) || (boxFlags & Box.Flags.MaxX) != 0 && (Ray.Origin.X > box.Max.X)) return false; } if ((dirFlags & DirFlags.PositiveY) != 0) { if ((boxFlags & Box.Flags.MaxY) != 0) { __ftype__ t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxY; } } if ((boxFlags & Box.Flags.MinY) != 0) { __ftype__ t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinY; } } } else if ((dirFlags & DirFlags.NegativeY) != 0) { if ((boxFlags & Box.Flags.MinY) != 0) { __ftype__ t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinY; } } if ((boxFlags & Box.Flags.MaxY) != 0) { __ftype__ t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxY; } } } else // ray parallel to Y-plane { if ((boxFlags & Box.Flags.MinY) != 0 && (Ray.Origin.Y < box.Min.Y) || (boxFlags & Box.Flags.MaxY) != 0 && (Ray.Origin.Y > box.Max.Y)) return false; } if ((dirFlags & DirFlags.PositiveZ) != 0) { if ((boxFlags & Box.Flags.MaxZ) != 0) { __ftype__ t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MaxZ; } } if ((boxFlags & Box.Flags.MinZ) != 0) { __ftype__ t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MinZ; } } } else if ((dirFlags & DirFlags.NegativeZ) != 0) { if ((boxFlags & Box.Flags.MinZ) != 0) { __ftype__ t = (box.Min.Z - Ray.Origin.Z) * InvDir.Z; if (t <= tmin) return false; if (t < tmax) { tmax = t; tmaxFlags = Box.Flags.MinZ; } } if ((boxFlags & Box.Flags.MaxZ) != 0) { __ftype__ t = (box.Max.Z - Ray.Origin.Z) * InvDir.Z; if (t >= tmax) return false; if (t > tmin) { tmin = t; tminFlags = Box.Flags.MaxZ; } } } else // ray parallel to Z-plane { if ((boxFlags & Box.Flags.MinZ) != 0 && (Ray.Origin.Z < box.Min.Z) || (boxFlags & Box.Flags.MaxZ) != 0 && (Ray.Origin.Z > box.Max.Z)) return false; } if (tmin > tmax) return false; return true; } #endregion } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Sphere/Sphere3_auto.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Sphere3f /// /// A three dimensional sphere represented by center and radius. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Sphere3f : IEquatable, IBoundingBox3f, IValidity { [DataMember] public V3f Center; [DataMember] public float Radius; #region Constructors /// /// Initializes a new instance of the class using center and radius values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Sphere3f(V3f center, float radius) { Center = center; Radius = radius; } /// /// Creates a sphere from its center, and a point on its surface. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Sphere3f(V3f center, V3f pointOnSurface) { Center = center; Radius = (pointOnSurface - center).Length; } /// /// Uses the first 2 points in the sequence as the /// sphere's center and a point on the sphere's surface. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Sphere3f(IEnumerable points) { var va = points.TakeToArray(2); Center = va[0]; Radius = (va[1] - va[0]).Length; } /// /// Initializes a new instance of the class using values from another sphere instance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Sphere3f(Sphere3f sphere) { Center = sphere.Center; Radius = sphere.Radius; } /// /// Initializes a new instance of the class using values from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Sphere3f(Sphere3d sphere) { Center = (V3f)sphere.Center; Radius = (float)sphere.Radius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Sphere3f(Sphere3d s) => new Sphere3f(s); #endregion #region Static Factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Sphere3f FromRadius(float radius) => new Sphere3f(V3f.Zero, radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Sphere3f FromCenterAndRadius(V3f center, float radius) => new Sphere3f(center, radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Sphere3f FromPoints(IEnumerable points) => new Sphere3f(points); #endregion #region Properties public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius < 0.0; } public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius >= 0.0; } public readonly float RadiusSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius * Radius; } public readonly float SurfaceArea { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (4 * RadiusSquared * ConstantF.Pi); } public readonly float Volume { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (4.0f / 3.0f) * ConstantF.Pi * Radius * Radius * Radius; } #endregion #region Constants /// /// Sphere at origin with radius 0. /// public static Sphere3f Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Sphere3f(V3f.Zero, 0); } /// /// Sphere at origin with radius 1. /// public static Sphere3f Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Sphere3f(V3f.Zero, 1); } /// /// Sphere at NaN with radius -1. /// public static Sphere3f Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Sphere3f(V3f.NaN, -1); } #endregion #region Comparison operators /// /// Tests whether two specified spheres are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Sphere3f a, Sphere3f b) => (a.Center == b.Center) && (a.Radius == b.Radius); /// /// Tests whether two specified spheres are not equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Sphere3f a, Sphere3f b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() => HashCode.GetCombined(Center, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Sphere3f other) => Center.Equals(other.Center) && Radius.Equals(other.Radius); public override readonly bool Equals(object other) => (other is Sphere3f o) ? Equals(o) : false; /// /// Writes a sphere to String. /// /// String representing the sphere. public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Center, Radius); public static Sphere3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Sphere3f(V3f.Parse(x[0]), float.Parse(x[1], CultureInfo.InvariantCulture)); } #endregion #region IBoundingBox3f Members public readonly Box3f BoundingBox3f { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Box3f(Center - Radius, Center + Radius); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Sphere3f a, Sphere3f b, float tolerance) => ApproximateEquals(a.Center, b.Center, tolerance) && ApproximateEquals(a.Radius, b.Radius, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Sphere3f a, Sphere3f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Sphere3d /// /// A three dimensional sphere represented by center and radius. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Sphere3d : IEquatable, IBoundingBox3d, IValidity { [DataMember] public V3d Center; [DataMember] public double Radius; #region Constructors /// /// Initializes a new instance of the class using center and radius values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Sphere3d(V3d center, double radius) { Center = center; Radius = radius; } /// /// Creates a sphere from its center, and a point on its surface. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Sphere3d(V3d center, V3d pointOnSurface) { Center = center; Radius = (pointOnSurface - center).Length; } /// /// Uses the first 2 points in the sequence as the /// sphere's center and a point on the sphere's surface. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Sphere3d(IEnumerable points) { var va = points.TakeToArray(2); Center = va[0]; Radius = (va[1] - va[0]).Length; } /// /// Initializes a new instance of the class using values from another sphere instance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Sphere3d(Sphere3d sphere) { Center = sphere.Center; Radius = sphere.Radius; } /// /// Initializes a new instance of the class using values from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Sphere3d(Sphere3f sphere) { Center = (V3d)sphere.Center; Radius = (double)sphere.Radius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Sphere3d(Sphere3f s) => new Sphere3d(s); #endregion #region Static Factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Sphere3d FromRadius(double radius) => new Sphere3d(V3d.Zero, radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Sphere3d FromCenterAndRadius(V3d center, double radius) => new Sphere3d(center, radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Sphere3d FromPoints(IEnumerable points) => new Sphere3d(points); #endregion #region Properties public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius < 0.0; } public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius >= 0.0; } public readonly double RadiusSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius * Radius; } public readonly double SurfaceArea { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (4 * RadiusSquared * Constant.Pi); } public readonly double Volume { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (4.0 / 3.0) * Constant.Pi * Radius * Radius * Radius; } #endregion #region Constants /// /// Sphere at origin with radius 0. /// public static Sphere3d Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Sphere3d(V3d.Zero, 0); } /// /// Sphere at origin with radius 1. /// public static Sphere3d Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Sphere3d(V3d.Zero, 1); } /// /// Sphere at NaN with radius -1. /// public static Sphere3d Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Sphere3d(V3d.NaN, -1); } #endregion #region Comparison operators /// /// Tests whether two specified spheres are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Sphere3d a, Sphere3d b) => (a.Center == b.Center) && (a.Radius == b.Radius); /// /// Tests whether two specified spheres are not equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Sphere3d a, Sphere3d b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() => HashCode.GetCombined(Center, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Sphere3d other) => Center.Equals(other.Center) && Radius.Equals(other.Radius); public override readonly bool Equals(object other) => (other is Sphere3d o) ? Equals(o) : false; /// /// Writes a sphere to String. /// /// String representing the sphere. public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Center, Radius); public static Sphere3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Sphere3d(V3d.Parse(x[0]), double.Parse(x[1], CultureInfo.InvariantCulture)); } #endregion #region IBoundingBox3d Members public readonly Box3d BoundingBox3d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Box3d(Center - Radius, Center + Radius); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Sphere3d a, Sphere3d b, double tolerance) => ApproximateEquals(a.Center, b.Center, tolerance) && ApproximateEquals(a.Radius, b.Radius, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Sphere3d a, Sphere3d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Sphere/Sphere3_template.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Sphere3" + tc; //# var type2 = "Sphere3" + tc2; //# var v3t = "V3" + tc; //# var box3t = "Box3" + tc; //# var iboundingbox = "IBoundingBox3" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var fourbythree = isDouble ? "(4.0 / 3.0)" : "(4.0f / 3.0f)"; //# var pi = isDouble ? "Constant.Pi" : "ConstantF.Pi"; #region __type__ /// /// A three dimensional sphere represented by center and radius. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__>, __iboundingbox__, IValidity { [DataMember] public __v3t__ Center; [DataMember] public __ftype__ Radius; #region Constructors /// /// Initializes a new instance of the class using center and radius values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__v3t__ center, __ftype__ radius) { Center = center; Radius = radius; } /// /// Creates a sphere from its center, and a point on its surface. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__v3t__ center, __v3t__ pointOnSurface) { Center = center; Radius = (pointOnSurface - center).Length; } /// /// Uses the first 2 points in the sequence as the /// sphere's center and a point on the sphere's surface. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(IEnumerable<__v3t__> points) { var va = points.TakeToArray(2); Center = va[0]; Radius = (va[1] - va[0]).Length; } /// /// Initializes a new instance of the class using values from another sphere instance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ sphere) { Center = sphere.Center; Radius = sphere.Radius; } /// /// Initializes a new instance of the class using values from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ sphere) { Center = (__v3t__)sphere.Center; Radius = (__ftype__)sphere.Radius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type__(__type2__ s) => new __type__(s); #endregion #region Static Factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromRadius(__ftype__ radius) => new __type__(__v3t__.Zero, radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromCenterAndRadius(__v3t__ center, __ftype__ radius) => new __type__(center, radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromPoints(IEnumerable<__v3t__> points) => new __type__(points); #endregion #region Properties public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius < 0.0; } public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius >= 0.0; } public readonly __ftype__ RadiusSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Radius * Radius; } public readonly __ftype__ SurfaceArea { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (4 * RadiusSquared * __pi__); } public readonly __ftype__ Volume { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => __fourbythree__ * __pi__ * Radius * Radius * Radius; } #endregion #region Constants /// /// Sphere at origin with radius 0. /// public static __type__ Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(__v3t__.Zero, 0); } /// /// Sphere at origin with radius 1. /// public static __type__ Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(__v3t__.Zero, 1); } /// /// Sphere at NaN with radius -1. /// public static __type__ Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(__v3t__.NaN, -1); } #endregion #region Comparison operators /// /// Tests whether two specified spheres are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ a, __type__ b) => (a.Center == b.Center) && (a.Radius == b.Radius); /// /// Tests whether two specified spheres are not equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ a, __type__ b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() => HashCode.GetCombined(Center, Radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => Center.Equals(other.Center) && Radius.Equals(other.Radius); public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; /// /// Writes a sphere to String. /// /// String representing the sphere. public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Center, Radius); public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__(__v3t__.Parse(x[0]), __ftype__.Parse(x[1], CultureInfo.InvariantCulture)); } #endregion #region __iboundingbox__ Members public readonly __box3t__ BoundingBox3__tc__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __box3t__(Center - Radius, Center + Radius); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b, __ftype__ tolerance) => ApproximateEquals(a.Center, b.Center, tolerance) && ApproximateEquals(a.Radius, b.Radius, tolerance); /// /// Returns whether the given are equal within /// Constant<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b) => ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Torus/Torus3_auto.cs ================================================ using System; using System.Globalization; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Torus3f [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Torus3f : IEquatable, IBoundingBox3f { [DataMember] public V3f Position; [DataMember] public V3f Direction; [DataMember] public float MajorRadius; [DataMember] public float MinorRadius; #region Constructor public Torus3f(V3f position, V3f direction, float majorRadius, float minorRadius) { Position = position; Direction = direction; MinorRadius = minorRadius; MajorRadius = majorRadius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Torus3f(Torus3f o) { Position = o.Position; Direction = o.Direction; MinorRadius = o.MinorRadius; MajorRadius = o.MajorRadius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Torus3f(Torus3d o) { Position = (V3f)o.Position; Direction = (V3f)o.Direction; MinorRadius = (float)o.MinorRadius; MajorRadius = (float)o.MajorRadius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Torus3f(Torus3d o) => new Torus3f(o); #endregion #region Properties public readonly Circle3f MajorCircle { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => GetMajorCircle(); } public readonly float Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => 4 * ConstantF.PiSquared * MajorRadius * MinorRadius; } public readonly float Volume { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => 2 * ConstantF.PiSquared * MajorRadius * MinorRadius * MinorRadius; } #endregion #region Operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Circle3f GetMajorCircle() => new Circle3f(Position, Direction, MajorRadius); public readonly Circle3f GetMinorCircle(float angle) { var c = GetMajorCircle(); var p = c.GetPoint(angle); var dir = (p - Position).Normalized.Cross(Direction).Normalized; return new Circle3f(p, dir, MinorRadius); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float GetMinimalDistance(V3f p) => GetMinimalDistance(p, Position, Direction, MajorRadius, MinorRadius); public static float GetMinimalDistance(V3f p, V3f position, V3f direction, float majorRadius, float minorRadius) { var plane = new Plane3f(direction, position); var planePoint = p.GetClosestPointOn(plane); var distanceOnPlane = (Vec.Distance(planePoint, position) - majorRadius).Abs(); var distanceToCircle = (Vec.DistanceSquared(planePoint, p) + distanceOnPlane.Square()).Sqrt(); return (distanceToCircle - minorRadius).Abs(); } #endregion #region Comparison operators /// /// Tests whether two specified spheres are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Torus3f a, Torus3f b) => (a.Position == b.Position) && (a.Direction == b.Direction) && (a.MajorRadius == b.MajorRadius) && (a.MinorRadius == b.MinorRadius); /// /// Tests whether two specified spheres are not equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Torus3f a, Torus3f b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Position, Direction, MajorRadius, MinorRadius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Torus3f other) => Position.Equals(other.Position) && Direction.Equals(other.Direction) && MajorRadius.Equals(other.MajorRadius) && MinorRadius.Equals(other.MinorRadius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Torus3f o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}, {3}]", Position, Direction, MajorRadius, MinorRadius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Torus3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Torus3f( V3f.Parse(x[0]), V3f.Parse(x[1]), float.Parse(x[2], CultureInfo.InvariantCulture), float.Parse(x[3], CultureInfo.InvariantCulture) ); } #endregion #region IBoundingBox3f Members readonly Box3f IBoundingBox3f.BoundingBox3f { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => GetMajorCircle().BoundingBox3f.EnlargedBy(MinorRadius); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Torus3f a, Torus3f b, float tolerance) => ApproximateEquals(a.Position, b.Position, tolerance) && ApproximateEquals(a.Direction, b.Direction, tolerance) && ApproximateEquals(a.MajorRadius, b.MajorRadius, tolerance) && ApproximateEquals(a.MinorRadius, b.MinorRadius, tolerance); /// /// Returns whether the given are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Torus3f a, Torus3f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Torus3d [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Torus3d : IEquatable, IBoundingBox3d { [DataMember] public V3d Position; [DataMember] public V3d Direction; [DataMember] public double MajorRadius; [DataMember] public double MinorRadius; #region Constructor public Torus3d(V3d position, V3d direction, double majorRadius, double minorRadius) { Position = position; Direction = direction; MinorRadius = minorRadius; MajorRadius = majorRadius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Torus3d(Torus3d o) { Position = o.Position; Direction = o.Direction; MinorRadius = o.MinorRadius; MajorRadius = o.MajorRadius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Torus3d(Torus3f o) { Position = (V3d)o.Position; Direction = (V3d)o.Direction; MinorRadius = (double)o.MinorRadius; MajorRadius = (double)o.MajorRadius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Torus3d(Torus3f o) => new Torus3d(o); #endregion #region Properties public readonly Circle3d MajorCircle { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => GetMajorCircle(); } public readonly double Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => 4 * Constant.PiSquared * MajorRadius * MinorRadius; } public readonly double Volume { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => 2 * Constant.PiSquared * MajorRadius * MinorRadius * MinorRadius; } #endregion #region Operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Circle3d GetMajorCircle() => new Circle3d(Position, Direction, MajorRadius); public readonly Circle3d GetMinorCircle(double angle) { var c = GetMajorCircle(); var p = c.GetPoint(angle); var dir = (p - Position).Normalized.Cross(Direction).Normalized; return new Circle3d(p, dir, MinorRadius); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double GetMinimalDistance(V3d p) => GetMinimalDistance(p, Position, Direction, MajorRadius, MinorRadius); public static double GetMinimalDistance(V3d p, V3d position, V3d direction, double majorRadius, double minorRadius) { var plane = new Plane3d(direction, position); var planePoint = p.GetClosestPointOn(plane); var distanceOnPlane = (Vec.Distance(planePoint, position) - majorRadius).Abs(); var distanceToCircle = (Vec.DistanceSquared(planePoint, p) + distanceOnPlane.Square()).Sqrt(); return (distanceToCircle - minorRadius).Abs(); } #endregion #region Comparison operators /// /// Tests whether two specified spheres are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Torus3d a, Torus3d b) => (a.Position == b.Position) && (a.Direction == b.Direction) && (a.MajorRadius == b.MajorRadius) && (a.MinorRadius == b.MinorRadius); /// /// Tests whether two specified spheres are not equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Torus3d a, Torus3d b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Position, Direction, MajorRadius, MinorRadius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Torus3d other) => Position.Equals(other.Position) && Direction.Equals(other.Direction) && MajorRadius.Equals(other.MajorRadius) && MinorRadius.Equals(other.MinorRadius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is Torus3d o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}, {3}]", Position, Direction, MajorRadius, MinorRadius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Torus3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Torus3d( V3d.Parse(x[0]), V3d.Parse(x[1]), double.Parse(x[2], CultureInfo.InvariantCulture), double.Parse(x[3], CultureInfo.InvariantCulture) ); } #endregion #region IBoundingBox3d Members readonly Box3d IBoundingBox3d.BoundingBox3d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => GetMajorCircle().BoundingBox3d.EnlargedBy(MinorRadius); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Torus3d a, Torus3d b, double tolerance) => ApproximateEquals(a.Position, b.Position, tolerance) && ApproximateEquals(a.Direction, b.Direction, tolerance) && ApproximateEquals(a.MajorRadius, b.MajorRadius, tolerance) && ApproximateEquals(a.MinorRadius, b.MinorRadius, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Torus3d a, Torus3d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Torus/Torus3_template.cs ================================================ using System; using System.Globalization; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Runtime.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Torus3" + tc; //# var type2 = "Torus3" + tc2; //# var v3t = "V3" + tc; //# var box3t = "Box3" + tc; //# var circle3t = "Circle3" + tc; //# var plane3t = "Plane3" + tc; //# var trafo3t = "Trafo3" + tc; //# var iboundingbox3t = "IBoundingBox3" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var dotnine = isDouble ? "0.9" : "0.9f"; //# var constant = isDouble ? "Constant" : "ConstantF"; #region __type__ [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__>, __iboundingbox3t__ { [DataMember] public __v3t__ Position; [DataMember] public __v3t__ Direction; [DataMember] public __ftype__ MajorRadius; [DataMember] public __ftype__ MinorRadius; #region Constructor public __type__(__v3t__ position, __v3t__ direction, __ftype__ majorRadius, __ftype__ minorRadius) { Position = position; Direction = direction; MinorRadius = minorRadius; MajorRadius = majorRadius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ o) { Position = o.Position; Direction = o.Direction; MinorRadius = o.MinorRadius; MajorRadius = o.MajorRadius; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ o) { Position = (__v3t__)o.Position; Direction = (__v3t__)o.Direction; MinorRadius = (__ftype__)o.MinorRadius; MajorRadius = (__ftype__)o.MajorRadius; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type__(__type2__ o) => new __type__(o); #endregion #region Properties public readonly __circle3t__ MajorCircle { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => GetMajorCircle(); } public readonly __ftype__ Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => 4 * __constant__.PiSquared * MajorRadius * MinorRadius; } public readonly __ftype__ Volume { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => 2 * __constant__.PiSquared * MajorRadius * MinorRadius * MinorRadius; } #endregion #region Operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __circle3t__ GetMajorCircle() => new __circle3t__(Position, Direction, MajorRadius); public readonly __circle3t__ GetMinorCircle(__ftype__ angle) { var c = GetMajorCircle(); var p = c.GetPoint(angle); var dir = (p - Position).Normalized.Cross(Direction).Normalized; return new __circle3t__(p, dir, MinorRadius); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__ GetMinimalDistance(__v3t__ p) => GetMinimalDistance(p, Position, Direction, MajorRadius, MinorRadius); public static __ftype__ GetMinimalDistance(__v3t__ p, __v3t__ position, __v3t__ direction, __ftype__ majorRadius, __ftype__ minorRadius) { var plane = new __plane3t__(direction, position); var planePoint = p.GetClosestPointOn(plane); var distanceOnPlane = (Vec.Distance(planePoint, position) - majorRadius).Abs(); var distanceToCircle = (Vec.DistanceSquared(planePoint, p) + distanceOnPlane.Square()).Sqrt(); return (distanceToCircle - minorRadius).Abs(); } #endregion #region Comparison operators /// /// Tests whether two specified spheres are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ a, __type__ b) => (a.Position == b.Position) && (a.Direction == b.Direction) && (a.MajorRadius == b.MajorRadius) && (a.MinorRadius == b.MinorRadius); /// /// Tests whether two specified spheres are not equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ a, __type__ b) => !(a == b); #endregion #region Overrides [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => HashCode.GetCombined(Position, Direction, MajorRadius, MinorRadius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => Position.Equals(other.Position) && Direction.Equals(other.Direction) && MajorRadius.Equals(other.MajorRadius) && MinorRadius.Equals(other.MinorRadius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}, {3}]", Position, Direction, MajorRadius, MinorRadius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__( __v3t__.Parse(x[0]), __v3t__.Parse(x[1]), __ftype__.Parse(x[2], CultureInfo.InvariantCulture), __ftype__.Parse(x[3], CultureInfo.InvariantCulture) ); } #endregion #region __iboundingbox3t__ Members readonly __box3t__ __iboundingbox3t__.BoundingBox3__tc__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => GetMajorCircle().BoundingBox3__tc__.EnlargedBy(MinorRadius); } #endregion } public static partial class Fun { /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b, __ftype__ tolerance) => ApproximateEquals(a.Position, b.Position, tolerance) && ApproximateEquals(a.Direction, b.Direction, tolerance) && ApproximateEquals(a.MajorRadius, b.MajorRadius, tolerance) && ApproximateEquals(a.MinorRadius, b.MinorRadius, tolerance); /// /// Returns whether the given are equal within /// Constant<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b) => ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Triangle/Triangle2_auto.cs ================================================ using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Triangle2f /// /// A two-dimensional triangle represented by its three points. /// public partial struct Triangle2f : IBoundingCircle2f { #region Geometric Properties /// /// Returns the area of the triangle. /// public readonly float Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.Area(this); } /// /// Returns whether the triangle is degenerated, i.e. its area is zero. /// public readonly bool IsDegenerated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.IsDegenerated(this); } /// /// Returns a negative value if the triangle has a /// counter-clockwise winding order, and a positive value if it has a clockwise winding-order. /// The magnitude is twice the area of the triangle. /// public readonly float WindingOrder { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.WindingOrder(this); } #endregion #region CircumCircle public readonly Circle2f CircumCircle { get { ComputeCircumCircleSquared(P0, P1, P2, out V2f center, out float radiusSquared); return new Circle2f(center, radiusSquared.Sqrt()); } } public readonly Circle2f CircumCircleSquared { get { ComputeCircumCircleSquared(P0, P1, P2, out V2f center, out float radiusSquared); return new Circle2f(center, radiusSquared); } } public static void ComputeCircumCircleSquared( V2f p0, V2f p1, V2f p2, out V2f center, out float radiusSquared) { float y01abs = Fun.Abs(p0.Y - p1.Y); float y12abs = Fun.Abs(p1.Y - p2.Y); if (y01abs < Constant.PositiveTinyValue && y12abs < Constant.PositiveTinyValue) { center = V2f.NaN; radiusSquared = -1; return; } float xc, yc; if (y01abs < Constant.PositiveTinyValue) { float m2 = (p1.X - p2.X) / (p2.Y - p1.Y); float m12x = 0.5f * (p1.X + p2.X); float m12y = 0.5f * (p1.Y + p2.Y); xc = 0.5f * (p1.X + p0.X); yc = m2 * (xc - m12x) + m12y; } else if (y12abs < Constant.PositiveTinyValue) { float m1 = (p0.X - p1.X) / (p1.Y - p0.Y); float m01x = 0.5f * (p0.X + p1.X); float m01y = 0.5f * (p0.Y + p1.Y); xc = 0.5f * (p2.X + p1.X); yc = m1 * (xc - m01x) + m01y; } else { float m1 = (p0.X - p1.X) / (p1.Y - p0.Y); float m2 = (p1.X - p2.X) / (p2.Y - p1.Y); float m01x = 0.5f * (p0.X + p1.X); float m01y = 0.5f * (p0.Y + p1.Y); float m12x = 0.5f * (p1.X + p2.X); float m12y = 0.5f * (p1.Y + p2.Y); float m12 = m1 - m2; if (Fun.Abs(m12) < Constant.PositiveTinyValue) { center = V2f.NaN; radiusSquared = -1; return; } xc = (m1 * m01x - m2 * m12x + m12y - m01y) / m12; if (y01abs > y12abs) { yc = m1 * (xc - m01x) + m01y; } else { yc = m2 * (xc - m12x) + m12y; } } center = new V2f(xc, yc); radiusSquared = Vec.DistanceSquared(p0, center); } #endregion #region IBoundingCircle2f Members public readonly Circle2f BoundingCircle2f { get { var edge01 = P1 - P0; var edge02 = P2 - P0; float dot0101 = Vec.Dot(edge01, edge01); float dot0102 = Vec.Dot(edge01, edge02); float dot0202 = Vec.Dot(edge02, edge02); float d = 2 * (dot0101 * dot0202 - dot0102 * dot0102); if (d.Abs() <= 1e-4f) return Circle2f.Invalid; float s = (dot0101 * dot0202 - dot0202 * dot0102) / d; float t = (dot0202 * dot0101 - dot0101 * dot0102) / d; var p = P0; var cir = new Circle2f(); if (s <= 0) cir.Center = 0.5f * (P0 + P2); else if (t <= 0) cir.Center = 0.5f * (P0 + P1); else if (s + t >= 1) { cir.Center = 0.5f * (P1 + P2); p = P1; } else cir.Center = P0 + s * edge01 + t * edge02; cir.Radius = (cir.Center - p).Length; return cir; } } #endregion } /// /// Contains static methods for triangles. /// public static partial class Triangle { #region Area /// /// Returns the area of the triangle defined by the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Area(V2f p0, V2f p1, V2f p2) => WindingOrder(p0, p1, p2).Abs() * 0.5f; /// /// Returns the area of the given triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Area(Triangle2f t) => Area(t.P0, t.P1, t.P2); #endregion #region IsDegenerated /// /// Returns whether the triangle defined by the give points is degenerated, i.e. its area is zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsDegenerated(V2f p0, V2f p1, V2f p2) => WindingOrder(p0, p1, p2).IsTiny(); /// /// Returns whether the given triangle is degenerated, i.e. its area is zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsDegenerated(Triangle2f t) => WindingOrder(t).IsTiny(); #endregion #region WindingOrder /// /// Returns a negative value if the triangle defined by the given points has a /// counter-clockwise winding order, and a positive value if it has a clockwise winding-order. /// The magnitude is twice the area of the triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float WindingOrder(V2f p0, V2f p1, V2f p2) => (p1.X - p0.X) * (p2.Y - p0.Y) - (p2.X - p0.X) * (p1.Y - p0.Y); /// /// Returns a negative value if the given triangle has a /// counter-clockwise winding order, and a positive value if it has a clockwise winding-order. /// The magnitude is twice the area of the triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float WindingOrder(Triangle2f t) => WindingOrder(t.P0, t.P1, t.P2); #endregion #region Distance /// /// Gets the distance between the closest point on the triangle [a, b, c] and the given query point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance(V2f a, V2f b, V2f c, V2f query) { var cp = query.GetClosestPointOnTriangle(a, b, c); return (cp - query).Length; } #endregion } #endregion #region Triangle2d /// /// A two-dimensional triangle represented by its three points. /// public partial struct Triangle2d : IBoundingCircle2d { #region Geometric Properties /// /// Returns the area of the triangle. /// public readonly double Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.Area(this); } /// /// Returns whether the triangle is degenerated, i.e. its area is zero. /// public readonly bool IsDegenerated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.IsDegenerated(this); } /// /// Returns a negative value if the triangle has a /// counter-clockwise winding order, and a positive value if it has a clockwise winding-order. /// The magnitude is twice the area of the triangle. /// public readonly double WindingOrder { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.WindingOrder(this); } #endregion #region CircumCircle public readonly Circle2d CircumCircle { get { ComputeCircumCircleSquared(P0, P1, P2, out V2d center, out double radiusSquared); return new Circle2d(center, radiusSquared.Sqrt()); } } public readonly Circle2d CircumCircleSquared { get { ComputeCircumCircleSquared(P0, P1, P2, out V2d center, out double radiusSquared); return new Circle2d(center, radiusSquared); } } public static void ComputeCircumCircleSquared( V2d p0, V2d p1, V2d p2, out V2d center, out double radiusSquared) { double y01abs = Fun.Abs(p0.Y - p1.Y); double y12abs = Fun.Abs(p1.Y - p2.Y); if (y01abs < Constant.PositiveTinyValue && y12abs < Constant.PositiveTinyValue) { center = V2d.NaN; radiusSquared = -1; return; } double xc, yc; if (y01abs < Constant.PositiveTinyValue) { double m2 = (p1.X - p2.X) / (p2.Y - p1.Y); double m12x = 0.5 * (p1.X + p2.X); double m12y = 0.5 * (p1.Y + p2.Y); xc = 0.5 * (p1.X + p0.X); yc = m2 * (xc - m12x) + m12y; } else if (y12abs < Constant.PositiveTinyValue) { double m1 = (p0.X - p1.X) / (p1.Y - p0.Y); double m01x = 0.5 * (p0.X + p1.X); double m01y = 0.5 * (p0.Y + p1.Y); xc = 0.5 * (p2.X + p1.X); yc = m1 * (xc - m01x) + m01y; } else { double m1 = (p0.X - p1.X) / (p1.Y - p0.Y); double m2 = (p1.X - p2.X) / (p2.Y - p1.Y); double m01x = 0.5 * (p0.X + p1.X); double m01y = 0.5 * (p0.Y + p1.Y); double m12x = 0.5 * (p1.X + p2.X); double m12y = 0.5 * (p1.Y + p2.Y); double m12 = m1 - m2; if (Fun.Abs(m12) < Constant.PositiveTinyValue) { center = V2d.NaN; radiusSquared = -1; return; } xc = (m1 * m01x - m2 * m12x + m12y - m01y) / m12; if (y01abs > y12abs) { yc = m1 * (xc - m01x) + m01y; } else { yc = m2 * (xc - m12x) + m12y; } } center = new V2d(xc, yc); radiusSquared = Vec.DistanceSquared(p0, center); } #endregion #region IBoundingCircle2d Members public readonly Circle2d BoundingCircle2d { get { var edge01 = P1 - P0; var edge02 = P2 - P0; double dot0101 = Vec.Dot(edge01, edge01); double dot0102 = Vec.Dot(edge01, edge02); double dot0202 = Vec.Dot(edge02, edge02); double d = 2 * (dot0101 * dot0202 - dot0102 * dot0102); if (d.Abs() <= 1e-6) return Circle2d.Invalid; double s = (dot0101 * dot0202 - dot0202 * dot0102) / d; double t = (dot0202 * dot0101 - dot0101 * dot0102) / d; var p = P0; var cir = new Circle2d(); if (s <= 0) cir.Center = 0.5 * (P0 + P2); else if (t <= 0) cir.Center = 0.5 * (P0 + P1); else if (s + t >= 1) { cir.Center = 0.5 * (P1 + P2); p = P1; } else cir.Center = P0 + s * edge01 + t * edge02; cir.Radius = (cir.Center - p).Length; return cir; } } #endregion } /// /// Contains static methods for triangles. /// public static partial class Triangle { #region Area /// /// Returns the area of the triangle defined by the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Area(V2d p0, V2d p1, V2d p2) => WindingOrder(p0, p1, p2).Abs() * 0.5; /// /// Returns the area of the given triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Area(Triangle2d t) => Area(t.P0, t.P1, t.P2); #endregion #region IsDegenerated /// /// Returns whether the triangle defined by the give points is degenerated, i.e. its area is zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsDegenerated(V2d p0, V2d p1, V2d p2) => WindingOrder(p0, p1, p2).IsTiny(); /// /// Returns whether the given triangle is degenerated, i.e. its area is zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsDegenerated(Triangle2d t) => WindingOrder(t).IsTiny(); #endregion #region WindingOrder /// /// Returns a negative value if the triangle defined by the given points has a /// counter-clockwise winding order, and a positive value if it has a clockwise winding-order. /// The magnitude is twice the area of the triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double WindingOrder(V2d p0, V2d p1, V2d p2) => (p1.X - p0.X) * (p2.Y - p0.Y) - (p2.X - p0.X) * (p1.Y - p0.Y); /// /// Returns a negative value if the given triangle has a /// counter-clockwise winding order, and a positive value if it has a clockwise winding-order. /// The magnitude is twice the area of the triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double WindingOrder(Triangle2d t) => WindingOrder(t.P0, t.P1, t.P2); #endregion #region Distance /// /// Gets the distance between the closest point on the triangle [a, b, c] and the given query point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(V2d a, V2d b, V2d c, V2d query) { var cp = query.GetClosestPointOnTriangle(a, b, c); return (cp - query).Length; } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Triangle/Triangle2_template.cs ================================================ using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Triangle2" + tc; //# var type2 = "Triangle2" + tc2; //# var v2t = "V2" + tc; //# var box2t = "Box2" + tc; //# var plane2t = "Plane2" + tc; //# var circle2t = "Circle2" + tc; //# var iboundingcircle2t = "IBoundingCircle2" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var pi = isDouble ? "Constant.Pi" : "ConstantF.Pi"; //# var eps = isDouble ? "1e-6" : "1e-4f"; #region __type__ /// /// A two-dimensional triangle represented by its three points. /// public partial struct __type__ : __iboundingcircle2t__ { #region Geometric Properties /// /// Returns the area of the triangle. /// public readonly __ftype__ Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.Area(this); } /// /// Returns whether the triangle is degenerated, i.e. its area is zero. /// public readonly bool IsDegenerated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.IsDegenerated(this); } /// /// Returns a negative value if the triangle has a /// counter-clockwise winding order, and a positive value if it has a clockwise winding-order. /// The magnitude is twice the area of the triangle. /// public readonly __ftype__ WindingOrder { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.WindingOrder(this); } #endregion #region CircumCircle public readonly __circle2t__ CircumCircle { get { ComputeCircumCircleSquared(P0, P1, P2, out __v2t__ center, out __ftype__ radiusSquared); return new __circle2t__(center, radiusSquared.Sqrt()); } } public readonly __circle2t__ CircumCircleSquared { get { ComputeCircumCircleSquared(P0, P1, P2, out __v2t__ center, out __ftype__ radiusSquared); return new __circle2t__(center, radiusSquared); } } public static void ComputeCircumCircleSquared( __v2t__ p0, __v2t__ p1, __v2t__ p2, out __v2t__ center, out __ftype__ radiusSquared) { __ftype__ y01abs = Fun.Abs(p0.Y - p1.Y); __ftype__ y12abs = Fun.Abs(p1.Y - p2.Y); if (y01abs < Constant<__ftype__>.PositiveTinyValue && y12abs < Constant<__ftype__>.PositiveTinyValue) { center = __v2t__.NaN; radiusSquared = -1; return; } __ftype__ xc, yc; if (y01abs < Constant<__ftype__>.PositiveTinyValue) { __ftype__ m2 = (p1.X - p2.X) / (p2.Y - p1.Y); __ftype__ m12x = __half__ * (p1.X + p2.X); __ftype__ m12y = __half__ * (p1.Y + p2.Y); xc = __half__ * (p1.X + p0.X); yc = m2 * (xc - m12x) + m12y; } else if (y12abs < Constant<__ftype__>.PositiveTinyValue) { __ftype__ m1 = (p0.X - p1.X) / (p1.Y - p0.Y); __ftype__ m01x = __half__ * (p0.X + p1.X); __ftype__ m01y = __half__ * (p0.Y + p1.Y); xc = __half__ * (p2.X + p1.X); yc = m1 * (xc - m01x) + m01y; } else { __ftype__ m1 = (p0.X - p1.X) / (p1.Y - p0.Y); __ftype__ m2 = (p1.X - p2.X) / (p2.Y - p1.Y); __ftype__ m01x = __half__ * (p0.X + p1.X); __ftype__ m01y = __half__ * (p0.Y + p1.Y); __ftype__ m12x = __half__ * (p1.X + p2.X); __ftype__ m12y = __half__ * (p1.Y + p2.Y); __ftype__ m12 = m1 - m2; if (Fun.Abs(m12) < Constant<__ftype__>.PositiveTinyValue) { center = __v2t__.NaN; radiusSquared = -1; return; } xc = (m1 * m01x - m2 * m12x + m12y - m01y) / m12; if (y01abs > y12abs) { yc = m1 * (xc - m01x) + m01y; } else { yc = m2 * (xc - m12x) + m12y; } } center = new __v2t__(xc, yc); radiusSquared = Vec.DistanceSquared(p0, center); } #endregion #region __iboundingcircle2t__ Members public readonly __circle2t__ BoundingCircle2__tc__ { get { var edge01 = P1 - P0; var edge02 = P2 - P0; __ftype__ dot0101 = Vec.Dot(edge01, edge01); __ftype__ dot0102 = Vec.Dot(edge01, edge02); __ftype__ dot0202 = Vec.Dot(edge02, edge02); __ftype__ d = 2 * (dot0101 * dot0202 - dot0102 * dot0102); if (d.Abs() <= __eps__) return __circle2t__.Invalid; __ftype__ s = (dot0101 * dot0202 - dot0202 * dot0102) / d; __ftype__ t = (dot0202 * dot0101 - dot0101 * dot0102) / d; var p = P0; var cir = new __circle2t__(); if (s <= 0) cir.Center = __half__ * (P0 + P2); else if (t <= 0) cir.Center = __half__ * (P0 + P1); else if (s + t >= 1) { cir.Center = __half__ * (P1 + P2); p = P1; } else cir.Center = P0 + s * edge01 + t * edge02; cir.Radius = (cir.Center - p).Length; return cir; } } #endregion } /// /// Contains static methods for triangles. /// public static partial class Triangle { #region Area /// /// Returns the area of the triangle defined by the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Area(__v2t__ p0, __v2t__ p1, __v2t__ p2) => WindingOrder(p0, p1, p2).Abs() * __half__; /// /// Returns the area of the given triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Area(__type__ t) => Area(t.P0, t.P1, t.P2); #endregion #region IsDegenerated /// /// Returns whether the triangle defined by the give points is degenerated, i.e. its area is zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsDegenerated(__v2t__ p0, __v2t__ p1, __v2t__ p2) => WindingOrder(p0, p1, p2).IsTiny(); /// /// Returns whether the given triangle is degenerated, i.e. its area is zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsDegenerated(__type__ t) => WindingOrder(t).IsTiny(); #endregion #region WindingOrder /// /// Returns a negative value if the triangle defined by the given points has a /// counter-clockwise winding order, and a positive value if it has a clockwise winding-order. /// The magnitude is twice the area of the triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ WindingOrder(__v2t__ p0, __v2t__ p1, __v2t__ p2) => (p1.X - p0.X) * (p2.Y - p0.Y) - (p2.X - p0.X) * (p1.Y - p0.Y); /// /// Returns a negative value if the given triangle has a /// counter-clockwise winding order, and a positive value if it has a clockwise winding-order. /// The magnitude is twice the area of the triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ WindingOrder(__type__ t) => WindingOrder(t.P0, t.P1, t.P2); #endregion #region Distance /// /// Gets the distance between the closest point on the triangle [a, b, c] and the given query point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Distance(__v2t__ a, __v2t__ b, __v2t__ c, __v2t__ query) { var cp = query.GetClosestPointOnTriangle(a, b, c); return (cp - query).Length; } #endregion } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Triangle/Triangle3_auto.cs ================================================ using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Triangle3f /// /// A three-dimensional triangle represented by its three points. /// public partial struct Triangle3f : IBoundingSphere3f { #region Geometric Properties /// /// Returns the area of the triangle. /// public readonly float Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.Area(this); } /// /// Returns whether the triangle is degenerated, i.e. its area is zero. /// public readonly bool IsDegenerated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.IsDegenerated(this); } /// /// Returns the normal of the triangle. /// public readonly V3f Normal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.Normal(this); } /// /// Returns the plane that contains the points of the triangle. /// public readonly Plane3f Plane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.Plane(this); } #endregion #region IBoundingSphere3f Members /// /// Returns the bounding sphere of the triangle. /// public readonly Sphere3f BoundingSphere3f { get { var edge01 = Edge01; var edge02 = Edge02; float dot0101 = Vec.Dot(edge01, edge01); float dot0102 = Vec.Dot(edge01, edge02); float dot0202 = Vec.Dot(edge02, edge02); float d = 2 * (dot0101 * dot0202 - dot0102 * dot0102); if (d.Abs() <= 1e-5f) return Sphere3f.Invalid; float s = (dot0101 * dot0202 - dot0202 * dot0102) / d; float t = (dot0202 * dot0101 - dot0101 * dot0102) / d; var p = P0; var sph = new Sphere3f(); if (s <= 0) sph.Center = 0.5f * (P0 + P2); else if (t <= 0) sph.Center = 0.5f * (P0 + P1); else if (s + t >= 1) { sph.Center = 0.5f * (P1 + P2); p = P1; } else sph.Center = P0 + s * edge01 + t * edge02; sph.Radius = (sph.Center - p).Length; return sph; } } #endregion } /// /// Contains static methods for triangles. /// public static partial class Triangle { #region Area /// /// Returns the area of the triangle defined by the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Area(V3f p0, V3f p1, V3f p2) => (p1 - p0).Cross(p2 - p0).Length * 0.5f; /// /// Returns the area of the given triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Area(Triangle3f t) => Area(t.P0, t.P1, t.P2); #endregion #region IsDegenerated /// /// Returns whether the triangle defined by the give points is degenerated, i.e. its area is zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsDegenerated(V3f p0, V3f p1, V3f p2) => (p1 - p0).Cross(p2 - p0).AllTiny; /// /// Returns whether the given triangle is degenerated, i.e. its area is zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsDegenerated(Triangle3f t) => IsDegenerated(t.P0, t.P1, t.P2); #endregion #region Normal /// /// Returns the normal of the triangle defined by the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Normal(V3f p0, V3f p1, V3f p2) => (p1 - p0).Cross(p2 - p0).Normalized; /// /// Returns the normal of the given triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Normal(Triangle3f t) => Normal(t.P0, t.P1, t.P2); #endregion #region Plane /// /// Returns the plane that contains the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Plane3f Plane(V3f p0, V3f p1, V3f p2) => new Plane3f(Normal(p0, p1, p2), p0); /// /// Returns the plane that contains the points of the given triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Plane3f Plane(Triangle3f t) => Plane(t.P0, t.P1, t.P2); #endregion #region SolidAngle /// /// Computes the solid angle for a planar triangle as seen from the origin. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float SolidAngle(Triangle3f t) => SolidAngle(t.P0, t.P1, t.P2); /// /// Computes the solid angle for a planar triangle as seen from the origin. /// /// Van Oosterom, A., and Strackee, J. (1983). /// The solid angle of a plane triangle. /// IEEE transactions on Biomedical Engineering, (2), 125-126. /// /// https://en.wikipedia.org/wiki/Solid_angle#Tetrahedron /// public static float SolidAngle(V3f va, V3f vb, V3f vc) { var ma = va.Length; var mb = vb.Length; var mc = vc.Length; var numerator = Fun.Abs(Vec.Dot(va, (Vec.Cross(vb, vc)))); var denom = ma * mb * mc + Vec.Dot(va, vb) * mc + Vec.Dot(va, vc) * mb + Vec.Dot(vb, vc) * ma; var halfSA = Fun.Atan2(numerator, denom); return 2 * (halfSA >= 0 ? halfSA : halfSA + ConstantF.Pi); } /// /// Computes the solid angle for a planar triangle as seen from the given point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float SolidAngle(V3f va, V3f vb, V3f vc, V3f p) => SolidAngle(va - p, vb - p, vc - p); /// /// Computes the solid angle for a planar triangle as seen from the given point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float SolidAngle(Triangle3f t, V3f p) => SolidAngle(t.P0 - p, t.P1 - p, t.P2 - p); #endregion #region Distance /// /// Gets the distance between the closest point on the triangle [a, b, c] and the given query point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance(V3f a, V3f b, V3f c, V3f query) { var cp = query.GetClosestPointOnTriangle(a, b, c); return (cp - query).Length; } #endregion } #endregion #region Triangle3d /// /// A three-dimensional triangle represented by its three points. /// public partial struct Triangle3d : IBoundingSphere3d { #region Geometric Properties /// /// Returns the area of the triangle. /// public readonly double Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.Area(this); } /// /// Returns whether the triangle is degenerated, i.e. its area is zero. /// public readonly bool IsDegenerated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.IsDegenerated(this); } /// /// Returns the normal of the triangle. /// public readonly V3d Normal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.Normal(this); } /// /// Returns the plane that contains the points of the triangle. /// public readonly Plane3d Plane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.Plane(this); } #endregion #region IBoundingSphere3d Members /// /// Returns the bounding sphere of the triangle. /// public readonly Sphere3d BoundingSphere3d { get { var edge01 = Edge01; var edge02 = Edge02; double dot0101 = Vec.Dot(edge01, edge01); double dot0102 = Vec.Dot(edge01, edge02); double dot0202 = Vec.Dot(edge02, edge02); double d = 2 * (dot0101 * dot0202 - dot0102 * dot0102); if (d.Abs() <= 1e-9) return Sphere3d.Invalid; double s = (dot0101 * dot0202 - dot0202 * dot0102) / d; double t = (dot0202 * dot0101 - dot0101 * dot0102) / d; var p = P0; var sph = new Sphere3d(); if (s <= 0) sph.Center = 0.5 * (P0 + P2); else if (t <= 0) sph.Center = 0.5 * (P0 + P1); else if (s + t >= 1) { sph.Center = 0.5 * (P1 + P2); p = P1; } else sph.Center = P0 + s * edge01 + t * edge02; sph.Radius = (sph.Center - p).Length; return sph; } } #endregion } /// /// Contains static methods for triangles. /// public static partial class Triangle { #region Area /// /// Returns the area of the triangle defined by the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Area(V3d p0, V3d p1, V3d p2) => (p1 - p0).Cross(p2 - p0).Length * 0.5; /// /// Returns the area of the given triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Area(Triangle3d t) => Area(t.P0, t.P1, t.P2); #endregion #region IsDegenerated /// /// Returns whether the triangle defined by the give points is degenerated, i.e. its area is zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsDegenerated(V3d p0, V3d p1, V3d p2) => (p1 - p0).Cross(p2 - p0).AllTiny; /// /// Returns whether the given triangle is degenerated, i.e. its area is zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsDegenerated(Triangle3d t) => IsDegenerated(t.P0, t.P1, t.P2); #endregion #region Normal /// /// Returns the normal of the triangle defined by the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Normal(V3d p0, V3d p1, V3d p2) => (p1 - p0).Cross(p2 - p0).Normalized; /// /// Returns the normal of the given triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Normal(Triangle3d t) => Normal(t.P0, t.P1, t.P2); #endregion #region Plane /// /// Returns the plane that contains the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Plane3d Plane(V3d p0, V3d p1, V3d p2) => new Plane3d(Normal(p0, p1, p2), p0); /// /// Returns the plane that contains the points of the given triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Plane3d Plane(Triangle3d t) => Plane(t.P0, t.P1, t.P2); #endregion #region SolidAngle /// /// Computes the solid angle for a planar triangle as seen from the origin. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double SolidAngle(Triangle3d t) => SolidAngle(t.P0, t.P1, t.P2); /// /// Computes the solid angle for a planar triangle as seen from the origin. /// /// Van Oosterom, A., and Strackee, J. (1983). /// The solid angle of a plane triangle. /// IEEE transactions on Biomedical Engineering, (2), 125-126. /// /// https://en.wikipedia.org/wiki/Solid_angle#Tetrahedron /// public static double SolidAngle(V3d va, V3d vb, V3d vc) { var ma = va.Length; var mb = vb.Length; var mc = vc.Length; var numerator = Fun.Abs(Vec.Dot(va, (Vec.Cross(vb, vc)))); var denom = ma * mb * mc + Vec.Dot(va, vb) * mc + Vec.Dot(va, vc) * mb + Vec.Dot(vb, vc) * ma; var halfSA = Fun.Atan2(numerator, denom); return 2 * (halfSA >= 0 ? halfSA : halfSA + Constant.Pi); } /// /// Computes the solid angle for a planar triangle as seen from the given point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double SolidAngle(V3d va, V3d vb, V3d vc, V3d p) => SolidAngle(va - p, vb - p, vc - p); /// /// Computes the solid angle for a planar triangle as seen from the given point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double SolidAngle(Triangle3d t, V3d p) => SolidAngle(t.P0 - p, t.P1 - p, t.P2 - p); #endregion #region Distance /// /// Gets the distance between the closest point on the triangle [a, b, c] and the given query point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(V3d a, V3d b, V3d c, V3d query) { var cp = query.GetClosestPointOnTriangle(a, b, c); return (cp - query).Length; } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Geometry/Types/Triangle/Triangle3_template.cs ================================================ using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Triangle3" + tc; //# var type2 = "Triangle3" + tc2; //# var v3t = "V3" + tc; //# var box3t = "Box3" + tc; //# var plane3t = "Plane3" + tc; //# var sphere3t = "Sphere3" + tc; //# var iboundingsphere3t = "IBoundingSphere3" + tc; //# var half = isDouble ? "0.5" : "0.5f"; //# var pi = isDouble ? "Constant.Pi" : "ConstantF.Pi"; //# var eps = isDouble ? "1e-9" : "1e-5f"; #region __type__ /// /// A three-dimensional triangle represented by its three points. /// public partial struct __type__ : __iboundingsphere3t__ { #region Geometric Properties /// /// Returns the area of the triangle. /// public readonly __ftype__ Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.Area(this); } /// /// Returns whether the triangle is degenerated, i.e. its area is zero. /// public readonly bool IsDegenerated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.IsDegenerated(this); } /// /// Returns the normal of the triangle. /// public readonly __v3t__ Normal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.Normal(this); } /// /// Returns the plane that contains the points of the triangle. /// public readonly __plane3t__ Plane { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Triangle.Plane(this); } #endregion #region __iboundingsphere3t__ Members /// /// Returns the bounding sphere of the triangle. /// public readonly __sphere3t__ BoundingSphere3__tc__ { get { var edge01 = Edge01; var edge02 = Edge02; __ftype__ dot0101 = Vec.Dot(edge01, edge01); __ftype__ dot0102 = Vec.Dot(edge01, edge02); __ftype__ dot0202 = Vec.Dot(edge02, edge02); __ftype__ d = 2 * (dot0101 * dot0202 - dot0102 * dot0102); if (d.Abs() <= __eps__) return __sphere3t__.Invalid; __ftype__ s = (dot0101 * dot0202 - dot0202 * dot0102) / d; __ftype__ t = (dot0202 * dot0101 - dot0101 * dot0102) / d; var p = P0; var sph = new __sphere3t__(); if (s <= 0) sph.Center = __half__ * (P0 + P2); else if (t <= 0) sph.Center = __half__ * (P0 + P1); else if (s + t >= 1) { sph.Center = __half__ * (P1 + P2); p = P1; } else sph.Center = P0 + s * edge01 + t * edge02; sph.Radius = (sph.Center - p).Length; return sph; } } #endregion } /// /// Contains static methods for triangles. /// public static partial class Triangle { #region Area /// /// Returns the area of the triangle defined by the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Area(__v3t__ p0, __v3t__ p1, __v3t__ p2) => (p1 - p0).Cross(p2 - p0).Length * __half__; /// /// Returns the area of the given triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Area(__type__ t) => Area(t.P0, t.P1, t.P2); #endregion #region IsDegenerated /// /// Returns whether the triangle defined by the give points is degenerated, i.e. its area is zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsDegenerated(__v3t__ p0, __v3t__ p1, __v3t__ p2) => (p1 - p0).Cross(p2 - p0).AllTiny; /// /// Returns whether the given triangle is degenerated, i.e. its area is zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsDegenerated(__type__ t) => IsDegenerated(t.P0, t.P1, t.P2); #endregion #region Normal /// /// Returns the normal of the triangle defined by the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ Normal(__v3t__ p0, __v3t__ p1, __v3t__ p2) => (p1 - p0).Cross(p2 - p0).Normalized; /// /// Returns the normal of the given triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ Normal(__type__ t) => Normal(t.P0, t.P1, t.P2); #endregion #region Plane /// /// Returns the plane that contains the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __plane3t__ Plane(__v3t__ p0, __v3t__ p1, __v3t__ p2) => new __plane3t__(Normal(p0, p1, p2), p0); /// /// Returns the plane that contains the points of the given triangle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __plane3t__ Plane(__type__ t) => Plane(t.P0, t.P1, t.P2); #endregion #region SolidAngle /// /// Computes the solid angle for a planar triangle as seen from the origin. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ SolidAngle(__type__ t) => SolidAngle(t.P0, t.P1, t.P2); /// /// Computes the solid angle for a planar triangle as seen from the origin. /// /// Van Oosterom, A., and Strackee, J. (1983). /// The solid angle of a plane triangle. /// IEEE transactions on Biomedical Engineering, (2), 125-126. /// /// https://en.wikipedia.org/wiki/Solid_angle#Tetrahedron /// public static __ftype__ SolidAngle(__v3t__ va, __v3t__ vb, __v3t__ vc) { var ma = va.Length; var mb = vb.Length; var mc = vc.Length; var numerator = Fun.Abs(Vec.Dot(va, (Vec.Cross(vb, vc)))); var denom = ma * mb * mc + Vec.Dot(va, vb) * mc + Vec.Dot(va, vc) * mb + Vec.Dot(vb, vc) * ma; var halfSA = Fun.Atan2(numerator, denom); return 2 * (halfSA >= 0 ? halfSA : halfSA + __pi__); } /// /// Computes the solid angle for a planar triangle as seen from the given point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ SolidAngle(__v3t__ va, __v3t__ vb, __v3t__ vc, __v3t__ p) => SolidAngle(va - p, vb - p, vc - p); /// /// Computes the solid angle for a planar triangle as seen from the given point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ SolidAngle(__type__ t, __v3t__ p) => SolidAngle(t.P0 - p, t.P1 - p, t.P2 - p); #endregion #region Distance /// /// Gets the distance between the closest point on the triangle [a, b, c] and the given query point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Distance(__v3t__ a, __v3t__ b, __v3t__ c, __v3t__ query) { var cp = query.GetClosestPointOnTriangle(a, b, c); return (cp - query).Length; } #endregion } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Hashing/HashCode.cs ================================================ using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using static System.Math; namespace Aardvark.Base { public static class HashCode { /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint UCombine(int a, int b) => (uint)a ^ (uint)b + 0x9e3779b9 + ((uint)a << 6) + ((uint)a >> 2); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint UCombine(uint a, int b) => a ^ (uint)b + 0x9e3779b9 + (a << 6) + (a >> 2); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint UCombine(int a, uint b) => (uint)a ^ (uint)b + 0x9e3779b9 + ((uint)a << 6) + ((uint)a >> 2); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint UCombine(uint a, uint b) => a ^ b + 0x9e3779b9 + (a << 6) + (a >> 2); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Combine(uint a, uint b) => (int)(a ^ b + 0x9e3779b9 + (a << 6) + (a >> 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Combine(int a, uint b) => (int)((uint)a ^ b + 0x9e3779b9 + ((uint)a << 6) + ((uint)a >> 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Combine(uint a, int b) => (int)(a ^ (uint)b + 0x9e3779b9 + (a << 6) + (a >> 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Combine(int a, int b) => (int)((uint)a ^ (uint)b + 0x9e3779b9 + ((uint)a << 6) + ((uint)a >> 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Combine(long a, int b) => Combine(UCombine((int)(a >> 32), (int)a), b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Combine(int a, long b) => Combine(a, UCombine((int)(b >> 32), (int)b)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Combine(long a, long b) => Combine(UCombine((int)(a >> 32), (int)a), UCombine((int)(b >> 32), (int)b)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Combine(int a, int b, int c) { return Combine(UCombine(a, b), c); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Combine(int a, int b, int c, int d) { return Combine(UCombine(UCombine(a, b), c), d); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Combine(int a, int b, int c, int d, int e) { return Combine(UCombine(UCombine(UCombine(a, b), c), d), e); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Combine(int a, int b, int c, int d, int e, int f) { return Combine(UCombine(UCombine(UCombine(UCombine(a, b), c), d), e), f); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Combine(int a, int b, int c, int d, int e, int f, int g) { return Combine(UCombine(UCombine(UCombine(UCombine(UCombine(a, b), c), d), e), f), g); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Combine(int a, int b, int c, int d, int e, int f, int g, int h) { return Combine(UCombine(UCombine(UCombine(UCombine(UCombine(UCombine(a, b), c), d), e), f), g), h); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Combine(int a, int b, params int[] rest) { uint h = UCombine(a, b); foreach (var i in rest) h = UCombine(h, i); return (int)h; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetCombined(T0 e0, T1 e1) where T0 : struct where T1 : struct => Combine(e0.GetHashCode(), e1.GetHashCode()); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetCombined(T0 e0, T1 e1, T2 e2) where T0 : struct where T1 : struct where T2 : struct => Combine(UCombine(e0.GetHashCode(), e1.GetHashCode()), e2.GetHashCode()); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetCombined(T0 e0, T1 e1, T2 e2, T3 e3) where T0 : struct where T1 : struct where T2 : struct where T3 : struct => Combine(UCombine(UCombine(e0.GetHashCode(), e1.GetHashCode()), e2.GetHashCode()), e3.GetHashCode()); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetCombined(T0 e0, T1 e1, T2 e2, T3 e3, T4 e4) where T0 : struct where T1 : struct where T2 : struct where T3 : struct where T4 : struct => Combine(UCombine(UCombine(UCombine(e0.GetHashCode(), e1.GetHashCode()), e2.GetHashCode()), e3.GetHashCode()), e4.GetHashCode()); /// /// Compute the combined hash code of an IEnumerable of items. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetCombinedHashCode(this IEnumerable items) where T : struct => (int)items.Aggregate(0U, (h, i) => UCombine(h, i.GetHashCode())); /// /// Compute the combined hash code of an array of items (explicit /// implementation in order to be faster than IEnumerable version). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetCombinedHashCode(this T[] array) where T : struct => array.GetCombinedHashCode(array.LongLength); /// /// Compute the combined hash code of an array of items (explicit /// implementation in order to be faster than IEnumerable version). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetCombinedHashCode(this T[] array, long count) where T : struct { if (count == 0) return 0; var h = (uint)array[0].GetHashCode(); for (var i = 1; i < count; i++) h = UCombine(h, array[i].GetHashCode()); return (int)h; } /// /// Compute the combined hash code of an array of items (explicit /// implementation in order to be faster than IEnumerable version). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetCombinedHashCode(this T[] array, long first, long count) where T : struct { if (count == 0) return 0; var h = (uint)array[first].GetHashCode(); for (long i = first + 1, e = first + count; i < e; i++) h = UCombine(h, array[i].GetHashCode()); return (int)h; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetCombinedWithDefaultZero(T0 e0, T1 e1) => Combine(e0.Equals(default(T0)) ? 0 : e0.GetHashCode(), e1.Equals(default(T1)) ? 0 : e1.GetHashCode()); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetCombinedWithDefaultZero(T0 e0, T1 e1, T2 e2) => Combine(UCombine(e0.Equals(default(T0)) ? 0 : e0.GetHashCode(), e1.Equals(default(T1)) ? 0 : e1.GetHashCode()), e2.Equals(default(T2)) ? 0 : e2.GetHashCode()); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetCombinedWithDefaultZero(T0 e0, T1 e1, T2 e2, T3 e3) => Combine(UCombine(UCombine(e0.Equals(default(T0)) ? 0 : e0.GetHashCode(), e1.Equals(default(T1)) ? 0 : e1.GetHashCode()), e2.Equals(default(T2)) ? 0 : e2.GetHashCode()), e3.Equals(default(T3)) ? 0 : e3.GetHashCode()); /// /// Compute the first of two possible hashcodes for hashing in a 1-D /// unit grid. Add items with this function, retrieve with function /// HashCode.Get2. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Get1of2(double x) { var xi = (long)Floor(x); return (int)(xi >> 1); } /// /// Compute all two possible hashcodes for hashing in a 1-D unit grid. /// Retrive all items with the two hashodes written into the supplied /// array. Items need to be added just with the first of the two /// hashcodes (also computed by function HashCodeGet1of2). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Get2(double x, int[] hca) { var xi = (long)Floor(x); int xh0 = (int)(xi >> 1); hca[0] = xh0; hca[1] = xh0 - 1 + ((int)(xi & 1) << 1); } /// /// Compute the first of four possible hashcodes for hashing in a 2-D /// unit grid. Add items with this function, retrieve with function /// HashCode.Get4. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Get1of4(double x, double y) { var xi = (long)Floor(x); var yi = (long)Floor(y); return Combine((int)(xi >> 1), (int)(yi >> 1)); } /// /// Compute all four possible hashcodes for hashing in a 2-D unit grid. /// Retrive all items with the four hashodes written into the supplied /// array. Items need to be added just with the first of the four /// hashcodes (also computed by function HashCodeGet1of4). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Get4(double x, double y, int[] hca) { var xi = (long)Floor(x); var yi = (long)Floor(y); int xh0 = (int)(xi >> 1), xh1 = xh0 - 1 + ((int)(xi & 1) << 1); int yh0 = (int)(yi >> 1), yh1 = yh0 - 1 + ((int)(yi & 1) << 1); hca[0] = Combine(xh0, yh0); hca[1] = Combine(xh1, yh0); hca[2] = Combine(xh0, yh1); hca[3] = Combine(xh1, yh1); } /// /// Compute the first of eight possible hashcodes for hashing in a 3-D /// unit grid. Add items with this function, retrieve with function /// HashCode.Get8. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Get1of8(double x, double y, double z) { var xi = (long)Floor(x); var yi = (long)Floor(y); var zi = (long)Floor(z); return Combine((int)(xi >> 1), (int)(yi >> 1), (int)(zi >> 1)); } /// /// Compute all eight possible hashcodes for hashing in a 3-D unit grid. /// Retrive all items with the eight hashodes written into the supplied /// array. Items need to be added just with the first of the eight /// hashcodes (also computed by function HashCodeGet1of2). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Get8(double x, double y, double z, int[] hca) { var xi = (long)Floor(x); var yi = (long)Floor(y); var zi = (long)Floor(z); int xh0 = (int)(xi >> 1), xh1 = xh0 - 1 + ((int)(xi & 1) << 1); int yh0 = (int)(yi >> 1), yh1 = yh0 - 1 + ((int)(yi & 1) << 1); int zh0 = (int)(zi >> 1), zh1 = zh0 - 1 + ((int)(zi & 1) << 1); hca[0] = Combine(xh0, yh0, zh0); hca[1] = Combine(xh1, yh0, zh0); hca[2] = Combine(xh0, yh1, zh0); hca[3] = Combine(xh1, yh1, zh0); hca[4] = Combine(xh0, yh0, zh1); hca[5] = Combine(xh1, yh0, zh1); hca[6] = Combine(xh0, yh1, zh1); hca[7] = Combine(xh1, yh1, zh1); } /// /// Compute the first of 16 possible hashcodes for hashing in a 4-D /// unit grid. Add items with this function, retrieve with function /// HashCode.Get16. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Get1of16(double x, double y, double z, double w) { var xi = (long)Floor(x); var yi = (long)Floor(y); var zi = (long)Floor(z); var wi = (long)Floor(w); return Combine((int)(xi >> 1), (int)(yi >> 1), (int)(zi >> 1), (int)(wi >> 1)); } /// /// Compute all 16 possible hashcodes for hashing in a 4-D unit grid. /// Retrive all items with the 16 hashodes written into the supplied /// array. Items need to be added just with the first of the 16 /// hashcodes (also computed by function HashCodeGet1of16). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Get16(double x, double y, double z, double w, int[] hca) { var xi = (long)Floor(x); var yi = (long)Floor(y); var zi = (long)Floor(z); var wi = (long)Floor(w); int xh0 = (int)(xi >> 1), xh1 = xh0 - 1 + ((int)(xi & 1) << 1); int yh0 = (int)(yi >> 1), yh1 = yh0 - 1 + ((int)(yi & 1) << 1); int zh0 = (int)(zi >> 1), zh1 = zh0 - 1 + ((int)(zi & 1) << 1); int dh0 = (int)(wi >> 1), dh1 = dh0 - 1 + ((int)(wi & 1) << 1); hca[0] = Combine(xh0, yh0, zh0, dh0); hca[1] = Combine(xh1, yh0, zh0, dh0); hca[2] = Combine(xh0, yh1, zh0, dh0); hca[3] = Combine(xh1, yh1, zh0, dh0); hca[4] = Combine(xh0, yh0, zh1, dh0); hca[5] = Combine(xh1, yh0, zh1, dh0); hca[6] = Combine(xh0, yh1, zh1, dh0); hca[7] = Combine(xh1, yh1, zh1, dh0); hca[8] = Combine(xh0, yh0, zh0, dh1); hca[9] = Combine(xh1, yh0, zh0, dh1); hca[10] = Combine(xh0, yh1, zh0, dh1); hca[11] = Combine(xh1, yh1, zh0, dh1); hca[12] = Combine(xh0, yh0, zh1, dh1); hca[13] = Combine(xh1, yh0, zh1, dh1); hca[14] = Combine(xh0, yh1, zh1, dh1); hca[15] = Combine(xh1, yh1, zh1, dh1); } } } ================================================ FILE: src/Aardvark.Base/Introspection/Aardvark.cs ================================================ namespace Aardvark.Base; using System; using System.IO; using System.Reflection; using System.Runtime.InteropServices; #if NET8_0_OR_GREATER using System.Runtime.Loader; #endif // TODO: static class [Serializable] public partial class Aardvark { [Obsolete("Use static methods instead.")] public Aardvark() { } private enum OS { Unknown = 0, Win32 = 1, Linux = 2, MacOS = 3 } private static bool TryParseOS(string os, out OS value) { value = os?.ToLower() switch { "win" or "win32" or "win64" or "windows" => OS.Win32, "linux" or "nix" or "unix" => OS.Linux, "mac" or "macos" or "macosx" => OS.MacOS, _ => OS.Unknown }; return value != OS.Unknown; } private static OS GetOS() { return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? OS.Win32 : RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? OS.MacOS : RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? OS.Linux : OS.Unknown; } /// /// Gets the current operating system platform as an value. /// /// /// The method checks /// and returns one of , , or . /// If none of these are detected, an with the name "UNKNOWN" is returned via /// . This can happen on unsupported or future platforms. /// /// /// The current platform descriptor. /// public static OSPlatform GetOSPlatform() { return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? OSPlatform.Windows : RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? OSPlatform.OSX : RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? OSPlatform.Linux : OSPlatform.Create("UNKNOWN"); } private static bool isInitialized; public static void Init() { if (isInitialized) return; Report.BeginTimed("Initializing Aardvark"); const string framework = #if NET8_0 ".NET 8.0"; #elif NETSTANDARD2_0 ".NET Standard 2.0"; #endif Report.Begin("System Information:"); Report.Line("System: {0}", RuntimeInformation.OSDescription); Report.Line("Processor: {0} core {1}", Environment.ProcessorCount, ArchitectureString(RuntimeInformation.OSArchitecture)); Report.Line("Process: {0}", ArchitectureString(RuntimeInformation.ProcessArchitecture)); Report.Line("Runtime: {0}", RuntimeInformation.FrameworkDescription); Report.Line("Framework: {0}", framework); if (RuntimeInformation.ProcessArchitecture != Architecture.X64) { Report.Error("{0} is not officially supported yet: some features may not work correctly", ArchitectureString(RuntimeInformation.ProcessArchitecture)); } Report.End(); #if NETCOREAPP3_1_OR_GREATER // Assembly loading via name fails if the assembly is not referenced as runtime or compile library. // This happens when a plugin is not referenced but simply dropped next to the entry assembly (e.g. multiple projects share the same output folder). // Here we just try to locate the assembly next to the entry path. // See: https://github.com/Particular/Workshop/issues/64 AssemblyLoadContext.Default.Resolving += (ctx, name) => { Report.Begin(4, $"Trying to resolve assembly: {name.FullName}"); try { var path = Path.Combine(IntrospectionProperties.CurrentEntryPath, name.Name + ".dll"); if (File.Exists(path)) { var asm = ctx.LoadFromAssemblyPath(path); Report.End(4, $" - success: {path}"); return asm; } Report.End(4, $" - not found"); return null; } catch (Exception e) { Report.End(4, $" - failed: {e}"); return null; } }; // Called whenever a native library cannot be resolved by the managed runtime. // Note that this is only called for native libraries that are loaded from managed code. // Dependencies of native libraries are resolved using the dynamic linker of the platform. // On Linux, this can be problematic if an assembly has native dependencies consisting of // multiple libraries (e.g., liba and libb will be unpacked to the same directory, where liba requires libb). // In this case the libraries must be built with rpath set to $ORIGIN so that libb can be found next to liba. AssemblyLoadContext.Default.ResolvingUnmanagedDll += (assembly, name) => { Report.Begin(4, $"Resolving native library '{name}'"); var ptr = LoadLibrary(assembly, name, global: false, resolving: true); Report.End(4); return ptr; }; #endif // Set error mode to SEM_FAILCRITICALERRORS: // The system does not display the critical-error-handler message box. // Instead, the system sends the error to the calling process. if (GetOS() == OS.Win32) Kernel32.SetErrorMode(Kernel32.SEM_FAILCRITICALERRORS); if (IntrospectionProperties.NativeLibraryUnpackingAllowed) { AppDomain.CurrentDomain.AssemblyLoad += (_, args) => { LoadNativeDependencies(args.LoadedAssembly); }; Report.BeginTimed("Loading native dependencies"); foreach (var assmebly in AppDomain.CurrentDomain.GetAssemblies()) { LoadNativeDependencies(assmebly); } Report.EndTimed(); } else { Report.Line(4, "Skipping native dependency loading since NativeLibraryUnpackingAllowed = false"); } if (IntrospectionProperties.PluginsEnabled) { Plugins.Init(); } else { Report.Line(4, "Skipping plugin loading since PluginsEnabled = false"); } Report.End(); isInitialized = true; } } ================================================ FILE: src/Aardvark.Base/Introspection/CachingProperties.cs ================================================ namespace Aardvark.Base; using System; using System.IO; using System.Reflection; public static class CachingProperties { /// /// Naming schemes for cache files. /// public enum NamingScheme { /// /// Name is based on the version of the assembly. /// Version, /// /// Name is based on the modification time of the assembly file. /// Timestamp } private static readonly Lazy s_cacheDirectory = new(() => { var path = CustomCacheDirectory; if (string.IsNullOrWhiteSpace(path)) { path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); if (string.IsNullOrWhiteSpace(path)) { Report.Warn("Environment.SpecialFolder.LocalApplicationData does not exist!"); path = "Cache"; // using ./Cache } else { path = Path.Combine(path, "Aardvark", "Cache"); } } Report.Line(4, $"Cache directory: {path}"); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } return path; }); /// /// If set, determines the directory holding cache files. Otherwise, a default directory is used. /// Must be set before is used. /// public static string CustomCacheDirectory { get; set; } /// /// Directory holding cache files, if is not set, a default directory based on /// will be used instead. /// public static string CacheDirectory => s_cacheDirectory.Value; /// /// Gets or sets the naming scheme used for plugins cache files. /// Default scheme is based on assembly version. /// public static NamingScheme PluginsCacheFileNaming { get; set; } = NamingScheme.Version; /// /// Gets or sets the naming scheme used for introspection cache files. /// Default scheme is based on assembly version. /// public static NamingScheme IntrospectionCacheFileNaming { get; set; } = NamingScheme.Version; internal static string GetIdentifier(this Assembly asm, NamingScheme scheme) { return scheme switch { NamingScheme.Version => asm.GetName()?.Version?.ToString() ?? "0.0.0.0", NamingScheme.Timestamp => asm.GetLastWriteTimeSafe().ToBinary().ToString(), _ => "" }; } } ================================================ FILE: src/Aardvark.Base/Introspection/Introspection.cs ================================================ namespace Aardvark.Base; using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; public static class Introspection { private static readonly CultureInfo s_cultureInfoEnUs = new("en-us"); private static readonly Dictionary s_assemblies; private static readonly HashSet s_assembliesThatFailedToLoad = []; private static readonly HashSet s_allAssemblies = []; private static string InitializeCacheDirectory() { var path = Path.Combine(CachingProperties.CacheDirectory, "Introspection"); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } return path; } private static readonly Lazy s_cacheDirectory = new(InitializeCacheDirectory); /// /// Returns the directory of the introspection cache files. /// public static string CacheDirectory => s_cacheDirectory.Value; /// /// Registers an additional assembly at runtime to be /// used for subsequent introspection queries. This /// may be used for e.g. plugin scenarios. /// All assemblies that are reachable from the entry /// assembly are registered automatically at startup. /// public static void RegisterAssembly(Assembly assembly) { if (assembly != null) s_allAssemblies.Add(assembly); } /// /// Enumerates all known assemblies. /// public static IEnumerable AllAssemblies => s_allAssemblies; /// /// Enumerates all classes implementing the specified interface. /// public static IEnumerable GetAllClassesImplementingInterface(Type interfaceType) => AllAssemblies.SelectMany(a => GetAllClassesImplementingInterface(a, interfaceType)); /// /// Enumerates all classes inheriting from the specified base class. /// public static IEnumerable GetAllClassesInheritingFrom(Type baseType) => AllAssemblies.SelectMany(a => GetAllClassesInheritingFrom(a, baseType)); /// /// Enumerates all types decorated with attribute T as tuples of type /// and its one or more T-attributes. /// public static IEnumerable<(Type, T[])> GetAllTypesWithAttribute() => AllAssemblies.SelectMany(GetAllTypesWithAttribute); /// /// Enumerates all methods decorated with attribute T as tuples of MethodInfo /// and its one or more T-attributes. /// public static IEnumerable<(MethodInfo, T[])> GetAllMethodsWithAttribute() => AllAssemblies.SelectMany(GetAllMethodsWithAttribute); /// /// Enumerates all classes from the specified assembly /// implementing the specified interface. /// public static Type[] GetAllClassesImplementingInterface(Assembly assembly, Type interfaceType) => GetAll___(assembly, interfaceType.FullName, lines => lines.Select(Type.GetType), types => types.Where(t => (t.IsClass || t.IsValueType) && t.GetInterfaces().Contains(interfaceType)), result => result.Select(t => t.AssemblyQualifiedName) ); /// /// Enumerates all classes from the specified assembly /// inheriting from the specified base class. /// public static Type[] GetAllClassesInheritingFrom(Assembly assembly, Type baseType) => GetAll___(assembly, baseType.FullName, lines => lines.Select(Type.GetType), types => types.Where(t => t.IsSubclassOf(baseType)), result => result.Select(t => t.AssemblyQualifiedName) ); /// /// Enumerates all types from the specified assembly /// decorated with attribute T as tuples of type /// and its one or more T-attributes. /// public static (Type, T[])[] GetAllTypesWithAttribute(Assembly assembly) => GetAll___<(Type, T[])>(assembly, typeof(T).FullName, lines => lines.Select(Type.GetType) .Select(t => (t, TryGetCustomAttributes(t))), types => from t in types let attribs = TryGetCustomAttributes(t) where attribs.Length > 0 select (t, attribs), result => result.Select(t => t.Item1.AssemblyQualifiedName) ); private static T[] TryGetCustomAttributes(Type type) { try { return type.GetCustomAttributes(typeof(T), false).Select(x => (T)x).ToArray(); } catch (Exception e) { Report.Line(3, "[Introspection] Failed to get custom attributes for {0}: {1} ({2})", type.FullName, e.Message, e.GetType().Name); } return []; } private static T[] TryGetCustomAttributes(MethodInfo mi) { try { return mi.GetCustomAttributes(typeof(T), false).Select(x => (T)x).ToArray(); } catch (Exception e) { Report.Line(3, "[Introspection] Failed to get custom attributes for {0}.{1}: {2} ({3})", mi.DeclaringType?.FullName, mi.Name, e.Message, e.GetType().Name); } return []; } /// /// Enumerates all methods from the specified assembly /// decorated with attribute T as tuples of MethodInfo /// and its one or more T-attributes. /// public static (MethodInfo, T[])[] GetAllMethodsWithAttribute(Assembly assembly) => GetAll___<(MethodInfo, T[])>(assembly, typeof(T).FullName, lines => from line in lines let t = Type.GetType(line) where t != null from m in t.GetMethods() let attribs = TryGetCustomAttributes(m) where attribs.Length > 0 select (m, attribs), types => from t in types where t != null from m in t.GetMethods() let attribs = TryGetCustomAttributes(m) where attribs.Length > 0 select (m, attribs), result => result.SelectNotNull(m => m.Item1.DeclaringType?.AssemblyQualifiedName) ); static Introspection() { Report.BeginTimed("Enumerating assemblies for introspection"); // enumerating all assemblies reachable from entry assembly s_assemblies = new Dictionary(); var entryAssembly = IntrospectionProperties.CurrentEntryAssembly ?? typeof(Aardvark).Assembly; if (entryAssembly == null) { Report.Warn("[Introspection] Could not determine entry assembly"); RegisterAllAssembliesInPath(IntrospectionProperties.CurrentEntryPath); } else { var location = IntrospectionProperties.CurrentEntryBundle ?? entryAssembly.GetLocationSafe(); if (location != null) Report.Line(4, $"[Introspection] Entry assembly: {entryAssembly.FullName} (path: {location})"); else Report.Line(4, $"[Introspection] Entry assembly: {entryAssembly.FullName} (unknown location)"); var name = entryAssembly.GetName().Name; EnumerateAssemblies(name, entryAssembly); } Report.EndTimed(); } /// /// Tries to load and register all assemblies in given path. /// [DebuggerNonUserCode] [Obsolete("Use overload without verbose parameter.")] public static void RegisterAllAssembliesInPath(string path, bool verbose) => RegisterAllAssembliesInPath(path); /// /// Tries to load and register all assemblies in given path. /// [DebuggerNonUserCode] public static void RegisterAllAssembliesInPath(string path) { Report.Begin(4, $"[Introspection] Registering assemblies in: {path}"); try { foreach (var file in DirectoryUtils.GetFilesSafe(path)) { var ext = PathUtils.GetExtensionSafe(file)?.ToLowerInvariant(); if (ext != ".dll" && ext != ".exe") continue; try { var name = AssemblyName.GetAssemblyName(file); Report.Line(4, $"{PathUtils.GetFileNameSafe(file)}"); EnumerateAssemblies(name.Name); } catch { } } } catch (Exception e) { Report.Warn($"Error while registering assemblies in '{path}': {e.Message}"); } finally { Report.End(4); } } /// /// Note by hs: Since this function throws and catches exceptions in non-exceptional cases we /// use [DebuggerNonUserCode] to deactive first chance exceptions here /// at least if non-user code is deactivated in Options/Debugging. /// /// the name of the entry assembly /// If the root assembly is not the assembly which has been started /// by the AppDomain a customAssembly is used alternatively. [DebuggerNonUserCode] private static void EnumerateAssemblies(string name, Assembly customAssembly = null) { if (string.IsNullOrEmpty(name)) return; if (s_assembliesThatFailedToLoad.Contains(name)) return; if (s_assemblies.ContainsKey(name)) return; if (!IntrospectionProperties.AssemblyFilter(name)) { Report.Line(4, "[Introspection] Ignoring assembly {0} due to filter", name); return; } try { var assembly = customAssembly ?? Assembly.Load(name); s_assemblies[name] = assembly; RegisterAssembly(assembly); foreach (var a in assembly.GetReferencedAssemblies()) { if (a.Name != null && !s_assemblies.ContainsKey(a.Name)) { EnumerateAssemblies(a.Name); } } } catch //(Exception e) { s_assembliesThatFailedToLoad.Add(name); //Report.Warn(e.ToString()); //Report.Warn("{0}", name); } } private static string GetQueryCacheFilename(Assembly asm, Guid queryGuid) { var name = asm.GetName().Name; var id = asm.GetIdentifier(CachingProperties.IntrospectionCacheFileNaming); return Path.Combine(CacheDirectory, $"{name}_{id}_{queryGuid}.query"); } private class CacheFileHeader { public int Version; public DateTime TimeStampOfCachedFile; public override string ToString() { if (Version <= 0) throw new ArgumentOutOfRangeException(nameof(Version)); return string.Format(s_cultureInfoEnUs, "version {0} timestamp {1}", Version, TimeStampOfCachedFile.ToBinary()); } public static CacheFileHeader Parse(string s) { if (string.IsNullOrEmpty(s)) throw new ArgumentNullException(nameof(s)); if (!s.StartsWith("version")) return null; // old file without header var tokens = s.Split(' '); if (tokens.Length != 4) throw new FormatException(); return new CacheFileHeader { Version = int.Parse(tokens[1]), TimeStampOfCachedFile = DateTime.FromBinary(long.Parse(tokens[3])) }; } } private static T[] GetAll___( Assembly a, string discriminator, Func, IEnumerable> decode, Func, IEnumerable> createResult, Func> encode ) { var cacheFileName = ""; var assemblyTimeStamp = DateTime.MinValue; // whatever happens, don't halt just because of caching... this actually happens for self-contained deployments https://github.com/aardvark-platform/aardvark.base/issues/65 try { cacheFileName = GetQueryCacheFilename(a, discriminator.ToGuid()); assemblyTimeStamp = a.GetLastWriteTimeSafe(); // for standalone deployments cacheFileNames cannot be retrieved robustly - we skip those if (!string.IsNullOrEmpty(cacheFileName) && File.Exists(cacheFileName)) { var lines = File.ReadAllLines(cacheFileName); var header = lines.Length > 0 ? CacheFileHeader.Parse(lines[0]) : null; if (header != null && header.TimeStampOfCachedFile == assemblyTimeStamp) { // return cached types Report.Line(4, "[cache hit ] {0}", a); return decode(lines.Skip(1)).ToArray(); } } } catch(Exception e) { Report.Warn("Could not get cache for {1}: {0}", e.Message, a.FullName); } Report.Line(4, "[cache miss] {0}", a); // Notes by hs: // previously (rev 19495) typeloadexception resulted in empty result set. // even in case of typeloadexception there may be some successfully loaded // types in result set. Just continue processing with these types // effect: dlls with external unused dependencies don't have to be shipped. Type[] ts; try { ts = a.GetTypes(); } catch (ReflectionTypeLoadException e) { Report.Begin("ReflectionTypeLoadException error in assembly {0}", a.GetName().Name); Report.Line("Full assembly name is {0}.", a.FullName); Report.Line("Exception is {0}", e); Report.Begin("Loader exceptions are"); foreach (var x in e.LoaderExceptions) { Report.Line("{0}", x); } Report.End(); Report.End(); ts = e.Types.Where(t => t != null).ToArray(); } var result = createResult(ts).ToArray(); // whatever happens, don't halt everything just because caching fails try { // for standalone deployments cacheFileNames cannot be retrieved robustly - we skip those if (!string.IsNullOrEmpty(cacheFileName)) { // write cache file var headerLine = new CacheFileHeader { Version = 1, TimeStampOfCachedFile = assemblyTimeStamp } .ToString() .IntoIEnumerable(); File.WriteAllLines(cacheFileName, headerLine.Concat(encode(result)).ToArray()); } } catch(Exception e) { Report.Warn("Could not write cache for {1}: {0}", e.Message, a.FullName); } return result; } } ================================================ FILE: src/Aardvark.Base/Introspection/IntrospectionProperties.cs ================================================ namespace Aardvark.Base; using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.InteropServices; public static class IntrospectionProperties { /// /// Introspection is based on Assembly.GetEntryAssembly which represents the managed /// entry point (i.e. the first assembly that was executed by AppDomain.ExecuteAssembly). /// However, started from an unmanaged entry point (like Visual Studio tests) Assembly.GetEntryAssembly /// is null. To allow us to start from unmanaged hosting processes this alternative /// has been implemented. /// A second use case are managed interactive shells like fsi.exi. Here we want to /// start our dependency walk at a custom assembly instead of the running assembly /// which is the interactive shell host. /// public static Assembly CustomEntryAssembly { get; set; } public static Assembly CurrentEntryAssembly => CustomEntryAssembly ?? Assembly.GetEntryAssembly(); /// /// Whether plugin loading should be enabled /// public static bool PluginsEnabled = true; /// /// Whether Aardvark.Init should unpack native libraries /// public static bool NativeLibraryUnpackingAllowed = true; public static string CurrentEntryPath { get { var location = CurrentEntryAssembly?.GetLocationSafe(); return PathUtils.GetDirectoryNameSafe(location) ?? AppDomain.CurrentDomain.BaseDirectory; } } /// /// Returns the path to the single file deployed entry bundle if it exists, null otherwise. /// public static string CurrentEntryBundle { get { var entryAssembly = CurrentEntryAssembly; // If Location is empty or null, we might have a single-file application if (entryAssembly != null && !entryAssembly.HasLocation()) { var name = entryAssembly.GetName().Name; var ext = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : ""; var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, name + ext); if (File.Exists(path)) { return path; } Report.Warn($"Could not find bundle executable: {path}"); } return null; } } private static readonly HashSet s_defaultAssemblyBlacklist = [ "ASift.CLI", "CUDA.NET", "Emgu.CV", "levmarCLI", "LSDCli", "OpenNI.Net", "OpenSURFcs", "PdfSharp", "PresentationFramework", "PresentationCore", "PrimitiveShapesCLI", "SiftGpu.CLI", "SlamToroCli", "System", "WindowsBase", "OpenTK", "Suave", "Newtonsoft.Json", "Aether", "CommonMark", "CSharp.Data.Adaptive", "FSharp.Data.Adaptive", "ICSharpCode.SharpZipLib", "LibTessDotNet", "SixLabors.ImageSharp", "netstandard", "FsPickler", "WindowsFormsIntegration", "Unofficial.Typography" ]; /// /// Given an assembly name, should it be considered as plugin/native resource etc. This one by default excludes portions of clr base library /// public static bool DefaultAssemblyFilter(string name) { return !(s_defaultAssemblyBlacklist.Contains(name) || name.StartsWith("System.") || name.StartsWith("VRLib.CLI") || name.StartsWith("Microsoft") || name.StartsWith("LidorSystems") || name.StartsWith("WeifenLuo.") || name.StartsWith("OpenCV") && name != "OpenCVSharp" || // OpenCVSharp.dll contains native assemblies that need to be unpacked name.StartsWith("nunit.") || name.StartsWith("Extreme.Numerics") || name.StartsWith("fftwlib") || name.StartsWith("GraphCutsCLI") || name.StartsWith("Interop.MLApp") || name.StartsWith("IPP") && name != "IPP" || // IPP.dll contains native assemblies that need to be unpacked name.StartsWith("IronRuby") || name.StartsWith("MapTools") || name.StartsWith("MetaDataExtractor") || name.StartsWith("mscorlib") || name.StartsWith("SlimDX") || name.StartsWith("TDx.TDxInput") || name.StartsWith("WiimoteLib") || name.StartsWith("OpenTK") || name.StartsWith("Kitware") || name.StartsWith("ICSharpCode") || name.StartsWith("Roslyn") || name.StartsWith("SharpDX") || name.StartsWith("Aardvark.Jynx.Native") || name.StartsWith("SurfaceQueueInteropHelper") || name.StartsWith("ScintillaNET") || name.StartsWith("IKVM") || name.StartsWith("Super") || name.StartsWith("Java") || name.StartsWith("PresentationFramework") || name.StartsWith("FShade") || name.StartsWith("Xceed") || name.StartsWith("UIAutomation") || name.StartsWith("Uncodium") ); } /// /// Determines if the built-in assembly filter is ignored or applied (default: false). /// public static bool IgnoreDefaultAssemblyFilter { get; set; } = false; /// /// Filter function determining if an assembly with the given name (without extension) should be loaded or ignored. /// determines if the function is applied on top of the built-in filter rules. /// public static Func CustomAssemblyFilter { get; set; } = (_) => true; /// /// Filters assemblies according to DefaultAssemblyFilter /// public static bool AssemblyFilter(string name) { return (IgnoreDefaultAssemblyFilter || DefaultAssemblyFilter(name)) && CustomAssemblyFilter(name); } /// /// can be set from application code to disable native unpacking for specific assemblies. Per default, we use the same filter as for EnumerateAssemblies. /// It is absolute crucial to prevent exceptions within this code because of mscorlib resource bug detection /// public static Func UnpackNativeLibrariesFilter = assembly => { var name = assembly?.GetName()?.Name; return name != null && AssemblyFilter(name); }; [Obsolete] public static string BundleEntryPoint = ""; [Obsolete] public static Func GetLastWriteTimeUtc = assembly => assembly.GetLastWriteTimeSafe(); } ================================================ FILE: src/Aardvark.Base/Introspection/Native.cs ================================================ namespace Aardvark.Base; using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Xml.Linq; public partial class Aardvark { private static readonly Lazy s_nativeLibraryCacheDirectory = new(() => Path.Combine(CachingProperties.CacheDirectory, "Native")); /// /// Directory containing unpacked native dependencies. /// public static readonly string NativeLibraryCacheDirectory = s_nativeLibraryCacheDirectory.Value; /// Specify if native libraries should be extracted each to its own sub folder or directory to the NativeLibraryPath /// NOTE: When using global shared NativeLibraryPath, SeparateLibraryDirectories should not be set to false, as there might be version conflicts public static bool SeparateLibraryDirectories = true; #region Dependencies Unpacking private static readonly Dictionary s_nativeDependenciesDirectory = new(); private static readonly Dictionary s_nativeLibraryPaths = new(); /// /// Returns whether the file path appears to be a native library for the current platform. /// private static bool IsNativeLibrary(string path) => RegexPatterns.NativeLibrary.Extension.IsMatch(path); private static string PlatformString(OSPlatform platform) { return platform == OSPlatform.Windows ? "windows" : platform == OSPlatform.OSX ? "mac" : platform == OSPlatform.Linux ? "linux" : "unknown"; } private static string ArchitectureString(Architecture arch) => arch switch { Architecture.X86 => "x86", Architecture.X64 => "AMD64", Architecture.Arm => "ARM", Architecture.Arm64 => "ARM64", _ => arch.ToString() }; #region DllMap private static Dictionary GetSymlinks(XDocument document) { var dict = new Dictionary(); var myOs = GetOS(); var root = document.Element(XName.Get("configuration")); if(root != null) { foreach(var e in root.Elements(XName.Get("dllmap"))) { var src = e.Attribute(XName.Get("dll")); var os = e.Attribute(XName.Get("os")); var dst = e.Attribute(XName.Get("target")); if(src != null && dst != null && os != null) { var srcStr = src.Value; var osStr = os.Value; var dstStr = dst.Value; if(!string.IsNullOrWhiteSpace(srcStr) && !string.IsNullOrWhiteSpace(dstStr) && TryParseOS(osStr, out var osVal)) { if(myOs == osVal) { dict[srcStr] = dstStr; } } } } } return dict; } #endregion #region Symlink #if NET8_0_OR_GREATER private static void CreateSymlink(string src, string dst) => File.CreateSymbolicLink(src, dst); #else [DllImport("libc")] private static extern int symlink(string oldpath, string newpath); private static void CreateSymlink(string src, string dst) { var ret = symlink(dst, src); if (ret != 0) throw new Exception($"symlink() failed (exit code = {ret})"); } #endif private static void CreateSymlink(string baseDir, string src, string dst) { var os = GetOS(); if (os is OS.Win32 or OS.Unknown) return; Report.Begin(3, $"Creating symlink '{src}' -> '{dst}'"); try { var srcPath = Path.Combine(baseDir, src); Report.Line(3, $"Directory: {baseDir}"); var dstPath = os is OS.Linux && LdConfig.TryGetPath(dst, out string resolvedPath) ? resolvedPath : Path.Combine(baseDir, dst); Report.Line(3, $"Target path: {dstPath}"); if (!File.Exists(dstPath)) { Report.End(3, " - target not found"); return; } if (File.Exists(srcPath)) { File.Delete(srcPath); } else { var srcDir = PathUtils.GetDirectoryNameSafe(srcPath); if (!Directory.Exists(srcDir)) Directory.CreateDirectory(srcDir); } CreateSymlink(srcPath, dstPath); Report.End(3, " - success"); } catch (Exception e) { Report.Line(3, $"{e.GetType().Name}: {e.Message}"); Report.End(3, " - failure"); } } #endregion /// /// Extracts native libraries embedded in the specified assembly and returns their relative file names. /// /// The assembly whose embedded native dependencies should be unpacked. Dynamic assemblies are ignored. /// The target operating system platform used to select the appropriate files from the archive. /// The target CPU architecture used to select the appropriate files from the archive. /// Destination directory where files are extracted. If null or empty, defaults to . /// /// An array of relative paths (using the archive's internal folder structure) of the native libraries that were present /// for the given platform/architecture combination. The returned paths are relative to . /// public static string[] UnpackAndListNativeDependencies(Assembly assembly, OSPlatform platform, Architecture architecture, string outputDir = null) { if (assembly.IsDynamic) return []; if (outputDir.IsNullOrEmpty()) outputDir = IntrospectionProperties.CurrentEntryPath; Report.Begin(3, $"Unpacking native dependencies for {assembly.FullName}"); try { Report.Line(3, $"Output directory: {outputDir}"); var info = assembly.GetManifestResourceInfo("native.zip"); if (info == null) { Report.Line(3, $"Assembly does not contain native dependencies."); return []; } var platformString = PlatformString(platform); var architectureString = ArchitectureString(architecture); string[] copyPaths = [ $"{platformString}/{architectureString}/", $"{architectureString}/" ]; List libNames = []; Dictionary remap = []; bool TryGetLocalName(string entryName, out string localName) { foreach(var prefix in copyPaths) { if (entryName.StartsWith(prefix)) { var name = entryName.Substring(prefix.Length); #if NET8_0_OR_GREATER var parts = name.Split('/', StringSplitOptions.RemoveEmptyEntries); #else var parts = name.Split(['/'], StringSplitOptions.RemoveEmptyEntries); #endif if (parts.Length > 0) { localName = Path.Combine(parts); return true; } } } localName = null; return false; } using var stream = assembly.GetManifestResourceStream("native.zip"); using var archive = new ZipArchive(stream); foreach (var e in archive.Entries) { var entryName = e.FullName.Replace(Path.DirectorySeparatorChar, '/'); if (entryName == "remap.xml") { using var es = e.Open(); var doc = XDocument.Load(es); remap = GetSymlinks(doc); } else if (TryGetLocalName(entryName, out var localName)) { var dstPath = Path.Combine(outputDir, localName); var dstDir = PathUtils.GetDirectoryNameSafe(dstPath); if (!File.Exists(dstDir)) Directory.CreateDirectory(dstDir); if (!File.Exists(dstPath) || FileUtils.GetLastWriteTimeSafe(dstPath) < e.LastWriteTime.UtcDateTime) { Report.Line(3, $"Unpacking: {localName}"); e.ExtractToFile(dstPath, true); } else { Report.Line(3, $"Found: {localName}"); } if (IsNativeLibrary(localName)) libNames.Add(localName); } } foreach (var kvp in remap) { CreateSymlink(outputDir, kvp.Key, kvp.Value); if (IsNativeLibrary(kvp.Key)) libNames.Add(kvp.Key); } return libNames.ToArray(); } catch (Exception e) { Report.Warn($"Could not unpack native dependencies for {assembly.FullName}: {e.Message}"); return []; } finally { Report.End(3); } } /// /// Extracts native libraries embedded in for the current OS platform and process architecture. /// /// The assembly whose embedded native dependencies should be unpacked. /// Destination directory where files are extracted. If null or empty, defaults to . /// /// An array of relative paths of the native libraries that were present for the current platform and architecture. /// The paths are relative to . /// public static string[] UnpackAndListNativeDependencies(Assembly assembly, string outputDir = null) => UnpackAndListNativeDependencies(assembly, GetOSPlatform(), RuntimeInformation.ProcessArchitecture, outputDir); /// /// Extracts native libraries embedded in for the specified platform and architecture. /// /// The assembly whose embedded native dependencies should be unpacked. /// The target operating system platform used to select the appropriate files from the archive. /// The target CPU architecture used to select the appropriate files from the archive. /// Destination directory where files are extracted. If null or empty, defaults to . public static void UnpackNativeDependencies(Assembly assembly, OSPlatform platform, Architecture architecture, string outputDir = null) => UnpackAndListNativeDependencies(assembly, platform, architecture, outputDir); /// /// Extracts native libraries embedded in for the current OS platform and process architecture. /// /// The assembly whose embedded native dependencies should be unpacked. /// Destination directory where files are extracted. If null or empty, defaults to . public static void UnpackNativeDependencies(Assembly assembly, string outputDir) => UnpackAndListNativeDependencies(assembly, outputDir); /// /// Extracts native libraries embedded in to /// using the current OS platform and process architecture. /// /// The assembly whose embedded native dependencies should be unpacked. public static void UnpackNativeDependencies(Assembly assembly) => UnpackAndListNativeDependencies(assembly); /// /// Returns the paths of the directories containing native dependencies of all assemblies. /// public static string[] GetNativeDependenciesDirectories() { lock(s_nativeDependenciesDirectory) { return s_nativeDependenciesDirectory.Values.Where(Directory.Exists).ToArray(); } } /// /// Returns the path of the directory containing native dependencies of the given assembly. /// /// Assembly with native dependencies. /// Returns the path of the directory, if the assembly has native dependencies. /// True if the assembly has native dependencies, false otherwise. public static bool TryGetNativeDependenciesDirectory(Assembly assembly, out string path) { var name = assembly?.GetName().Name; if (assembly == null || assembly.IsDynamic || string.IsNullOrEmpty(name)) { path = null; return false; } lock (s_nativeDependenciesDirectory) { if (s_nativeDependenciesDirectory.TryGetValue(assembly, out path)) { return path != null; } var info = assembly.GetManifestResourceInfo("native.zip"); if (info == null) { s_nativeDependenciesDirectory[assembly] = null; return false; } using var stream = assembly.GetManifestResourceStream("native.zip"); string dstFolder = NativeLibraryCacheDirectory; if (SeparateLibraryDirectories) { #if NET8_0_OR_GREATER var hash = SHA1.HashData(stream); var guid = new Guid(hash.AsSpan(0, 16)); #else using var sha1 = SHA1.Create(); var hash = sha1.ComputeHash(stream); Array.Resize(ref hash, 16); var guid = new Guid(hash); #endif var platform = PlatformString(GetOSPlatform()); var arch = ArchitectureString(RuntimeInformation.ProcessArchitecture); dstFolder = Path.Combine(dstFolder, name, guid.ToString(), platform, arch); } s_nativeDependenciesDirectory[assembly] = dstFolder; path = dstFolder; return true; } } private static bool ShouldUnpackNativeDependencies(Assembly assembly) { try { return IntrospectionProperties.UnpackNativeLibrariesFilter(assembly); } catch (Exception e) { Report.Warn($"Error while invoking UnpackNativeLibrariesFilter for {assembly.FullName}: {e.Message}"); return false; } } public static void LoadNativeDependencies(Assembly assembly) { if (assembly == null) return; if (!ShouldUnpackNativeDependencies(assembly)) { Report.Line(4, $"Skipped loading native dependencies for {assembly.FullName}"); return; } if (TryGetNativeDependenciesDirectory(assembly, out string dstFolder)) { try { Report.BeginTimed(3, $"Loading native dependencies for {assembly.FullName}"); var libraryNames = UnpackAndListNativeDependencies(assembly, dstFolder); var libraryPaths = new List(capacity: libraryNames.Length); lock (s_nativeLibraryPaths) { foreach (var libraryName in libraryNames) { var path = Path.Combine(dstFolder, libraryName); if (File.Exists(path)) libraryPaths.Add(path); } s_nativeLibraryPaths[assembly] = libraryPaths.ToArray(); } #if !NETCOREAPP3_1_OR_GREATER // For .NET Standard 2.0, we don't have access to the ResolvingUnmanagedDll event (see Aardvark.Init()) // Instead we load all the native libraries preemptively after unpacking. // Caveat: This does not work with symlinks (on Linux at least), but there is no reason to use the .NET Standard 2.0 build // for non-Windows platforms anyway. foreach (var libraryPath in libraryPaths) { LoadLibrary(assembly, libraryPath, resolving: false, global: true); } #endif } catch (Exception e) { Report.Warn($"Could not load native dependencies for {assembly.FullName}: {e.Message}"); } finally { Report.EndTimed(3); } } } #endregion #region Library Loading private static string NativeLibraryExtension { get; } = GetOS() switch { OS.Win32 => ".dll", OS.MacOS => ".dylib", _ => ".so" }; private static bool TryLoadNativeLibrary(string libraryName, bool global, out IntPtr handle) { #if NETCOREAPP3_1_OR_GREATER return NativeLibrary.TryLoad(libraryName, out handle); #else try { if (GetOS() == OS.Win32) { var flags = Kernel32.LOAD_LIBRARY_SEARCH_DEFAULT_DIRS; if (PathUtils.IsPathFullyQualified(libraryName)) flags |= Kernel32.LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR; handle = Kernel32.LoadLibraryEx(libraryName, IntPtr.Zero, flags); if (handle != IntPtr.Zero) return true; var error = Marshal.GetLastWin32Error(); Report.Line(3, $"Kernel32.LoadLibrary failed (error: {error})"); } else { var flags = global ? Dl.RTLD_NODELETE | Dl.RTLD_GLOBAL | Dl.RTLD_NOW : Dl.RTLD_LAZY; handle = Dl.dlopen(libraryName, flags); } } catch (Exception e) { Report.Line(3, $"{e.GetType().Name}: {e.Message}"); handle = IntPtr.Zero; } return handle != IntPtr.Zero; #endif } private static IEnumerable GetNativeLibraryPaths(Assembly assembly) { var result = new List(capacity: 1); // Search in current / assembly directory var currentDirectory = PathUtils.GetDirectoryNameSafe(assembly?.GetLocationSafe()) ?? IntrospectionProperties.CurrentEntryPath; result.AddRange(DirectoryUtils.GetFilesSafe(currentDirectory)); lock (s_nativeLibraryPaths) { // Probe extracted native libraries if (assembly != null && s_nativeLibraryPaths.TryGetValue(assembly, out var filePathsForAssembly)) { result.AddRange(filePathsForAssembly); } // Probe extracted native libraries for other assemblies foreach (var filePaths in s_nativeLibraryPaths.Values) result.AddRange(filePaths); } return result.Distinct(); } private static readonly Dictionary<(Assembly, string), string> s_nativeLibraryCache = new(); private static IntPtr LoadLibrary(Assembly assembly, string libraryNameOrPath, bool resolving, bool global) { if (string.IsNullOrEmpty(libraryNameOrPath)) return IntPtr.Zero; assembly ??= IntrospectionProperties.CurrentEntryAssembly ?? Assembly.GetExecutingAssembly(); IntPtr ptr = IntPtr.Zero; bool TryLoad(string probe) { using var _ = SetDllDirectory(probe); if (TryLoadNativeLibrary(probe, global, out ptr)) { Report.Line(4, $"Loaded: {probe}"); try { lock (s_nativeLibraryCache) { s_nativeLibraryCache[(assembly, libraryNameOrPath)] = probe; } } catch {} return true; } Report.Line(4, $"Failed to load: {probe}"); return false; } Report.Begin(3, $"Loading native library '{libraryNameOrPath}'"); Report.Line(4, $"Assembly: {assembly}"); try { // If the input is a path (i.e., it has a directory part) just load as is. if (PathUtils.HasDirectoryInformation(libraryNameOrPath)) { if (!resolving) TryLoad(libraryNameOrPath); return ptr; } // Lookup input in cache Report.Begin(4, "Looking up in cache"); try { lock (s_nativeLibraryCache) { var inCache = s_nativeLibraryCache.TryGetValue((assembly, libraryNameOrPath), out var path); if(inCache && File.Exists(path) && TryLoad(path)) return ptr; } } finally { Report.End(4); } // Determine file names of library to search for // If the file name has an unknown or no extension, we add the default library extenion for the current platform var libraryFileNames = new List(capacity: 4) { libraryNameOrPath, $"lib{libraryNameOrPath}" }; if (!string.Equals(PathUtils.GetExtensionSafe(libraryNameOrPath), NativeLibraryExtension, StringComparison.OrdinalIgnoreCase)) { libraryFileNames.Add($"{libraryNameOrPath}{NativeLibraryExtension}"); libraryFileNames.Add($"lib{libraryNameOrPath}{NativeLibraryExtension}"); } // Search in known locations (i.e., entry directory and extracted native directories). Report.Begin(4, "Searching library directories"); try { foreach (var filePath in GetNativeLibraryPaths(assembly)) { var fileName = PathUtils.GetFileNameSafe(filePath); foreach (var libraryFileName in libraryFileNames) { if (string.Equals(fileName, libraryFileName, StringComparison.OrdinalIgnoreCase)) { if (File.Exists(filePath) && TryLoad(filePath)) return ptr; } } } } finally { Report.End(4); } // Did not find the library in any of the search directories. // Try to load using the dynamic linker, i.e., only using the library name (and variants) instead of a path. Report.Begin(4, "Using dynamic linker"); try { foreach (var libraryFileName in libraryFileNames) { if (resolving && libraryFileName == libraryNameOrPath) continue; if (TryLoad(libraryFileName)) return ptr; } } finally { Report.End(4); } // On Linux, as a final resort, we go over all the known libraries as returned by `ldconfig` and look for // the library ignoring version numbers. if (GetOS() == OS.Linux) { var libraryName = RegexPatterns.NativeLibrary.Extension.Replace(libraryNameOrPath, ""); if (!string.IsNullOrEmpty(libraryName)) { Report.Begin(4, "Using ldconfig ignoring version numbers"); try { foreach (var filePath in LdConfig.AllPaths) { var fileName = PathUtils.GetFileNameSafe(filePath); if (!string.IsNullOrEmpty(fileName)) { fileName = RegexPatterns.NativeLibrary.Extension.Replace(fileName, ""); if (string.Equals(fileName, libraryName, StringComparison.OrdinalIgnoreCase) || string.Equals(fileName, $"lib{libraryName}", StringComparison.OrdinalIgnoreCase)) { if (File.Exists(filePath) && TryLoad(filePath)) return ptr; } } } } finally { Report.End(4); } } } return IntPtr.Zero; } catch (Exception e) { Report.Warn($"{e.GetType().Name} occurred while loading native library '{libraryNameOrPath}': {e.Message}"); return IntPtr.Zero; } finally { Report.End(3, ptr != IntPtr.Zero ? $" - success" : " - failed"); } } /// /// Loads the specified native library; the input can be a name or a file path. /// /// /// If is a path (i.e., it contains a directory separator) the /// platform's dynamic linker is invoked directly with that value. Otherwise, the function /// tries to locate the library by: /// /// Searching the directory where the assembly is located. /// Searching the directory of the native dependencies of the assembly. /// Searching the directories of the native dependencies of all the other assemblies. /// Invoking the dynamic linker. /// Resolving the path by using `ldconfig` ignoring version information (Linux only). /// /// Library name comparison is case-insensitive and variants ('lib' prefix, platform-specific extension) are considered. /// /// Name or file path of the library to load. /// Assembly loading the native library. If null the calling assembly is used. /// Handle of the loaded library on success, otherwise. [MethodImpl(MethodImplOptions.NoInlining)] public static IntPtr LoadLibrary(string libraryNameOrPath, Assembly assembly = null) => LoadLibrary(assembly ?? Assembly.GetCallingAssembly(), libraryNameOrPath, resolving: false, global: false); public static IntPtr GetProcAddress(IntPtr handle, string name) { if (handle == IntPtr.Zero) return IntPtr.Zero; #if NETCOREAPP3_1_OR_GREATER return NativeLibrary.TryGetExport(handle, name, out var ptr) ? ptr : IntPtr.Zero; #else return GetOS() == OS.Win32 ? Kernel32.GetProcAddress(handle, name) : Dl.dlsym(handle, name); #endif } #endregion #region Obsolete [Obsolete("Use UnpackNativeDependencies instead.")] public static void UnpackNativeDependenciesToBaseDir(Assembly a, string baseDir) => UnpackNativeDependencies(a, baseDir); [Obsolete("using explicit native library path is no longer possble https://github.com/aardvark-platform/aardvark.base/issues/64")] public static string NativeLibraryPath = Path.Combine(Path.GetTempPath(), "aardvark-native"); [Obsolete("Use GetNativeDependenciesDirectories instead.")] public static string[] GetNativeLibraryPaths() => GetNativeDependenciesDirectories(); [Obsolete("Use TryGetNativeDependenciesDirectory instead.")] public static bool TryGetNativeLibraryPath(Assembly assembly, out string path) => TryGetNativeDependenciesDirectory(assembly, out path); [MethodImpl(MethodImplOptions.NoInlining)] [Obsolete("Use overload with optional 'assembly' parameter instead.")] public static IntPtr LoadLibrary(Assembly assembly, string libraryNameOrPath) => LoadLibrary(assembly ?? Assembly.GetCallingAssembly(), libraryNameOrPath, resolving: false, global: false); #endregion } ================================================ FILE: src/Aardvark.Base/Introspection/Platform/Dl.cs ================================================ using System; using System.Runtime.InteropServices; namespace Aardvark.Base; public partial class Aardvark { internal static class Dl { public const int RTLD_LAZY = 0x00001; public const int RTLD_NOW = 0x00002; public const int RTLD_BINDING_MASK = 0x00003; public const int RTLD_NOLOAD = 0x00004; public const int RTLD_DEEPBIND = 0x00008; public const int RTLD_GLOBAL = 0x00100; public const int RTLD_LOCAL = 0x00000; public const int RTLD_NODELETE = 0x01000; [DllImport("libc", SetLastError = false, CharSet = CharSet.Ansi)] public static extern IntPtr dlopen(string path, int flag); [DllImport("libc", SetLastError = true, CharSet = CharSet.Ansi)] public static extern IntPtr dlsym(IntPtr handle, string name); } } ================================================ FILE: src/Aardvark.Base/Introspection/Platform/Kernel32.cs ================================================ namespace Aardvark.Base; using System; using System.Runtime.InteropServices; public partial class Aardvark { /// /// Indicates whether the DLL directory is altered temporarily before loading a native library from a file. /// The DLL directory is set to the directory of the library so that transitive dependencies in /// the same folder can be found. This is usually not required as the dynamic linker should search the directory of /// a library for its dependencies. However, some libraries (e.g., IPP) may use another loading mechanism that require /// setting the DLL directory explicitly. /// /// Only works on Windows, disabled by default. public static bool UseSetDllDirectory { get; set; } = false; internal static class Kernel32 { public const uint DONT_RESOLVE_DLL_REFERENCES = 0x00000001; public const uint LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010; public const uint LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100; public const uint LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200; public const uint LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400; public const uint LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800; public const uint LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000; public const uint LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008; public const int SEM_FAILCRITICALERRORS = 0x0001; [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern IntPtr LoadLibrary(string path); [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern IntPtr LoadLibraryEx(string path, IntPtr handle, uint dwFlags); [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern IntPtr AddDllDirectory(string path); [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern bool SetCurrentDirectory(string pathName); [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern bool SetDllDirectory(string pathName); [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern uint GetDllDirectory(uint nBufferLength, [Out] char[] lpPathName); [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] public static extern IntPtr GetProcAddress(IntPtr handle, string name); [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] public static extern uint SetErrorMode(uint mode); public static int TryGetDllDirectory(out string path) { char[] buffer; uint requiredSize = 128; do { buffer = new char[(int)requiredSize + 1]; requiredSize = GetDllDirectory((uint)buffer.Length - 1, buffer); } while (requiredSize > 0 && requiredSize > buffer.Length); if (requiredSize == 0) { path = null; return Marshal.GetLastWin32Error(); } path = new string(buffer, 0, (int)requiredSize); return 0; } } private struct DllDirectoryDisposable(string previousPath) : IDisposable { private bool isActive = true; public void Dispose() { if (isActive) { if (!Kernel32.SetDllDirectory(previousPath)) { var error = Marshal.GetLastWin32Error(); Report.Line(4, $"Failed to reset DLL directory to '{previousPath}' (error: {error})"); } isActive = false; } } } /// private static DllDirectoryDisposable SetDllDirectory(string libraryPath) { if (!UseSetDllDirectory || GetOS() != OS.Win32) { return new DllDirectoryDisposable(); } var directoryPath = PathUtils.HasDirectoryInformation(libraryPath) ? PathUtils.GetDirectoryNameSafe(libraryPath) : null; if (string.IsNullOrEmpty(directoryPath)) { return new DllDirectoryDisposable(); } Report.Begin(4, $"Setting DLL directory to '{directoryPath}'"); try { var result = Kernel32.TryGetDllDirectory(out var previousPath); if (result != 0) { Report.Line(4, $"Failed to retrieve current DLL directory (error: {result})"); } else if (previousPath != null) { Report.Line(4, $"Previous path: {previousPath}"); } if (Kernel32.SetDllDirectory(directoryPath)) { return new DllDirectoryDisposable(previousPath); } var error = Marshal.GetLastWin32Error(); Report.Line(4, $"Failed to set DLL directory to '{directoryPath}' (error: {error})"); } catch (Exception e) { Report.Line(4, $"{e.GetType().Name}: {e.Message}"); } finally { Report.End(4); } return new DllDirectoryDisposable(); } } ================================================ FILE: src/Aardvark.Base/Introspection/Platform/LdConfig.cs ================================================ namespace Aardvark.Base; using System; using System.Collections.Generic; using System.Diagnostics; public partial class Aardvark { private static class LdConfig { private static readonly Lazy> s_lookup = new(Load); static List Run(string path) { Report.Begin(3, $"{path} -p"); try { using var p = new Process(); p.StartInfo.FileName = path; p.StartInfo.Arguments = "-p"; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.RedirectStandardError = true; p.StartInfo.UseShellExecute = false; p.StartInfo.CreateNoWindow = true; var result = new List(); p.ErrorDataReceived += (_, _) => { }; p.OutputDataReceived += (_, args) => { lock (result) { if (args.Data != null) result.Add(args.Data); } }; p.Start(); p.BeginOutputReadLine(); p.BeginErrorReadLine(); p.WaitForExit(); if (p.ExitCode == 0) { Report.End(3, " - success"); return result; } var output = string.Join(Environment.NewLine, result); Report.Line(3, output); } catch (Exception e) { Report.Line(3, $"{e.GetType().Name}: {e.Message}"); } Report.End(3, " - failed"); return null; } static Dictionary Load() { var result = new Dictionary(); Report.BeginTimed(3, "Building shared library location cache"); try { string[] commands = ["/usr/sbin/ldconfig", "/sbin/ldconfig", "ldconfig"]; List output = null; foreach (var command in commands) { output = Run(command); if (output != null) break; } var directories = new HashSet(); if (output != null) { foreach (var data in output) { var m = RegexPatterns.LdConfig.Entry?.Match(data); if (m is { Success: true }) { var name = m.Groups["name"].Value.ToLowerInvariant(); var path = m.Groups["path"].Value; var directory = PathUtils.GetDirectoryNameSafe(path); if (directory != null) directories.Add(directory); result[name] = path; } } } // Find files in library directories that are not in cache foreach (var directory in directories) { foreach (var path in DirectoryUtils.GetFilesSafe(directory)) { var name = PathUtils.GetFileNameSafe(path)?.ToLowerInvariant(); if (name != null && IsNativeLibrary(name) && !result.ContainsKey(name)) { result[name] = path; } } } } catch (Exception e) { Report.Warn($"{e.GetType().Name}: {e.Message}"); } Report.Line(3, $"Found {result.Count} libraries"); Report.EndTimed(3); return result; } public static ICollection AllPaths => s_lookup.Value.Values; public static bool TryGetPath(string name, out string path) { if (name != null) return s_lookup.Value.TryGetValue(name.ToLowerInvariant(), out path); path = null; return false; } } } ================================================ FILE: src/Aardvark.Base/Introspection/Plugins.cs ================================================ namespace Aardvark.Base; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; using System.Runtime.Serialization; using System.Xml; using BundleReader = SingleFileExtractor.Core.ExecutableReader; using BundleFileEntry = SingleFileExtractor.Core.FileEntry; #if NET8_0_OR_GREATER using System.Runtime.Loader; #endif [AttributeUsage(AttributeTargets.Method)] public class OnAardvarkInitAttribute : Attribute; public partial class Aardvark { private static class Plugins { #region Paths private static readonly Lazy s_pluginsCacheDirectory = new (() => { var path = Path.Combine(CachingProperties.CacheDirectory, "Plugins"); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } return path; }); private static readonly Lazy s_pluginsCacheFile = new(() => { Assembly entryAssembly = IntrospectionProperties.CurrentEntryAssembly; string entryAssemblyName = entryAssembly?.GetName().Name ?? "unknown"; string entryAssemblyId = entryAssembly?.GetIdentifier(CachingProperties.PluginsCacheFileNaming) ?? "unknown"; string fileName = $"{entryAssemblyName}_{entryAssemblyId}_plugins.xml"; return Path.Combine(CacheDirectory, fileName); }); /// /// Returns the directory of the plugins cache files. /// public static string CacheDirectory => s_pluginsCacheDirectory.Value; /// /// Returns the path of the plugins cache file. /// public static string CacheFile => s_pluginsCacheFile.Value; #endregion #region Assembly Source private abstract class AssemblySource { public abstract string Path { get; } public abstract DateTime LastModified { get; } public abstract Stream OpenRead(); public abstract Assembly Load(); } private class FileAssemblySource(string path) : AssemblySource { public override string Path { get; } = path; public override DateTime LastModified { get; } = FileUtils.GetLastWriteTimeSafe(path); public override Stream OpenRead() => File.OpenRead(Path); public override Assembly Load() { #if NETCOREAPP3_1_OR_GREATER // In .NET core Assembly.LoadFile uses a separate context, resulting in assemblies being // potentially loaded multiple times -> leads to problems with static fields in unit tests // See: https://github.com/dotnet/runtime/issues/39783 return AssemblyLoadContext.Default.LoadFromAssemblyPath(Path); #else return Assembly.LoadFile(Path); #endif } } private class BundleAssemblySource : AssemblySource { private readonly BundleFileEntry m_entry; private byte[] m_data; public override string Path { get; } public override DateTime LastModified { get; } public BundleAssemblySource(BundleFileEntry entry) { var bundlePath = entry.ExecutableReader.FileName; Path = System.IO.Path.Combine(bundlePath, entry.RelativePath); LastModified = FileUtils.GetLastWriteTimeSafe(bundlePath); m_entry = entry; } private byte[] GetData() { if (m_data == null) { using var s = m_entry.AsStream(); using var ms = new MemoryStream(s.CanSeek ? (int)s.Length : 0); s.CopyTo(ms); m_data = ms.GetBuffer(); } return m_data; } public override Stream OpenRead() => new MemoryStream(GetData()); public override Assembly Load() { #if NETCOREAPP3_1_OR_GREATER using var s = OpenRead(); return AssemblyLoadContext.Default.LoadFromStream(s); #else return Assembly.Load(GetData()); #endif } } private class AssemblySourceList : List, IDisposable { private BundleReader m_reader; public void AddDirectory(string path) { foreach (var p in DirectoryUtils.GetFilesSafe(path)) { Add(new FileAssemblySource(p)); } } public void AddBundle(BundleReader reader) { if (m_reader != null) throw new InvalidOperationException("Cannot add multiple bundles."); m_reader = reader; if (reader.IsSingleFile && reader.IsSupported) { foreach (var e in reader.Bundle.Files) { Add(new BundleAssemblySource(e)); } } else { Report.Warn($"Cannot read bundle executable: {reader.FileName}"); } } public void Dispose() { m_reader?.Dispose(); m_reader = null; } } #endregion #region Cache /// /// Cache containing information about whether an assembly is an Aardvark plugin. /// [CollectionDataContract(Name = "Plugins", ItemName = "Assembly", KeyName = "Path", ValueName = "Data")] private class PluginCache : Dictionary { [DataContract] public struct Data(DateTime lastModified, bool isPlugin) { /// /// Modification time stamp of the assembly when the cache was created. /// Used to determine if the cache has been invalidated. /// [DataMember(IsRequired = true)] public DateTime LastModified = lastModified; /// /// Indicates whether the assembly is an Aardvark plugin. /// [DataMember(IsRequired = true)] public bool IsPlugin = isPlugin; } private static readonly DataContractSerializer serializer = new(typeof(PluginCache)); // Note: Used in unit test via reflection private static PluginCache Deserialize(Stream stream) => (PluginCache)serializer.ReadObject(stream); private void Serialize(Stream stream) { using var writer = XmlWriter.Create(stream, new XmlWriterSettings { Indent = true }); serializer.WriteObject(writer, this); } public static PluginCache ReadFromFile() { if (File.Exists(CacheFile)) { try { using var stream = new FileStream(CacheFile, FileMode.Open); var result = Deserialize(stream); Report.Line(3, $"Loaded plugins cache file: {CacheFile}"); return result; } catch (Exception e) { Report.Line(3, $"Could not load plugins cache file '{CacheFile}': {e.Message}"); return new PluginCache(); } } Report.Line(3, $"Using new plugins cache file: {CacheFile}"); return new PluginCache(); } public void WriteToFile() { if (string.IsNullOrEmpty(CacheFile)) { Report.Warn("Could not write plugins cache file since Aardvark.Plugins.CacheFile is null or empty"); } else { try { if (File.Exists(CacheFile)) File.Delete(CacheFile); using var stream = new FileStream(CacheFile, FileMode.CreateNew); Serialize(stream); } catch(Exception e) { Report.Warn($"Could not write plugins cache file '{CacheFile}': {e.Message}"); } } } } #endregion private static unsafe bool ProbeForPlugin(Stream stream) { using var v = new PEReader(stream, PEStreamOptions.LeaveOpen); if (v.PEHeaders.CorHeader == null || !v.HasMetadata) return false; var data = v.GetMetadata(); var m = new MetadataReader(data.Pointer, data.Length); var assdef = m.GetAssemblyDefinition(); foreach (var att in assdef.GetCustomAttributes()) { var attDef = m.GetCustomAttribute(att); if (attDef.Constructor.Kind == HandleKind.MemberReference) { var hh = (MemberReferenceHandle)attDef.Constructor; var e = m.GetMemberReference(hh); var pp = e.Parent; if (pp.Kind == HandleKind.TypeReference) { var attType = m.GetTypeReference((TypeReferenceHandle)pp); var nameStr = m.GetString(attType.Name); var nsStr = m.GetString(attType.Namespace); if (nsStr == "System.Runtime.Versioning" && nameStr == "TargetFrameworkAttribute") { var reader = m.GetBlobReader(attDef.Value); if (reader.ReadUInt16() == 1) { var version = reader.ReadSerializedString(); var match = version != null ? RegexPatterns.Assembly.TargetFramework.Match(version) : null; if (match is { Success: true }) { var fwName = match.Groups["name"].Value; var isLoadable = fwName is ".NETCoreApp" or ".NETStandard"; if (!isLoadable) return false; } } } } } } foreach (var t in m.TypeDefinitions) { var def = m.GetTypeDefinition(t); foreach (var meth in def.GetMethods()) { var mdef = m.GetMethodDefinition(meth); var hasInitAtt = mdef.GetCustomAttributes().Any(att => { var attDef = m.GetCustomAttribute(att); if (attDef.Constructor.Kind == HandleKind.MemberReference) { var hh = (MemberReferenceHandle)attDef.Constructor; var e = m.GetMemberReference(hh); var pp = e.Parent; if (pp.Kind == HandleKind.TypeReference) { var attType = m.GetTypeReference((TypeReferenceHandle)pp); var nameStr = m.GetString(attType.Name); var nsStr = m.GetString(attType.Namespace); return nsStr == "Aardvark.Base" && nameStr == nameof(OnAardvarkInitAttribute); } else return false; } else return false; }); if (hasInitAtt) return true; } } return false; } private static AssemblySourceList FindAssemblySources() { var sources = new AssemblySourceList(); try { var bundlePath = IntrospectionProperties.CurrentEntryBundle; if (bundlePath != null) { try { var reader = new BundleReader(bundlePath); sources.AddBundle(reader); } catch (Exception e) { Report.Warn($"Failed to get assemblies from single file application: {e.Message}"); } } else { var rootPath = IntrospectionProperties.CurrentEntryPath; sources.AddDirectory(rootPath); } } catch (Exception e) { Report.Warn($"Error while locating plugin assemblies: {e}"); } return sources; } private static bool IsPlugin(AssemblySource source, PluginCache oldCache, PluginCache newCache) { var ext = PathUtils.GetExtensionSafe(source.Path)?.ToLowerInvariant(); if (ext != ".dll" && ext != ".exe") return false; var name = Path.GetFileNameWithoutExtension(source.Path); if (!IntrospectionProperties.AssemblyFilter(name)) { Report.Line(4, $"[IsPlugin] Ignoring assembly {name} due to filter"); return false; } bool isPlugin = false; bool exists = oldCache.TryGetValue(source.Path, out PluginCache.Data cacheValue); if (exists && source.LastModified <= cacheValue.LastModified) { Report.Line(4, $"[IsPlugin] Cache found for: {source.Path}"); isPlugin = cacheValue.IsPlugin; } else { if (exists) Report.Line(4, $"[IsPlugin] Retrying to load because cache is outdated: {source.Path}"); else Report.Line(4, $"[IsPlugin] Retrying to load because not in cache: {source.Path}"); try { using var s = source.OpenRead(); isPlugin = ProbeForPlugin(s); } catch (Exception e) { Report.Line(4, $"[IsPlugin] Error while probing assembly '{source.Path}': {e.Message}"); } } if (isPlugin) Report.Line(3, $"[IsPlugin] Plugin found: {source.Path}"); newCache[source.Path] = new PluginCache.Data(source.LastModified, isPlugin); return isPlugin; } internal static List Find() { var oldCache = PluginCache.ReadFromFile(); var newCache = new PluginCache(); using var sources = FindAssemblySources(); List assemblies = []; try { foreach (var source in sources) { try { if (!IsPlugin(source, oldCache, newCache)) continue; var asm = source.Load(); assemblies.Add(asm); } catch (Exception e) { Report.Warn($"Failed to load plugin assembly '{source.Path}': {e.Message}"); } } } finally { newCache.WriteToFile(); } return assemblies; } internal static void Init() { Report.BeginTimed("Loading plugins"); try { List plugins; Report.BeginTimed("Finding and loading assemblies"); try { plugins = Find(); } finally { Report.EndTimed(); } foreach (var assembly in plugins ?? []) { HashSet initMethods = []; try { var query = Introspection.GetAllMethodsWithAttribute(assembly); foreach (var q in query) initMethods.Add(q.Item1); } catch (Exception e) { Report.Warn($"Failed to query initialization methods for assembly '{assembly}': {e.Message}"); } foreach (var mi in initMethods) { var parameters = mi.GetParameters(); Report.BeginTimed($"Initializing {mi.DeclaringType?.Name ?? mi.Name}"); try { if (parameters.Length == 0) mi.Invoke(null, null); else if (parameters.Length == 1 && parameters[0].ParameterType == typeof(IEnumerable)) mi.Invoke(null, [Introspection.AllAssemblies]); else Report.Warn($"Strange Aardvark init method found: {mi}, should be IEnumberable -> unit or unit -> unit"); } catch (Exception e) { Report.Warn($"Failed: {e}"); } finally { Report.End(); } } } } catch (Exception e) { Report.Warn($"{e.GetType().Name} occurred while loading plugins: {e.Message}"); } Report.EndTimed(); } } /// /// Returns the directory of the plugins cache files. /// public static string PluginsCacheDirectory => Plugins.CacheDirectory; /// /// Returns the path of the plugins cache file. /// public static string PluginsCacheFile => Plugins.CacheFile; #region Obsolete [Obsolete("Use PluginsCacheDirectory instead.")] public static string CacheDirectory => PluginsCacheDirectory; [Obsolete("Use PluginsCacheFile instead.")] public string CacheFile = string.Empty; [Obsolete] public static List LoadPlugins() => Plugins.Find(); #endregion } ================================================ FILE: src/Aardvark.Base/Introspection/RegexPatterns.cs ================================================ using System.Runtime.InteropServices; using System.Text.RegularExpressions; namespace Aardvark.Base; public partial class Aardvark { private partial class RegexPatterns { public static partial class NativeLibrary { private const string EXT_WIN32 = @"\.dll$"; private const string EXT_MACOS = @"\.dylib$"; private const string EXT_LINUX = @"\.so(?:\.[0-9]+)*$"; #if NET8_0_OR_GREATER [GeneratedRegex(EXT_WIN32, RegexOptions.IgnoreCase)] private static partial Regex _ExtensionWin32(); private static Regex ExtensionWin32 => _ExtensionWin32(); [GeneratedRegex(EXT_MACOS, RegexOptions.IgnoreCase)] private static partial Regex _ExtensionMacOS(); private static Regex ExtensionMacOS => _ExtensionMacOS(); [GeneratedRegex(EXT_LINUX, RegexOptions.IgnoreCase)] private static partial Regex _ExtensionLinux(); private static Regex ExtensionLinux => _ExtensionLinux(); #else private static Regex ExtensionWin32 { get; } = new(EXT_WIN32, RegexOptions.IgnoreCase | RegexOptions.Compiled); private static Regex ExtensionMacOS { get; } = new(EXT_MACOS, RegexOptions.IgnoreCase | RegexOptions.Compiled); private static Regex ExtensionLinux { get; } = new(EXT_LINUX, RegexOptions.IgnoreCase | RegexOptions.Compiled); #endif public static Regex Extension => GetOS() switch { OS.Win32 => ExtensionWin32, OS.MacOS => ExtensionMacOS, _ => ExtensionLinux }; } public static partial class LdConfig { private const string ENTRY_X64 = @"[ \t]*(?[^ \t]+)[ \t]+\((?[^,]+)\,x86-64[^\)]*\)[ \t]*\=\>[ \t]*(?.*)"; private const string ENTRY_ARM64 = @"[ \t]*(?[^ \t]+)[ \t]+\((?[^,]+)\,arm-64[^\)]*\)[ \t]*\=\>[ \t]*(?.*)"; #if NET8_0_OR_GREATER [GeneratedRegex(ENTRY_X64, RegexOptions.IgnoreCase)] private static partial Regex _EntryX64(); private static Regex EntryX64 => _EntryX64(); [GeneratedRegex(ENTRY_ARM64, RegexOptions.IgnoreCase)] private static partial Regex _EntryArm64(); private static Regex EntryArm64 => _EntryArm64(); #else private static Regex EntryX64 { get; } = new(ENTRY_X64, RegexOptions.IgnoreCase | RegexOptions.Compiled); private static Regex EntryArm64 { get; } = new(ENTRY_ARM64, RegexOptions.IgnoreCase | RegexOptions.Compiled); #endif public static Regex Entry => RuntimeInformation.ProcessArchitecture switch { Architecture.X64 => EntryX64, Architecture.Arm64 => EntryArm64, _ => null }; } public static partial class Assembly { private const string TARGET_FRAMEWORK = @"^[ \t]*(?[\.A-Za-z_0-9]+)[ \t]*,[ \t]*(v|V)ersion[ \t]*=[ \t]*(?[\.A-Za-z_0-9]+)$"; #if NET8_0_OR_GREATER [GeneratedRegex(TARGET_FRAMEWORK)] private static partial Regex _TargetFramework(); public static Regex TargetFramework => _TargetFramework(); #else public static Regex TargetFramework { get; } = new(TARGET_FRAMEWORK, RegexOptions.Compiled); #endif } } } ================================================ FILE: src/Aardvark.Base/Introspection/Utilities.cs ================================================ namespace Aardvark.Base; using System; using System.IO; using System.Reflection; #if !NET8_0_OR_GREATER using System.Linq; #endif internal static class FileUtils { public static DateTime GetLastWriteTimeSafe(string path) { try { return File.Exists(path) ? File.GetLastWriteTimeUtc(path) : DateTime.MaxValue; } catch (Exception) { Report.Warn($"Could not get write time for: {path}"); return DateTime.MaxValue; } } } internal static class DirectoryUtils { public static string[] GetFilesSafe(string directory) { try { return Directory.Exists(directory) ? Directory.GetFiles(directory) : []; } catch (Exception e) { Report.Warn($"Failed to enumerate files in '{directory}': {e.Message}"); return []; } } } internal static class PathUtils { public static bool HasDirectoryInformation(string path) => path != null && (path.Contains(Path.DirectorySeparatorChar) || path.Contains(Path.AltDirectorySeparatorChar)); public static string GetDirectoryNameSafe(string path) { try { return !string.IsNullOrEmpty(path) ? Path.GetDirectoryName(path) : null; } catch { return null; } } public static string GetFileNameSafe(string path) { try { return Path.GetFileName(path); } catch { return null; } } public static string GetExtensionSafe(string path) { try { return Path.GetExtension(path); } catch { return null; } } #if !NET8_0_OR_GREATER // See: https://github.com/dotnet/runtime/blob/main/src/libraries/Common/src/System/IO/PathInternal.Windows.cs private static bool IsValidDriveChar(char value) => (uint)((value | 0x20) - 'a') <= (uint)('z' - 'a'); private static bool IsDirectorySeparator(char c) => c == Path.DirectorySeparatorChar || c == Path.AltDirectorySeparatorChar; private static bool IsPartiallyQualified(string path) { if (path.Length < 2) { // It isn't fixed, it must be relative. There is no way to specify a fixed // path with one character (or less). return true; } if (IsDirectorySeparator(path[0])) { // There is no valid way to specify a relative path with two initial slashes or // \? as ? isn't valid for drive relative paths and \??\ is equivalent to \\?\ return !(path[1] == '?' || IsDirectorySeparator(path[1])); } // The only way to specify a fixed path that doesn't begin with two slashes // is the drive, colon, slash format- i.e. C:\ return !((path.Length >= 3) && (path[1] == Path.VolumeSeparatorChar) && IsDirectorySeparator(path[2]) // To match old behavior we'll check the drive character for validity as the path is technically // not qualified if you don't have a valid drive. "=:\" is the "=" file's default data stream. && IsValidDriveChar(path[0])); } public static bool IsPathFullyQualified(string path) => !IsPartiallyQualified(path); #endif } internal static class AssemblyExtenions { public static string GetLocationSafe(this Assembly assembly) { try { var location = assembly.Location; return location.IsNullOrEmpty() ? null : location; } catch { return null; } } public static bool HasLocation(this Assembly assembly) => assembly.GetLocationSafe() != null; public static DateTime GetLastWriteTimeSafe(this Assembly assembly) { var location = assembly?.GetLocationSafe() ?? IntrospectionProperties.CurrentEntryBundle; return FileUtils.GetLastWriteTimeSafe(location); } } ================================================ FILE: src/Aardvark.Base/Json/JsonConverters.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Text.Json; using System.Text.Json.Serialization; namespace Aardvark.Base { public static class JsonConverterExtensions { private const string FLOAT_NEGATIVE_INFINITY = "-Infinity"; private const string FLOAT_POSITIVE_INFINITY = "Infinity"; private const string FLOAT_NAN = "NaN"; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteFloatValue(this Utf8JsonWriter writer, double x) { if (double.IsNegativeInfinity(x)) writer.WriteStringValue(FLOAT_NEGATIVE_INFINITY); else if (double.IsPositiveInfinity(x)) writer.WriteStringValue(FLOAT_POSITIVE_INFINITY); else if (double.IsNaN(x)) writer.WriteStringValue(FLOAT_NAN); else writer.WriteNumberValue(x); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteFloatValue(this Utf8JsonWriter writer, float x) { if (float.IsNegativeInfinity(x)) writer.WriteStringValue(FLOAT_NEGATIVE_INFINITY); else if (float.IsPositiveInfinity(x)) writer.WriteStringValue(FLOAT_POSITIVE_INFINITY); else if (float.IsNaN(x)) writer.WriteStringValue(FLOAT_NAN); else writer.WriteNumberValue(x); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteFloat(this Utf8JsonWriter writer, string propertyName, double x) { if (double.IsNegativeInfinity(x)) writer.WriteString(propertyName, FLOAT_NEGATIVE_INFINITY); else if (double.IsPositiveInfinity(x)) writer.WriteString(propertyName, FLOAT_POSITIVE_INFINITY); else if (double.IsNaN(x)) writer.WriteString(propertyName, FLOAT_NAN); else writer.WriteNumber(propertyName, x); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteFloat(this Utf8JsonWriter writer, string propertyName, float x) { if (float.IsNegativeInfinity(x)) writer.WriteString(propertyName, FLOAT_NEGATIVE_INFINITY); else if (float.IsPositiveInfinity(x)) writer.WriteString(propertyName, FLOAT_POSITIVE_INFINITY); else if (float.IsNaN(x)) writer.WriteString(propertyName, FLOAT_NAN); else writer.WriteNumber(propertyName, x); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetDoubleExtended(this ref Utf8JsonReader reader) { if (reader.TokenType == JsonTokenType.Number) { return reader.GetDouble(); } else { return reader.GetString() switch { FLOAT_NEGATIVE_INFINITY => double.NegativeInfinity, FLOAT_POSITIVE_INFINITY => double.PositiveInfinity, FLOAT_NAN => double.NaN, _ => throw new Exception($"Invalid floating point value {reader.GetString()}. Error 2b204bf5-8b7e-471b-bdcf-beda7281251f.") }; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetSingleExtended(this ref Utf8JsonReader reader) { if (reader.TokenType == JsonTokenType.Number) { return reader.GetSingle(); } else { return reader.GetString() switch { FLOAT_NEGATIVE_INFINITY => float.NegativeInfinity, FLOAT_POSITIVE_INFINITY => float.PositiveInfinity, FLOAT_NAN => float.NaN, _ => throw new Exception($"Invalid floating point value {reader.GetString()}. Error 403b381c-ef85-4a49-8aef-fd0cac8f0735.") }; } } #region Colors public static void W(this Utf8JsonWriter writer, in C3b value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.R); writer.WriteNumberValue(value.G); writer.WriteNumberValue(value.B); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out C3b value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.R = reader.GetByte(); reader.Read(); value.G = reader.GetByte(); reader.Read(); value.B = reader.GetByte(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in C3d value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.R); writer.WriteFloatValue(value.G); writer.WriteFloatValue(value.B); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out C3d value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.R = reader.GetDoubleExtended(); reader.Read(); value.G = reader.GetDoubleExtended(); reader.Read(); value.B = reader.GetDoubleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in C3f value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.R); writer.WriteFloatValue(value.G); writer.WriteFloatValue(value.B); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out C3f value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.R = reader.GetSingleExtended(); reader.Read(); value.G = reader.GetSingleExtended(); reader.Read(); value.B = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in C3ui value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.R); writer.WriteNumberValue(value.G); writer.WriteNumberValue(value.B); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out C3ui value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.R = reader.GetUInt32(); reader.Read(); value.G = reader.GetUInt32(); reader.Read(); value.B = reader.GetUInt32(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in C3us value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.R); writer.WriteNumberValue(value.G); writer.WriteNumberValue(value.B); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out C3us value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.R = reader.GetUInt16(); reader.Read(); value.G = reader.GetUInt16(); reader.Read(); value.B = reader.GetUInt16(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in C4b value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.R); writer.WriteNumberValue(value.G); writer.WriteNumberValue(value.B); writer.WriteNumberValue(value.A); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out C4b value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.R = reader.GetByte(); reader.Read(); value.G = reader.GetByte(); reader.Read(); value.B = reader.GetByte(); reader.Read(); value.A = reader.GetByte(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in C4d value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.R); writer.WriteFloatValue(value.G); writer.WriteFloatValue(value.B); writer.WriteFloatValue(value.A); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out C4d value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.R = reader.GetDoubleExtended(); reader.Read(); value.G = reader.GetDoubleExtended(); reader.Read(); value.B = reader.GetDoubleExtended(); reader.Read(); value.A = reader.GetDoubleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in C4f value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.R); writer.WriteFloatValue(value.G); writer.WriteFloatValue(value.B); writer.WriteFloatValue(value.A); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out C4f value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.R = reader.GetSingleExtended(); reader.Read(); value.G = reader.GetSingleExtended(); reader.Read(); value.B = reader.GetSingleExtended(); reader.Read(); value.A = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in C4ui value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.R); writer.WriteNumberValue(value.G); writer.WriteNumberValue(value.B); writer.WriteNumberValue(value.A); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out C4ui value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.R = reader.GetUInt32(); reader.Read(); value.G = reader.GetUInt32(); reader.Read(); value.B = reader.GetUInt32(); reader.Read(); value.A = reader.GetUInt32(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in C4us value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.R); writer.WriteNumberValue(value.G); writer.WriteNumberValue(value.B); writer.WriteNumberValue(value.A); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out C4us value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.R = reader.GetUInt16(); reader.Read(); value.G = reader.GetUInt16(); reader.Read(); value.B = reader.GetUInt16(); reader.Read(); value.A = reader.GetUInt16(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in CieLabf value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.L); writer.WriteFloatValue(value.a); writer.WriteFloatValue(value.b); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out CieLabf value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.L = reader.GetSingleExtended(); reader.Read(); value.a = reader.GetSingleExtended(); reader.Read(); value.b = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in CieLuvf value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.L); writer.WriteFloatValue(value.u); writer.WriteFloatValue(value.v); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out CieLuvf value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.L = reader.GetSingleExtended(); reader.Read(); value.u = reader.GetSingleExtended(); reader.Read(); value.v = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in CieXYZf value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.X); writer.WriteFloatValue(value.Y); writer.WriteFloatValue(value.Z); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out CieXYZf value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.X = reader.GetSingleExtended(); reader.Read(); value.Y = reader.GetSingleExtended(); reader.Read(); value.Z = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in CieYxyf value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.Y); writer.WriteFloatValue(value.x); writer.WriteFloatValue(value.y); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out CieYxyf value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.Y = reader.GetSingleExtended(); reader.Read(); value.x = reader.GetSingleExtended(); reader.Read(); value.y = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in CMYKf value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.C); writer.WriteFloatValue(value.M); writer.WriteFloatValue(value.Y); writer.WriteFloatValue(value.K); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out CMYKf value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.C = reader.GetSingleExtended(); reader.Read(); value.M = reader.GetSingleExtended(); reader.Read(); value.Y = reader.GetSingleExtended(); reader.Read(); value.K = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in HSLf value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.H); writer.WriteFloatValue(value.S); writer.WriteFloatValue(value.L); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out HSLf value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.H = reader.GetSingleExtended(); reader.Read(); value.S = reader.GetSingleExtended(); reader.Read(); value.L = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in HSVf value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.H); writer.WriteFloatValue(value.S); writer.WriteFloatValue(value.V); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out HSVf value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.H = reader.GetSingleExtended(); reader.Read(); value.S = reader.GetSingleExtended(); reader.Read(); value.V = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Yuvf value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.Y); writer.WriteFloatValue(value.u); writer.WriteFloatValue(value.v); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out Yuvf value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.Y = reader.GetSingleExtended(); reader.Read(); value.u = reader.GetSingleExtended(); reader.Read(); value.v = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } #endregion #region Euclidean public static void W(this Utf8JsonWriter writer, in Euclidean2d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Rot"); writer.W(value.Rot, options); writer.WritePropertyName("Trans"); writer.W(value.Trans, options); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Euclidean2d result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "rot": case "Rot": reader.R(out result.Rot, options); break; case "trans": case "Trans": reader.R(out result.Trans, options); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Euclidean2f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Rot"); writer.W(value.Rot, options); writer.WritePropertyName("Trans"); writer.W(value.Trans, options); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Euclidean2f result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "rot": case "Rot": reader.R(out result.Rot, options); break; case "trans": case "Trans": reader.R(out result.Trans, options); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Euclidean3d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Rot"); writer.W(value.Rot, options); writer.WritePropertyName("Trans"); writer.W(value.Trans, options); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Euclidean3d result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "rot": case "Rot": reader.R(out result.Rot, options); break; case "trans": case "Trans": reader.R(out result.Trans, options); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Euclidean3f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Rot"); writer.W(value.Rot, options); writer.WritePropertyName("Trans"); writer.W(value.Trans, options); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Euclidean3f result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "rot": case "Rot": reader.R(out result.Rot, options); break; case "trans": case "Trans": reader.R(out result.Trans, options); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } #endregion #region Lines public static void W(this Utf8JsonWriter writer, in Line2d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("P0"); writer.W(value.P0, options); writer.WritePropertyName("P1"); writer.W(value.P1, options); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Line2d result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "p0": case "P0": reader.R(out result.P0, options); break; case "p1": case "P1": reader.R(out result.P1, options); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Line2f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("P0"); writer.W(value.P0, options); writer.WritePropertyName("P1"); writer.W(value.P1, options); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Line2f result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "p0": case "P0": reader.R(out result.P0, options); break; case "p1": case "P1": reader.R(out result.P1, options); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Line3d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("P0"); writer.W(value.P0, options); writer.WritePropertyName("P1"); writer.W(value.P1, options); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Line3d result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "p0": case "P0": reader.R(out result.P0, options); break; case "p1": case "P1": reader.R(out result.P1, options); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Line3f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("P0"); writer.W(value.P0, options); writer.WritePropertyName("P1"); writer.W(value.P1, options); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Line3f result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "p0": case "P0": reader.R(out result.P0, options); break; case "p1": case "P1": reader.R(out result.P1, options); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } #endregion #region Matrices public static void W(this Utf8JsonWriter writer, in M22d value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteFloatValue(xs[i]); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out M22d value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new double[4]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetDoubleExtended(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); value = new M22d(xs); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in M22f value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteFloatValue(xs[i]); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out M22f value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new float[4]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetSingleExtended(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); value = new M22f(xs); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in M33d value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteFloatValue(xs[i]); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out M33d value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new double[9]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetDoubleExtended(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); value = new M33d(xs); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in M33f value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteFloatValue(xs[i]); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out M33f value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new float[9]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetSingleExtended(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); value = new M33f(xs); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in M44d value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteFloatValue(xs[i]); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out M44d value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new double[16]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetDoubleExtended(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); value = new M44d(xs); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in M44f value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteFloatValue(xs[i]); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out M44f value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new float[16]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetSingleExtended(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); value = new M44f(xs); } else { throw new JsonException(); } } #endregion #region Planes public static void W(this Utf8JsonWriter writer, in Plane2d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Normal"); writer.W(value.Normal, options); writer.WriteFloat("Distance", value.Distance); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Plane2d result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "normal": case "Normal": reader.R(out result.Normal, options); break; case "distance": case "Distance": result.Distance = reader.GetDoubleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Plane2f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Normal"); writer.W(value.Normal, options); writer.WriteFloat("Distance", value.Distance); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Plane2f result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "normal": case "Normal": reader.R(out result.Normal, options); break; case "distance": case "Distance": result.Distance = reader.GetSingleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Plane3d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Normal"); writer.W(value.Normal, options); writer.WriteFloat("Distance", value.Distance); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Plane3d result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "normal": case "Normal": reader.R(out result.Normal, options); break; case "distance": case "Distance": result.Distance = reader.GetDoubleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Plane3f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Normal"); writer.W(value.Normal, options); writer.WriteFloat("Distance", value.Distance); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Plane3f result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "normal": case "Normal": reader.R(out result.Normal, options); break; case "distance": case "Distance": result.Distance = reader.GetSingleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, IEnumerable value, JsonSerializerOptions options) { writer.WriteStartArray(); foreach (var x in value) writer.W(x, options); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, ref Plane2d[] result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new List(); while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndArray) break; var x = default(Plane2d); reader.R(ref x, options); xs.Add(x); } result = xs.ToArray(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, IEnumerable value, JsonSerializerOptions options) { writer.WriteStartArray(); foreach (var x in value) writer.W(x, options); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, ref Plane2f[] result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new List(); while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndArray) break; var x = default(Plane2f); reader.R(ref x, options); xs.Add(x); } result = xs.ToArray(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, IEnumerable value, JsonSerializerOptions options) { writer.WriteStartArray(); foreach (var x in value) writer.W(x, options); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, ref Plane3d[] result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new List(); while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndArray) break; var x = default(Plane3d); reader.R(ref x, options); xs.Add(x); } result = xs.ToArray(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, IEnumerable value, JsonSerializerOptions options) { writer.WriteStartArray(); foreach (var x in value) writer.W(x, options); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, ref Plane3f[] result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new List(); while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndArray) break; var x = default(Plane3f); reader.R(ref x, options); xs.Add(x); } result = xs.ToArray(); } else { throw new JsonException(); } } #endregion #region Vectors public static void W(this Utf8JsonWriter writer, in Range1b value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.Min); writer.WriteNumberValue(value.Max); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out Range1b value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.Min = reader.GetByte(); reader.Read(); value.Max = reader.GetByte(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Range1d value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.Min); writer.WriteFloatValue(value.Max); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out Range1d value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.Min = reader.GetDoubleExtended(); reader.Read(); value.Max = reader.GetDoubleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Range1f value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.Min); writer.WriteFloatValue(value.Max); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out Range1f value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.Min = reader.GetSingleExtended(); reader.Read(); value.Max = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Range1i value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.Min); writer.WriteNumberValue(value.Max); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out Range1i value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.Min = reader.GetInt32(); reader.Read(); value.Max = reader.GetInt32(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Range1l value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.Min); writer.WriteNumberValue(value.Max); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out Range1l value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.Min = reader.GetInt64(); reader.Read(); value.Max = reader.GetInt64(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Range1s value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.Min); writer.WriteNumberValue(value.Max); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out Range1s value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.Min = reader.GetInt16(); reader.Read(); value.Max = reader.GetInt16(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Range1sb value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.Min); writer.WriteNumberValue(value.Max); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out Range1sb value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.Min = reader.GetSByte(); reader.Read(); value.Max = reader.GetSByte(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Range1ui value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.Min); writer.WriteNumberValue(value.Max); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out Range1ui value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.Min = reader.GetUInt32(); reader.Read(); value.Max = reader.GetUInt32(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Range1ul value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.Min); writer.WriteNumberValue(value.Max); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out Range1ul value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.Min = reader.GetUInt64(); reader.Read(); value.Max = reader.GetUInt64(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Range1us value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.Min); writer.WriteNumberValue(value.Max); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out Range1us value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.Min = reader.GetUInt16(); reader.Read(); value.Max = reader.GetUInt16(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } #endregion #region Rays public static void W(this Utf8JsonWriter writer, in Ray2d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Origin"); writer.W(value.Origin, options); writer.WritePropertyName("Direction"); writer.W(value.Direction, options); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Ray2d result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "origin": case "Origin": reader.R(out result.Origin, options); break; case "direction": case "Direction": reader.R(out result.Direction, options); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Ray2f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Origin"); writer.W(value.Origin, options); writer.WritePropertyName("Direction"); writer.W(value.Direction, options); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Ray2f result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "origin": case "Origin": reader.R(out result.Origin, options); break; case "direction": case "Direction": reader.R(out result.Direction, options); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Ray3d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Origin"); writer.W(value.Origin, options); writer.WritePropertyName("Direction"); writer.W(value.Direction, options); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Ray3d result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "origin": case "Origin": reader.R(out result.Origin, options); break; case "direction": case "Direction": reader.R(out result.Direction, options); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Ray3f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Origin"); writer.W(value.Origin, options); writer.WritePropertyName("Direction"); writer.W(value.Direction, options); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Ray3f result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "origin": case "Origin": reader.R(out result.Origin, options); break; case "direction": case "Direction": reader.R(out result.Direction, options); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } #endregion #region Rotations, Quaternions public static void W(this Utf8JsonWriter writer, in Rot2d value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.Angle); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out Rot2d value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.Angle = reader.GetDoubleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Rot2f value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.Angle); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out Rot2f value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.Angle = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Rot3d value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.W); writer.WriteFloatValue(value.X); writer.WriteFloatValue(value.Y); writer.WriteFloatValue(value.Z); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out Rot3d value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.W = reader.GetDoubleExtended(); reader.Read(); value.X = reader.GetDoubleExtended(); reader.Read(); value.Y = reader.GetDoubleExtended(); reader.Read(); value.Z = reader.GetDoubleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Rot3f value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.W); writer.WriteFloatValue(value.X); writer.WriteFloatValue(value.Y); writer.WriteFloatValue(value.Z); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out Rot3f value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.W = reader.GetSingleExtended(); reader.Read(); value.X = reader.GetSingleExtended(); reader.Read(); value.Y = reader.GetSingleExtended(); reader.Read(); value.Z = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in QuaternionD value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.W); writer.WriteFloatValue(value.X); writer.WriteFloatValue(value.Y); writer.WriteFloatValue(value.Z); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out QuaternionD value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.W = reader.GetDoubleExtended(); reader.Read(); value.X = reader.GetDoubleExtended(); reader.Read(); value.Y = reader.GetDoubleExtended(); reader.Read(); value.Z = reader.GetDoubleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in QuaternionF value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.W); writer.WriteFloatValue(value.X); writer.WriteFloatValue(value.Y); writer.WriteFloatValue(value.Z); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out QuaternionF value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.W = reader.GetSingleExtended(); reader.Read(); value.X = reader.GetSingleExtended(); reader.Read(); value.Y = reader.GetSingleExtended(); reader.Read(); value.Z = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } #endregion #region Similarity public static void W(this Utf8JsonWriter writer, in Similarity2d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WriteFloat("Scale", value.Scale); writer.WritePropertyName("Euclidean"); writer.W(value.Euclidean, options); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Similarity2d result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "scale": case "Scale": result.Scale = reader.GetDoubleExtended(); break; case "euclidean": case "Euclidean": reader.R(ref result.Euclidean, options); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Similarity2f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WriteFloat("Scale", value.Scale); writer.WritePropertyName("Euclidean"); writer.W(value.Euclidean, options); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Similarity2f result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "scale": case "Scale": result.Scale = reader.GetSingleExtended(); break; case "euclidean": case "Euclidean": reader.R(ref result.Euclidean, options); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Similarity3d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WriteFloat("Scale", value.Scale); writer.WritePropertyName("Euclidean"); writer.W(value.Euclidean, options); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Similarity3d result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "scale": case "Scale": result.Scale = reader.GetDoubleExtended(); break; case "euclidean": case "Euclidean": reader.R(ref result.Euclidean, options); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in Similarity3f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WriteFloat("Scale", value.Scale); writer.WritePropertyName("Euclidean"); writer.W(value.Euclidean, options); writer.WriteEndObject(); } public static void R(this ref Utf8JsonReader reader, ref Similarity3f result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "scale": case "Scale": result.Scale = reader.GetSingleExtended(); break; case "euclidean": case "Euclidean": reader.R(ref result.Euclidean, options); break; default: throw new JsonException($"Invalid property {p}."); } } } else { throw new JsonException(); } } #endregion #region Vectors public static void W(this Utf8JsonWriter writer, in V2d value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.X); writer.WriteFloatValue(value.Y); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out V2d value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.X = reader.GetDoubleExtended(); reader.Read(); value.Y = reader.GetDoubleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in V2f value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.X); writer.WriteFloatValue(value.Y); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out V2f value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.X = reader.GetSingleExtended(); reader.Read(); value.Y = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in V3d value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.X); writer.WriteFloatValue(value.Y); writer.WriteFloatValue(value.Z); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out V3d value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.X = reader.GetDoubleExtended(); reader.Read(); value.Y = reader.GetDoubleExtended(); reader.Read(); value.Z = reader.GetDoubleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, in V3f value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.X); writer.WriteFloatValue(value.Y); writer.WriteFloatValue(value.Z); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, out V3f value, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); value.X = reader.GetSingleExtended(); reader.Read(); value.Y = reader.GetSingleExtended(); reader.Read(); value.Z = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, IEnumerable value, JsonSerializerOptions options) { writer.WriteStartArray(); foreach (var x in value) writer.W(x, options); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, ref V2d[] result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new List(); while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndArray) break; reader.R(out V2d x, options); xs.Add(x); } result = xs.ToArray(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, IEnumerable value, JsonSerializerOptions options) { writer.WriteStartArray(); foreach (var x in value) writer.W(x, options); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, ref V2f[] result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new List(); while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndArray) break; reader.R(out V2f x, options); xs.Add(x); } result = xs.ToArray(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, IEnumerable value, JsonSerializerOptions options) { writer.WriteStartArray(); foreach (var x in value) writer.W(x, options); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, ref V3d[] result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new List(); while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndArray) break; reader.R(out V3d x, options); xs.Add(x); } result = xs.ToArray(); } else { throw new JsonException(); } } public static void W(this Utf8JsonWriter writer, IEnumerable value, JsonSerializerOptions options) { writer.WriteStartArray(); foreach (var x in value) writer.W(x, options); writer.WriteEndArray(); } public static void R(this ref Utf8JsonReader reader, ref V3f[] result, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new List(); while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndArray) break; reader.R(out V3f x, options); xs.Add(x); } result = xs.ToArray(); } else { throw new JsonException(); } } #endregion } //[JsonConverter(typeof(Converter))] //public partial struct _Template //{ //} #region Affine [JsonConverter(typeof(Converter))] public partial struct Affine2d { private class Converter : JsonConverter { public override Affine2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Affine2d result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "linear": case "Linear": reader.R(out result.Linear, options); break; case "trans": case "Trans": reader.R(out result.Trans, options); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Affine2d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Linear"); writer.W(value.Linear, options); writer.WritePropertyName("Trans"); writer.W(value.Trans, options); writer.WriteEndObject(); } } } [JsonConverter(typeof(Converter))] public partial struct Affine2f { private class Converter : JsonConverter { public override Affine2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Affine2f result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "linear": case "Linear": reader.R(out result.Linear, options); break; case "trans": case "Trans": reader.R(out result.Trans, options); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Affine2f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Linear"); writer.W(value.Linear, options); writer.WritePropertyName("Trans"); writer.W(value.Trans, options); writer.WriteEndObject(); } } } [JsonConverter(typeof(Converter))] public partial struct Affine3d { private class Converter : JsonConverter { public override Affine3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Affine3d result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "linear": case "Linear": reader.R(out result.Linear, options); break; case "trans": case "Trans": reader.R(out result.Trans, options); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Affine3d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Linear"); writer.W(value.Linear, options); writer.WritePropertyName("Trans"); writer.W(value.Trans, options); writer.WriteEndObject(); } } } [JsonConverter(typeof(Converter))] public partial struct Affine3f { private class Converter : JsonConverter { public override Affine3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Affine3f result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "linear": case "Linear": reader.R(out result.Linear, options); break; case "trans": case "Trans": reader.R(out result.Trans, options); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Affine3f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Linear"); writer.W(value.Linear, options); writer.WritePropertyName("Trans"); writer.W(value.Trans, options); writer.WriteEndObject(); } } } #endregion #region Box[23][dfil] [JsonConverter(typeof(Converter))] public partial struct Box2d { private class Converter : JsonConverter { public override Box2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var min = new V2d(); reader.Read(); min.X = reader.GetDoubleExtended(); reader.Read(); min.Y = reader.GetDoubleExtended(); var max = new V2d(); reader.Read(); max.X = reader.GetDoubleExtended(); reader.Read(); max.Y = reader.GetDoubleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new Box2d(min, max); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Box2d value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.Min.X); writer.WriteFloatValue(value.Min.Y); writer.WriteFloatValue(value.Max.X); writer.WriteFloatValue(value.Max.Y); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct Box2f { private class Converter : JsonConverter { public override Box2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var min = new V2f(); reader.Read(); min.X = reader.GetSingleExtended(); reader.Read(); min.Y = reader.GetSingleExtended(); var max = new V2f(); reader.Read(); max.X = reader.GetSingleExtended(); reader.Read(); max.Y = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new Box2f(min, max); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Box2f value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.Min.X); writer.WriteFloatValue(value.Min.Y); writer.WriteFloatValue(value.Max.X); writer.WriteFloatValue(value.Max.Y); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct Box2i { private class Converter : JsonConverter { public override Box2i Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var min = new V2i(); reader.Read(); min.X = reader.GetInt32(); reader.Read(); min.Y = reader.GetInt32(); var max = new V2i(); reader.Read(); max.X = reader.GetInt32(); reader.Read(); max.Y = reader.GetInt32(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new Box2i(min, max); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Box2i value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.Min.X); writer.WriteNumberValue(value.Min.Y); writer.WriteNumberValue(value.Max.X); writer.WriteNumberValue(value.Max.Y); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct Box2l { private class Converter : JsonConverter { public override Box2l Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var min = new V2l(); reader.Read(); min.X = reader.GetInt64(); reader.Read(); min.Y = reader.GetInt64(); var max = new V2l(); reader.Read(); max.X = reader.GetInt64(); reader.Read(); max.Y = reader.GetInt64(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new Box2l(min, max); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Box2l value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.Min.X); writer.WriteNumberValue(value.Min.Y); writer.WriteNumberValue(value.Max.X); writer.WriteNumberValue(value.Max.Y); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct Box3d { private class Converter : JsonConverter { public override Box3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var min = new V3d(); reader.Read(); min.X = reader.GetDoubleExtended(); reader.Read(); min.Y = reader.GetDoubleExtended(); reader.Read(); min.Z = reader.GetDoubleExtended(); var max = new V3d(); reader.Read(); max.X = reader.GetDoubleExtended(); reader.Read(); max.Y = reader.GetDoubleExtended(); reader.Read(); max.Z = reader.GetDoubleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new Box3d(min, max); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Box3d value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.Min.X); writer.WriteFloatValue(value.Min.Y); writer.WriteFloatValue(value.Min.Z); writer.WriteFloatValue(value.Max.X); writer.WriteFloatValue(value.Max.Y); writer.WriteFloatValue(value.Max.Z); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct Box3f { private class Converter : JsonConverter { public override Box3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var min = new V3f(); reader.Read(); min.X = reader.GetSingleExtended(); reader.Read(); min.Y = reader.GetSingleExtended(); reader.Read(); min.Z = reader.GetSingleExtended(); var max = new V3f(); reader.Read(); max.X = reader.GetSingleExtended(); reader.Read(); max.Y = reader.GetSingleExtended(); reader.Read(); max.Z = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new Box3f(min, max); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Box3f value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.Min.X); writer.WriteFloatValue(value.Min.Y); writer.WriteFloatValue(value.Min.Z); writer.WriteFloatValue(value.Max.X); writer.WriteFloatValue(value.Max.Y); writer.WriteFloatValue(value.Max.Z); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct Box3i { private class Converter : JsonConverter { public override Box3i Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var min = new V3i(); reader.Read(); min.X = reader.GetInt32(); reader.Read(); min.Y = reader.GetInt32(); reader.Read(); min.Z = reader.GetInt32(); var max = new V3i(); reader.Read(); max.X = reader.GetInt32(); reader.Read(); max.Y = reader.GetInt32(); reader.Read(); max.Z = reader.GetInt32(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new Box3i(min, max); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Box3i value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.Min.X); writer.WriteNumberValue(value.Min.Y); writer.WriteNumberValue(value.Min.Z); writer.WriteNumberValue(value.Max.X); writer.WriteNumberValue(value.Max.Y); writer.WriteNumberValue(value.Max.Z); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct Box3l { private class Converter : JsonConverter { public override Box3l Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var min = new V3l(); reader.Read(); min.X = reader.GetInt64(); reader.Read(); min.Y = reader.GetInt64(); reader.Read(); min.Z = reader.GetInt64(); var max = new V3l(); reader.Read(); max.X = reader.GetInt64(); reader.Read(); max.Y = reader.GetInt64(); reader.Read(); max.Z = reader.GetInt64(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new Box3l(min, max); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Box3l value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.Min.X); writer.WriteNumberValue(value.Min.Y); writer.WriteNumberValue(value.Min.Z); writer.WriteNumberValue(value.Max.X); writer.WriteNumberValue(value.Max.Y); writer.WriteNumberValue(value.Max.Z); writer.WriteEndArray(); } } } #endregion #region Capsules [JsonConverter(typeof(Converter))] public partial struct Capsule3d { private class Converter : JsonConverter { public override Capsule3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Capsule3d result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "p0": case "P0": reader.R(out result.P0, options); break; case "p1": case "P1": reader.R(out result.P1, options); break; case "radius": case "Radius": result.Radius = reader.GetDoubleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Capsule3d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("P0"); writer.W(value.P0, options); writer.WritePropertyName("P1"); writer.W(value.P1, options); writer.WriteFloat("Radius", value.Radius); writer.WriteEndObject(); } } } [JsonConverter(typeof(Converter))] public partial struct Capsule3f { private class Converter : JsonConverter { public override Capsule3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Capsule3f result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "p0": case "P0": reader.R(out result.P0, options); break; case "p1": case "P1": reader.R(out result.P1, options); break; case "radius": case "Radius": result.Radius = reader.GetSingleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Capsule3f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("P0"); writer.W(value.P0, options); writer.WritePropertyName("P1"); writer.W(value.P1, options); writer.WriteFloat("Radius", value.Radius); writer.WriteEndObject(); } } } #endregion #region Cell, Cell2d [JsonConverter(typeof(Converter))] public readonly partial struct Cell2d { private class Converter : JsonConverter { public override Cell2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); var x = reader.GetInt64(); reader.Read(); if (reader.TokenType == JsonTokenType.EndArray) { if (x == int.MinValue) return Invalid; if (x < int.MinValue) throw new JsonException( $"Expected exponent < int.MinValue, but found {x}. " + $"Error e4fa77f3-e47b-47a2-8be7-9414f9715826." ); return new Cell2d(exponent: (int)x); } var y = reader.GetInt64(); reader.Read(); var e = reader.GetInt32(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new Cell2d(x, y, e); } else if (reader.TokenType == JsonTokenType.StartObject) { var x = 0L; var y = 0L; var e = 0; bool hasX = false, hasY = false, hasE = false; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); Debug.Assert(reader.TokenType == JsonTokenType.Number); switch (p) { case "x": case "X": if (hasX) throw new JsonException(); x = reader.GetInt64(); hasX = true; break; case "y": case "Y": if (hasY) throw new JsonException(); y = reader.GetInt64(); hasY = true; break; case "e": case "E": if (hasE) throw new JsonException(); e = reader.GetInt32(); hasE = true; break; default: throw new JsonException($"Invalid property {p}. Error 09514e99-055a-4f0a-8573-0e10bcb29446."); } } if (e == int.MinValue) { if (hasX || hasY) throw new JsonException(); return Invalid; } if (hasX == false || hasY == false || hasE == false) { if (hasE && !hasX && !hasY) { return new Cell2d(e); } else { throw new JsonException("Error 41366f74-f340-4229-8a24-ed6689c8685f."); } } return new Cell2d(x, y, e); } else if (reader.TokenType == JsonTokenType.String) { var s = reader.GetString(); reader.Read(); return Parse(s); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Cell2d value, JsonSerializerOptions options) { if (value.IsCenteredAtOrigin || value.IsInvalid) { writer.WriteStartArray(); writer.WriteNumberValue(value.Exponent); writer.WriteEndArray(); } else { writer.WriteStartArray(); writer.WriteNumberValue(value.X); writer.WriteNumberValue(value.Y); writer.WriteNumberValue(value.Exponent); writer.WriteEndArray(); } } } } [JsonConverter(typeof(Converter))] public readonly partial struct Cell { private class Converter : JsonConverter { public override Cell Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); var x = reader.GetInt64(); reader.Read(); if (reader.TokenType == JsonTokenType.EndArray) { if (x == int.MinValue) return Invalid; if (x < int.MinValue) throw new JsonException( $"Expected exponent < int.MinValue, but found {x}. " + $"Error c9f85be5-2856-405b-adf2-c499ad8107b6." ); return new Cell(exponent: (int)x); } var y = reader.GetInt64(); reader.Read(); var z = reader.GetInt64(); reader.Read(); var e = reader.GetInt32(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new Cell(x, y, z, e); } else if (reader.TokenType == JsonTokenType.StartObject) { var x = 0L; var y = 0L; var z = 0L; var e = 0; bool hasX = false, hasY = false, hasZ = false, hasE = false; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); Debug.Assert(reader.TokenType == JsonTokenType.Number); switch (p) { case "x": case "X": if (hasX) throw new JsonException(); x = reader.GetInt64(); hasX = true; break; case "y": case "Y": if (hasY) throw new JsonException(); y = reader.GetInt64(); hasY = true; break; case "z": case "Z": if (hasZ) throw new JsonException(); z = reader.GetInt64(); hasZ = true; break; case "e": case "E": if (hasE) throw new JsonException(); e = reader.GetInt32(); hasE = true; break; default: throw new JsonException($"Invalid property {p}. Error 17d72803-3cee-4451-9768-81bdb8374c72."); } } if (e == int.MinValue) { if (hasX || hasY || hasZ) throw new JsonException(); return Invalid; } if (hasX == false || hasY == false || hasZ == false || hasE == false) { if (hasE && !hasX && !hasY && !hasZ) { return new Cell(e); } else { throw new JsonException("Error e4446e9c-0dd2-481c-8082-901400b231fa."); } } return new Cell(x, y, z, e); } else if (reader.TokenType == JsonTokenType.String) { var s = reader.GetString(); reader.Read(); return Parse(s); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Cell value, JsonSerializerOptions options) { if (value.IsCenteredAtOrigin || value.IsInvalid) { writer.WriteStartArray(); writer.WriteNumberValue(value.Exponent); writer.WriteEndArray(); } else { writer.WriteStartArray(); writer.WriteNumberValue(value.X); writer.WriteNumberValue(value.Y); writer.WriteNumberValue(value.Z); writer.WriteNumberValue(value.Exponent); writer.WriteEndArray(); } } } } #endregion #region Circles [JsonConverter(typeof(Converter))] public partial struct Circle2d { private class Converter : JsonConverter { public override Circle2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Circle2d result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "center": case "Center": reader.R(out result.Center, options); break; case "radius": case "Radius": result.Radius = reader.GetDoubleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Circle2d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Center"); writer.W(value.Center, options); writer.WriteFloat("Radius", value.Radius); writer.WriteEndObject(); } } } [JsonConverter(typeof(Converter))] public partial struct Circle2f { private class Converter : JsonConverter { public override Circle2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Circle2f result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "center": case "Center": reader.R(out result.Center, options); break; case "radius": case "Radius": result.Radius = reader.GetSingleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Circle2f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Center"); writer.W(value.Center, options); writer.WriteFloat("Radius", value.Radius); writer.WriteEndObject(); } } } [JsonConverter(typeof(Converter))] public partial struct Circle3d { private class Converter : JsonConverter { public override Circle3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Circle3d result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "center": case "Center": reader.R(out result.Center, options); break; case "normal": case "Normal": reader.R(out result.Normal, options); break; case "radius": case "Radius": result.Radius = reader.GetDoubleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Circle3d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Center"); writer.W(value.Center, options); writer.WritePropertyName("Normal"); writer.W(value.Normal, options); writer.WriteFloat("Radius", value.Radius); writer.WriteEndObject(); } } } [JsonConverter(typeof(Converter))] public partial struct Circle3f { private class Converter : JsonConverter { public override Circle3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Circle3f result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "center": case "Center": reader.R(out result.Center, options); break; case "normal": case "Normal": reader.R(out result.Normal, options); break; case "radius": case "Radius": result.Radius = reader.GetSingleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Circle3f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Center"); writer.W(value.Center, options); writer.WritePropertyName("Normal"); writer.W(value.Normal, options); writer.WriteFloat("Radius", value.Radius); writer.WriteEndObject(); } } } #endregion #region Colors [JsonConverter(typeof(Converter))] public partial struct C3b { private class Converter : JsonConverter { public override C3b Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { reader.R(out C3b value, options); return value; } public override void Write(Utf8JsonWriter writer, C3b value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct C3d { private class Converter : JsonConverter { public override C3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { reader.R(out C3d value, options); return value; } public override void Write(Utf8JsonWriter writer, C3d value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct C3f { private class Converter : JsonConverter { public override C3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { C3f value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, C3f value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct C3ui { private class Converter : JsonConverter { public override C3ui Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { C3ui value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, C3ui value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct C3us { private class Converter : JsonConverter { public override C3us Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { C3us value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, C3us value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct C4b { private class Converter : JsonConverter { public override C4b Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { C4b value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, C4b value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct C4d { private class Converter : JsonConverter { public override C4d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { C4d value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, C4d value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct C4f { private class Converter : JsonConverter { public override C4f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { C4f value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, C4f value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct C4ui { private class Converter : JsonConverter { public override C4ui Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { C4ui value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, C4ui value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct C4us { private class Converter : JsonConverter { public override C4us Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { C4us value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, C4us value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct CieLabf { private class Converter : JsonConverter { public override CieLabf Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { CieLabf value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, CieLabf value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct CieLuvf { private class Converter : JsonConverter { public override CieLuvf Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { CieLuvf value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, CieLuvf value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct CieXYZf { private class Converter : JsonConverter { public override CieXYZf Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { CieXYZf value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, CieXYZf value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct CieYxyf { private class Converter : JsonConverter { public override CieYxyf Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { CieYxyf value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, CieYxyf value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct CMYKf { private class Converter : JsonConverter { public override CMYKf Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { CMYKf value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, CMYKf value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct HSLf { private class Converter : JsonConverter { public override HSLf Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { HSLf value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, HSLf value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct HSVf { private class Converter : JsonConverter { public override HSVf Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { HSVf value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, HSVf value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Yuvf { private class Converter : JsonConverter { public override Yuvf Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Yuvf value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, Yuvf value, JsonSerializerOptions options) => writer.W(value, options); } } #endregion #region Cones [JsonConverter(typeof(Converter))] public partial struct Cone3d { private class Converter : JsonConverter { public override Cone3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Cone3d result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "origin": case "Origin": reader.R(out result.Origin, options); break; case "direction": case "Direction": reader.R(out result.Direction, options); break; case "angle": case "Angle": result.Angle = reader.GetDoubleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Cone3d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Origin"); writer.W(value.Origin, options); writer.WritePropertyName("Direction"); writer.W(value.Direction, options); writer.WriteFloat("Angle", value.Angle); writer.WriteEndObject(); } } } [JsonConverter(typeof(Converter))] public partial struct Cone3f { private class Converter : JsonConverter { public override Cone3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Cone3f result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "origin": case "Origin": reader.R(out result.Origin, options); break; case "direction": case "Direction": reader.R(out result.Direction, options); break; case "angle": case "Angle": result.Angle = reader.GetSingleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Cone3f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Origin"); writer.W(value.Origin, options); writer.WritePropertyName("Direction"); writer.W(value.Direction, options); writer.WriteFloat("Angle", value.Angle); writer.WriteEndObject(); } } } #endregion #region Cylinder [JsonConverter(typeof(Converter))] public partial struct Cylinder3d { private class Converter : JsonConverter { public override Cylinder3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Cylinder3d result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "p0": case "P0": reader.R(out result.P0, options); break; case "p1": case "P1": reader.R(out result.P1, options); break; case "radius": case "Radius": result.Radius = reader.GetDoubleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Cylinder3d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("P0"); writer.W(value.P0, options); writer.WritePropertyName("P1"); writer.W(value.P1, options); writer.WriteFloat("Radius", value.Radius); writer.WriteEndObject(); } } } [JsonConverter(typeof(Converter))] public partial struct Cylinder3f { private class Converter : JsonConverter { public override Cylinder3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Cylinder3f result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "p0": case "P0": reader.R(out result.P0, options); break; case "p1": case "P1": reader.R(out result.P1, options); break; case "radius": case "Radius": result.Radius = reader.GetSingleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Cylinder3f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("P0"); writer.W(value.P0, options); writer.WritePropertyName("P1"); writer.W(value.P1, options); writer.WriteFloat("Radius", value.Radius); writer.WriteEndObject(); } } } #endregion #region Euclideans [JsonConverter(typeof(Converter))] public partial struct Euclidean2d { private class Converter : JsonConverter { public override Euclidean2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Euclidean2d value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Euclidean2d value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Euclidean2f { private class Converter : JsonConverter { public override Euclidean2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Euclidean2f value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Euclidean2f value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Euclidean3d { private class Converter : JsonConverter { public override Euclidean3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Euclidean3d value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Euclidean3d value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Euclidean3f { private class Converter : JsonConverter { public override Euclidean3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Euclidean3f value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Euclidean3f value, JsonSerializerOptions options) => writer.W(value, options); } } #endregion #region Hulls [JsonConverter(typeof(Converter))] public partial struct Hull2d { private class Converter : JsonConverter { public override Hull2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Hull2d value = default; reader.R(ref value.PlaneArray, options); return value; } public override void Write(Utf8JsonWriter writer, Hull2d value, JsonSerializerOptions options) => writer.W(value.PlaneArray, options); } } [JsonConverter(typeof(Converter))] public partial struct Hull2f { private class Converter : JsonConverter { public override Hull2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Hull2f value = default; reader.R(ref value.PlaneArray, options); return value; } public override void Write(Utf8JsonWriter writer, Hull2f value, JsonSerializerOptions options) => writer.W(value.PlaneArray, options); } } [JsonConverter(typeof(Converter))] public partial struct Hull3d { private class Converter : JsonConverter { public override Hull3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Hull3d value = default; reader.R(ref value.PlaneArray, options); return value; } public override void Write(Utf8JsonWriter writer, Hull3d value, JsonSerializerOptions options) => writer.W(value.PlaneArray, options); } } [JsonConverter(typeof(Converter))] public partial struct Hull3f { private class Converter : JsonConverter { public override Hull3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Hull3f value = default; reader.R(ref value.PlaneArray, options); return value; } public override void Write(Utf8JsonWriter writer, Hull3f value, JsonSerializerOptions options) => writer.W(value.PlaneArray, options); } } #endregion #region Lines [JsonConverter(typeof(Converter))] public partial struct Line2d { private class Converter : JsonConverter { public override Line2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Line2d value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Line2d value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Line2f { private class Converter : JsonConverter { public override Line2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Line2f value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Line2f value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Line3d { private class Converter : JsonConverter { public override Line3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Line3d value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Line3d value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Line3f { private class Converter : JsonConverter { public override Line3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Line3f value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Line3f value, JsonSerializerOptions options) => writer.W(value, options); } } #endregion #region M[22|23|33|34|44][dfil] [JsonConverter(typeof(Converter))] public partial struct M22d { private class Converter : JsonConverter { public override M22d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new double[4]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetDoubleExtended(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M22d(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M22d value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteFloatValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M22f { private class Converter : JsonConverter { public override M22f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new float[4]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetSingleExtended(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M22f(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M22f value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteFloatValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M22i { private class Converter : JsonConverter { public override M22i Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new int[4]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetInt32(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M22i(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M22i value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteNumberValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M22l { private class Converter : JsonConverter { public override M22l Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new long[4]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetInt64(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M22l(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M22l value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteNumberValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M23d { private class Converter : JsonConverter { public override M23d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new double[6]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetDoubleExtended(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M23d(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M23d value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteFloatValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M23f { private class Converter : JsonConverter { public override M23f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new float[6]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetSingleExtended(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M23f(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M23f value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteFloatValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M23i { private class Converter : JsonConverter { public override M23i Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new int[6]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetInt32(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M23i(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M23i value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteNumberValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M23l { private class Converter : JsonConverter { public override M23l Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new long[6]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetInt64(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M23l(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M23l value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteNumberValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M33d { private class Converter : JsonConverter { public override M33d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new double[9]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetDoubleExtended(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M33d(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M33d value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteFloatValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M33f { private class Converter : JsonConverter { public override M33f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new float[9]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetSingleExtended(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M33f(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M33f value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteFloatValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M33i { private class Converter : JsonConverter { public override M33i Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new int[9]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetInt32(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M33i(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M33i value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteNumberValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M33l { private class Converter : JsonConverter { public override M33l Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new long[9]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetInt64(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M33l(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M33l value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteNumberValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M34d { private class Converter : JsonConverter { public override M34d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new double[12]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetDoubleExtended(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M34d(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M34d value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteFloatValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M34f { private class Converter : JsonConverter { public override M34f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new float[12]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetSingleExtended(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M34f(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M34f value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteFloatValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M34i { private class Converter : JsonConverter { public override M34i Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new int[12]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetInt32(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M34i(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M34i value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteNumberValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M34l { private class Converter : JsonConverter { public override M34l Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new long[12]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetInt64(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M34l(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M34l value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteNumberValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M44d { private class Converter : JsonConverter { public override M44d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new double[16]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetDoubleExtended(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M44d(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M44d value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteFloatValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M44f { private class Converter : JsonConverter { public override M44f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new float[16]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetSingleExtended(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M44f(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M44f value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteFloatValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M44i { private class Converter : JsonConverter { public override M44i Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new int[16]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetInt32(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M44i(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M44i value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteNumberValue(xs[i]); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct M44l { private class Converter : JsonConverter { public override M44l Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { var xs = new long[16]; for (var i = 0; i < xs.Length; i++) { reader.Read(); xs[i] = reader.GetInt64(); } reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new M44l(xs); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, M44l value, JsonSerializerOptions options) { writer.WriteStartArray(); var xs = value.ToArray(); for (var i = 0; i < xs.Length; i++) writer.WriteNumberValue(xs[i]); writer.WriteEndArray(); } } } #endregion #region Planes [JsonConverter(typeof(Converter))] public partial struct Plane2d { private class Converter : JsonConverter { public override Plane2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Plane2d value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Plane2d value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Plane2f { private class Converter : JsonConverter { public override Plane2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Plane2f value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Plane2f value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Plane3d { private class Converter : JsonConverter { public override Plane3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Plane3d value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Plane3d value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Plane3f { private class Converter : JsonConverter { public override Plane3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Plane3f value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Plane3f value, JsonSerializerOptions options) => writer.W(value, options); } } #endregion #region Polygons [JsonConverter(typeof(Converter))] public partial struct Polygon2d { private class Converter : JsonConverter { public override Polygon2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { V2d[] value = default; reader.R(ref value, options); return new Polygon2d(value); } public override void Write(Utf8JsonWriter writer, Polygon2d value, JsonSerializerOptions options) => writer.W(value.Points, options); } } [JsonConverter(typeof(Converter))] public partial struct Polygon2f { private class Converter : JsonConverter { public override Polygon2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { V2f[] value = default; reader.R(ref value, options); return new Polygon2f(value); } public override void Write(Utf8JsonWriter writer, Polygon2f value, JsonSerializerOptions options) => writer.W(value.Points, options); } } [JsonConverter(typeof(Converter))] public partial struct Polygon3d { private class Converter : JsonConverter { public override Polygon3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { V3d[] value = default; reader.R(ref value, options); return new Polygon3d(value); } public override void Write(Utf8JsonWriter writer, Polygon3d value, JsonSerializerOptions options) => writer.W(value.Points, options); } } [JsonConverter(typeof(Converter))] public partial struct Polygon3f { private class Converter : JsonConverter { public override Polygon3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { V3f[] value = default; reader.R(ref value, options); return new Polygon3f(value); } public override void Write(Utf8JsonWriter writer, Polygon3f value, JsonSerializerOptions options) => writer.W(value.Points, options); } } #endregion #region Quads [JsonConverter(typeof(Converter))] public partial struct Quad2d { private class Converter : JsonConverter { public override Quad2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { V2d[] value = default; reader.R(ref value, options); return new Quad2d(value); } public override void Write(Utf8JsonWriter writer, Quad2d value, JsonSerializerOptions options) => writer.W(value.Points, options); } } [JsonConverter(typeof(Converter))] public partial struct Quad2f { private class Converter : JsonConverter { public override Quad2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { V2f[] value = default; reader.R(ref value, options); return new Quad2f(value); } public override void Write(Utf8JsonWriter writer, Quad2f value, JsonSerializerOptions options) => writer.W(value.Points, options); } } [JsonConverter(typeof(Converter))] public partial struct Quad3d { private class Converter : JsonConverter { public override Quad3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { V3d[] value = default; reader.R(ref value, options); return new Quad3d(value); } public override void Write(Utf8JsonWriter writer, Quad3d value, JsonSerializerOptions options) => writer.W(value.Points, options); } } [JsonConverter(typeof(Converter))] public partial struct Quad3f { private class Converter : JsonConverter { public override Quad3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { V3f[] value = default; reader.R(ref value, options); return new Quad3f(value); } public override void Write(Utf8JsonWriter writer, Quad3f value, JsonSerializerOptions options) => writer.W(value.Points, options); } } #endregion #region Ranges [JsonConverter(typeof(Converter))] public partial struct Range1b { private class Converter : JsonConverter { public override Range1b Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Range1b value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, Range1b value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Range1d { private class Converter : JsonConverter { public override Range1d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Range1d value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, Range1d value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Range1f { private class Converter : JsonConverter { public override Range1f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Range1f value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, Range1f value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Range1i { private class Converter : JsonConverter { public override Range1i Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Range1i value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, Range1i value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Range1l { private class Converter : JsonConverter { public override Range1l Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Range1l value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, Range1l value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Range1s { private class Converter : JsonConverter { public override Range1s Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Range1s value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, Range1s value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Range1sb { private class Converter : JsonConverter { public override Range1sb Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Range1sb value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, Range1sb value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Range1ui { private class Converter : JsonConverter { public override Range1ui Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Range1ui value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, Range1ui value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Range1ul { private class Converter : JsonConverter { public override Range1ul Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Range1ul value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, Range1ul value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Range1us { private class Converter : JsonConverter { public override Range1us Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Range1us value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, Range1us value, JsonSerializerOptions options) => writer.W(value, options); } } #endregion #region Rays [JsonConverter(typeof(Converter))] public partial struct Ray2d { private class Converter : JsonConverter { public override Ray2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Ray2d value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Ray2d value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Ray2f { private class Converter : JsonConverter { public override Ray2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Ray2f value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Ray2f value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Ray3d { private class Converter : JsonConverter { public override Ray3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Ray3d value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Ray3d value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Ray3f { private class Converter : JsonConverter { public override Ray3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Ray3f value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Ray3f value, JsonSerializerOptions options) => writer.W(value, options); } } #endregion #region Rotations, Quaternions [JsonConverter(typeof(Converter))] public partial struct Rot2d { private class Converter : JsonConverter { public override Rot2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Rot2d value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, Rot2d value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Rot2f { private class Converter : JsonConverter { public override Rot2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Rot2f value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, Rot2f value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Rot3d { private class Converter : JsonConverter { public override Rot3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Rot3d value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, Rot3d value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Rot3f { private class Converter : JsonConverter { public override Rot3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Rot3f value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, Rot3f value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct QuaternionD { private class Converter : JsonConverter { public override QuaternionD Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { QuaternionD value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, QuaternionD value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct QuaternionF { private class Converter : JsonConverter { public override QuaternionF Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { QuaternionF value = default; reader.R(out value, options); return value; } public override void Write(Utf8JsonWriter writer, QuaternionF value, JsonSerializerOptions options) => writer.W(value, options); } } #endregion #region Scales [JsonConverter(typeof(Converter))] public partial struct Scale2d { private class Converter : JsonConverter { public override Scale2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { reader.R(out V2d value, options); return new Scale2d(value); } public override void Write(Utf8JsonWriter writer, Scale2d value, JsonSerializerOptions options) => writer.W(value.V, options); } } [JsonConverter(typeof(Converter))] public partial struct Scale2f { private class Converter : JsonConverter { public override Scale2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { reader.R(out V2f value, options); return new Scale2f(value); } public override void Write(Utf8JsonWriter writer, Scale2f value, JsonSerializerOptions options) => writer.W(value.V, options); } } [JsonConverter(typeof(Converter))] public partial struct Scale3d { private class Converter : JsonConverter { public override Scale3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { reader.R(out V3d value, options); return new Scale3d(value); } public override void Write(Utf8JsonWriter writer, Scale3d value, JsonSerializerOptions options) => writer.W(value.V, options); } } [JsonConverter(typeof(Converter))] public partial struct Scale3f { private class Converter : JsonConverter { public override Scale3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { reader.R(out V3f value, options); return new Scale3f(value); } public override void Write(Utf8JsonWriter writer, Scale3f value, JsonSerializerOptions options) => writer.W(value.V, options); } } #endregion #region Shifts [JsonConverter(typeof(Converter))] public partial struct Shift2d { private class Converter : JsonConverter { public override Shift2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { reader.R(out V2d value, options); return new Shift2d(value); } public override void Write(Utf8JsonWriter writer, Shift2d value, JsonSerializerOptions options) => writer.W(value.V, options); } } [JsonConverter(typeof(Converter))] public partial struct Shift2f { private class Converter : JsonConverter { public override Shift2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { reader.R(out V2f value, options); return new Shift2f(value); } public override void Write(Utf8JsonWriter writer, Shift2f value, JsonSerializerOptions options) => writer.W(value.V, options); } } [JsonConverter(typeof(Converter))] public partial struct Shift3d { private class Converter : JsonConverter { public override Shift3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { reader.R(out V3d value, options); return new Shift3d(value); } public override void Write(Utf8JsonWriter writer, Shift3d value, JsonSerializerOptions options) => writer.W(value.V, options); } } [JsonConverter(typeof(Converter))] public partial struct Shift3f { private class Converter : JsonConverter { public override Shift3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { reader.R(out V3f value, options); return new Shift3f(value); } public override void Write(Utf8JsonWriter writer, Shift3f value, JsonSerializerOptions options) => writer.W(value.V, options); } } #endregion #region Similarities [JsonConverter(typeof(Converter))] public partial struct Similarity2d { private class Converter : JsonConverter { public override Similarity2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Similarity2d value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Similarity2d value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Similarity2f { private class Converter : JsonConverter { public override Similarity2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Similarity2f value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Similarity2f value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Similarity3d { private class Converter : JsonConverter { public override Similarity3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Similarity3d value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Similarity3d value, JsonSerializerOptions options) => writer.W(value, options); } } [JsonConverter(typeof(Converter))] public partial struct Similarity3f { private class Converter : JsonConverter { public override Similarity3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Similarity3f value = default; reader.R(ref value, options); return value; } public override void Write(Utf8JsonWriter writer, Similarity3f value, JsonSerializerOptions options) => writer.W(value, options); } } #endregion #region Spheres [JsonConverter(typeof(Converter))] public partial struct Sphere3d { private class Converter : JsonConverter { public override Sphere3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Sphere3d result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "center": case "Center": reader.R(out result.Center, options); break; case "radius": case "Radius": result.Radius = reader.GetDoubleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Sphere3d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Center"); writer.W(value.Center, options); writer.WriteFloat("Radius", value.Radius); writer.WriteEndObject(); } } } [JsonConverter(typeof(Converter))] public partial struct Sphere3f { private class Converter : JsonConverter { public override Sphere3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Sphere3f result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "center": case "Center": reader.R(out result.Center, options); break; case "radius": case "Radius": result.Radius = reader.GetSingleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Sphere3f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Center"); writer.W(value.Center, options); writer.WriteFloat("Radius", value.Radius); writer.WriteEndObject(); } } } #endregion #region Tori [JsonConverter(typeof(Converter))] public partial struct Torus3d { private class Converter : JsonConverter { public override Torus3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Torus3d result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "position": case "Position": reader.R(out result.Position, options); break; case "direction": case "Direction": reader.R(out result.Direction, options); break; case "majorRadius": case "MajorRadius": result.MajorRadius = reader.GetDoubleExtended(); break; case "minorRadius": case "MinorRadius": result.MinorRadius = reader.GetDoubleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Torus3d value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Position"); writer.W(value.Position, options); writer.WritePropertyName("Direction"); writer.W(value.Direction, options); writer.WriteFloat("MajorRadius", value.MajorRadius); writer.WriteFloat("MinorRadius", value.MinorRadius); writer.WriteEndObject(); } } } [JsonConverter(typeof(Converter))] public partial struct Torus3f { private class Converter : JsonConverter { public override Torus3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Torus3f result = default; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); var p = reader.GetString(); reader.Read(); switch (p) { case "position": case "Position": reader.R(out result.Position, options); break; case "direction": case "Direction": reader.R(out result.Direction, options); break; case "majorRadius": case "MajorRadius": result.MajorRadius = reader.GetSingleExtended(); break; case "minorRadius": case "MinorRadius": result.MinorRadius = reader.GetSingleExtended(); break; default: throw new JsonException($"Invalid property {p}."); } } return result; } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, Torus3f value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WritePropertyName("Position"); writer.W(value.Position, options); writer.WritePropertyName("Direction"); writer.W(value.Direction, options); writer.WriteFloat("MajorRadius", value.MajorRadius); writer.WriteFloat("MinorRadius", value.MinorRadius); writer.WriteEndObject(); } } } #endregion #region Trafos [JsonConverter(typeof(Converter))] public readonly partial struct Trafo2d { private class Converter : JsonConverter { public override Trafo2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { M33d forward; M33d backward; reader.Read(); if (reader.TokenType != JsonTokenType.StartArray) throw new JsonException(); reader.R(out forward, options); reader.Read(); if (reader.TokenType != JsonTokenType.StartArray) throw new JsonException(); reader.R(out backward, options); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new Trafo2d(forward, backward); } public override void Write(Utf8JsonWriter writer, Trafo2d value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.W(value.Forward, options); writer.W(value.Backward, options); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public readonly partial struct Trafo2f { private class Converter : JsonConverter { public override Trafo2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { M33f forward; M33f backward; reader.Read(); if (reader.TokenType != JsonTokenType.StartArray) throw new JsonException(); reader.R(out forward, options); reader.Read(); if (reader.TokenType != JsonTokenType.StartArray) throw new JsonException(); reader.R(out backward, options); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new Trafo2f(forward, backward); } public override void Write(Utf8JsonWriter writer, Trafo2f value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.W(value.Forward, options); writer.W(value.Backward, options); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public readonly partial struct Trafo3d { private class Converter : JsonConverter { public override Trafo3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { M44d forward; M44d backward; reader.Read(); if (reader.TokenType != JsonTokenType.StartArray) throw new JsonException(); reader.R(out forward, options); reader.Read(); if (reader.TokenType != JsonTokenType.StartArray) throw new JsonException(); reader.R(out backward, options); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new Trafo3d(forward, backward); } public override void Write(Utf8JsonWriter writer, Trafo3d value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.W(value.Forward, options); writer.W(value.Backward, options); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public readonly partial struct Trafo3f { private class Converter : JsonConverter { public override Trafo3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { M44f forward; M44f backward; reader.Read(); if (reader.TokenType != JsonTokenType.StartArray) throw new JsonException(); reader.R(out forward, options); reader.Read(); if (reader.TokenType != JsonTokenType.StartArray) throw new JsonException(); reader.R(out backward, options); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new Trafo3f(forward, backward); } public override void Write(Utf8JsonWriter writer, Trafo3f value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.W(value.Forward, options); writer.W(value.Backward, options); writer.WriteEndArray(); } } } #endregion #region Triangles [JsonConverter(typeof(Converter))] public partial struct Triangle2d { private class Converter : JsonConverter { public override Triangle2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { V2d[] value = default; reader.R(ref value, options); return new Triangle2d(value); } public override void Write(Utf8JsonWriter writer, Triangle2d value, JsonSerializerOptions options) => writer.W(value.Points, options); } } [JsonConverter(typeof(Converter))] public partial struct Triangle2f { private class Converter : JsonConverter { public override Triangle2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { V2f[] value = default; reader.R(ref value, options); return new Triangle2f(value); } public override void Write(Utf8JsonWriter writer, Triangle2f value, JsonSerializerOptions options) => writer.W(value.Points, options); } } [JsonConverter(typeof(Converter))] public partial struct Triangle3d { private class Converter : JsonConverter { public override Triangle3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { V3d[] value = default; reader.R(ref value, options); return new Triangle3d(value); } public override void Write(Utf8JsonWriter writer, Triangle3d value, JsonSerializerOptions options) => writer.W(value.Points, options); } } [JsonConverter(typeof(Converter))] public partial struct Triangle3f { private class Converter : JsonConverter { public override Triangle3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { V3f[] value = default; reader.R(ref value, options); return new Triangle3f(value); } public override void Write(Utf8JsonWriter writer, Triangle3f value, JsonSerializerOptions options) => writer.W(value.Points, options); } } #endregion #region V[234][dfil] [JsonConverter(typeof(Converter))] public partial struct V2d { private class Converter : JsonConverter { public override V2d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); var x = reader.GetDoubleExtended(); reader.Read(); var y = reader.GetDoubleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new V2d(x, y); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, V2d value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.X); writer.WriteFloatValue(value.Y); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct V2f { private class Converter : JsonConverter { public override V2f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); var x = reader.GetSingleExtended(); reader.Read(); var y = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new V2f(x, y); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, V2f value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.X); writer.WriteFloatValue(value.Y); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct V2i { private class Converter : JsonConverter { public override V2i Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); var x = reader.GetInt32(); reader.Read(); var y = reader.GetInt32(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new V2i(x, y); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, V2i value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.X); writer.WriteNumberValue(value.Y); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct V2l { private class Converter : JsonConverter { public override V2l Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); var x = reader.GetInt64(); reader.Read(); var y = reader.GetInt64(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new V2l(x, y); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, V2l value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.X); writer.WriteNumberValue(value.Y); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct V3d { private class Converter : JsonConverter { public override V3d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); var x = reader.GetDoubleExtended(); reader.Read(); var y = reader.GetDoubleExtended(); reader.Read(); var z = reader.GetDoubleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new V3d(x, y, z); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, V3d value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.X); writer.WriteFloatValue(value.Y); writer.WriteFloatValue(value.Z); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct V3f { private class Converter : JsonConverter { public override V3f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); var x = reader.GetSingleExtended(); reader.Read(); var y = reader.GetSingleExtended(); reader.Read(); var z = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new V3f(x, y, z); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, V3f value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.X); writer.WriteFloatValue(value.Y); writer.WriteFloatValue(value.Z); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct V3i { private class Converter : JsonConverter { public override V3i Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); var x = reader.GetInt32(); reader.Read(); var y = reader.GetInt32(); reader.Read(); var z = reader.GetInt32(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new V3i(x, y, z); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, V3i value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.X); writer.WriteNumberValue(value.Y); writer.WriteNumberValue(value.Z); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct V3l { private class Converter : JsonConverter { public override V3l Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); var x = reader.GetInt64(); reader.Read(); var y = reader.GetInt64(); reader.Read(); var z = reader.GetInt64(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new V3l(x, y, z); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, V3l value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.X); writer.WriteNumberValue(value.Y); writer.WriteNumberValue(value.Z); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct V4d { private class Converter : JsonConverter { public override V4d Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); var x = reader.GetDoubleExtended(); reader.Read(); var y = reader.GetDoubleExtended(); reader.Read(); var z = reader.GetDoubleExtended(); reader.Read(); var w = reader.GetDoubleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new V4d(x, y, z, w); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, V4d value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.X); writer.WriteFloatValue(value.Y); writer.WriteFloatValue(value.Z); writer.WriteFloatValue(value.W); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct V4f { private class Converter : JsonConverter { public override V4f Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); var x = reader.GetSingleExtended(); reader.Read(); var y = reader.GetSingleExtended(); reader.Read(); var z = reader.GetSingleExtended(); reader.Read(); var w = reader.GetSingleExtended(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new V4f(x, y, z, w); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, V4f value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteFloatValue(value.X); writer.WriteFloatValue(value.Y); writer.WriteFloatValue(value.Z); writer.WriteFloatValue(value.W); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct V4i { private class Converter : JsonConverter { public override V4i Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); var x = reader.GetInt32(); reader.Read(); var y = reader.GetInt32(); reader.Read(); var z = reader.GetInt32(); reader.Read(); var w = reader.GetInt32(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new V4i(x, y, z, w); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, V4i value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.X); writer.WriteNumberValue(value.Y); writer.WriteNumberValue(value.Z); writer.WriteNumberValue(value.W); writer.WriteEndArray(); } } } [JsonConverter(typeof(Converter))] public partial struct V4l { private class Converter : JsonConverter { public override V4l Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); var x = reader.GetInt64(); reader.Read(); var y = reader.GetInt64(); reader.Read(); var z = reader.GetInt64(); reader.Read(); var w = reader.GetInt64(); reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) throw new JsonException(); return new V4l(x, y, z, w); } else { throw new JsonException(); } } public override void Write(Utf8JsonWriter writer, V4l value, JsonSerializerOptions options) { writer.WriteStartArray(); writer.WriteNumberValue(value.X); writer.WriteNumberValue(value.Y); writer.WriteNumberValue(value.Z); writer.WriteNumberValue(value.W); writer.WriteEndArray(); } } } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Base/Adler32.cs ================================================ using System; using System.IO; namespace Aardvark.Base { /// /// Computes Adler32 checksum for a stream of data. An Adler32 /// checksum is not as reliable as a CRC32 checksum, but a lot faster to /// compute. /// /// The specification for Adler32 may be found in RFC 1950. /// /// /// From that document: /// /// "ADLER32 (Adler-32 checksum) /// This contains a checksum value of the uncompressed data /// (excluding any dictionary data) computed according to Adler-32 /// algorithm. This algorithm is a 32-bit extension and improvement /// of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073 /// standard. /// /// Adler-32 is composed of two sums accumulated per byte: s1 is /// the sum of all bytes, s2 is the sum of all s1 values. Both sums /// are done modulo 65521. s1 is initialized to 1, s2 to zero. The /// Adler-32 checksum is stored as s2*65536 + s1 in most- /// significant-byte first (network) order." /// /// "8.2. The Adler-32 algorithm /// /// The Adler-32 algorithm is much faster than the CRC32 algorithm yet /// still provides an extremely low probability of undetected errors. /// /// The modulo on unsigned long accumulators can be delayed for 5552 /// bytes, so the modulo operation time is negligible. If the bytes /// are a, b, c, the second sum is 3a + 2b + c + 3, and so is position /// and order sensitive, unlike the first sum, which is just a /// checksum. That 65521 is prime is important to avoid a possible /// large class of two-byte errors that leave the check unchanged. /// (The Fletcher checksum uses 255, which is not prime and which also /// makes the Fletcher check insensitive to single byte changes 0 - /// 255.) /// /// The sum s1 is initialized to 1 instead of zero to make the length /// of the sequence part of s2, so that the length does not have to be /// checked separately. (Any sequence of zeroes has a Fletcher /// checksum of zero.)" /// public sealed class Adler32 { private const uint BASE = 65521; private uint m_checksum; /// /// Creates a new instance of the Adler32 class. /// The checksum starts off with a value of 1. /// public Adler32() { Reset(); } /// /// Returns the Adler32 data checksum computed so far. /// public uint Checksum { get { return m_checksum; } } /// /// Resets the Adler32 checksum to the initial value. /// public void Reset() { m_checksum = 1; } /// /// Updates the checksum with the byte b. /// public void Update(byte bval) { uint s1 = m_checksum & 0xFFFF; uint s2 = m_checksum >> 16; s1 = (s1 + ((uint)bval & 0xFF)) % BASE; s2 = (s1 + s2) % BASE; m_checksum = (s2 << 16) + s1; } /// /// Updates the checksum with the bytes taken from the stream. /// public void Update(Stream stream) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } int count; var buffer = new byte[1024]; while ((count = stream.Read(buffer, 0, 1024)) > 0) Update(buffer, 0, count); } /// /// Updates the checksum with the bytes taken from the array. /// public void Update(byte[] buffer) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } Update(buffer, 0, buffer.Length); } /// /// Updates the checksum with the bytes taken from the array. /// public void Update(byte[] buffer, int offset, int length) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset)); } if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } if (offset > buffer.Length - length) { throw new ArgumentOutOfRangeException(); } uint s1 = m_checksum & 0xFFFF; uint s2 = m_checksum >> 16; while (length > 0) { // We can defer the modulo operation: // s1 maximally grows from 65521 to 65521 + 255 * 3800 // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31 int n = 3800; if (n > length) n = length; length -= n; while (--n >= 0) { s1 = s1 + (uint)(buffer[offset++] & 0xFF); s2 = s2 + s1; } s1 %= BASE; s2 %= BASE; } m_checksum = (s2 << 16) | s1; } /// /// Updates the checksum with the bytes taken from the array. /// public void Update(ReadOnlySpan buffer) { if (buffer == null) { throw new ArgumentNullException("buffer"); } uint s1 = m_checksum & 0xFFFF; uint s2 = m_checksum >> 16; var offset = 0; var length = buffer.Length; while (length > 0) { // We can defer the modulo operation: // s1 maximally grows from 65521 to 65521 + 255 * 3800 // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31 int n = 3800; if (n > length) n = length; length -= n; while (--n >= 0) { s1 = s1 + (uint)(buffer[offset++] & 0xFF); s2 = s2 + s1; } s1 %= BASE; s2 %= BASE; } m_checksum = (s2 << 16) | s1; } } } ================================================ FILE: src/Aardvark.Base/Math/Base/AliasTable_auto.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Aardvark.Base { // AUTOGENERATED CODE - DO NOT CHANGE! /// /// Walker 1974: https://en.wikipedia.org/wiki/Alias_method /// Algorithm to sample a discrete probability distribution function (PDF) in O(1). /// The PDF does not need to be normalized, but the normalization factor "1/Sum(pdf)" needs to be supplied. /// public class AliasTableF { float[] _probablity; // U[i] int[] _alias; // K[i] public float[] U => _probablity; public int[] K => _alias; /// /// Creates an alias table from a genral PDF that does not integrate to 1. /// The normalization factor will be calculated for the construction. /// public AliasTableF FromPdf(float[] pdf, IRandomUniform rnd = null) { return new AliasTableF(pdf, 1 / pdf.Sum(), rnd); } /// /// Creates an alias table from an already normalized PDF (integrates to 1). /// public AliasTableF FromNormalizedPdf(float[] pdf, IRandomUniform rnd = null) { return new AliasTableF(pdf, 1, rnd); } /// /// Create an alias table from a PDf and its normalization factor: 1.0 / Sum(pdf) /// public AliasTableF(float[] pdf, float pdfNorm, IRandomUniform rnd = null) { var n = pdf.Length; _probablity = new float[n]; _alias = new int[n]; Update(pdf, pdfNorm, rnd); } /// /// Updates the alias table with the given PDF and its norm. /// The length of the PDF is expected to match the length of AliasTable. /// public void Update(float[] pdf, float pdfNorm, IRandomUniform rnd = null) { if (pdf.Length != _alias.Length) throw new ArgumentException("The length of the PDF does not match the length of the AliasTable!"); if (rnd == null) rnd = new RandomSystem(); var n = pdf.Length; var overfull = new List(n); var underfull = new List(n); for (int i = 0; i < n; i++) { var ui = pdf[i] * pdfNorm * n; _probablity[i] = ui; if (ui > 1) overfull.Add(i); else if (ui < 1) underfull.Add(i); } while (overfull.Count > 0 && underfull.Count > 0) { var ii = rnd.UniformInt(overfull.Count); // random overfull var jj = rnd.UniformInt(underfull.Count); // random underfull var ri = overfull[ii]; var rj = underfull[jj]; underfull[jj] = underfull[underfull.Count - 1]; underfull.RemoveAt(underfull.Count - 1); // rj will become exactly full (with own probability + alias for remainder) _alias[rj] = ri; // K[j] = i var uri = _probablity[ri]; var urj = _probablity[rj]; var uinew = uri + urj - 1; // U[i] + U[j] - 1 _probablity[ri] = uinew; if (uinew <= 1) // otherwise keep in overfull { overfull[ii] = overfull[overfull.Count - 1]; overfull.RemoveAt(overfull.Count - 1); if (uinew < 1) underfull.Add(ri); } } while (underfull.Count > 0) { var i = underfull[underfull.Count - 1]; _probablity[i] = 1; underfull.RemoveAt(underfull.Count - 1); } while (overfull.Count > 0) { var i = overfull[overfull.Count - 1]; _probablity[i] = 1; overfull.RemoveAt(overfull.Count - 1); } } /// /// Sample pdf using the alias table with random variable x: [0, 1) in O(1). /// NOTE: About x2-4 faster than sampling a CDF with a binary search. /// public int Sample(float x1) { var nx = _probablity.Length * x1; var i = (int)nx; var y = nx - i; return y < _probablity[i] ? i : _alias[i]; } } /// /// Walker 1974: https://en.wikipedia.org/wiki/Alias_method /// Algorithm to sample a discrete probability distribution function (PDF) in O(1). /// The PDF does not need to be normalized, but the normalization factor "1/Sum(pdf)" needs to be supplied. /// public class AliasTableD { double[] _probablity; // U[i] int[] _alias; // K[i] public double[] U => _probablity; public int[] K => _alias; /// /// Creates an alias table from a genral PDF that does not integrate to 1. /// The normalization factor will be calculated for the construction. /// public AliasTableD FromPdf(double[] pdf, IRandomUniform rnd = null) { return new AliasTableD(pdf, 1 / pdf.Sum(), rnd); } /// /// Creates an alias table from an already normalized PDF (integrates to 1). /// public AliasTableD FromNormalizedPdf(double[] pdf, IRandomUniform rnd = null) { return new AliasTableD(pdf, 1, rnd); } /// /// Create an alias table from a PDf and its normalization factor: 1.0 / Sum(pdf) /// public AliasTableD(double[] pdf, double pdfNorm, IRandomUniform rnd = null) { var n = pdf.Length; _probablity = new double[n]; _alias = new int[n]; Update(pdf, pdfNorm, rnd); } /// /// Updates the alias table with the given PDF and its norm. /// The length of the PDF is expected to match the length of AliasTable. /// public void Update(double[] pdf, double pdfNorm, IRandomUniform rnd = null) { if (pdf.Length != _alias.Length) throw new ArgumentException("The length of the PDF does not match the length of the AliasTable!"); if (rnd == null) rnd = new RandomSystem(); var n = pdf.Length; var overfull = new List(n); var underfull = new List(n); for (int i = 0; i < n; i++) { var ui = pdf[i] * pdfNorm * n; _probablity[i] = ui; if (ui > 1) overfull.Add(i); else if (ui < 1) underfull.Add(i); } while (overfull.Count > 0 && underfull.Count > 0) { var ii = rnd.UniformInt(overfull.Count); // random overfull var jj = rnd.UniformInt(underfull.Count); // random underfull var ri = overfull[ii]; var rj = underfull[jj]; underfull[jj] = underfull[underfull.Count - 1]; underfull.RemoveAt(underfull.Count - 1); // rj will become exactly full (with own probability + alias for remainder) _alias[rj] = ri; // K[j] = i var uri = _probablity[ri]; var urj = _probablity[rj]; var uinew = uri + urj - 1; // U[i] + U[j] - 1 _probablity[ri] = uinew; if (uinew <= 1) // otherwise keep in overfull { overfull[ii] = overfull[overfull.Count - 1]; overfull.RemoveAt(overfull.Count - 1); if (uinew < 1) underfull.Add(ri); } } while (underfull.Count > 0) { var i = underfull[underfull.Count - 1]; _probablity[i] = 1; underfull.RemoveAt(underfull.Count - 1); } while (overfull.Count > 0) { var i = overfull[overfull.Count - 1]; _probablity[i] = 1; overfull.RemoveAt(overfull.Count - 1); } } /// /// Sample pdf using the alias table with random variable x: [0, 1) in O(1). /// NOTE: About x2-4 faster than sampling a CDF with a binary search. /// public int Sample(double x1) { var nx = _probablity.Length * x1; var i = (int)nx; var y = nx - i; return y < _probablity[i] ? i : _alias[i]; } } } ================================================ FILE: src/Aardvark.Base/Math/Base/AliasTable_template.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Aardvark.Base { // AUTOGENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? Meta.DoubleType : Meta.FloatType; //# var ft = ftype.Name; //# var at = isDouble ? "AliasTableD" : "AliasTableF"; /// /// Walker 1974: https://en.wikipedia.org/wiki/Alias_method /// Algorithm to sample a discrete probability distribution function (PDF) in O(1). /// The PDF does not need to be normalized, but the normalization factor "1/Sum(pdf)" needs to be supplied. /// public class __at__ { __ft__[] _probablity; // U[i] int[] _alias; // K[i] public __ft__[] U => _probablity; public int[] K => _alias; /// /// Creates an alias table from a genral PDF that does not integrate to 1. /// The normalization factor will be calculated for the construction. /// public __at__ FromPdf(__ft__[] pdf, IRandomUniform rnd = null) { return new __at__(pdf, 1 / pdf.Sum(), rnd); } /// /// Creates an alias table from an already normalized PDF (integrates to 1). /// public __at__ FromNormalizedPdf(__ft__[] pdf, IRandomUniform rnd = null) { return new __at__(pdf, 1, rnd); } /// /// Create an alias table from a PDf and its normalization factor: 1.0 / Sum(pdf) /// public __at__(__ft__[] pdf, __ft__ pdfNorm, IRandomUniform rnd = null) { var n = pdf.Length; _probablity = new __ft__[n]; _alias = new int[n]; Update(pdf, pdfNorm, rnd); } /// /// Updates the alias table with the given PDF and its norm. /// The length of the PDF is expected to match the length of AliasTable. /// public void Update(__ft__[] pdf, __ft__ pdfNorm, IRandomUniform rnd = null) { if (pdf.Length != _alias.Length) throw new ArgumentException("The length of the PDF does not match the length of the AliasTable!"); if (rnd == null) rnd = new RandomSystem(); var n = pdf.Length; var overfull = new List(n); var underfull = new List(n); for (int i = 0; i < n; i++) { var ui = pdf[i] * pdfNorm * n; _probablity[i] = ui; if (ui > 1) overfull.Add(i); else if (ui < 1) underfull.Add(i); } while (overfull.Count > 0 && underfull.Count > 0) { var ii = rnd.UniformInt(overfull.Count); // random overfull var jj = rnd.UniformInt(underfull.Count); // random underfull var ri = overfull[ii]; var rj = underfull[jj]; underfull[jj] = underfull[underfull.Count - 1]; underfull.RemoveAt(underfull.Count - 1); // rj will become exactly full (with own probability + alias for remainder) _alias[rj] = ri; // K[j] = i var uri = _probablity[ri]; var urj = _probablity[rj]; var uinew = uri + urj - 1; // U[i] + U[j] - 1 _probablity[ri] = uinew; if (uinew <= 1) // otherwise keep in overfull { overfull[ii] = overfull[overfull.Count - 1]; overfull.RemoveAt(overfull.Count - 1); if (uinew < 1) underfull.Add(ri); } } while (underfull.Count > 0) { var i = underfull[underfull.Count - 1]; _probablity[i] = 1; underfull.RemoveAt(underfull.Count - 1); } while (overfull.Count > 0) { var i = overfull[overfull.Count - 1]; _probablity[i] = 1; overfull.RemoveAt(overfull.Count - 1); } } /// /// Sample pdf using the alias table with random variable x: [0, 1) in O(1). /// NOTE: About x2-4 faster than sampling a CDF with a binary search. /// public int Sample(__ft__ x1) { var nx = _probablity.Length * x1; var i = (int)nx; var y = nx - i; return y < _probablity[i] ? i : _alias[i]; } } //# } // isDouble } ================================================ FILE: src/Aardvark.Base/Math/Base/Complex_auto.cs ================================================ using System; using System.Linq; using System.Globalization; using System.ComponentModel; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { [DataContract] [StructLayout(LayoutKind.Sequential)] public struct ComplexF : IEquatable { [DataMember] public float Real; [DataMember] public float Imag; #region Constructors /// /// Constructs a from a real scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public ComplexF(float real) { Real = real; Imag = 0; } /// /// Constructs a from a real and an imaginary part. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public ComplexF(float real, float imag) { Real = real; Imag = imag; } /// /// Constructs a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public ComplexF(ComplexD complex) { Real = (float)complex.Real; Imag = (float)complex.Imag; } #endregion #region Constants /// /// Returns 0 + 0i. /// public static ComplexF Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ComplexF(0, 0); } /// /// Returns 1 + 0i. /// public static ComplexF One { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ComplexF(1, 0); } /// /// Returns 0 + 1i. /// public static ComplexF I { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ComplexF(0, 1); } /// /// Returns ∞ + 0i. /// public static ComplexF PositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ComplexF(float.PositiveInfinity); } /// /// Returns -∞ + 0i. /// public static ComplexF NegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ComplexF(float.NegativeInfinity); } /// /// Returns 0 + ∞i. /// public static ComplexF PositiveInfinityI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ComplexF(0, float.PositiveInfinity); } /// /// Returns 0 - ∞i. /// public static ComplexF NegativeInfinityI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ComplexF(0, float.NegativeInfinity); } #endregion #region Properties /// /// Returns the conjugated of the complex number. /// public readonly ComplexF Conjugated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new ComplexF(Real, -Imag); } } /// /// Returns the reciprocal of the complex number. /// public readonly ComplexF Reciprocal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { float t = 1 / NormSquared; return new ComplexF(Real * t, -Imag * t); } } /// /// Returns the squared Gaussian Norm (modulus) of the complex number. /// public readonly float NormSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Real * Real + Imag * Imag; } } /// /// Returns the Gaussian Norm (modulus) of the complex number. /// [XmlIgnore] public float Norm { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Fun.Sqrt(Real * Real + Imag * Imag); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { float r = Norm; Real = value * Real / r; Imag = value * Imag / r; } } /// /// Retruns the argument of the complex number. /// [XmlIgnore] public float Argument { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Fun.Atan2(Imag, Real); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { float r = Norm; Real = r * Fun.Cos(value); Imag = r * Fun.Sin(value); } } /// /// Returns whether the complex number has no imaginary part. /// public readonly bool IsReal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Imag.IsTiny(); } } /// /// Returns whether the complex number has no real part. /// public readonly bool IsImaginary { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Real.IsTiny(); } } /// /// Returns whether the complex number is 1 + 0i. /// public readonly bool IsOne { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Real.ApproximateEquals(1) && Imag.IsTiny(); } } /// /// Returns whether the complex number is zero. /// public readonly bool IsZero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Real.IsTiny() && Imag.IsTiny(); } } /// /// Returns whether the complex number is 0 + 1i. /// public readonly bool IsI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Real.IsTiny(Real) && Imag.ApproximateEquals(1); } } /// /// Returns whether the complex number has a part that is NaN. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (float.IsNaN(Real) || float.IsNaN(Imag)); } } /// /// Returns whether the complex number has a part that is infinite (positive or negative). /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (float.IsInfinity(Real) || float.IsInfinity(Imag)); } } /// /// Returns whether the complex number has a part that is infinite and positive. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (float.IsPositiveInfinity(Real) || float.IsPositiveInfinity(Imag)); } } /// /// Returns whether the complex number has a part that is infinite and negative. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (float.IsNegativeInfinity(Real) || float.IsNegativeInfinity(Imag)); } } /// /// Returns whether the complex number is finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !(IsNaN || IsInfinity); } } #endregion #region Static factories /// /// Creates a Radial Complex /// /// Norm of the complex number /// Argument of the complex number /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF CreateRadial(float r, float phi) => new ComplexF(r * Fun.Cos(phi), r * Fun.Sin(phi)); /// /// Creates a Orthogonal Complex /// /// Real-Part /// Imaginary-Part /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF CreateOrthogonal(float real, float imag) => new ComplexF(real, imag); #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Acos(ComplexF x) => x.Acos(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Acoshb(ComplexF x) => x.Acosh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Cos(ComplexF x) => x.Cos(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Cosh(ComplexF x) => x.Cosh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Asin(ComplexF x) => x.Asin(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Asinhb(ComplexF x) => x.Asinh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Sin(ComplexF x) => x.Sin(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Sinh(ComplexF x) => x.Sinh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Atan(ComplexF x) => x.Atan(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Atanhb(ComplexF x) => x.Atanh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Tan(ComplexF x) => x.Tan(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Tanh(ComplexF x) => x.Tanh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Sqrt(ComplexF x) => x.Sqrt(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF CubeRoot(ComplexF x) => x.Cbrt(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Exp(ComplexF x) => x.Exp(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Log(ComplexF x) => x.Log(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF LogBinary(ComplexF x) => x.Log2(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Log10(ComplexF x) => x.Log10(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF DivideByInt(ComplexF x, int y) => x / y; #endregion #region Operators /// /// Conversion from a to a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ComplexD(ComplexF c) => new ComplexD(c); /// /// Implicit conversion from a to a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator ComplexF(float a) => new ComplexF(a); /// /// Adds two complex numbers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF operator +(ComplexF a, ComplexF b) => new ComplexF(a.Real + b.Real, a.Imag + b.Imag); /// /// Adds a complex number and a real number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF operator +(ComplexF a, float b) => new ComplexF(a.Real + b, a.Imag); /// /// Adds a real number and a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF operator +(float a, ComplexF b) => new ComplexF(a + b.Real, b.Imag); /// /// Subtracts two complex numbers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF operator -(ComplexF a, ComplexF b) => new ComplexF(a.Real - b.Real, a.Imag - b.Imag); /// /// Subtracts a real number from a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF operator -(ComplexF a, float b) => new ComplexF(a.Real - b, a.Imag); /// /// Subtracts a complex number from a real number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF operator -(float a, ComplexF b) => new ComplexF(a - b.Real, -b.Imag); /// /// Multiplies two complex numbers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF operator *(ComplexF a, ComplexF b) => new ComplexF( a.Real * b.Real - a.Imag * b.Imag, a.Real * b.Imag + a.Imag * b.Real); /// /// Multiplies a complex number and a real number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF operator *(ComplexF a, float b) => new ComplexF(a.Real * b, a.Imag * b); /// /// Multiplies a real number and a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF operator *(float a, ComplexF b) => new ComplexF(a * b.Real, a * b.Imag); /// /// Divides two complex numbers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF operator /(ComplexF a, ComplexF b) { float t = 1 / b.NormSquared; return new ComplexF( t * (a.Real * b.Real + a.Imag * b.Imag), t * (a.Imag * b.Real - a.Real * b.Imag)); } /// /// Divides a complex number by a real number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF operator /(ComplexF a, float b) => new ComplexF(a.Real / b, a.Imag / b); /// /// Divides a real number by a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF operator /(float a, ComplexF b) { float t = 1 / b.NormSquared; return new ComplexF( t * (a * b.Real), t * (-a * b.Imag)); } /// /// Negates a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF operator -(ComplexF a) => new ComplexF(-a.Real, -a.Imag); /// /// Returns the conjugate of a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF operator !(ComplexF a) => a.Conjugated; #endregion #region Comparison Operators /// /// Returns whether two are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(ComplexF a, ComplexF b) => a.Real == b.Real && a.Imag == b.Imag; /// /// Returns whether two are not equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(ComplexF a, ComplexF b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() => HashCode.GetCombined(Real, Imag); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(ComplexF other) => Real.Equals(other.Real) && Imag.Equals(other.Imag); public override readonly bool Equals(object other) { if (other is ComplexF obj) return Equals(obj); else return false; } public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Real, Imag); } public static ComplexF Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(2); return new ComplexF( float.Parse(x[0], CultureInfo.InvariantCulture), float.Parse(x[1], CultureInfo.InvariantCulture) ); } #endregion } public static partial class Complex { #region Conjugate /// /// Returns the conjugate of a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Conjugated(ComplexF c) => c.Conjugated; #endregion #region Norm /// /// Returns the squared Gaussian Norm (modulus) of the complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormSquared(ComplexF c) => c.NormSquared; /// /// Returns the Gaussian Norm (modulus) of the complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm(ComplexF c) => c.Norm; #endregion #region Argument /// /// Retruns the argument of the complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Argument(ComplexF c) => c.Argument; #endregion } public static partial class Fun { #region Power /// /// Returns the complex number raised to the power of . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Pow(this ComplexF number, ComplexF exponent) { if (number.IsZero) return ComplexF.Zero; else if (exponent.IsZero) return ComplexF.One; else { float r = number.Norm; float phi = number.Argument; float a = exponent.Real; float b = exponent.Imag; return ComplexF.CreateRadial(Exp(Log(r) * a - b * phi), a * phi + b * Log(r)); } } /// /// Returns the complex number raised to the power of . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Pow(this ComplexF number, float exponent) { if (number.IsZero) return ComplexF.Zero; else { float r = number.Norm; float phi = number.Argument; return ComplexF.CreateRadial(Pow(r, exponent), exponent * phi); } } /// /// Returns raised to the power of . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Pow(this float number, ComplexF exponent) { if (number == 0) return ComplexF.Zero; else { float a = exponent.Real; float b = exponent.Imag; if (number < 0) { var phi = ConstantF.Pi; return ComplexF.CreateRadial(Exp(Log(-number) * a - b * phi), a * phi + b * Log(-number)); } else return ComplexF.CreateRadial(Pow(number, a), b * Log(number)); } } [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Power(this ComplexF number, ComplexF exponent) => Pow(number, exponent); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Power(this ComplexF number, float exponent) => Pow(number, exponent); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Power(this float number, ComplexF exponent) => Pow(number, exponent); #endregion #region Trigonometry /// /// Returns the angle that is the arc cosine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Acos(this ComplexF x) { var t = Log(new ComplexF(-x.Imag, x.Real) + Sqrt(1 - x * x)); return new ComplexF(-t.Imag + ConstantF.PiHalf, t.Real); } /// /// Returns the angle that is the hyperbolic arc cosine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Acosh(this ComplexF x) => Log(x + Sqrt(x * x - 1)); /// /// Returns the cosine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Cos(this ComplexF x) => ( Exp(new ComplexF(-x.Imag, x.Real)) + Exp(new ComplexF(x.Imag, -x.Real)) ) * 0.5f; /// /// Returns the hyperbolic cosine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Cosh(this ComplexF x) => Cos(new ComplexF(-x.Imag, x.Real)); /// /// Returns the angle that is the arc sine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Asin(this ComplexF x) { var t = Log(new ComplexF(-x.Imag, x.Real) + Sqrt(1 - x * x)); return new ComplexF(t.Imag, -t.Real); } /// /// Returns the angle that is the hyperbolic arc sine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Asinh(this ComplexF x) => Log(x + Sqrt(1 + x * x)); /// /// Returns the sine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Sin(this ComplexF x) { var a = Exp(new ComplexF(-x.Imag, x.Real)) - Exp(new ComplexF(x.Imag, -x.Real)); return new ComplexF(a.Imag, -a.Real) * 0.5f; } /// /// Returns the hyperbolic sine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Sinh(this ComplexF x) { var sin = Sin(new ComplexF(-x.Imag, x.Real)); return new ComplexF(sin.Imag, -sin.Real); } /// /// Returns the angle that is the arc tangent of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Atan(this ComplexF x) { if (x == ComplexF.I) return ComplexF.PositiveInfinityI; else if (x == -ComplexF.I) return ComplexF.NegativeInfinityI; else if (x == ComplexF.PositiveInfinity) return new ComplexF(ConstantF.PiHalf); else if (x == ComplexF.NegativeInfinity) return new ComplexF(-ConstantF.PiHalf); else return new ComplexF(0, 0.5f) * Log((ComplexF.I + x) / (ComplexF.I - x)); } /// /// Returns the angle that is the hyperbolic arc tangent of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Atanh(this ComplexF x) { if (x == ComplexF.Zero) return ComplexF.Zero; else if (x == ComplexF.One) return ComplexF.PositiveInfinity; else if (x == ComplexF.PositiveInfinity) return new ComplexF(0, -ConstantF.PiHalf); else if (x == ComplexF.I) return new ComplexF(0, ConstantF.PiQuarter); else return 0.5f * (Log(1 + x) - Log(1 - x)); } /// /// Returns the tangent of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Tan(this ComplexF x) { if (x == ComplexF.PositiveInfinityI) return ComplexF.I; else if (x == ComplexF.NegativeInfinityI) return -ComplexF.I; else return Sin(x) / Cos(x); } /// /// Returns the hyperbolic tangent of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Tanh(this ComplexF x) { var tan = Tan(new ComplexF(-x.Imag, x.Real)); return new ComplexF(tan.Imag, -tan.Real); } #endregion #region Exp, Log /// /// Returns e raised to the power of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Exp(this ComplexF x) => new ComplexF(Cos(x.Imag), Sin(x.Imag)) * Exp(x.Real); /// /// Returns the natural logarithm of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Log(this ComplexF x) => new ComplexF(Log(x.Norm), x.Argument); /// /// Returns the logarithm of the complex number in the given basis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Log(this ComplexF x, float basis) => x.Log() / basis.Log(); /// /// Returns the base-10 logarithm of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Log10(this ComplexF x) => Log(x, 10); /// /// Returns the base-2 logarithm of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Log2(this ComplexF x) => x.Log() * ConstantF.Ln2Inv; #endregion #region Roots /// /// Returns the principal square root of the complex number . /// // https://math.stackexchange.com/a/44500 // TODO: Check if this is actually better than the naive implementation [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Sqrt(this ComplexF x) { if (x.Imag == 0) { if (x.Real < 0) return new ComplexF(0, Sqrt(-x.Real)); else return new ComplexF(Sqrt(x.Real), 0); } else { var a = x.Norm; var b = x + a; return a.Sqrt() * (b / b.Norm); } } /// /// Returns the principal cubic root of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Cbrt(this ComplexF x) => ComplexF.CreateRadial(Cbrt(x.Norm), x.Argument / 3); /// /// Returns the square root of the given real number and returns a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF Csqrt(this float number) { if (number >= 0) { return new ComplexF(Sqrt(number), 0); } else { return new ComplexF(0, Sqrt(-number)); } } /// /// Calculates both square roots of a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF[] Csqrt(this ComplexF number) { ComplexF res0 = ComplexF.CreateRadial(Sqrt(number.Norm), number.Argument / 2); ComplexF res1 = ComplexF.CreateRadial(Sqrt(number.Norm), number.Argument / 2 + ConstantF.Pi); return new ComplexF[2] { res0, res1 }; } /// /// Calculates the n-th root of a complex number and returns n solutions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexF[] Root(this ComplexF number, int n) { ComplexF[] values = new ComplexF[n]; float invN = 1 / (float)n; float phi = number.Argument / n; float dphi = ConstantF.PiTimesTwo * invN; float r = Pow(number.Norm, invN); for (int i = 0; i < n; i++) { values[i] = ComplexF.CreateRadial(r, phi + dphi * i); } return values; } #endregion #region ApproximateEquals /// /// Returns whether the given complex numbers are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this ComplexF a, ComplexF b, float tolerance) { return ApproximateEquals(a.Real, b.Real, tolerance) && ApproximateEquals(a.Imag, b.Imag, tolerance); } /// /// Returns whether the given complex numbers are equal within /// Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this ComplexF a, ComplexF b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Special Floating Point Value Checks /// /// Returns whether the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(ComplexF v) => v.IsNaN; /// /// Returns whether the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(ComplexF v) => v.IsInfinity; /// /// Returns whether the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(ComplexF v) => v.IsPositiveInfinity; /// /// Returns whether the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(ComplexF v) => v.IsNegativeInfinity; /// /// Returns whether the given is finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(ComplexF v) => v.IsFinite; #endregion } [DataContract] [StructLayout(LayoutKind.Sequential)] public struct ComplexD : IEquatable { [DataMember] public double Real; [DataMember] public double Imag; #region Constructors /// /// Constructs a from a real scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public ComplexD(double real) { Real = real; Imag = 0; } /// /// Constructs a from a real and an imaginary part. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public ComplexD(double real, double imag) { Real = real; Imag = imag; } /// /// Constructs a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public ComplexD(ComplexF complex) { Real = (double)complex.Real; Imag = (double)complex.Imag; } #endregion #region Constants /// /// Returns 0 + 0i. /// public static ComplexD Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ComplexD(0, 0); } /// /// Returns 1 + 0i. /// public static ComplexD One { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ComplexD(1, 0); } /// /// Returns 0 + 1i. /// public static ComplexD I { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ComplexD(0, 1); } /// /// Returns ∞ + 0i. /// public static ComplexD PositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ComplexD(double.PositiveInfinity); } /// /// Returns -∞ + 0i. /// public static ComplexD NegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ComplexD(double.NegativeInfinity); } /// /// Returns 0 + ∞i. /// public static ComplexD PositiveInfinityI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ComplexD(0, double.PositiveInfinity); } /// /// Returns 0 - ∞i. /// public static ComplexD NegativeInfinityI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ComplexD(0, double.NegativeInfinity); } #endregion #region Properties /// /// Returns the conjugated of the complex number. /// public readonly ComplexD Conjugated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new ComplexD(Real, -Imag); } } /// /// Returns the reciprocal of the complex number. /// public readonly ComplexD Reciprocal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { double t = 1 / NormSquared; return new ComplexD(Real * t, -Imag * t); } } /// /// Returns the squared Gaussian Norm (modulus) of the complex number. /// public readonly double NormSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Real * Real + Imag * Imag; } } /// /// Returns the Gaussian Norm (modulus) of the complex number. /// [XmlIgnore] public double Norm { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Fun.Sqrt(Real * Real + Imag * Imag); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { double r = Norm; Real = value * Real / r; Imag = value * Imag / r; } } /// /// Retruns the argument of the complex number. /// [XmlIgnore] public double Argument { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Fun.Atan2(Imag, Real); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { double r = Norm; Real = r * Fun.Cos(value); Imag = r * Fun.Sin(value); } } /// /// Returns whether the complex number has no imaginary part. /// public readonly bool IsReal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Imag.IsTiny(); } } /// /// Returns whether the complex number has no real part. /// public readonly bool IsImaginary { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Real.IsTiny(); } } /// /// Returns whether the complex number is 1 + 0i. /// public readonly bool IsOne { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Real.ApproximateEquals(1) && Imag.IsTiny(); } } /// /// Returns whether the complex number is zero. /// public readonly bool IsZero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Real.IsTiny() && Imag.IsTiny(); } } /// /// Returns whether the complex number is 0 + 1i. /// public readonly bool IsI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Real.IsTiny(Real) && Imag.ApproximateEquals(1); } } /// /// Returns whether the complex number has a part that is NaN. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (double.IsNaN(Real) || double.IsNaN(Imag)); } } /// /// Returns whether the complex number has a part that is infinite (positive or negative). /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (double.IsInfinity(Real) || double.IsInfinity(Imag)); } } /// /// Returns whether the complex number has a part that is infinite and positive. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (double.IsPositiveInfinity(Real) || double.IsPositiveInfinity(Imag)); } } /// /// Returns whether the complex number has a part that is infinite and negative. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (double.IsNegativeInfinity(Real) || double.IsNegativeInfinity(Imag)); } } /// /// Returns whether the complex number is finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !(IsNaN || IsInfinity); } } #endregion #region Static factories /// /// Creates a Radial Complex /// /// Norm of the complex number /// Argument of the complex number /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD CreateRadial(double r, double phi) => new ComplexD(r * Fun.Cos(phi), r * Fun.Sin(phi)); /// /// Creates a Orthogonal Complex /// /// Real-Part /// Imaginary-Part /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD CreateOrthogonal(double real, double imag) => new ComplexD(real, imag); #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Acos(ComplexD x) => x.Acos(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Acoshb(ComplexD x) => x.Acosh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Cos(ComplexD x) => x.Cos(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Cosh(ComplexD x) => x.Cosh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Asin(ComplexD x) => x.Asin(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Asinhb(ComplexD x) => x.Asinh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Sin(ComplexD x) => x.Sin(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Sinh(ComplexD x) => x.Sinh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Atan(ComplexD x) => x.Atan(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Atanhb(ComplexD x) => x.Atanh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Tan(ComplexD x) => x.Tan(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Tanh(ComplexD x) => x.Tanh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Sqrt(ComplexD x) => x.Sqrt(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD CubeRoot(ComplexD x) => x.Cbrt(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Exp(ComplexD x) => x.Exp(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Log(ComplexD x) => x.Log(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD LogBinary(ComplexD x) => x.Log2(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Log10(ComplexD x) => x.Log10(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD DivideByInt(ComplexD x, int y) => x / y; #endregion #region Operators /// /// Conversion from a to a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ComplexF(ComplexD c) => new ComplexF(c); /// /// Implicit conversion from a to a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator ComplexD(double a) => new ComplexD(a); /// /// Adds two complex numbers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD operator +(ComplexD a, ComplexD b) => new ComplexD(a.Real + b.Real, a.Imag + b.Imag); /// /// Adds a complex number and a real number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD operator +(ComplexD a, double b) => new ComplexD(a.Real + b, a.Imag); /// /// Adds a real number and a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD operator +(double a, ComplexD b) => new ComplexD(a + b.Real, b.Imag); /// /// Subtracts two complex numbers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD operator -(ComplexD a, ComplexD b) => new ComplexD(a.Real - b.Real, a.Imag - b.Imag); /// /// Subtracts a real number from a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD operator -(ComplexD a, double b) => new ComplexD(a.Real - b, a.Imag); /// /// Subtracts a complex number from a real number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD operator -(double a, ComplexD b) => new ComplexD(a - b.Real, -b.Imag); /// /// Multiplies two complex numbers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD operator *(ComplexD a, ComplexD b) => new ComplexD( a.Real * b.Real - a.Imag * b.Imag, a.Real * b.Imag + a.Imag * b.Real); /// /// Multiplies a complex number and a real number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD operator *(ComplexD a, double b) => new ComplexD(a.Real * b, a.Imag * b); /// /// Multiplies a real number and a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD operator *(double a, ComplexD b) => new ComplexD(a * b.Real, a * b.Imag); /// /// Divides two complex numbers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD operator /(ComplexD a, ComplexD b) { double t = 1 / b.NormSquared; return new ComplexD( t * (a.Real * b.Real + a.Imag * b.Imag), t * (a.Imag * b.Real - a.Real * b.Imag)); } /// /// Divides a complex number by a real number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD operator /(ComplexD a, double b) => new ComplexD(a.Real / b, a.Imag / b); /// /// Divides a real number by a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD operator /(double a, ComplexD b) { double t = 1 / b.NormSquared; return new ComplexD( t * (a * b.Real), t * (-a * b.Imag)); } /// /// Negates a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD operator -(ComplexD a) => new ComplexD(-a.Real, -a.Imag); /// /// Returns the conjugate of a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD operator !(ComplexD a) => a.Conjugated; #endregion #region Comparison Operators /// /// Returns whether two are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(ComplexD a, ComplexD b) => a.Real == b.Real && a.Imag == b.Imag; /// /// Returns whether two are not equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(ComplexD a, ComplexD b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() => HashCode.GetCombined(Real, Imag); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(ComplexD other) => Real.Equals(other.Real) && Imag.Equals(other.Imag); public override readonly bool Equals(object other) { if (other is ComplexD obj) return Equals(obj); else return false; } public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Real, Imag); } public static ComplexD Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(2); return new ComplexD( double.Parse(x[0], CultureInfo.InvariantCulture), double.Parse(x[1], CultureInfo.InvariantCulture) ); } #endregion } public static partial class Complex { #region Conjugate /// /// Returns the conjugate of a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Conjugated(ComplexD c) => c.Conjugated; #endregion #region Norm /// /// Returns the squared Gaussian Norm (modulus) of the complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormSquared(ComplexD c) => c.NormSquared; /// /// Returns the Gaussian Norm (modulus) of the complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(ComplexD c) => c.Norm; #endregion #region Argument /// /// Retruns the argument of the complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Argument(ComplexD c) => c.Argument; #endregion } public static partial class Fun { #region Power /// /// Returns the complex number raised to the power of . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Pow(this ComplexD number, ComplexD exponent) { if (number.IsZero) return ComplexD.Zero; else if (exponent.IsZero) return ComplexD.One; else { double r = number.Norm; double phi = number.Argument; double a = exponent.Real; double b = exponent.Imag; return ComplexD.CreateRadial(Exp(Log(r) * a - b * phi), a * phi + b * Log(r)); } } /// /// Returns the complex number raised to the power of . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Pow(this ComplexD number, double exponent) { if (number.IsZero) return ComplexD.Zero; else { double r = number.Norm; double phi = number.Argument; return ComplexD.CreateRadial(Pow(r, exponent), exponent * phi); } } /// /// Returns raised to the power of . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Pow(this double number, ComplexD exponent) { if (number == 0) return ComplexD.Zero; else { double a = exponent.Real; double b = exponent.Imag; if (number < 0) { var phi = Constant.Pi; return ComplexD.CreateRadial(Exp(Log(-number) * a - b * phi), a * phi + b * Log(-number)); } else return ComplexD.CreateRadial(Pow(number, a), b * Log(number)); } } [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Power(this ComplexD number, ComplexD exponent) => Pow(number, exponent); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Power(this ComplexD number, double exponent) => Pow(number, exponent); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Power(this double number, ComplexD exponent) => Pow(number, exponent); #endregion #region Trigonometry /// /// Returns the angle that is the arc cosine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Acos(this ComplexD x) { var t = Log(new ComplexD(-x.Imag, x.Real) + Sqrt(1 - x * x)); return new ComplexD(-t.Imag + Constant.PiHalf, t.Real); } /// /// Returns the angle that is the hyperbolic arc cosine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Acosh(this ComplexD x) => Log(x + Sqrt(x * x - 1)); /// /// Returns the cosine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Cos(this ComplexD x) => ( Exp(new ComplexD(-x.Imag, x.Real)) + Exp(new ComplexD(x.Imag, -x.Real)) ) * 0.5; /// /// Returns the hyperbolic cosine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Cosh(this ComplexD x) => Cos(new ComplexD(-x.Imag, x.Real)); /// /// Returns the angle that is the arc sine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Asin(this ComplexD x) { var t = Log(new ComplexD(-x.Imag, x.Real) + Sqrt(1 - x * x)); return new ComplexD(t.Imag, -t.Real); } /// /// Returns the angle that is the hyperbolic arc sine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Asinh(this ComplexD x) => Log(x + Sqrt(1 + x * x)); /// /// Returns the sine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Sin(this ComplexD x) { var a = Exp(new ComplexD(-x.Imag, x.Real)) - Exp(new ComplexD(x.Imag, -x.Real)); return new ComplexD(a.Imag, -a.Real) * 0.5; } /// /// Returns the hyperbolic sine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Sinh(this ComplexD x) { var sin = Sin(new ComplexD(-x.Imag, x.Real)); return new ComplexD(sin.Imag, -sin.Real); } /// /// Returns the angle that is the arc tangent of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Atan(this ComplexD x) { if (x == ComplexD.I) return ComplexD.PositiveInfinityI; else if (x == -ComplexD.I) return ComplexD.NegativeInfinityI; else if (x == ComplexD.PositiveInfinity) return new ComplexD(Constant.PiHalf); else if (x == ComplexD.NegativeInfinity) return new ComplexD(-Constant.PiHalf); else return new ComplexD(0, 0.5) * Log((ComplexD.I + x) / (ComplexD.I - x)); } /// /// Returns the angle that is the hyperbolic arc tangent of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Atanh(this ComplexD x) { if (x == ComplexD.Zero) return ComplexD.Zero; else if (x == ComplexD.One) return ComplexD.PositiveInfinity; else if (x == ComplexD.PositiveInfinity) return new ComplexD(0, -Constant.PiHalf); else if (x == ComplexD.I) return new ComplexD(0, Constant.PiQuarter); else return 0.5 * (Log(1 + x) - Log(1 - x)); } /// /// Returns the tangent of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Tan(this ComplexD x) { if (x == ComplexD.PositiveInfinityI) return ComplexD.I; else if (x == ComplexD.NegativeInfinityI) return -ComplexD.I; else return Sin(x) / Cos(x); } /// /// Returns the hyperbolic tangent of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Tanh(this ComplexD x) { var tan = Tan(new ComplexD(-x.Imag, x.Real)); return new ComplexD(tan.Imag, -tan.Real); } #endregion #region Exp, Log /// /// Returns e raised to the power of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Exp(this ComplexD x) => new ComplexD(Cos(x.Imag), Sin(x.Imag)) * Exp(x.Real); /// /// Returns the natural logarithm of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Log(this ComplexD x) => new ComplexD(Log(x.Norm), x.Argument); /// /// Returns the logarithm of the complex number in the given basis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Log(this ComplexD x, double basis) => x.Log() / basis.Log(); /// /// Returns the base-10 logarithm of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Log10(this ComplexD x) => Log(x, 10); /// /// Returns the base-2 logarithm of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Log2(this ComplexD x) => x.Log() * Constant.Ln2Inv; #endregion #region Roots /// /// Returns the principal square root of the complex number . /// // https://math.stackexchange.com/a/44500 // TODO: Check if this is actually better than the naive implementation [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Sqrt(this ComplexD x) { if (x.Imag == 0) { if (x.Real < 0) return new ComplexD(0, Sqrt(-x.Real)); else return new ComplexD(Sqrt(x.Real), 0); } else { var a = x.Norm; var b = x + a; return a.Sqrt() * (b / b.Norm); } } /// /// Returns the principal cubic root of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Cbrt(this ComplexD x) => ComplexD.CreateRadial(Cbrt(x.Norm), x.Argument / 3); /// /// Returns the square root of the given real number and returns a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Csqrt(this sbyte number) { if (number >= 0) { return new ComplexD(Sqrt(number), 0); } else { return new ComplexD(0, Sqrt(-number)); } } /// /// Returns the square root of the given real number and returns a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Csqrt(this short number) { if (number >= 0) { return new ComplexD(Sqrt(number), 0); } else { return new ComplexD(0, Sqrt(-number)); } } /// /// Returns the square root of the given real number and returns a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Csqrt(this int number) { if (number >= 0) { return new ComplexD(Sqrt(number), 0); } else { return new ComplexD(0, Sqrt(-number)); } } /// /// Returns the square root of the given real number and returns a complex number. /// Note: This function uses a double representation internally, but not all long values can be represented exactly as double. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Csqrt(this long number) { if (number >= 0) { return new ComplexD(Sqrt(number), 0); } else { return new ComplexD(0, Sqrt(-number)); } } /// /// Returns the square root of the given real number and returns a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD Csqrt(this double number) { if (number >= 0) { return new ComplexD(Sqrt(number), 0); } else { return new ComplexD(0, Sqrt(-number)); } } /// /// Calculates both square roots of a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD[] Csqrt(this ComplexD number) { ComplexD res0 = ComplexD.CreateRadial(Sqrt(number.Norm), number.Argument / 2); ComplexD res1 = ComplexD.CreateRadial(Sqrt(number.Norm), number.Argument / 2 + Constant.Pi); return new ComplexD[2] { res0, res1 }; } /// /// Calculates the n-th root of a complex number and returns n solutions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComplexD[] Root(this ComplexD number, int n) { ComplexD[] values = new ComplexD[n]; double invN = 1 / (double)n; double phi = number.Argument / n; double dphi = Constant.PiTimesTwo * invN; double r = Pow(number.Norm, invN); for (int i = 0; i < n; i++) { values[i] = ComplexD.CreateRadial(r, phi + dphi * i); } return values; } #endregion #region ApproximateEquals /// /// Returns whether the given complex numbers are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this ComplexD a, ComplexD b, double tolerance) { return ApproximateEquals(a.Real, b.Real, tolerance) && ApproximateEquals(a.Imag, b.Imag, tolerance); } /// /// Returns whether the given complex numbers are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this ComplexD a, ComplexD b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region Special Floating Point Value Checks /// /// Returns whether the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(ComplexD v) => v.IsNaN; /// /// Returns whether the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(ComplexD v) => v.IsInfinity; /// /// Returns whether the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(ComplexD v) => v.IsPositiveInfinity; /// /// Returns whether the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(ComplexD v) => v.IsNegativeInfinity; /// /// Returns whether the given is finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(ComplexD v) => v.IsFinite; #endregion } } ================================================ FILE: src/Aardvark.Base/Math/Base/Complex_template.cs ================================================ using System; using System.Linq; using System.Globalization; using System.ComponentModel; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { //# var signedtypes = Meta.SignedTypes; //# var numtypes = Meta.StandardNumericTypes; //# var dreptypes = Meta.DoubleRepresentableTypes; //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? Meta.DoubleType : Meta.FloatType; //# var ftype2 = isDouble ? Meta.FloatType : Meta.DoubleType; //# var ft = ftype.Name; //# var ft2 = ftype2.Name; //# var ct = isDouble ? "ComplexD" : "ComplexF"; //# var ct2 = isDouble ? "ComplexF" : "ComplexD"; //# var constant = isDouble ? "Constant" : "ConstantF"; //# var half = isDouble ? "0.5" : "0.5f"; [DataContract] [StructLayout(LayoutKind.Sequential)] public struct __ct__ : IEquatable<__ct__> { [DataMember] public __ft__ Real; [DataMember] public __ft__ Imag; #region Constructors /// /// Constructs a from a real scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __ct__(__ft__ real) { Real = real; Imag = 0; } /// /// Constructs a from a real and an imaginary part. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __ct__(__ft__ real, __ft__ imag) { Real = real; Imag = imag; } /// /// Constructs a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __ct__(__ct2__ complex) { Real = (__ft__)complex.Real; Imag = (__ft__)complex.Imag; } #endregion #region Constants /// /// Returns 0 + 0i. /// public static __ct__ Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __ct__(0, 0); } /// /// Returns 1 + 0i. /// public static __ct__ One { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __ct__(1, 0); } /// /// Returns 0 + 1i. /// public static __ct__ I { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __ct__(0, 1); } /// /// Returns ∞ + 0i. /// public static __ct__ PositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __ct__(__ft__.PositiveInfinity); } /// /// Returns -∞ + 0i. /// public static __ct__ NegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __ct__(__ft__.NegativeInfinity); } /// /// Returns 0 + ∞i. /// public static __ct__ PositiveInfinityI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __ct__(0, __ft__.PositiveInfinity); } /// /// Returns 0 - ∞i. /// public static __ct__ NegativeInfinityI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __ct__(0, __ft__.NegativeInfinity); } #endregion #region Properties /// /// Returns the conjugated of the complex number. /// public readonly __ct__ Conjugated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new __ct__(Real, -Imag); } } /// /// Returns the reciprocal of the complex number. /// public readonly __ct__ Reciprocal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { __ft__ t = 1 / NormSquared; return new __ct__(Real * t, -Imag * t); } } /// /// Returns the squared Gaussian Norm (modulus) of the complex number. /// public readonly __ft__ NormSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Real * Real + Imag * Imag; } } /// /// Returns the Gaussian Norm (modulus) of the complex number. /// [XmlIgnore] public __ft__ Norm { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Fun.Sqrt(Real * Real + Imag * Imag); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { __ft__ r = Norm; Real = value * Real / r; Imag = value * Imag / r; } } /// /// Retruns the argument of the complex number. /// [XmlIgnore] public __ft__ Argument { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Fun.Atan2(Imag, Real); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { __ft__ r = Norm; Real = r * Fun.Cos(value); Imag = r * Fun.Sin(value); } } /// /// Returns whether the complex number has no imaginary part. /// public readonly bool IsReal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Imag.IsTiny(); } } /// /// Returns whether the complex number has no real part. /// public readonly bool IsImaginary { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Real.IsTiny(); } } /// /// Returns whether the complex number is 1 + 0i. /// public readonly bool IsOne { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Real.ApproximateEquals(1) && Imag.IsTiny(); } } /// /// Returns whether the complex number is zero. /// public readonly bool IsZero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Real.IsTiny() && Imag.IsTiny(); } } /// /// Returns whether the complex number is 0 + 1i. /// public readonly bool IsI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Real.IsTiny(Real) && Imag.ApproximateEquals(1); } } /// /// Returns whether the complex number has a part that is NaN. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (__ft__.IsNaN(Real) || __ft__.IsNaN(Imag)); } } /// /// Returns whether the complex number has a part that is infinite (positive or negative). /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (__ft__.IsInfinity(Real) || __ft__.IsInfinity(Imag)); } } /// /// Returns whether the complex number has a part that is infinite and positive. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (__ft__.IsPositiveInfinity(Real) || __ft__.IsPositiveInfinity(Imag)); } } /// /// Returns whether the complex number has a part that is infinite and negative. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (__ft__.IsNegativeInfinity(Real) || __ft__.IsNegativeInfinity(Imag)); } } /// /// Returns whether the complex number is finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !(IsNaN || IsInfinity); } } #endregion #region Static factories /// /// Creates a Radial Complex /// /// Norm of the complex number /// Argument of the complex number /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ CreateRadial(__ft__ r, __ft__ phi) => new __ct__(r * Fun.Cos(phi), r * Fun.Sin(phi)); /// /// Creates a Orthogonal Complex /// /// Real-Part /// Imaginary-Part /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ CreateOrthogonal(__ft__ real, __ft__ imag) => new __ct__(real, imag); #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Acos(__ct__ x) => x.Acos(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Acoshb(__ct__ x) => x.Acosh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Cos(__ct__ x) => x.Cos(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Cosh(__ct__ x) => x.Cosh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Asin(__ct__ x) => x.Asin(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Asinhb(__ct__ x) => x.Asinh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Sin(__ct__ x) => x.Sin(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Sinh(__ct__ x) => x.Sinh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Atan(__ct__ x) => x.Atan(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Atanhb(__ct__ x) => x.Atanh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Tan(__ct__ x) => x.Tan(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Tanh(__ct__ x) => x.Tanh(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Sqrt(__ct__ x) => x.Sqrt(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ CubeRoot(__ct__ x) => x.Cbrt(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Exp(__ct__ x) => x.Exp(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Log(__ct__ x) => x.Log(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ LogBinary(__ct__ x) => x.Log2(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Log10(__ct__ x) => x.Log10(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ DivideByInt(__ct__ x, int y) => x / y; #endregion #region Operators /// /// Conversion from a to a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __ct2__(__ct__ c) => new __ct2__(c); /// /// Implicit conversion from a to a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator __ct__(__ft__ a) => new __ct__(a); /// /// Adds two complex numbers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ operator +(__ct__ a, __ct__ b) => new __ct__(a.Real + b.Real, a.Imag + b.Imag); /// /// Adds a complex number and a real number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ operator +(__ct__ a, __ft__ b) => new __ct__(a.Real + b, a.Imag); /// /// Adds a real number and a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ operator +(__ft__ a, __ct__ b) => new __ct__(a + b.Real, b.Imag); /// /// Subtracts two complex numbers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ operator -(__ct__ a, __ct__ b) => new __ct__(a.Real - b.Real, a.Imag - b.Imag); /// /// Subtracts a real number from a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ operator -(__ct__ a, __ft__ b) => new __ct__(a.Real - b, a.Imag); /// /// Subtracts a complex number from a real number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ operator -(__ft__ a, __ct__ b) => new __ct__(a - b.Real, -b.Imag); /// /// Multiplies two complex numbers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ operator *(__ct__ a, __ct__ b) => new __ct__( a.Real * b.Real - a.Imag * b.Imag, a.Real * b.Imag + a.Imag * b.Real); /// /// Multiplies a complex number and a real number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ operator *(__ct__ a, __ft__ b) => new __ct__(a.Real * b, a.Imag * b); /// /// Multiplies a real number and a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ operator *(__ft__ a, __ct__ b) => new __ct__(a * b.Real, a * b.Imag); /// /// Divides two complex numbers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ operator /(__ct__ a, __ct__ b) { __ft__ t = 1 / b.NormSquared; return new __ct__( t * (a.Real * b.Real + a.Imag * b.Imag), t * (a.Imag * b.Real - a.Real * b.Imag)); } /// /// Divides a complex number by a real number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ operator /(__ct__ a, __ft__ b) => new __ct__(a.Real / b, a.Imag / b); /// /// Divides a real number by a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ operator /(__ft__ a, __ct__ b) { __ft__ t = 1 / b.NormSquared; return new __ct__( t * (a * b.Real), t * (-a * b.Imag)); } /// /// Negates a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ operator -(__ct__ a) => new __ct__(-a.Real, -a.Imag); /// /// Returns the conjugate of a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ operator !(__ct__ a) => a.Conjugated; #endregion #region Comparison Operators /// /// Returns whether two are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__ct__ a, __ct__ b) => a.Real == b.Real && a.Imag == b.Imag; /// /// Returns whether two are not equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__ct__ a, __ct__ b) => !(a == b); #endregion #region Overrides public override readonly int GetHashCode() => HashCode.GetCombined(Real, Imag); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__ct__ other) => Real.Equals(other.Real) && Imag.Equals(other.Imag); public override readonly bool Equals(object other) { if (other is __ct__ obj) return Equals(obj); else return false; } public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Real, Imag); } public static __ct__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(2); return new __ct__( __ft__.Parse(x[0], CultureInfo.InvariantCulture), __ft__.Parse(x[1], CultureInfo.InvariantCulture) ); } #endregion } public static partial class Complex { #region Conjugate /// /// Returns the conjugate of a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Conjugated(__ct__ c) => c.Conjugated; #endregion #region Norm /// /// Returns the squared Gaussian Norm (modulus) of the complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ft__ NormSquared(__ct__ c) => c.NormSquared; /// /// Returns the Gaussian Norm (modulus) of the complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ft__ Norm(__ct__ c) => c.Norm; #endregion #region Argument /// /// Retruns the argument of the complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ft__ Argument(__ct__ c) => c.Argument; #endregion } public static partial class Fun { #region Power /// /// Returns the complex number raised to the power of . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Pow(this __ct__ number, __ct__ exponent) { if (number.IsZero) return __ct__.Zero; else if (exponent.IsZero) return __ct__.One; else { __ft__ r = number.Norm; __ft__ phi = number.Argument; __ft__ a = exponent.Real; __ft__ b = exponent.Imag; return __ct__.CreateRadial(Exp(Log(r) * a - b * phi), a * phi + b * Log(r)); } } /// /// Returns the complex number raised to the power of . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Pow(this __ct__ number, __ft__ exponent) { if (number.IsZero) return __ct__.Zero; else { __ft__ r = number.Norm; __ft__ phi = number.Argument; return __ct__.CreateRadial(Pow(r, exponent), exponent * phi); } } /// /// Returns raised to the power of . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Pow(this __ft__ number, __ct__ exponent) { if (number == 0) return __ct__.Zero; else { __ft__ a = exponent.Real; __ft__ b = exponent.Imag; if (number < 0) { var phi = __constant__.Pi; return __ct__.CreateRadial(Exp(Log(-number) * a - b * phi), a * phi + b * Log(-number)); } else return __ct__.CreateRadial(Pow(number, a), b * Log(number)); } } [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Power(this __ct__ number, __ct__ exponent) => Pow(number, exponent); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Power(this __ct__ number, __ft__ exponent) => Pow(number, exponent); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Power(this __ft__ number, __ct__ exponent) => Pow(number, exponent); #endregion #region Trigonometry /// /// Returns the angle that is the arc cosine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Acos(this __ct__ x) { var t = Log(new __ct__(-x.Imag, x.Real) + Sqrt(1 - x * x)); return new __ct__(-t.Imag + __constant__.PiHalf, t.Real); } /// /// Returns the angle that is the hyperbolic arc cosine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Acosh(this __ct__ x) => Log(x + Sqrt(x * x - 1)); /// /// Returns the cosine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Cos(this __ct__ x) => ( Exp(new __ct__(-x.Imag, x.Real)) + Exp(new __ct__(x.Imag, -x.Real)) ) * __half__; /// /// Returns the hyperbolic cosine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Cosh(this __ct__ x) => Cos(new __ct__(-x.Imag, x.Real)); /// /// Returns the angle that is the arc sine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Asin(this __ct__ x) { var t = Log(new __ct__(-x.Imag, x.Real) + Sqrt(1 - x * x)); return new __ct__(t.Imag, -t.Real); } /// /// Returns the angle that is the hyperbolic arc sine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Asinh(this __ct__ x) => Log(x + Sqrt(1 + x * x)); /// /// Returns the sine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Sin(this __ct__ x) { var a = Exp(new __ct__(-x.Imag, x.Real)) - Exp(new __ct__(x.Imag, -x.Real)); return new __ct__(a.Imag, -a.Real) * __half__; } /// /// Returns the hyperbolic sine of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Sinh(this __ct__ x) { var sin = Sin(new __ct__(-x.Imag, x.Real)); return new __ct__(sin.Imag, -sin.Real); } /// /// Returns the angle that is the arc tangent of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Atan(this __ct__ x) { if (x == __ct__.I) return __ct__.PositiveInfinityI; else if (x == -__ct__.I) return __ct__.NegativeInfinityI; else if (x == __ct__.PositiveInfinity) return new __ct__(__constant__.PiHalf); else if (x == __ct__.NegativeInfinity) return new __ct__(-__constant__.PiHalf); else return new __ct__(0, __half__) * Log((__ct__.I + x) / (__ct__.I - x)); } /// /// Returns the angle that is the hyperbolic arc tangent of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Atanh(this __ct__ x) { if (x == __ct__.Zero) return __ct__.Zero; else if (x == __ct__.One) return __ct__.PositiveInfinity; else if (x == __ct__.PositiveInfinity) return new __ct__(0, -__constant__.PiHalf); else if (x == __ct__.I) return new __ct__(0, __constant__.PiQuarter); else return __half__ * (Log(1 + x) - Log(1 - x)); } /// /// Returns the tangent of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Tan(this __ct__ x) { if (x == __ct__.PositiveInfinityI) return __ct__.I; else if (x == __ct__.NegativeInfinityI) return -__ct__.I; else return Sin(x) / Cos(x); } /// /// Returns the hyperbolic tangent of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Tanh(this __ct__ x) { var tan = Tan(new __ct__(-x.Imag, x.Real)); return new __ct__(tan.Imag, -tan.Real); } #endregion #region Exp, Log /// /// Returns e raised to the power of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Exp(this __ct__ x) => new __ct__(Cos(x.Imag), Sin(x.Imag)) * Exp(x.Real); /// /// Returns the natural logarithm of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Log(this __ct__ x) => new __ct__(Log(x.Norm), x.Argument); /// /// Returns the logarithm of the complex number in the given basis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Log(this __ct__ x, __ft__ basis) => x.Log() / basis.Log(); /// /// Returns the base-10 logarithm of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Log10(this __ct__ x) => Log(x, 10); /// /// Returns the base-2 logarithm of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Log2(this __ct__ x) => x.Log() * __constant__.Ln2Inv; #endregion #region Roots /// /// Returns the principal square root of the complex number . /// // https://math.stackexchange.com/a/44500 // TODO: Check if this is actually better than the naive implementation [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Sqrt(this __ct__ x) { if (x.Imag == 0) { if (x.Real < 0) return new __ct__(0, Sqrt(-x.Real)); else return new __ct__(Sqrt(x.Real), 0); } else { var a = x.Norm; var b = x + a; return a.Sqrt() * (b / b.Norm); } } /// /// Returns the principal cubic root of the complex number . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Cbrt(this __ct__ x) => __ct__.CreateRadial(Cbrt(x.Norm), x.Argument / 3); //# signedtypes.ForEach(t => { if (t != Meta.DecimalType) { //# if (ftype == Meta.DoubleType ^ t == Meta.FloatType) { /// /// Returns the square root of the given real number and returns a complex number. //# if (!dreptypes.Contains(t)) { /// Note: This function uses a double representation internally, but not all __t.Name__ values can be represented exactly as double. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__ Csqrt(this __t.Name__ number) { if (number >= 0) { return new __ct__(Sqrt(number), 0); } else { return new __ct__(0, Sqrt(-number)); } } //# }}}); /// /// Calculates both square roots of a complex number. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__[] Csqrt(this __ct__ number) { __ct__ res0 = __ct__.CreateRadial(Sqrt(number.Norm), number.Argument / 2); __ct__ res1 = __ct__.CreateRadial(Sqrt(number.Norm), number.Argument / 2 + __constant__.Pi); return new __ct__[2] { res0, res1 }; } /// /// Calculates the n-th root of a complex number and returns n solutions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ct__[] Root(this __ct__ number, int n) { __ct__[] values = new __ct__[n]; __ft__ invN = 1 / (__ft__)n; __ft__ phi = number.Argument / n; __ft__ dphi = __constant__.PiTimesTwo * invN; __ft__ r = Pow(number.Norm, invN); for (int i = 0; i < n; i++) { values[i] = __ct__.CreateRadial(r, phi + dphi * i); } return values; } #endregion #region ApproximateEquals /// /// Returns whether the given complex numbers are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __ct__ a, __ct__ b, __ft__ tolerance) { return ApproximateEquals(a.Real, b.Real, tolerance) && ApproximateEquals(a.Imag, b.Imag, tolerance); } /// /// Returns whether the given complex numbers are equal within /// Constant<__ft__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __ct__ a, __ct__ b) { return ApproximateEquals(a, b, Constant<__ft__>.PositiveTinyValue); } #endregion #region Special Floating Point Value Checks /// /// Returns whether the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(__ct__ v) => v.IsNaN; /// /// Returns whether the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(__ct__ v) => v.IsInfinity; /// /// Returns whether the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(__ct__ v) => v.IsPositiveInfinity; /// /// Returns whether the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(__ct__ v) => v.IsNegativeInfinity; /// /// Returns whether the given is finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(__ct__ v) => v.IsFinite; #endregion } //# } // isDouble } ================================================ FILE: src/Aardvark.Base/Math/Base/Constant.cs ================================================ using System; namespace Aardvark.Base { public enum Metric { Manhattan = 1, Euclidean = 2, Maximum = int.MaxValue, L1 = Manhattan, L2 = Euclidean, LInfinity = Maximum, } public static class Constant { /// /// A value that is or is close to the minimum value of the type, but /// can be parsed back without exception. /// public static readonly T ParseableMinValue; /// /// A value that is or is close to the maximum value of the type, but /// can be parsed back without exception. /// public static readonly T ParseableMaxValue; /// /// The smallest value that can be added to 1.0 for obtaining a result /// that is different from 1.0. /// public static readonly T MachineEpsilon; /// /// Four times the MachineEpsilon of the type. /// public static readonly T PositiveTinyValue; /// /// Minus four times the MachineEpsilon of the type. /// public static readonly T NegativeTinyValue; static Constant() { if (typeof(T) == typeof(byte)) { ParseableMinValue = (T)(object)byte.MinValue; ParseableMinValue = (T)(object)byte.MinValue; ParseableMaxValue = (T)(object)byte.MaxValue; MachineEpsilon = (T)(object)(byte)1; PositiveTinyValue = (T)(object)(byte)4; } else if (typeof(T) == typeof(ushort)) { ParseableMinValue = (T)(object)ushort.MinValue; ParseableMaxValue = (T)(object)ushort.MaxValue; MachineEpsilon = (T)(object)(ushort)1; PositiveTinyValue = (T)(object)(ushort)4; } else if (typeof(T) == typeof(uint)) { ParseableMinValue = (T)(object)uint.MinValue; ParseableMaxValue = (T)(object)uint.MaxValue; MachineEpsilon = (T)(object)(uint)1; PositiveTinyValue = (T)(object)(uint)4; } else if (typeof(T) == typeof(ulong)) { ParseableMinValue = (T)(object)ulong.MinValue; ParseableMaxValue = (T)(object)ulong.MaxValue; MachineEpsilon = (T)(object)(ulong)1; PositiveTinyValue = (T)(object)(ulong)4; } else if (typeof(T) == typeof(sbyte)) { ParseableMinValue = (T)(object)sbyte.MinValue; ParseableMaxValue = (T)(object)sbyte.MaxValue; MachineEpsilon = (T)(object)(sbyte)1; PositiveTinyValue = (T)(object)(sbyte)4; NegativeTinyValue = (T)(object)(sbyte)-4; } else if (typeof(T) == typeof(short)) { ParseableMinValue = (T)(object)short.MinValue; ParseableMaxValue = (T)(object)short.MaxValue; MachineEpsilon = (T)(object)(short)1; PositiveTinyValue = (T)(object)(short)4; NegativeTinyValue = (T)(object)(short)-4; } else if (typeof(T) == typeof(int)) { ParseableMinValue = (T)(object)int.MinValue; ParseableMaxValue = (T)(object)int.MaxValue; MachineEpsilon = (T)(object)1; PositiveTinyValue = (T)(object)4; NegativeTinyValue = (T)(object)-4; } else if (typeof(T) == typeof(long)) { ParseableMinValue = (T)(object)long.MinValue; ParseableMaxValue = (T)(object)long.MaxValue; MachineEpsilon = (T)(object)1L; PositiveTinyValue = (T)(object)4L; NegativeTinyValue = (T)(object)-4L; } else if (typeof(T) == typeof(float)) { float floatEps = Fun.FloatFromBits(Fun.FloatToBits(1.0f) + 1) - 1.0f; ParseableMinValue = (T)(object)(float.MinValue * 0.999999f); ParseableMaxValue = (T)(object)(float.MaxValue * 0.999999f); MachineEpsilon = (T)(object)floatEps; PositiveTinyValue = (T)(object)(4 * floatEps); NegativeTinyValue = (T)(object)(-4 * floatEps); } else if (typeof(T) == typeof(double)) { double doubleEps = Fun.FloatFromBits(Fun.FloatToBits(1.0) + 1L) - 1.0; ParseableMinValue = (T)(object)(double.MinValue * 0.999999995); ParseableMaxValue = (T)(object)(double.MaxValue * 0.999999995); MachineEpsilon = (T)(object)doubleEps; PositiveTinyValue = (T)(object)(4 * doubleEps); NegativeTinyValue = (T)(object)(-4 * doubleEps); } } } [Obsolete] static class Constants { public static void Init() { var ignore1 = Constant.MachineEpsilon; var ignore2 = Constant.MachineEpsilon; var ignore3 = Constant.MachineEpsilon; var ignore4 = Constant.MachineEpsilon; var ignore5 = Constant.MachineEpsilon; var ignore6 = Constant.MachineEpsilon; var ignore7 = Constant.MachineEpsilon; var ignore8 = Constant.MachineEpsilon; var ignore9 = Constant.MachineEpsilon; var ignore0 = Constant.MachineEpsilon; } } /// /// Mathematical constants. /// public static class Constant { /// /// Ratio of a circle's circumference to its diameter /// in Euclidean geometry. Also known as Archimedes' constant. /// public const double Pi = 3.1415926535897932384626433832795; /// /// One divided by Pi (1 / Pi). /// public const double PiInv = 0.318309886183790671537767526745028724068919291480912897495; /// /// Two times PI: the circumference of the unit circle. /// public const double PiTimesTwo = 6.283185307179586476925286766559; /// /// Three times PI. /// public const double PiTimesThree = 9.424777960769379715387930149839; /// /// Four times PI: the surface area of the unit sphere. /// public const double PiTimesFour = 12.56637061435917295385057353312; /// /// Half of PI. /// public const double PiHalf = 1.570796326794896619231321691640; /// /// Quarter of PI. /// public const double PiQuarter = 0.78539816339744830961566084581988; /// /// Square of PI. /// public const double PiSquared = 9.869604401089358618834490999876; /// /// Sqrt(2 * PI). /// public const double SqrtPiTimesTwo = 2.5066282746310005024157652848110; /// /// Base of the natural logarithm. /// Also known as Euler's number. /// public const double E = Math.E; /// /// Golden Ratio. /// The golden ratio expresses the relationship that /// the sum of two quantities is to the larger quantity /// as the larger is to the smaller. /// It is defined as (1 + sqrt(5)) / 2). /// public const double Phi = 1.61803398874989484820458683; /// /// Square root of 2. /// public const double Sqrt2 = 1.414213562373095048801688724209; /// /// Square root of 0.5. /// public const double Sqrt2Half = 0.70710678118654752440084436210485; /// /// Square root of 3. /// public const double Sqrt3 = 1.732050807568877293527446341505; /// /// Square root of 5. /// public const double Sqrt5 = 2.236067977499789696409173668731; /// /// Natural logarithm (base e) of 2. /// public const double Ln2 = 0.69314718055994530941723212145818; /// /// 1 divided by logarithm of 2 (base e). /// public const double Ln2Inv = 1.4426950408889634073599246810023; /// /// 1 divided by 3. /// public const double OneThird = 0.33333333333333333333333333333333; /// /// Used to convert degrees to radians. /// See also class. /// public const double RadiansPerDegree = Pi / 180.0; /// /// Used to convert radians to degrees. /// See also class. /// public const double DegreesPerRadian = 180.0 / Pi; /// /// Used to convert gons to radians. /// See also class. /// public const double RadiansPerGon = Pi / 200.0; /// /// Used to convert radians to gons. /// See also class. /// public const double GonsPerRadian = 200.0 / Pi; /// /// Used to convert gons to degrees. /// See also class. /// public const double DegreesPerGon = 180.0 / 200.0; /// /// Used to convert degrees to gons. /// See also class. /// public const double GonsPerDegree = 200.0 / 180.0; /// /// One sixtieth (1/60) of one degree (in radians). /// public const double ArcMinute = Pi / (180 * 60); /// /// One sixtieth (1/60) of one arc minute (in radians). /// public const double ArcSecond = Pi / (180 * 60 * 60); /// /// The speed of light in meters per second. /// public const double SpeedOfLight = 299792458.0; } /// /// Mathematical constants. /// public static class ConstantF { /// /// Ratio of a circle's circumference to its diameter /// in Euclidean geometry. Also known as Archimedes' constant. /// public const float Pi = (float)Constant.Pi; /// /// One divided by Pi (1 / Pi). /// public const float PiInv = (float)Constant.PiInv; /// /// Two times PI: the circumference of the unit circle. /// public const float PiTimesTwo = (float)Constant.PiTimesTwo; /// /// Twree times PI. /// public const float PiTimesThree = (float)Constant.PiTimesThree; /// /// Four times PI: the surface area of the unit sphere. /// public const float PiTimesFour = (float)Constant.PiTimesFour; /// /// Half of PI. /// public const float PiHalf = (float)Constant.PiHalf; /// /// Quarter of PI. /// public const float PiQuarter = (float)Constant.PiQuarter; /// /// Square of PI. /// public const float PiSquared = (float)Constant.PiSquared; /// /// Sqrt(2 * PI). /// public const float SqrtPiTimesTwo = (float)Constant.SqrtPiTimesTwo; /// /// Base of the natural logarithm. /// Also known as Euler's number. /// public const float E = (float)Constant.E; /// /// Golden Ratio. /// The golden ratio expresses the relationship that /// the sum of two quantities is to the larger quantity /// as the larger is to the smaller. /// It is defined as (1 + sqrt(5)) / 2). /// public const float Phi = (float)Constant.Phi; /// /// Square root of 2. /// public const float Sqrt2 = (float)Constant.Sqrt2; /// /// Square root of 0.5. /// public const float Sqrt2Half = (float)Constant.Sqrt2Half; /// /// Square root of 3. /// public const float Sqrt3 = (float)Constant.Sqrt3; /// /// Square root of 5. /// public const float Sqrt5 = (float)Constant.Sqrt5; /// /// Natural logarithm (base e) of 2. /// public const float Ln2 = (float)Constant.Ln2; /// /// 1 divided by logarithm of 2 (base e). /// public const float Ln2Inv = (float)Constant.Ln2Inv; /// /// 1 divided by 3. /// public const float OneThird = (float)Constant.OneThird; /// /// Used to convert degrees to radians. /// See also class. /// public const float RadiansPerDegree = (float)Constant.RadiansPerDegree; /// /// Used to convert radians to degrees. /// See also class. /// public const float DegreesPerRadian = (float)Constant.DegreesPerRadian; /// /// Used to convert gons to radians. /// See also class. /// public const float RadiansPerGon = (float)Constant.RadiansPerGon; /// /// Used to convert radians to gons. /// See also class. /// public const float GonsPerRadian = (float)Constant.GonsPerRadian; /// /// Used to convert gons to degrees. /// See also class. /// public const float DegreesPerGon = (float)Constant.DegreesPerGon; /// /// Used to convert degrees to gons. /// See also class. /// public const float GonsPerDegree = (float)Constant.GonsPerDegree; /// /// One sixtieth (1/60) of one degree (in radians). /// public const float ArcMinute = (float)Constant.ArcMinute; /// /// One sixtieth (1/60) of one arc minute (in radians). /// public const float ArcSecond = (float)Constant.ArcSecond; /// /// The speed of light in meters per second. /// public const float SpeedOfLight = (float)Constant.SpeedOfLight; } } ================================================ FILE: src/Aardvark.Base/Math/Base/Conversion.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Text; namespace Aardvark.Base { /// /// Conversion routines. /// public static partial class Conversion { #region Spherical <-> Cartesian /// /// Returns unit vector in direction (phi, theta). /// Phi is rotation in xy-plane (x-axis is 0, y-axis is pi/2, ...). /// Positive theta rotates towards positive z-axis. /// public static V3d CartesianFromSpherical(double phi, double theta) { var s = theta.Cos(); return new V3d(phi.Cos() * s, phi.Sin() * s, theta.Sin()); } /// /// Returns unit vector in direction (phi, theta). /// Phi is rotation in xy-plane (x-axis is 0, y-axis is pi/2, ...). /// Positive theta rotates towards positive z-axis. /// public static V3d CartesianFromSpherical(this V2d phiAndTheta) { return CartesianFromSpherical(phiAndTheta.X, phiAndTheta.Y); } /// /// Returns unit vector in direction phi. /// Phi is rotation in xy-plane (x-axis is 0, y-axis is pi/2, ...). /// public static V2d CartesianFromSpherical(this double phi) { return new V2d(phi.Cos(), phi.Sin()); } /// /// Returns spherical direction (phi, theta) from Cartesian direction. /// public static V2d SphericalFromCartesian(this V3d v) { return new V2d( Fun.Atan2(v.Y, v.X), // phi Fun.Atan2(v.Z, v.XY.Length) // theta ); } /// /// Returns spherical direction (phi) from Cartesian direction. /// public static double SphericalFromCartesian(this V2d v) { return Fun.Atan2(v.Y, v.X); } #endregion #region Angles (Radians, Degrees, Gons) /// /// Converts an angle given in radians to degrees. /// public static float DegreesFromRadians(this float radians) { return radians * ConstantF.DegreesPerRadian; } /// /// Converts an angle given in radians to degrees. /// public static double DegreesFromRadians(this double radians) { return radians * Constant.DegreesPerRadian; } /// /// Converts an angle given in degrees to radians. /// public static float RadiansFromDegrees(this float degrees) { return degrees * ConstantF.RadiansPerDegree; } /// /// Converts an angle given in degrees to radians. /// public static double RadiansFromDegrees(this double degrees) { return degrees * Constant.RadiansPerDegree; } /// /// Converts an angle given in gons to degrees. /// public static float DegreesFromGons(this float gons) { return gons * ConstantF.DegreesPerGon; } /// /// Converts an angle given in gons to degrees. /// public static double DegreesFromGons(this double gons) { return gons * Constant.DegreesPerGon; } /// /// Converts an angle given in gons to radians. /// public static float RadiansFromGons(this float gons) { return gons * ConstantF.RadiansPerGon; } /// /// Converts an angle given in gons to radians. /// public static double RadiansFromGons(this double gons) { return gons * Constant.RadiansPerGon; } /// /// Converts an angle given in degrees to gons. /// public static float GonsFromDegrees(this float degrees) { return degrees * ConstantF.GonsPerDegree; } /// /// Converts an angle given in degrees to gons. /// public static double GonsFromDegrees(this double degrees) { return degrees * Constant.GonsPerDegree; } /// /// Converts an angle given in radians to gons. /// public static float GonsFromRadians(this float radians) { return radians * ConstantF.GonsPerRadian; } /// /// Converts an angle given in radians to gons. /// public static double GonsFromRadians(this double radians) { return radians * Constant.GonsPerRadian; } #endregion #region Temperature /// /// Converts a temperature given in Fahrenheit to Celsius. /// public static float CelsiusFromFahrenheit(this float fahrenheit) { return (fahrenheit - 32.0f) / 1.8f; } /// /// Converts a temperature given in Fahrenheit to Celsius. /// public static double CelsiusFromFahrenheit(this double fahrenheit) { return (fahrenheit - 32.0) / 1.8; } /// /// Converts a temperature given in Celsius to Fahrenheit. /// public static float FahrenheitFromCelsius(this float celsius) { return (celsius * 1.8f) + 32.0f; } /// /// Converts a temperature given in Celsius to Fahrenheit. /// public static double FahrenheitFromCelsius(this double celsius) { return (celsius * 1.8) + 32.0; } /// /// Converts a temperature given in Fahrenheit to Kelvin. /// public static float KelvinFromFahrenheit(this float fahrenheit) { return (fahrenheit + 459.67f) / 1.8f; } /// /// Converts a temperature given in Fahrenheit to Kelvin. /// public static double KelvinFromFahrenheit(this double fahrenheit) { return (fahrenheit + 459.67) / 1.8; } /// /// Converts a temperature given in Kelvin to Fahrenheit. /// public static float FahrenheitFromKelvin(this float kelvin) { return (kelvin * 1.8f) - 459.67f; } /// /// Converts a temperature given in Kelvin to Fahrenheit. /// public static double FahrenheitFromKelvin(this double kelvin) { return (kelvin * 1.8) - 459.67; } /// /// Converts a temperature given in Kelvin to Celsius. /// public static float CelsiusFromKelvin(this float kelvin) { return kelvin - 273.15f; } /// /// Converts a temperature given in Kelvin to Celsius. /// public static double CelsiusFromKelvin(this double kelvin) { return kelvin - 273.15; } /// /// Converts a temperature given in Celsius to Kelvin. /// public static float KelvinFromCelsius(this float celsius) { return celsius + 273.15f; } /// /// Converts a temperature given in Celsius to Kelvin. /// public static double KelvinFromCelsius(this double celsius) { return celsius + 273.15; } #endregion #region Byte order (little endian / big endian) #region HostToNetworkOrder public static byte[] HostToNetworkOrder(short x) { byte[] data = BitConverter.GetBytes(x); if (BitConverter.IsLittleEndian) ReverseBytes(data); return data; } public static byte[] HostToNetworkOrder(ushort x) { byte[] data = BitConverter.GetBytes(x); if (BitConverter.IsLittleEndian) ReverseBytes(data); return data; } public static byte[] HostToNetworkOrder(int x) { byte[] data = BitConverter.GetBytes(x); if (BitConverter.IsLittleEndian) ReverseBytes(data); return data; } public static byte[] HostToNetworkOrder(uint x) { byte[] data = BitConverter.GetBytes(x); if (BitConverter.IsLittleEndian) ReverseBytes(data); return data; } public static byte[] HostToNetworkOrder(long x) { byte[] data = BitConverter.GetBytes(x); if (BitConverter.IsLittleEndian) ReverseBytes(data); return data; } public static byte[] HostToNetworkOrder(ulong x) { byte[] data = BitConverter.GetBytes(x); if (BitConverter.IsLittleEndian) ReverseBytes(data); return data; } public static byte[] HostToNetworkOrder(float x) { byte[] data = BitConverter.GetBytes(x); if (BitConverter.IsLittleEndian) ReverseBytes(data); return data; } public static byte[] HostToNetworkOrder(double x) { byte[] data = BitConverter.GetBytes(x); if (BitConverter.IsLittleEndian) ReverseBytes(data); return data; } #endregion #region NetworkToHostOrder public static short NetworkToHostOrderInt16(byte[] data) { byte[] copy = (byte[])data.Clone(); if (BitConverter.IsLittleEndian) ReverseBytes(copy); return BitConverter.ToInt16(copy, 0); } public static short NetworkToHostOrderInt16InPlace(byte[] data) { if (BitConverter.IsLittleEndian) ReverseBytes(data); return BitConverter.ToInt16(data, 0); } public static ushort NetworkToHostOrderUInt16(byte[] data) { byte[] copy = (byte[])data.Clone(); if (BitConverter.IsLittleEndian) ReverseBytes(copy); return BitConverter.ToUInt16(copy, 0); } public static ushort NetworkToHostOrderUInt16InPlace(byte[] data) { if (BitConverter.IsLittleEndian) ReverseBytes(data); return BitConverter.ToUInt16(data, 0); } public static int NetworkToHostOrderInt32(byte[] data) { byte[] copy = (byte[])data.Clone(); if (BitConverter.IsLittleEndian) ReverseBytes(copy); return BitConverter.ToInt32(copy, 0); } public static int NetworkToHostOrderInt32InPlace(byte[] data) { if (BitConverter.IsLittleEndian) ReverseBytes(data); return BitConverter.ToInt32(data, 0); } public static uint NetworkToHostOrderUInt32(byte[] data) { byte[] copy = (byte[])data.Clone(); if (BitConverter.IsLittleEndian) ReverseBytes(copy); return BitConverter.ToUInt32(copy, 0); } public static uint NetworkToHostOrderUInt32InPlace(byte[] data) { if (BitConverter.IsLittleEndian) ReverseBytes(data); return BitConverter.ToUInt32(data, 0); } public static long NetworkToHostOrderInt64(byte[] data) { byte[] copy = (byte[])data.Clone(); if (BitConverter.IsLittleEndian) ReverseBytes(copy); return BitConverter.ToInt64(copy, 0); } public static long NetworkToHostOrderInt64InPlace(byte[] data) { if (BitConverter.IsLittleEndian) ReverseBytes(data); return BitConverter.ToInt64(data, 0); } public static ulong NetworkToHostOrderUInt64(byte[] data) { byte[] copy = (byte[])data.Clone(); if (BitConverter.IsLittleEndian) ReverseBytes(copy); return BitConverter.ToUInt64(copy, 0); } public static ulong NetworkToHostOrderUInt64InPlace(byte[] data) { if (BitConverter.IsLittleEndian) ReverseBytes(data); return BitConverter.ToUInt64(data, 0); } public static float NetworkToHostOrderSingle(byte[] data) { byte[] copy = (byte[])data.Clone(); if (BitConverter.IsLittleEndian) ReverseBytes(copy); return BitConverter.ToSingle(copy, 0); } public static float NetworkToHostOrderSingleInPlace(byte[] data) { if (BitConverter.IsLittleEndian) ReverseBytes(data); return BitConverter.ToSingle(data, 0); } public static double NetworkToHostOrderDouble(byte[] data) { byte[] copy = (byte[])data.Clone(); if (BitConverter.IsLittleEndian) ReverseBytes(copy); return BitConverter.ToDouble(copy, 0); } public static double NetworkToHostOrderDoubleInPlace(byte[] data) { if (BitConverter.IsLittleEndian) ReverseBytes(data); return BitConverter.ToDouble(data, 0); } #endregion /// /// Reverses elements of given byte array. /// public static void ReverseBytes(byte[] data) { int length = data.Length; int maxIndex = length - 1; for (int i = 0; i < length / 2; i++) { int j = maxIndex - i; byte tmp = data[i]; data[i] = data[j]; data[j] = tmp; } } #endregion #region Color /// /// Converts XYZ-color to Lab-color /// /// /// public static C3f XYZToLab(this C3f xyz) { var X = xyz.R / XREF; var Y = xyz.G / YREF; var Z = xyz.B / ZREF; var fx = f(X); var fy = f(Y); var fz = f(Z); var L = (116 * fy) - 16; var a = 500 * (fx - fy); var b = 200 * (fy - fz); return new C3f(L, a, b); } /// /// converts Lab-color to XYZ-color /// /// L=[0,100], a=[-150,150], b=[-150,150] /// public static C3f LabToXYZ(this C3f lab) { var L = lab.R; var a = lab.G; var b = lab.B; var d = (1.0f / 116.0f) * (L + 16); var Y = YREF * fInv(d); var X = XREF * fInv(d + a / 500.0f); var Z = ZREF * fInv(d - b / 200.0f); return new C3f(X, Y, Z); } private static float f(float t) { if (t > 0.008856) return t.Pow(1.0f / 3.0f); return (903.3f * t + 16f) / 116f; //(1.0f / 3.0f) * (float)(29.0f / 6.0f).Square() * t + (4.0f / 29.0f); } private static float fInv(float t) { if (t > 0.20689) return t.Pow(3); return (t * 116f - 16) / 903.3f; //3 * (float)(6.0f / 29.0f).Square() * (t - 4.0f / 29.0f); } private const float XREF = 0.95f; // Illuminant= D65 private const float YREF = 1f; private const float ZREF = 1.09f; #endregion } public static class ColorConversion { public static C3f FromYuvToYxy(this C3f Yuv) { var Y = Yuv.R; var u = Yuv.G; var v = Yuv.B; return new C3f(Y, 3 * u / (2 * u - 8 * v + 4), 2 * v / (2 * u - 8 * v + 4)); } public static C3f FromYxyToXYZ(this C3f Yxy) { double Y = Yxy.R; double x = Yxy.G; double y = Yxy.B; //AZ: check for y == 0 needed - szabo: DONE if (y == 0) y = double.Epsilon; return new C3f((x * (Y / y)), Y, ((1 - x - y) * (Y / y))); } public static C3f FromXYZToYxy(this C3f XYZ) { double Y = XYZ.G; double x = XYZ.R / (XYZ.R + XYZ.G + XYZ.B); double y = XYZ.G / (XYZ.R + XYZ.G + XYZ.B); return new C3f(Y, x, y); } /// /// Returns the GamutMap represantion of the supplied C3f. /// public static C3f ToGamutMap(this C3f self) { return self.Clamped(0.0f, 1.0f); } /// /// Returns the int representation of the supplied C3f color. /// public static int FromRgbToInt(this C3f self) { return Col.FloatToByte(self.R) << 16 | Col.FloatToByte(self.G) << 8 | Col.FloatToByte(self.B); } } } ================================================ FILE: src/Aardvark.Base/Math/Base/DistributionFunction.cs ================================================ using System.Linq; using System.Runtime.CompilerServices; namespace Aardvark.Base { /// /// Represents a discrete function that is represented by a probability density function (PDF) /// and a cumulative distribution function (CDF). /// public class DistributionFunction { readonly double[] m_pdf; readonly double[] m_cdf; /// /// Gets the input probability density function. /// It is not necessarily normalized. /// public double[] PDF { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return m_pdf; } } /// /// Gets the calculated cumulative distribution function with +1 elements than the PDF. /// It is not necessarily normalized. /// public double[] CDF { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return m_cdf; } } /// /// Returns the normalization factor of the PDF and CDF. /// In case the supplied PDF is not normalized this factor will be != 1.0 and /// needs to be considered when interpreting the raw PDF or CDF values. /// public double Norm { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return m_cdf[m_cdf.Length - 1]; } } /// /// Create distribution from a discrete probability distribution function (PDF). /// The PDF does not need to be normalized. /// public DistributionFunction(double[] pdf) { m_pdf = pdf; m_cdf = m_pdf.Integrated(); } /// /// Create distribution from a discrete probability distribution function (PDF) /// and its cumulative distribution function (CDF). /// The PDF does not need to be normalized. /// public DistributionFunction(double[] pdf, double[] cdf) { m_pdf = pdf; m_cdf = cdf; } /// /// Retrieve random index distributed proportional to probability density function. /// Uses binary search O(log n). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public int Sample(IRandomUniform rnd) { return Sample(rnd.UniformDouble()); } /// /// Retrieve index to the discrete PDF where its cumulative distribution matches the random variable x1 [0, 1]. /// Uses binary search O(log n). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public int Sample(double x1) { return SampleCDF(m_cdf, x1); } /// /// Retrieve random index of a discretized PDF given its cumulative distribution function (CDF). /// Uses binary search O(log n). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int SampleCDF(double[] cdf, IRandomUniform rnd) { return SampleCDF(cdf, rnd.UniformDouble()); } /// /// Retrieve index of a discrete PDF given its cumulative distribution function (CDF) and a random variable x1 [0, 1]. /// Uses binary search O(log n). /// public static int SampleCDF(double[] cdf, double x1) { var range = cdf.Length; var valueToFind = x1 * cdf[range - 1]; // x1 * sum -> CDF threshold to find var i0 = 0; // binary search while (range > 0) { var halfRange = range >> 1; var center = i0 + halfRange; // check if value is left or right if (cdf[center] <= valueToFind) { // right half i0 = center + 1; range -= halfRange + 1; } else { // left half range = halfRange; } } return Fun.Clamp(i0 - 1, 0, cdf.Length - 2); } /// /// Gets the normalized probability density function value at the supplied index. /// The function is normalized to integrate to a value of 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public double PDFValue(int index) { return m_pdf[index] / this.Norm; } /// /// Gets the normalized cumulative distribution function value at the supplied index. /// The function is normalized to integrate to a value of 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public double CDFValue(int index) { return m_cdf[index] / this.Norm; } /// /// Inplace update of the CDF by re-integerating the PDF. /// public void UpdateCDF() { var cdf = m_cdf; var pdf = m_pdf; cdf[0] = 0; double acc = 0; for (int i = 0; i < pdf.Length;) { acc += pdf[i++]; cdf[i] = acc; } } } } ================================================ FILE: src/Aardvark.Base/Math/Base/Fraction.cs ================================================ using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; namespace Aardvark.Base { /// /// Represents an integral fraction. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public struct Fraction { [DataMember] public long Numerator; [DataMember] public long Denominator; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public Fraction(long value) { Numerator = value; Denominator = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Fraction(long numerator, long denominator) { // ensure positive denominator Numerator = denominator < 0 ? -numerator : numerator; Denominator = Fun.Abs(denominator); } #endregion #region Properties public readonly double Value { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (double)Numerator / Denominator; } } public readonly Fraction Reduced { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { long gcd = Fun.GreatestCommonDivisor(Numerator, Denominator); return new Fraction(Numerator / gcd, Denominator / gcd); } } #endregion #region Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Fraction operator +(Fraction a) { return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Fraction operator -(Fraction a) { return new Fraction(-a.Numerator, a.Denominator); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Fraction operator +(Fraction a, Fraction b) { long gcd = Fun.GreatestCommonDivisor(a.Denominator, b.Denominator); long aDenomDivGcd = a.Denominator / gcd; return new Fraction( a.Numerator * (b.Denominator / gcd) + b.Numerator * aDenomDivGcd, aDenomDivGcd * b.Denominator ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Fraction operator -(Fraction a, Fraction b) { return a + (-b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Fraction operator *(Fraction a, Fraction b) { return new Fraction( a.Numerator * b.Numerator, a.Denominator * b.Denominator ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Fraction operator /(Fraction a, Fraction b) { if (b.Numerator < 0) // ensure positive denominator return new Fraction( -a.Numerator * b.Denominator, -b.Numerator * a.Denominator ); return new Fraction( a.Numerator * b.Denominator, a.Denominator * b.Numerator ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator <(Fraction a, Fraction b) { return a.Value < b.Value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator <=(Fraction a, Fraction b) { return a.Value <= b.Value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Fraction a, Fraction b) { return a.Value == b.Value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Fraction a, Fraction b) { return a.Value != b.Value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator >=(Fraction a, Fraction b) { return a.Value >= b.Value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator >(Fraction a, Fraction b) { return a.Value > b.Value; } #endregion #region Constants /// /// Gets a that evaluates to 0. /// public static Fraction Zero => new Fraction(0, 1); /// /// Gets a that evaluates to 1. /// public static Fraction One => new Fraction(1, 1); /// /// Gets the smallest positive value greater than zero. /// public static Fraction Epsilon => new Fraction(1, long.MaxValue); /// /// Gets the smallest possible value of a . /// public static Fraction MinValue => new Fraction(long.MinValue, 1); /// /// Gets the largest possible value of a . /// public static Fraction MaxValue => new Fraction(long.MaxValue, 1); /// /// Gets a value that is not a number (NaN). /// public static Fraction NaN => new Fraction(0, 0); /// /// Represents negative infinity. /// public static Fraction NegativeInfinity => new Fraction(-1, 0); /// /// Represents positive infinity. /// public static Fraction PositiveInfinity => new Fraction(+1, 0); #endregion /// /// Returns whether the specified /// evaluates to negative or positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(Fraction f) { return f.Denominator == 0; } /// /// Returns whether the specified /// evaluates to negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(Fraction f) { return f.Denominator == 0 && f.Numerator < 0; } /// /// Returns whether the specified /// evaluates to positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(Fraction f) { return f.Denominator == 0 && f.Numerator > 0; } /// /// Returns whether the specified /// evaluates to a value that is not a number (Fraction.NaN). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(Fraction f) { return f.Denominator == 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Fraction other) => Numerator.Equals(other.Numerator) && Denominator.Equals(other.Denominator); public override readonly bool Equals(object obj) => (obj is Fraction o) ? Equals(o) : false; public override readonly int GetHashCode() { return Value.GetHashCode(); } public override readonly string ToString() { return Numerator + "/" + Denominator; } public static Fraction Parse(string s) { int sep = s.IndexOf('/'); if (sep < 0) return new Fraction(long.Parse(s)); return new Fraction( long.Parse(s.Substring(0, sep)), long.Parse(s.Substring(sep+1, s.Length-sep-1)) ); } } public static partial class Fun { #region ApproximateEquals /// /// Returns whether the given are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Fraction a, Fraction b, double tolerance) => ApproximateEquals(a.Value, b.Value, tolerance); /// /// Returns whether the given are equal within /// Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Fraction a, Fraction b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); #endregion } } ================================================ FILE: src/Aardvark.Base/Math/Base/Fun.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; namespace Aardvark.Base { public enum Winding { CCW = 0, CW = 1, } /// /// This enum can be used to store an aggregate sign classification /// of multiple entities whose sign ccan be classified. /// [Flags] public enum Signs { None = 0x00, Zero = 0x01, Negative = 0x02, Positive = 0x04, NonPositive = Negative | Zero, NonNegative = Positive | Zero, } public static partial class Fun { public static T Identity(T value) { return value; } #region Array Indices of Certain Elements /// /// For an array of monotonically increasing values, returns /// the index i of the largest value such that array[i] <= x. /// If x is smaller than the first value, then -1 is returned. /// If x is greater than the last value, then a.Length is returned. /// public static int IndexOfLargestLessOrEqual(this T[] a, T x) where T : IComparable { var r = new Range1i(0, a.Length - 1); if (x.CompareTo(a[0]) < 0) return -1; if (x.CompareTo(a[r.Max]) > 0) return a.Length; while (r.Size > 1) { var half = r.Center; if (x.CompareTo(a[half]) < 0) r.Max = half; else r.Min = half; } return r.Min; } /// /// For an array of monotonically increasing values, returns /// the index i of the largest value such that array[i] <= x. /// If x is smaller than the first value, then -1 is returned. /// If x is greater than the last value, then a.Length is returned. /// public static long LongIndexOfLargestLessOrEqual(this T[] a, T x) where T : IComparable { var r = new Range1l(0, a.Length - 1); if (x.CompareTo(a[0]) < 0) return -1; if (x.CompareTo(a[r.Max]) > 0) return a.Length; while (r.Size > 1) { var half = r.Center; if (x.CompareTo(a[half]) < 0) r.Max = half; else r.Min = half; } return r.Min; } /// /// For a list of monotonically increasing values, returns /// the index i of the largest value such that list[i] <= x. /// If x is smaller than the first value, then -1 is returned. /// If x is greater than the last value, then a.Count is returned. /// public static int IndexOfLargestLessOrEqual(this List a, T x) where T : IComparable { var r = new Range1i(0, a.Count - 1); if (x.CompareTo(a[0]) < 0) return -1; if (x.CompareTo(a[r.Max]) > 0) return a.Count; while (r.Size > 1) { int half = r.Center; if (x.CompareTo(a[half]) < 0) r.Max = half; else r.Min = half; } return r.Min; } #endregion #region Bit Operations public static int HighestBit(this int i) { if (i == 0) return -1; int bit = 31; if ((i & 0xFFFFFF00) == 0) { i <<= 24; bit = 7; } else if ((i & 0xFFFF0000) == 0) { i <<= 16; bit = 15; } else if ((i & 0xFF000000) == 0) { i <<= 8; bit = 23; } if ((i & 0xF0000000) == 0) { i <<= 4; bit -= 4; } while ((i & 0x80000000) == 0) { i <<= 1; bit--; } return bit; } public static int TrailingZeroBitCount(this long x) { x &= -x; int c = (x == 0) ? 1 : 0; if ((x & 0x00000000ffffffffL) == 0) c += 32; if ((x & 0x0000ffff0000ffffL) == 0) c += 16; if ((x & 0x00ff00ff00ff00ffL) == 0) c += 8; if ((x & 0x0f0f0f0f0f0f0f0fL) == 0) c += 4; if ((x & 0x3333333333333333L) == 0) c += 2; if ((x & 0x5555555555555555L) == 0) c += 1; return c; } public static int TrailingZeroBitCount(this int x) { x &= -x; int c = (x == 0) ? 1 : 0; if ((x & 0x0000ffff) == 0) c += 16; if ((x & 0x00ff00ff) == 0) c += 8; if ((x & 0x0f0f0f0f) == 0) c += 4; if ((x & 0x33333333) == 0) c += 2; if ((x & 0x55555555) == 0) c += 1; return c; } #endregion #region Bitwise Rotation /// /// Bitwise circular left shift. /// public static int BitwiseRotateLeft(this int value, int numberOfBits) { return (value << numberOfBits) | (value >> (32 - numberOfBits)); } /// /// Bitwise circular left shift. /// public static uint BitwiseRotateLeft(this uint value, int numberOfBits) { return (value << numberOfBits) | (value >> (32 - numberOfBits)); } /// /// Bitwise circular left shift. /// public static long BitwiseRotateLeft(this long value, int numberOfBits) { return (value << numberOfBits) | (value >> (64 - numberOfBits)); } /// /// Bitwise circular left shift. /// public static ulong BitwiseRotateLeft(this ulong value, int numberOfBits) { return (value << numberOfBits) | (value >> (64 - numberOfBits)); } #endregion #region Digits Counts of Integer/Fractional Parts public static int DigitCountOfIntegerPart(this double value) { var str = value.ToString(CultureInfo.InvariantCulture); var x = str.Split('.'); return x[0].Length; } public static int DigitCountOfFractionalPart(this double value) { var str = value.ToString(CultureInfo.InvariantCulture); var x = str.Split('.'); return x.Length < 2 ? 0 : x[1].Length; } public static int DigitCountOfIntegerPart(this float value) { return ((double)value).DigitCountOfIntegerPart(); } public static int DigitCountOfFractionalPart(this float value) { return ((double)value).DigitCountOfFractionalPart(); } #endregion #region Monotony public static bool IsMonotonicallyIncreasing(this IEnumerable self) where T : IComparable { foreach (var p in self.PairChain()) if (p.Item1.CompareTo(p.Item2) > 0) return false; return true; } public static bool IsStrictlyIncreasing(this IEnumerable self) where T : IComparable { foreach (var p in self.PairChain()) if (p.Item1.CompareTo(p.Item2) >= 0) return false; return true; } public static bool IsMonotonicallyDecreasing(this IEnumerable self) where T : IComparable { foreach (var p in self.PairChain()) if (p.Item1.CompareTo(p.Item2) < 0) return false; return true; } public static bool IsStrictlyDecreasing(this IEnumerable self) where T : IComparable { foreach (var p in self.PairChain()) if (p.Item1.CompareTo(p.Item2) <= 0) return false; return true; } #endregion #region Outer Sum public static Tup4 OuterSum(Tup2 x, Tup2 y) { return new Tup4(x.E0 + y.E0, x.E1 + y.E0, x.E0 + y.E1, x.E1 + y.E1); } public static Tup8 OuterSum(Tup2 x, Tup2 y, Tup2 z) { long y0z0 = y.E0 + z.E0, y1z0 = y.E1 + z.E0, y0z1 = y.E0 + z.E1, y1z1 = y.E1 + z.E1; return new Tup8(x.E0 + y0z0, x.E1 + y0z0, x.E0 + y1z0, x.E1 + y1z0, x.E0 + y0z1, x.E1 + y0z1, x.E0 + y1z1, x.E1 + y1z1); } public static Tup16 OuterSum(Tup4 x, Tup4 y) { return new Tup16(x.E0 + y.E0, x.E1 + y.E0, x.E2 + y.E0, x.E3 + y.E0, x.E0 + y.E1, x.E1 + y.E1, x.E2 + y.E1, x.E3 + y.E1, x.E0 + y.E2, x.E1 + y.E2, x.E2 + y.E2, x.E3 + y.E2, x.E0 + y.E3, x.E1 + y.E3, x.E2 + y.E3, x.E3 + y.E3); } #endregion #region Relative Epsilon public static float PlusRelativeEps(this float value, float eps) { if (value > 0) return value + eps * value; if (value < 0) return value - eps * value; return eps > 0 ? value + Constant.PositiveTinyValue : value - Constant.PositiveTinyValue; } public static float MinusRelativeEps(this float value, float eps) { if (value > 0) return value - eps * value; if (value < 0) return value + eps * value; return eps > 0 ? value - Constant.PositiveTinyValue : value + Constant.PositiveTinyValue; } public static double PlusRelativeEps(this double value, float eps) { if (value > 0) return value + eps * value; if (value < 0) return value - eps * value; return eps > 0 ? value + Constant.PositiveTinyValue : value - Constant.PositiveTinyValue; } public static double MinusRelativeEps(this double value, float eps) { if (value > 0) return value - eps * value; if (value < 0) return value + eps * value; return eps > 0 ? value - Constant.PositiveTinyValue : value + Constant.PositiveTinyValue; } #endregion #region Shannon Entropy /// /// Shannon entropy of values. /// public static double Entropy(this IEnumerable xs) { double total = xs.Count(); return xs.GroupBy(x => x) .Select(g => { double p = g.Count() / total; return p * -p.Log2(); }) .Sum(); } /// /// Shannon entropy of bipartite set. /// public static double Entropy(this bool[] xs) { if (xs == null) throw new ArgumentNullException("xs"); var count = xs.Length; var countPos = 0; var countNeg = 0; for (var i = 0; i < count; i++) { if (xs[i]) { countPos++; } else { countNeg++; } } if (countPos == 0 || countNeg == 0) return 0.0; var pPos = countPos / (double)count; var pNeg = countNeg / (double)count; var hPos = -Math.Log(pPos, 2); var hNeg = -Math.Log(pNeg, 2); var H = pPos * hPos + pNeg * hNeg; return H; } /// /// Shannon entropy of weighted bipartite set. /// public static double Entropy(this bool[] xs, double[] weights) { if (weights == null) throw new ArgumentNullException("weights"); if (xs == null) throw new ArgumentNullException("xs"); if (weights.Length != xs.Length) throw new ArgumentException("weights.Length != xs.Length"); var count = xs.Length; var countPos = 0.0; var countNeg = 0.0; for (var i = 0; i < count; i++) { if (xs[i]) { countPos += weights[i]; } else { countNeg += weights[i]; } } if (countPos == 0 || countNeg == 0) return 0.0; var pPos = countPos / (double)count; var pNeg = countNeg / (double)count; var hPos = -Math.Log(pPos, 2); var hNeg = -Math.Log(pNeg, 2); var H = pPos * hPos + pNeg * hNeg; return H; } #endregion #region Step [Pure] public static T Step(this float x, T a, T b) { return x < 0.5f ? a : b; } [Pure] public static T Step(this double x, T a, T b) { return x < 0.5 ? a : b; } #endregion #region Weight Functions for Interpolation /// /// Creates weight function for cubic interpolation according to /// "Comparison of Interpolating for Image Resampling" by /// J.A.Parker, R.V.Kenyon & D.E.Troxel, IEEE Transactions on /// Medical Imaging Vol. 2, 1983. Recommended values for a: /// -0.5 for medical/astronomical images, -1.0 for other photos. /// a = -0.5 exactly reconstructs second degree polynomials, /// a = -0.75 results in a continuous second derivative of the /// two polynomials used /// a = -1.0 matches the slope of the sinc function at 1 /// (amplifying frequencies just below the cutoff frequency) /// public static Func> CreateCubicTup4d(double a) { double ap2 = a + 2; double ap3 = a + 3; return t => { double tt = t * t; double tastta = (t - tt) * a, ttasttta = t * tastta; double ttap3stttap2 = tt * (ap3 - t * ap2); return new Tup4(tastta - ttasttta, 1 - ttap3stttap2, ttap3stttap2 - tastta, ttasttta); // Weights: // a t^3 - 2 a t^2 + a t = t ( a - a t (2 - t)) // (a+2) t^3 - (a+3) t^2 + 1 = 1 - t^2 ((a+3) - (a+2) t) // -(a+2) t^3 + (2a+3) t^2 - a t = t ( -a + t ((2a + 3) - (a+2) t)) // -a t^3 + a t^2 = t^2 a (1 - t) }; } /// /// Creates weight function for cubic interpolation according to /// "Comparison of Interpolating for Image Resampling" by /// J.A.Parker, R.V.Kenyon & D.E.Troxel, IEEE Transactions on /// Medical Imaging Vol. 2, 1983. Recommended values for a: /// -0.5 for medical/astronomical images, -1.0 for other photos. /// a = -0.5 exactly reconstructs second degree polynomials, /// a = -0.75 results in a continuous second derivative of the /// two polynomials used /// a = -1.0 matches the slope of the sinc function at 1 /// (amplifying frequencies just below the cutoff frequency) /// public static Func> CreateCubicTup4h(double a) { double ap2 = a + 2; double ap3 = a + 3; return t => { double tt = t * t; double tastta = (t - tt) * a, ttasttta = t * tastta; double ttap3stttap2 = tt * (ap3 - t * ap2); return new Tup4((Half)(tastta - ttasttta), (Half)(1 - ttap3stttap2), (Half)(ttap3stttap2 - tastta), (Half)ttasttta); }; } /// /// Creates weight function for cubic interpolation according to /// "Comparison of Interpolating for Image Resampling" by /// J.A.Parker, R.V.Kenyon & D.E.Troxel, IEEE Transactions on /// Medical Imaging Vol. 2, 1983. Recommended values for a: /// -0.5 for medical/astronomical images, -1.0 for other photos. /// a = -0.5 exactly reconstructs second degree polynomials, /// a = -0.75 results in a continuous second derivative of the /// two polynomials used /// a = -1.0 matches the slope of the sinc function at 1 /// (amplifying frequencies just below the cutoff frequency) /// public static Func> CreateCubicTup4f(double a) { double ap2 = a + 2; double ap3 = a + 3; return t => { double tt = t * t; double tastta = (t - tt) * a, ttasttta = t * tastta; double ttap3stttap2 = tt * (ap3 - t * ap2); return new Tup4((float)(tastta - ttasttta), (float)(1 - ttap3stttap2), (float)(ttap3stttap2 - tastta), (float)ttasttta); }; } /// /// Returns the weights of the cubic B-Spline function for four /// equally distant function points to approximate. The supplied /// parameter t in the range [0..1] traverses the approximation /// between the two center points. /// public static Tup4 BSpline3d(double t) => new Tup4( t*(t*(t*(-1/6.0) + 3/6.0) - 3/6.0) + 1/6.0, t*(t*(t*( 3/6.0) - 6/6.0) ) + 4/6.0, t*(t*(t*(-3/6.0) + 3/6.0) + 3/6.0) + 1/6.0, t*(t*(t*( 1/6.0) ) ) ); /// /// Returns the weights of the cubic B-Spline function for four /// equally distant function points to approximate. The supplied /// parameter t in the range [0..1] traverses the approximation /// between the two center points. /// public static Tup4 BSpline3h(double t) => new Tup4( (Half)(t*(t*(t*(-1/6.0) + 3/6.0) - 3/6.0) + 1/6.0), (Half)(t*(t*(t*( 3/6.0) - 6/6.0) ) + 4/6.0), (Half)(t*(t*(t*(-3/6.0) + 3/6.0) + 3/6.0) + 1/6.0), (Half)(t*(t*(t*( 1/6.0) ) ) )); /// /// Returns the weights of the cubic B-Spline function for four /// equally distant function points to approximate. The supplied /// parameter t in the range [0..1] traverses the approximation /// between the two center points. /// public static Tup4 BSpline3f(double t) => new Tup4( (float)(t*(t*(t*(-1/6.0) + 3/6.0) - 3/6.0) + 1/6.0), (float)(t*(t*(t*( 3/6.0) - 6/6.0) ) + 4/6.0), (float)(t*(t*(t*(-3/6.0) + 3/6.0) + 3/6.0) + 1/6.0), (float)(t*(t*(t*( 1/6.0) ) ) )); /// /// Returns the weights of the order 5 B-Spline function for six /// equally distant function points to approximate. The supplied /// parameter t in the range [0..1] traverses the approximation /// between the two center points. /// public static Tup6 BSpline5d(double t) => new Tup6( t*(t*(t*(t*(t*( -1/120.0) +5/120.0) -10/120.0) +10/120.0) -5/120.0) +1/120.0, t*(t*(t*(t*(t*( 5/120.0) -20/120.0) +20/120.0) +20/120.0) -50/120.0) +26/120.0, t*(t*(t*(t*(t*(-10/120.0) +30/120.0) ) -60/120.0) ) +66/120.0, t*(t*(t*(t*(t*( 10/120.0) -20/120.0) -20/120.0) +20/120.0) +50/120.0) +26/120.0, t*(t*(t*(t*(t*( -5/120.0) +5/120.0) +10/120.0) +10/120.0) +5/120.0) +1/120.0, t*(t*(t*(t*(t*( 1/120.0) ) ) ) ) ); /// /// Returns the weights of the order 5 B-Spline function for six /// equally distant function points to approximate. The supplied /// parameter t in the range [0..1] traverses the approximation /// between the two center points. /// public static Tup6 BSpline5h(double t) => new Tup6( (Half)(t*(t*(t*(t*(t*( -1/120.0) +5/120.0) -10/120.0) +10/120.0) -5/120.0) +1/120.0), (Half)(t*(t*(t*(t*(t*( 5/120.0) -20/120.0) +20/120.0) +20/120.0) -50/120.0) +26/120.0), (Half)(t*(t*(t*(t*(t*(-10/120.0) +30/120.0) ) -60/120.0) ) +66/120.0), (Half)(t*(t*(t*(t*(t*( 10/120.0) -20/120.0) -20/120.0) +20/120.0) +50/120.0) +26/120.0), (Half)(t*(t*(t*(t*(t*( -5/120.0) +5/120.0) +10/120.0) +10/120.0) +5/120.0) +1/120.0), (Half)(t*(t*(t*(t*(t*( 1/120.0) ) ) ) ) )); /// /// Returns the weights of the order 5 B-Spline function for six /// equally distant function points to approximate. The supplied /// parameter t in the range [0..1] traverses the approximation /// between the two center points. /// public static Tup6 BSpline5f(double t) => new Tup6( (float)(t*(t*(t*(t*(t*( -1/120.0) +5/120.0) -10/120.0) +10/120.0) -5/120.0) +1/120.0), (float)(t*(t*(t*(t*(t*( 5/120.0) -20/120.0) +20/120.0) +20/120.0) -50/120.0) +26/120.0), (float)(t*(t*(t*(t*(t*(-10/120.0) +30/120.0) ) -60/120.0) ) +66/120.0), (float)(t*(t*(t*(t*(t*( 10/120.0) -20/120.0) -20/120.0) +20/120.0) +50/120.0) +26/120.0), (float)(t*(t*(t*(t*(t*( -5/120.0) +5/120.0) +10/120.0) +10/120.0) +5/120.0) +1/120.0), (float)(t*(t*(t*(t*(t*( 1/120.0) ) ) ) ) )); public static Tup6 Lanczos3d(double x) { const double a = 1.0/3.0; double px = Constant.Pi * x, pxa = px * a; if (pxa.IsTiny()) return new Tup6(0.0, 0.0, 1.0, 0.0, 0.0, 0.0); double p1mx = Constant.Pi - px, p1mxa = p1mx * a; if (p1mxa.IsTiny()) return new Tup6(0.0, 0.0, 0.0, 1.0, 0.0, 0.0); double p1px = Constant.Pi + px, p2px = Constant.PiTimesTwo + px; double p2mx = Constant.PiTimesTwo - px, p3mx = Constant.PiTimesThree - px; double spx = Fun.Sin(px), spxa = Fun.Sin(pxa); double sp1pxa = Fun.Sin(p1px * a), sp2pxa = Fun.Sin(p2px * a); return new Tup6(spx * sp2pxa / (p2px * p2px * a), -spx * sp1pxa / (p1px * p1px * a), (spx / px) * (spxa / pxa), (spx / p1mx) * (sp2pxa / p1mxa), -spx * sp1pxa / (p2mx * p2mx * a), spx * spxa / (p3mx * p3mx * a)); } public static Tup6 Lanczos3h(double x) { const double a = 1.0 / 3.0; double px = Constant.Pi * x, pxa = px * a; if (pxa.IsTiny()) return new Tup6((Half)0.0f, (Half)0.0f, (Half)1.0f, (Half)0.0f, (Half)0.0f, (Half)0.0f); double p1mx = Constant.Pi - px, p1mxa = p1mx * a; if (p1mxa.IsTiny()) return new Tup6((Half)0.0f, (Half)0.0f, (Half)0.0f, (Half)1.0f, (Half)0.0f, (Half)0.0f); double p1px = Constant.Pi + px, p2px = Constant.PiTimesTwo + px; double p2mx = Constant.PiTimesTwo - px, p3mx = Constant.PiTimesThree - px; double spx = Fun.Sin(px), spxa = Fun.Sin(pxa); double sp1pxa = Fun.Sin(p1px * a), sp2pxa = Fun.Sin(p2px * a); return new Tup6( (Half)(spx * sp2pxa / (p2px * p2px * a)), (Half)(-spx * sp1pxa / (p1px * p1px * a)), (Half)((spx / px) * (spxa / pxa)), (Half)((spx / p1mx) * (sp2pxa / p1mxa)), (Half)(-spx * sp1pxa / (p2mx * p2mx * a)), (Half)(spx * spxa / (p3mx * p3mx * a))); } public static Tup6 Lanczos3f(double x) { const double a = 1.0 / 3.0; double px = Constant.Pi * x, pxa = px * a; if (pxa.IsTiny()) return new Tup6(0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); double p1mx = Constant.Pi - px, p1mxa = p1mx * a; if (p1mxa.IsTiny()) return new Tup6(0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f); double p1px = Constant.Pi + px, p2px = Constant.PiTimesTwo + px; double p2mx = Constant.PiTimesTwo - px, p3mx = Constant.PiTimesThree - px; double spx = Fun.Sin(px), spxa = Fun.Sin(pxa); double sp1pxa = Fun.Sin(p1px * a), sp2pxa = Fun.Sin(p2px * a); return new Tup6( (float)(spx * sp2pxa / (p2px * p2px * a)), (float)(-spx * sp1pxa / (p1px * p1px * a)), (float)((spx / px) * (spxa / pxa)), (float)((spx / p1mx) * (sp2pxa / p1mxa)), (float)(-spx * sp1pxa / (p2mx * p2mx * a)), (float)(spx * spxa / (p3mx * p3mx * a))); } #endregion #region Pythagoras /// /// Computes sqrt(a²+b²) without destructive underflow or overflow. /// public static double Pythag(double a, double b) { double at = a > 0 ? a : -a, bt = b > 0 ? b : -b, ct, result; if (at > bt) { ct = bt / at; result = at * Math.Sqrt(1.0 + ct * ct); } else if (bt > 0.0) { ct = at / bt; result = bt * Math.Sqrt(1.0 + ct * ct); } else result = 0.0; return result; } #endregion #region Log2Int /// /// the number of bits used for storing the double-mantissa /// public const int DoubleMantissaBits = 52; /// /// the bitmask used for the double exponent /// public const ulong DoubleExponentMask = 0x7FF0000000000000; /// /// the bitmask used for the double mantissa /// public const ulong DoubleMantissaMask = 0x000FFFFFFFFFFFFF; /// /// the number of bits used for storing the float-mantissa /// public const int FloatMantissaBits = 23; /// /// the bitmask used for the float exponent /// public const uint FloatExponentMask = 0x7F800000; /// /// the bitmask used for the float mantissa /// public const uint FloatMantissaMask = 0x007FFFFF; [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe int Log2IntRef(ref double v) { fixed (double* ptr = &v) { var a = (ulong*)ptr; return (int)(((*a & DoubleExponentMask) >> DoubleMantissaBits)) - 1023; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe int Log2IntRef(ref float v) { fixed (float* ptr = &v) { var a = (uint*)ptr; return (int)(((*a & FloatExponentMask) >> FloatMantissaBits)) - 127; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe int Log2CeilingIntRef(ref double v) { fixed (double* ptr = &v) { var a = (ulong*)ptr; var shift = (*a & DoubleMantissaMask) > 0 ? 1022 : 1023; return (int)(((*a & DoubleExponentMask) >> DoubleMantissaBits)) - shift; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe int Log2CeilingIntRef(ref float v) { fixed (float* ptr = &v) { var a = (uint*)ptr; var shift = (*a & FloatMantissaMask) > 0 ? 126 : 127; return (int)(((*a & FloatExponentMask) >> FloatMantissaBits)) - shift; } } /// /// Efficiently computes the Log2 for the given value rounded to the next integer towards negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Log2Int(this double v) => Log2IntRef(ref v); /// /// Efficiently computes the Log2 for the given value rounded to the next integer towards negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Log2Int(this float v) => Log2IntRef(ref v); /// /// Efficiently computes the Log2 for the given value rounded to the next integer towards negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Log2Int(this int v) { #if NETCOREAPP3_1_OR_GREATER return System.Numerics.BitOperations.Log2((uint)v); #else return Log2Int((float)v); #endif } /// /// Efficiently computes the Log2 for the given value rounded to the next integer towards negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Log2Int(this uint v) { #if NETCOREAPP3_1_OR_GREATER return System.Numerics.BitOperations.Log2(v); #else return Log2Int((float)v); #endif } /// /// Efficiently computes the Log2 for the given value rounded to the next integer towards negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Log2Int(this long v) { #if NETCOREAPP3_1_OR_GREATER return System.Numerics.BitOperations.Log2((ulong)v); #else return Log2Int((double)v); #endif } /// /// Efficiently computes the Log2 for the given value rounded to the next integer towards negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Log2Int(this ulong v) { #if NETCOREAPP3_1_OR_GREATER return System.Numerics.BitOperations.Log2(v); #else return Log2Int((double)v); #endif } /// /// Efficiently computes the Log2 for the given value rounded to the next integer towards positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Log2CeilingInt(this double v) => Log2CeilingIntRef(ref v); /// /// Efficiently computes the Log2 for the given value rounded to the next integer towards positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Log2CeilingInt(this float v) => Log2CeilingIntRef(ref v); /// /// Efficiently computes the Log2 for the given value rounded to the next integer towards positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Log2CeilingInt(this int v) => Log2CeilingInt((float)v); /// /// Efficiently computes the Log2 for the given value rounded to the next integer towards positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Log2CeilingInt(this uint v) => Log2CeilingInt((float)v); /// /// Efficiently computes the Log2 for the given value rounded to the next integer towards positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Log2CeilingInt(this long v) => Log2CeilingInt((double)v); /// /// Efficiently computes the Log2 for the given value rounded to the next integer towards positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Log2CeilingInt(this ulong v) => Log2CeilingInt((double)v); #endregion #region Mipmap levels /// /// Computes the number of 3D images in a mipmap chain with the given base size. /// /// The size of the image in the base level. /// The total number of levels. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MipmapLevels(V3i baseSize) => 1 + Log2Int(baseSize.MaxElement); /// /// Computes the number of 2D images in a mipmap chain with the given base size. /// /// The size of the image in the base level. /// The total number of levels. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MipmapLevels(V2i baseSize) => 1 + Log2Int(baseSize.MaxElement); /// /// Computes the number of 1D images in a mipmap chain with the given base size. /// /// The size of the image in the base level. /// The total number of levels. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MipmapLevels(int baseSize) => 1 + Log2Int(baseSize); /// /// Computes the size of a 3D image in a mipmap chain. /// /// The size of the image in the base level. /// The level of the queried image (base level = 0). /// The size of the image at the given level. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i MipmapLevelSize(V3i baseSize, int level) => Max(baseSize >> level, 1); /// /// Computes the size of a 2D image in a mipmap chain. /// /// The size of the image in the base level. /// The level of the queried image (base level = 0). /// The size of the image at the given level. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i MipmapLevelSize(V2i baseSize, int level) => Max(baseSize >> level, 1); /// /// Computes the size of a 1D image in a mipmap chain. /// /// The size of the image in the base level. /// The level of the queried image (base level = 0). /// The size of the image at the given level. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MipmapLevelSize(int baseSize, int level) => Max(baseSize >> level, 1); #endregion #region Gaussian /// /// Returns the function value of the normalized Gaussian distribution /// with the given standard deviation. /// public static double Gauss(double x, double stdDev) { var rcpS = 1.0 / stdDev; return rcpS / Constant.SqrtPiTimesTwo * Fun.Exp(-0.5 * (x * stdDev).Square()); } /// /// Returns the function value of the normalized elliptical 2d Gaussian distribution /// with different standard deviations in x and y. /// public static double Gauss2d(double x, double y, double sx, double sy) { return 1.0 / (sx * sy * Constant.PiTimesTwo) * Fun.Exp(-0.5 * ((x / sx).Square() + (y / sy).Square())); } /// /// Returns the function value of the normalized elliptical 2d Gaussian distribution /// with different standard deviations in x and y. /// public static double Gauss2d(V2d p, double sx, double sy) { return 1.0 / (sx * sy * Constant.PiTimesTwo) * Fun.Exp(-0.5 * ((p.X / sx).Square() + (p.Y / sy).Square())); } /// /// Returns the function value of the normalized 2d Gaussian distribution with /// given symmetrical standard deviation. /// public static double Gauss2d(double x, double y, double s) { var halfRcpS2 = 0.5 / s.Square(); return halfRcpS2 * Constant.PiInv * Fun.Exp(-(x * x + y * y) * halfRcpS2); } /// /// Returns the function value of the normalized 2d Gaussian distribution with /// given symmetrical standard deviation. /// public static double Gauss2d(V2d p, double s) { var halfRcpS2 = 0.5 / s.Square(); return halfRcpS2 * Constant.PiInv * Fun.Exp(-p.LengthSquared * halfRcpS2); } /// /// Gaussian error function using a numerical approximation /// https://www.johndcook.com/blog/csharp_erf/ /// public static double Erf(double x) { // constants double a1 = 0.254829592; double a2 = -0.284496736; double a3 = 1.421413741; double a4 = -1.453152027; double a5 = 1.061405429; double p = 0.3275911; // Save the sign of x int sign = 1; if (x < 0) sign = -1; x = Math.Abs(x); // A&S formula 7.1.26 double t = 1.0 / (1.0 + p * x); double y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * Math.Exp(-x * x); return sign * y; } /// /// Gaussian error function using a numerical approximation with /// a maximum error of 1.2e-7 /// Wikipedia https://en.wikipedia.org/wiki/Error_function#Numerical_approximations /// public static double Erf2(double x) { // constants double a = -1.26551223; double b = 1.00002368; double c = 0.37409196; double d = 0.09678418; double e = -0.18628806; double f = 0.27886807; double g = -1.13520398; double h = 1.48851587; double j = -0.82215223; double k = 0.17087277; var t = 1.0 / (1.0 + 0.5 * x.Abs()); var r = t * Fun.Exp(-x.Square() + a + t * (b + t * (c + t * (d + t * (e + t * (f + t * (g + t * (h + t * (j + t * k))))))))); return x >= 0 ? 1 - r : r - 1; } #endregion } #region KahanSum /// /// A simple quadruple precision sum (around 108 bit) based on Kahan's /// summation method. This is used in Stats, to maintain higher precision /// sums for statistical moment computation. /// public struct KahanSum { private double m_sum; private double m_carry; public KahanSum(double sum, double carry) { m_sum = sum; m_carry = carry; } public KahanSum(double sum) : this(sum, 0.0) { } public void Add(double value) { double y = value - m_carry; double t = m_sum + y; m_carry = (t - m_sum) - y; m_sum = t; } public void Sub(double value) { double y = -value - m_carry; double t = m_sum + y; m_carry = (t - m_sum) - y; m_sum = t; } public void Add(KahanSum sum) { Sub(sum.m_carry); Add(sum.m_sum); } public void Sub(KahanSum sum) { Add(sum.m_carry); Sub(sum.m_sum); } public readonly double Value { get { return m_sum; } } public static KahanSum operator +(KahanSum sum, double value) { double y = value - sum.m_carry; double t = sum.m_sum + y; return new KahanSum(t, (t - sum.m_sum) - y); } public static KahanSum operator -(KahanSum sum, double value) { double y = -value - sum.m_carry; double t = sum.m_sum + y; return new KahanSum(t, (t - sum.m_sum) - y); } public static KahanSum operator +(KahanSum sum0, KahanSum sum1) { var r = sum0 - sum1.m_carry; r.Add(sum1.m_sum); return r; } public static KahanSum operator -(KahanSum sum0, KahanSum sum1) { var r = sum0 + sum1.m_carry; r.Sub(sum1.m_sum); return r; } public static readonly KahanSum Zero = new KahanSum(0.0); } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Base/Fun_auto.cs ================================================ using System; using System.ComponentModel; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.Contracts; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTOGENERATED CODE - DO NOT CHANGE! public static partial class Fun { #region Min and Max /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Min(this byte a, byte b) => a < b ? a : b; /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Max(this byte a, byte b) => a > b ? a : b; /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Min(this byte a, byte b, byte c) => a < b ? (a < c ? a : c) : (b < c ? b : c); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Max(this byte a, byte b, byte c) => a > b ? (a > c ? a : c) : (b > c ? b : c); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Min(this byte a, byte b, byte c, byte d) => Min(Min(a, b), Min(c, d)); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Max(this byte a, byte b, byte c, byte d) => Max(Max(a, b), Max(c, d)); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Min(this byte x, params byte[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Min(result, values[i]); } return result; } /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Max(this byte x, params byte[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Max(result, values[i]); } return result; } /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Min(this sbyte a, sbyte b) => a < b ? a : b; /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Max(this sbyte a, sbyte b) => a > b ? a : b; /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Min(this sbyte a, sbyte b, sbyte c) => a < b ? (a < c ? a : c) : (b < c ? b : c); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Max(this sbyte a, sbyte b, sbyte c) => a > b ? (a > c ? a : c) : (b > c ? b : c); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Min(this sbyte a, sbyte b, sbyte c, sbyte d) => Min(Min(a, b), Min(c, d)); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Max(this sbyte a, sbyte b, sbyte c, sbyte d) => Max(Max(a, b), Max(c, d)); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Min(this sbyte x, params sbyte[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Min(result, values[i]); } return result; } /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Max(this sbyte x, params sbyte[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Max(result, values[i]); } return result; } /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Min(this short a, short b) => a < b ? a : b; /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Max(this short a, short b) => a > b ? a : b; /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Min(this short a, short b, short c) => a < b ? (a < c ? a : c) : (b < c ? b : c); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Max(this short a, short b, short c) => a > b ? (a > c ? a : c) : (b > c ? b : c); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Min(this short a, short b, short c, short d) => Min(Min(a, b), Min(c, d)); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Max(this short a, short b, short c, short d) => Max(Max(a, b), Max(c, d)); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Min(this short x, params short[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Min(result, values[i]); } return result; } /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Max(this short x, params short[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Max(result, values[i]); } return result; } /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Min(this ushort a, ushort b) => a < b ? a : b; /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Max(this ushort a, ushort b) => a > b ? a : b; /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Min(this ushort a, ushort b, ushort c) => a < b ? (a < c ? a : c) : (b < c ? b : c); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Max(this ushort a, ushort b, ushort c) => a > b ? (a > c ? a : c) : (b > c ? b : c); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Min(this ushort a, ushort b, ushort c, ushort d) => Min(Min(a, b), Min(c, d)); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Max(this ushort a, ushort b, ushort c, ushort d) => Max(Max(a, b), Max(c, d)); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Min(this ushort x, params ushort[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Min(result, values[i]); } return result; } /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Max(this ushort x, params ushort[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Max(result, values[i]); } return result; } /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Min(this int a, int b) => a < b ? a : b; /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Max(this int a, int b) => a > b ? a : b; /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Min(this int a, int b, int c) => a < b ? (a < c ? a : c) : (b < c ? b : c); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Max(this int a, int b, int c) => a > b ? (a > c ? a : c) : (b > c ? b : c); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Min(this int a, int b, int c, int d) => Min(Min(a, b), Min(c, d)); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Max(this int a, int b, int c, int d) => Max(Max(a, b), Max(c, d)); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Min(this int x, params int[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Min(result, values[i]); } return result; } /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Max(this int x, params int[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Max(result, values[i]); } return result; } /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Min(this uint a, uint b) => a < b ? a : b; /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Max(this uint a, uint b) => a > b ? a : b; /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Min(this uint a, uint b, uint c) => a < b ? (a < c ? a : c) : (b < c ? b : c); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Max(this uint a, uint b, uint c) => a > b ? (a > c ? a : c) : (b > c ? b : c); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Min(this uint a, uint b, uint c, uint d) => Min(Min(a, b), Min(c, d)); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Max(this uint a, uint b, uint c, uint d) => Max(Max(a, b), Max(c, d)); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Min(this uint x, params uint[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Min(result, values[i]); } return result; } /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Max(this uint x, params uint[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Max(result, values[i]); } return result; } /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Min(this long a, long b) => a < b ? a : b; /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Max(this long a, long b) => a > b ? a : b; /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Min(this long a, long b, long c) => a < b ? (a < c ? a : c) : (b < c ? b : c); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Max(this long a, long b, long c) => a > b ? (a > c ? a : c) : (b > c ? b : c); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Min(this long a, long b, long c, long d) => Min(Min(a, b), Min(c, d)); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Max(this long a, long b, long c, long d) => Max(Max(a, b), Max(c, d)); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Min(this long x, params long[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Min(result, values[i]); } return result; } /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Max(this long x, params long[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Max(result, values[i]); } return result; } /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Min(this ulong a, ulong b) => a < b ? a : b; /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Max(this ulong a, ulong b) => a > b ? a : b; /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Min(this ulong a, ulong b, ulong c) => a < b ? (a < c ? a : c) : (b < c ? b : c); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Max(this ulong a, ulong b, ulong c) => a > b ? (a > c ? a : c) : (b > c ? b : c); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Min(this ulong a, ulong b, ulong c, ulong d) => Min(Min(a, b), Min(c, d)); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Max(this ulong a, ulong b, ulong c, ulong d) => Max(Max(a, b), Max(c, d)); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Min(this ulong x, params ulong[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Min(result, values[i]); } return result; } /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Max(this ulong x, params ulong[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Max(result, values[i]); } return result; } /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Min(this float a, float b) => a < b ? a : b; /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Max(this float a, float b) => a > b ? a : b; /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Min(this float a, float b, float c) => a < b ? (a < c ? a : c) : (b < c ? b : c); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Max(this float a, float b, float c) => a > b ? (a > c ? a : c) : (b > c ? b : c); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Min(this float a, float b, float c, float d) => Min(Min(a, b), Min(c, d)); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Max(this float a, float b, float c, float d) => Max(Max(a, b), Max(c, d)); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Min(this float x, params float[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Min(result, values[i]); } return result; } /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Max(this float x, params float[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Max(result, values[i]); } return result; } /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Min(this double a, double b) => a < b ? a : b; /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Max(this double a, double b) => a > b ? a : b; /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Min(this double a, double b, double c) => a < b ? (a < c ? a : c) : (b < c ? b : c); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Max(this double a, double b, double c) => a > b ? (a > c ? a : c) : (b > c ? b : c); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Min(this double a, double b, double c, double d) => Min(Min(a, b), Min(c, d)); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Max(this double a, double b, double c, double d) => Max(Max(a, b), Max(c, d)); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Min(this double x, params double[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Min(result, values[i]); } return result; } /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Max(this double x, params double[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Max(result, values[i]); } return result; } /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Min(this decimal a, decimal b) => a < b ? a : b; /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Max(this decimal a, decimal b) => a > b ? a : b; /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Min(this decimal a, decimal b, decimal c) => a < b ? (a < c ? a : c) : (b < c ? b : c); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Max(this decimal a, decimal b, decimal c) => a > b ? (a > c ? a : c) : (b > c ? b : c); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Min(this decimal a, decimal b, decimal c, decimal d) => Min(Min(a, b), Min(c, d)); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Max(this decimal a, decimal b, decimal c, decimal d) => Max(Max(a, b), Max(c, d)); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Min(this decimal x, params decimal[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Min(result, values[i]); } return result; } /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Max(this decimal x, params decimal[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Max(result, values[i]); } return result; } /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Fraction Min(this Fraction a, Fraction b) => a < b ? a : b; /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Fraction Max(this Fraction a, Fraction b) => a > b ? a : b; /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Fraction Min(this Fraction a, Fraction b, Fraction c) => a < b ? (a < c ? a : c) : (b < c ? b : c); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Fraction Max(this Fraction a, Fraction b, Fraction c) => a > b ? (a > c ? a : c) : (b > c ? b : c); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Fraction Min(this Fraction a, Fraction b, Fraction c, Fraction d) => Min(Min(a, b), Min(c, d)); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Fraction Max(this Fraction a, Fraction b, Fraction c, Fraction d) => Max(Max(a, b), Max(c, d)); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Fraction Min(this Fraction x, params Fraction[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Min(result, values[i]); } return result; } /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Fraction Max(this Fraction x, params Fraction[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Max(result, values[i]); } return result; } /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DateTime Min(this DateTime a, DateTime b) => a < b ? a : b; /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DateTime Max(this DateTime a, DateTime b) => a > b ? a : b; /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DateTime Min(this DateTime a, DateTime b, DateTime c) => a < b ? (a < c ? a : c) : (b < c ? b : c); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DateTime Max(this DateTime a, DateTime b, DateTime c) => a > b ? (a > c ? a : c) : (b > c ? b : c); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DateTime Min(this DateTime a, DateTime b, DateTime c, DateTime d) => Min(Min(a, b), Min(c, d)); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DateTime Max(this DateTime a, DateTime b, DateTime c, DateTime d) => Max(Max(a, b), Max(c, d)); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DateTime Min(this DateTime x, params DateTime[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Min(result, values[i]); } return result; } /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DateTime Max(this DateTime x, params DateTime[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Max(result, values[i]); } return result; } /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TimeSpan Min(this TimeSpan a, TimeSpan b) => a < b ? a : b; /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TimeSpan Max(this TimeSpan a, TimeSpan b) => a > b ? a : b; /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TimeSpan Min(this TimeSpan a, TimeSpan b, TimeSpan c) => a < b ? (a < c ? a : c) : (b < c ? b : c); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TimeSpan Max(this TimeSpan a, TimeSpan b, TimeSpan c) => a > b ? (a > c ? a : c) : (b > c ? b : c); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TimeSpan Min(this TimeSpan a, TimeSpan b, TimeSpan c, TimeSpan d) => Min(Min(a, b), Min(c, d)); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TimeSpan Max(this TimeSpan a, TimeSpan b, TimeSpan c, TimeSpan d) => Max(Max(a, b), Max(c, d)); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TimeSpan Min(this TimeSpan x, params TimeSpan[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Min(result, values[i]); } return result; } /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TimeSpan Max(this TimeSpan x, params TimeSpan[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Max(result, values[i]); } return result; } #endregion #region Abs /// /// Returns the absolute value of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Abs(this sbyte x) { return Math.Abs(x); } /// /// Returns the absolute value of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Abs(this short x) { return Math.Abs(x); } /// /// Returns the absolute value of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Abs(this int x) { return Math.Abs(x); } /// /// Returns the absolute value of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Abs(this long x) { return Math.Abs(x); } /// /// Returns the absolute value of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Abs(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Abs(x); #else return Math.Abs(x); #endif } /// /// Returns the absolute value of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Abs(this double x) { return Math.Abs(x); } /// /// Returns the absolute value of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Abs(this decimal x) { return Math.Abs(x); } #endregion #region Angular Distance /// /// Returns the absolute difference between two angles in radians. /// The result is within the range of [0, Pi]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float AngleDistance(this float alphaInRadians, float betaInRadians) { var phi = Abs(betaInRadians - alphaInRadians) % ConstantF.PiTimesTwo; return (phi > ConstantF.Pi) ? ConstantF.PiTimesTwo - phi : phi; } /// /// Returns the signed difference between two angles in radians. /// The result is within the range of [-Pi, Pi). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float AngleDifference(this float alphaInRadians, float betaInRadians) { var phi = (betaInRadians - alphaInRadians + ConstantF.Pi) % ConstantF.PiTimesTwo - ConstantF.Pi; return (phi < -ConstantF.Pi) ? phi + ConstantF.PiTimesTwo : phi; } /// /// Returns the absolute difference between two angles in radians. /// The result is within the range of [0, Pi]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double AngleDistance(this double alphaInRadians, double betaInRadians) { var phi = Abs(betaInRadians - alphaInRadians) % Constant.PiTimesTwo; return (phi > Constant.Pi) ? Constant.PiTimesTwo - phi : phi; } /// /// Returns the signed difference between two angles in radians. /// The result is within the range of [-Pi, Pi). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double AngleDifference(this double alphaInRadians, double betaInRadians) { var phi = (betaInRadians - alphaInRadians + Constant.Pi) % Constant.PiTimesTwo - Constant.Pi; return (phi < -Constant.Pi) ? phi + Constant.PiTimesTwo : phi; } #endregion #region ApproximateEquals /// /// Returns whether the distance between x and y is not more than epsilon. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this byte x, byte y, byte epsilon) { return (x > y) ? ((x - y) <= epsilon) : ((y - x) <= epsilon); } /// /// Returns whether the distance between x and y is not more than epsilon. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this sbyte x, sbyte y, sbyte epsilon) { return Abs(x - y) <= epsilon; } /// /// Returns whether the distance between x and y is not more than epsilon. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this short x, short y, short epsilon) { return Abs(x - y) <= epsilon; } /// /// Returns whether the distance between x and y is not more than epsilon. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this ushort x, ushort y, ushort epsilon) { return (x > y) ? ((x - y) <= epsilon) : ((y - x) <= epsilon); } /// /// Returns whether the distance between x and y is not more than epsilon. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this int x, int y, int epsilon) { return Abs(x - y) <= epsilon; } /// /// Returns whether the distance between x and y is not more than epsilon. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this uint x, uint y, uint epsilon) { return (x > y) ? ((x - y) <= epsilon) : ((y - x) <= epsilon); } /// /// Returns whether the distance between x and y is not more than epsilon. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this long x, long y, long epsilon) { return Abs(x - y) <= epsilon; } /// /// Returns whether the distance between x and y is not more than epsilon. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this ulong x, ulong y, ulong epsilon) { return (x > y) ? ((x - y) <= epsilon) : ((y - x) <= epsilon); } /// /// Returns whether the distance between x and y is not more than epsilon. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this float x, float y, float epsilon) { return Abs(x - y) <= epsilon; } /// /// Returns whether the distance between x and y is not more than epsilon. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this double x, double y, double epsilon) { return Abs(x - y) <= epsilon; } /// /// Returns whether the distance between x and y is not more than /// Constant{float}.PositiveTinyValue. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this float x, float y) => ApproximateEquals(x, y, Constant.PositiveTinyValue); /// /// Returns whether the distance between x and y is not more than /// Constant{double}.PositiveTinyValue. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this double x, double y) => ApproximateEquals(x, y, Constant.PositiveTinyValue); #endregion #region Floor /// /// Returns the largest integer less than or equal to the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Floor(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Floor(x); #else return (float) Math.Floor(x); #endif } /// /// Returns the largest integer less than or equal to the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Floor(this double x) { return Math.Floor(x); } /// /// Returns the largest integer less than or equal to the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Floor(this decimal x) { return Decimal.Floor(x); } #endregion #region Ceiling /// /// Returns the smallest integer greater than or equal to the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Ceiling(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Ceiling(x); #else return (float) Math.Ceiling(x); #endif } /// /// Returns the smallest integer greater than or equal to the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Ceiling(this double x) { return Math.Ceiling(x); } /// /// Returns the smallest integer greater than or equal to the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Ceiling(this decimal x) { return Decimal.Ceiling(x); } #endregion #region Round /// /// Rounds a floating-point value to the nearest integral value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Round(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Round(x); #else return (float) Math.Round(x); #endif } /// /// Rounds a floating-point value to the nearest integral value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Round(this float x, MidpointRounding mode) { #if NETCOREAPP3_1_OR_GREATER return MathF.Round(x, mode); #else return (float) Math.Round(x, mode); #endif } /// /// Rounds a floating-point value to the nearest integral value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Round(this float x, int digits) { #if NETCOREAPP3_1_OR_GREATER return MathF.Round(x, digits); #else return (float) Math.Round(x, digits); #endif } /// /// Rounds a floating-point value to the nearest integral value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Round(this float x, int digits, MidpointRounding mode) { #if NETCOREAPP3_1_OR_GREATER return MathF.Round(x, digits, mode); #else return (float) Math.Round(x, digits, mode); #endif } /// /// Rounds a floating-point value to the nearest integral value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Round(this double x) { return Math.Round(x); } /// /// Rounds a floating-point value to the nearest integral value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Round(this double x, MidpointRounding mode) { return Math.Round(x, mode); } /// /// Rounds a floating-point value to the nearest integral value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Round(this double x, int digits) { return Math.Round(x, digits); } /// /// Rounds a floating-point value to the nearest integral value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Round(this double x, int digits, MidpointRounding mode) { return Math.Round(x, digits, mode); } /// /// Rounds a floating-point value to the nearest integral value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Round(this decimal x) { return Decimal.Round(x); } /// /// Rounds a floating-point value to the nearest integral value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Round(this decimal x, MidpointRounding mode) { return Decimal.Round(x, mode); } /// /// Rounds a floating-point value to the nearest integral value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Round(this decimal x, int digits) { return Decimal.Round(x, digits); } /// /// Rounds a floating-point value to the nearest integral value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Round(this decimal x, int digits, MidpointRounding mode) { return Decimal.Round(x, digits, mode); } #endregion #region Truncate /// /// Rounds a floating-point value to the nearest integar towards zero. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Truncate(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Truncate(x); #else return (float) Math.Truncate(x); #endif } /// /// Rounds a floating-point value to the nearest integar towards zero. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Truncate(this double x) { return Math.Truncate(x); } /// /// Rounds a floating-point value to the nearest integar towards zero. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Truncate(this decimal x) { return Decimal.Truncate(x); } #endregion #region Frac /// /// Returns the fractional part of t. Calculated as t - floor(t). /// The result is always positive and in [0, 1). /// The fractional part of a negative input will be flipped (e.g. frac(-0.3) -> 0.7). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Frac(this float t) { var res = t - Floor(t); return res == 1 ? 0 : res; } /// /// Returns the fractional part of t. Calculated as t - floor(t). /// The result is always positive and in [0, 1). /// The fractional part of a negative input will be flipped (e.g. frac(-0.3) -> 0.7). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Frac(this double t) { var res = t - Floor(t); return res == 1 ? 0 : res; } /// /// Returns the fractional part of t. Calculated as t - floor(t). /// The result is always positive and in [0, 1). /// The fractional part of a negative input will be flipped (e.g. frac(-0.3) -> 0.7). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Frac(this decimal t) { var res = t - Floor(t); return res == 1 ? 0 : res; } #endregion #region Clamp /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Clamp(this byte x, byte a, byte b) { if (x < a) return a; if (x > b) return b; return x; } /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Clamp(this sbyte x, sbyte a, sbyte b) { if (x < a) return a; if (x > b) return b; return x; } /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Clamp(this short x, short a, short b) { if (x < a) return a; if (x > b) return b; return x; } /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Clamp(this ushort x, ushort a, ushort b) { if (x < a) return a; if (x > b) return b; return x; } /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Clamp(this int x, int a, int b) { if (x < a) return a; if (x > b) return b; return x; } /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Clamp(this uint x, uint a, uint b) { if (x < a) return a; if (x > b) return b; return x; } /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Clamp(this long x, long a, long b) { if (x < a) return a; if (x > b) return b; return x; } /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Clamp(this ulong x, ulong a, ulong b) { if (x < a) return a; if (x > b) return b; return x; } /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Clamp(this float x, float a, float b) { if (x < a) return a; if (x > b) return b; return x; } /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Clamp(this double x, double a, double b) { if (x < a) return a; if (x > b) return b; return x; } /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Clamp(this decimal x, decimal a, decimal b) { if (x < a) return a; if (x > b) return b; return x; } /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Clamp(this int x, Range1i range) { if (x < range.Min) return range.Min; if (x > range.Max) return range.Max; return x; } /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Clamp(this uint x, Range1ui range) { if (x < range.Min) return range.Min; if (x > range.Max) return range.Max; return x; } /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Clamp(this long x, Range1l range) { if (x < range.Min) return range.Min; if (x > range.Max) return range.Max; return x; } /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Clamp(this float x, Range1f range) { if (x < range.Min) return range.Min; if (x > range.Max) return range.Max; return x; } /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Clamp(this double x, Range1d range) { if (x < range.Min) return range.Min; if (x > range.Max) return range.Max; return x; } #endregion #region ClampExcl /// /// Clamps value to interval [a,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte ClampExcl(this byte x, byte a, byte b) { if (x < a) return a; if (x >= b) return (byte)(b - 1); return x; } /// /// Clamps value to interval [a,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte ClampExcl(this sbyte x, sbyte a, sbyte b) { if (x < a) return a; if (x >= b) return (sbyte)(b - 1); return x; } /// /// Clamps value to interval [a,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short ClampExcl(this short x, short a, short b) { if (x < a) return a; if (x >= b) return (short)(b - 1); return x; } /// /// Clamps value to interval [a,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort ClampExcl(this ushort x, ushort a, ushort b) { if (x < a) return a; if (x >= b) return (ushort)(b - 1); return x; } /// /// Clamps value to interval [a,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int ClampExcl(this int x, int a, int b) { if (x < a) return a; if (x >= b) return (int)(b - 1); return x; } /// /// Clamps value to interval [a,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ClampExcl(this uint x, uint a, uint b) { if (x < a) return a; if (x >= b) return (uint)(b - 1); return x; } /// /// Clamps value to interval [a,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long ClampExcl(this long x, long a, long b) { if (x < a) return a; if (x >= b) return (long)(b - 1); return x; } /// /// Clamps value to interval [a,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong ClampExcl(this ulong x, ulong a, ulong b) { if (x < a) return a; if (x >= b) return (ulong)(b - 1); return x; } /// /// Clamps value to interval [a,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal ClampExcl(this decimal x, decimal a, decimal b) { if (x < a) return a; if (x >= b) return (decimal)(b - 1); return x; } /// /// Clamps value to interval [a,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int ClampExcl(this int x, Range1i range) { if (x < range.Min) return range.Min; if (x >= range.Max) return (int)(range.Max - 1); return x; } /// /// Clamps value to interval [a,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ClampExcl(this uint x, Range1ui range) { if (x < range.Min) return range.Min; if (x >= range.Max) return (uint)(range.Max - 1); return x; } /// /// Clamps value to interval [a,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long ClampExcl(this long x, Range1l range) { if (x < range.Min) return range.Min; if (x >= range.Max) return (long)(range.Max - 1); return x; } #endregion #region ClampWrap /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte ClampWrap(this byte x, byte a, byte b) => (byte)(ModP(x - a, b - a) + a); /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte ClampWrap(this sbyte x, sbyte a, sbyte b) => (sbyte)(ModP(x - a, b - a) + a); /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short ClampWrap(this short x, short a, short b) => (short)(ModP(x - a, b - a) + a); /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort ClampWrap(this ushort x, ushort a, ushort b) => (ushort)(ModP(x - a, b - a) + a); /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int ClampWrap(this int x, int a, int b) => (int)(ModP(x - a, b - a) + a); /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ClampWrap(this uint x, uint a, uint b) => (uint)(ModP(x - a, b - a) + a); /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long ClampWrap(this long x, long a, long b) => (long)(ModP(x - a, b - a) + a); /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ClampWrap(this float x, float a, float b) => (float)(ModP(x - a, b - a) + a); /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ClampWrap(this double x, double a, double b) => (double)(ModP(x - a, b - a) + a); /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal ClampWrap(this decimal x, decimal a, decimal b) => (decimal)(ModP(x - a, b - a) + a); /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int ClampWrap(this int x, Range1i range) => (int)(ModP(x - range.Min, range.Max - range.Min) + range.Min); /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ClampWrap(this uint x, Range1ui range) => (uint)(ModP(x - range.Min, range.Max - range.Min) + range.Min); /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long ClampWrap(this long x, Range1l range) => (long)(ModP(x - range.Min, range.Max - range.Min) + range.Min); /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ClampWrap(this float x, Range1f range) => (float)(ModP(x - range.Min, range.Max - range.Min) + range.Min); /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ClampWrap(this double x, Range1d range) => (double)(ModP(x - range.Min, range.Max - range.Min) + range.Min); #endregion #region WrapToPi /// /// Wraps the given angle to the [-Pi, Pi] range. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float WrapToPi(this float angleInRadians) { var x = angleInRadians % ConstantF.PiTimesTwo; return (x.Abs() > ConstantF.Pi) ? x - ConstantF.PiTimesTwo * x.Signum() : x; } /// /// Wraps the given angle to the [-Pi, Pi] range. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double WrapToPi(this double angleInRadians) { var x = angleInRadians % Constant.PiTimesTwo; return (x.Abs() > Constant.Pi) ? x - Constant.PiTimesTwo * x.Signum() : x; } #endregion #region Saturate /// /// Clamps value to interval [0,1]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Saturate(this byte x) => Clamp(x, (byte)0, (byte)1); /// /// Clamps value to interval [0,1]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Saturate(this sbyte x) => Clamp(x, (sbyte)0, (sbyte)1); /// /// Clamps value to interval [0,1]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Saturate(this short x) => Clamp(x, (short)0, (short)1); /// /// Clamps value to interval [0,1]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Saturate(this ushort x) => Clamp(x, (ushort)0, (ushort)1); /// /// Clamps value to interval [0,1]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Saturate(this int x) => Clamp(x, 0, 1); /// /// Clamps value to interval [0,1]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Saturate(this uint x) => Clamp(x, 0, 1); /// /// Clamps value to interval [0,1]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Saturate(this long x) => Clamp(x, 0, 1); /// /// Clamps value to interval [0,1]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Saturate(this ulong x) => Clamp(x, 0, 1); /// /// Clamps value to interval [0,1]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Saturate(this float x) => Clamp(x, 0, 1); /// /// Clamps value to interval [0,1]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Saturate(this double x) => Clamp(x, 0, 1); /// /// Clamps value to interval [0,1]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Saturate(this decimal x) => Clamp(x, 0, 1); #endregion #region MapToUnitInterval /// /// Maps value from interval [0, tMax] to interval [0, 1]. /// Values outside [0, tMax] are clamped - if t is greater than tMax /// then 1 is returned, if t is less than 0 then 0 is returned. /// If 'repeat' is true, then every interval [i * tMax, (i+1) * tMax] /// (for i from integers) is mapped to [0, 1]. /// If 'mirror' is true, then every second interval is flipped, such /// that [0, tMax) [tMax, 2*tMax) [2*tMax, 3*tMax] ... is mapped to /// [0,1)[1,0)[0,1)... /// [Pure] public static float MapToUnitInterval( this float t, float tMax, bool repeat, bool mirror ) { t = t / tMax; if (!repeat) { if (t >= 1) return 1; if (t <= 0) return 0; } if (mirror) { t = t - Floor(t * 0.5f) * 2; return t < 1 ? t : 2 - t; } else { return t - Floor(t); } } /// /// Maps value from interval [0, tMax] to interval [0, 1]. /// If 'repeat' is true, then every interval [i * tMax, (i+1) * tMax] /// (for i from integers) is mapped to [0, 1]. /// [Pure] public static float MapToUnitInterval(this float t, float tMax, bool repeat) { t = t / tMax; if (!repeat) { if (t >= 1) return 1; if (t <= 0) return 0; } return t - Floor(t); } /// /// Maps value from interval [0, tMax] to interval [0, 1]. /// [Pure] public static float MapToUnitInterval(this float t, float tMax) { t = t / tMax; if (t > 1) return 1; if (t < 0) return 0; return t; } /// /// Maps value from interval [tMin, tMax] to interval [0, 1]. /// [Pure] public static float MapToUnitInterval(this float t, float tMin, float tMax) { t = (t - tMin) / (tMax - tMin); if (t > 1) return 1; if (t < 0) return 0; return t; } /// /// Maps value from interval [0, tMax] to interval [0, 1]. /// Values outside [0, tMax] are clamped - if t is greater than tMax /// then 1 is returned, if t is less than 0 then 0 is returned. /// If 'repeat' is true, then every interval [i * tMax, (i+1) * tMax] /// (for i from integers) is mapped to [0, 1]. /// If 'mirror' is true, then every second interval is flipped, such /// that [0, tMax) [tMax, 2*tMax) [2*tMax, 3*tMax] ... is mapped to /// [0,1)[1,0)[0,1)... /// [Pure] public static double MapToUnitInterval( this double t, double tMax, bool repeat, bool mirror ) { t = t / tMax; if (!repeat) { if (t >= 1) return 1; if (t <= 0) return 0; } if (mirror) { t = t - Floor(t * 0.5) * 2; return t < 1 ? t : 2 - t; } else { return t - Floor(t); } } /// /// Maps value from interval [0, tMax] to interval [0, 1]. /// If 'repeat' is true, then every interval [i * tMax, (i+1) * tMax] /// (for i from integers) is mapped to [0, 1]. /// [Pure] public static double MapToUnitInterval(this double t, double tMax, bool repeat) { t = t / tMax; if (!repeat) { if (t >= 1) return 1; if (t <= 0) return 0; } return t - Floor(t); } /// /// Maps value from interval [0, tMax] to interval [0, 1]. /// [Pure] public static double MapToUnitInterval(this double t, double tMax) { t = t / tMax; if (t > 1) return 1; if (t < 0) return 0; return t; } /// /// Maps value from interval [tMin, tMax] to interval [0, 1]. /// [Pure] public static double MapToUnitInterval(this double t, double tMin, double tMax) { t = (t - tMin) / (tMax - tMin); if (t > 1) return 1; if (t < 0) return 0; return t; } #endregion #region Sign /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Sign(this sbyte x) { return Math.Sign(x); } /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// // Same as Fun.Sign(), we need this for the F# generic math library! [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Signumi(this sbyte x) => Sign(x); /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Signum(this sbyte x) { return (sbyte) Math.Sign(x); } /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Sign(this short x) { return Math.Sign(x); } /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// // Same as Fun.Sign(), we need this for the F# generic math library! [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Signumi(this short x) => Sign(x); /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Signum(this short x) { return (short) Math.Sign(x); } /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Sign(this int x) { return Math.Sign(x); } /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// // Same as Fun.Sign(), we need this for the F# generic math library! [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Signumi(this int x) => Sign(x); /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Signum(this int x) { return (int) Math.Sign(x); } /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Sign(this long x) { return Math.Sign(x); } /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// // Same as Fun.Sign(), we need this for the F# generic math library! [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Signumi(this long x) => Sign(x); /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Signum(this long x) { return (long) Math.Sign(x); } /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Sign(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Sign(x); #else return Math.Sign(x); #endif } /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// // Same as Fun.Sign(), we need this for the F# generic math library! [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Signumi(this float x) => Sign(x); /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Signum(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Sign(x); #else return Math.Sign(x); #endif } /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Sign(this double x) { return Math.Sign(x); } /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// // Same as Fun.Sign(), we need this for the F# generic math library! [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Signumi(this double x) => Sign(x); /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Signum(this double x) { return (double) Math.Sign(x); } /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Sign(this decimal x) { return Math.Sign(x); } /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// // Same as Fun.Sign(), we need this for the F# generic math library! [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Signumi(this decimal x) => Sign(x); /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Signum(this decimal x) { return (decimal) Math.Sign(x); } #endregion #region Multiply-Add /// /// Returns (x * y) + z. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte MultiplyAdd(byte x, byte y, byte z) => (byte)((x * y) + z); /// /// Returns (x * y) + z. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte MultiplyAdd(sbyte x, sbyte y, sbyte z) => (sbyte)((x * y) + z); /// /// Returns (x * y) + z. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short MultiplyAdd(short x, short y, short z) => (short)((x * y) + z); /// /// Returns (x * y) + z. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort MultiplyAdd(ushort x, ushort y, ushort z) => (ushort)((x * y) + z); /// /// Returns (x * y) + z. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MultiplyAdd(int x, int y, int z) => ((x * y) + z); /// /// Returns (x * y) + z. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint MultiplyAdd(uint x, uint y, uint z) => ((x * y) + z); /// /// Returns (x * y) + z. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MultiplyAdd(long x, long y, long z) => ((x * y) + z); /// /// Returns (x * y) + z. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong MultiplyAdd(ulong x, ulong y, ulong z) => ((x * y) + z); #if NETCOREAPP3_1_OR_GREATER /// /// Returns (x * y) + z. /// Computes the result rounded as a single ternary operation. /// #else /// /// Returns (x * y) + z. /// #endif [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MultiplyAdd(float x, float y, float z) { #if NETCOREAPP3_1_OR_GREATER return MathF.FusedMultiplyAdd(x, y, z); #else return (x * y) + z; #endif } #if NETCOREAPP3_1_OR_GREATER /// /// Returns (x * y) + z. /// Computes the result rounded as a single ternary operation. /// #else /// /// Returns (x * y) + z. /// #endif [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MultiplyAdd(double x, double y, double z) { #if NETCOREAPP3_1_OR_GREATER return Math.FusedMultiplyAdd(x, y, z); #else return (x * y) + z; #endif } /// /// Returns (x * y) + z. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal MultiplyAdd(decimal x, decimal y, decimal z) => ((x * y) + z); #endregion #region Floating point bits #if NETSTANDARD2_0 /// /// Returns the bit representation of the given value as a . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe int FloatToBits(this float x) => *((int*)&x); /// /// Returns the value represented by the given . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe float FloatFromBits(this int x) => *((float*)&x); #else /// /// Returns the bit representation of the given value as a . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int FloatToBits(this float x) => BitConverter.SingleToInt32Bits(x); /// /// Returns the value represented by the given . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float FloatFromBits(this int x) => BitConverter.Int32BitsToSingle(x); #endif /// /// Returns the bit representation of the given value as a . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe uint FloatToUnsignedBits(this float x) => *((uint*)&x); /// /// Returns the value represented by the given . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe float FloatFromUnsignedBits(this uint x) => *((float*)&x); #if NETSTANDARD2_0 /// /// Returns the bit representation of the given value as a . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe long FloatToBits(this double x) => *((long*)&x); /// /// Returns the value represented by the given . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe double FloatFromBits(this long x) => *((double*)&x); #else /// /// Returns the bit representation of the given value as a . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long FloatToBits(this double x) => BitConverter.DoubleToInt64Bits(x); /// /// Returns the value represented by the given . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double FloatFromBits(this long x) => BitConverter.Int64BitsToDouble(x); #endif /// /// Returns the bit representation of the given value as a . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe ulong FloatToUnsignedBits(this double x) => *((ulong*)&x); /// /// Returns the value represented by the given . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe double FloatFromUnsignedBits(this ulong x) => *((double*)&x); #endregion #region Copy sign /// /// Returns a value with the maginute of and the sign of . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float CopySign(float value, float sign) { #if NETCOREAPP3_1_OR_GREATER return MathF.CopySign(value, sign); #else var xbits = FloatToBits(value); var ybits = FloatToBits(sign); if ((xbits ^ ybits) < 0) { return FloatFromBits(xbits ^ int.MinValue); } return value; #endif } /// /// Returns a value with the maginute of and the sign of . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double CopySign(double value, double sign) { #if NETCOREAPP3_1_OR_GREATER return Math.CopySign(value, sign); #else var xbits = FloatToBits(value); var ybits = FloatToBits(sign); if ((xbits ^ ybits) < 0) { return FloatFromBits(xbits ^ long.MinValue); } return value; #endif } #endregion #region Comparisons /// /// Returns whether is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this byte x, byte epsilon) => x < epsilon; /// /// Returns whether the absolute value of is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this sbyte x, sbyte epsilon) => x.Abs() < epsilon; /// /// Returns whether the absolute value of is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this short x, short epsilon) => x.Abs() < epsilon; /// /// Returns whether is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this ushort x, ushort epsilon) => x < epsilon; /// /// Returns whether the absolute value of is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this int x, int epsilon) => x.Abs() < epsilon; /// /// Returns whether is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this uint x, uint epsilon) => x < epsilon; /// /// Returns whether the absolute value of is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this long x, long epsilon) => x.Abs() < epsilon; /// /// Returns whether is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this ulong x, ulong epsilon) => x < epsilon; /// /// Returns whether the absolute value of is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this float x, float epsilon) => x.Abs() < epsilon; /// /// Returns whether the absolute value of is smaller than Constant<float>.PositiveTinyValue. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this float x) => x.Abs() < Constant.PositiveTinyValue; /// /// Returns whether the absolute value of is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this double x, double epsilon) => x.Abs() < epsilon; /// /// Returns whether the absolute value of is smaller than Constant<double>.PositiveTinyValue. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this double x) => x.Abs() < Constant.PositiveTinyValue; #endregion #region AbsSum /// /// Returns the sum of the absolute values of the given numbers. /// [Pure] public static int AbsSum(this IEnumerable array) { int sum = 0; foreach (var i in array) sum += i.Abs(); return sum; } /// /// Returns the sum of the absolute values of the given numbers. /// [Pure] public static long AbsSum(this IEnumerable array) { long sum = 0; foreach (var i in array) sum += i.Abs(); return sum; } /// /// Returns the sum of the absolute values of the given numbers. /// [Pure] public static long AbsSum(this IEnumerable array) { long sum = 0; foreach (var i in array) sum += i.Abs(); return sum; } /// /// Returns the sum of the absolute values of the given numbers. /// [Pure] public static long AbsSum(this IEnumerable array) { long sum = 0; foreach (var i in array) sum += i.Abs(); return sum; } /// /// Returns the sum of the absolute values of the given numbers. /// [Pure] public static double AbsSum(this IEnumerable array) { double sum = 0; foreach (var i in array) sum += i.Abs(); return sum; } /// /// Returns the sum of the absolute values of the given numbers. /// [Pure] public static double AbsSum(this IEnumerable array) { double sum = 0; foreach (var i in array) sum += i.Abs(); return sum; } /// /// Returns the sum of the absolute values of the given numbers. /// [Pure] public static decimal AbsSum(this IEnumerable array) { decimal sum = 0; foreach (var i in array) sum += i.Abs(); return sum; } #endregion #region Roots /// /// Returns the n-th root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Root(this byte x, int n) { return Math.Pow(x, 1.0 / n); } /// /// Returns the n-th root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Root(this sbyte x, int n) { return Math.Pow(x, 1.0 / n); } /// /// Returns the n-th root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Root(this short x, int n) { return Math.Pow(x, 1.0 / n); } /// /// Returns the n-th root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Root(this ushort x, int n) { return Math.Pow(x, 1.0 / n); } /// /// Returns the n-th root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Root(this int x, int n) { return Math.Pow(x, 1.0 / n); } /// /// Returns the n-th root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Root(this uint x, int n) { return Math.Pow(x, 1.0 / n); } /// /// Returns the n-th root of the specified number. /// Note: This function uses a double representation internally, but not all long values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Root(this long x, int n) { return Math.Pow(x, 1.0 / n); } /// /// Returns the n-th root of the specified number. /// Note: This function uses a double representation internally, but not all ulong values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Root(this ulong x, int n) { return Math.Pow(x, 1.0 / n); } /// /// Returns the n-th root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Root(this float x, int n) { #if NETCOREAPP3_1_OR_GREATER return MathF.Pow(x, 1.0f / n); #else return (float)Math.Pow(x, 1.0 / n); #endif } /// /// Returns the n-th root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Root(this double x, int n) { return Math.Pow(x, 1.0 / n); } /// /// Returns the square root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Sqrt(this byte x) { return Math.Sqrt(x); } /// /// Returns the square root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Sqrt(this sbyte x) { return Math.Sqrt(x); } /// /// Returns the square root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Sqrt(this short x) { return Math.Sqrt(x); } /// /// Returns the square root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Sqrt(this ushort x) { return Math.Sqrt(x); } /// /// Returns the square root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Sqrt(this int x) { return Math.Sqrt(x); } /// /// Returns the square root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Sqrt(this uint x) { return Math.Sqrt(x); } /// /// Returns the square root of the specified number. /// Note: This function uses a double representation internally, but not all long values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Sqrt(this long x) { return Math.Sqrt(x); } /// /// Returns the square root of the specified number. /// Note: This function uses a double representation internally, but not all ulong values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Sqrt(this ulong x) { return Math.Sqrt(x); } /// /// Returns the square root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Sqrt(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Sqrt(x); #else return (float)Math.Sqrt(x); #endif } /// /// Returns the square root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Sqrt(this double x) { return Math.Sqrt(x); } /// /// Returns the cubic root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Cbrt(this byte x) { #if NETCOREAPP3_1_OR_GREATER return Math.Cbrt(x); #else return Math.Pow(x, Constant.OneThird); #endif } /// /// Returns the cubic root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Cbrt(this sbyte x) { #if NETCOREAPP3_1_OR_GREATER return Math.Cbrt(x); #else return x < 0 ? -Math.Pow(-x, Constant.OneThird) : Math.Pow( x, Constant.OneThird); #endif } /// /// Returns the cubic root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Cbrt(this short x) { #if NETCOREAPP3_1_OR_GREATER return Math.Cbrt(x); #else return x < 0 ? -Math.Pow(-x, Constant.OneThird) : Math.Pow( x, Constant.OneThird); #endif } /// /// Returns the cubic root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Cbrt(this ushort x) { #if NETCOREAPP3_1_OR_GREATER return Math.Cbrt(x); #else return Math.Pow(x, Constant.OneThird); #endif } /// /// Returns the cubic root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Cbrt(this int x) { #if NETCOREAPP3_1_OR_GREATER return Math.Cbrt(x); #else return x < 0 ? -Math.Pow(-x, Constant.OneThird) : Math.Pow( x, Constant.OneThird); #endif } /// /// Returns the cubic root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Cbrt(this uint x) { #if NETCOREAPP3_1_OR_GREATER return Math.Cbrt(x); #else return Math.Pow(x, Constant.OneThird); #endif } /// /// Returns the cubic root of the specified number. /// Note: This function uses a double representation internally, but not all long values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Cbrt(this long x) { #if NETCOREAPP3_1_OR_GREATER return Math.Cbrt(x); #else return x < 0 ? -Math.Pow(-x, Constant.OneThird) : Math.Pow( x, Constant.OneThird); #endif } /// /// Returns the cubic root of the specified number. /// Note: This function uses a double representation internally, but not all ulong values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Cbrt(this ulong x) { #if NETCOREAPP3_1_OR_GREATER return Math.Cbrt(x); #else return Math.Pow(x, Constant.OneThird); #endif } /// /// Returns the cubic root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Cbrt(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Cbrt(x); #else return x < 0 ? (float)-Math.Pow(-x, Constant.OneThird) : (float)Math.Pow( x, Constant.OneThird); #endif } /// /// Returns the cubic root of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Cbrt(this double x) { #if NETCOREAPP3_1_OR_GREATER return Math.Cbrt(x); #else return x < 0 ? -Math.Pow(-x, Constant.OneThird) : Math.Pow( x, Constant.OneThird); #endif } #endregion #region Square /// /// Returns the square of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Square(this byte x) => (byte)(x * x); /// /// Returns the square of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Square(this sbyte x) => (sbyte)(x * x); /// /// Returns the square of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Square(this short x) => (short)(x * x); /// /// Returns the square of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Square(this ushort x) => (ushort)(x * x); /// /// Returns the square of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Square(this int x) => (int)(x * x); /// /// Returns the square of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Square(this uint x) => (uint)(x * x); /// /// Returns the square of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Square(this long x) => (long)(x * x); /// /// Returns the square of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Square(this ulong x) => (ulong)(x * x); /// /// Returns the square of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Square(this float x) => (float)(x * x); /// /// Returns the square of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Square(this double x) => (double)(x * x); /// /// Returns the square of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Square(this decimal x) => (decimal)(x * x); #endregion #region Power /// /// Returns the number raised to the specified power. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Pow(this byte x, float y) { #if NETCOREAPP3_1_OR_GREATER return MathF.Pow(x, y); #else return (float)Math.Pow(x, y); #endif } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Power(this byte x, float y) => Pow(x, y); /// /// Returns the number raised to the specified power. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Pow(this byte x, double y) { return Math.Pow(x, y); } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Power(this byte x, double y) => Pow(x, y); /// /// Returns the number raised to the specified integer power. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Pown(this byte x, byte y) { return (byte)Pown((uint)x, y); } /// /// Returns the number raised to the specified integer power. /// The exponent must not be negative. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Pown(this byte x, int y) { return (byte)Pown((uint)x, y); } /// /// Returns the number raised to the specified power. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Pow(this sbyte x, float y) { #if NETCOREAPP3_1_OR_GREATER return MathF.Pow(x, y); #else return (float)Math.Pow(x, y); #endif } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Power(this sbyte x, float y) => Pow(x, y); /// /// Returns the number raised to the specified power. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Pow(this sbyte x, double y) { return Math.Pow(x, y); } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Power(this sbyte x, double y) => Pow(x, y); /// /// Returns the number raised to the specified integer power. /// The exponent must not be negative. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Pown(this sbyte x, sbyte y) { return (sbyte)Pown((int)x, y); } /// /// Returns the number raised to the specified integer power. /// The exponent must not be negative. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Pown(this sbyte x, int y) { return (sbyte)Pown((int)x, y); } /// /// Returns the number raised to the specified power. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Pow(this short x, float y) { #if NETCOREAPP3_1_OR_GREATER return MathF.Pow(x, y); #else return (float)Math.Pow(x, y); #endif } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Power(this short x, float y) => Pow(x, y); /// /// Returns the number raised to the specified power. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Pow(this short x, double y) { return Math.Pow(x, y); } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Power(this short x, double y) => Pow(x, y); /// /// Returns the number raised to the specified integer power. /// The exponent must not be negative. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Pown(this short x, short y) { return (short)Pown((int)x, y); } /// /// Returns the number raised to the specified integer power. /// The exponent must not be negative. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Pown(this short x, int y) { return (short)Pown((int)x, y); } /// /// Returns the number raised to the specified power. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Pow(this ushort x, float y) { #if NETCOREAPP3_1_OR_GREATER return MathF.Pow(x, y); #else return (float)Math.Pow(x, y); #endif } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Power(this ushort x, float y) => Pow(x, y); /// /// Returns the number raised to the specified power. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Pow(this ushort x, double y) { return Math.Pow(x, y); } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Power(this ushort x, double y) => Pow(x, y); /// /// Returns the number raised to the specified integer power. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Pown(this ushort x, ushort y) { return (ushort)Pown((uint)x, y); } /// /// Returns the number raised to the specified integer power. /// The exponent must not be negative. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Pown(this ushort x, int y) { return (ushort)Pown((uint)x, y); } /// /// Returns the number raised to the specified power. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Pow(this int x, float y) { return (float)Math.Pow(x, y); } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Power(this int x, float y) => Pow(x, y); /// /// Returns the number raised to the specified power. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Pow(this int x, double y) { return Math.Pow(x, y); } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Power(this int x, double y) => Pow(x, y); /// /// Returns the number raised to the specified integer power. /// The exponent must not be negative. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Pown(this int x, int y) { Debug.Assert(y >= 0); if (y == 0) return 1; if (y == 1) return x; if (y == 2) return x * x; if (y == 3) return x * x * x; if (y == 4) { var xx = x * x; return xx * xx; } var v = Pown(x, y / 2); v *= v; return (y % 2 == 0) ? v : v * x; } /// /// Returns the number raised to the specified power. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Pow(this uint x, float y) { return (float)Math.Pow(x, y); } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Power(this uint x, float y) => Pow(x, y); /// /// Returns the number raised to the specified power. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Pow(this uint x, double y) { return Math.Pow(x, y); } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Power(this uint x, double y) => Pow(x, y); /// /// Returns the number raised to the specified integer power. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Pown(this uint x, uint y) { Debug.Assert(y >= 0); if (y == 0) return 1; if (y == 1) return x; if (y == 2) return x * x; if (y == 3) return x * x * x; if (y == 4) { var xx = x * x; return xx * xx; } var v = Pown(x, y / 2); v *= v; return (y % 2 == 0) ? v : v * x; } /// /// Returns the number raised to the specified integer power. /// The exponent must not be negative. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Pown(this uint x, int y) { Debug.Assert(y >= 0); if (y == 0) return 1; if (y == 1) return x; if (y == 2) return x * x; if (y == 3) return x * x * x; if (y == 4) { var xx = x * x; return xx * xx; } var v = Pown(x, y / 2); v *= v; return (y % 2 == 0) ? v : v * x; } /// /// Returns the number raised to the specified power. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Pow(this long x, float y) { return (float)Math.Pow(x, y); } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Power(this long x, float y) => Pow(x, y); /// /// Returns the number raised to the specified power. /// Note: This function uses a double representation internally, but not all long values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Pow(this long x, double y) { return Math.Pow(x, y); } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Power(this long x, double y) => Pow(x, y); /// /// Returns the number raised to the specified integer power. /// The exponent must not be negative. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Pown(this long x, long y) { Debug.Assert(y >= 0); if (y == 0) return 1; if (y == 1) return x; if (y == 2) return x * x; if (y == 3) return x * x * x; if (y == 4) { var xx = x * x; return xx * xx; } var v = Pown(x, y / 2); v *= v; return (y % 2 == 0) ? v : v * x; } /// /// Returns the number raised to the specified integer power. /// The exponent must not be negative. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Pown(this long x, int y) { Debug.Assert(y >= 0); if (y == 0) return 1; if (y == 1) return x; if (y == 2) return x * x; if (y == 3) return x * x * x; if (y == 4) { var xx = x * x; return xx * xx; } var v = Pown(x, y / 2); v *= v; return (y % 2 == 0) ? v : v * x; } /// /// Returns the number raised to the specified power. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Pow(this ulong x, float y) { return (float)Math.Pow(x, y); } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Power(this ulong x, float y) => Pow(x, y); /// /// Returns the number raised to the specified power. /// Note: This function uses a double representation internally, but not all ulong values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Pow(this ulong x, double y) { return Math.Pow(x, y); } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Power(this ulong x, double y) => Pow(x, y); /// /// Returns the number raised to the specified integer power. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Pown(this ulong x, ulong y) { Debug.Assert(y >= 0); if (y == 0) return 1; if (y == 1) return x; if (y == 2) return x * x; if (y == 3) return x * x * x; if (y == 4) { var xx = x * x; return xx * xx; } var v = Pown(x, y / 2); v *= v; return (y % 2 == 0) ? v : v * x; } /// /// Returns the number raised to the specified integer power. /// The exponent must not be negative. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Pown(this ulong x, int y) { Debug.Assert(y >= 0); if (y == 0) return 1; if (y == 1) return x; if (y == 2) return x * x; if (y == 3) return x * x * x; if (y == 4) { var xx = x * x; return xx * xx; } var v = Pown(x, y / 2); v *= v; return (y % 2 == 0) ? v : v * x; } /// /// Returns the number raised to the specified power. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Pow(this float x, float y) { #if NETCOREAPP3_1_OR_GREATER return MathF.Pow(x, y); #else return (float)Math.Pow(x, y); #endif } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Power(this float x, float y) => Pow(x, y); /// /// Returns the number raised to the specified integer power. /// The exponent must not be negative. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Pown(this float x, int y) { Debug.Assert(y >= 0); if (y == 0) return 1; if (y == 1) return x; if (y == 2) return x * x; if (y == 3) return x * x * x; if (y == 4) { var xx = x * x; return xx * xx; } var v = Pown(x, y / 2); v *= v; return (y % 2 == 0) ? v : v * x; } /// /// Returns the number raised to the specified power. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Pow(this double x, double y) { return Math.Pow(x, y); } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Power(this double x, double y) => Pow(x, y); /// /// Returns the number raised to the specified integer power. /// The exponent must not be negative. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Pown(this double x, int y) { Debug.Assert(y >= 0); if (y == 0) return 1; if (y == 1) return x; if (y == 2) return x * x; if (y == 3) return x * x * x; if (y == 4) { var xx = x * x; return xx * xx; } var v = Pown(x, y / 2); v *= v; return (y % 2 == 0) ? v : v * x; } #endregion #region Exp and Log /// /// Returns e raised to the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Exp(this byte x) { return Math.Exp(x); } /// /// Returns the natural (base e) logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this byte x) { return Math.Log(x); } /// /// Returns the base 10 logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log10(this byte x) { return Math.Log10(x); } /// /// Returns the base 2 logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log2(this byte x) { #if NETCOREAPP3_1_OR_GREATER return Math.Log2(x); #else return x.Log() * Constant.Ln2Inv; #endif } /// /// Returns the values logarithm of the specified basis. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this byte x, double basis) { return Math.Log(x, basis); } /// /// Returns e raised to the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Exp(this sbyte x) { return Math.Exp(x); } /// /// Returns the natural (base e) logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this sbyte x) { return Math.Log(x); } /// /// Returns the base 10 logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log10(this sbyte x) { return Math.Log10(x); } /// /// Returns the base 2 logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log2(this sbyte x) { #if NETCOREAPP3_1_OR_GREATER return Math.Log2(x); #else return x.Log() * Constant.Ln2Inv; #endif } /// /// Returns the values logarithm of the specified basis. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this sbyte x, double basis) { return Math.Log(x, basis); } /// /// Returns e raised to the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Exp(this short x) { return Math.Exp(x); } /// /// Returns the natural (base e) logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this short x) { return Math.Log(x); } /// /// Returns the base 10 logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log10(this short x) { return Math.Log10(x); } /// /// Returns the base 2 logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log2(this short x) { #if NETCOREAPP3_1_OR_GREATER return Math.Log2(x); #else return x.Log() * Constant.Ln2Inv; #endif } /// /// Returns the values logarithm of the specified basis. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this short x, double basis) { return Math.Log(x, basis); } /// /// Returns e raised to the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Exp(this ushort x) { return Math.Exp(x); } /// /// Returns the natural (base e) logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this ushort x) { return Math.Log(x); } /// /// Returns the base 10 logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log10(this ushort x) { return Math.Log10(x); } /// /// Returns the base 2 logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log2(this ushort x) { #if NETCOREAPP3_1_OR_GREATER return Math.Log2(x); #else return x.Log() * Constant.Ln2Inv; #endif } /// /// Returns the values logarithm of the specified basis. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this ushort x, double basis) { return Math.Log(x, basis); } /// /// Returns e raised to the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Exp(this int x) { return Math.Exp(x); } /// /// Returns the natural (base e) logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this int x) { return Math.Log(x); } /// /// Returns the base 10 logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log10(this int x) { return Math.Log10(x); } /// /// Returns the base 2 logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log2(this int x) { #if NETCOREAPP3_1_OR_GREATER return Math.Log2(x); #else return x.Log() * Constant.Ln2Inv; #endif } /// /// Returns the values logarithm of the specified basis. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this int x, double basis) { return Math.Log(x, basis); } /// /// Returns e raised to the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Exp(this uint x) { return Math.Exp(x); } /// /// Returns the natural (base e) logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this uint x) { return Math.Log(x); } /// /// Returns the base 10 logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log10(this uint x) { return Math.Log10(x); } /// /// Returns the base 2 logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log2(this uint x) { #if NETCOREAPP3_1_OR_GREATER return Math.Log2(x); #else return x.Log() * Constant.Ln2Inv; #endif } /// /// Returns the values logarithm of the specified basis. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this uint x, double basis) { return Math.Log(x, basis); } /// /// Returns e raised to the specified number. /// Note: This function uses a double representation internally, but not all long values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Exp(this long x) { return Math.Exp(x); } /// /// Returns the natural (base e) logarithm of the specified number. /// Note: This function uses a double representation internally, but not all long values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this long x) { return Math.Log(x); } /// /// Returns the base 10 logarithm of the specified number. /// Note: This function uses a double representation internally, but not all long values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log10(this long x) { return Math.Log10(x); } /// /// Returns the base 2 logarithm of the specified number. /// Note: This function uses a double representation internally, but not all long values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log2(this long x) { #if NETCOREAPP3_1_OR_GREATER return Math.Log2(x); #else return x.Log() * Constant.Ln2Inv; #endif } /// /// Returns the values logarithm of the specified basis. /// Note: This function uses a double representation internally, but not all long values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this long x, double basis) { return Math.Log(x, basis); } /// /// Returns e raised to the specified number. /// Note: This function uses a double representation internally, but not all ulong values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Exp(this ulong x) { return Math.Exp(x); } /// /// Returns the natural (base e) logarithm of the specified number. /// Note: This function uses a double representation internally, but not all ulong values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this ulong x) { return Math.Log(x); } /// /// Returns the base 10 logarithm of the specified number. /// Note: This function uses a double representation internally, but not all ulong values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log10(this ulong x) { return Math.Log10(x); } /// /// Returns the base 2 logarithm of the specified number. /// Note: This function uses a double representation internally, but not all ulong values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log2(this ulong x) { #if NETCOREAPP3_1_OR_GREATER return Math.Log2(x); #else return x.Log() * Constant.Ln2Inv; #endif } /// /// Returns the values logarithm of the specified basis. /// Note: This function uses a double representation internally, but not all ulong values can be represented exactly as double. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this ulong x, double basis) { return Math.Log(x, basis); } /// /// Returns e raised to the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Exp(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Exp(x); #else return (float)Math.Exp(x); #endif } /// /// Returns the natural (base e) logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Log(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Log(x); #else return (float)Math.Log(x); #endif } /// /// Returns the base 10 logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Log10(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Log10(x); #else return (float)Math.Log10(x); #endif } /// /// Returns the base 2 logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Log2(this float x) { #if NETCOREAPP3_1_OR_GREATER //return MathF.Log2(x); // MathF.Log2 actually uses a conversion to double internally and has bad perfromance, see Aardvark.Base.Benchmarks/Log2Int.cs return x.Log() * ConstantF.Ln2Inv; #else return x.Log() * ConstantF.Ln2Inv; #endif } /// /// Returns the values logarithm of the specified basis. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Log(this float x, float basis) { #if NETCOREAPP3_1_OR_GREATER return MathF.Log(x, basis); #else return (float)Math.Log(x, basis); #endif } /// /// Returns e raised to the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Exp(this double x) { return Math.Exp(x); } /// /// Returns the natural (base e) logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this double x) { return Math.Log(x); } /// /// Returns the base 10 logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log10(this double x) { return Math.Log10(x); } /// /// Returns the base 2 logarithm of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log2(this double x) { #if NETCOREAPP3_1_OR_GREATER return Math.Log2(x); #else return x.Log() * Constant.Ln2Inv; #endif } /// /// Returns the values logarithm of the specified basis. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Log(this double x, double basis) { return Math.Log(x, basis); } #endregion #region LinCom [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte LinCom( byte p0, byte p1, byte p2, byte p3, ref Tup4 w) { return (byte)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3, (float)byte.MinValue, (float)byte.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinComRawF( byte p0, byte p1, byte p2, byte p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte LinCom( byte p0, byte p1, byte p2, byte p3, ref Tup4 w) { return (byte)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3, (double)byte.MinValue, (double)byte.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinComRawD( byte p0, byte p1, byte p2, byte p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte LinCom( byte p0, byte p1, byte p2, byte p3, byte p4, byte p5, ref Tup6 w) { return (byte)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5, (float)byte.MinValue, (float)byte.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinComRawF( byte p0, byte p1, byte p2, byte p3, byte p4, byte p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte LinCom( byte p0, byte p1, byte p2, byte p3, byte p4, byte p5, ref Tup6 w) { return (byte)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5, (double)byte.MinValue, (double)byte.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinComRawD( byte p0, byte p1, byte p2, byte p3, byte p4, byte p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte LinCom( sbyte p0, sbyte p1, sbyte p2, sbyte p3, ref Tup4 w) { return (sbyte)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3, (float)sbyte.MinValue, (float)sbyte.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinComRawF( sbyte p0, sbyte p1, sbyte p2, sbyte p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte LinCom( sbyte p0, sbyte p1, sbyte p2, sbyte p3, ref Tup4 w) { return (sbyte)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3, (double)sbyte.MinValue, (double)sbyte.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinComRawD( sbyte p0, sbyte p1, sbyte p2, sbyte p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte LinCom( sbyte p0, sbyte p1, sbyte p2, sbyte p3, sbyte p4, sbyte p5, ref Tup6 w) { return (sbyte)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5, (float)sbyte.MinValue, (float)sbyte.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinComRawF( sbyte p0, sbyte p1, sbyte p2, sbyte p3, sbyte p4, sbyte p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte LinCom( sbyte p0, sbyte p1, sbyte p2, sbyte p3, sbyte p4, sbyte p5, ref Tup6 w) { return (sbyte)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5, (double)sbyte.MinValue, (double)sbyte.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinComRawD( sbyte p0, sbyte p1, sbyte p2, sbyte p3, sbyte p4, sbyte p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short LinCom( short p0, short p1, short p2, short p3, ref Tup4 w) { return (short)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3, (float)short.MinValue, (float)short.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinComRawF( short p0, short p1, short p2, short p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short LinCom( short p0, short p1, short p2, short p3, ref Tup4 w) { return (short)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3, (double)short.MinValue, (double)short.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinComRawD( short p0, short p1, short p2, short p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short LinCom( short p0, short p1, short p2, short p3, short p4, short p5, ref Tup6 w) { return (short)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5, (float)short.MinValue, (float)short.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinComRawF( short p0, short p1, short p2, short p3, short p4, short p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short LinCom( short p0, short p1, short p2, short p3, short p4, short p5, ref Tup6 w) { return (short)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5, (double)short.MinValue, (double)short.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinComRawD( short p0, short p1, short p2, short p3, short p4, short p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort LinCom( ushort p0, ushort p1, ushort p2, ushort p3, ref Tup4 w) { return (ushort)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3, (float)ushort.MinValue, (float)ushort.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinComRawF( ushort p0, ushort p1, ushort p2, ushort p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort LinCom( ushort p0, ushort p1, ushort p2, ushort p3, ref Tup4 w) { return (ushort)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3, (double)ushort.MinValue, (double)ushort.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinComRawD( ushort p0, ushort p1, ushort p2, ushort p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort LinCom( ushort p0, ushort p1, ushort p2, ushort p3, ushort p4, ushort p5, ref Tup6 w) { return (ushort)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5, (float)ushort.MinValue, (float)ushort.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinComRawF( ushort p0, ushort p1, ushort p2, ushort p3, ushort p4, ushort p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort LinCom( ushort p0, ushort p1, ushort p2, ushort p3, ushort p4, ushort p5, ref Tup6 w) { return (ushort)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5, (double)ushort.MinValue, (double)ushort.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinComRawD( ushort p0, ushort p1, ushort p2, ushort p3, ushort p4, ushort p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LinCom( int p0, int p1, int p2, int p3, ref Tup4 w) { return (int)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3, (float)int.MinValue, (float)int.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinComRawF( int p0, int p1, int p2, int p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LinCom( int p0, int p1, int p2, int p3, ref Tup4 w) { return (int)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3, (double)int.MinValue, (double)int.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinComRawD( int p0, int p1, int p2, int p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LinCom( int p0, int p1, int p2, int p3, int p4, int p5, ref Tup6 w) { return (int)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5, (float)int.MinValue, (float)int.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinComRawF( int p0, int p1, int p2, int p3, int p4, int p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LinCom( int p0, int p1, int p2, int p3, int p4, int p5, ref Tup6 w) { return (int)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5, (double)int.MinValue, (double)int.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinComRawD( int p0, int p1, int p2, int p3, int p4, int p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint LinCom( uint p0, uint p1, uint p2, uint p3, ref Tup4 w) { return (uint)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3, (float)uint.MinValue, (float)uint.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinComRawF( uint p0, uint p1, uint p2, uint p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint LinCom( uint p0, uint p1, uint p2, uint p3, ref Tup4 w) { return (uint)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3, (double)uint.MinValue, (double)uint.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinComRawD( uint p0, uint p1, uint p2, uint p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint LinCom( uint p0, uint p1, uint p2, uint p3, uint p4, uint p5, ref Tup6 w) { return (uint)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5, (float)uint.MinValue, (float)uint.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinComRawF( uint p0, uint p1, uint p2, uint p3, uint p4, uint p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint LinCom( uint p0, uint p1, uint p2, uint p3, uint p4, uint p5, ref Tup6 w) { return (uint)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5, (double)uint.MinValue, (double)uint.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinComRawD( uint p0, uint p1, uint p2, uint p3, uint p4, uint p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long LinCom( long p0, long p1, long p2, long p3, ref Tup4 w) { return (long)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3, (float)long.MinValue, (float)long.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinComRawF( long p0, long p1, long p2, long p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long LinCom( long p0, long p1, long p2, long p3, ref Tup4 w) { return (long)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3, (double)long.MinValue, (double)long.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinComRawD( long p0, long p1, long p2, long p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long LinCom( long p0, long p1, long p2, long p3, long p4, long p5, ref Tup6 w) { return (long)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5, (float)long.MinValue, (float)long.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinComRawF( long p0, long p1, long p2, long p3, long p4, long p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long LinCom( long p0, long p1, long p2, long p3, long p4, long p5, ref Tup6 w) { return (long)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5, (double)long.MinValue, (double)long.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinComRawD( long p0, long p1, long p2, long p3, long p4, long p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong LinCom( ulong p0, ulong p1, ulong p2, ulong p3, ref Tup4 w) { return (ulong)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3, (float)ulong.MinValue, (float)ulong.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinComRawF( ulong p0, ulong p1, ulong p2, ulong p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong LinCom( ulong p0, ulong p1, ulong p2, ulong p3, ref Tup4 w) { return (ulong)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3, (double)ulong.MinValue, (double)ulong.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinComRawD( ulong p0, ulong p1, ulong p2, ulong p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong LinCom( ulong p0, ulong p1, ulong p2, ulong p3, ulong p4, ulong p5, ref Tup6 w) { return (ulong)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5, (float)ulong.MinValue, (float)ulong.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinComRawF( ulong p0, ulong p1, ulong p2, ulong p3, ulong p4, ulong p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong LinCom( ulong p0, ulong p1, ulong p2, ulong p3, ulong p4, ulong p5, ref Tup6 w) { return (ulong)Fun.Clamp(p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5, (double)ulong.MinValue, (double)ulong.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinComRawD( ulong p0, ulong p1, ulong p2, ulong p3, ulong p4, ulong p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half LinCom(Half p0, Half p1, ref Tup2 w) { return p0 * w.E0 + p1 * w.E1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinCom(float p0, float p1, ref Tup2 w) { return p0 * w.E0 + p1 * w.E1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinCom(double p0, double p1, ref Tup2 w) { return p0 * w.E0 + p1 * w.E1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half LinCom(Half p0, Half p1, Half p2, ref Tup3 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinCom(float p0, float p1, float p2, ref Tup3 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinCom(double p0, double p1, double p2, ref Tup3 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half LinCom(Half p0, Half p1, Half p2, Half p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinCom(float p0, float p1, float p2, float p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinCom(double p0, double p1, double p2, double p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half LinCom(Half p0, Half p1, Half p2, Half p3, Half p4, ref Tup5 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinCom(float p0, float p1, float p2, float p3, float p4, ref Tup5 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinCom(double p0, double p1, double p2, double p3, double p4, ref Tup5 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half LinCom(Half p0, Half p1, Half p2, Half p3, Half p4, Half p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinCom(float p0, float p1, float p2, float p3, float p4, float p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinCom(double p0, double p1, double p2, double p3, double p4, double p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half LinCom(Half p0, Half p1, Half p2, Half p3, Half p4, Half p5, Half p6, ref Tup7 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5 + p6 * w.E6; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinCom(float p0, float p1, float p2, float p3, float p4, float p5, float p6, ref Tup7 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5 + p6 * w.E6; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LinCom(double p0, double p1, double p2, double p3, double p4, double p5, double p6, ref Tup7 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5 + p6 * w.E6; } #endregion #region ModP /// /// Returns the positive modulo operation a mod b giving values between [0,b[ /// instead of a % b giving values between ]-b,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte ModP(this sbyte a, sbyte b) { var m = a % b; if (m < 0) m += b; return (sbyte)m; } /// /// Returns the positive modulo operation a mod b giving values between [0,b[ /// instead of a % b giving values between ]-b,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short ModP(this short a, short b) { var m = a % b; if (m < 0) m += b; return (short)m; } /// /// Returns the positive modulo operation a mod b giving values between [0,b[ /// instead of a % b giving values between ]-b,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int ModP(this int a, int b) { var m = a % b; if (m < 0) m += b; return (int)m; } /// /// Returns the positive modulo operation a mod b giving values between [0,b[ /// instead of a % b giving values between ]-b,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long ModP(this long a, long b) { var m = a % b; if (m < 0) m += b; return (long)m; } /// /// Returns the positive modulo operation a mod b giving values between [0,b[ /// instead of a % b giving values between ]-b,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ModP(this float a, float b) { var m = a % b; if (m < 0) m += b; return (float)m; } /// /// Returns the positive modulo operation a mod b giving values between [0,b[ /// instead of a % b giving values between ]-b,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ModP(this double a, double b) { var m = a % b; if (m < 0) m += b; return (double)m; } /// /// Returns the positive modulo operation a mod b giving values between [0,b[ /// instead of a % b giving values between ]-b,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal ModP(this decimal a, decimal b) { var m = a % b; if (m < 0) m += b; return (decimal)m; } #endregion #region PowerOfTwo /// /// Returns true if the supplied number is 0 or a power of two. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPowerOfTwo(this int x) => (x & (x - 1)) == 0; /// /// Returns true if the supplied number is 0 or a power of two. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPowerOfTwo(this long x) => (x & (x - 1)) == 0; /// /// Returns true if the supplied number is 0 or a power of two. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPowerOfTwo(this uint x) => (x & (x - 1)) == 0; /// /// Returns true if the supplied number is 0 or a power of two. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPowerOfTwo(this ulong x) => (x & (x - 1)) == 0; /// /// Returns 2 raised to the power of the value. /// The exponent must be less than 64. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong PowerOfTwo(this byte x) { Debug.Assert(x >= 0 && x < 64); return 1UL << (int)x; } /// /// Returns 2 raised to the power of the value. /// The exponent must be within [0, 64). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong PowerOfTwo(this sbyte x) { Debug.Assert(x >= 0 && x < 64); return 1UL << (int)x; } /// /// Returns 2 raised to the power of the value. /// The exponent must be within [0, 64). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong PowerOfTwo(this short x) { Debug.Assert(x >= 0 && x < 64); return 1UL << (int)x; } /// /// Returns 2 raised to the power of the value. /// The exponent must be less than 64. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong PowerOfTwo(this ushort x) { Debug.Assert(x >= 0 && x < 64); return 1UL << (int)x; } /// /// Returns 2 raised to the power of the value. /// The exponent must be within [0, 64). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong PowerOfTwo(this int x) { Debug.Assert(x >= 0 && x < 64); return 1UL << (int)x; } /// /// Returns 2 raised to the power of the value. /// The exponent must be less than 64. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong PowerOfTwo(this uint x) { Debug.Assert(x >= 0 && x < 64); return 1UL << (int)x; } /// /// Returns 2 raised to the power of the value. /// The exponent must be within [0, 64). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong PowerOfTwo(this long x) { Debug.Assert(x >= 0 && x < 64); return 1UL << (int)x; } /// /// Returns 2 raised to the power of the value. /// The exponent must be less than 64. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong PowerOfTwo(this ulong x) { Debug.Assert(x >= 0 && x < 64); return 1UL << (int)x; } /// /// Returns 2 raised to the power of the value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float PowerOfTwo(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Pow(2, x); #else return (float)Math.Pow(2, x); #endif } /// /// Returns 2 raised to the power of the value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double PowerOfTwo(this double x) { return Math.Pow(2, x); } /// /// Returns the nearest superior power of two of the value. /// For x <= 0, returns 0. /// For x > 2^30, returns int.MinValue. /// E.g. x = 401 -> 512. /// E.g. x = 256 -> 256. /// [Pure] public static int NextPowerOfTwo(this int x) { --x; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; return ++x; } /// /// Returns the nearest inferior power of two of the value. /// For x <= 0, returns 0. /// E.g. x = 401 -> 256. /// E.g. x = 512 -> 512. /// [Pure] public static int PrevPowerOfTwo(this int x) { if (x <= 0) return 0; x >>= 1; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; return ++x; } /// /// Returns the nearest superior power of two of the value. /// For x <= 0, returns 0. /// For x > 2^62, returns long.MinValue. /// E.g. x = 401 -> 512. /// E.g. x = 256 -> 256. /// [Pure] public static long NextPowerOfTwo(this long x) { --x; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; x |= x >> 32; return ++x; } /// /// Returns the nearest inferior power of two of the value. /// For x <= 0, returns 0. /// E.g. x = 401 -> 256. /// E.g. x = 512 -> 512. /// [Pure] public static long PrevPowerOfTwo(this long x) { if (x <= 0) return 0; x >>= 1; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; x |= x >> 32; return ++x; } /// /// Returns the nearest superior power of two of the value. /// For x = 0 and x > 2^31, returns 0. /// E.g. x = 401 -> 512. /// E.g. x = 256 -> 256. /// [Pure] public static uint NextPowerOfTwo(this uint x) { --x; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; return ++x; } /// /// Returns the nearest inferior power of two of the value. /// For x <= 0, returns 0. /// E.g. x = 401 -> 256. /// E.g. x = 512 -> 512. /// [Pure] public static uint PrevPowerOfTwo(this uint x) { if (x == 0) return 0; x >>= 1; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; return ++x; } /// /// Returns the nearest superior power of two of the value. /// For x = 0 and x > 2^63, returns 0. /// E.g. x = 401 -> 512. /// E.g. x = 256 -> 256. /// [Pure] public static ulong NextPowerOfTwo(this ulong x) { --x; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; x |= x >> 32; return ++x; } /// /// Returns the nearest inferior power of two of the value. /// For x <= 0, returns 0. /// E.g. x = 401 -> 256. /// E.g. x = 512 -> 512. /// [Pure] public static ulong PrevPowerOfTwo(this ulong x) { if (x == 0) return 0; x >>= 1; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; x |= x >> 32; return ++x; } #endregion #region Trigonometry /// /// Normalized sinc function. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Sinc(this float x) { // See unit test for determining eps if (Abs(x) < 0.00017791694f) { return 1; } else { #if NETCOREAPP3_1_OR_GREATER return MathF.Sin(ConstantF.Pi * x) / (ConstantF.Pi * x); #else return (float)Math.Sin(ConstantF.Pi * x) / (ConstantF.Pi * x); #endif } } /// /// Returns the sine of the specified angle in radians. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Sin(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Sin(x); #else return (float)Math.Sin(x); #endif } /// /// Returns the cosine of the specified angle in radians. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Cos(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Cos(x); #else return (float)Math.Cos(x); #endif } /// /// Returns the tangent of the specified angle in radians. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Tan(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Tan(x); #else return (float)Math.Tan(x); #endif } /// /// Returns the angle in radians whose sine is the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Asin(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Asin(x); #else return (float)Math.Asin(x); #endif } /// /// Returns the angle in radians whose sine is the specified number while clamping the input to [-1, 1] in order to avoid numerical problems. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float AsinClamped(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Asin(Clamp(x, -1, 1)); #else return (float)Math.Asin(Clamp(x, -1, 1)); #endif } /// /// Returns the angle in radians whose cosine is the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Acos(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Acos(x); #else return (float)Math.Acos(x); #endif } /// /// Returns the angle in radians whose cosine is the specified number while clamping the input to [-1, 1] in order to avoid numerical problems. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float AcosClamped(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Acos(Clamp(x, -1, 1)); #else return (float)Math.Acos(Clamp(x, -1, 1)); #endif } /// /// Returns the angle in radians whose tangent is the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Atan(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Atan(x); #else return (float)Math.Atan(x); #endif } /// /// Returns the angle in radians whose tangent is /// the quotient of the two specified numbers. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Atan2(float y, float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Atan2(y, x); #else return (float)Math.Atan2(y, x); #endif } /// /// Returns the angle in radians whose tangent is /// the quotient of the two specified numbers using /// a faster algorithm than Math.Atan2. /// NOTE: Accuracy untested /// [Pure] public static float FastAtan2(float y, float x) { float angle; double piThreeFourths = Constant.Pi * 3 / 4; double yAbs = y.Abs() + Constant.PositiveTinyValue; // prevent 0/0 condition if (x >= 0) { double r = (x - yAbs) / (x + yAbs); angle = (float)(Constant.PiQuarter * (1 - r)); } else { double r = (x + yAbs) / (yAbs - x); angle = (float)(piThreeFourths - Constant.PiQuarter * r); } return y < 0 ? -angle : angle; // negate if in quad III or IV } /// /// Returns the hyperbolic sine of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Sinh(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Sinh(x); #else return (float)Math.Sinh(x); #endif } /// /// Returns the hyperbolic cosine of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Cosh(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Cosh(x); #else return (float)Math.Cosh(x); #endif } /// /// Returns the hyperbolic tangent of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Tanh(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Tanh(x); #else return (float)Math.Tanh(x); #endif } /// /// Returns the inverse hyperbolic sine of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Asinh(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Asinh(x); #else return Log(x + Sqrt(x * x + 1)); #endif } /// /// Returns the inverse hyperbolic cosine of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Acosh(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Acosh(x); #else return Log(x + Sqrt(x * x - 1)); #endif } /// /// Returns the inverse hyperbolic tangent of the specified number. /// Note that the absolute value of the argument must be smaller than 1. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Atanh(this float x) { #if NETCOREAPP3_1_OR_GREATER return MathF.Atanh(x); #else return 0.5f * Log((1 + x) / (1 - x)); #endif } /// /// Normalized sinc function. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Sinc(this double x) { // See unit test for determining eps if (Abs(x) < 6.840859302478615E-09) { return 1; } else { return Math.Sin(Constant.Pi * x) / (Constant.Pi * x); } } /// /// Returns the sine of the specified angle in radians. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Sin(this double x) { return Math.Sin(x); } /// /// Returns the cosine of the specified angle in radians. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Cos(this double x) { return Math.Cos(x); } /// /// Returns the tangent of the specified angle in radians. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Tan(this double x) { return Math.Tan(x); } /// /// Returns the angle in radians whose sine is the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Asin(this double x) { return Math.Asin(x); } /// /// Returns the angle in radians whose sine is the specified number while clamping the input to [-1, 1] in order to avoid numerical problems. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double AsinClamped(this double x) { return Math.Asin(Clamp(x, -1, 1)); } /// /// Returns the angle in radians whose cosine is the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Acos(this double x) { return Math.Acos(x); } /// /// Returns the angle in radians whose cosine is the specified number while clamping the input to [-1, 1] in order to avoid numerical problems. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double AcosClamped(this double x) { return Math.Acos(Clamp(x, -1, 1)); } /// /// Returns the angle in radians whose tangent is the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Atan(this double x) { return Math.Atan(x); } /// /// Returns the angle in radians whose tangent is /// the quotient of the two specified numbers. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Atan2(double y, double x) { return Math.Atan2(y, x); } /// /// Returns the angle in radians whose tangent is /// the quotient of the two specified numbers using /// a faster algorithm than Math.Atan2. /// NOTE: Accuracy untested /// [Pure] public static double FastAtan2(double y, double x) { double angle; double piThreeFourths = Constant.Pi * 3 / 4; double yAbs = y.Abs() + Constant.PositiveTinyValue; // prevent 0/0 condition if (x >= 0) { double r = (x - yAbs) / (x + yAbs); angle = (Constant.PiQuarter * (1 - r)); } else { double r = (x + yAbs) / (yAbs - x); angle = (piThreeFourths - Constant.PiQuarter * r); } return y < 0 ? -angle : angle; // negate if in quad III or IV } /// /// Returns the hyperbolic sine of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Sinh(this double x) { return Math.Sinh(x); } /// /// Returns the hyperbolic cosine of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Cosh(this double x) { return Math.Cosh(x); } /// /// Returns the hyperbolic tangent of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Tanh(this double x) { return Math.Tanh(x); } /// /// Returns the inverse hyperbolic sine of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Asinh(this double x) { #if NETCOREAPP3_1_OR_GREATER return Math.Asinh(x); #else return Log(x + Sqrt(x * x + 1)); #endif } /// /// Returns the inverse hyperbolic cosine of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Acosh(this double x) { #if NETCOREAPP3_1_OR_GREATER return Math.Acosh(x); #else return Log(x + Sqrt(x * x - 1)); #endif } /// /// Returns the inverse hyperbolic tangent of the specified number. /// Note that the absolute value of the argument must be smaller than 1. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Atanh(this double x) { #if NETCOREAPP3_1_OR_GREATER return Math.Atanh(x); #else return 0.5 * Log((1 + x) / (1 - x)); #endif } #endregion #region Step functions /// /// Returns 0 if < , and 1 otherwise. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Step(this byte x, byte edge) => x < edge ? (byte)0 : (byte)1; /// /// Returns 0 if < , and 1 otherwise. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Step(this sbyte x, sbyte edge) => x < edge ? (sbyte)0 : (sbyte)1; /// /// Returns 0 if < , and 1 otherwise. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Step(this short x, short edge) => x < edge ? (short)0 : (short)1; /// /// Returns 0 if < , and 1 otherwise. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Step(this ushort x, ushort edge) => x < edge ? (ushort)0 : (ushort)1; /// /// Returns 0 if < , and 1 otherwise. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Step(this int x, int edge) => x < edge ? 0 : 1; /// /// Returns 0 if < , and 1 otherwise. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Step(this uint x, uint edge) => x < edge ? (uint)0 : (uint)1; /// /// Returns 0 if < , and 1 otherwise. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Step(this long x, long edge) => x < edge ? 0 : 1; /// /// Returns 0 if < , and 1 otherwise. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Step(this ulong x, ulong edge) => x < edge ? (ulong)0 : (ulong)1; /// /// Returns 0 if < , and 1 otherwise. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Step(this float x, float edge) => x < edge ? 0 : 1; /// /// Inverse linear interpolation, clamped to [0, 1]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Linearstep(this float x, float edge0, float edge1) => Saturate(InvLerp(x, edge0, edge1)); /// /// Performs smooth Hermite interpolation between 0 and 1 when edge0 < x < edge1. /// [Pure] public static float Smoothstep(this float x, float edge0, float edge1) { var t = Linearstep(x, edge0, edge1); return t * t * (3 - 2 * t); } /// /// Returns 0 if < , and 1 otherwise. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Step(this double x, double edge) => x < edge ? 0 : 1; /// /// Inverse linear interpolation, clamped to [0, 1]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Linearstep(this double x, double edge0, double edge1) => Saturate(InvLerp(x, edge0, edge1)); /// /// Performs smooth Hermite interpolation between 0 and 1 when edge0 < x < edge1. /// [Pure] public static double Smoothstep(this double x, double edge0, double edge1) { var t = Linearstep(x, edge0, edge1); return t * t * (3 - 2 * t); } /// /// Returns 0 if < , and 1 otherwise. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Step(this decimal x, decimal edge) => x < edge ? 0 : 1; /// /// Inverse linear interpolation, clamped to [0, 1]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Linearstep(this decimal x, decimal edge0, decimal edge1) => Saturate(InvLerp(x, edge0, edge1)); /// /// Performs smooth Hermite interpolation between 0 and 1 when edge0 < x < edge1. /// [Pure] public static decimal Smoothstep(this decimal x, decimal edge0, decimal edge1) { var t = Linearstep(x, edge0, edge1); return t * t * (3 - 2 * t); } #endregion #region Interpolation /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Lerp(this float t, byte a, byte b) => (byte)Round(a * (1 - t) + b * t); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Lerp(this double t, byte a, byte b) => (byte)Round(a * (1 - t) + b * t); /// /// Inverse linear interpolation. Computes t of y = a * (1 - t) + b * t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double InvLerp(this byte y, byte a, byte b) => ((double)a - (double)y) / ((double)a - (double)b); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Lerp(this float t, sbyte a, sbyte b) => (sbyte)Round(a * (1 - t) + b * t); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Lerp(this double t, sbyte a, sbyte b) => (sbyte)Round(a * (1 - t) + b * t); /// /// Inverse linear interpolation. Computes t of y = a * (1 - t) + b * t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double InvLerp(this sbyte y, sbyte a, sbyte b) => ((double)a - (double)y) / ((double)a - (double)b); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Lerp(this float t, short a, short b) => (short)Round(a * (1 - t) + b * t); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Lerp(this double t, short a, short b) => (short)Round(a * (1 - t) + b * t); /// /// Inverse linear interpolation. Computes t of y = a * (1 - t) + b * t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double InvLerp(this short y, short a, short b) => ((double)a - (double)y) / ((double)a - (double)b); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Lerp(this float t, ushort a, ushort b) => (ushort)Round(a * (1 - t) + b * t); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort Lerp(this double t, ushort a, ushort b) => (ushort)Round(a * (1 - t) + b * t); /// /// Inverse linear interpolation. Computes t of y = a * (1 - t) + b * t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double InvLerp(this ushort y, ushort a, ushort b) => ((double)a - (double)y) / ((double)a - (double)b); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Lerp(this float t, int a, int b) => (int)Round(a * (1 - t) + b * t); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Lerp(this double t, int a, int b) => (int)Round(a * (1 - t) + b * t); /// /// Inverse linear interpolation. Computes t of y = a * (1 - t) + b * t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double InvLerp(this int y, int a, int b) => ((double)a - (double)y) / ((double)a - (double)b); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Lerp(this float t, uint a, uint b) => (uint)Round(a * (1 - t) + b * t); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Lerp(this double t, uint a, uint b) => (uint)Round(a * (1 - t) + b * t); /// /// Inverse linear interpolation. Computes t of y = a * (1 - t) + b * t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double InvLerp(this uint y, uint a, uint b) => ((double)a - (double)y) / ((double)a - (double)b); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Lerp(this float t, long a, long b) => (long)Round(a * (1 - t) + b * t); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Lerp(this double t, long a, long b) => (long)Round(a * (1 - t) + b * t); /// /// Inverse linear interpolation. Computes t of y = a * (1 - t) + b * t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double InvLerp(this long y, long a, long b) => ((double)a - (double)y) / ((double)a - (double)b); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Lerp(this float t, ulong a, ulong b) => (ulong)Round(a * (1 - t) + b * t); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Lerp(this double t, ulong a, ulong b) => (ulong)Round(a * (1 - t) + b * t); /// /// Inverse linear interpolation. Computes t of y = a * (1 - t) + b * t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double InvLerp(this ulong y, ulong a, ulong b) => ((double)a - (double)y) / ((double)a - (double)b); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Lerp(this float t, float a, float b) => a * (1 - t) + b * t; /// /// Inverse linear interpolation. Computes t of y = a * (1 - t) + b * t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float InvLerp(this float y, float a, float b) => (a - y) / (a - b); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Lerp(this double t, double a, double b) => a * (1 - t) + b * t; /// /// Inverse linear interpolation. Computes t of y = a * (1 - t) + b * t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double InvLerp(this double y, double a, double b) => (a - y) / (a - b); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Lerp(this decimal t, decimal a, decimal b) => a * (1 - t) + b * t; /// /// Inverse linear interpolation. Computes t of y = a * (1 - t) + b * t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal InvLerp(this decimal y, decimal a, decimal b) => (a - y) / (a - b); /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half Lerp(this Half t, Half a, Half b) => a * (1 - t) + b * t; /// /// Inverse linear interpolation. Computes t of y = a * (1 - t) + b * t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half InvLerp(this Half y, Half a, Half b) => (a - y) / (a - b); #endregion #region Mean /// /// Returns the mean of the given values. /// [Pure] public static double Mean(this IEnumerable array) { int count = 0; int sum = 0; foreach (var x in array) { sum += x; ++count; } return (double)sum / count; } /// /// Returns the mean of the given values. /// [Pure] public static double Mean(this IEnumerable array) { int count = 0; int sum = 0; foreach (var x in array) { sum += x; ++count; } return (double)sum / count; } /// /// Returns the mean of the given values. /// [Pure] public static double Mean(this IEnumerable array) { int count = 0; long sum = 0; foreach (var x in array) { sum += x; ++count; } return (double)sum / count; } /// /// Returns the mean of the given values. /// [Pure] public static double Mean(this IEnumerable array) { int count = 0; long sum = 0; foreach (var x in array) { sum += x; ++count; } return (double)sum / count; } /// /// Returns the mean of the given values. /// [Pure] public static double Mean(this IEnumerable array) { int count = 0; long sum = 0; foreach (var x in array) { sum += x; ++count; } return (double)sum / count; } /// /// Returns the mean of the given values. /// [Pure] public static double Mean(this IEnumerable array) { int count = 0; long sum = 0; foreach (var x in array) { sum += x; ++count; } return (double)sum / count; } /// /// Returns the mean of the given values. /// [Pure] public static double Mean(this IEnumerable array) { int count = 0; long sum = 0; foreach (var x in array) { sum += x; ++count; } return (double)sum / count; } /// /// Returns the mean of the given values. /// [Pure] public static double Mean(this IEnumerable array) { int count = 0; ulong sum = 0; foreach (var x in array) { sum += x; ++count; } return (double)sum / count; } /// /// Returns the mean of the given values. /// [Pure] public static double Mean(this IEnumerable array) { int count = 0; double sum = 0; foreach (var x in array) { sum += x; ++count; } return (double)sum / count; } /// /// Returns the mean of the given values. /// [Pure] public static double Mean(this IEnumerable array) { int count = 0; double sum = 0; foreach (var x in array) { sum += x; ++count; } return (double)sum / count; } [Pure] public static decimal Mean(this IEnumerable array) { int count = 0; decimal sum = 0; foreach (var x in array) { sum += x; ++count; } return (decimal)sum / count; } /// /// Returns the mean of the given values. /// [Pure] public static double Mean( this IEnumerable array, Func selector ) { int count = 0; double sum = 0; foreach (var x in array) { sum += selector(x); ++count; } return sum / count; } #endregion #region Variance & Standard Deviation /// /// Calculates the variance of given elements. /// [Pure] public static double Variance(this IEnumerable data) { int count = 0; double sum = 0, mean = data.Mean(); foreach (var x in data) { sum += (x - mean).Square(); count++; } return sum / count; } /// /// Calculates the standard deviation of given elements. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double StandardDeviation(this IEnumerable data) => data.Variance().Sqrt(); /// /// Calculates the variance of given elements. /// [Pure] public static double Variance(this IEnumerable data) { int count = 0; double sum = 0, mean = data.Mean(); foreach (var x in data) { sum += (x - mean).Square(); count++; } return sum / count; } /// /// Calculates the standard deviation of given elements. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double StandardDeviation(this IEnumerable data) => data.Variance().Sqrt(); /// /// Calculates the variance of given elements. /// [Pure] public static double Variance(this IEnumerable data) { int count = 0; double sum = 0, mean = data.Mean(); foreach (var x in data) { sum += (x - mean).Square(); count++; } return sum / count; } /// /// Calculates the standard deviation of given elements. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double StandardDeviation(this IEnumerable data) => data.Variance().Sqrt(); /// /// Calculates the variance of given elements. /// [Pure] public static double Variance(this IEnumerable data) { int count = 0; double sum = 0, mean = data.Mean(); foreach (var x in data) { sum += (x - mean).Square(); count++; } return sum / count; } /// /// Calculates the standard deviation of given elements. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double StandardDeviation(this IEnumerable data) => data.Variance().Sqrt(); /// /// Calculates the variance of given elements. /// [Pure] public static double Variance( this IEnumerable data, Func selector ) { int count = 0; double sum = 0, mean = data.Mean(selector); foreach (var x in data) { sum += (selector(x) - mean).Square(); count++; } return sum / count; } /// /// Calculates the standard deviation of given elements. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double StandardDeviation(this IEnumerable data, Func selector) => data.Variance(selector).Sqrt(); #endregion #region CountPositives /// /// Return the number of values greater than 0. /// [Pure] public static int CountPositives(this IEnumerable array) { int count = 0; foreach (var x in array) if (x > 0) ++count; return count; } /// /// Return the number of values greater than 0. /// [Pure] public static int CountPositives(this IEnumerable array) { int count = 0; foreach (var x in array) if (x > 0) ++count; return count; } /// /// Return the number of values greater than 0. /// [Pure] public static int CountPositives(this IEnumerable array) { int count = 0; foreach (var x in array) if (x > 0) ++count; return count; } /// /// Return the number of values greater than 0. /// [Pure] public static int CountPositives(this IEnumerable array) { int count = 0; foreach (var x in array) if (x > 0) ++count; return count; } /// /// Return the number of values greater than 0. /// [Pure] public static int CountPositives(this IEnumerable array) { int count = 0; foreach (var x in array) if (x > 0) ++count; return count; } /// /// Return the number of values greater than 0. /// [Pure] public static int CountPositives(this IEnumerable array) { int count = 0; foreach (var x in array) if (x > 0) ++count; return count; } /// /// Return the number of values greater than 0. /// [Pure] public static int CountPositives(this IEnumerable array) { int count = 0; foreach (var x in array) if (x > 0) ++count; return count; } #endregion #region CountNegatives /// /// Return the number of values less than 0. /// [Pure] public static int CountNegatives(this IEnumerable array) { int count = 0; foreach (var x in array) if (x < 0) ++count; return count; } /// /// Return the number of values less than 0. /// [Pure] public static int CountNegatives(this IEnumerable array) { int count = 0; foreach (var x in array) if (x < 0) ++count; return count; } /// /// Return the number of values less than 0. /// [Pure] public static int CountNegatives(this IEnumerable array) { int count = 0; foreach (var x in array) if (x < 0) ++count; return count; } /// /// Return the number of values less than 0. /// [Pure] public static int CountNegatives(this IEnumerable array) { int count = 0; foreach (var x in array) if (x < 0) ++count; return count; } /// /// Return the number of values less than 0. /// [Pure] public static int CountNegatives(this IEnumerable array) { int count = 0; foreach (var x in array) if (x < 0) ++count; return count; } /// /// Return the number of values less than 0. /// [Pure] public static int CountNegatives(this IEnumerable array) { int count = 0; foreach (var x in array) if (x < 0) ++count; return count; } /// /// Return the number of values less than 0. /// [Pure] public static int CountNegatives(this IEnumerable array) { int count = 0; foreach (var x in array) if (x < 0) ++count; return count; } #endregion #region Primes /// /// Checks if the given value is a prime number. /// /// The number to check. /// True if the number is a prime; otherwise, False. [Pure] public static bool IsPrime(this int value) { int imax = (int)Sqrt(value); for (int i = 2; i <= imax; i++) if (value % i == 0) return false; return true; } /// /// Checks if the given value is a prime number. /// /// The number to check. /// True if the number is a prime; otherwise, False. [Pure] public static bool IsPrime(this long value) { long imax = (long)Sqrt(value); for (long i = 2; i <= imax; i++) if (value % i == 0) return false; return true; } #endregion #region Swap /// /// Swaps and , /// so that afterwards a=b and b=a. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Swap(ref T a, ref T b) { T t = a; a = b; b = t; } /// /// Rotates left , , and , /// so that afterwards a=b, b=c and c=a. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Rotate(ref T a, ref T b, ref T c) { T t = a; a = b; b = c; c = t; } /// /// Rotates left , , , and , /// so that afterwards a=b, b=c, c=b and d=a. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Rotate(ref T a, ref T b, ref T c, ref T d) { T t = a; a = b; b = c; c = d; d = t; } /// /// Rotates left , , , , and , /// so that afterwards a=b, b=c, c=b and d=c and e=a. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Rotate(ref T a, ref T b, ref T c, ref T d, ref T e) { T t = a; a = b; b = c; c = d; d = e; e = t; } #endregion #region Common Divisor and Multiple /// TODO: Handle negative inputs? [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GreatestCommonDivisor(this int a, int b) => b == 0 ? a : GreatestCommonDivisor(b, a % b); /// TODO: Handle negative inputs? [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LeastCommonMultiple(this int a, int b) => a * b / GreatestCommonDivisor(a, b); /// TODO: Handle negative inputs? [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long GreatestCommonDivisor(this long a, long b) => b == 0 ? a : GreatestCommonDivisor(b, a % b); /// TODO: Handle negative inputs? [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long LeastCommonMultiple(this long a, long b) => a * b / GreatestCommonDivisor(a, b); /// TODO: Handle negative inputs? [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint GreatestCommonDivisor(this uint a, uint b) => b == 0 ? a : GreatestCommonDivisor(b, a % b); /// TODO: Handle negative inputs? [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint LeastCommonMultiple(this uint a, uint b) => a * b / GreatestCommonDivisor(a, b); /// TODO: Handle negative inputs? [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong GreatestCommonDivisor(this ulong a, ulong b) => b == 0 ? a : GreatestCommonDivisor(b, a % b); /// TODO: Handle negative inputs? [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong LeastCommonMultiple(this ulong a, ulong b) => a * b / GreatestCommonDivisor(a, b); #endregion #region Conversion [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int ToInt(this float x) => (int)x; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long ToLong(this float x) => (long)x; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int ToInt(this double x) => (int)x; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long ToLong(this double x) => (long)x; #endregion #region Weighted Sum [Pure] public static float WeightedSum(this float[] items, float[] weights) { float r = 0; var count = weights.Length; for (int i = 0; i < count; i++) r += weights[i] * items[i]; return r; } [Pure] public static double WeightedSum(this double[] items, double[] weights) { double r = 0; var count = weights.Length; for (int i = 0; i < count; i++) r += weights[i] * items[i]; return r; } #endregion #region Special Floating Point Value Checks /// /// Returns whether the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(this float v) => Single.IsNaN(v); /// /// Returns whether the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(this float v) => Single.IsInfinity(v); /// /// Returns whether the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(this float v) => Single.IsNegativeInfinity(v); /// /// Returns whether the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(this float v) => Single.IsPositiveInfinity(v); /// /// Returns whether the given is finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(this float v) { #if NETCOREAPP3_1_OR_GREATER return Single.IsFinite(v); #else return !(IsNaN(v) || IsInfinity(v)); #endif } /// /// Returns whether the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(this double v) => Double.IsNaN(v); /// /// Returns whether the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(this double v) => Double.IsInfinity(v); /// /// Returns whether the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(this double v) => Double.IsNegativeInfinity(v); /// /// Returns whether the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(this double v) => Double.IsPositiveInfinity(v); /// /// Returns whether the given is finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(this double v) { #if NETCOREAPP3_1_OR_GREATER return Double.IsFinite(v); #else return !(IsNaN(v) || IsInfinity(v)); #endif } #endregion #region Signs [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Signs GetSigns(this float value, float epsilon) { if (value < -epsilon) return Signs.Negative; if (value > +epsilon) return Signs.Positive; return Signs.Zero; } public static void AggregateSigns( this IEnumerable values, float epsilon, out int negativeCount, out int zeroCount, out int positiveCount) { int nc = 0, zc = 0, pc = 0; foreach (var v in values) { if (v < -epsilon) { ++nc; continue; } if (v > +epsilon) { ++pc; continue; } ++zc; } negativeCount = nc; zeroCount = zc; positiveCount = pc; } public static void AggregateSigns( this (float, float) values, float epsilon, out int negativeCount, out int zeroCount, out int positiveCount) => AggregateSigns(new[] { values.Item1, values.Item2 }, epsilon, out negativeCount, out zeroCount, out positiveCount); public static void AggregateSigns( this (float, float, float) values, float epsilon, out int negativeCount, out int zeroCount, out int positiveCount) => AggregateSigns(new[] { values.Item1, values.Item2, values.Item3 }, epsilon, out negativeCount, out zeroCount, out positiveCount); public static void AggregateSigns( this (float, float, float, float) values, float epsilon, out int negativeCount, out int zeroCount, out int positiveCount) => AggregateSigns(new[] { values.Item1, values.Item2, values.Item3, values.Item4 }, epsilon, out negativeCount, out zeroCount, out positiveCount); public static Signs AggregateSigns(this IEnumerable values, float epsilon) { var signs = Signs.None; foreach (var v in values) { if (v < -epsilon) { signs |= Signs.Negative; continue; } if (v > +epsilon) { signs |= Signs.Positive; continue; } signs |= Signs.Zero; } return signs; } public static Signs AggregateSigns(this (float, float) values, float epsilon) => AggregateSigns(new[] { values.Item1, values.Item2 }, epsilon); public static Signs AggregateSigns(this (float, float, float) values, float epsilon) => AggregateSigns(new[] { values.Item1, values.Item2, values.Item3 }, epsilon); public static Signs AggregateSigns(this (float, float, float, float) values, float epsilon) => AggregateSigns(new[] { values.Item1, values.Item2, values.Item3, values.Item4 }, epsilon); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Signs GetSigns(this double value, double epsilon) { if (value < -epsilon) return Signs.Negative; if (value > +epsilon) return Signs.Positive; return Signs.Zero; } public static void AggregateSigns( this IEnumerable values, double epsilon, out int negativeCount, out int zeroCount, out int positiveCount) { int nc = 0, zc = 0, pc = 0; foreach (var v in values) { if (v < -epsilon) { ++nc; continue; } if (v > +epsilon) { ++pc; continue; } ++zc; } negativeCount = nc; zeroCount = zc; positiveCount = pc; } public static void AggregateSigns( this (double, double) values, double epsilon, out int negativeCount, out int zeroCount, out int positiveCount) => AggregateSigns(new[] { values.Item1, values.Item2 }, epsilon, out negativeCount, out zeroCount, out positiveCount); public static void AggregateSigns( this (double, double, double) values, double epsilon, out int negativeCount, out int zeroCount, out int positiveCount) => AggregateSigns(new[] { values.Item1, values.Item2, values.Item3 }, epsilon, out negativeCount, out zeroCount, out positiveCount); public static void AggregateSigns( this (double, double, double, double) values, double epsilon, out int negativeCount, out int zeroCount, out int positiveCount) => AggregateSigns(new[] { values.Item1, values.Item2, values.Item3, values.Item4 }, epsilon, out negativeCount, out zeroCount, out positiveCount); public static Signs AggregateSigns(this IEnumerable values, double epsilon) { var signs = Signs.None; foreach (var v in values) { if (v < -epsilon) { signs |= Signs.Negative; continue; } if (v > +epsilon) { signs |= Signs.Positive; continue; } signs |= Signs.Zero; } return signs; } public static Signs AggregateSigns(this (double, double) values, double epsilon) => AggregateSigns(new[] { values.Item1, values.Item2 }, epsilon); public static Signs AggregateSigns(this (double, double, double) values, double epsilon) => AggregateSigns(new[] { values.Item1, values.Item2, values.Item3 }, epsilon); public static Signs AggregateSigns(this (double, double, double, double) values, double epsilon) => AggregateSigns(new[] { values.Item1, values.Item2, values.Item3, values.Item4 }, epsilon); #endregion } } ================================================ FILE: src/Aardvark.Base/Math/Base/Fun_template.cs ================================================ using System; using System.ComponentModel; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.Contracts; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTOGENERATED CODE - DO NOT CHANGE! //# Action comma = () => Out(", "); //# Action add = () => Out(" + "); //# var inttypes = Meta.IntegerTypes; //# var signedtypes = Meta.SignedTypes; //# var unsignedtypes = Meta.UnsignedTypes; //# var numtypes = Meta.StandardNumericTypes; //# var numdectypes = Meta.BuiltInNumericTypes; //# var numhdectypes = Meta.BuiltInNumericTypes.Concat(Meta.HalfType); //# var reptypes = Meta.RealRepresentableTypes; //# var freptypes = reptypes[Meta.FloatType]; //# var dreptypes = reptypes[Meta.DoubleType]; //# var modtypes = new [] { Meta.IntType, Meta.LongType, Meta.UIntType, Meta.ULongType }; //# var smalltypes = new [] { Meta.SByteType, Meta.ShortType, Meta.ByteType, Meta.UShortType }; //# var iltypes = new[] { Meta.IntType, Meta.LongType }; //# var fdtypes = new[] { Meta.FloatType, Meta.DoubleType }; //# var hfdtypes = new[] { Meta.HalfType, Meta.FloatType, Meta.DoubleType }; //# var fddectypes = new [] { Meta.FloatType, Meta.DoubleType, Meta.DecimalType }; //# var hfddectypes = new [] { Meta.HalfType, Meta.FloatType, Meta.DoubleType, Meta.DecimalType }; //# var ilfdtypes = Meta.VecFieldTypes; public static partial class Fun { #region Min and Max //# Meta.ComparableTypes.ForEach(t => { var type = t.Name; /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Min(this __type__ a, __type__ b) => a < b ? a : b; /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Max(this __type__ a, __type__ b) => a > b ? a : b; /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Min(this __type__ a, __type__ b, __type__ c) => a < b ? (a < c ? a : c) : (b < c ? b : c); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Max(this __type__ a, __type__ b, __type__ c) => a > b ? (a > c ? a : c) : (b > c ? b : c); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Min(this __type__ a, __type__ b, __type__ c, __type__ d) => Min(Min(a, b), Min(c, d)); /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Max(this __type__ a, __type__ b, __type__ c, __type__ d) => Max(Max(a, b), Max(c, d)); /// /// Returns the minimum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Min(this __type__ x, params __type__[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Min(result, values[i]); } return result; } /// /// Returns the maximum of the given values. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Max(this __type__ x, params __type__[] values) { var result = x; for (var i = 0; i < values.Length; i++) { result = Max(result, values[i]); } return result; } //# }); #endregion #region Abs //# signedtypes.ForEach(t => { //# var fname = "Abs"; /// /// Returns the absolute value of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Abs(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return Math.__fname__(x); #endif //# } } //# }); #endregion #region Angular Distance //# fdtypes.ForEach(t => { //# var constant = (t == Meta.DoubleType) ? "Constant" : "ConstantF"; /// /// Returns the absolute difference between two angles in radians. /// The result is within the range of [0, Pi]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ AngleDistance(this __t.Name__ alphaInRadians, __t.Name__ betaInRadians) { var phi = Abs(betaInRadians - alphaInRadians) % __constant__.PiTimesTwo; return (phi > __constant__.Pi) ? __constant__.PiTimesTwo - phi : phi; } /// /// Returns the signed difference between two angles in radians. /// The result is within the range of [-Pi, Pi). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ AngleDifference(this __t.Name__ alphaInRadians, __t.Name__ betaInRadians) { var phi = (betaInRadians - alphaInRadians + __constant__.Pi) % __constant__.PiTimesTwo - __constant__.Pi; return (phi < -__constant__.Pi) ? phi + __constant__.PiTimesTwo : phi; } //# }); #endregion #region ApproximateEquals //# numtypes.ForEach(t => { /// /// Returns whether the distance between x and y is not more than epsilon. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __t.Name__ x, __t.Name__ y, __t.Name__ epsilon) { //# if (signedtypes.Contains(t)) { return Abs(x - y) <= epsilon; //# } else { return (x > y) ? ((x - y) <= epsilon) : ((y - x) <= epsilon); //# } } //# }); //# fdtypes.ForEach(t => { /// /// Returns whether the distance between x and y is not more than /// Constant{__t.Name__}.PositiveTinyValue. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __t.Name__ x, __t.Name__ y) => ApproximateEquals(x, y, Constant<__t.Name__>.PositiveTinyValue); //# }); #endregion #region Floor //# fddectypes.ForEach(t => { //# var fname = "Floor"; /// /// Returns the largest integer less than or equal to the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Floor(this __t.Name__ x) { //# if (t == Meta.DecimalType) { return Decimal.__fname__(x); //# } else if (t == Meta.DoubleType) { return Math.__fname__(x); //# } else if (t == Meta.FloatType) { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float) Math.__fname__(x); #endif //# } } //# }); #endregion #region Ceiling //# fddectypes.ForEach(t => { //# var fname = "Ceiling"; /// /// Returns the smallest integer greater than or equal to the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Ceiling(this __t.Name__ x) { //# if (t == Meta.DecimalType) { return Decimal.__fname__(x); //# } else if (t == Meta.DoubleType) { return Math.__fname__(x); //# } else if (t == Meta.FloatType) { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float) Math.__fname__(x); #endif //# } } //# }); #endregion #region Round //# fddectypes.ForEach(t => { //# var fname = "Round"; /// /// Rounds a floating-point value to the nearest integral value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Round(this __t.Name__ x) { //# if (t == Meta.DecimalType) { return Decimal.__fname__(x); //# } else if (t == Meta.DoubleType) { return Math.__fname__(x); //# } else if (t == Meta.FloatType) { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float) Math.__fname__(x); #endif //# } } /// /// Rounds a floating-point value to the nearest integral value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Round(this __t.Name__ x, MidpointRounding mode) { //# if (t == Meta.DecimalType) { return Decimal.__fname__(x, mode); //# } else if (t == Meta.DoubleType) { return Math.__fname__(x, mode); //# } else if (t == Meta.FloatType) { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x, mode); #else return (float) Math.__fname__(x, mode); #endif //# } } /// /// Rounds a floating-point value to the nearest integral value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Round(this __t.Name__ x, int digits) { //# if (t == Meta.DecimalType) { return Decimal.__fname__(x, digits); //# } else if (t == Meta.DoubleType) { return Math.__fname__(x, digits); //# } else if (t == Meta.FloatType) { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x, digits); #else return (float) Math.__fname__(x, digits); #endif //# } } /// /// Rounds a floating-point value to the nearest integral value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Round(this __t.Name__ x, int digits, MidpointRounding mode) { //# if (t == Meta.DecimalType) { return Decimal.__fname__(x, digits, mode); //# } else if (t == Meta.DoubleType) { return Math.__fname__(x, digits, mode); //# } else if (t == Meta.FloatType) { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x, digits, mode); #else return (float) Math.__fname__(x, digits, mode); #endif //# } } //# }); #endregion #region Truncate //# fddectypes.ForEach(t => { //# var fname = "Truncate"; /// /// Rounds a floating-point value to the nearest integar towards zero. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Truncate(this __t.Name__ x) { //# if (t == Meta.DecimalType) { return Decimal.__fname__(x); //# } else if (t == Meta.DoubleType) { return Math.__fname__(x); //# } else if (t == Meta.FloatType) { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float) Math.__fname__(x); #endif //# } } //# }); #endregion #region Frac //# fddectypes.ForEach(t => { /// /// Returns the fractional part of t. Calculated as t - floor(t). /// The result is always positive and in [0, 1). /// The fractional part of a negative input will be flipped (e.g. frac(-0.3) -> 0.7). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Frac(this __t.Name__ t) { var res = t - Floor(t); return res == 1 ? 0 : res; } //# }); #endregion #region Clamp //# numdectypes.ForEach(t => { /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Clamp(this __t.Name__ x, __t.Name__ a, __t.Name__ b) { if (x < a) return a; if (x > b) return b; return x; } //# }); //# ilfdtypes.ForEach(t => { /// /// Clamps value to interval [a,b]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Clamp(this __t.Name__ x, Range1__t.Char__ range) { if (x < range.Min) return range.Min; if (x > range.Max) return range.Max; return x; } //# }); #endregion #region ClampExcl //# numdectypes.Where(t => !t.IsReal).ForEach(t => { /// /// Clamps value to interval [a,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ ClampExcl(this __t.Name__ x, __t.Name__ a, __t.Name__ b) { if (x < a) return a; if (x >= b) return (__t.Name__)(b - 1); return x; } //# }); //# ilfdtypes.Where(t => !t.IsReal).ForEach(t => { /// /// Clamps value to interval [a,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ ClampExcl(this __t.Name__ x, Range1__t.Char__ range) { if (x < range.Min) return range.Min; if (x >= range.Max) return (__t.Name__)(range.Max - 1); return x; } //# }); #endregion #region ClampWrap //# numdectypes.Where(t => t.Name != "ulong").ForEach(t => { //ulong cannot be wrapped in a larger integer variable for subtraction /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ ClampWrap(this __t.Name__ x, __t.Name__ a, __t.Name__ b) => (__t.Name__)(ModP(x - a, b - a) + a); //# }); //# ilfdtypes.Where(t => t.Name != "ulong").ForEach(t => { //ulong cannot be wrapped in a larger integer variable for subtraction /// /// Clamps value to interval [a,b[ and cyclically wraps around values outside this interval. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ ClampWrap(this __t.Name__ x, Range1__t.Char__ range) => (__t.Name__)(ModP(x - range.Min, range.Max - range.Min) + range.Min); //# }); #endregion #region WrapToPi //# fdtypes.ForEach(t => { //# var constant = (t == Meta.DoubleType) ? "Constant" : "ConstantF"; /// /// Wraps the given angle to the [-Pi, Pi] range. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ WrapToPi(this __t.Name__ angleInRadians) { var x = angleInRadians % __constant__.PiTimesTwo; return (x.Abs() > __constant__.Pi) ? x - __constant__.PiTimesTwo * x.Signum() : x; } //# }); #endregion #region Saturate //# numdectypes.ForEach(t => { //# var cast = smalltypes.Contains(t) ? "(" + t.Name + ")" : ""; /// /// Clamps value to interval [0,1]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Saturate(this __t.Name__ x) => Clamp(x, __cast__0, __cast__1); //# }); #endregion #region MapToUnitInterval //# fdtypes.ForEach(t => { //# var half = (t != Meta.DoubleType) ? "0.5f" : "0.5"; /// /// Maps value from interval [0, tMax] to interval [0, 1]. /// Values outside [0, tMax] are clamped - if t is greater than tMax /// then 1 is returned, if t is less than 0 then 0 is returned. /// If 'repeat' is true, then every interval [i * tMax, (i+1) * tMax] /// (for i from integers) is mapped to [0, 1]. /// If 'mirror' is true, then every second interval is flipped, such /// that [0, tMax) [tMax, 2*tMax) [2*tMax, 3*tMax] ... is mapped to /// [0,1)[1,0)[0,1)... /// [Pure] public static __t.Name__ MapToUnitInterval( this __t.Name__ t, __t.Name__ tMax, bool repeat, bool mirror ) { t = t / tMax; if (!repeat) { if (t >= 1) return 1; if (t <= 0) return 0; } if (mirror) { t = t - Floor(t * __half__) * 2; return t < 1 ? t : 2 - t; } else { return t - Floor(t); } } /// /// Maps value from interval [0, tMax] to interval [0, 1]. /// If 'repeat' is true, then every interval [i * tMax, (i+1) * tMax] /// (for i from integers) is mapped to [0, 1]. /// [Pure] public static __t.Name__ MapToUnitInterval(this __t.Name__ t, __t.Name__ tMax, bool repeat) { t = t / tMax; if (!repeat) { if (t >= 1) return 1; if (t <= 0) return 0; } return t - Floor(t); } /// /// Maps value from interval [0, tMax] to interval [0, 1]. /// [Pure] public static __t.Name__ MapToUnitInterval(this __t.Name__ t, __t.Name__ tMax) { t = t / tMax; if (t > 1) return 1; if (t < 0) return 0; return t; } /// /// Maps value from interval [tMin, tMax] to interval [0, 1]. /// [Pure] public static __t.Name__ MapToUnitInterval(this __t.Name__ t, __t.Name__ tMin, __t.Name__ tMax) { t = (t - tMin) / (tMax - tMin); if (t > 1) return 1; if (t < 0) return 0; return t; } //# }); #endregion #region Sign //# signedtypes.ForEach(t => { //# var fname = "Sign"; /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Sign(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return Math.__fname__(x); #endif //# } } /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// // Same as Fun.Sign(), we need this for the F# generic math library! [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Signumi(this __t.Name__ x) => Sign(x); /// /// Returns either -1, 0, or +1, indicating the sign of the specified value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Signum(this __t.Name__ x) { //# if (t != Meta.FloatType) { return (__t.Name__) Math.__fname__(x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return Math.__fname__(x); #endif //# } } //# }); #endregion #region Multiply-Add //# numdectypes.ForEach(t => { //# var type = t.Name; //# var isDouble = (t == Meta.DoubleType); //# if (fdtypes.Contains(t)) { #if NETCOREAPP3_1_OR_GREATER /// /// Returns (x * y) + z. /// Computes the result rounded as a single ternary operation. /// #else /// /// Returns (x * y) + z. /// #endif [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ MultiplyAdd(__type__ x, __type__ y, __type__ z) { #if NETCOREAPP3_1_OR_GREATER //# if (isDouble) { return Math.FusedMultiplyAdd(x, y, z); //# } else { return MathF.FusedMultiplyAdd(x, y, z); //# } #else return (x * y) + z; #endif } //# } else { //# var cast = smalltypes.Contains(t) ? "(" + type + ")" : ""; /// /// Returns (x * y) + z. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ MultiplyAdd(__type__ x, __type__ y, __type__ z) => __cast__((x * y) + z); //# } //# }); #endregion #region Floating point bits //# fdtypes.ForEach(t => { //# var type = t.Name; //# var isDouble = (t == Meta.DoubleType); //# { //# var toBits = isDouble ? "DoubleToInt64Bits" : "SingleToInt32Bits"; //# var fromBits = isDouble ? "Int64BitsToDouble" : "Int32BitsToSingle"; //# var bittype = isDouble ? "long" : "int"; #if NETSTANDARD2_0 /// /// Returns the bit representation of the given value as a . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe __bittype__ FloatToBits(this __type__ x) => *((__bittype__*)&x); /// /// Returns the value represented by the given . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe __type__ FloatFromBits(this __bittype__ x) => *((__type__*)&x); #else /// /// Returns the bit representation of the given value as a . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __bittype__ FloatToBits(this __type__ x) => BitConverter.__toBits__(x); /// /// Returns the value represented by the given . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FloatFromBits(this __bittype__ x) => BitConverter.__fromBits__(x); #endif //# } //# { //# var bittype = isDouble ? "ulong" : "uint"; /// /// Returns the bit representation of the given value as a . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe __bittype__ FloatToUnsignedBits(this __type__ x) => *((__bittype__*)&x); /// /// Returns the value represented by the given . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe __type__ FloatFromUnsignedBits(this __bittype__ x) => *((__type__*)&x); //# } //# }); #endregion #region Copy sign //# fdtypes.ForEach(t => { //# var type = t.Name; //# var fname = "CopySign"; //# var isDouble = (t == Meta.DoubleType); //# var bittype = isDouble ? "long" : "int"; /// /// Returns a value with the maginute of and the sign of . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ __fname__(__type__ value, __type__ sign) { #if NETCOREAPP3_1_OR_GREATER //# if (t != Meta.FloatType) { return Math.__fname__(value, sign); //# } else { return MathF.__fname__(value, sign); //# } #else var xbits = FloatToBits(value); var ybits = FloatToBits(sign); if ((xbits ^ ybits) < 0) { return FloatFromBits(xbits ^ __bittype__.MinValue); } return value; #endif } //# }); #endregion #region Comparisons //# numtypes.ForEach(t => { //# var abs = signedtypes.Contains(t) ? ".Abs()" : ""; //# var absValue = signedtypes.Contains(t) ? "the absolute value of " : ""; /// /// Returns whether __absValue__ is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this __t.Name__ x, __t.Name__ epsilon) => x__abs__ < epsilon; //# if (fdtypes.Contains(t)) { /// /// Returns whether the absolute value of is smaller than Constant<__t.Name__>.PositiveTinyValue. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this __t.Name__ x) => x__abs__ < Constant<__t.Name__>.PositiveTinyValue; //# } //# }); #endregion #region AbsSum //# signedtypes.ForEach(t => { var st = Meta.SummationTypeOf(t); /// /// Returns the sum of the absolute values of the given numbers. /// [Pure] public static __st.Name__ AbsSum(this IEnumerable<__t.Name__> array) { __st.Name__ sum = 0; foreach (var i in array) sum += i.Abs(); return sum; } //# }); #endregion #region Roots //# numtypes.ForEach(t => { //# var fname = "Pow"; //# var rtype = (t != Meta.FloatType) ? Meta.DoubleType : Meta.FloatType; /// /// Returns the n-th root of the specified number. //# if (!dreptypes.Contains(t)) { /// Note: This function uses a double representation internally, but not all __t.Name__ values can be represented exactly as double. //# } /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype.Name__ Root(this __t.Name__ x, int n) { //# if (t != Meta.FloatType) { return Math.__fname__(x, 1.0 / n); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x, 1.0f / n); #else return (float)Math.__fname__(x, 1.0 / n); #endif //# } } //# }); //# numtypes.ForEach(t => { //# var fname = "Sqrt"; //# var rtype = (t != Meta.FloatType) ? Meta.DoubleType : Meta.FloatType; /// /// Returns the square root of the specified number. //# if (!dreptypes.Contains(t)) { /// Note: This function uses a double representation internally, but not all __t.Name__ values can be represented exactly as double. //# } /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype.Name__ Sqrt(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float)Math.__fname__(x); #endif //# } } //# }); //# numtypes.ForEach(t => { //# var fname = "Cbrt"; //# var rtype = (t != Meta.FloatType) ? Meta.DoubleType : Meta.FloatType; //# var rcast = (rtype != Meta.DoubleType) ? "(" + rtype.Name + ")" : ""; /// /// Returns the cubic root of the specified number. //# if (!dreptypes.Contains(t)) { /// Note: This function uses a double representation internally, but not all __t.Name__ values can be represented exactly as double. //# } /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype.Name__ Cbrt(this __t.Name__ x) { #if NETCOREAPP3_1_OR_GREATER //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { return MathF.__fname__(x); //# } #else //# if (signedtypes.Contains(t)) { return x < 0 ? __rcast__-Math.Pow(-x, Constant.OneThird) : __rcast__Math.Pow( x, Constant.OneThird); //# } else { return __rcast__Math.Pow(x, Constant.OneThird); //# } #endif } //# }); #endregion #region Square //# numdectypes.ForEach(t => { /// /// Returns the square of the specified number. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Square(this __t.Name__ x) => (__t.Name__)(x * x); //# }); #endregion #region Power //# numtypes.ForEach(t => { //# fdtypes.ForEach(rt => { //# var rcast = (rt != Meta.DoubleType) ? "(" + rt.Name + ")" : ""; //# if (!fdtypes.Contains(t) || t == rt) { /// /// Returns the number raised to the specified power. //# if (rt == Meta.DoubleType && !dreptypes.Contains(t)) { /// Note: This function uses a double representation internally, but not all __t.Name__ values can be represented exactly as double. //# } /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rt.Name__ Pow(this __t.Name__ x, __rt.Name__ y) { //# if (rt != Meta.FloatType || !freptypes.Contains(t)) { return __rcast__Math.Pow(x, y); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.Pow(x, y); #else return __rcast__Math.Pow(x, y); #endif //# } } [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rt.Name__ Power(this __t.Name__ x, __rt.Name__ y) => Pow(x, y); //# } //# }); //# if (!fdtypes.Contains(t) && t != Meta.IntType) { /// /// Returns the number raised to the specified integer power. //# if (signedtypes.Contains(t)) { /// The exponent must not be negative. //# } /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Pown(this __t.Name__ x, __t.Name__ y) { //# if (smalltypes.Contains(t)) { //# var cast = Meta.UnsignedTypes.Contains(t) ? "(uint)" : "(int)"; return (__t.Name__)Pown(__cast__x, y); //# } else { Debug.Assert(y >= 0); if (y == 0) return 1; if (y == 1) return x; if (y == 2) return x * x; if (y == 3) return x * x * x; if (y == 4) { var xx = x * x; return xx * xx; } var v = Pown(x, y / 2); v *= v; return (y % 2 == 0) ? v : v * x; //# } } //# } /// /// Returns the number raised to the specified integer power. /// The exponent must not be negative. /// // Based on the F# core library implementation (ComputePowerGenericInlined) [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Pown(this __t.Name__ x, int y) { //# if (smalltypes.Contains(t)) { //# var cast = Meta.UnsignedTypes.Contains(t) ? "(uint)" : "(int)"; return (__t.Name__)Pown(__cast__x, y); //# } else { Debug.Assert(y >= 0); if (y == 0) return 1; if (y == 1) return x; if (y == 2) return x * x; if (y == 3) return x * x * x; if (y == 4) { var xx = x * x; return xx * xx; } var v = Pown(x, y / 2); v *= v; return (y % 2 == 0) ? v : v * x; //# } } //# }); #endregion #region Exp and Log //# numtypes.ForEach(t => { //# var rtype = (t != Meta.FloatType) ? Meta.DoubleType : Meta.FloatType; //# var rconst = (rtype != Meta.DoubleType) ? "ConstantF" : "Constant"; /// /// Returns e raised to the specified number. //# if (!dreptypes.Contains(t)) { /// Note: This function uses a double representation internally, but not all __t.Name__ values can be represented exactly as double. //# } /// //# var fname = "Exp"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype.Name__ __fname__(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float)Math.__fname__(x); #endif //# } } /// /// Returns the natural (base e) logarithm of the specified number. //# if (!dreptypes.Contains(t)) { /// Note: This function uses a double representation internally, but not all __t.Name__ values can be represented exactly as double. //# } /// //# fname = "Log"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype.Name__ __fname__(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float)Math.__fname__(x); #endif //# } } /// /// Returns the base 10 logarithm of the specified number. //# if (!dreptypes.Contains(t)) { /// Note: This function uses a double representation internally, but not all __t.Name__ values can be represented exactly as double. //# } /// //# fname = "Log10"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype.Name__ __fname__(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float)Math.__fname__(x); #endif //# } } /// /// Returns the base 2 logarithm of the specified number. //# if (!dreptypes.Contains(t)) { /// Note: This function uses a double representation internally, but not all __t.Name__ values can be represented exactly as double. //# } /// //# fname = "Log2"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype.Name__ __fname__(this __t.Name__ x) { #if NETCOREAPP3_1_OR_GREATER //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { //return MathF.__fname__(x); // MathF.Log2 actually uses a conversion to double internally and has bad perfromance, see Aardvark.Base.Benchmarks/Log2Int.cs return x.Log() * __rconst__.Ln2Inv; //# } #else return x.Log() * __rconst__.Ln2Inv; #endif } /// /// Returns the values logarithm of the specified basis. //# if (!dreptypes.Contains(t)) { /// Note: This function uses a double representation internally, but not all __t.Name__ values can be represented exactly as double. //# } /// //# fname = "Log"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype.Name__ __fname__(this __t.Name__ x, __rtype.Name__ basis) { //# if (t != Meta.FloatType) { return Math.__fname__(x, basis); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x, basis); #else return (float)Math.__fname__(x, basis); #endif //# } } //# }); #endregion #region LinCom //# foreach (var it in Meta.IntegerTypes) { var itn = it.Name; //# for (int tpc = 4; tpc < 7; tpc+=2) { //# foreach (var rt in Meta.RealTypes) { var rtn = rt.Name; var rtc = rt.Caps[0]; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __itn__ LinCom( /*# tpc.ForEach(i => { */__itn__ p__i__/*# }, comma); */, ref Tup__tpc__<__rtn__> w) { return (__itn__)Fun.Clamp(/*# tpc.ForEach(i => { */p__i__ * w.E__i__/*# }, add); */, (__rtn__)__itn__.MinValue, (__rtn__)__itn__.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtn__ LinComRaw__rtc__( /*# tpc.ForEach(i => { */__itn__ p__i__/*# }, comma); */, ref Tup__tpc__<__rtn__> w) { return /*# tpc.ForEach(i => { */p__i__ * w.E__i__/*# }, add); */; } //# } // rt //# } // tpc //# } // it //# for (int tpc = 2; tpc < 8; tpc++ ) { //# foreach (var rt in hfdtypes) { var rtn = rt.Name; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtn__ LinCom(/*# tpc.ForEach(i => { */__rtn__ p__i__/*# }, comma); */, ref Tup__tpc__<__rtn__> w) { return /*# tpc.ForEach(i => { */p__i__ * w.E__i__/*# }, add); */; } //# } // rt //# } // tpc #endregion #region ModP //# signedtypes.ForEach(t => { /// /// Returns the positive modulo operation a mod b giving values between [0,b[ /// instead of a % b giving values between ]-b,b[. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ ModP(this __t.Name__ a, __t.Name__ b) { var m = a % b; if (m < 0) m += b; return (__t.Name__)m; } //# }); #endregion #region PowerOfTwo //# modtypes.ForEach(t => { /// /// Returns true if the supplied number is 0 or a power of two. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPowerOfTwo(this __t.Name__ x) => (x & (x - 1)) == 0; //# }); //# inttypes.ForEach(t => { /// /// Returns 2 raised to the power of the value. //# if (signedtypes.Contains(t)) { /// The exponent must be within [0, 64). //# } else { /// The exponent must be less than 64. //# } /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong PowerOfTwo(this __t.Name__ x) { Debug.Assert(x >= 0 && x < 64); return 1UL << (int)x; } //# }); //# fdtypes.ForEach(t => { /// /// Returns 2 raised to the power of the value. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ PowerOfTwo(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.Pow(2, x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.Pow(2, x); #else return (float)Math.Pow(2, x); #endif //# } } //# }); //# modtypes.ForEach(t => { //# var limit = new Dictionary //# { //# { Meta.IntType, "30" }, //# { Meta.UIntType, "31" }, //# { Meta.LongType, "62" }, //# { Meta.ULongType, "63" } //# }; /// /// Returns the nearest superior power of two of the value. //# if (signedtypes.Contains(t)) { /// For x <= 0, returns 0. /// For x > 2^__limit[t]__, returns __t.Name__.MinValue. //# } else { /// For x = 0 and x > 2^__limit[t]__, returns 0. //# } /// E.g. x = 401 -> 512. /// E.g. x = 256 -> 256. /// [Pure] public static __t.Name__ NextPowerOfTwo(this __t.Name__ x) { --x; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; //# if (t == Meta.LongType || t == Meta.ULongType) { x |= x >> 32; //# } return ++x; } /// /// Returns the nearest inferior power of two of the value. /// For x <= 0, returns 0. /// E.g. x = 401 -> 256. /// E.g. x = 512 -> 512. /// [Pure] public static __t.Name__ PrevPowerOfTwo(this __t.Name__ x) { //# if (signedtypes.Contains(t)) { if (x <= 0) return 0; //# } else { if (x == 0) return 0; //# } x >>= 1; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; //# if (t == Meta.LongType || t == Meta.ULongType) { x |= x >> 32; //# } return ++x; } //# }); #endregion #region Trigonometry //# fdtypes.ForEach(t => { //# var cast = t != Meta.DoubleType ? "(" + t.Name + ")" : ""; //# var half = (t == Meta.DoubleType) ? "0.5" : "0.5f"; //# var constant = (t == Meta.DoubleType) ? "Constant" : "ConstantF"; //# { //# var eps = (t == Meta.DoubleType) ? "6.840859302478615E-09" : "0.00017791694f"; /// /// Normalized sinc function. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Sinc(this __t.Name__ x) { // See unit test for determining eps if (Abs(x) < __eps__) { return 1; } else { //# if (t != Meta.FloatType) { return Math.Sin(__constant__.Pi * x) / (__constant__.Pi * x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.Sin(__constant__.Pi * x) / (__constant__.Pi * x); #else return (float)Math.Sin(__constant__.Pi * x) / (__constant__.Pi * x); #endif //# } } } //# } /// /// Returns the sine of the specified angle in radians. /// //# var fname = "Sin"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ __fname__(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float)Math.__fname__(x); #endif //# } } /// /// Returns the cosine of the specified angle in radians. /// //# fname = "Cos"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ __fname__(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float)Math.__fname__(x); #endif //# } } /// /// Returns the tangent of the specified angle in radians. /// //# fname = "Tan"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ __fname__(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float)Math.__fname__(x); #endif //# } } /// /// Returns the angle in radians whose sine is the specified number. /// //# fname = "Asin"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ __fname__(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float)Math.__fname__(x); #endif //# } } /// /// Returns the angle in radians whose sine is the specified number while clamping the input to [-1, 1] in order to avoid numerical problems. /// //# fname = "Asin"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ __fname__Clamped(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(Clamp(x, -1, 1)); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(Clamp(x, -1, 1)); #else return (float)Math.__fname__(Clamp(x, -1, 1)); #endif //# } } /// /// Returns the angle in radians whose cosine is the specified number. /// //# fname = "Acos"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ __fname__(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float)Math.__fname__(x); #endif //# } } /// /// Returns the angle in radians whose cosine is the specified number while clamping the input to [-1, 1] in order to avoid numerical problems. /// //# fname = "Acos"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ __fname__Clamped(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(Clamp(x, -1, 1)); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(Clamp(x, -1, 1)); #else return (float)Math.__fname__(Clamp(x, -1, 1)); #endif //# } } /// /// Returns the angle in radians whose tangent is the specified number. /// //# fname = "Atan"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ __fname__(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float)Math.__fname__(x); #endif //# } } /// /// Returns the angle in radians whose tangent is /// the quotient of the two specified numbers. /// //# fname = "Atan2"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ __fname__(__t.Name__ y, __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(y, x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(y, x); #else return (float)Math.__fname__(y, x); #endif //# } } /// /// Returns the angle in radians whose tangent is /// the quotient of the two specified numbers using /// a faster algorithm than Math.Atan2. /// NOTE: Accuracy untested /// [Pure] public static __t.Name__ FastAtan2(__t.Name__ y, __t.Name__ x) { __t.Name__ angle; double piThreeFourths = Constant.Pi * 3 / 4; double yAbs = y.Abs() + Constant.PositiveTinyValue; // prevent 0/0 condition if (x >= 0) { double r = (x - yAbs) / (x + yAbs); angle = __cast__(Constant.PiQuarter * (1 - r)); } else { double r = (x + yAbs) / (yAbs - x); angle = __cast__(piThreeFourths - Constant.PiQuarter * r); } return y < 0 ? -angle : angle; // negate if in quad III or IV } /// /// Returns the hyperbolic sine of the specified number. /// //# fname = "Sinh"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ __fname__(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float)Math.__fname__(x); #endif //# } } /// /// Returns the hyperbolic cosine of the specified number. /// //# fname = "Cosh"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ __fname__(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float)Math.__fname__(x); #endif //# } } /// /// Returns the hyperbolic tangent of the specified number. /// //# fname = "Tanh"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ __fname__(this __t.Name__ x) { //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { #if NETCOREAPP3_1_OR_GREATER return MathF.__fname__(x); #else return (float)Math.__fname__(x); #endif //# } } /// /// Returns the inverse hyperbolic sine of the specified number. /// //# fname = "Asinh"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ __fname__(this __t.Name__ x) { #if NETCOREAPP3_1_OR_GREATER //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { return MathF.__fname__(x); //# } #else return Log(x + Sqrt(x * x + 1)); #endif } /// /// Returns the inverse hyperbolic cosine of the specified number. /// //# fname = "Acosh"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ __fname__(this __t.Name__ x) { #if NETCOREAPP3_1_OR_GREATER //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { return MathF.__fname__(x); //# } #else return Log(x + Sqrt(x * x - 1)); #endif } /// /// Returns the inverse hyperbolic tangent of the specified number. /// Note that the absolute value of the argument must be smaller than 1. /// //# fname = "Atanh"; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ __fname__(this __t.Name__ x) { #if NETCOREAPP3_1_OR_GREATER //# if (t != Meta.FloatType) { return Math.__fname__(x); //# } else { return MathF.__fname__(x); //# } #else return __half__ * Log((1 + x) / (1 - x)); #endif } //# }); #endregion #region Step functions //# numdectypes.ForEach(t => { //# var cast = (smalltypes.Contains(t) || unsignedtypes.Contains(t)) ? "(" + t.Name + ")" : ""; /// /// Returns 0 if < , and 1 otherwise. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Step(this __t.Name__ x, __t.Name__ edge) => x < edge ? __cast__0 : __cast__1; //# if (fddectypes.Contains(t)) { /// /// Inverse linear interpolation, clamped to [0, 1]. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Linearstep(this __t.Name__ x, __t.Name__ edge0, __t.Name__ edge1) => Saturate(InvLerp(x, edge0, edge1)); /// /// Performs smooth Hermite interpolation between 0 and 1 when edge0 < x < edge1. /// [Pure] public static __t.Name__ Smoothstep(this __t.Name__ x, __t.Name__ edge0, __t.Name__ edge1) { var t = Linearstep(x, edge0, edge1); return t * t * (3 - 2 * t); } //# } //# }); #endregion #region Interpolation //# numhdectypes.ForEach(t => { //# if (hfddectypes.Contains(t)) { /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Lerp(this __t.Name__ t, __t.Name__ a, __t.Name__ b) => a * (1 - t) + b * t; /// /// Inverse linear interpolation. Computes t of y = a * (1 - t) + b * t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ InvLerp(this __t.Name__ y, __t.Name__ a, __t.Name__ b) => (a - y) / (a - b); //# } else { //# fdtypes.ForEach(rt => { //# var one = (rt != Meta.DoubleType) ? "1.0f" : "1.0"; /// /// Linearly interpolates between a and b according to t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ Lerp(this __rt.Name__ t, __t.Name__ a, __t.Name__ b) => (__t.Name__)Round(a * (1 - t) + b * t); //# }); /// /// Inverse linear interpolation. Computes t of y = a * (1 - t) + b * t. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double InvLerp(this __t.Name__ y, __t.Name__ a, __t.Name__ b) => ((double)a - (double)y) / ((double)a - (double)b); //# } //# }); #endregion #region Mean //# numtypes.ForEach(t => { var st = Meta.SummationTypeOf(t); /// /// Returns the mean of the given values. /// [Pure] public static double Mean(this IEnumerable<__t.Name__> array) { int count = 0; __st.Name__ sum = 0; foreach (var x in array) { sum += x; ++count; } return (double)sum / count; } //# }); [Pure] public static decimal Mean(this IEnumerable array) { int count = 0; decimal sum = 0; foreach (var x in array) { sum += x; ++count; } return (decimal)sum / count; } /// /// Returns the mean of the given values. /// [Pure] public static double Mean( this IEnumerable array, Func selector ) { int count = 0; double sum = 0; foreach (var x in array) { sum += selector(x); ++count; } return sum / count; } #endregion #region Variance & Standard Deviation //# ilfdtypes.ForEach(t => { var type = t.Name; //# if (Meta.UnsignedTypes.Contains(t)) return; /// /// Calculates the variance of given elements. /// [Pure] public static double Variance(this IEnumerable<__type__> data) { int count = 0; double sum = 0, mean = data.Mean(); foreach (var x in data) { sum += (x - mean).Square(); count++; } return sum / count; } /// /// Calculates the standard deviation of given elements. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double StandardDeviation(this IEnumerable<__type__> data) => data.Variance().Sqrt(); //# }); /// /// Calculates the variance of given elements. /// [Pure] public static double Variance( this IEnumerable data, Func selector ) { int count = 0; double sum = 0, mean = data.Mean(selector); foreach (var x in data) { sum += (selector(x) - mean).Square(); count++; } return sum / count; } /// /// Calculates the standard deviation of given elements. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double StandardDeviation(this IEnumerable data, Func selector) => data.Variance(selector).Sqrt(); #endregion #region CountPositives //# signedtypes.ForEach(t => { /// /// Return the number of values greater than 0. /// [Pure] public static int CountPositives(this IEnumerable<__t.Name__> array) { int count = 0; foreach (var x in array) if (x > 0) ++count; return count; } //# }); #endregion #region CountNegatives //# signedtypes.ForEach(t => { /// /// Return the number of values less than 0. /// [Pure] public static int CountNegatives(this IEnumerable<__t.Name__> array) { int count = 0; foreach (var x in array) if (x < 0) ++count; return count; } //# }); #endregion #region Primes //# iltypes.ForEach(t => { /// /// Checks if the given value is a prime number. /// /// The number to check. /// True if the number is a prime; otherwise, False. [Pure] public static bool IsPrime(this __t.Name__ value) { __t.Name__ imax = (__t.Name__)Sqrt(value); for (__t.Name__ i = 2; i <= imax; i++) if (value % i == 0) return false; return true; } //# }); #endregion #region Swap /// /// Swaps and , /// so that afterwards a=b and b=a. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Swap(ref T a, ref T b) { T t = a; a = b; b = t; } /// /// Rotates left , , and , /// so that afterwards a=b, b=c and c=a. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Rotate(ref T a, ref T b, ref T c) { T t = a; a = b; b = c; c = t; } /// /// Rotates left , , , and , /// so that afterwards a=b, b=c, c=b and d=a. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Rotate(ref T a, ref T b, ref T c, ref T d) { T t = a; a = b; b = c; c = d; d = t; } /// /// Rotates left , , , , and , /// so that afterwards a=b, b=c, c=b and d=c and e=a. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Rotate(ref T a, ref T b, ref T c, ref T d, ref T e) { T t = a; a = b; b = c; c = d; d = e; e = t; } #endregion #region Common Divisor and Multiple //# modtypes.ForEach(t => { /// TODO: Handle negative inputs? [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ GreatestCommonDivisor(this __t.Name__ a, __t.Name__ b) => b == 0 ? a : GreatestCommonDivisor(b, a % b); /// TODO: Handle negative inputs? [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __t.Name__ LeastCommonMultiple(this __t.Name__ a, __t.Name__ b) => a * b / GreatestCommonDivisor(a, b); //# }); #endregion #region Conversion [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int ToInt(this float x) => (int)x; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long ToLong(this float x) => (long)x; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int ToInt(this double x) => (int)x; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long ToLong(this double x) => (long)x; #endregion #region Weighted Sum //# fdtypes.ForEach(t => { //# var type = t.Name; [Pure] public static __type__ WeightedSum(this __type__[] items, __type__[] weights) { __type__ r = 0; var count = weights.Length; for (int i = 0; i < count; i++) r += weights[i] * items[i]; return r; } //# }); #endregion #region Special Floating Point Value Checks //# fdtypes.ForEach(t => { //# var type = t.Name; //# var clsnm = (t == Meta.DoubleType) ? "Double" : "Single"; /// /// Returns whether the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(this __type__ v) => __clsnm__.IsNaN(v); /// /// Returns whether the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(this __type__ v) => __clsnm__.IsInfinity(v); /// /// Returns whether the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(this __type__ v) => __clsnm__.IsNegativeInfinity(v); /// /// Returns whether the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(this __type__ v) => __clsnm__.IsPositiveInfinity(v); /// /// Returns whether the given is finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(this __type__ v) { #if NETCOREAPP3_1_OR_GREATER return __clsnm__.IsFinite(v); #else return !(IsNaN(v) || IsInfinity(v)); #endif } //# }); #endregion #region Signs //# fdtypes.ForEach(t => { //# var type = t.Name; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Signs GetSigns(this __type__ value, __type__ epsilon) { if (value < -epsilon) return Signs.Negative; if (value > +epsilon) return Signs.Positive; return Signs.Zero; } public static void AggregateSigns( this IEnumerable<__type__> values, __type__ epsilon, out int negativeCount, out int zeroCount, out int positiveCount) { int nc = 0, zc = 0, pc = 0; foreach (var v in values) { if (v < -epsilon) { ++nc; continue; } if (v > +epsilon) { ++pc; continue; } ++zc; } negativeCount = nc; zeroCount = zc; positiveCount = pc; } public static void AggregateSigns( this (__type__, __type__) values, __type__ epsilon, out int negativeCount, out int zeroCount, out int positiveCount) => AggregateSigns(new[] { values.Item1, values.Item2 }, epsilon, out negativeCount, out zeroCount, out positiveCount); public static void AggregateSigns( this (__type__, __type__, __type__) values, __type__ epsilon, out int negativeCount, out int zeroCount, out int positiveCount) => AggregateSigns(new[] { values.Item1, values.Item2, values.Item3 }, epsilon, out negativeCount, out zeroCount, out positiveCount); public static void AggregateSigns( this (__type__, __type__, __type__, __type__) values, __type__ epsilon, out int negativeCount, out int zeroCount, out int positiveCount) => AggregateSigns(new[] { values.Item1, values.Item2, values.Item3, values.Item4 }, epsilon, out negativeCount, out zeroCount, out positiveCount); public static Signs AggregateSigns(this IEnumerable<__type__> values, __type__ epsilon) { var signs = Signs.None; foreach (var v in values) { if (v < -epsilon) { signs |= Signs.Negative; continue; } if (v > +epsilon) { signs |= Signs.Positive; continue; } signs |= Signs.Zero; } return signs; } public static Signs AggregateSigns(this (__type__, __type__) values, __type__ epsilon) => AggregateSigns(new[] { values.Item1, values.Item2 }, epsilon); public static Signs AggregateSigns(this (__type__, __type__, __type__) values, __type__ epsilon) => AggregateSigns(new[] { values.Item1, values.Item2, values.Item3 }, epsilon); public static Signs AggregateSigns(this (__type__, __type__, __type__, __type__) values, __type__ epsilon) => AggregateSigns(new[] { values.Item1, values.Item2, values.Item3, values.Item4 }, epsilon); //# }); #endregion } } ================================================ FILE: src/Aardvark.Base/Math/Base/Half.cs ================================================ using System; using System.Diagnostics; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Aardvark.Base { // Code by Ladislav Lang: https://sourceforge.net/projects/csharp-half/ // Based on: http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf #region Helpers /// /// Helper class for Half conversions and some low level operations. /// This class is internally used in the Half class. /// /// /// References: /// - Fast Half Float Conversions, Jeroen van der Zijp, link: http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf /// [ComVisible(false)] internal static class HalfHelper { private static readonly uint[] mantissaTable = GenerateMantissaTable(); private static readonly uint[] exponentTable = GenerateExponentTable(); private static readonly ushort[] offsetTable = GenerateOffsetTable(); private static readonly ushort[] baseTable = GenerateBaseTable(); private static readonly sbyte[] shiftTable = GenerateShiftTable(); // Transforms the subnormal representation to a normalized one. private static uint ConvertMantissa(int i) { uint m = (uint)(i << 13); // Zero pad mantissa bits uint e = 0; // Zero exponent // While not normalized while ((m & 0x00800000) == 0) { e -= 0x00800000; // Decrement exponent (1<<23) m <<= 1; // Shift mantissa } m &= unchecked((uint)~0x00800000); // Clear leading 1 bit e += 0x38800000; // Adjust bias ((127-14)<<23) return m | e; // Return combined number } private static uint[] GenerateMantissaTable() { uint[] mantissaTable = new uint[2048]; mantissaTable[0] = 0; for (int i = 1; i < 1024; i++) { mantissaTable[i] = ConvertMantissa(i); } for (int i = 1024; i < 2048; i++) { mantissaTable[i] = (uint)(0x38000000 + ((i - 1024) << 13)); } return mantissaTable; } private static uint[] GenerateExponentTable() { uint[] exponentTable = new uint[64]; exponentTable[0] = 0; for (int i = 1; i < 31; i++) { exponentTable[i] = (uint)(i << 23); } exponentTable[31] = 0x47800000; exponentTable[32] = 0x80000000; for (int i = 33; i < 63; i++) { exponentTable[i] = (uint)(0x80000000 + ((i - 32) << 23)); } exponentTable[63] = 0xc7800000; return exponentTable; } private static ushort[] GenerateOffsetTable() { ushort[] offsetTable = new ushort[64]; offsetTable[0] = 0; for (int i = 1; i < 32; i++) { offsetTable[i] = 1024; } offsetTable[32] = 0; for (int i = 33; i < 64; i++) { offsetTable[i] = 1024; } return offsetTable; } private static ushort[] GenerateBaseTable() { ushort[] baseTable = new ushort[512]; for (int i = 0; i < 256; ++i) { int e = i - 127; if (e < -24) { // Very small numbers map to zero baseTable[i | 0x000] = 0x0000; baseTable[i | 0x100] = 0x8000; } else if (e < -14) { // Small numbers map to denorms baseTable[i | 0x000] = (ushort)(0x0400 >> (-e - 14)); baseTable[i | 0x100] = (ushort)((0x0400 >> (-e - 14)) | 0x8000); } else if (e <= 15) { // Normal numbers just lose precision baseTable[i | 0x000] = (ushort)((e + 15) << 10); baseTable[i | 0x100] = (ushort)(((e + 15) << 10) | 0x8000); } else if (e < 128) { // Large numbers map to Infinity baseTable[i | 0x000] = 0x7C00; baseTable[i | 0x100] = 0xFC00; } else { // Infinity and NaN's stay Infinity and NaN's baseTable[i | 0x000] = 0x7C00; baseTable[i | 0x100] = 0xFC00; } } return baseTable; //ushort[] baseTable = new ushort[512]; //for (int i = 0; i < 256; ++i) //{ // sbyte e = (sbyte)(127 - i); // if (e > 24) // { // Very small numbers map to zero // baseTable[i | 0x000] = 0x0000; // baseTable[i | 0x100] = 0x8000; // } // else if (e > 14) // { // Small numbers map to denorms // baseTable[i | 0x000] = (ushort)(0x0400 >> (18 + e)); // baseTable[i | 0x100] = (ushort)((0x0400 >> (18 + e)) | 0x8000); // } // else if (e >= -15) // { // Normal numbers just lose precision // baseTable[i | 0x000] = (ushort)((15 - e) << 10); // baseTable[i | 0x100] = (ushort)(((15 - e) << 10) | 0x8000); // } // else if (e > -128) // { // Large numbers map to Infinity // baseTable[i | 0x000] = 0x7c00; // baseTable[i | 0x100] = 0xfc00; // } // else // { // Infinity and NaN's stay Infinity and NaN's // baseTable[i | 0x000] = 0x7c00; // baseTable[i | 0x100] = 0xfc00; // } //} //return baseTable; } private static sbyte[] GenerateShiftTable() { sbyte[] shiftTable = new sbyte[512]; for (int i = 0; i < 256; ++i) { int e = i - 127; if (e < -24) { // Very small numbers map to zero shiftTable[i | 0x000] = 24; shiftTable[i | 0x100] = 24; } else if (e < -14) { // Small numbers map to denorms shiftTable[i | 0x000] = (sbyte)(-e - 1); shiftTable[i | 0x100] = (sbyte)(-e - 1); } else if (e <= 15) { // Normal numbers just lose precision shiftTable[i | 0x000] = 13; shiftTable[i | 0x100] = 13; } else if (e < 128) { // Large numbers map to Infinity shiftTable[i | 0x000] = 24; shiftTable[i | 0x100] = 24; } else { // Infinity and NaN's stay Infinity and NaN's shiftTable[i | 0x000] = 13; shiftTable[i | 0x100] = 13; } } return shiftTable; //sbyte[] shiftTable = new sbyte[512]; //for (int i = 0; i < 256; ++i) //{ // sbyte e = (sbyte)(127 - i); // if (e > 24) // { // Very small numbers map to zero // shiftTable[i | 0x000] = 24; // shiftTable[i | 0x100] = 24; // } // else if (e > 14) // { // Small numbers map to denorms // shiftTable[i | 0x000] = (sbyte)(e - 1); // shiftTable[i | 0x100] = (sbyte)(e - 1); // } // else if (e >= -15) // { // Normal numbers just lose precision // shiftTable[i | 0x000] = 13; // shiftTable[i | 0x100] = 13; // } // else if (e > -128) // { // Large numbers map to Infinity // shiftTable[i | 0x000] = 24; // shiftTable[i | 0x100] = 24; // } // else // { // Infinity and NaN's stay Infinity and NaN's // shiftTable[i | 0x000] = 13; // shiftTable[i | 0x100] = 13; // } //} //return shiftTable; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe float HalfToSingle(Half half) { uint result = mantissaTable[offsetTable[half.value >> 10] + (half.value & 0x3ff)] + exponentTable[half.value >> 10]; return *((float*)&result); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe Half SingleToHalf(float single) { uint value = *((uint*)&single); ushort result = (ushort)(baseTable[(value >> 23) & 0x1ff] + ((value & 0x007fffff) >> shiftTable[value >> 23])); return Half.ToHalf(result); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half Negate(Half half) => Half.ToHalf((ushort)(half.value ^ 0x8000)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half Abs(Half half) => Half.ToHalf((ushort)(half.value & 0x7fff)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(Half half) => ((half.value & 0x7fff) > 0x7c00); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(Half half) => ((half.value & 0x7fff) == 0x7c00); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(Half half) => (half.value == 0x7c00); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(Half half) => (half.value == 0xfc00); } #endregion Helper /// /// Represents a half-precision floating point number. /// [Serializable] public struct Half : IComparable, IFormattable, IConvertible, IComparable, IEquatable { /// /// Internal representation of the half-precision floating-point number. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] internal ushort value; #region Constants /// /// Represents a half value of zero. /// public static Half Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Half.ToHalf(0x0000); } /// /// Represents a half value of one. /// public static Half One { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Half.ToHalf(0x3c00); } /// /// Represents the smallest positive Half value greater than zero. /// public static Half Epsilon { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Half.ToHalf(0x0001); } /// /// Represents the largest possible value of Half. /// public static Half MaxValue { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Half.ToHalf(0x7bff); } /// /// Represents the smallest possible value of Half. /// public static Half MinValue { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Half.ToHalf(0xfbff); } /// /// Represents not a number (NaN). /// public static Half NaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Half.ToHalf(0xfe00); } /// /// Represents negative infinity. /// public static Half NegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Half.ToHalf(0xfc00); } /// /// Represents positive infinity. /// public static Half PositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Half.ToHalf(0x7c00); } #endregion #region Constructors /// /// Initializes a new instance of Half to the value of the specified single-precision floating-point number. /// /// The value to represent as a Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Half(float value) { this = HalfHelper.SingleToHalf(value); } /// /// Initializes a new instance of Half to the value of the specified 32-bit signed integer. /// /// The value to represent as a Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Half(int value) : this((float)value) { } /// /// Initializes a new instance of Half to the value of the specified 64-bit signed integer. /// /// The value to represent as a Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Half(long value) : this((float)value) { } /// /// Initializes a new instance of Half to the value of the specified double-precision floating-point number. /// /// The value to represent as a Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Half(double value) : this((float)value) { } /// /// Initializes a new instance of Half to the value of the specified decimal number. /// /// The value to represent as a Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Half(decimal value) : this((float)value) { } /// /// Initializes a new instance of Half to the value of the specified 32-bit unsigned integer. /// /// The value to represent as a Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Half(uint value) : this((float)value) { } /// /// Initializes a new instance of Half to the value of the specified 64-bit unsigned integer. /// /// The value to represent as a Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Half(ulong value) : this((float)value) { } #endregion #region Numeric operators /// /// Returns the result of multiplying the specified Half value by negative one. /// /// A Half. /// A Half with the value of half, but the opposite sign. -or- Zero, if half is zero. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half Negate(Half half) { return -half; } /// /// Adds two specified Half values. /// /// A Half. /// A Half. /// A Half value that is the sum of half1 and half2. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half Add(Half half1, Half half2) { return half1 + half2; } /// /// Subtracts one specified Half value from another. /// /// A Half (the minuend). /// A Half (the subtrahend). /// The Half result of subtracting half2 from half1. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half Subtract(Half half1, Half half2) { return half1 - half2; } /// /// Multiplies two specified Half values. /// /// A Half (the multiplicand). /// A Half (the multiplier). /// A Half that is the result of multiplying half1 and half2. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half Multiply(Half half1, Half half2) { return half1 * half2; } /// /// Divides two specified Half values. /// /// A Half (the dividend). /// A Half (the divisor). /// The Half that is the result of dividing half1 by half2. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half Divide(Half half1, Half half2) { return half1 / half2; } /// /// Returns the value of the Half operand (the sign of the operand is unchanged). /// /// The Half operand. /// The value of the operand, half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half operator +(Half half) { return half; } /// /// Negates the value of the specified Half operand. /// /// The Half operand. /// The result of half multiplied by negative one (-1). [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half operator -(Half half) { return HalfHelper.Negate(half); } /// /// Increments the Half operand by 1. /// /// The Half operand. /// The value of half incremented by 1. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half operator ++(Half half) { return (Half)(half + 1f); } /// /// Decrements the Half operand by one. /// /// The Half operand. /// The value of half decremented by 1. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half operator --(Half half) { return (Half)(half - 1f); } /// /// Adds two specified Half values. /// /// A Half. /// A Half. /// The Half result of adding half1 and half2. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half operator +(Half half1, Half half2) { return (Half)((float)half1 + (float)half2); } /// /// Subtracts two specified Half values. /// /// A Half. /// A Half. /// The Half result of subtracting half1 and half2. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half operator -(Half half1, Half half2) { return (Half)((float)half1 - (float)half2); } /// /// Multiplies two specified Half values. /// /// A Half. /// A Half. /// The Half result of multiplying half1 by half2. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half operator *(Half half1, Half half2) { return (Half)((float)half1 * (float)half2); } /// /// Divides two specified Half values. /// /// A Half (the dividend). /// A Half (the divisor). /// The Half result of half1 by half2. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half operator /(Half half1, Half half2) { return (Half)((float)half1 / (float)half2); } /// /// Returns a value indicating whether two instances of Half are equal. /// /// A Half. /// A Half. /// true if half1 and half2 are equal; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Half half1, Half half2) { return (!IsNaN(half1) && (half1.value == half2.value)); } /// /// Returns a value indicating whether two instances of Half are not equal. /// /// A Half. /// A Half. /// true if half1 and half2 are not equal; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Half half1, Half half2) { return !(half1.value == half2.value); } /// /// Returns a value indicating whether a specified Half is less than another specified Half. /// /// A Half. /// A Half. /// true if half1 is less than half1; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator <(Half half1, Half half2) { return (float)half1 < (float)half2; } /// /// Returns a value indicating whether a specified Half is greater than another specified Half. /// /// A Half. /// A Half. /// true if half1 is greater than half2; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator >(Half half1, Half half2) { return (float)half1 > (float)half2; } /// /// Returns a value indicating whether a specified Half is less than or equal to another specified Half. /// /// A Half. /// A Half. /// true if half1 is less than or equal to half2; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator <=(Half half1, Half half2) { return (half1 == half2) || (half1 < half2); } /// /// Returns a value indicating whether a specified Half is greater than or equal to another specified Half. /// /// A Half. /// A Half. /// true if half1 is greater than or equal to half2; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator >=(Half half1, Half half2) { return (half1 == half2) || (half1 > half2); } #endregion #region Type casting operators /// /// Converts an 8-bit unsigned integer to a Half. /// /// An 8-bit unsigned integer. /// A Half that represents the converted 8-bit unsigned integer. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Half(byte value) { return new Half((float)value); } /// /// Converts a 16-bit signed integer to a Half. /// /// A 16-bit signed integer. /// A Half that represents the converted 16-bit signed integer. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Half(short value) { return new Half((float)value); } /// /// Converts a Unicode character to a Half. /// /// A Unicode character. /// A Half that represents the converted Unicode character. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Half(char value) { return new Half((float)value); } /// /// Converts a 32-bit signed integer to a Half. /// /// A 32-bit signed integer. /// A Half that represents the converted 32-bit signed integer. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Half(int value) { return new Half((float)value); } /// /// Converts a 64-bit signed integer to a Half. /// /// A 64-bit signed integer. /// A Half that represents the converted 64-bit signed integer. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Half(long value) { return new Half((float)value); } /// /// Converts a single-precision floating-point number to a Half. /// /// A single-precision floating-point number. /// A Half that represents the converted single-precision floating point number. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Half(float value) { return new Half((float)value); } /// /// Converts a double-precision floating-point number to a Half. /// /// A double-precision floating-point number. /// A Half that represents the converted double-precision floating point number. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Half(double value) { return new Half((float)value); } /// /// Converts a decimal number to a Half. /// /// decimal number /// A Half that represents the converted decimal number. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Half(decimal value) { return new Half((float)value); } /// /// Converts a Half to an 8-bit unsigned integer. /// /// A Half to convert. /// An 8-bit unsigned integer that represents the converted Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator byte(Half value) { return (byte)(float)value; } /// /// Converts a Half to a Unicode character. /// /// A Half to convert. /// A Unicode character that represents the converted Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator char(Half value) { return (char)(float)value; } /// /// Converts a Half to a 16-bit signed integer. /// /// A Half to convert. /// A 16-bit signed integer that represents the converted Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator short(Half value) { return (short)(float)value; } /// /// Converts a Half to a 32-bit signed integer. /// /// A Half to convert. /// A 32-bit signed integer that represents the converted Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int(Half value) { return (int)(float)value; } /// /// Converts a Half to a 64-bit signed integer. /// /// A Half to convert. /// A 64-bit signed integer that represents the converted Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long(Half value) { return (long)(float)value; } /// /// Converts a Half to a single-precision floating-point number. /// /// A Half to convert. /// A single-precision floating-point number that represents the converted Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator float(Half value) { return (float)HalfHelper.HalfToSingle(value); } /// /// Converts a Half to a double-precision floating-point number. /// /// A Half to convert. /// A double-precision floating-point number that represents the converted Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator double(Half value) { return (double)(float)value; } /// /// Converts a Half to a decimal number. /// /// A Half to convert. /// A decimal number that represents the converted Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator decimal(Half value) { return (decimal)(float)value; } /// /// Converts an 8-bit signed integer to a Half. /// /// An 8-bit signed integer. /// A Half that represents the converted 8-bit signed integer. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Half(sbyte value) { return new Half((float)value); } /// /// Converts a 16-bit unsigned integer to a Half. /// /// A 16-bit unsigned integer. /// A Half that represents the converted 16-bit unsigned integer. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Half(ushort value) { return new Half((float)value); } /// /// Converts a 32-bit unsigned integer to a Half. /// /// A 32-bit unsigned integer. /// A Half that represents the converted 32-bit unsigned integer. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Half(uint value) { return new Half((float)value); } /// /// Converts a 64-bit unsigned integer to a Half. /// /// A 64-bit unsigned integer. /// A Half that represents the converted 64-bit unsigned integer. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Half(ulong value) { return new Half((float)value); } /// /// Converts a Half to an 8-bit signed integer. /// /// A Half to convert. /// An 8-bit signed integer that represents the converted Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator sbyte(Half value) { return (sbyte)(float)value; } /// /// Converts a Half to a 16-bit unsigned integer. /// /// A Half to convert. /// A 16-bit unsigned integer that represents the converted Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ushort(Half value) { return (ushort)(float)value; } /// /// Converts a Half to a 32-bit unsigned integer. /// /// A Half to convert. /// A 32-bit unsigned integer that represents the converted Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint(Half value) { return (uint)(float)value; } /// /// Converts a Half to a 64-bit unsigned integer. /// /// A Half to convert. /// A 64-bit unsigned integer that represents the converted Half. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ulong(Half value) { return (ulong)(float)value; } #endregion #region Comparison /// /// Compares this instance to a specified Half object. /// /// A Half object. /// /// A signed number indicating the relative values of this instance and value. /// Return Value Meaning Less than zero This instance is less than value. Zero /// This instance is equal to value. Greater than zero This instance is greater than value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int CompareTo(Half other) { int result = 0; if (this < other) { result = -1; } else if (this > other) { result = 1; } else if (this != other) { if (!IsNaN(this)) { result = 1; } else if (!IsNaN(other)) { result = -1; } } return result; } /// /// Compares this instance to a specified System.Object. /// /// An System.Object or null. /// /// A signed number indicating the relative values of this instance and value. /// Return Value Meaning Less than zero This instance is less than value. Zero /// This instance is equal to value. Greater than zero This instance is greater /// than value. -or- value is null. /// /// value is not a Half [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int CompareTo(object obj) { int result; if (obj == null) { result = 1; } else { if (obj is Half half) { result = CompareTo(half); } else { throw new ArgumentException("Object must be of type Half."); } } return result; } /// /// Returns a value indicating whether this instance and a specified Half object represent the same value. /// /// A Half object to compare to this instance. /// true if value is equal to this instance; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Half other) { return ((other == this) || (IsNaN(other) && IsNaN(this))); } /// /// Returns a value indicating whether this instance and a specified System.Object /// represent the same type and value. /// /// An System.Object. /// true if value is a Half and equal to this instance; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object obj) { bool result = false; if (obj is Half half) { if ((half == this) || (IsNaN(half) && IsNaN(this))) { result = true; } } return result; } /// /// Returns the hash code for this instance. /// /// A 32-bit signed integer hash code. [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly int GetHashCode() => value.GetHashCode(); /// /// Returns the System.TypeCode for value type Half. /// /// The enumerated constant (TypeCode)255. [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly TypeCode GetTypeCode() => (TypeCode)255; #endregion #region BitConverter & Math methods for Half /// /// Returns the specified half-precision floating point value as an array of bytes. /// /// The number to convert. /// An array of bytes with length 2. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] GetBytes(Half value) => BitConverter.GetBytes(value.value); /// /// Converts the value of a specified instance of Half to its equivalent binary representation. /// /// A Half value. /// A 16-bit unsigned integer that contain the binary representation of value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort GetBits(Half value) => value.value; /// /// Returns a half-precision floating point number converted from two bytes /// at a specified position in a byte array. /// /// An array of bytes. /// The starting position within value. /// A half-precision floating point number formed by two bytes beginning at startIndex. /// /// startIndex is greater than or equal to the length of value minus 1, and is /// less than or equal to the length of value minus 1. /// /// value is null. /// startIndex is less than zero or greater than the length of value minus 1. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half ToHalf(byte[] value, int startIndex) => Half.ToHalf((ushort)BitConverter.ToInt16(value, startIndex)); /// /// Returns a half-precision floating point number converted from its binary representation. /// /// Binary representation of Half value /// A half-precision floating point number formed by its binary representation. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half ToHalf(ushort bits) => new Half { value = bits }; /// /// Returns a value indicating the sign of a half-precision floating-point number. /// /// A signed number. /// /// A number indicating the sign of value. Number Description -1 value is less /// than zero. 0 value is equal to zero. 1 value is greater than zero. /// /// value is equal to Half.NaN. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Sign(Half value) { if (value < 0) { return -1; } else if (value > 0) { return 1; } else { if (value != 0) { throw new ArithmeticException("Function does not accept floating point Not-a-Number values."); } } return 0; } /// /// Returns the absolute value of a half-precision floating-point number. /// /// A number in the range Half.MinValue ≤ value ≤ Half.MaxValue. /// A half-precision floating-point number, x, such that 0 ≤ x ≤Half.MaxValue. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half Abs(Half value) => HalfHelper.Abs(value); /// /// Returns the larger of two half-precision floating-point numbers. /// /// The first of two half-precision floating-point numbers to compare. /// The second of two half-precision floating-point numbers to compare. /// /// Parameter value1 or value2, whichever is larger. If value1, or value2, or both val1 /// and value2 are equal to Half.NaN, Half.NaN is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half Max(Half value1, Half value2) => (value1 < value2) ? value2 : value1; /// /// Returns the smaller of two half-precision floating-point numbers. /// /// The first of two half-precision floating-point numbers to compare. /// The second of two half-precision floating-point numbers to compare. /// /// Parameter value1 or value2, whichever is smaller. If value1, or value2, or both val1 /// and value2 are equal to Half.NaN, Half.NaN is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half Min(Half value1, Half value2) => (value1 < value2) ? value1 : value2; #endregion #region Special value checks /// /// Returns a value indicating whether the specified number evaluates to not a number (Half.NaN). /// /// A half-precision floating-point number. /// true if value evaluates to not a number (Half.NaN); otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(Half half) => HalfHelper.IsNaN(half); /// /// Returns a value indicating whether the specified number evaluates to negative or positive infinity. /// /// A half-precision floating-point number. /// true if half evaluates to Half.PositiveInfinity or Half.NegativeInfinity; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(Half half) => HalfHelper.IsInfinity(half); /// /// Returns a value indicating whether the specified number evaluates to negative infinity. /// /// A half-precision floating-point number. /// true if half evaluates to Half.NegativeInfinity; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(Half half) => HalfHelper.IsNegativeInfinity(half); /// /// Returns a value indicating whether the specified number evaluates to positive infinity. /// /// A half-precision floating-point number. /// true if half evaluates to Half.PositiveInfinity; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(Half half) => HalfHelper.IsPositiveInfinity(half); #endregion #region String operations (Parse and ToString) /// /// Converts the string representation of a number to its Half equivalent. /// /// The string representation of the number to convert. /// The Half number equivalent to the number contained in value. /// value is null. /// value is not in the correct format. /// value represents a number less than Half.MinValue or greater than Half.MaxValue. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half Parse(string value) => (Half)float.Parse(value, CultureInfo.InvariantCulture); /// /// Converts the string representation of a number to its Half equivalent /// using the specified culture-specific format information. /// /// The string representation of the number to convert. /// An System.IFormatProvider that supplies culture-specific parsing information about value. /// The Half number equivalent to the number contained in s as specified by provider. /// value is null. /// value is not in the correct format. /// value represents a number less than Half.MinValue or greater than Half.MaxValue. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half Parse(string value, IFormatProvider provider) =>(Half)float.Parse(value, provider); /// /// Converts the string representation of a number in a specified style to its Half equivalent. /// /// The string representation of the number to convert. /// /// A bitwise combination of System.Globalization.NumberStyles values that indicates /// the style elements that can be present in value. A typical value to specify is /// System.Globalization.NumberStyles.Number. /// /// The Half number equivalent to the number contained in s as specified by style. /// value is null. /// /// style is not a System.Globalization.NumberStyles value. -or- style is the /// System.Globalization.NumberStyles.AllowHexSpecifier value. /// /// value is not in the correct format. /// value represents a number less than Half.MinValue or greater than Half.MaxValue. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half Parse(string value, NumberStyles style) => (Half)float.Parse(value, style, CultureInfo.InvariantCulture); /// /// Converts the string representation of a number to its Half equivalent /// using the specified style and culture-specific format. /// /// The string representation of the number to convert. /// /// A bitwise combination of System.Globalization.NumberStyles values that indicates /// the style elements that can be present in value. A typical value to specify is /// System.Globalization.NumberStyles.Number. /// /// An System.IFormatProvider object that supplies culture-specific information about the format of value. /// The Half number equivalent to the number contained in s as specified by style and provider. /// value is null. /// /// style is not a System.Globalization.NumberStyles value. -or- style is the /// System.Globalization.NumberStyles.AllowHexSpecifier value. /// /// value is not in the correct format. /// value represents a number less than Half.MinValue or greater than Half.MaxValue. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half Parse(string value, NumberStyles style, IFormatProvider provider) => (Half)float.Parse(value, style, provider); /// /// Converts the string representation of a number to its Half equivalent. /// A return value indicates whether the conversion succeeded or failed. /// /// The string representation of the number to convert. /// /// When this method returns, contains the Half number that is equivalent /// to the numeric value contained in value, if the conversion succeeded, or is zero /// if the conversion failed. The conversion fails if the s parameter is null, /// is not a number in a valid format, or represents a number less than Half.MinValue /// or greater than Half.MaxValue. This parameter is passed uninitialized. /// /// true if s was converted successfully; otherwise, false. public static bool TryParse(string value, out Half result) { if (float.TryParse(value, out float f)) { result = (Half)f; return true; } result = new Half(); return false; } /// /// Converts the string representation of a number to its Half equivalent /// using the specified style and culture-specific format. A return value indicates /// whether the conversion succeeded or failed. /// /// The string representation of the number to convert. /// /// A bitwise combination of System.Globalization.NumberStyles values that indicates /// the permitted format of value. A typical value to specify is System.Globalization.NumberStyles.Number. /// /// An System.IFormatProvider object that supplies culture-specific parsing information about value. /// /// When this method returns, contains the Half number that is equivalent /// to the numeric value contained in value, if the conversion succeeded, or is zero /// if the conversion failed. The conversion fails if the s parameter is null, /// is not in a format compliant with style, or represents a number less than /// Half.MinValue or greater than Half.MaxValue. This parameter is passed uninitialized. /// /// true if s was converted successfully; otherwise, false. /// /// style is not a System.Globalization.NumberStyles value. -or- style /// is the System.Globalization.NumberStyles.AllowHexSpecifier value. /// public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out Half result) { bool parseResult = false; if (float.TryParse(value, style, provider, out float f)) { result = (Half)f; parseResult = true; } else { result = new Half(); } return parseResult; } /// /// Converts the numeric value of this instance to its equivalent string representation. /// /// A string that represents the value of this instance. [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() => ((float)this).ToString(CultureInfo.InvariantCulture); /// /// Converts the numeric value of this instance to its equivalent string representation /// using the specified culture-specific format information. /// /// An System.IFormatProvider that supplies culture-specific formatting information. /// The string representation of the value of this instance as specified by provider. [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly string ToString(IFormatProvider formatProvider) => ((float)this).ToString(formatProvider); /// /// Converts the numeric value of this instance to its equivalent string representation, using the specified format. /// /// A numeric format string. /// The string representation of the value of this instance as specified by format. [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly string ToString(string format) => ((float)this).ToString(format, CultureInfo.InvariantCulture); /// /// Converts the numeric value of this instance to its equivalent string representation /// using the specified format and culture-specific format information. /// /// A numeric format string. /// An System.IFormatProvider that supplies culture-specific formatting information. /// The string representation of the value of this instance as specified by format and provider. /// format is invalid. [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly string ToString(string format, IFormatProvider formatProvider) => ((float)this).ToString(format, formatProvider); #endregion #region IConvertible Members [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly float IConvertible.ToSingle(IFormatProvider provider) => (float)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly TypeCode IConvertible.GetTypeCode() => GetTypeCode(); [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly bool IConvertible.ToBoolean(IFormatProvider provider) => Convert.ToBoolean((float)this); [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly byte IConvertible.ToByte(IFormatProvider provider) => Convert.ToByte((float)this); [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly char IConvertible.ToChar(IFormatProvider provider) => throw new InvalidCastException(string.Format(CultureInfo.CurrentCulture, "Invalid cast from '{0}' to '{1}'.", "Half", "Char")); [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly DateTime IConvertible.ToDateTime(IFormatProvider provider) => throw new InvalidCastException(string.Format(CultureInfo.CurrentCulture, "Invalid cast from '{0}' to '{1}'.", "Half", "DateTime")); [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly decimal IConvertible.ToDecimal(IFormatProvider provider) => Convert.ToDecimal((float)this); [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly double IConvertible.ToDouble(IFormatProvider provider) => Convert.ToDouble((float)this); [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly short IConvertible.ToInt16(IFormatProvider provider) => Convert.ToInt16((float)this); [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly int IConvertible.ToInt32(IFormatProvider provider) => Convert.ToInt32((float)this); [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly long IConvertible.ToInt64(IFormatProvider provider) => Convert.ToInt64((float)this); [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly sbyte IConvertible.ToSByte(IFormatProvider provider) => Convert.ToSByte((float)this); [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly string IConvertible.ToString(IFormatProvider provider) => Convert.ToString((float)this, CultureInfo.InvariantCulture); [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly object IConvertible.ToType(Type conversionType, IFormatProvider provider) => (((float)this) as IConvertible).ToType(conversionType, provider); [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly ushort IConvertible.ToUInt16(IFormatProvider provider) => Convert.ToUInt16((float)this); [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly uint IConvertible.ToUInt32(IFormatProvider provider) => Convert.ToUInt32((float)this); [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly ulong IConvertible.ToUInt64(IFormatProvider provider) => Convert.ToUInt64((float)this); #endregion } } ================================================ FILE: src/Aardvark.Base/Math/Base/MedianWindow.cs ================================================ using Aardvark.Base.Sorting; using System; using System.Collections.Generic; namespace Aardvark.Base { /// /// Represents a moving median window of a sequence. /// It builds the median of the last N inserted values. /// public class MedianWindow { double m_median = 0; int m_write = -1; int m_count = 0; // for case when buffer is not fully filled readonly double[] m_buffer; readonly int[] m_indices; public MedianWindow(int count) { m_buffer = new double[count]; m_indices = new int[count].SetByIndex(i => i); } public double Insert(double value) { if (m_count < m_buffer.Length) m_count++; if (m_write > m_buffer.Length - 2) m_write = 0; else m_write++; m_buffer[m_write] = value; // NOTE: indices are still sorted from last insert m_indices.PermutationQuickSortAscending(m_buffer, 0, m_count); m_median = m_buffer[m_indices[m_count >> 1]]; return m_median; } /// /// Returns the history buffer. Contains zeroes if less elements than the window size have been inserted. /// public IReadOnlyList History { get { return m_buffer; } } public double Value { get { return m_median; } } /// /// Returns the last inserted valued. /// In case no value has been inserted yet, 0 is returned. /// public double Last { get { // in the case that last is queried before any insert return 0 if (m_write >= m_count) return 0; return m_buffer[m_write]; } } /// /// Resets the median window. /// public void Reset() { m_median = 0; m_write = -1; m_count = 0; m_indices.SetByIndex(i => i); } } } ================================================ FILE: src/Aardvark.Base/Math/Base/PhysicsConsts.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Aardvark.Base { public static class PhysicsConstant { /// /// Age of universe in years. /// public const double AgeOfUniverse = 13.73e9; public const double AgeOfUniverseRelativeStandardUncertainty = 8.8e-3; /// /// Angular velocity of the earth in radians/s. /// public const double AngularVelocityOfEarth = 7.2921159e-5; /// /// Astronomical unit in m. /// public const double AstronomicalUnit = 1.4959787066e11; public const double AstronomicalUnitRelativeStandardUncertainty = 2.0e-11; /// /// Astronomical unit in m. /// public const double au = AstronomicalUnit; /// /// Atomic mass unit in kg. /// public const double AtomicMassUnit = 1.66053886e-27; public const double AtomicMassUnitRelativeStandardUncertainty = 1.7e-7; /// /// Avogadro constant in mol^-1. /// public const double AvogadroConstant = 6.0221415e23; public const double AvogadroConstantRelativeStandardUncertainty = 1.7e-7; /// /// Bohr magneton in J/T. /// public const double BohrMagneton = 927.400915e-26; public const double BohrMagnetonRelativeStandardUncertainty = 2.5e-8; /// /// Bohr radius in m. /// public const double BohrRadius = 5.291772108e-11; public const double BohrRadiusRelativeStandardUncertainty = 3.3e-9; /// /// Boltzmann constant k in J/K. /// public const double BoltzmannConstant = 1.3806504e-23; public const double BoltzmannConstantRelativeStandardUncertainty = 1.8e-6; /// /// Boltzmann constant k in J/K. /// public const double k = BoltzmannConstant; /// /// Classical electron radius r_e in m. /// public const double ClassicalElectronRadius = 2.8179402894e-15; public const double ClassicalElectronRadiusRelativeStandardUncertainty = 2.1e-9; /// /// Conductance quantum in S. /// public const double ConductanceQuantum = 7.7480917004e-5; public const double ConductanceQuantumRelativeStandardUncertainty = 6.8e-10; /// /// Coulomb's constant in N * m^2 * C^-2. This is a defined value /// with no uncertainty. /// public const double CoulombsConstant = 1.0 / (4.0 * Constant.Pi * epsilon0); /// /// Earth mass in kg. /// public const double EarthMass = 5.9737076e24; /// /// Earth equatorial radius in m. /// public const double EarthRadiusEquatorial = 6.378140e6; /// /// Electron rest mass in kg. /// public const double ElectronRestMass = 9.10938215e-31; public const double ElectronRestMassRelativeStandardUncertainty = 5.0e-8; /// /// Elementary charge e in coulomb. /// public const double ElementaryCharge = 1.602176487e-19; public const double ElementaryChargeRelativeStandardUncertainty = 2.5e-8; /// /// Faraday constant in C/mol. /// public const double FaradayConstant = 96485.3383; public const double FaradayConstantRelativeStandardUncertainty = 8.6e-8; /// /// Fine structure constant (dimensionless). /// public const double FineStructureConstant = 7.2973525376e-3; public const double FineStructureConstantRelativeStandardUncertainty = 6.8e-10; /// /// Newtonian constant of gravitation G in m^3/(kg s^2). /// public const double GravitationalConstant = 6.67428e-11; public const double GravitationalConstantRelativeStandardUncertainty = 1e-4; /// /// Newtonian constant of gravitation G in m^3/(kg s^2). /// public const double G = GravitationalConstant; /// /// Ideal (molar) gas constant in J/(kg*mol). /// public const double IdealGasConstant = 8.314472; public const double IdealGasConstantRelativeStandardUncertainty = 1.7e-6; /// /// Neutron rest mass in kg. /// public const double NeutronRestMass = 1.6749286e-27; /// /// Planck constant h in Js. /// public const double PlanckConstant = 6.62606896e-34; public const double PlanckConstantRelativeStandardUncertainty = 5e-8; public const double ReducedPlanckConstant = PlanckConstant / Constant.PiTimesTwo; /// /// Planck constant h in Js. /// public const double h = PlanckConstant; /// /// Planck mass in kg. /// public const double PlanckMass = 2.17644e-8; public const double PlanckMassRelativeStandardUncertainty = 5.0e-5; /// /// Proton rest mass in kg. /// public const double ProtonRestMass = 1.672621637e-27; public const double ProtonRestMassRelativeStandardUncertainty = 5.0e-8; /// /// Rydberg constat in m^-1. /// public const double RydbergConstant = 10973731.568525; public const double RydbergConstantRelativeStandardUncertainty = 6.6e-12; /// /// Rydberg energy in eV. /// public const double RydbergEnergy = 13.605698140; /// /// Specific gas constant of dry air in J/(kg*K). /// public const double SpecificGasConstantOfDryAir = 287.05; /// /// Velocity of light in vacuum c in m/s. This is a defined value /// with no uncertainty. /// public const double SpeedOfLight = 299792458; /// /// Velocity of light in vacuum c in m/s. This is a defined value /// with no uncertainty. /// public const double c = SpeedOfLight; /// /// Standard acceleration of gravity g in m/s^2. This is a defined /// value with no uncertainty. /// public const double StandardAccelerationOfGravity = 9.80665; /// /// Standard acceleration of gravity g in m/s^2. This is a defined /// value with no uncertainty. /// public const double g = StandardAccelerationOfGravity; /// /// Standard atmosphere in Pa. This is a defined value with no /// uncertainty. /// public const double StandardAtmosphere = 101325; /// /// Standard atmosphere in Pa. This is a defined value with no /// uncertainty. /// public const double atm = StandardAtmosphere; /// /// Tropospheric temperature lapse rate in K/m. /// Source: http://www.iupac.org/goldbook/T06266.pdf /// public const double TroposphericTemperatureLapseRate = 0.0065; /// /// The characteristic impedance of vacuum in Ohm. This is a /// defined value with no uncertainty. /// public const double VacuumImpedance = my0 * c; /// /// The characteristic impedance of vacuum in Ohm. This is a /// defined value with no uncertainty. /// public const double Z0 = VacuumImpedance; /// /// Vacuum Permittivity in (A^2 s^4)/(kg m^3). This is a defined /// value with no uncertainty. /// public const double VacuumPermittivity = 1.0 / (my0 * c * c); /// /// Vacuum Permittivity in (A^2 s^4)/(kg m^3). This is a defined /// value with no uncertainty. /// public const double epsilon0 = VacuumPermittivity; /// /// Vacuum Permeability in N/A^2. This is a defined value with no /// uncertainty. /// public const double VacuumPermeability = 4.0E-7 * Constant.Pi; /// /// Vacuum Permeability in N/A^2. This is a defined value with no /// uncertainty. /// public const double my0 = VacuumPermeability; /// /// Molar mass of dry air in kg/mol. /// Source: http://en.wikipedia.org/wiki/Density_of_air /// public const double MolarMassOfDryAir = 0.0289644; /// /// Day, mean sidereal. /// public static readonly TimeSpan DayMeanSidereal = new TimeSpan(0, 23, 56, 4, 090); /// /// Light year in m. /// public const double LightYear = 9460730472580800.0; /// /// Parsec (au/arcsec) in m. /// public const double Parsec = 3.08567758074e16; /// /// Parsec (au/arcsec) in m. /// public const double pc = Parsec; /// /// Schwarzschild radius of Sun in m. /// public const double SchwarzschildRadiusOfSun = 2953.25008; /// /// Strong coupling constant. /// public const double StrongCouplingConstant = 0.1183; /// /// Sun distance from Core in m. /// public const double SunDistanceFromCore = 8.05 * Parsec; /// /// Sun luminosity in W. /// public const double SunLuminosity = 3.846e26; /// /// Sun mass in kg. /// public const double SunMass = 1.9889225e30; /// /// Sun radius (equatorial) in m. /// public const double SunRadiusEquatorial = 6.96e8; /// /// Sun speed around Core in m/s. /// public const double SunSpeedAroundCore = 22020000; /// /// Sun speed to cosmic background in m/s. /// public const double SunSpeedToCosmicBackground = 369500; /// /// Year, sideral (fixed star to fixed star, 1994) in s. /// public const double YearSideral = 31558149.8; /// /// Year, tropical (equinox to equinox, 1994) in s. /// public const double YearTropical = 31556925.2; /// /// Angstrom in m. /// public const double Angstrom = 10e-10; /// /// Electronvolt eV in J. /// public const double ElectronvoltInJoule = 1.60217733e-19; /// /// Nautical mile in m. /// public const double NauticalMile = 1852; /// /// Minute in seconds. /// public const double Minute = 60; /// /// Hour in seconds. /// public const double Hour = 60 * Minute; /// /// Day in seconds. /// public const double Day = 24 * Hour; /// /// Knot (1 nautical mile per hour) in m/s. /// public const double Knot = NauticalMile / Hour; /// /// Are in m^2. /// public const double Are = 100; /// /// Hectare in m^2. /// public const double Hectare = 10000; /// /// Barn in m^2. /// public const double Barn = 1e-28; /// /// Bar in Pa. /// public const double Bar = 10e5; /// /// Gal in m/s^2. /// public const double Gal = 10e-2; /// /// Curie Ci in Bq. /// public const double Curie = 3.7e10; /// /// Roentgen R in C/kg. /// public const double Roentgen = 2.58e-4; } } ================================================ FILE: src/Aardvark.Base/Math/Base/Quaternion_auto.cs ================================================ using System; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { // AUTOGENERATED CODE - DO NOT CHANGE! #region QuaternionF /// /// Struct for general quaternions, for rotations in 3-dimensional space use . /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct QuaternionF : IEquatable { /// /// Scalar (real) part of the quaternion. /// [DataMember] public float W; /// /// First component of vector (imaginary) part of the quaternion. /// [DataMember] public float X; /// /// Second component of vector (imaginary) part of the quaternion. /// [DataMember] public float Y; /// /// Third component of vector (imaginary) part of the quaternion. /// [DataMember] public float Z; #region Constructors /// /// Creates a (a, (a, a, a)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionF(float a) { W = a; X = a; Y = a; Z = a; } /// /// Creates a (w, (x, y, z)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionF(float w, float x, float y, float z) { W = w; X = x; Y = y; Z = z; } /// /// Creates a (v.x, (v.y, v.z, v.w)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionF(V4f v) { W = v.X; X = v.Y; Y = v.Z; Z = v.W; } /// /// Creates a (w, (v.x, v.y, v.z)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionF(float w, V3f v) { W = w; X = v.X; Y = v.Y; Z = v.Z; } /// /// Creates a copy of the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionF(QuaternionF q) { W = q.W; X = q.X; Y = q.Y; Z = q.Z; } /// /// Creates a from the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionF(QuaternionD q) { W = (float)q.W; X = (float)q.X; Y = (float)q.Y; Z = (float)q.Z; } /// /// Creates a from the given transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionF(Rot3f r) { W = r.W; X = r.X; Y = r.Y; Z = r.Z; } /// /// Creates a from the given transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionF(Rot3d r) { W = (float)r.W; X = (float)r.X; Y = (float)r.Y; Z = (float)r.Z; } /// /// Creates a from an array. /// (w = a[0], (x = a[1], y = a[2], z = a[3])). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionF(float[] a) { W = a[0]; X = a[1]; Y = a[2]; Z = a[3]; } /// /// Creates a from an array starting at specified index. /// (w = a[start], (x = a[start+1], y = a[start+2], z = a[start+3])). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionF(float[] a, int start) { W = a[start]; X = a[start + 1]; Y = a[start + 2]; Z = a[start + 3]; } #endregion #region Properties /// /// Gets or sets the vector part (x, y, z) of this . /// [XmlIgnore] public V3f V { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3f(X, Y, Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value.X; Y = value.Y; Z = value.Z; } } /// /// Gets the squared norm (or squared length) of this . /// public readonly float NormSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => W * W + X * X + Y * Y + Z * Z; } /// /// Gets the norm (or length) of this . /// public readonly float Norm { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => NormSquared.Sqrt(); } /// /// Gets normalized (unit) quaternion from this /// public readonly QuaternionF Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var rs = new QuaternionF(this); rs.Normalize(); return rs; } } /// /// Gets the (multiplicative) inverse of this . /// The zero quaternion is returned, if this quaternion is zero. /// public readonly QuaternionF Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var rs = new QuaternionF(this); rs.Invert(); return rs; } } /// /// Gets the conjugate of this . /// For unit quaternions this is the same as its inverse. /// public readonly QuaternionF Conjugated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new QuaternionF(W, -V); } /// /// Gets if this is zero. /// public readonly bool IsZero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (W == 0) && (X == 0) && (Y == 0) && (Z == 0); } #endregion #region Constants /// /// Gets a with (0, (0, 0, 0)). /// public static QuaternionF Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new QuaternionF(0); } /// /// Gets a with (1, (0, 0, 0)). /// public static QuaternionF One { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new QuaternionF(1, 0, 0, 0); } /// /// Gets the identity with (1, (0, 0, 0)). /// public static QuaternionF Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new QuaternionF(1, 0, 0, 0); } /// /// Gets a with (0, (1, 0, 0)). /// public static QuaternionF I { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new QuaternionF(0, 1, 0, 0); } /// /// Gets a with (0, (0, 1, 0)). /// public static QuaternionF J { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new QuaternionF(0, 0, 1, 0); } /// /// Gets a with (0, (0, 0, 1)). /// public static QuaternionF K { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new QuaternionF(0, 0, 0, 1); } #endregion #region Arithmetic Operators /// /// Returns the component-wise negation of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator -(QuaternionF q) => new QuaternionF(-q.W, -q.X, -q.Y, -q.Z); /// /// Returns the sum of two . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator +(QuaternionF a, QuaternionF b) => new QuaternionF(a.W + b.W, a.X + b.X, a.Y + b.Y, a.Z + b.Z); /// /// Returns the sum of a and a real scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator +(QuaternionF q, float s) => new QuaternionF(q.W + s, q.X, q.Y, q.Z); /// /// Returns the sum of a real scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator +(float s, QuaternionF q) => new QuaternionF(q.W + s, q.X, q.Y, q.Z); /// /// Returns the difference between two . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator -(QuaternionF a, QuaternionF b) => new QuaternionF(a.W - b.W, a.X - b.X, a.Y - b.Y, a.Z - b.Z); /// /// Returns the difference between a and a real scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator -(QuaternionF q, float s) => new QuaternionF(q.W - s, q.X, q.Y, q.Z); /// /// Returns the difference between a real scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator -(float s, QuaternionF q) => new QuaternionF(s - q.W, -q.X, -q.Y, -q.Z); /// /// Returns the product of a and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator *(QuaternionF q, float s) => new QuaternionF(q.W * s, q.X * s, q.Y * s, q.Z * s); /// /// Returns the product of a scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator *(float s, QuaternionF q) => new QuaternionF(q.W * s, q.X * s, q.Y * s, q.Z * s); /// /// Multiplies two . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator *(QuaternionF a, QuaternionF b) { return new QuaternionF( a.W * b.W - a.X * b.X - a.Y * b.Y - a.Z * b.Z, a.W * b.X + a.X * b.W + a.Y * b.Z - a.Z * b.Y, a.W * b.Y + a.Y * b.W + a.Z * b.X - a.X * b.Z, a.W * b.Z + a.Z * b.W + a.X * b.Y - a.Y * b.X); } /// /// Divides two . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator /(QuaternionF a, QuaternionF b) => a * b.Inverse; /// /// Divides a by a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator /(QuaternionF q, float s) => new QuaternionF(q.W / s, q.X / s, q.Y / s, q.Z / s); /// /// Divides a scalar by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator /(float s, QuaternionF q) => new QuaternionF(s / q.W, s / q.X, s / q.Y, s / q.Z); #endregion #region Comparison Operators /// /// Checks whether two are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(QuaternionF q0, QuaternionF q1) => q0.W == q1.W && q0.X == q1.X && q0.Y == q1.Y && q0.Z == q1.Z; /// /// Checks whether two are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(QuaternionF q0, QuaternionF q1) => q0.W != q1.W || q0.X != q1.X || q0.Y != q1.Y || q0.Z != q1.Z; #endregion #region Conversions /// /// Conversion from a to a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator QuaternionD(QuaternionF q) => new QuaternionD(q); /// /// Returns this as a 4x4 matrix. Quaternions are represented as matrices in such /// a way that quaternion multiplication and addition is equivalent to matrix multiplication and addition. /// Note that there are 48 distinct such matrix representations for a single quaternion. /// [Obsolete("Misleading conversion. Do you want a Rot3f to M44f conversion instead?")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44f(QuaternionF q) { return new M44f( q.W, -q.X, -q.Y, -q.Z, q.X, q.W, -q.Z, q.Y, q.Y, q.Z, q.W, -q.X, q.Z, -q.Y, q.X, q.W); } /// /// Returns this as a vector. /// Note that the components are ordered (w, x, y, z). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(QuaternionF q) => new V4f(q.W, q.X, q.Y, q.Z); /// /// Returns all values of a instance /// in a float[] array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](QuaternionF q) { float[] array = new float[4]; array[0] = q.W; array[1] = q.X; array[2] = q.Y; array[3] = q.Z; return array; } #endregion #region Indexing /// /// Gets or sets the -th component of the with components (w, (x, y, z)). /// public unsafe float this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &W) { return ptr[i]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &W) { ptr[i] = value; } } } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(W, X, Y, Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(QuaternionF other) => W.Equals(other.W) && X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z); public override readonly bool Equals(object other) => (other is QuaternionF o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}, {3}]", W, X, Y, Z); } public static QuaternionF Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new QuaternionF(float.Parse(x[0], CultureInfo.InvariantCulture), float.Parse(x[1], CultureInfo.InvariantCulture), float.Parse(x[2], CultureInfo.InvariantCulture), float.Parse(x[3], CultureInfo.InvariantCulture)); } #endregion } public static partial class Quaternion { #region Invert, Normalize, Conjugate, Dot /// /// Returns the inverse of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF Inverse(QuaternionF q) => q.Inverse; /// /// Inverts a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref QuaternionF q) { var norm = q.NormSquared; if (norm > 0) { var scale = 1 / norm; q.W *= scale; q.X *= -scale; q.Y *= -scale; q.Z *= -scale; } } /// /// Returns a normalized copy of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF Normalized(QuaternionF q) => q.Normalized; /// /// Normalizes a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref QuaternionF q) { var norm = q.Norm; if (norm > 0) { var scale = 1 / norm; q.W *= scale; q.X *= scale; q.Y *= scale; q.Z *= scale; } } /// /// Returns the conjugate of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF Conjugated(QuaternionF q) => q.Conjugated; /// /// Conjugates a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Conjugate(this ref QuaternionF q) { q.X = -q.X; q.Y = -q.Y; q.Z = -q.Z; } /// /// Returns the dot product of two . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot(this QuaternionF a, QuaternionF b) { return a.W * b.W + a.X * b.X + a.Y * b.Y + a.Z * b.Z; } #endregion #region Norm /// /// Gets the squared norm (or length) of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormSquared(QuaternionF q) => q.NormSquared; /// /// Gets the norm (or length) of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm(QuaternionF q) => q.Norm; #endregion #region Spherical Linear Interpolation /// /// Spherical linear interpolation. /// /// Assumes q1 and q2 are normalized and that t in [0,1]. /// /// This method interpolates along the shortest arc between q1 and q2. /// public static QuaternionF SlerpShortest(this QuaternionF q1, QuaternionF q2, float t) { QuaternionF q3 = q2; float cosomega = Dot(q1, q3); if (cosomega < 0) { cosomega = -cosomega; q3 = -q3; } if (cosomega >= 1) { // Special case: q1 and q2 are the same, so just return one of them. // This also catches the case where cosomega is very slightly > 1.0 return q1; } float sinomega = Fun.Sqrt(1 - cosomega * cosomega); QuaternionF result; if (sinomega * float.MaxValue > 1) { float omega = Fun.Acos(cosomega); float s1 = Fun.Sin((1 - t) * omega) / sinomega; float s2 = Fun.Sin(t * omega) / sinomega; result = new QuaternionF(s1 * q1 + s2 * q3); } else if (cosomega > 0) { // omega == 0 float s1 = 1 - t; float s2 = t; result = new QuaternionF(s1 * q1 + s2 * q3); } else { // omega == -pi result = new QuaternionF(q1.Z, -q1.Y, q1.X, -q1.W); float s1 = Fun.Sin((0.5f - t) * ConstantF.Pi); float s2 = Fun.Sin(t * ConstantF.Pi); result = new QuaternionF(s1 * q1 + s2 * result); } return result; } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this QuaternionF q0, QuaternionF q1) { return ApproximateEquals(q0, q1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this QuaternionF q0, QuaternionF q1, float tolerance) { return ApproximateEquals(q0.W, q1.W, tolerance) && ApproximateEquals(q0.X, q1.X, tolerance) && ApproximateEquals(q0.Y, q1.Y, tolerance) && ApproximateEquals(q0.Z, q1.Z, tolerance); } #endregion } #endregion #region QuaternionD /// /// Struct for general quaternions, for rotations in 3-dimensional space use . /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct QuaternionD : IEquatable { /// /// Scalar (real) part of the quaternion. /// [DataMember] public double W; /// /// First component of vector (imaginary) part of the quaternion. /// [DataMember] public double X; /// /// Second component of vector (imaginary) part of the quaternion. /// [DataMember] public double Y; /// /// Third component of vector (imaginary) part of the quaternion. /// [DataMember] public double Z; #region Constructors /// /// Creates a (a, (a, a, a)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionD(double a) { W = a; X = a; Y = a; Z = a; } /// /// Creates a (w, (x, y, z)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionD(double w, double x, double y, double z) { W = w; X = x; Y = y; Z = z; } /// /// Creates a (v.x, (v.y, v.z, v.w)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionD(V4d v) { W = v.X; X = v.Y; Y = v.Z; Z = v.W; } /// /// Creates a (w, (v.x, v.y, v.z)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionD(double w, V3d v) { W = w; X = v.X; Y = v.Y; Z = v.Z; } /// /// Creates a copy of the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionD(QuaternionD q) { W = q.W; X = q.X; Y = q.Y; Z = q.Z; } /// /// Creates a from the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionD(QuaternionF q) { W = (double)q.W; X = (double)q.X; Y = (double)q.Y; Z = (double)q.Z; } /// /// Creates a from the given transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionD(Rot3d r) { W = r.W; X = r.X; Y = r.Y; Z = r.Z; } /// /// Creates a from the given transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionD(Rot3f r) { W = (double)r.W; X = (double)r.X; Y = (double)r.Y; Z = (double)r.Z; } /// /// Creates a from an array. /// (w = a[0], (x = a[1], y = a[2], z = a[3])). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionD(double[] a) { W = a[0]; X = a[1]; Y = a[2]; Z = a[3]; } /// /// Creates a from an array starting at specified index. /// (w = a[start], (x = a[start+1], y = a[start+2], z = a[start+3])). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public QuaternionD(double[] a, int start) { W = a[start]; X = a[start + 1]; Y = a[start + 2]; Z = a[start + 3]; } #endregion #region Properties /// /// Gets or sets the vector part (x, y, z) of this . /// [XmlIgnore] public V3d V { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3d(X, Y, Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value.X; Y = value.Y; Z = value.Z; } } /// /// Gets the squared norm (or squared length) of this . /// public readonly double NormSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => W * W + X * X + Y * Y + Z * Z; } /// /// Gets the norm (or length) of this . /// public readonly double Norm { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => NormSquared.Sqrt(); } /// /// Gets normalized (unit) quaternion from this /// public readonly QuaternionD Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var rs = new QuaternionD(this); rs.Normalize(); return rs; } } /// /// Gets the (multiplicative) inverse of this . /// The zero quaternion is returned, if this quaternion is zero. /// public readonly QuaternionD Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var rs = new QuaternionD(this); rs.Invert(); return rs; } } /// /// Gets the conjugate of this . /// For unit quaternions this is the same as its inverse. /// public readonly QuaternionD Conjugated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new QuaternionD(W, -V); } /// /// Gets if this is zero. /// public readonly bool IsZero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (W == 0) && (X == 0) && (Y == 0) && (Z == 0); } #endregion #region Constants /// /// Gets a with (0, (0, 0, 0)). /// public static QuaternionD Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new QuaternionD(0); } /// /// Gets a with (1, (0, 0, 0)). /// public static QuaternionD One { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new QuaternionD(1, 0, 0, 0); } /// /// Gets the identity with (1, (0, 0, 0)). /// public static QuaternionD Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new QuaternionD(1, 0, 0, 0); } /// /// Gets a with (0, (1, 0, 0)). /// public static QuaternionD I { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new QuaternionD(0, 1, 0, 0); } /// /// Gets a with (0, (0, 1, 0)). /// public static QuaternionD J { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new QuaternionD(0, 0, 1, 0); } /// /// Gets a with (0, (0, 0, 1)). /// public static QuaternionD K { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new QuaternionD(0, 0, 0, 1); } #endregion #region Arithmetic Operators /// /// Returns the component-wise negation of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator -(QuaternionD q) => new QuaternionD(-q.W, -q.X, -q.Y, -q.Z); /// /// Returns the sum of two . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator +(QuaternionD a, QuaternionD b) => new QuaternionD(a.W + b.W, a.X + b.X, a.Y + b.Y, a.Z + b.Z); /// /// Returns the sum of a and a real scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator +(QuaternionD q, double s) => new QuaternionD(q.W + s, q.X, q.Y, q.Z); /// /// Returns the sum of a real scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator +(double s, QuaternionD q) => new QuaternionD(q.W + s, q.X, q.Y, q.Z); /// /// Returns the difference between two . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator -(QuaternionD a, QuaternionD b) => new QuaternionD(a.W - b.W, a.X - b.X, a.Y - b.Y, a.Z - b.Z); /// /// Returns the difference between a and a real scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator -(QuaternionD q, double s) => new QuaternionD(q.W - s, q.X, q.Y, q.Z); /// /// Returns the difference between a real scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator -(double s, QuaternionD q) => new QuaternionD(s - q.W, -q.X, -q.Y, -q.Z); /// /// Returns the product of a and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator *(QuaternionD q, double s) => new QuaternionD(q.W * s, q.X * s, q.Y * s, q.Z * s); /// /// Returns the product of a scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator *(double s, QuaternionD q) => new QuaternionD(q.W * s, q.X * s, q.Y * s, q.Z * s); /// /// Multiplies two . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator *(QuaternionD a, QuaternionD b) { return new QuaternionD( a.W * b.W - a.X * b.X - a.Y * b.Y - a.Z * b.Z, a.W * b.X + a.X * b.W + a.Y * b.Z - a.Z * b.Y, a.W * b.Y + a.Y * b.W + a.Z * b.X - a.X * b.Z, a.W * b.Z + a.Z * b.W + a.X * b.Y - a.Y * b.X); } /// /// Divides two . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator /(QuaternionD a, QuaternionD b) => a * b.Inverse; /// /// Divides a by a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator /(QuaternionD q, double s) => new QuaternionD(q.W / s, q.X / s, q.Y / s, q.Z / s); /// /// Divides a scalar by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator /(double s, QuaternionD q) => new QuaternionD(s / q.W, s / q.X, s / q.Y, s / q.Z); #endregion #region Comparison Operators /// /// Checks whether two are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(QuaternionD q0, QuaternionD q1) => q0.W == q1.W && q0.X == q1.X && q0.Y == q1.Y && q0.Z == q1.Z; /// /// Checks whether two are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(QuaternionD q0, QuaternionD q1) => q0.W != q1.W || q0.X != q1.X || q0.Y != q1.Y || q0.Z != q1.Z; #endregion #region Conversions /// /// Conversion from a to a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator QuaternionF(QuaternionD q) => new QuaternionF(q); /// /// Returns this as a 4x4 matrix. Quaternions are represented as matrices in such /// a way that quaternion multiplication and addition is equivalent to matrix multiplication and addition. /// Note that there are 48 distinct such matrix representations for a single quaternion. /// [Obsolete("Misleading conversion. Do you want a Rot3d to M44d conversion instead?")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44d(QuaternionD q) { return new M44d( q.W, -q.X, -q.Y, -q.Z, q.X, q.W, -q.Z, q.Y, q.Y, q.Z, q.W, -q.X, q.Z, -q.Y, q.X, q.W); } /// /// Returns this as a vector. /// Note that the components are ordered (w, x, y, z). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(QuaternionD q) => new V4d(q.W, q.X, q.Y, q.Z); /// /// Returns all values of a instance /// in a double[] array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](QuaternionD q) { double[] array = new double[4]; array[0] = q.W; array[1] = q.X; array[2] = q.Y; array[3] = q.Z; return array; } #endregion #region Indexing /// /// Gets or sets the -th component of the with components (w, (x, y, z)). /// public unsafe double this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &W) { return ptr[i]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &W) { ptr[i] = value; } } } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(W, X, Y, Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(QuaternionD other) => W.Equals(other.W) && X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z); public override readonly bool Equals(object other) => (other is QuaternionD o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}, {3}]", W, X, Y, Z); } public static QuaternionD Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new QuaternionD(double.Parse(x[0], CultureInfo.InvariantCulture), double.Parse(x[1], CultureInfo.InvariantCulture), double.Parse(x[2], CultureInfo.InvariantCulture), double.Parse(x[3], CultureInfo.InvariantCulture)); } #endregion } public static partial class Quaternion { #region Invert, Normalize, Conjugate, Dot /// /// Returns the inverse of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD Inverse(QuaternionD q) => q.Inverse; /// /// Inverts a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref QuaternionD q) { var norm = q.NormSquared; if (norm > 0) { var scale = 1 / norm; q.W *= scale; q.X *= -scale; q.Y *= -scale; q.Z *= -scale; } } /// /// Returns a normalized copy of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD Normalized(QuaternionD q) => q.Normalized; /// /// Normalizes a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref QuaternionD q) { var norm = q.Norm; if (norm > 0) { var scale = 1 / norm; q.W *= scale; q.X *= scale; q.Y *= scale; q.Z *= scale; } } /// /// Returns the conjugate of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD Conjugated(QuaternionD q) => q.Conjugated; /// /// Conjugates a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Conjugate(this ref QuaternionD q) { q.X = -q.X; q.Y = -q.Y; q.Z = -q.Z; } /// /// Returns the dot product of two . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Dot(this QuaternionD a, QuaternionD b) { return a.W * b.W + a.X * b.X + a.Y * b.Y + a.Z * b.Z; } #endregion #region Norm /// /// Gets the squared norm (or length) of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormSquared(QuaternionD q) => q.NormSquared; /// /// Gets the norm (or length) of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(QuaternionD q) => q.Norm; #endregion #region Spherical Linear Interpolation /// /// Spherical linear interpolation. /// /// Assumes q1 and q2 are normalized and that t in [0,1]. /// /// This method interpolates along the shortest arc between q1 and q2. /// public static QuaternionD SlerpShortest(this QuaternionD q1, QuaternionD q2, double t) { QuaternionD q3 = q2; double cosomega = Dot(q1, q3); if (cosomega < 0) { cosomega = -cosomega; q3 = -q3; } if (cosomega >= 1) { // Special case: q1 and q2 are the same, so just return one of them. // This also catches the case where cosomega is very slightly > 1.0 return q1; } double sinomega = Fun.Sqrt(1 - cosomega * cosomega); QuaternionD result; if (sinomega * double.MaxValue > 1) { double omega = Fun.Acos(cosomega); double s1 = Fun.Sin((1 - t) * omega) / sinomega; double s2 = Fun.Sin(t * omega) / sinomega; result = new QuaternionD(s1 * q1 + s2 * q3); } else if (cosomega > 0) { // omega == 0 double s1 = 1 - t; double s2 = t; result = new QuaternionD(s1 * q1 + s2 * q3); } else { // omega == -pi result = new QuaternionD(q1.Z, -q1.Y, q1.X, -q1.W); double s1 = Fun.Sin((0.5 - t) * Constant.Pi); double s2 = Fun.Sin(t * Constant.Pi); result = new QuaternionD(s1 * q1 + s2 * result); } return result; } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this QuaternionD q0, QuaternionD q1) { return ApproximateEquals(q0, q1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this QuaternionD q0, QuaternionD q1, double tolerance) { return ApproximateEquals(q0.W, q1.W, tolerance) && ApproximateEquals(q0.X, q1.X, tolerance) && ApproximateEquals(q0.Y, q1.Y, tolerance) && ApproximateEquals(q0.Z, q1.Z, tolerance); } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Base/Quaternion_template.cs ================================================ using System; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { // AUTOGENERATED CODE - DO NOT CHANGE! //# Action comma = () => Out(", "); //# Action commaln = () => Out("," + Environment.NewLine); //# Action add = () => Out(" + "); //# Action and = () => Out(" && "); //# Action or = () => Out(" || "); //# Action andLit = () => Out(" and "); //# var qfields = new[] {"W", "X", "Y", "Z"}; //# var qfieldsL = new[] {"w", "x", "y", "z"}; //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var tccaps = tc.ToUpper(); //# var tccaps2 = tc2.ToUpper(); //# var type = "Quaternion" + tccaps; //# var type2 = "Quaternion" + tccaps2; //# var v3t = "V3" + tc; //# var v4t = "V4" + tc; //# var m44t = "M44" + tc; //# var rot3t = "Rot3" + tc; //# var rot3t2 = "Rot3" + tc2; //# var getptr = "&" + qfields[0]; //# var half = isDouble ? "0.5" : "0.5f"; //# var pi = isDouble ? "Constant.Pi" : "ConstantF.Pi"; //# var piHalf = isDouble ? "Constant.PiHalf" : "ConstantF.PiHalf"; #region __type__ /// /// Struct for general quaternions, for rotations in 3-dimensional space use . /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__> { /// /// Scalar (real) part of the quaternion. /// [DataMember] public __ftype__ W; /// /// First component of vector (imaginary) part of the quaternion. /// [DataMember] public __ftype__ X; /// /// Second component of vector (imaginary) part of the quaternion. /// [DataMember] public __ftype__ Y; /// /// Third component of vector (imaginary) part of the quaternion. /// [DataMember] public __ftype__ Z; #region Constructors /// /// Creates a (a, (a, a, a)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__ a) { W = a; X = a; Y = a; Z = a; } /// /// Creates a (w, (x, y, z)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__ w, __ftype__ x, __ftype__ y, __ftype__ z) { W = w; X = x; Y = y; Z = z; } /// /// Creates a (v.x, (v.y, v.z, v.w)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__v4t__ v) { W = v.X; X = v.Y; Y = v.Z; Z = v.W; } /// /// Creates a (w, (v.x, v.y, v.z)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__ w, __v3t__ v) { W = w; X = v.X; Y = v.Y; Z = v.Z; } /// /// Creates a copy of the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ q) { /*# qfields.ForEach(f => {*/__f__ = q.__f__; /*# });*/ } /// /// Creates a from the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ q) { /*# qfields.ForEach(f => {*/__f__ = (__ftype__)q.__f__; /*# });*/ } /// /// Creates a from the given transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__rot3t__ r) { /*# qfields.ForEach(f => {*/__f__ = r.__f__; /*# });*/ } /// /// Creates a from the given transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__rot3t2__ r) { /*# qfields.ForEach(f => {*/__f__ = (__ftype__)r.__f__; /*# });*/ } /// /// Creates a from an array. /// (w = a[0], (x = a[1], y = a[2], z = a[3])). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__[] a) { W = a[0]; X = a[1]; Y = a[2]; Z = a[3]; } /// /// Creates a from an array starting at specified index. /// (w = a[start], (x = a[start+1], y = a[start+2], z = a[start+3])). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__[] a, int start) { W = a[start]; X = a[start + 1]; Y = a[start + 2]; Z = a[start + 3]; } #endregion #region Properties /// /// Gets or sets the vector part (x, y, z) of this . /// [XmlIgnore] public __v3t__ V { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new __v3t__(X, Y, Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value.X; Y = value.Y; Z = value.Z; } } /// /// Gets the squared norm (or squared length) of this . /// public readonly __ftype__ NormSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => /*# qfields.ForEach(f => {*/__f__ * __f__/*# }, add);*/; } /// /// Gets the norm (or length) of this . /// public readonly __ftype__ Norm { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => NormSquared.Sqrt(); } /// /// Gets normalized (unit) quaternion from this /// public readonly __type__ Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var rs = new __type__(this); rs.Normalize(); return rs; } } /// /// Gets the (multiplicative) inverse of this . /// The zero quaternion is returned, if this quaternion is zero. /// public readonly __type__ Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var rs = new __type__(this); rs.Invert(); return rs; } } /// /// Gets the conjugate of this . /// For unit quaternions this is the same as its inverse. /// public readonly __type__ Conjugated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(W, -V); } /// /// Gets if this is zero. /// public readonly bool IsZero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => /*# qfields.ForEach(f => {*/(__f__ == 0)/*# }, and);*/; } #endregion #region Constants /// /// Gets a with (0, (0, 0, 0)). /// public static __type__ Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(0); } /// /// Gets a with (1, (0, 0, 0)). /// public static __type__ One { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(1, 0, 0, 0); } /// /// Gets the identity with (1, (0, 0, 0)). /// public static __type__ Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(1, 0, 0, 0); } /// /// Gets a with (0, (1, 0, 0)). /// public static __type__ I { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(0, 1, 0, 0); } /// /// Gets a with (0, (0, 1, 0)). /// public static __type__ J { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(0, 0, 1, 0); } /// /// Gets a with (0, (0, 0, 1)). /// public static __type__ K { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(0, 0, 0, 1); } #endregion #region Arithmetic Operators /// /// Returns the component-wise negation of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator -(__type__ q) => new __type__(/*# qfields.ForEach(f => {*/-q.__f__/*# }, comma);*/); /// /// Returns the sum of two . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator +(__type__ a, __type__ b) => new __type__(/*# qfields.ForEach(f => {*/a.__f__ + b.__f__/*# }, comma);*/); /// /// Returns the sum of a and a real scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator +(__type__ q, __ftype__ s) => new __type__(q.W + s, q.X, q.Y, q.Z); /// /// Returns the sum of a real scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator +(__ftype__ s, __type__ q) => new __type__(q.W + s, q.X, q.Y, q.Z); /// /// Returns the difference between two . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator -(__type__ a, __type__ b) => new __type__(/*# qfields.ForEach(f => {*/a.__f__ - b.__f__/*# }, comma);*/); /// /// Returns the difference between a and a real scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator -(__type__ q, __ftype__ s) => new __type__(q.W - s, q.X, q.Y, q.Z); /// /// Returns the difference between a real scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator -(__ftype__ s, __type__ q) => new __type__(s - q.W, -q.X, -q.Y, -q.Z); /// /// Returns the product of a and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ q, __ftype__ s) => new __type__(/*# qfields.ForEach(f => {*/q.__f__ * s/*# }, comma);*/); /// /// Returns the product of a scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__ftype__ s, __type__ q) => new __type__(/*# qfields.ForEach(f => {*/q.__f__ * s/*# }, comma);*/); /// /// Multiplies two . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ a, __type__ b) { return new __type__( a.W * b.W - a.X * b.X - a.Y * b.Y - a.Z * b.Z, a.W * b.X + a.X * b.W + a.Y * b.Z - a.Z * b.Y, a.W * b.Y + a.Y * b.W + a.Z * b.X - a.X * b.Z, a.W * b.Z + a.Z * b.W + a.X * b.Y - a.Y * b.X); } /// /// Divides two . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator /(__type__ a, __type__ b) => a * b.Inverse; /// /// Divides a by a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator /(__type__ q, __ftype__ s) => new __type__(/*# qfields.ForEach(f => {*/q.__f__ / s/*# }, comma);*/); /// /// Divides a scalar by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator /(__ftype__ s, __type__ q) => new __type__(/*# qfields.ForEach(f => {*/s / q.__f__/*# }, comma);*/); #endregion #region Comparison Operators /// /// Checks whether two are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ q0, __type__ q1) => /*# qfields.ForEach(f => {*/q0.__f__ == q1.__f__/*# }, and);*/; /// /// Checks whether two are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ q0, __type__ q1) => /*# qfields.ForEach(f => {*/q0.__f__ != q1.__f__/*# }, or);*/; #endregion #region Conversions /// /// Conversion from a to a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type2__(__type__ q) => new __type2__(q); /// /// Returns this as a 4x4 matrix. Quaternions are represented as matrices in such /// a way that quaternion multiplication and addition is equivalent to matrix multiplication and addition. /// Note that there are 48 distinct such matrix representations for a single quaternion. /// [Obsolete("Misleading conversion. Do you want a Rot3__tc__ to __m44t__ conversion instead?")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __m44t__(__type__ q) { return new __m44t__( q.W, -q.X, -q.Y, -q.Z, q.X, q.W, -q.Z, q.Y, q.Y, q.Z, q.W, -q.X, q.Z, -q.Y, q.X, q.W); } /// /// Returns this as a vector. /// Note that the components are ordered (w, x, y, z). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __v4t__(__type__ q) => new __v4t__(/*# qfields.ForEach(f => {*/q.__f__/*# }, comma);*/); /// /// Returns all values of a instance /// in a __ftype__[] array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __ftype__[](__type__ q) { __ftype__[] array = new __ftype__[__qfields.Length__]; /*# qfields.ForEach((f, i) => {*/array[__i__] = q.__f__; /*# });*/return array; } #endregion #region Indexing /// /// Gets or sets the -th component of the with components (w, (x, y, z)). /// public unsafe __ftype__ this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (__ftype__* ptr = __getptr__) { return ptr[i]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (__ftype__* ptr = __getptr__) { ptr[i] = value; } } } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(W, X, Y, Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => /*# qfields.ForEach(f => {*/__f__.Equals(other.__f__)/*# }, and);*/; public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}, {3}]", W, X, Y, Z); } public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__(/*# 4.ForEach(i => {*/__ftype__.Parse(x[__i__], CultureInfo.InvariantCulture)/*# }, comma);*/); } #endregion } public static partial class Quaternion { #region Invert, Normalize, Conjugate, Dot /// /// Returns the inverse of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Inverse(__type__ q) => q.Inverse; /// /// Inverts a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref __type__ q) { var norm = q.NormSquared; if (norm > 0) { var scale = 1 / norm; q.W *= scale; q.X *= -scale; q.Y *= -scale; q.Z *= -scale; } } /// /// Returns a normalized copy of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Normalized(__type__ q) => q.Normalized; /// /// Normalizes a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref __type__ q) { var norm = q.Norm; if (norm > 0) { var scale = 1 / norm; q.W *= scale; q.X *= scale; q.Y *= scale; q.Z *= scale; } } /// /// Returns the conjugate of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Conjugated(__type__ q) => q.Conjugated; /// /// Conjugates a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Conjugate(this ref __type__ q) { q.X = -q.X; q.Y = -q.Y; q.Z = -q.Z; } /// /// Returns the dot product of two . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Dot(this __type__ a, __type__ b) { return a.W * b.W + a.X * b.X + a.Y * b.Y + a.Z * b.Z; } #endregion #region Norm /// /// Gets the squared norm (or length) of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ NormSquared(__type__ q) => q.NormSquared; /// /// Gets the norm (or length) of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Norm(__type__ q) => q.Norm; #endregion #region Spherical Linear Interpolation /// /// Spherical linear interpolation. /// /// Assumes q1 and q2 are normalized and that t in [0,1]. /// /// This method interpolates along the shortest arc between q1 and q2. /// public static __type__ SlerpShortest(this __type__ q1, __type__ q2, __ftype__ t) { __type__ q3 = q2; __ftype__ cosomega = Dot(q1, q3); if (cosomega < 0) { cosomega = -cosomega; q3 = -q3; } if (cosomega >= 1) { // Special case: q1 and q2 are the same, so just return one of them. // This also catches the case where cosomega is very slightly > 1.0 return q1; } __ftype__ sinomega = Fun.Sqrt(1 - cosomega * cosomega); __type__ result; if (sinomega * __ftype__.MaxValue > 1) { __ftype__ omega = Fun.Acos(cosomega); __ftype__ s1 = Fun.Sin((1 - t) * omega) / sinomega; __ftype__ s2 = Fun.Sin(t * omega) / sinomega; result = new __type__(s1 * q1 + s2 * q3); } else if (cosomega > 0) { // omega == 0 __ftype__ s1 = 1 - t; __ftype__ s2 = t; result = new __type__(s1 * q1 + s2 * q3); } else { // omega == -pi result = new __type__(q1.Z, -q1.Y, q1.X, -q1.W); __ftype__ s1 = Fun.Sin((__half__ - t) * __pi__); __ftype__ s2 = Fun.Sin(t * __pi__); result = new __type__(s1 * q1 + s2 * result); } return result; } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ q0, __type__ q1) { return ApproximateEquals(q0, q1, Constant<__ftype__>.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ q0, __type__ q1, __ftype__ tolerance) { return /*# qfields.ForEach(f => {*/ApproximateEquals(q0.__f__, q1.__f__, tolerance)/*# }, and);*/; } #endregion } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Math/Base/SampleGrid2d.cs ================================================ using System; namespace Aardvark.Base { public class SampleGrid2d { private V2l m_last; private Box2d m_region; private V2d m_delta; public SampleGrid2d(V2l gridSize, Box2d region) { m_last = gridSize - new V2l(1, 1); m_region = region; m_delta = region.Size / (V2d)m_last; } public static void AdaptivelyFill( Action xMid, Action yMid, Action xyMid, long x0, long x1, long y0, long y1 ) { var dx = x1 - x0; var dy = y1 - y0; if ((dx < 2) && (dy < 2)) return; long xm = 0, ym = 0; double wx0 = 0.0, wx1 = 0.0, wy0 = 0.0, wy1 = 0.0; if (dx > 1) { xm = (x1 + x0) / 2; wx1 = (xm - x0) / (double)dx; wx0 = (x1 - xm) / (double)dx; xMid(x0, x1, y0, xm, wx0, wx1); xMid(x0, x1, y1, xm, wx0, wx1); if (dy < 2) { AdaptivelyFill(xMid, yMid, xyMid, x0, xm, y0, y1); AdaptivelyFill(xMid, yMid, xyMid, xm, x1, y0, y1); return; } } if (dy > 1) { ym = (y1 + y0) / 2; wy1 = (ym - y0) / (double)dy; wy0 = (y1 - ym) / (double)dy; yMid(x0, y0, y1, ym, wy0, wy1); yMid(x1, y0, y1, ym, wy0, wy1); if (dx < 2) { AdaptivelyFill(xMid, yMid, xyMid, x0, x1, y0, ym); AdaptivelyFill(xMid, yMid, xyMid, x0, x1, ym, y1); return; } } if (dx > 1 && dy > 1) { xyMid(x0, x1, y0, y1, xm, ym, wx0, wx1, wy0, wy1); AdaptivelyFill(xMid, yMid, xyMid, x0, xm, y0, ym); AdaptivelyFill(xMid, yMid, xyMid, xm, x1, y0, ym); AdaptivelyFill(xMid, yMid, xyMid, x0, xm, ym, y1); AdaptivelyFill(xMid, yMid, xyMid, xm, x1, ym, y1); } } public static void AdaptivelyFill( Action xMid, Action yMid, Action xyMid, int depth, long x0, long x1, long y0, long y1 ) { var dx = x1 - x0; var dy = y1 - y0; if ((dx < 2) && (dy < 2)) return; long xm = 0, ym = 0; double wx0 = 0.0, wx1 = 0.0, wy0 = 0.0, wy1 = 0.0; if (dx > 1) { xm = (x1 + x0) / 2; wx1 = (xm - x0) / (double)dx; wx0 = (x1 - xm) / (double)dx; xMid(depth, x0, x1, y0, xm, wx0, wx1); xMid(depth, x0, x1, y1, xm, wx0, wx1); if (dy < 2) { AdaptivelyFill(xMid, yMid, xyMid, depth + 1, x0, xm, y0, y1); AdaptivelyFill(xMid, yMid, xyMid, depth + 1, xm, x1, y0, y1); return; } } if (dy > 1) { ym = (y1 + y0) / 2; wy1 = (ym - y0) / (double)dy; wy0 = (y1 - ym) / (double)dy; yMid(depth, x0, y0, y1, ym, wy0, wy1); yMid(depth, x1, y0, y1, ym, wy0, wy1); if (dx < 2) { AdaptivelyFill(xMid, yMid, xyMid, depth + 1, x0, x1, y0, ym); AdaptivelyFill(xMid, yMid, xyMid, depth + 1, x0, x1, ym, y1); return; } } if (dx > 1 && dy > 1) { xyMid(depth, x0, x1, y0, y1, xm, ym, wx0, wx1, wy0, wy1); AdaptivelyFill(xMid, yMid, xyMid, depth + 1, x0, xm, y0, ym); AdaptivelyFill(xMid, yMid, xyMid, depth + 1, xm, x1, y0, ym); AdaptivelyFill(xMid, yMid, xyMid, depth + 1, x0, xm, ym, y1); AdaptivelyFill(xMid, yMid, xyMid, depth + 1, xm, x1, ym, y1); } } public static void AdaptivelySample( Func similar, Action sample, Action region, Action super, long x0, long x1, long y0, long y1, double xd0, double xd1, double yd0, double yd1 ) { var dx = x1 - x0; var dy = y1 - y0; if ((dx < 2) && (dy < 2)) { super(x0, x1, y0, y1, xd0, xd1, yd0, yd1); return; } if (similar(x0, x1, y0, y1, xd0, xd1, yd0, yd1)) { region(x0, x1, y0, y1, xd0, xd1, yd0, yd1); return; } if (dx > 1) { var xm = (x1 + x0) / 2; var xdm = xd0 + (xd1 - xd0) * (xm - x0) / (double)dx; sample(xm, y0, xdm, yd0); sample(xm, y1, xdm, yd1); if (dy > 1) { var ym = (y1 + y0) / 2; var ydm = yd0 + (yd1 - yd0) * (ym - y0) / (double)dy; sample(x0, ym, xd0, ydm); sample(xm, ym, xdm, ydm); sample(x1, ym, xd1, ydm); AdaptivelySample(similar, sample, region, super, x0, xm, y0, ym, xd0, xdm, yd0, ydm); AdaptivelySample(similar, sample, region, super, xm, x1, y0, ym, xdm, xd1, yd0, ydm); AdaptivelySample(similar, sample, region, super, x0, xm, ym, y1, xd0, xdm, ydm, yd1); AdaptivelySample(similar, sample, region, super, xm, x1, ym, y1, xdm, xd1, ydm, yd1); } else { AdaptivelySample(similar, sample, region, super, x0, xm, y0, y1, xd0, xdm, yd0, yd1); AdaptivelySample(similar, sample, region, super, xm, x1, y0, y1, xdm, xd1, yd0, yd1); } } else { var ym = (y1 + y0) / 2; var ydm = yd0 + (yd1 - yd0) * (ym - y0) / (double)dy; sample(x0, ym, xd0, ydm); sample(x1, ym, xd1, ydm); AdaptivelySample(similar, sample, region, super, x0, x1, y0, ym, xd0, xd1, yd0, ydm); AdaptivelySample(similar, sample, region, super, x0, x1, ym, y1, xd0, xd1, ydm, yd1); } } public void Sample(V2l count, Action sample) { V2d step = (V2d)m_last / (V2d)count; double yd = 0.5; for (int yi = 0; yi <= m_last.Y; yd += step.Y, yi = (int)yd) { double y = m_region.Min.Y + yi * m_delta.Y; double xd = 0.5; for (int xi = 0; xi <= m_last.X; xd += step.X, xi = (int)xd) { double x = m_region.Min.X + xi * m_delta.X; sample(xi, yi, x, y); } } } public void Sample(V2l count, Action region) { V2d step = (V2d)m_last / (V2d)count; double y = m_region.Min.Y; double yd = 0.5 + step.Y; for (int yi = 0, nyi = (int)yd; yi < m_last.Y; yd += step.Y, yi = nyi, nyi = (int)yd) { double ny = m_region.Min.Y + nyi * m_delta.Y; double x = m_region.Min.X; double xd = 0.5 + step.X; for (int xi = 0, nxi = (int)xd; xi < m_last.X; xd += step.X, xi = nxi, nxi = (int)xd) { double nx = m_region.Min.X + nxi * m_delta.X; region(xi, nxi, yi, nyi, x, nx, y, ny); x = nx; } y = ny; } } /// /// Perform the supplied action on grid elements that are separated /// by a supplied step size. Only near the borders, the separation /// may be smaller. The (possibly) smaller border separation is /// distributed to all four borders. /// public void SampleRegular(V2l step, Action sample) { V2l regularLast = (m_last / step) * step; V2l offset = (m_last - regularLast) / 2; regularLast += offset; if (offset.Y > 0) { if (offset.X > 0) sample(0, 0, m_region.Min.X, m_region.Min.Y); for (long xi = offset.X; xi <= regularLast.X; xi += step.X) sample(xi, 0, m_region.Min.X + xi * m_delta.X, m_region.Min.Y); if (regularLast.X < m_last.X) sample(m_last.X, 0, m_region.Max.X, m_region.Min.Y); } for (long yi = offset.Y; yi <= regularLast.Y; yi += step.Y) { double y = m_region.Min.Y + yi * m_delta.Y; if (offset.X > 0) sample(0, yi, m_region.Min.X, y); for (long xi = offset.X; xi <= regularLast.X; xi += step.X) sample(xi, yi, m_region.Min.X + xi * m_delta.X, y); if (regularLast.X < m_last.X) sample(m_last.X, yi, m_region.Max.X, y); } if (regularLast.Y < m_last.Y) { if (offset.X > 0) sample(0, m_last.Y, m_region.Min.X, m_region.Max.Y); for (long xi = offset.X; xi <= regularLast.X; xi += step.X) sample(xi, m_last.Y, m_region.Min.X + xi * m_delta.X, m_region.Max.Y); if (regularLast.X < m_last.X) sample(m_last.X, m_last.Y, m_region.Max.X, m_region.Max.Y); } } /// /// Perform the supplied action on grid regions of a supplied step /// size. Only near the borders, the regions may be smaller. The /// (possibly) smaller border region size is distributed to all four /// borders. /// public void SampleRegular(V2l step, Action region) { V2l regularLast = (m_last / step) * step; V2l offset = (m_last - regularLast) / 2; regularLast += offset; if (offset.Y > 0) { double maxY = m_region.Min.Y + offset.Y * m_delta.Y; if (offset.X > 0) region(0, offset.X, 0, offset.Y, m_region.Min.X, m_region.Min.X + offset.X * m_delta.X, m_region.Min.Y, maxY); for (long xi = offset.X, nxi = xi + step.X; xi < regularLast.X; xi = nxi, nxi += step.X) region(xi, nxi, 0, offset.Y, m_region.Min.X + xi * m_delta.X, m_region.Min.X + nxi * m_delta.X, m_region.Min.Y, maxY); if (regularLast.X < m_last.X) region(regularLast.X, m_last.X, 0, offset.Y, m_region.Min.X + regularLast.X * m_delta.X, m_region.Min.X + m_last.X * m_delta.X, m_region.Min.Y, maxY); } for (long yi = offset.Y, nyi = yi + step.Y; yi < regularLast.Y; yi = nyi, nyi += step.Y) { double minY = m_region.Min.Y + yi * m_delta.Y; double maxY = minY + m_delta.Y; if (offset.X > 0) region(0, offset.X, yi, nyi, m_region.Min.X, m_region.Min.X + offset.X * m_delta.X, minY, maxY); for (long xi = offset.X, nxi = xi + step.X; xi < regularLast.X; xi = nxi, nxi += step.X) { region(xi, nxi, yi, nyi, m_region.Min.X + xi * m_delta.X, m_region.Min.X + nxi * m_delta.X, minY, maxY); } if (regularLast.X < m_last.X) region(regularLast.X, m_last.X, yi, nyi, m_region.Min.X + regularLast.X * m_delta.X, m_region.Min.X + m_last.X * m_delta.X, minY, maxY); } if (regularLast.Y < m_last.Y) { double minY = m_region.Min.Y + regularLast.Y * m_delta.Y; if (offset.X > 0) region(0, offset.X, regularLast.Y, m_last.Y, m_region.Min.X, m_region.Min.X + offset.X * m_delta.X, minY, m_region.Max.Y); for (long xi = offset.X, nxi = xi + step.X; xi < regularLast.X; xi = nxi, nxi += step.X) region(xi, xi + step.X, regularLast.Y, m_last.Y, m_region.Min.X + xi * m_delta.X, m_region.Min.X + nxi * m_delta.X, minY, m_region.Max.Y); if (regularLast.X < m_last.X) region(regularLast.X, m_last.X, regularLast.Y, m_last.Y, m_region.Min.X + regularLast.X * m_delta.X, m_region.Min.X + m_last.X * m_delta.X, minY, m_region.Max.Y); } } } } ================================================ FILE: src/Aardvark.Base/Math/Base/Statistics.cs ================================================ using System; using System.Collections.Generic; namespace Aardvark.Base { #region Extremum /// /// A structure that maintains the extreme Value and an associated Data field /// as each value/data pair is added. /// public struct Extremum { private double m_value; private T m_data; #region Constructor public Extremum(double value, T data) { m_value = value; m_data = data; } #endregion #region Constants public static readonly Extremum EmptyMin = new Extremum(Constant.ParseableMaxValue, default(T)); public static readonly Extremum EmptyMax = new Extremum(Constant.ParseableMinValue, default(T)); #endregion #region Properties public readonly double Value { get { return m_value; } } public readonly T Data { get { return m_data; } } #endregion #region Methods public void AddMin(double value) { if (value < m_value) { m_value = value; } } public void AddMax(double value) { if (value > m_value) { m_value = value; } } public void AddMin(double value, T data) { if (value < m_value) { m_value = value; m_data = data; } } public void AddMax(double value, T data) { if (value > m_value) { m_value = value; m_data = data; } } public static Extremum Max(Extremum e0, Extremum e1) { return e0.m_value >= e1.m_value ? e0 : e1; } public static Extremum Min(Extremum e0, Extremum e1) { return e0.m_value < e1.m_value ? e0 : e1; } #endregion } #endregion #region StatsOptions [Flags] public enum StatsOptions { Count = 0x0001, Sum = 0x0002, Mean = 0x0004, Min = 0x0010, Max = 0x0020, Range = 0x0030, Variance = 0x0100, StandardDeviation = 000200, NeedsSumOfSquares = 0x0300, All = 0x3fffffff, MaxMean = Max | Mean, MinMean = Min | Mean, RangeMean = Range | Mean, CountRange = Count | Range, } #endregion #region Stats /// /// A data structure for accumulating statistical moments. Currently only /// Count/Sum/Min/Max/Mean/Variance is implemented. Extend as necessary. /// public struct Stats : IReportable { long m_count; KahanSum m_sum; readonly StatsOptions m_options; Extremum m_min; Extremum m_max; KahanSum m_sumOfSquares; #region Constructor public Stats(StatsOptions options) { m_options = options; m_count = 0; m_min = Extremum.EmptyMin; m_max = Extremum.EmptyMax; m_sum = KahanSum.Zero; m_sumOfSquares = KahanSum.Zero; } #endregion #region Constants public static readonly Stats ComputeCountRange = new Stats(StatsOptions.Count | StatsOptions.Range); public static readonly Stats ComputeRange = new Stats(StatsOptions.Range); public static readonly Stats ComputeMinMean = new Stats(StatsOptions.Mean | StatsOptions.Min); public static readonly Stats ComputeMaxMean = new Stats(StatsOptions.Mean | StatsOptions.Max); public static readonly Stats ComputeRangeMean = new Stats(StatsOptions.Mean | StatsOptions.Range); public static readonly Stats ComputeCountMaxMean = new Stats(StatsOptions.Count | StatsOptions.Mean | StatsOptions.Max); public static readonly Stats ComputeCountRangeMean = new Stats(StatsOptions.Count | StatsOptions.Mean | StatsOptions.Range); public static readonly Stats ComputeAll = new Stats(StatsOptions.All); #endregion #region Properties public readonly long Count { get { return m_count; } } public readonly double Min { get { return m_min.Value; } } public readonly double Max { get { return m_max.Value; } } public readonly T MinData { get { return m_min.Data; } } public readonly T MaxData { get { return m_max.Data; } } public readonly double Sum { get { return m_sum.Value; } } public readonly double SumOfSquares { get { return m_sumOfSquares.Value; } } public readonly double Mean { get { return Sum / m_count; } } public readonly double Variance { get { return (SumOfSquares - Sum * Mean)/ m_count; } } public readonly double SampleVariance { get { return (SumOfSquares - Sum * Mean) / (m_count - 1); } } #endregion #region Methods public void Add(double value) { Add(value, default(T)); } public void Add(double value, T data) { ++m_count; m_sum.Add(value); if ((m_options & StatsOptions.Min) != 0) m_min.AddMin(value, data); if ((m_options & StatsOptions.Max) != 0) m_max.AddMax(value, data); if ((m_options & StatsOptions.NeedsSumOfSquares) != 0) m_sumOfSquares.Add(Fun.Square(value)); } public void Add(Stats s) { if (s.m_options != m_options) throw new ArgumentException("need matching options for adding"); m_count += s.m_count; m_sum.Add(s.m_sum); m_min = Extremum.Min(m_min, s.m_min); m_max = Extremum.Min(m_max, s.m_max); m_sumOfSquares.Add(s.m_sumOfSquares); } public static Stats operator+(Stats s0, Stats s1) { if (s0.m_options != s1.m_options) throw new ArgumentException("need matching options for adding"); return new Stats(s0.m_options) { m_count = s0.m_count + s1.m_count, m_sum = s0.m_sum + s1.m_sum, m_min = Extremum.Min(s0.m_min, s1.m_min), m_max = Extremum.Min(s0.m_max, s1.m_max), m_sumOfSquares = s0.m_sumOfSquares + s1.m_sumOfSquares, }; } #endregion #region IReportable Members public readonly void ReportValue(int verbosity, string name) { using (Report.Job(verbosity, name)) { if ((m_options & StatsOptions.Count) != 0) Report.Value(verbosity, "count", Count); if ((m_options & StatsOptions.Sum) != 0) Report.Value(verbosity, "sum", Sum); if ((m_options & StatsOptions.Min) != 0) Report.Value(verbosity, "minimum", Min); if ((m_options & StatsOptions.Max) != 0) Report.Value(verbosity, "maximum", Max); if ((m_options & StatsOptions.Mean) != 0) { Report.Value(verbosity, "mean", Mean); } if ((m_options & StatsOptions.NeedsSumOfSquares) != 0) { double variance = Variance; if ((m_options & StatsOptions.Variance) != 0) Report.Value(verbosity, "variance", variance); if ((m_options & StatsOptions.Variance) != 0) Report.Value(verbosity, "standard deviation", Fun.Sqrt(variance)); } } } #endregion } public class StatsClass { public Stats Value; } #endregion #region Histogram /// /// A data structure that maintains a histogram with a selectable number /// of slots. /// public struct Histogram : IReportable { private Range1d m_slotRange; private readonly double m_scale; private long m_small; private long m_large; private Range1d m_dataRange; private readonly long[] m_histo; #region Constructor public Histogram(double min, double max, int slotCount) : this(new Range1d(min, max), slotCount) { } public Histogram(Range1d range, int slotCount) { m_slotRange = range; m_scale = slotCount / (range.Max - range.Min); m_small = 0; m_large = 0; m_dataRange = Range1d.Invalid; m_histo = new long[slotCount]; } #endregion #region Properties public readonly Range1d DataRange { get { return m_dataRange; } } public readonly Range1d SlotRange { get { return m_slotRange; } } public readonly long SmallCount { get { return m_small; } } public readonly long LargeCount { get { return m_large; } } public readonly int SlotCount { get { return m_histo.Length; } } public readonly long this[int slot] { get { return m_histo[slot]; } } public readonly long[] Slots { get { return m_histo; } } #endregion #region Methods public void AddLog10(double value) { Add(Fun.Log10(value)); } public void AddLog2(double value) { Add(Fun.Log2(value)); } public void Add(double value) { m_dataRange.ExtendBy(value); if (value >= m_slotRange.Max) { ++m_large; return; } value -= m_slotRange.Min; if (value < 0.0) { ++m_small; return; } int slot = (int)(value * m_scale); if (slot >= m_histo.Length) slot = m_histo.Length - 1; m_histo[slot] += 1; } public void AddRange(IEnumerable values) { foreach (var v in values) Add(v); } public void Clear() { m_small = 0; m_large = 0; m_dataRange = Range1d.Invalid; m_histo.Set(0); } public void Add(Histogram h) { if (m_dataRange != h.m_dataRange) throw new ArgumentException("adding histograms requires identical data ranges"); if (m_scale != h.m_scale || m_histo.Length != h.m_histo.Length) throw new ArgumentException("adding histograms reuqires identical scales and slots"); m_small += h.m_small; m_large += h.m_large; for (int i = 0; i < m_histo.Length; i++) m_histo[i] += h.m_histo[i]; } public static Histogram operator +(Histogram h0, Histogram h1) { if (h0.m_dataRange != h1.m_dataRange) throw new ArgumentException("adding histograms requires identical data ranges"); if (h0.m_scale != h1.m_scale || h0.m_histo.Length != h1.m_histo.Length) throw new ArgumentException("adding histograms reuqires identical scales and slots"); var h = new Histogram(h0.m_dataRange, h0.SlotCount); h.m_small = h0.m_small + h1.m_small; h.m_large = h0.m_large + h1.m_large; for (int i = 0; i < h.m_histo.Length; i++) h.m_histo[i] = h0.m_histo[i] + h1.m_histo[i]; return h; } #endregion #region IReportable Members private static void ReportRange( int v, double min, double max, long count, bool outside) { string range = String.Format("[{0,9:g6} <= x < {1,-9:g6}]", min, max); if (outside) Report.Values(v, range, " ", count, "***"); else Report.Value(v, range, count); } public readonly void ReportValue(int v, string name) { using (Report.Job(v, "{0}:", name)) { if (m_small > 0) ReportRange(v, m_dataRange.Min, m_slotRange.Min, m_small, true); double min = m_slotRange.Min; double scale = (m_slotRange.Max - m_slotRange.Min) / (double)SlotCount; for (int s = 0; s < SlotCount; s++) { double max = m_slotRange.Min + (s + 1.0) * scale; ReportRange(v, min, max, m_histo[s], false); min = max; } if (m_large > 0) ReportRange(v, m_slotRange.Max, m_dataRange.Max, m_large, true); } } #endregion } public class HistogramClass { public Histogram Value; } #endregion #region HistogramAndStats public class HistogramAndStats { public Histogram Histogram; public Stats Stats; #region Constructors public HistogramAndStats(Histogram histogram, Stats stats) { Histogram = histogram; Stats = stats; } public HistogramAndStats(double min, double max, int steps, StatsOptions options) : this(new Histogram(min, max, steps), new Stats(options)) { } #endregion #region Operations public void AddLog10Hist(double value, T data) { Histogram.AddLog10(value); Stats.Add(value, data); } public void AddLog2Hist(double value, T data) { Histogram.AddLog2(value); Stats.Add(value, data); } public void Add(double value, T data) { Histogram.Add(value); Stats.Add(value, data); } public void Add(HistogramAndStats hs) { Histogram.Add(hs.Histogram); Stats.Add(hs.Stats); } public static HistogramAndStats operator +(HistogramAndStats hs0, HistogramAndStats hs1) { return new HistogramAndStats(hs0.Histogram + hs1.Histogram, hs0.Stats + hs1.Stats); } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Base/WeightedIndex.cs ================================================ namespace Aardvark.Base { /// /// A structure holding a double weight and an index. /// public struct WeightedIndex { public double Weight; public int Index; #region Constructor public WeightedIndex(double weight, int index) { Weight = weight; Index = index; } #endregion } } ================================================ FILE: src/Aardvark.Base/Math/Colors/Color.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Text.RegularExpressions; namespace Aardvark.Base { #region Col /// /// A static container class that provides functionality for dealing with /// colors. It is intentionally named Col in order to avoid a collision /// with the system provided Color class. /// [Serializable] public static partial class Col { #region Space [Serializable] public enum Space { None, SRGB, LinearSRGB, XYZ, } #endregion #region Format [Serializable] public enum Format { None, Alpha, BW, Gray, GrayAlpha, RGB, BGR, RGBA, BGRA, /// /// RGB with premultiplied alpha. /// RGBP, /// /// BGR with premultiplied alpha. /// BGRP, // TODO: CieXYZ, CieYxy, CieLab, CieLuv, Yuv, HSL, HSV, RG, } #endregion #region Channel [Serializable] public enum Channel { BW, Gray, Red, Green, Blue, Alpha, PremultipliedAlpha, // TODO: CieX, CieY, CieZ, Ciex, Ciey, Cieu, Ciev, CieL, Ciea, Cieb, L, H, S, V, Y, u, v, } #endregion #region Maximal Value Constants public static class Info { public static readonly T MaxValue; static Info() { if (typeof(T) == typeof(bool)) { MaxValue = (T)(object)true; } else if (typeof(T) == typeof(byte)) { MaxValue = (T)(object)(byte)255; } else if (typeof(T) == typeof(ushort)) { MaxValue = (T)(object)ushort.MaxValue; } else if (typeof(T) == typeof(uint)) { MaxValue = (T)(object)uint.MaxValue; } else if (typeof(T) == typeof(float)) { MaxValue = (T)(object)1.0f; } else if (typeof(T) == typeof(double)) { MaxValue = (T)(object)1.0; } } }; #endregion #region Table-Driven Query Methods public static class Name { public static readonly Symbol BW = "BW"; public static readonly Symbol Gray = "Gray"; public static readonly Symbol Alpha = "Alpha"; public static readonly Symbol GrayAlpha = "GrayAlpha"; public static readonly Symbol RG = "RG"; public static readonly Symbol RGB = "RGB"; public static readonly Symbol BGR = "BGR"; public static readonly Symbol RGBA = "RGBA"; public static readonly Symbol BGRA = "BGRA"; public static readonly Symbol RGBP = "RGBP"; public static readonly Symbol BGRP = "BGRP"; // TODO: public static readonly Symbol CieXYZ = "CieXYZ"; public static readonly Symbol CieYxy = "CieYxy"; public static readonly Symbol CieLab = "CieLab"; public static readonly Symbol CieLuv = "CieLuv"; public static readonly Symbol Yuv = "Yuv"; public static readonly Symbol HSL = "HSL"; public static readonly Symbol HSV = "HSV"; }; public static class Intent { public static readonly Symbol BW = "BW"; public static readonly Symbol Gray = "Gray"; public static readonly Symbol Alpha = "Alpha"; public static readonly Symbol GrayAlpha = "GrayAlpha"; public static readonly Symbol RG = "RG"; public static readonly Symbol RGB = "RGB"; public static readonly Symbol BGR = "BGR"; public static readonly Symbol RGBA = "RGBA"; public static readonly Symbol BGRA = "BGRA"; // TODO: public static readonly Symbol CieXYZ = "CieXYZ"; public static readonly Symbol CieYxy = "CieYxy"; public static readonly Symbol CieLab = "CieLab"; public static readonly Symbol CieLuv = "CieLuv"; public static readonly Symbol Yuv = "Yuv"; public static readonly Symbol HSL = "HSL"; public static readonly Symbol HSV = "HSV"; }; private static readonly (Col.Format, Symbol, Symbol, int)[] s_colFormatArray = new[] { (Format.BW, Name.BW, Intent.BW, 1), (Format.Gray, Name.Gray, Intent.Gray, 1), (Format.Alpha, Name.Alpha, Intent.Alpha, 1), (Format.GrayAlpha, Name.GrayAlpha, Intent.GrayAlpha, 2), (Format.RG, Name.RG, Intent.RG, 2), (Format.RGB, Name.RGB, Intent.RGB, 3), (Format.BGR, Name.BGR, Intent.BGR, 3), (Format.RGBA, Name.RGBA, Intent.RGBA, 4), (Format.BGRA, Name.BGRA, Intent.BGRA, 4), (Format.RGBP, Name.RGBP, Intent.RGBA, 4), (Format.BGRP, Name.BGRP, Intent.BGRA, 4), (Format.CieXYZ, Name.CieXYZ, Intent.CieXYZ, 3), (Format.CieYxy, Name.CieYxy, Intent.CieYxy, 3), (Format.CieLab, Name.CieLab, Intent.CieLab, 3), (Format.CieLuv, Name.CieLuv, Intent.CieLuv, 3), (Format.Yuv, Name.Yuv, Intent.Yuv, 3), (Format.HSL, Name.HSL, Intent.HSL, 3), (Format.HSV, Name.HSV, Intent.HSV, 3), }; static Col() { var count = s_colFormatArray.Length; s_nameOfFormat = new Dict(count); s_formatOfName = new SymbolDict(count); s_intentOfFormat = new Dict(count); s_channelCountMap = new Dict(count); foreach (var t in s_colFormatArray) { var format = t.Item1; var name = t.Item2; var intent = t.Item3; var channelCount = t.Item4; s_nameOfFormat.Add(format, intent); s_formatOfName.Add(name, format); s_intentOfFormat.Add(format, intent); s_channelCountMap.Add(format, channelCount); } } private static readonly Dict s_nameOfFormat = null; private static readonly SymbolDict s_formatOfName = null; private static readonly Dict s_intentOfFormat = null; private static readonly Dict s_channelCountMap = null; public static Symbol GetName(this Format format) { return s_nameOfFormat[format]; } public static Format FormatOfName(Symbol name) { return s_formatOfName[name]; } public static Symbol GetIntent(this Format format) { return s_intentOfFormat[format]; } public static bool IsPremultiplied(this Format format) { return format == Format.RGBP || format == Format.BGRP; } public static int ChannelCount(this Format format) { return s_channelCountMap[format]; } private static readonly Dict s_formatChannelsMap = new Dict() { { Format.BW, new[] { Channel.BW } }, { Format.Gray, new[] { Channel.Gray } }, { Format.Alpha, new[] { Channel.Alpha } }, { Format.GrayAlpha, new[] { Channel.Gray, Channel.Alpha } }, { Format.RG, new[] { Channel.Red, Channel.Green } }, { Format.RGB, new[] { Channel.Red, Channel.Green, Channel.Blue } }, { Format.BGR, new[] { Channel.Blue, Channel.Green, Channel.Red } }, { Format.RGBA, new[] { Channel.Red, Channel.Green, Channel.Blue, Channel.Alpha } }, { Format.BGRA, new[] { Channel.Blue, Channel.Green, Channel.Red, Channel.Alpha } }, { Format.RGBP, new[] { Channel.Red, Channel.Green, Channel.Blue, Channel.PremultipliedAlpha } }, { Format.BGRP, new[] { Channel.Blue, Channel.Green, Channel.Red, Channel.PremultipliedAlpha } }, { Format.CieXYZ, new[] { Channel.CieX, Channel.CieY, Channel.CieZ } }, { Format.CieYxy, new[] { Channel.CieY, Channel.Ciex, Channel.Ciey } }, { Format.CieLab, new[] { Channel.CieL, Channel.Ciea, Channel.Cieb } }, { Format.CieLuv, new[] { Channel.CieL, Channel.Cieu, Channel.Ciev } }, { Format.HSL, new[] { Channel.H, Channel.S, Channel.L } }, { Format.HSV, new[] { Channel.H, Channel.S, Channel.V } }, { Format.Yuv, new[] { Channel.Y, Channel.u, Channel.v } }, }; public static Channel[] ChannelsOfFormat(this Format format) { Channel[] channels; if (s_formatChannelsMap.TryGetValue(format, out channels)) return channels; throw new ArgumentException($"Channels of format {format} not defined."); } private static readonly Dict s_channelOrderMap = new Dict() { { Format.BW, new[] { 0L } }, { Format.Gray, new[] { 0L } }, { Format.Alpha, new[] { 0L } }, { Format.GrayAlpha, new[] { 0L, 1L } }, { Format.RG, new[] { 0L, 1L } }, { Format.RGB, new[] { 0L, 1L, 2L } }, { Format.BGR, new[] { 2L, 1L, 0L } }, { Format.RGBA, new[] { 0L, 1L, 2L, 3L } }, { Format.BGRA, new[] { 2L, 1L, 0L, 3L } }, { Format.RGBP, new[] { 0L, 1L, 2L, 3L } }, { Format.BGRP, new[] { 2L, 1L, 0L, 3L } }, { Format.CieXYZ, new[] { 0L, 1L, 2L } }, { Format.CieYxy, new[] { 0L, 1L, 2L } }, { Format.CieLab, new[] { 0L, 1L, 2L } }, { Format.CieLuv, new[] { 0L, 1L, 2L } }, { Format.HSL, new[] { 0L, 1L, 2L } }, { Format.HSV, new[] { 0L, 1L, 2L } }, { Format.Yuv, new[] { 0L, 1L, 2L } }, }; public static long[] ChannelOrder(this Format format) { return s_channelOrderMap[format]; } private static readonly Dict<(Format, Channel), long> s_channelIndexMap = new Dict<(Format, Channel), long>() { { (Format.BW, Channel.BW), 0L }, { (Format.Gray, Channel.Gray), 0L }, { (Format.Alpha, Channel.Alpha), 0L }, { (Format.GrayAlpha, Channel.Gray), 0L }, { (Format.GrayAlpha, Channel.Alpha), 1L }, { (Format.RG, Channel.Red), 0L }, { (Format.RG, Channel.Green), 1L }, { (Format.RGB, Channel.Red), 0L }, { (Format.RGB, Channel.Green), 1L }, { (Format.RGB, Channel.Blue), 2L }, { (Format.BGR, Channel.Blue), 0L }, { (Format.BGR, Channel.Green), 1L }, { (Format.BGR, Channel.Red), 2L }, { (Format.RGBA, Channel.Red), 0L }, { (Format.RGBA, Channel.Green), 1L }, { (Format.RGBA, Channel.Blue), 2L }, { (Format.RGBA, Channel.Alpha), 3L }, { (Format.BGRA, Channel.Blue), 0L }, { (Format.BGRA, Channel.Green), 1L }, { (Format.BGRA, Channel.Red), 2L }, { (Format.BGRA, Channel.Alpha), 3L }, { (Format.RGBP, Channel.Red), 0L }, { (Format.RGBP, Channel.Green), 1L }, { (Format.RGBP, Channel.Blue), 2L }, { (Format.RGBP, Channel.PremultipliedAlpha), 3L }, { (Format.BGRP, Channel.Blue), 0L }, { (Format.BGRP, Channel.Green), 1L }, { (Format.BGRP, Channel.Red), 2L }, { (Format.BGRP, Channel.PremultipliedAlpha), 3L }, { (Format.CieXYZ, Channel.CieX), 0L }, { (Format.CieXYZ, Channel.CieY), 1L }, { (Format.CieXYZ, Channel.CieZ), 2L }, { (Format.CieYxy, Channel.CieY), 0L }, { (Format.CieYxy, Channel.Ciex), 1L }, { (Format.CieYxy, Channel.Ciey), 2L }, { (Format.CieLab, Channel.CieL), 0L }, { (Format.CieLab, Channel.Ciea), 1L }, { (Format.CieLab, Channel.Cieb), 2L }, { (Format.CieLuv, Channel.CieL), 0L }, { (Format.CieLuv, Channel.Cieu), 1L }, { (Format.CieLuv, Channel.Ciev), 2L }, { (Format.HSL, Channel.H), 0L }, { (Format.HSL, Channel.S), 1L }, { (Format.HSL, Channel.L), 2L }, { (Format.HSV, Channel.H), 0L }, { (Format.HSV, Channel.S), 1L }, { (Format.HSV, Channel.V), 2L }, { (Format.Yuv, Channel.Y), 0L }, { (Format.Yuv, Channel.u), 1L }, { (Format.Yuv, Channel.v), 2L }, }; public static long ChannelIndex(this Format format, Channel channel) { if (s_channelIndexMap.TryGetValue((format, channel), out long index)) return index; throw new ArgumentException($"Format {format} does not contain channel {channel}."); } public static long ChannelIndexNoThrow(this Format format, Channel channel) { long index; if (s_channelIndexMap.TryGetValue((format, channel), out index)) return index; return -1; } public static Format FormatDefaultOf(this Type type, long channelCount) { return channelCount switch { 1 => Format.Gray, 2 => Format.RG, 3 => (type == typeof(byte)) ? Format.BGR : Format.RGB, 4 => (type == typeof(byte)) ? Format.BGRA : Format.RGBA, _ => throw new ArgumentException($"No default format for {type} with {channelCount} channels"), }; } #endregion #region Color Channel Conversion Constants private const float c_floatToByte = 255.9999f; private const float c_byteToFloat = 1.0f / 255.0f; private const double c_doubleToByte = 255.9999999999999; private const double c_byteToDouble = 1.0 / 255.0; private const float c_floatToUShort = 65535.99f; private const float c_uShortToFloat = 1.0f / 65535.0f; private const double c_doubleToUShort = 65535.99999999999; private const double c_uShortToDouble = 1.0 / 65535.0; private const double c_floatToUIntAsDouble = 4294967295.999999; private const double c_uIntToFloatAsDouble = 1.0 / 4294967295.0; private const double c_doubleToUInt = 4294967295.999999; private const double c_uIntToDouble = 1.0 / 4294967295.0; #endregion #region Color Channel Conversions between Byte, UShort, UInt, float, and double #region Byte [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort ByteToUShort(this byte b) => (ushort)(257 * b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ByteToUInt(this byte b) => 0x1010101u * (uint)b; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half ByteToHalf(this byte b) => (Half)(c_byteToFloat * (float)b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ByteToFloat(this byte b) => c_byteToFloat * (float)b; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ByteToDouble(this byte b) => c_byteToDouble * (double)b; #endregion #region UShort [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte UShortToByte(this ushort us) => (byte)(us >> 8); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint UShortToUInt(this ushort us) => 65537u * (uint)us; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half UShortToHalf(this ushort us) => (Half)(c_uShortToFloat * (float)us); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float UShortToFloat(this ushort us) => c_uShortToFloat * (float)us; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double UShortToDouble(this ushort us) => c_uShortToDouble * (double)us; #endregion #region UInt [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte UIntToByte(this uint ui) => (byte)(ui >> 24); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort UIntToUShort(this uint ui) => (ushort)(ui >> 16); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half UIntToHalf(this uint ui) => (Half)(c_uIntToFloatAsDouble * ui); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float UIntToFloat(this uint ui) => (float)(c_uIntToFloatAsDouble * ui); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double UIntToDouble(this uint ui) => c_uIntToDouble * (double)ui; #endregion #region Half [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte HalfToByte(this Half f) => (byte)(c_floatToByte * f); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort HalfToUShort(this Half f) => (ushort)(c_floatToUShort * f); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint HalfToUInt(this Half f) => (uint)(c_floatToUIntAsDouble * f); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float HalfToFloat(this Half f) => (float)f; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double HalfToDouble(this Half f) => (double)f; #endregion #region Float [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte FloatToByte(this float f) => (byte)(c_floatToByte * f); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte FloatToByteClamped(this float f) => (byte)(c_floatToByte * f).Clamp(0, 255); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort FloatToUShort(this float f) => (ushort)(c_floatToUShort * f); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort FloatToUShortClamped(this float f) => (ushort)(c_floatToUShort * f).Clamp(0, 65535); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint FloatToUInt(this float f) => (uint)(c_floatToUIntAsDouble * f); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint FloatToUIntClamped(this float f) => (uint)(c_floatToUIntAsDouble * f).Clamp(0, 4294967295); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half FloatToHalf(this float f) => (Half)f; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double FloatToDouble(this float f) => (double)f; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double FloatToDoubleClamped(this float f) => ((double)f).Clamp(0, 1); #endregion #region Double [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte DoubleToByte(this double d) => (byte)(c_doubleToByte * d); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte DoubleToByteClamped(this double d) => (byte)(c_doubleToByte * d).Clamp(0, 255); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort DoubleToUShort(this double d) => (ushort)(c_doubleToUShort * d); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort DoubleToUShortClamped(this double d) => (ushort)(c_doubleToUShort * d).Clamp(0, 65535); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint DoubleToUInt(this double d) => (uint)(c_doubleToUInt * d); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint DoubleToUIntClamped(this double d) => (uint)(c_doubleToUInt * d).Clamp(0, 4294967295); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half DoubleToHalf(this double d) => (Half)d; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DoubleToFloat(this double d) => (float)d; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DoubleToFloatClamped(this double d) => ((float)d).Clamp(0, 1); #endregion #endregion #region Special Color Channel Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ByteInIntToFloat(this int i) { return (float)i * c_byteToFloat; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int FloatToByteInInt(this float f) { return (int)(f * c_floatToByte); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ByteInIntToDouble(this int i) { return (double)i * c_byteToDouble; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int DoubleToByteInInt(this double d) { return (int)(d * c_doubleToByte); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double UShortInIntToDouble(this int i) { return (double)i * c_uShortToDouble; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int DoubleToUShortInInt(this double d) { return (int)(d * c_doubleToUShort); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte BitInByteToByte(this byte b) { return (byte)(b * 255); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte ByteToBitInByte(this byte b) { return (byte)(b >> 7); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte ByteInFloatToByte(this float f) { return (byte)(f + 0.5f); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte ByteInDoubleToByte(this double d) { return (byte)(d + 0.5); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort UShortInFloatToUShort(this float f) { return (ushort)(f + 0.5f); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort UShortInDoubleToUShort(this double d) { return (ushort)(d + 0.5); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint UIntInDoubleToUInt(this double d) { return (uint)(d + 0.5); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int FloatToByteInIntClamped(this float f) { return (int)(f * c_floatToByte).Clamp(0, 255); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int DoubleToUShortInIntClamped(this double d) { return (int)(d * c_doubleToUShort).Clamp(0, 65535); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte ByteInFloatToByteClamped(this float f) { return (byte)(f.Clamp(0.0f, 255.0f) + 0.5f); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte ByteInDoubleToByteClamped(this double d) { return (byte)(d.Clamp(0.0, 255.0) + 0.5); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort UShortInFloatToUShortClamped(this float f) { return (ushort)(f.Clamp(0.0f, 65535.0f) + 0.5f); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort UShortInDoubleToUShortClamped(this double d) { return (ushort)(d.Clamp(0.0, 65535.0) + 0.5); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint UIntInDoubleToUIntClamped(this double d) { return (uint)(d.Clamp(0.0, (double)uint.MaxValue) + 0.5); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ByteInFloatToFloat(this float f) { return f * c_byteToFloat; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float FloatToByteInFloat(this float f) { return f * c_floatToByte; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ByteInDoubleToDouble(this double d) { return d * c_byteToDouble; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DoubleToByteInDouble(this double d) { return d * c_doubleToByte; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ByteInFloatToFloatClamped(this float f) { return f.ByteInFloatToFloat().Clamp(0, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float FloatToByteInFloatClamped(this float f) { return f.FloatToByteInFloat().Clamp(0, 255); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ByteInDoubleToDoubleClamped(this double d) { return d.ByteInDoubleToDouble().Clamp(0, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DoubleToByteInDoubleClamped(this double d) { return d.DoubleToByteInDouble().Clamp(0, 255); } #endregion #region Color to Gray Conversion Constants private const double c_grayDoubleRed = 0.2989; private const double c_grayDoubleGreen = 0.5870; private const double c_grayDoubleBlue = 0.1140; private const float c_grayFloatRed = (float)c_grayDoubleRed; private const float c_grayFloatGreen = (float)c_grayDoubleGreen; private const float c_grayFloatBlue = (float)c_grayDoubleBlue; // 65793 == 65536 * 255.99998/255 private const int c_grayByteRed = (int)(65793 * c_grayDoubleRed); private const int c_grayByteGreen = (int)(65793 * c_grayDoubleGreen); private const int c_grayByteBlue = (int)(65793 * c_grayDoubleBlue); // 4295032833 == 4294967296 * 65535.99999999999/65535 private const long c_grayUShortRed = (long)(4295032833L * c_grayDoubleRed); private const long c_grayUShortGreen = (long)(4295032833L * c_grayDoubleGreen); private const long c_grayUShortBlue = (long)(4295032833L * c_grayDoubleBlue); #endregion #region Color to Gray Conversions #region Byte [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte ToGrayByte(byte r, byte g, byte b) => (byte)((r * c_grayByteRed + g * c_grayByteGreen + b * c_grayByteBlue) >> 16); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte ToGrayByte(this C3b c) => ToGrayByte(c.R, c.G, c.B); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte ToGrayByte(this C4b c) => ToGrayByte(c.R, c.G, c.B); #endregion #region UShort [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort ToGrayUShort(ushort r, ushort g, ushort b) => (ushort)((r * c_grayUShortRed + g * c_grayUShortGreen + b * c_grayUShortBlue) >> 32); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort ToGrayUShort(this C3us c) => ToGrayUShort(c.R, c.G, c.B); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort ToGrayUShort(this C4us c) => ToGrayUShort(c.R, c.G, c.B); #endregion #region UInt [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ToGrayUInt(uint r, uint g, uint b) => DoubleToUInt(ToGrayDoubleClamped(UIntToDouble(r), UIntToDouble(g), UIntToDouble(b))); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ToGrayUInt(this C3ui c) => ToGrayUInt(c.R, c.G, c.B); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ToGrayUInt(this C4ui c) => ToGrayUInt(c.R, c.G, c.B); #endregion #region Half [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half ToGrayHalf(Half r, Half g, Half b) => (Half)ToGrayFloat(r, g, b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Half ToGrayHalfClamped(Half r, Half g, Half b) => (Half)ToGrayFloatClamped(r, g, b); #endregion #region Float [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ToGrayFloat(float r, float g, float b) => r * c_grayFloatRed + g * c_grayFloatGreen + b * c_grayFloatBlue; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ToGrayFloat(this C3f c) => ToGrayFloat(c.R, c.G, c.B); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ToGrayFloat(this C4f c) => ToGrayFloat(c.R, c.G, c.B); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ToGrayFloatClamped(float r, float g, float b) => ToGrayFloat(r, g, b).Clamp(0, 1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ToGrayFloatClamped(this C3f c) => ToGrayFloatClamped(c.R, c.G, c.B); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ToGrayFloatClamped(C4f c) => ToGrayFloatClamped(c.R, c.G, c.B); #endregion #region Double [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ToGrayDouble(double r, double g, double b) => r * c_grayDoubleRed + g * c_grayDoubleGreen + b * c_grayDoubleBlue; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ToGrayDouble(this C3d c) => ToGrayDouble(c.R, c.G, c.B); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ToGrayDouble(this C4d c) => ToGrayDouble(c.R, c.G, c.B); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ToGrayDoubleClamped(double r, double g, double b) => ToGrayDouble(r, g, b).Clamp(0, 1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ToGrayDoubleClamped(this C3d c) => ToGrayDoubleClamped(c.R, c.G, c.B); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ToGrayDoubleClamped(C4d c) => ToGrayDoubleClamped(c.R, c.G, c.B); #endregion #endregion #region Alpha to premultiplied Alpha and back [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b AlphaToPremultipliedAlpha(this C4b c) { var f = c_byteToDouble * (double)c.A; return new C4b((byte)(f * c.R), (byte)(f * c.G), (byte)(f * c.B), c.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b PremultipliedAlphaToAlpha(this C4b c) { if (c.A == 0) return new C4b(0, 0, 0, 0); var f = 1.0 / (c_byteToDouble * (double)c.A); return new C4b((byte)(f * c.R), (byte)(f * c.G), (byte)(f * c.B), c.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us AlphaToPremultipliedAlpha(this C4us c) { var f = c_uShortToDouble * (double)c.A; return new C4us((ushort)(f * c.R), (ushort)(f * c.G), (ushort)(f * c.B), c.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us PremultipliedAlphaToAlpha(this C4us c) { if (c.A == 0) return new C4us(0, 0, 0, 0); var f = 1.0 / (c_uShortToDouble * (double)c.A); return new C4us((ushort)(f * c.R), (ushort)(f * c.G), (ushort)(f * c.B), c.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui AlphaToPremultipliedAlpha(this C4ui c) { var f = c_uIntToDouble * (double)c.A; return new C4ui((uint)(f * c.R), (uint)(f * c.G), (uint)(f * c.B), c.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui PremultipliedAlphaToAlpha(this C4ui c) { if (c.A == 0) return new C4ui(0, 0, 0, 0); var f = 1.0 / (c_uIntToDouble * (double)c.A); return new C4ui((uint)(f * c.R), (uint)(f * c.G), (uint)(f * c.B), c.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f AlphaToPremultipliedAlpha(this C4f c) { return new C4f(c.R * c.A, c.G * c.A, c.B * c.A, c.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f PremultipliedAlphaToAlpha(this C4f c) { if (c.A == 0.0f) return new C4f(0.0f, 0.0f, 0.0f, 0.0f); return new C4f(c.R / c.A, c.G / c.A, c.B / c.A, c.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d AlphaToPremultipliedAlpha(this C4d c) { return new C4d(c.R * c.A, c.G * c.A, c.B * c.A, c.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d PremultipliedAlphaToAlpha(this C4d c) { if (c.A == 0.0) return new C4d(0.0, 0.0, 0.0, 0.0); return new C4d(c.R / c.A, c.G / c.A, c.B / c.A, c.A); } #endregion #region SRGB/Linear SRGB/CieXYZ/CieLab/CieYxy Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinearSRGBFloatToSRGBFloat(this float c) => (float)(c <= 0.0031308 ? c * 12.92 : 1.055 * Fun.Pow(c, 1.0 / 2.4) - 0.055); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float SRGBFloatToLinearSRGBFloat(this float c) => (float)(c <= 0.04045 ? c / 12.92 : Fun.Pow((c + 0.055) / 1.055, 2.4)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f LinearSRGBToSRGB(this C3f c) { return new C3f(c.R <= 0.0031308 ? c.R * 12.92 : 1.055 * Fun.Pow(c.R, 1.0 / 2.4) - 0.055, c.G <= 0.0031308 ? c.G * 12.92 : 1.055 * Fun.Pow(c.G, 1.0 / 2.4) - 0.055, c.B <= 0.0031308 ? c.B * 12.92 : 1.055 * Fun.Pow(c.B, 1.0 / 2.4) - 0.055); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f LinearSRGBAToSRGBA(this C4f c) { return new C4f(c.R <= 0.0031308 ? c.R * 12.92 : 1.055 * Fun.Pow(c.R, 1.0 / 2.4) - 0.055, c.G <= 0.0031308 ? c.G * 12.92 : 1.055 * Fun.Pow(c.G, 1.0 / 2.4) - 0.055, c.B <= 0.0031308 ? c.B * 12.92 : 1.055 * Fun.Pow(c.B, 1.0 / 2.4) - 0.055, c.A <= 0.0031308 ? c.A * 12.92 : 1.055 * Fun.Pow(c.A, 1.0 / 2.4) - 0.055); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f SRGBToLinearSRGB(this C3f c) { return new C3f(c.R <= 0.04045 ? c.R / 12.92 : Fun.Pow((c.R + 0.055) / 1.055, 2.4), c.G <= 0.04045 ? c.G / 12.92 : Fun.Pow((c.G + 0.055) / 1.055, 2.4), c.B <= 0.04045 ? c.B / 12.92 : Fun.Pow((c.B + 0.055) / 1.055, 2.4)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f SRGBAToLinearSRGBA(this C4f c) { return new C4f(c.R <= 0.04045 ? c.R / 12.92 : Fun.Pow((c.R + 0.055) / 1.055, 2.4), c.G <= 0.04045 ? c.G / 12.92 : Fun.Pow((c.G + 0.055) / 1.055, 2.4), c.B <= 0.04045 ? c.B / 12.92 : Fun.Pow((c.B + 0.055) / 1.055, 2.4), c.A <= 0.04045 ? c.A / 12.92 : Fun.Pow((c.A + 0.055) / 1.055, 2.4)); } /// /// Convert linear SRGB with channel values in the range [0.0, 1.0] to XYZ. /// SRGB white (1, 1, 1) is converted to XYZ white (0.9505, 1.0000, 1.0890) /// at D65 with unit luminance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f LinearSRGBToXYZinC3f(this C3f c) { return new C3f(0.4124 * c.R + 0.3576 * c.G + 0.1805 * c.B, 0.2126 * c.R + 0.7152 * c.G + 0.0722 * c.B, 0.0193 * c.R + 0.1192 * c.G + 0.9505 * c.B); } /// /// Convert XYZ to linear SRGB with channel values in the range [0.0, 1.0]. /// XYZ white (0.9505, 1.0000, 1.0890) at D65 with unit luminance is /// converted to SRGB white (1, 1, 1) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f XYZinC3fToLinearSRGB(this C3f c) { return new C3f(3.2406 * c.R - 1.5372 * c.G - 0.4986 * c.B, -0.9689 * c.R + 1.8758 * c.G + 0.0415 * c.B, 0.0557 * c.R - 0.2040 * c.G + 1.0570 * c.B); } /// /// Convert XYZ to CIE RGB with channel values in the range [0.0, 1.0]. /// XYZ white (1, 1, 1) is converted to (1, 1, 1). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f XYZinC3fToCIERGB(this C3f c) { return new C3f( 2.3706743 * c.R - 0.9000405 * c.G - 0.4706338 * c.B, -0.5138850 * c.R + 1.4253036 * c.G + 0.0885814 * c.B, 0.0052982 * c.R - 0.0146949 * c.G + 1.0093968 * c.B); } /// /// Convert SRGB with channel values in the range [0.0, 1.0] to XYZ. /// SRGB white (1, 1, 1) is converted to XYZ white (0.9505, 1.0000, 1.0890) /// at D65 with unit luminance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f SRGBToXYZinC3f(this C3f c) { return c.SRGBToLinearSRGB().LinearSRGBToXYZinC3f(); } /// /// Convert XYZ to SRGB with channel values in the range [0.0, 1.0]. /// XYZ white (0.9505, 1.0000, 1.0890) at D65 with unit luminance is /// converted to SRGB white (1, 1, 1) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f XYZinC3fToSRGB(this C3f c) { return c.XYZinC3fToLinearSRGB().LinearSRGBToSRGB(); } /// /// Convert linear SRGBA with channel values in the range [0.0, 1.0] to XYZA. /// SRGB white (1, 1, 1) is converted to XYZA white (0.9505, 1.0000, 1.0890) /// at D65 with unit luminance. The alpha value is simply copied. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f LinearSRGBAToXYZAinC4f(this C4f c) { return new C4f(0.4124 * c.R + 0.3576 * c.G + 0.1805 * c.B, 0.2126 * c.R + 0.7152 * c.G + 0.0722 * c.B, 0.0193 * c.R + 0.1192 * c.G + 0.9505 * c.B, c.A); } /// /// Convert XYZA to linear SRGBA with channel values in the range [0.0, 1.0]. /// XYZ white (0.9505, 1.0000, 1.0890) at D65 with unit luminance is /// converted to SRGB white (1, 1, 1). The alpha value is simply copied. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f XYZAinC4fToLinearSRGBA(this C4f c) { return new C4f(3.2410 * c.R - 1.5374 * c.G - 0.4986 * c.B, -0.9692 * c.R + 1.876 * c.G + 0.0416 * c.B, 0.0556 * c.R - 0.204 * c.G + 1.057 * c.B, c.A); } /// /// Convert SRGBA with channel values in the range [0.0, 1.0] to XYZA. /// SRGBA white (1, 1, 1) is converted to XYZA white (0.9505, 1.0000, 1.0890) /// at D65 with unit luminance. The alpha value is subject to sRGB de-gamma /// conversion. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f SRGBAToXYZAinC4f(this C4f c) { return c.SRGBAToLinearSRGBA().LinearSRGBAToXYZAinC4f(); } /// /// Convert XYZA to SRGBA with channel values in the range [0.0, 1.0]. /// XYZA white (0.9505, 1.0000, 1.0890) at D65 with unit luminance is /// converted to SRGBA white (1, 1, 1). The alpha value is subject to /// sRGB gamma conversion. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f XYZAinC4fToSRGBA(this C4f c) { return c.XYZAinC4fToLinearSRGBA().LinearSRGBAToSRGBA(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static CieXYZf XYZinC3fToCieXYZf(this C3f c) { return new CieXYZf(c.R * 100.0, c.G * 100.0, c.B * 100.0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static CieXYZf XYZAinC4fToCieXYZf(this C4f c) { return new CieXYZf(c.R * 100.0, c.G * 100.0, c.B * 100.0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static CieXYZf LinearSRGBToCieXYZf(this C3f c) { return c.LinearSRGBToXYZinC3f().XYZinC3fToCieXYZf(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static CieXYZf LinearSRGBAToCieXYZf(this C4f c) { return c.LinearSRGBAToXYZAinC4f().XYZAinC4fToCieXYZf(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static CieXYZf SRGBToCieXYZf(this C3f c) { return c.SRGBToXYZinC3f().XYZinC3fToCieXYZf(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static CieXYZf SRGBAToCieXYZf(this C4f c) { return c.SRGBAToXYZAinC4f().XYZAinC4fToCieXYZf(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f ToXYZinC3f(this CieXYZf c) { return new C3f(c.X * 0.01f, c.Y * 0.01f, c.Z * 0.01f); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f ToXYZAinC4f(this CieXYZf c) { return new C4f(c.X * 0.01f, c.Y * 0.01f, c.Z * 0.01f); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f ToLinearSRGB(this CieXYZf c) { return c.ToXYZinC3f().XYZinC3fToLinearSRGB(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f ToLinearSRGBA(this CieXYZf c) { return c.ToXYZAinC4f().XYZAinC4fToLinearSRGBA(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f ToSRGB(this CieXYZf c) { return c. ToXYZinC3f().XYZinC3fToSRGB(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f ToSRGBA(this CieXYZf c) { return c.ToXYZAinC4f().XYZAinC4fToSRGBA(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static CieYxyf ToCieYxyf(this CieXYZf c) { var s = c.X + c.Y + c.Z; return s > 0.0f ? new CieYxyf(c.Y, c.X / s, c.Y / s) : new CieYxyf(0, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static CieXYZf ToCieXYZf(this CieYxyf c) { var s = c.y > 0.0 ? c.Y / c.y : 0.0; return new CieXYZf(s * c.x, c.Y, s * (1 - c.x - c.y)); } private const double s_labF_t3 = (6 / 29.0) * (6 / 29.0) * (6 / 29.0); private const double s_labF_t1 = (1 / 3.0) * (29 / 6.0) * (29 / 6.0); private const double s_labF_t0 = 4 / 29.0; [MethodImpl(MethodImplOptions.AggressiveInlining)] private static double s_labF(double t) { return t > s_labF_t3 ? Math.Pow(t, Constant.OneThird) : s_labF_t1 * t + s_labF_t0; } private const double s_labFinv_t3 = 6 / 29.0; private const double s_labFinv_t1 = 3.0 * (6 / 29.0) * (6 / 29.0); [MethodImpl(MethodImplOptions.AggressiveInlining)] private static double s_labFinv(double t) { return t > s_labFinv_t3 ? t * t * t : s_labFinv_t1 * (t - s_labF_t0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static CieLabf ToCieLabf(this CieXYZf c, CieXYZf white) { var fy = s_labF(c.Y / white.Y); return new CieLabf( 116.0 * fy - 16.0, 500.0 * (s_labF(c.X / white.X) - fy), 200.0 * (fy - s_labF(c.Z / white.Z))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static CieXYZf ToCieXYZf(this CieLabf c, CieXYZf white) { var l = (c.L + 16.0) / 116.0; return new CieXYZf(white.Y * s_labFinv(l), white.X * s_labFinv(l + c.a * 0.002), white.Z * s_labFinv(l - c.b * 0.005)); } public static readonly Trafo2d ConeResponseDomain_XYZScaling = new Trafo2d(M33d.Identity, M33d.Identity); public static readonly Trafo2d ConeResponseDomain_Bradford = new Trafo2d(new M33d(0.8951000, 0.2664000, -0.1614000, -0.7502000, 1.7135000, 0.0367000, 0.0389000, -0.0685000, 1.0296000), new M33d(0.9869929, -0.1470543, 0.1599627, 0.4323053, 0.5183603, 0.0492912, -0.0085287, 0.0400428, 0.9684867)); public static readonly Trafo2d ConeResponseDomain_VonKries = new Trafo2d(new M33d(0.4002400, 0.7076000, -0.0808100, -0.2263000, 1.1653200, 0.0457000, 0.0000000, 0.0000000, 0.9182200), new M33d(1.8599364, -1.1293816, 0.2198974, 0.3611914, 0.6388125, -0.0000064, 0.0000000, 0.0000000, 1.0890636)); public static readonly CieXYZf CieXYZfAWhite = new CieXYZf(109.85, 100.0, 35.585); public static readonly CieXYZf CieXYZfBWhite = new CieXYZf(99.072, 100.0, 85.223); public static readonly CieXYZf CieXYZfCWhite = new CieXYZf(98.074, 100.0, 118.232); public static readonly CieXYZf CieXYZfD50White = new CieXYZf(96.422, 100.0, 82.521); public static readonly CieXYZf CieXYZfD55White = new CieXYZf(95.682, 100.0, 92.149); public static readonly CieXYZf CieXYZfD65White = new CieXYZf(95.047, 100.0, 108.883); public static readonly CieXYZf CieXYZfD75White = new CieXYZf(94.972, 100.0, 122.638); public static readonly CieXYZf CieXYZfEWhite = new CieXYZf(100.0, 100.0, 100.0); public static readonly CieXYZf CieXYZfF2White = new CieXYZf(99.186, 100.00, 67.393); public static readonly CieXYZf CieXYZfF7White = new CieXYZf(95.041, 100.00, 108.747); public static readonly CieXYZf CieXYZfF11White = new CieXYZf(100.962, 100.00, 64.350); public static M33d BuildChromaticAdaptationMatrix(CieXYZf whiteFrom, CieXYZf whiteTo, Trafo2d coneResponseDomain) { // see: http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html var responseSource = coneResponseDomain.Forward * new V3d(whiteFrom.X, whiteFrom.Y, whiteFrom.Z); var responseTarget = coneResponseDomain.Forward * new V3d(whiteTo.X, whiteTo.Y, whiteTo.Z); var det = responseTarget / responseSource; var scaleMat = new M33d(det.X, 0, 0, 0, det.Y, 0, 0, 0, det.Z); return coneResponseDomain.Backward * scaleMat * coneResponseDomain.Forward; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static CieLabf ToCieLabfD65(this CieXYZf c) { return ToCieLabf(c, CieXYZfD65White); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static CieXYZf ToCieXYZfD65(this CieLabf c) { return ToCieXYZf(c, CieXYZfD65White); } #endregion #region HSL and HSV Conversions (see http://en.wikipedia.org/wiki/HSL_and_HSV) public static HSLf ToHSLf(this C3f c) { double cr = 0.0, h6 = 0.0, l = 0.0; if (c.R > c.G) { if (c.R > c.B) { if (c.G > c.B) { cr = c.R - c.B; l = 0.5 * (c.R + c.B); } // R > G > B else { cr = c.R - c.G; l = 0.5 * (c.R + c.G); } // R > B >= G h6 = 0 + (c.G - c.B) / cr; } else // B >= R > G { cr = c.B - c.G; l = 0.5 * (c.B + c.G); h6 = 4 + (c.R - c.G) / cr; } } else // G >= R { if (c.G > c.B) { if (c.R > c.B) { cr = c.G - c.B; l = 0.5 * (c.G + c.B); } // G >= R > B else { cr = c.G - c.R; l = 0.5 * (c.G + c.R); } // G > B >= R h6 = 2 + (c.B - c.R) / cr; } else // B >= G >= R { cr = c.B - c.R; l = 0.5 * (c.B + c.R); if (cr > 0.0) h6 = 4 + (c.R - c.G) / cr; } } return new HSLf(Fun.Frac(h6 * 1.0 / 6.0), cr > Constant.PositiveTinyValue ? cr / (1.0 - Fun.Abs(2.0 * l - 1.0)) : 0.0, l); } public static HSVf ToHSVf(this C3f c) { double cr = 0.0, h6 = 0.0, v = 0.0; if (c.R > c.G) { if (c.R > c.B) { if (c.G > c.B) cr = c.R - c.B; // R > G > B else cr = c.R - c.G; // R > B >= G v = c.R; h6 = 0 + (c.G - c.B) / cr; } else // B >= R > G { cr = c.B - c.G; v = c.B; h6 = 4 + (c.R - c.G) / cr; } } else // G >= R { if (c.G > c.B) { if (c.R > c.B) cr = c.G - c.B; // G >= R > B else cr = c.G - c.R; // G > B >= R v = c.G; h6 = 2 + (c.B - c.R) / cr; } else // B >= G >= R { cr = c.B - c.R; v = c.B; if (cr > 0.0) h6 = 4 + (c.R - c.G) / cr; } } return new HSVf(Fun.Frac(h6 * 1.0 / 6.0), cr > Constant.PositiveTinyValue ? cr / v : 0.0, v); } public static C3f ToC3f(this HSLf c) { double h = Fun.Frac(c.H); var chr = (1.0 - Fun.Abs(2.0 * c.L - 1.0)) * c.S; var x = chr * (1.0 - Fun.Abs(Fun.Frac(h * 3.0) * 2.0 - 1.0)); var m = c.L - 0.5 * chr; switch ((int)(h * 6.0)) { case 0: return new C3f(chr + m, x + m, m); case 1: return new C3f(x + m, chr + m, m); case 2: return new C3f(m, chr + m, x + m); case 3: return new C3f(m, x + m, chr + m); case 4: return new C3f(x + m, m, chr + m); case 5: return new C3f(chr + m, m, x + m); default: throw new ArgumentException("will never occur"); } } public static C3f ToC3f(this HSVf c) { double h = Fun.Frac(c.H); var chr = c.V * c.S; var x = chr * (1.0 - Fun.Abs(Fun.Frac(h * 3.0) * 2.0 - 1.0)); var m = c.V - chr; switch ((int)(h * 6.0)) { case 0: return new C3f(chr + m, x + m, m); case 1: return new C3f(x + m, chr + m, m); case 2: return new C3f(m, chr + m, x + m); case 3: return new C3f(m, x + m, chr + m); case 4: return new C3f(x + m, m, chr + m); case 5: return new C3f(chr + m, m, x + m); default: throw new ArgumentException("will never occur"); } } #endregion #region Gamma Correction Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GammaFloatToLinearFloat(float c, double gamma) { return (float)Fun.Pow(c, gamma); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LinearFloatToGammaFloat(float c, double gamma) { double inverseGamma = 1.0 / gamma; return (float)Fun.Pow(c, inverseGamma); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f GammaToLinear(this C3f c, double gamma) { return new C3f(Fun.Pow(c.R, gamma), Fun.Pow(c.G, gamma), Fun.Pow(c.B, gamma)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f GammaToLinear(this C4f c, double gamma) { return new C4f(Fun.Pow(c.R, gamma), Fun.Pow(c.G, gamma), Fun.Pow(c.B, gamma), Fun.Pow(c.A, gamma)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f LinearToGamma(this C3f c, double gamma) { double inv = 1.0 / gamma; return new C3f(Fun.Pow(c.R, inv), Fun.Pow(c.G, inv), Fun.Pow(c.B, inv)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f LinearToGamma(this C4f c, double gamma) { double inv = 1.0 / gamma; return new C4f(Fun.Pow(c.R, inv), Fun.Pow(c.G, inv), Fun.Pow(c.B, inv), Fun.Pow(c.A, inv)); } #endregion #region Color Temperature public static C3f TemperatureToYuvInC3f(this double t) { // calculation from: // http://en.wikipedia.org/wiki/Planckian_locus var t2 = t.Square(); return new C3f( 100, (0.860117757 + 1.54118254e-4 * t + 1.28641212e-7 * t2) / (1 + 8.42420235e-4 * t + 7.08145163e-7 * t2), // u: error within 8e-5 from 1000K < T < 15000K (0.317398726 + 4.22806245e-5 * t + 4.20481691e-8 * t2) / (1 - 2.89741816e-5 * t + 1.61456053e-7 * t2)); // v: error within 9e-5 from 1000K < T < 15000K } public static C3f TemperatureToYxyInC3f(this double t) { // calculation from: // http://en.wikipedia.org/wiki/Planckian_locus // defined from 1667 <= T <= 25000 if (t <= 0) return new C3f(0, 0, 0); var t2 = t * t; var t3 = t2 * t; var x = t <= 4000 ? -0.2661239e9/t3 - 0.2343580e6/t2 + 0.8776956e3/t + 0.179910 : -3.0258469e9/t3 + 2.1070379e6/t2 + 0.2226347e3/t + 0.240390; var x2 = x * x; var x3 = x2 * x; var y = t <= 2222 ? -1.1063814*x3 - 1.34811020*x2 + 2.18555832*x - 0.20219683 : t <= 4000 ? -0.9549476*x3 - 1.37418593*x2 + 2.09137015*x - 0.16748867 : 3.0817580*x3 - 5.87338670*x2 + 3.75112997*x - 0.37001483; return new C3f(100, x, y); } #endregion #region Operations public static C3b Average(this IEnumerable items) { var sum = new C3d(0, 0, 0); long count = 0; foreach (var c in items) { sum.R += c.R; sum.G += c.G; sum.B += c.B; ++count; } var scale = 1.0 / count; return new C3b((byte)(sum.R * scale), (byte)(sum.G * scale), (byte)(sum.B * scale)); } public static C4b Average(this IEnumerable items) { var sum = new C4d(0, 0, 0); long count = 0; foreach (var c in items) { sum.R += c.R; sum.G += c.G; sum.B += c.B; sum.A += c.A; ++count; } var scale = 1.0 / count; return new C4b((byte)(sum.R * scale), (byte)(sum.G * scale), (byte)(sum.B * scale), (byte)(sum.A * scale)); } public static C3f Average(this IEnumerable items) { var sum = new C3d(0, 0, 0); long count = 0; foreach (var c in items) { sum.R += c.R; sum.G += c.G; sum.B += c.B; ++count; } var scale = 1.0 / count; return new C3f(sum.R * scale, sum.G * scale, sum.B * scale); } public static C4f Average(this IEnumerable items) { var sum = new C4d(0, 0, 0, 0); long count = 0; foreach (var c in items) { sum.R += c.R; sum.G += c.G; sum.B += c.B; sum.A += c.A; ++count; } var scale = 1.0 / count; return new C4f(sum.R * scale, sum.B * scale, sum.G * scale, sum.A * scale); } #endregion #region Hex Parsing // See: https://developer.mozilla.org/en-US/docs/Web/CSS/hex-color private static readonly Regex regexHexSgl = new Regex("^(?:#|0x)?(?[0-9a-fA-F])(?[0-9a-fA-F])(?[0-9a-fA-F])(?[0-9a-fA-F])?$", RegexOptions.Compiled); private static readonly Regex regexHexDbl = new Regex("^(?:#|0x)?(?[0-9a-fA-F]{2})(?[0-9a-fA-F]{2})(?[0-9a-fA-F]{2})(?[0-9a-fA-F]{2})?$", RegexOptions.Compiled); private static bool TryParseHex(Regex regex, string input, out C4b result) { var m = regex.Match(input); if (m.Success) { string[] values = new string[4]; values[0] = m.Groups["R"].Value; values[1] = m.Groups["G"].Value; values[2] = m.Groups["B"].Value; values[3] = m.Groups["A"].Success ? m.Groups["A"].Value : "FF"; result = new C4b(values.Map((x) => { var value = x.Length == 1 ? new string(x[0], 2) : x; return byte.Parse(value, NumberStyles.AllowHexSpecifier); })); return true; } result = C4b.Zero; return false; } /// /// Parses a hexadecimal color string with format RRGGBBAA or RGBA, where the alpha component is optional. /// /// /// For the single digit RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// The color string may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C4b.Zero otherwise. /// True on success, false otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParseHex(Text input, out C4b result) { var str = input.WhiteSpaceTrimmed.ToString(); return TryParseHex(regexHexDbl, str, out result) || TryParseHex(regexHexSgl, str, out result); } /// /// Parses a hexadecimal color string with format RRGGBBAA or RGBA, where the alpha component is optional. /// /// /// For the single digit RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// The color string may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C4b.Zero otherwise. /// True on success, false otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParseHex(string input, out C4b result) => TryParseHex(new Text(input), out result); /// /// Parses a hexadecimal color string with format RRGGBBAA or RGBA, where the alpha component is optional. /// /// /// For the single digit RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// The color string may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid hexadecimal color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b ParseHex(Text input) => TryParseHex(input, out C4b result) ? result : throw new FormatException($"{input} is not a valid hexadecimal color."); /// /// Parses a hexadecimal color string with format RRGGBBAA or RGBA, where the alpha component is optional. /// /// /// For the single digit RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// The color string may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid hexadecimal color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b ParseHex(string input) => ParseHex(new Text(input)); #endregion } #endregion #region PixFormat /// /// The PixFormat encodes the channel type and the color format of an image. /// [DataContract] [Serializable] public readonly struct PixFormat : IEquatable { [DataMember] public readonly Type Type; [DataMember] public readonly Col.Format Format; #region Constructor public PixFormat(Type type, Col.Format format) { Type = type; Format = format; } #endregion #region Predefined PixFormats public static readonly PixFormat ByteBW = new PixFormat(typeof(byte), Col.Format.BW); public static readonly PixFormat ByteGray = new PixFormat(typeof(byte), Col.Format.Gray); public static readonly PixFormat ByteGrayAlpha = new PixFormat(typeof(byte), Col.Format.GrayAlpha); public static readonly PixFormat ByteRG = new PixFormat(typeof(byte), Col.Format.RG); public static readonly PixFormat ByteBGR = new PixFormat(typeof(byte), Col.Format.BGR); public static readonly PixFormat ByteRGB = new PixFormat(typeof(byte), Col.Format.RGB); public static readonly PixFormat ByteBGRA = new PixFormat(typeof(byte), Col.Format.BGRA); public static readonly PixFormat ByteRGBA = new PixFormat(typeof(byte), Col.Format.RGBA); public static readonly PixFormat ByteBGRP = new PixFormat(typeof(byte), Col.Format.BGRP); public static readonly PixFormat ByteRGBP = new PixFormat(typeof(byte), Col.Format.RGBP); public static readonly PixFormat SByteBW = new PixFormat(typeof(sbyte), Col.Format.BW); public static readonly PixFormat SByteGray = new PixFormat(typeof(sbyte), Col.Format.Gray); public static readonly PixFormat SByteGrayAlpha = new PixFormat(typeof(sbyte), Col.Format.GrayAlpha); public static readonly PixFormat SByteRG = new PixFormat(typeof(sbyte), Col.Format.RG); public static readonly PixFormat SByteBGR = new PixFormat(typeof(sbyte), Col.Format.BGR); public static readonly PixFormat SByteRGB = new PixFormat(typeof(sbyte), Col.Format.RGB); public static readonly PixFormat SByteBGRA = new PixFormat(typeof(sbyte), Col.Format.BGRA); public static readonly PixFormat SByteRGBA = new PixFormat(typeof(sbyte), Col.Format.RGBA); public static readonly PixFormat SByteBGRP = new PixFormat(typeof(sbyte), Col.Format.BGRP); public static readonly PixFormat SByteRGBP = new PixFormat(typeof(sbyte), Col.Format.RGBP); public static readonly PixFormat UShortGray = new PixFormat(typeof(ushort), Col.Format.Gray); public static readonly PixFormat UShortGrayAlpha = new PixFormat(typeof(ushort), Col.Format.GrayAlpha); public static readonly PixFormat UShortRG = new PixFormat(typeof(ushort), Col.Format.RG); public static readonly PixFormat UShortBGR = new PixFormat(typeof(ushort), Col.Format.BGR); public static readonly PixFormat UShortRGB = new PixFormat(typeof(ushort), Col.Format.RGB); public static readonly PixFormat UShortBGRA = new PixFormat(typeof(ushort), Col.Format.BGRA); public static readonly PixFormat UShortRGBA = new PixFormat(typeof(ushort), Col.Format.RGBA); public static readonly PixFormat UShortBGRP = new PixFormat(typeof(ushort), Col.Format.BGRP); public static readonly PixFormat UShortRGBP = new PixFormat(typeof(ushort), Col.Format.RGBP); public static readonly PixFormat ShortGray = new PixFormat(typeof(short), Col.Format.Gray); public static readonly PixFormat ShortGrayAlpha = new PixFormat(typeof(short), Col.Format.GrayAlpha); public static readonly PixFormat ShortRG = new PixFormat(typeof(short), Col.Format.RG); public static readonly PixFormat ShortBGR = new PixFormat(typeof(short), Col.Format.BGR); public static readonly PixFormat ShortRGB = new PixFormat(typeof(short), Col.Format.RGB); public static readonly PixFormat ShortBGRA = new PixFormat(typeof(short), Col.Format.BGRA); public static readonly PixFormat ShortRGBA = new PixFormat(typeof(short), Col.Format.RGBA); public static readonly PixFormat ShortBGRP = new PixFormat(typeof(short), Col.Format.BGRP); public static readonly PixFormat ShortRGBP = new PixFormat(typeof(short), Col.Format.RGBP); public static readonly PixFormat UIntGray = new PixFormat(typeof(uint), Col.Format.Gray); public static readonly PixFormat UIntGrayAlpha = new PixFormat(typeof(uint), Col.Format.GrayAlpha); public static readonly PixFormat UIntRG = new PixFormat(typeof(uint), Col.Format.RG); public static readonly PixFormat UIntBGR = new PixFormat(typeof(uint), Col.Format.BGR); public static readonly PixFormat UIntRGB = new PixFormat(typeof(uint), Col.Format.RGB); public static readonly PixFormat UIntBGRA = new PixFormat(typeof(uint), Col.Format.BGRA); public static readonly PixFormat UIntRGBA = new PixFormat(typeof(uint), Col.Format.RGBA); public static readonly PixFormat UIntBGRP = new PixFormat(typeof(uint), Col.Format.BGRP); public static readonly PixFormat UIntRGBP = new PixFormat(typeof(uint), Col.Format.RGBP); public static readonly PixFormat IntGray = new PixFormat(typeof(int), Col.Format.Gray); public static readonly PixFormat IntGrayAlpha = new PixFormat(typeof(int), Col.Format.GrayAlpha); public static readonly PixFormat IntRG = new PixFormat(typeof(int), Col.Format.RG); public static readonly PixFormat IntBGR = new PixFormat(typeof(int), Col.Format.BGR); public static readonly PixFormat IntRGB = new PixFormat(typeof(int), Col.Format.RGB); public static readonly PixFormat IntBGRA = new PixFormat(typeof(int), Col.Format.BGRA); public static readonly PixFormat IntRGBA = new PixFormat(typeof(int), Col.Format.RGBA); public static readonly PixFormat IntBGRP = new PixFormat(typeof(int), Col.Format.BGRP); public static readonly PixFormat IntRGBP = new PixFormat(typeof(int), Col.Format.RGBP); public static readonly PixFormat HalfGray = new PixFormat(typeof(Half), Col.Format.Gray); public static readonly PixFormat HalfGrayAlpha = new PixFormat(typeof(Half), Col.Format.GrayAlpha); public static readonly PixFormat HalfRG = new PixFormat(typeof(Half), Col.Format.RG); public static readonly PixFormat HalfBGR = new PixFormat(typeof(Half), Col.Format.BGR); public static readonly PixFormat HalfRGB = new PixFormat(typeof(Half), Col.Format.RGB); public static readonly PixFormat HalfBGRA = new PixFormat(typeof(Half), Col.Format.BGRA); public static readonly PixFormat HalfRGBA = new PixFormat(typeof(Half), Col.Format.RGBA); public static readonly PixFormat HalfBGRP = new PixFormat(typeof(Half), Col.Format.BGRP); public static readonly PixFormat HalfRGBP = new PixFormat(typeof(Half), Col.Format.RGBP); public static readonly PixFormat FloatGray = new PixFormat(typeof(float), Col.Format.Gray); public static readonly PixFormat FloatGrayAlpha = new PixFormat(typeof(float), Col.Format.GrayAlpha); public static readonly PixFormat FloatRG = new PixFormat(typeof(float), Col.Format.RG); public static readonly PixFormat FloatBGR = new PixFormat(typeof(float), Col.Format.BGR); public static readonly PixFormat FloatRGB = new PixFormat(typeof(float), Col.Format.RGB); public static readonly PixFormat FloatBGRA = new PixFormat(typeof(float), Col.Format.BGRA); public static readonly PixFormat FloatRGBA = new PixFormat(typeof(float), Col.Format.RGBA); public static readonly PixFormat FloatBGRP = new PixFormat(typeof(float), Col.Format.BGRP); public static readonly PixFormat FloatRGBP = new PixFormat(typeof(float), Col.Format.RGBP); public static readonly PixFormat DoubleGray = new PixFormat(typeof(double), Col.Format.Gray); public static readonly PixFormat DoubleGrayAlpha = new PixFormat(typeof(double), Col.Format.GrayAlpha); public static readonly PixFormat DoubleRG = new PixFormat(typeof(double), Col.Format.RG); public static readonly PixFormat DoubleBGR = new PixFormat(typeof(double), Col.Format.BGR); public static readonly PixFormat DoubleRGB = new PixFormat(typeof(double), Col.Format.RGB); public static readonly PixFormat DoubleBGRA = new PixFormat(typeof(double), Col.Format.BGRA); public static readonly PixFormat DoubleRGBA = new PixFormat(typeof(double), Col.Format.RGBA); public static readonly PixFormat DoubleBGRP = new PixFormat(typeof(double), Col.Format.BGRP); public static readonly PixFormat DoubleRGBP = new PixFormat(typeof(double), Col.Format.RGBP); #endregion #region Properties public int ChannelCount { get { return Format.ChannelCount(); } } #endregion #region Operators public static bool operator ==(PixFormat a, PixFormat b) { return a.Type == b.Type && a.Format == b.Format; } public static bool operator !=(PixFormat a, PixFormat b) { return a.Type != b.Type || a.Format != b.Format; } #endregion #region Overrides public override bool Equals(object obj) { return obj is PixFormat ? this == (PixFormat)obj : false; } public override int GetHashCode() { return HashCode.Combine(Type.GetHashCode(), Format.GetHashCode()); } public override string ToString() => $"{Type.Name}{Format}"; #endregion #region IEquatable Members public bool Equals(PixFormat other) { return other.Type == Type && other.Format == Format; } #endregion } #endregion #region C3b [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct C3b { /// /// Memory layout for intel-based little-endian argb-ints. /// (DO NOT CHANGE!) /// [DataMember] public byte B; [DataMember] public byte G; [DataMember] public byte R; } #endregion #region C3us [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct C3us { [DataMember] public ushort R; [DataMember] public ushort G; [DataMember] public ushort B; } #endregion #region C3ui [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct C3ui { [DataMember] public uint R; [DataMember] public uint G; [DataMember] public uint B; } #endregion #region C3f [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct C3f { [DataMember] public float R; [DataMember] public float G; [DataMember] public float B; /// /// Creates an RGB representation from hue, saturation and value/brightness. /// /// Hue given in normalized angle [0,1] (may be larger than 1, wraps around), 0=1=red, 1/3=green, 2/3=blue. /// Saturation [0,1], 0 = gray, 1 = fully saturated. /// Value or Brightness [0,1], 0 = black, 1 = white. /// The RGB Color for the HSV values. public static C3f FromHSV(float hue, float saturation, float value) { return new HSVf(hue, saturation, value).ToC3f(); } /// /// Creates an RGB representation from hue, saturation and lightness. /// /// Hue given in normalized angle [0,1] (may be larger than 1, wraps around), 0=1=red, 1/3=green, 2/3=blue. /// Saturation [0,1], 0 = gray, 1 = fully saturated. /// Lightness [0,1], 0 = black, 1 = white. /// The RGB Color for the HSV values. public static C3f FromHSL(float hue, float saturation, float lightness) { return new HSLf(hue, saturation, lightness).ToC3f(); } public readonly HSLf AsHSLf() { return new HSLf(R, G, B); } public readonly HSVf AsHSVf() { return new HSVf(R, G, B); } } #endregion #region C3d [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct C3d { [DataMember] public double R; [DataMember] public double G; [DataMember] public double B; } #endregion #region C4b [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct C4b { /// /// Memory layout for intel-based little-endian argb-ints. /// (DO NOT CHANGE!) /// [DataMember] public byte B; [DataMember] public byte G; [DataMember] public byte R; [DataMember] public byte A; } #endregion #region C4us [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct C4us { [DataMember] public ushort R; [DataMember] public ushort G; [DataMember] public ushort B; [DataMember] public ushort A; } #endregion #region C4ui [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct C4ui { [DataMember] public uint R; [DataMember] public uint G; [DataMember] public uint B; [DataMember] public uint A; } #endregion #region C4f [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct C4f { [DataMember] public float R; [DataMember] public float G; [DataMember] public float B; [DataMember] public float A; } #endregion #region C4d [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct C4d { [DataMember] public double R; [DataMember] public double G; [DataMember] public double B; [DataMember] public double A; } #endregion #region CieLabf [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct CieLabf : IEquatable { [DataMember] public float L; [DataMember] public float a; [DataMember] public float b; public CieLabf(float _L, float _a, float _b) { L = _L; a = _a; b = _b; } public CieLabf(double _L, double _a, double _b) { L = (float)_L; a = (float)_a; b = (float)_b; } public readonly bool Equals(CieLabf other) => L == other.L && a == other.a && b == other.b; public override readonly bool Equals(object other) => (other is CieLabf o) ? Equals(o) : false; public override readonly int GetHashCode() => HashCode.GetCombined(L, a, b); } #endregion #region CieLuvf [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct CieLuvf : IEquatable { [DataMember] public float L; [DataMember] public float u; [DataMember] public float v; public CieLuvf(float _L, float _u, float _v) { L = _L; u = _u; v = _v; } public CieLuvf(double _L, double _u, double _v) { L = (float)_L; u = (float)_u; v = (float)_v; } public readonly C3f AsC3f() { return new C3f(L, u, v); } public readonly bool Equals(CieLuvf other) => L == other.L && u == other.u && v == other.v; public override readonly bool Equals(object other) => (other is CieLuvf o) ? Equals(o) : false; public override readonly int GetHashCode() => HashCode.GetCombined(L, u, v); } #endregion #region CieXYZf /// /// This structure holds Cie XYZ colors where Y should be in the range /// [0,100] for reflective color values. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct CieXYZf : IEquatable { [DataMember] public float X; [DataMember] public float Y; [DataMember] public float Z; public CieXYZf(float _X, float _Y, float _Z) { X = _X; Y = _Y; Z = _Z; } public CieXYZf(double _X, double _Y, double _Z) { X = (float)_X; Y = (float)_Y; Z = (float)_Z; } public readonly bool Equals(CieXYZf other) => X == other.X && Y == other.Y && Z == other.Z; public override readonly bool Equals(object other) => (other is CieXYZf o) ? Equals(o) : false; public override readonly int GetHashCode() => HashCode.GetCombined(X, Y, Z); } #endregion #region CieYxyf [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct CieYxyf : IEquatable { [DataMember] public float Y; [DataMember] public float x; [DataMember] public float y; public CieYxyf(float _Y, float _x, float _y) { Y = _Y; x = _x; y = _y; } public CieYxyf(double _Y, double _x, double _y) { Y = (float)_Y; x = (float)_x; y = (float)_y; } public readonly bool Equals(CieYxyf other) => Y == other.Y && x == other.x && y == other.y; public override readonly bool Equals(object other) => (other is CieYxyf o) ? Equals(o) : false; public override readonly int GetHashCode() => HashCode.GetCombined(Y, x, y); } #endregion #region CMYKf [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct CMYKf : IEquatable { [DataMember] public float C; [DataMember] public float M; [DataMember] public float Y; [DataMember] public float K; public CMYKf(float _C, float _M, float _Y, float _K) { C = _C; M = _M; Y = _Y; K = _K; } public CMYKf(double _C, double _M, double _Y, double _K) { C = (float)_C; M = (float)_M; Y = (float)_Y; K = (float)_K; } public readonly bool Equals(CMYKf other) => C == other.C && M == other.M && Y == other.Y && K == other.K; public override readonly bool Equals(object other) => (other is CMYKf o) ? Equals(o) : false; public override readonly int GetHashCode() => HashCode.GetCombined(C, M, Y, K); } #endregion #region HSLf /// /// Hue Saturation Value colors. All three components are defined in the range [0.0, 1.0]. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct HSLf : IEquatable { [DataMember] public float H; [DataMember] public float S; [DataMember] public float L; #region Constructors public HSLf(float hue, float saturation, float lightness) { H = hue; S = saturation; L = lightness; } public HSLf(double hue, double saturation, double lightness) { H = (float)hue; S = (float)saturation; L = (float)lightness; } #endregion #region Conversions public static HSLf FromC3f(C3f col) { return col.ToHSLf(); } public readonly C3f AsC3f() { return new C3f(H, S, L); } #endregion public readonly bool Equals(HSLf other) => H == other.H && S == other.S && L == other.L; public override readonly bool Equals(object other) => (other is HSLf o) ? Equals(o) : false; public override readonly int GetHashCode() => HashCode.GetCombined(H, S, L); } #endregion #region HSVf /// /// Hue Saturation Lightness colors. All three components are defined in the range [0.0, 1.0]. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct HSVf : IEquatable { [DataMember] public float H; [DataMember] public float S; [DataMember] public float V; #region Constructors public HSVf(float hue, float saturation, float value) { H = hue; S = saturation; V = value; } public HSVf(double hue, double saturation, double value) { H = (float)hue; S = (float)saturation; V = (float)value; } #endregion #region Conversions public static HSVf FromC3f(C3f col) { return col.ToHSVf(); } public readonly C3f AsC3f() { return new C3f(H, S, V); } #endregion public readonly bool Equals(HSVf other) => H == other.H && S == other.S && V == other.V; public override readonly bool Equals(object other) => (other is HSVf o) ? Equals(o) : false; public override readonly int GetHashCode() => HashCode.GetCombined(H, S, V); } #endregion #region Yuvf [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Yuvf : IEquatable { [DataMember] public float Y; [DataMember] public float u; [DataMember] public float v; public Yuvf(float _Y, float _u, float _v) { Y = _Y; u = _u; v = _v; } public Yuvf(double _Y, double _u, double _v) { Y = (float)_Y; u = (float)_u; v = (float)_v; } public readonly C3f AsC3f() { return new C3f(Y, u, v); } public readonly bool Equals(Yuvf other) => Y == other.Y && u == other.u && v == other.v; public override readonly bool Equals(object other) => (other is Yuvf o) ? Equals(o) : false; public override readonly int GetHashCode() => HashCode.GetCombined(Y, u, v); } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Colors/Color_auto.cs ================================================ using System; using System.Globalization; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region C3b /// /// Represents an RGB color with each channel stored as a value within [0, 255]. /// [Serializable] public partial struct C3b : IFormattable, IEquatable, IRGB { #region Constructors /// /// Creates a color from the given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(byte r, byte g, byte b) { R = r; G = g; B = b; } /// /// Creates a color from the given values. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(int r, int g, int b) { R = (byte)r; G = (byte)g; B = (byte)b; } /// /// Creates a color from the given values. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(long r, long g, long b) { R = (byte)r; G = (byte)g; B = (byte)b; } /// /// Creates a color from the given values. /// The values are mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(float r, float g, float b) { R = Col.FloatToByteClamped(r); G = Col.FloatToByteClamped(g); B = Col.FloatToByteClamped(b); } /// /// Creates a color from the given values. /// The values are mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(double r, double g, double b) { R = Col.DoubleToByteClamped(r); G = Col.DoubleToByteClamped(g); B = Col.DoubleToByteClamped(b); } /// /// Creates a color from a single value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(byte gray) { R = gray; G = gray; B = gray; } /// /// Creates a color from a single value. /// The value is mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(float gray) { var value = Col.FloatToByteClamped(gray); R = value; G = value; B = value; } /// /// Creates a color from a single value. /// The value is mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(double gray) { var value = Col.DoubleToByteClamped(gray); R = value; G = value; B = value; } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(C3b color) { R = (color.R); G = (color.G); B = (color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(C3us color) { R = Col.UShortToByte(color.R); G = Col.UShortToByte(color.G); B = Col.UShortToByte(color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(C3ui color) { R = Col.UIntToByte(color.R); G = Col.UIntToByte(color.G); B = Col.UIntToByte(color.B); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(C3f color) { R = Col.FloatToByteClamped(color.R); G = Col.FloatToByteClamped(color.G); B = Col.FloatToByteClamped(color.B); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(C3d color) { R = Col.DoubleToByteClamped(color.R); G = Col.DoubleToByteClamped(color.G); B = Col.DoubleToByteClamped(color.B); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(C4b color) { R = (color.R); G = (color.G); B = (color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(C4us color) { R = Col.UShortToByte(color.R); G = Col.UShortToByte(color.G); B = Col.UShortToByte(color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(C4ui color) { R = Col.UIntToByte(color.R); G = Col.UIntToByte(color.G); B = Col.UIntToByte(color.B); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(C4f color) { R = Col.FloatToByteClamped(color.R); G = Col.FloatToByteClamped(color.G); B = Col.FloatToByteClamped(color.B); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(C4d color) { R = Col.DoubleToByteClamped(color.R); G = Col.DoubleToByteClamped(color.G); B = Col.DoubleToByteClamped(color.B); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(V3i vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(V3ui vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(V3l vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(V3f vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(V3d vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(V4i vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(V4ui vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(V4l vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(V4f vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(V4d vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); } /// /// Creates a color from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(Func index_fun) { R = index_fun(0); G = index_fun(1); B = index_fun(2); } /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(byte[] values) { R = (values[0]); G = (values[1]); B = (values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(byte[] values, int start) { R = (values[start + 0]); G = (values[start + 1]); B = (values[start + 2]); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(ushort[] values) { R = Col.UShortToByte(values[0]); G = Col.UShortToByte(values[1]); B = Col.UShortToByte(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(ushort[] values, int start) { R = Col.UShortToByte(values[start + 0]); G = Col.UShortToByte(values[start + 1]); B = Col.UShortToByte(values[start + 2]); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(uint[] values) { R = Col.UIntToByte(values[0]); G = Col.UIntToByte(values[1]); B = Col.UIntToByte(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(uint[] values, int start) { R = Col.UIntToByte(values[start + 0]); G = Col.UIntToByte(values[start + 1]); B = Col.UIntToByte(values[start + 2]); } /// /// Creates a new color from the given array. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(float[] values) { R = Col.FloatToByteClamped(values[0]); G = Col.FloatToByteClamped(values[1]); B = Col.FloatToByteClamped(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(float[] values, int start) { R = Col.FloatToByteClamped(values[start + 0]); G = Col.FloatToByteClamped(values[start + 1]); B = Col.FloatToByteClamped(values[start + 2]); } /// /// Creates a new color from the given array. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(double[] values) { R = Col.DoubleToByteClamped(values[0]); G = Col.DoubleToByteClamped(values[1]); B = Col.DoubleToByteClamped(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3b(double[] values, int start) { R = Col.DoubleToByteClamped(values[start + 0]); G = Col.DoubleToByteClamped(values[start + 1]); B = Col.DoubleToByteClamped(values[start + 2]); } #endregion #region Conversions /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(C3us color) => new C3b(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromC3us(C3us c) => new C3b(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(C3ui color) => new C3b(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromC3ui(C3ui c) => new C3b(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(C3f color) => new C3b(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f ToC3f() => (C3f)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromC3f(C3f c) => new C3b(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(C3d color) => new C3b(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d ToC3d() => (C3d)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromC3d(C3d c) => new C3b(c); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(C4b color) => new C3b(color); /// /// Converts the given color to a color. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromC4b(C4b c) => new C3b(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(C4us color) => new C3b(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromC4us(C4us c) => new C3b(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(C4ui color) => new C3b(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromC4ui(C4ui c) => new C3b(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(C4f color) => new C3b(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f ToC4f() => (C4f)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromC4f(C4f c) => new C3b(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(C4d color) => new C3b(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d ToC4d() => (C4d)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromC4d(C4d c) => new C3b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(V3i v) => new C3b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromV3i(V3i c) => new C3b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(V3ui v) => new C3b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromV3ui(V3ui c) => new C3b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(V3l v) => new C3b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromV3l(V3l c) => new C3b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(V3f v) => new C3b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromV3f(V3f c) => new C3b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(V3d v) => new C3b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromV3d(V3d c) => new C3b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(V4i v) => new C3b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromV4i(V4i c) => new C3b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(V4ui v) => new C3b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromV4ui(V4ui c) => new C3b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(V4l v) => new C3b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromV4l(V4l c) => new C3b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(V4f v) => new C3b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromV4f(V4f c) => new C3b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(V4d v) => new C3b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b FromV4d(V4d c) => new C3b(c); /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(byte[] values) => new C3b(values); /// /// Creates a new array from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator byte[](C3b color) => new byte[] { (color.R), (color.G), (color.B) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(ushort[] values) => new C3b(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ushort[](C3b color) => new ushort[] { Col.ByteToUShort(color.R), Col.ByteToUShort(color.G), Col.ByteToUShort(color.B) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(uint[] values) => new C3b(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](C3b color) => new uint[] { Col.ByteToUInt(color.R), Col.ByteToUInt(color.G), Col.ByteToUInt(color.B) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(float[] values) => new C3b(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](C3b color) => new float[] { Col.ByteToFloat(color.R), Col.ByteToFloat(color.G), Col.ByteToFloat(color.B) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3b(double[] values) => new C3b(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](C3b color) => new double[] { Col.ByteToDouble(color.R), Col.ByteToDouble(color.G), Col.ByteToDouble(color.B) }; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b Map(Func channel_fun) { return new C3b(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us Map(Func channel_fun) { return new C3us(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui Map(Func channel_fun) { return new C3ui(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f Map(Func channel_fun) { return new C3f(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d Map(Func channel_fun) { return new C3d(channel_fun(R), channel_fun(G), channel_fun(B)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(R); array[start + 1] = element_fun(G); array[start + 2] = element_fun(B); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(R, 0); array[start + 1] = element_index_fun(G, 1); array[start + 2] = element_index_fun(B, 2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly byte[] ToArray() => (byte[])this; #endregion #region Indexer // Byte colors have a different byte order (red and blue are swapped) private static readonly byte[] IndexMapping = new byte[] { 2, 1, 0, 3 }; /// /// Indexer in canonical order 0=R, 1=G, 2=B, 3=A (availability depending on color type). /// public unsafe byte this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (byte* ptr = &B) { ptr[IndexMapping[i]] = value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (byte* ptr = &B) { return ptr[IndexMapping[i]]; } } } #endregion #region Constants /// /// C3b with all components zero. /// public static C3b Zero => new C3b(0, 0, 0); // Web colors public static C3b AliceBlue => new C3b(Col.DoubleToByteClamped(0.941176), Col.DoubleToByteClamped(0.972549), Col.DoubleToByteClamped(1)); public static C3b AntiqueWhite => new C3b(Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.921569), Col.DoubleToByteClamped(0.843137)); public static C3b Aqua => new C3b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1)); public static C3b Aquamarine => new C3b(Col.DoubleToByteClamped(0.498039), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.831373)); public static C3b Azure => new C3b(Col.DoubleToByteClamped(0.941176), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1)); public static C3b Beige => new C3b(Col.DoubleToByteClamped(0.960784), Col.DoubleToByteClamped(0.960784), Col.DoubleToByteClamped(0.862745)); public static C3b Bisque => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.894118), Col.DoubleToByteClamped(0.768627)); public static C3b Black => new C3b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0)); public static C3b BlanchedAlmond => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.921569), Col.DoubleToByteClamped(0.803922)); public static C3b Blue => new C3b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(1)); public static C3b BlueViolet => new C3b(Col.DoubleToByteClamped(0.541176), Col.DoubleToByteClamped(0.168627), Col.DoubleToByteClamped(0.886275)); public static C3b Brown => new C3b(Col.DoubleToByteClamped(0.647059), Col.DoubleToByteClamped(0.164706), Col.DoubleToByteClamped(0.164706)); public static C3b BurlyWood => new C3b(Col.DoubleToByteClamped(0.870588), Col.DoubleToByteClamped(0.721569), Col.DoubleToByteClamped(0.529412)); public static C3b CadetBlue => new C3b(Col.DoubleToByteClamped(0.372549), Col.DoubleToByteClamped(0.619608), Col.DoubleToByteClamped(0.627451)); public static C3b Chartreuse => new C3b(Col.DoubleToByteClamped(0.498039), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0)); public static C3b Chocolate => new C3b(Col.DoubleToByteClamped(0.823529), Col.DoubleToByteClamped(0.411765), Col.DoubleToByteClamped(0.117647)); public static C3b Coral => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.498039), Col.DoubleToByteClamped(0.313725)); public static C3b CornflowerBlue => new C3b(Col.DoubleToByteClamped(0.392157), Col.DoubleToByteClamped(0.584314), Col.DoubleToByteClamped(0.929412)); public static C3b Cornsilk => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.972549), Col.DoubleToByteClamped(0.862745)); public static C3b Crimson => new C3b(Col.DoubleToByteClamped(0.862745), Col.DoubleToByteClamped(0.078431), Col.DoubleToByteClamped(0.235294)); public static C3b Cyan => new C3b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1)); public static C3b DarkBlue => new C3b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.545098)); public static C3b DarkCyan => new C3b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.545098), Col.DoubleToByteClamped(0.545098)); public static C3b DarkGoldenRod => new C3b(Col.DoubleToByteClamped(0.721569), Col.DoubleToByteClamped(0.52549), Col.DoubleToByteClamped(0.043137)); public static C3b DarkGray => new C3b(Col.DoubleToByteClamped(0.662745), Col.DoubleToByteClamped(0.662745), Col.DoubleToByteClamped(0.662745)); public static C3b DarkGrey => new C3b(Col.DoubleToByteClamped(0.662745), Col.DoubleToByteClamped(0.662745), Col.DoubleToByteClamped(0.662745)); public static C3b DarkGreen => new C3b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.392157), Col.DoubleToByteClamped(0)); public static C3b DarkKhaki => new C3b(Col.DoubleToByteClamped(0.741176), Col.DoubleToByteClamped(0.717647), Col.DoubleToByteClamped(0.419608)); public static C3b DarkMagenta => new C3b(Col.DoubleToByteClamped(0.545098), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.545098)); public static C3b DarkOliveGreen => new C3b(Col.DoubleToByteClamped(0.333333), Col.DoubleToByteClamped(0.419608), Col.DoubleToByteClamped(0.184314)); public static C3b DarkOrange => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.54902), Col.DoubleToByteClamped(0)); public static C3b DarkOrchid => new C3b(Col.DoubleToByteClamped(0.6), Col.DoubleToByteClamped(0.196078), Col.DoubleToByteClamped(0.8)); public static C3b DarkRed => new C3b(Col.DoubleToByteClamped(0.545098), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0)); public static C3b DarkSalmon => new C3b(Col.DoubleToByteClamped(0.913725), Col.DoubleToByteClamped(0.588235), Col.DoubleToByteClamped(0.478431)); public static C3b DarkSeaGreen => new C3b(Col.DoubleToByteClamped(0.560784), Col.DoubleToByteClamped(0.737255), Col.DoubleToByteClamped(0.560784)); public static C3b DarkSlateBlue => new C3b(Col.DoubleToByteClamped(0.282353), Col.DoubleToByteClamped(0.239216), Col.DoubleToByteClamped(0.545098)); public static C3b DarkSlateGray => new C3b(Col.DoubleToByteClamped(0.184314), Col.DoubleToByteClamped(0.309804), Col.DoubleToByteClamped(0.309804)); public static C3b DarkSlateGrey => new C3b(Col.DoubleToByteClamped(0.184314), Col.DoubleToByteClamped(0.309804), Col.DoubleToByteClamped(0.309804)); public static C3b DarkTurquoise => new C3b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.807843), Col.DoubleToByteClamped(0.819608)); public static C3b DarkViolet => new C3b(Col.DoubleToByteClamped(0.580392), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.827451)); public static C3b DeepPink => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.078431), Col.DoubleToByteClamped(0.576471)); public static C3b DeepSkyBlue => new C3b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.74902), Col.DoubleToByteClamped(1)); public static C3b DimGray => new C3b(Col.DoubleToByteClamped(0.411765), Col.DoubleToByteClamped(0.411765), Col.DoubleToByteClamped(0.411765)); public static C3b DimGrey => new C3b(Col.DoubleToByteClamped(0.411765), Col.DoubleToByteClamped(0.411765), Col.DoubleToByteClamped(0.411765)); public static C3b DodgerBlue => new C3b(Col.DoubleToByteClamped(0.117647), Col.DoubleToByteClamped(0.564706), Col.DoubleToByteClamped(1)); public static C3b FireBrick => new C3b(Col.DoubleToByteClamped(0.698039), Col.DoubleToByteClamped(0.133333), Col.DoubleToByteClamped(0.133333)); public static C3b FloralWhite => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.941176)); public static C3b ForestGreen => new C3b(Col.DoubleToByteClamped(0.133333), Col.DoubleToByteClamped(0.545098), Col.DoubleToByteClamped(0.133333)); public static C3b Fuchsia => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(1)); public static C3b Gainsboro => new C3b(Col.DoubleToByteClamped(0.862745), Col.DoubleToByteClamped(0.862745), Col.DoubleToByteClamped(0.862745)); public static C3b GhostWhite => new C3b(Col.DoubleToByteClamped(0.972549), Col.DoubleToByteClamped(0.972549), Col.DoubleToByteClamped(1)); public static C3b Gold => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.843137), Col.DoubleToByteClamped(0)); public static C3b GoldenRod => new C3b(Col.DoubleToByteClamped(0.854902), Col.DoubleToByteClamped(0.647059), Col.DoubleToByteClamped(0.12549)); public static C3b Gray => new C3b(Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.501961)); public static C3b Grey => new C3b(Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.501961)); public static C3b Green => new C3b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0)); public static C3b GreenYellow => new C3b(Col.DoubleToByteClamped(0.678431), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.184314)); public static C3b HoneyDew => new C3b(Col.DoubleToByteClamped(0.941176), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.941176)); public static C3b HotPink => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.411765), Col.DoubleToByteClamped(0.705882)); public static C3b IndianRed => new C3b(Col.DoubleToByteClamped(0.803922), Col.DoubleToByteClamped(0.360784), Col.DoubleToByteClamped(0.360784)); public static C3b Indigo => new C3b(Col.DoubleToByteClamped(0.294118), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.509804)); public static C3b Ivory => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.941176)); public static C3b Khaki => new C3b(Col.DoubleToByteClamped(0.941176), Col.DoubleToByteClamped(0.901961), Col.DoubleToByteClamped(0.54902)); public static C3b Lavender => new C3b(Col.DoubleToByteClamped(0.901961), Col.DoubleToByteClamped(0.901961), Col.DoubleToByteClamped(0.980392)); public static C3b LavenderBlush => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.941176), Col.DoubleToByteClamped(0.960784)); public static C3b LawnGreen => new C3b(Col.DoubleToByteClamped(0.486275), Col.DoubleToByteClamped(0.988235), Col.DoubleToByteClamped(0)); public static C3b LemonChiffon => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.803922)); public static C3b LightBlue => new C3b(Col.DoubleToByteClamped(0.678431), Col.DoubleToByteClamped(0.847059), Col.DoubleToByteClamped(0.901961)); public static C3b LightCoral => new C3b(Col.DoubleToByteClamped(0.941176), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.501961)); public static C3b LightCyan => new C3b(Col.DoubleToByteClamped(0.878431), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1)); public static C3b LightGoldenRodYellow => new C3b(Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.823529)); public static C3b LightGray => new C3b(Col.DoubleToByteClamped(0.827451), Col.DoubleToByteClamped(0.827451), Col.DoubleToByteClamped(0.827451)); public static C3b LightGrey => new C3b(Col.DoubleToByteClamped(0.827451), Col.DoubleToByteClamped(0.827451), Col.DoubleToByteClamped(0.827451)); public static C3b LightGreen => new C3b(Col.DoubleToByteClamped(0.564706), Col.DoubleToByteClamped(0.933333), Col.DoubleToByteClamped(0.564706)); public static C3b LightPink => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.713725), Col.DoubleToByteClamped(0.756863)); public static C3b LightSalmon => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.627451), Col.DoubleToByteClamped(0.478431)); public static C3b LightSeaGreen => new C3b(Col.DoubleToByteClamped(0.12549), Col.DoubleToByteClamped(0.698039), Col.DoubleToByteClamped(0.666667)); public static C3b LightSkyBlue => new C3b(Col.DoubleToByteClamped(0.529412), Col.DoubleToByteClamped(0.807843), Col.DoubleToByteClamped(0.980392)); public static C3b LightSlateGray => new C3b(Col.DoubleToByteClamped(0.466667), Col.DoubleToByteClamped(0.533333), Col.DoubleToByteClamped(0.6)); public static C3b LightSlateGrey => new C3b(Col.DoubleToByteClamped(0.466667), Col.DoubleToByteClamped(0.533333), Col.DoubleToByteClamped(0.6)); public static C3b LightSteelBlue => new C3b(Col.DoubleToByteClamped(0.690196), Col.DoubleToByteClamped(0.768627), Col.DoubleToByteClamped(0.870588)); public static C3b LightYellow => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.878431)); public static C3b Lime => new C3b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0)); public static C3b LimeGreen => new C3b(Col.DoubleToByteClamped(0.196078), Col.DoubleToByteClamped(0.803922), Col.DoubleToByteClamped(0.196078)); public static C3b Linen => new C3b(Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.941176), Col.DoubleToByteClamped(0.901961)); public static C3b Magenta => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(1)); public static C3b Maroon => new C3b(Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0)); public static C3b MediumAquaMarine => new C3b(Col.DoubleToByteClamped(0.4), Col.DoubleToByteClamped(0.803922), Col.DoubleToByteClamped(0.666667)); public static C3b MediumBlue => new C3b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.803922)); public static C3b MediumOrchid => new C3b(Col.DoubleToByteClamped(0.729412), Col.DoubleToByteClamped(0.333333), Col.DoubleToByteClamped(0.827451)); public static C3b MediumPurple => new C3b(Col.DoubleToByteClamped(0.576471), Col.DoubleToByteClamped(0.439216), Col.DoubleToByteClamped(0.847059)); public static C3b MediumSeaGreen => new C3b(Col.DoubleToByteClamped(0.235294), Col.DoubleToByteClamped(0.701961), Col.DoubleToByteClamped(0.443137)); public static C3b MediumSlateBlue => new C3b(Col.DoubleToByteClamped(0.482353), Col.DoubleToByteClamped(0.407843), Col.DoubleToByteClamped(0.933333)); public static C3b MediumSpringGreen => new C3b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.603922)); public static C3b MediumTurquoise => new C3b(Col.DoubleToByteClamped(0.282353), Col.DoubleToByteClamped(0.819608), Col.DoubleToByteClamped(0.8)); public static C3b MediumVioletRed => new C3b(Col.DoubleToByteClamped(0.780392), Col.DoubleToByteClamped(0.082353), Col.DoubleToByteClamped(0.521569)); public static C3b MidnightBlue => new C3b(Col.DoubleToByteClamped(0.098039), Col.DoubleToByteClamped(0.098039), Col.DoubleToByteClamped(0.439216)); public static C3b MintCream => new C3b(Col.DoubleToByteClamped(0.960784), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.980392)); public static C3b MistyRose => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.894118), Col.DoubleToByteClamped(0.882353)); public static C3b Moccasin => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.894118), Col.DoubleToByteClamped(0.709804)); public static C3b NavajoWhite => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.870588), Col.DoubleToByteClamped(0.678431)); public static C3b Navy => new C3b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.501961)); public static C3b OldLace => new C3b(Col.DoubleToByteClamped(0.992157), Col.DoubleToByteClamped(0.960784), Col.DoubleToByteClamped(0.901961)); public static C3b Olive => new C3b(Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0)); public static C3b OliveDrab => new C3b(Col.DoubleToByteClamped(0.419608), Col.DoubleToByteClamped(0.556863), Col.DoubleToByteClamped(0.137255)); public static C3b Orange => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.647059), Col.DoubleToByteClamped(0)); public static C3b OrangeRed => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.270588), Col.DoubleToByteClamped(0)); public static C3b Orchid => new C3b(Col.DoubleToByteClamped(0.854902), Col.DoubleToByteClamped(0.439216), Col.DoubleToByteClamped(0.839216)); public static C3b PaleGoldenRod => new C3b(Col.DoubleToByteClamped(0.933333), Col.DoubleToByteClamped(0.909804), Col.DoubleToByteClamped(0.666667)); public static C3b PaleGreen => new C3b(Col.DoubleToByteClamped(0.596078), Col.DoubleToByteClamped(0.984314), Col.DoubleToByteClamped(0.596078)); public static C3b PaleTurquoise => new C3b(Col.DoubleToByteClamped(0.686275), Col.DoubleToByteClamped(0.933333), Col.DoubleToByteClamped(0.933333)); public static C3b PaleVioletRed => new C3b(Col.DoubleToByteClamped(0.847059), Col.DoubleToByteClamped(0.439216), Col.DoubleToByteClamped(0.576471)); public static C3b PapayaWhip => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.937255), Col.DoubleToByteClamped(0.835294)); public static C3b PeachPuff => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.854902), Col.DoubleToByteClamped(0.72549)); public static C3b Peru => new C3b(Col.DoubleToByteClamped(0.803922), Col.DoubleToByteClamped(0.521569), Col.DoubleToByteClamped(0.247059)); public static C3b Pink => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.752941), Col.DoubleToByteClamped(0.796078)); public static C3b Plum => new C3b(Col.DoubleToByteClamped(0.866667), Col.DoubleToByteClamped(0.627451), Col.DoubleToByteClamped(0.866667)); public static C3b PowderBlue => new C3b(Col.DoubleToByteClamped(0.690196), Col.DoubleToByteClamped(0.878431), Col.DoubleToByteClamped(0.901961)); public static C3b Purple => new C3b(Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.501961)); public static C3b Red => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0)); public static C3b RosyBrown => new C3b(Col.DoubleToByteClamped(0.737255), Col.DoubleToByteClamped(0.560784), Col.DoubleToByteClamped(0.560784)); public static C3b RoyalBlue => new C3b(Col.DoubleToByteClamped(0.254902), Col.DoubleToByteClamped(0.411765), Col.DoubleToByteClamped(0.882353)); public static C3b SaddleBrown => new C3b(Col.DoubleToByteClamped(0.545098), Col.DoubleToByteClamped(0.270588), Col.DoubleToByteClamped(0.07451)); public static C3b Salmon => new C3b(Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.447059)); public static C3b SandyBrown => new C3b(Col.DoubleToByteClamped(0.956863), Col.DoubleToByteClamped(0.643137), Col.DoubleToByteClamped(0.376471)); public static C3b SeaGreen => new C3b(Col.DoubleToByteClamped(0.180392), Col.DoubleToByteClamped(0.545098), Col.DoubleToByteClamped(0.341176)); public static C3b SeaShell => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.960784), Col.DoubleToByteClamped(0.933333)); public static C3b Sienna => new C3b(Col.DoubleToByteClamped(0.627451), Col.DoubleToByteClamped(0.321569), Col.DoubleToByteClamped(0.176471)); public static C3b Silver => new C3b(Col.DoubleToByteClamped(0.752941), Col.DoubleToByteClamped(0.752941), Col.DoubleToByteClamped(0.752941)); public static C3b SkyBlue => new C3b(Col.DoubleToByteClamped(0.529412), Col.DoubleToByteClamped(0.807843), Col.DoubleToByteClamped(0.921569)); public static C3b SlateBlue => new C3b(Col.DoubleToByteClamped(0.415686), Col.DoubleToByteClamped(0.352941), Col.DoubleToByteClamped(0.803922)); public static C3b SlateGray => new C3b(Col.DoubleToByteClamped(0.439216), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.564706)); public static C3b SlateGrey => new C3b(Col.DoubleToByteClamped(0.439216), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.564706)); public static C3b Snow => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.980392)); public static C3b SpringGreen => new C3b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.498039)); public static C3b SteelBlue => new C3b(Col.DoubleToByteClamped(0.27451), Col.DoubleToByteClamped(0.509804), Col.DoubleToByteClamped(0.705882)); public static C3b Tan => new C3b(Col.DoubleToByteClamped(0.823529), Col.DoubleToByteClamped(0.705882), Col.DoubleToByteClamped(0.54902)); public static C3b Teal => new C3b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.501961)); public static C3b Thistle => new C3b(Col.DoubleToByteClamped(0.847059), Col.DoubleToByteClamped(0.74902), Col.DoubleToByteClamped(0.847059)); public static C3b Tomato => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.388235), Col.DoubleToByteClamped(0.278431)); public static C3b Turquoise => new C3b(Col.DoubleToByteClamped(0.25098), Col.DoubleToByteClamped(0.878431), Col.DoubleToByteClamped(0.815686)); public static C3b Violet => new C3b(Col.DoubleToByteClamped(0.933333), Col.DoubleToByteClamped(0.509804), Col.DoubleToByteClamped(0.933333)); public static C3b Wheat => new C3b(Col.DoubleToByteClamped(0.960784), Col.DoubleToByteClamped(0.870588), Col.DoubleToByteClamped(0.701961)); public static C3b White => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1)); public static C3b WhiteSmoke => new C3b(Col.DoubleToByteClamped(0.960784), Col.DoubleToByteClamped(0.960784), Col.DoubleToByteClamped(0.960784)); public static C3b Yellow => new C3b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0)); public static C3b YellowGreen => new C3b(Col.DoubleToByteClamped(0.603922), Col.DoubleToByteClamped(0.803922), Col.DoubleToByteClamped(0.196078)); public static C3b DarkYellow => Olive; public static C3b VRVisGreen => new C3b(Col.DoubleToByteClamped(0.698), Col.DoubleToByteClamped(0.851), Col.DoubleToByteClamped(0.008)); public static C3b Gray10 => new C3b(Col.DoubleToByteClamped(0.1)); public static C3b Gray20 => new C3b(Col.DoubleToByteClamped(0.2)); public static C3b Gray30 => new C3b(Col.DoubleToByteClamped(0.3)); public static C3b Gray40 => new C3b(Col.DoubleToByteClamped(0.4)); public static C3b Gray50 => new C3b(Col.DoubleToByteClamped(0.5)); public static C3b Gray60 => new C3b(Col.DoubleToByteClamped(0.6)); public static C3b Gray70 => new C3b(Col.DoubleToByteClamped(0.7)); public static C3b Gray80 => new C3b(Col.DoubleToByteClamped(0.8)); public static C3b Gray90 => new C3b(Col.DoubleToByteClamped(0.9)); #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(C3b a, C3b b) { return a.R == b.R && a.G == b.G && a.B == b.B; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(C3b a, C3b b) { return a.R != b.R || a.G != b.G || a.B != b.B; } #endregion #region Color Arithmetic [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator *(C3b col, float scalar) { return new C3b( Col.FloatToByteClamped(Col.ByteToFloat(col.R) * scalar), Col.FloatToByteClamped(Col.ByteToFloat(col.G) * scalar), Col.FloatToByteClamped(Col.ByteToFloat(col.B) * scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator *(float scalar, C3b col) => col * scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator /(C3b col, float scalar) => col * (1 / scalar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator /(float scalar, C3b col) { return new C3b( Col.FloatToByteClamped(scalar / Col.ByteToFloat(col.R)), Col.FloatToByteClamped(scalar / Col.ByteToFloat(col.G)), Col.FloatToByteClamped(scalar / Col.ByteToFloat(col.B))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator *(C3b col, double scalar) { return new C3b( Col.DoubleToByteClamped(Col.ByteToDouble(col.R) * scalar), Col.DoubleToByteClamped(Col.ByteToDouble(col.G) * scalar), Col.DoubleToByteClamped(Col.ByteToDouble(col.B) * scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator *(double scalar, C3b col) => col * scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator /(C3b col, double scalar) => col * (1 / scalar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator /(double scalar, C3b col) { return new C3b( Col.DoubleToByteClamped(scalar / Col.ByteToDouble(col.R)), Col.DoubleToByteClamped(scalar / Col.ByteToDouble(col.G)), Col.DoubleToByteClamped(scalar / Col.ByteToDouble(col.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator +(C3b c0, C3us c1) { return new C3b( (byte)(c0.R + Col.UShortToByte(c1.R)), (byte)(c0.G + Col.UShortToByte(c1.G)), (byte)(c0.B + Col.UShortToByte(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator -(C3b c0, C3us c1) { return new C3b( (byte)(c0.R - Col.UShortToByte(c1.R)), (byte)(c0.G - Col.UShortToByte(c1.G)), (byte)(c0.B - Col.UShortToByte(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator +(C3b c0, C3ui c1) { return new C3b( (byte)(c0.R + Col.UIntToByte(c1.R)), (byte)(c0.G + Col.UIntToByte(c1.G)), (byte)(c0.B + Col.UIntToByte(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator -(C3b c0, C3ui c1) { return new C3b( (byte)(c0.R - Col.UIntToByte(c1.R)), (byte)(c0.G - Col.UIntToByte(c1.G)), (byte)(c0.B - Col.UIntToByte(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator +(C3b c0, C3f c1) { return new C3b( (byte)(c0.R + Col.FloatToByte(c1.R)), (byte)(c0.G + Col.FloatToByte(c1.G)), (byte)(c0.B + Col.FloatToByte(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator -(C3b c0, C3f c1) { return new C3b( (byte)(c0.R - Col.FloatToByte(c1.R)), (byte)(c0.G - Col.FloatToByte(c1.G)), (byte)(c0.B - Col.FloatToByte(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator +(C3b c0, C3d c1) { return new C3b( (byte)(c0.R + Col.DoubleToByte(c1.R)), (byte)(c0.G + Col.DoubleToByte(c1.G)), (byte)(c0.B + Col.DoubleToByte(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator -(C3b c0, C3d c1) { return new C3b( (byte)(c0.R - Col.DoubleToByte(c1.R)), (byte)(c0.G - Col.DoubleToByte(c1.G)), (byte)(c0.B - Col.DoubleToByte(c1.B))); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator *(C3b col, byte scalar) { return new C3b((byte)(col.R * scalar), (byte)(col.G * scalar), (byte)(col.B * scalar)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator *(byte scalar, C3b col) { return new C3b((byte)(scalar * col.R), (byte)(scalar * col.G), (byte)(scalar * col.B)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator /(C3b col, byte scalar) { return new C3b((byte)(col.R / scalar), (byte)(col.G / scalar), (byte)(col.B / scalar)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator /(byte scalar, C3b col) { return new C3b((byte)(scalar / col.R), (byte)(scalar / col.G), (byte)(scalar / col.B)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator *(C3b c0, C3b c1) { return new C3b((byte)(c0.R * c1.R), (byte)(c0.G * c1.G), (byte)(c0.B * c1.B)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator /(C3b c0, C3b c1) { return new C3b((byte)(c0.R / c1.R), (byte)(c0.G / c1.G), (byte)(c0.B / c1.B)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator +(C3b c0, C3b c1) { return new C3b( (255 - c0.R > c1.R) ? c0.R + c1.R : 255, (255 - c0.G > c1.G) ? c0.G + c1.G : 255, (255 - c0.B > c1.B) ? c0.B + c1.B : 255 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator +(C3b col, byte scalar) { return new C3b( (255 - col.R > scalar) ? col.R + scalar : 255, (255 - col.G > scalar) ? col.G + scalar : 255, (255 - col.B > scalar) ? col.B + scalar : 255 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator +(byte scalar, C3b col) => col + scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator -(C3b c0, C3b c1) { return new C3b( (c0.R > c1.R) ? c0.R - c1.R : 0, (c0.G > c1.G) ? c0.G - c1.G : 0, (c0.B > c1.B) ? c0.B - c1.B : 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator -(C3b col, byte scalar) { return new C3b( (col.R > scalar) ? col.R - scalar : 0, (col.G > scalar) ? col.G - scalar : 0, (col.B > scalar) ? col.B - scalar : 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b operator -(byte scalar, C3b col) { return new C3b( (scalar > col.R) ? scalar - col.R : 0, (scalar > col.G) ? scalar - col.G : 0, (scalar > col.B) ? scalar - col.B : 0 ); } /// /// Clamps the color channels to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clamp(byte min, byte max) { R = R.Clamp(min, max); G = G.Clamp(min, max); B = B.Clamp(min, max); } /// /// Returns a copy with the color channels clamped to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b Clamped(byte min, byte max) { return new C3b(R.Clamp(min, max), G.Clamp(min, max), B.Clamp(min, max)); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |R| + |G| + |B|. /// public readonly int Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return R + G + B; } } /// /// Returns the Euclidean (or 2-) norm of the color. This is calculated /// as sqrt(R^2 + G^2 + B^2). /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(R * R + G * G + B * B); } } /// /// Returns the infinite (or maximum) norm of the color. This is /// calculated as max(|R|, |G|, |B|). /// public readonly byte NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(R, G, B); } } /// /// Returns the minimum norm of the color. This is calculated as /// min(|R|, |G|, |B|). /// public readonly byte NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(R, G, B); } } #endregion #region Overrides public override readonly bool Equals(object other) => (other is C3b o) ? Equals(o) : false; public override readonly int GetHashCode() { return HashCode.GetCombined(R, G, B); } public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + R.ToString(null, CultureInfo.InvariantCulture) + ", " + G.ToString(null, CultureInfo.InvariantCulture) + ", " + B.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref C3b color, int i, byte value) => { switch (i) { case 0: color.R = value; return; case 1: color.G = value; return; case 2: color.B = value; return; default: throw new IndexOutOfRangeException(); } }; [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b LinearInterp(float t, C3b a, C3b b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b LinearInterp(V3f t, C3b a, C3b b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b LinearInterp(double t, C3b a, C3b b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b LinearInterp(V3d t, C3b a, C3b b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b DivideByInt(C3b c, int x) => c / x; #endregion #region Parsing /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C3b.Zero otherwise. /// True on success, false otherwise. public static bool TryParse(Text t, out C3b result) { if (Col.TryParseHex(t, out C4b tmp)) { result = tmp.ToC3b(); return true; } else { bool success = true; byte[] values = new byte[4] { 255, 255, 255, 255 }; byte parse(Text t) { if (!byte.TryParse(t.ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out byte value)) success = false; return value; }; var count = t.NestedBracketSplitCount2(1); if (count == 3 || count == 4) t.NestedBracketSplit(1, parse, () => values); else success = false; result = success ? new C3b(values) : Zero; return success; } } /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C3b.Zero otherwise. /// True on success, false otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParse(string s, out C3b result) => TryParse(new Text(s), out result); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C3b color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b Parse(string s) => Parse(new Text(s)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b Parse(Text t, int bracketLevel = 1) => t.NestedBracketSplit(bracketLevel, Text.Parse, C3b.Setter); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C3b color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b Parse(Text t) => TryParse(t, out C3b result) ? result : throw new FormatException($"{t} is not a valid C3b color."); #endregion #region IFormattable Members public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + R.ToString(format, fp) + between + G.ToString(format, fp) + between + B.ToString(format, fp) + end; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(C3b other) { return R.Equals(other.R) && G.Equals(other.G) && B.Equals(other.B); } #endregion #region IRGB Members double IRGB.Red { readonly get { return Col.ByteToDouble(R); } set { R = Col.DoubleToByteClamped(value); } } double IRGB.Green { readonly get { return Col.ByteToDouble(G); } set { G = Col.DoubleToByteClamped(value); } } double IRGB.Blue { readonly get { return Col.ByteToDouble(B); } set { B = Col.DoubleToByteClamped(value); } } #endregion } public static partial class Fun { #region Interpolation /// /// Returns the linearly interpolated color between a and b. /// public static C3b Lerp(this float t, C3b a, C3b b) => new C3b(Lerp(t, a.R, b.R), Lerp(t, a.G, b.G), Lerp(t, a.B, b.B)); /// /// Returns the linearly interpolated color between a and b. /// public static C3b Lerp(this V3f t, C3b a, C3b b) => new C3b(Lerp(t.X, a.R, b.R), Lerp(t.Y, a.G, b.G), Lerp(t.Z, a.B, b.B)); /// /// Returns the linearly interpolated color between a and b. /// public static C3b Lerp(this double t, C3b a, C3b b) => new C3b(Lerp(t, a.R, b.R), Lerp(t, a.G, b.G), Lerp(t, a.B, b.B)); /// /// Returns the linearly interpolated color between a and b. /// public static C3b Lerp(this V3d t, C3b a, C3b b) => new C3b(Lerp(t.X, a.R, b.R), Lerp(t.Y, a.G, b.G), Lerp(t.Z, a.B, b.B)); #endregion #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this C3b a, C3b b, byte tolerance) { return ApproximateEquals(a.R, b.R, tolerance) && ApproximateEquals(a.G, b.G, tolerance) && ApproximateEquals(a.B, b.B, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this C3b c, byte epsilon) => Col.AllTiny(c, epsilon); #endregion } public static partial class Col { #region ToHexString /// /// Returns the hexadecimal representation with format RRGGBB. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToHexString(this C3b c) => $"{c.R:X2}{c.G:X2}{c.B:X2}"; #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C3b a, C3b b) { return (a.R < b.R && a.G < b.G && a.B < b.B); } /// /// Returns whether ALL elements of col are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C3b col, byte s) { return (col.R < s && col.G < s && col.B < s); } /// /// Returns whether a is Smaller ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(byte s, C3b col) { return (s < col.R && s < col.G && s < col.B); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C3b a, C3b b) { return (a.R < b.R || a.G < b.G || a.B < b.B); } /// /// Returns whether AT LEAST ONE element of col is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C3b col, byte s) { return (col.R < s || col.G < s || col.B < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(byte s, C3b col) { return (s < col.R || s < col.G || s < col.B); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C3b a, C3b b) { return (a.R > b.R && a.G > b.G && a.B > b.B); } /// /// Returns whether ALL elements of col are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C3b col, byte s) { return (col.R > s && col.G > s && col.B > s); } /// /// Returns whether a is Greater ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(byte s, C3b col) { return (s > col.R && s > col.G && s > col.B); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C3b a, C3b b) { return (a.R > b.R || a.G > b.G || a.B > b.B); } /// /// Returns whether AT LEAST ONE element of col is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C3b col, byte s) { return (col.R > s || col.G > s || col.B > s); } /// /// Returns whether a is Greater AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(byte s, C3b col) { return (s > col.R || s > col.G || s > col.B); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C3b a, C3b b) { return (a.R <= b.R && a.G <= b.G && a.B <= b.B); } /// /// Returns whether ALL elements of col are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C3b col, byte s) { return (col.R <= s && col.G <= s && col.B <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(byte s, C3b col) { return (s <= col.R && s <= col.G && s <= col.B); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C3b a, C3b b) { return (a.R <= b.R || a.G <= b.G || a.B <= b.B); } /// /// Returns whether AT LEAST ONE element of col is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C3b col, byte s) { return (col.R <= s || col.G <= s || col.B <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(byte s, C3b col) { return (s <= col.R || s <= col.G || s <= col.B); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C3b a, C3b b) { return (a.R >= b.R && a.G >= b.G && a.B >= b.B); } /// /// Returns whether ALL elements of col are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C3b col, byte s) { return (col.R >= s && col.G >= s && col.B >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(byte s, C3b col) { return (s >= col.R && s >= col.G && s >= col.B); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C3b a, C3b b) { return (a.R >= b.R || a.G >= b.G || a.B >= b.B); } /// /// Returns whether AT LEAST ONE element of col is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C3b col, byte s) { return (col.R >= s || col.G >= s || col.B >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(byte s, C3b col) { return (s >= col.R || s >= col.G || s >= col.B); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C3b a, C3b b) { return (a.R == b.R && a.G == b.G && a.B == b.B); } /// /// Returns whether ALL elements of col are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C3b col, byte s) { return (col.R == s && col.G == s && col.B == s); } /// /// Returns whether a is Equal ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(byte s, C3b col) { return (s == col.R && s == col.G && s == col.B); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C3b a, C3b b) { return (a.R == b.R || a.G == b.G || a.B == b.B); } /// /// Returns whether AT LEAST ONE element of col is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C3b col, byte s) { return (col.R == s || col.G == s || col.B == s); } /// /// Returns whether a is Equal AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(byte s, C3b col) { return (s == col.R || s == col.G || s == col.B); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C3b a, C3b b) { return (a.R != b.R && a.G != b.G && a.B != b.B); } /// /// Returns whether ALL elements of col are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C3b col, byte s) { return (col.R != s && col.G != s && col.B != s); } /// /// Returns whether a is Different ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(byte s, C3b col) { return (s != col.R && s != col.G && s != col.B); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C3b a, C3b b) { return (a.R != b.R || a.G != b.G || a.B != b.B); } /// /// Returns whether AT LEAST ONE element of col is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C3b col, byte s) { return (col.R != s || col.G != s || col.B != s); } /// /// Returns whether a is Different AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(byte s, C3b col) { return (s != col.R || s != col.G || s != col.B); } #endregion #region Linear Combination /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b LinCom( C3b p0, C3b p1, C3b p2, C3b p3, ref Tup4 w) { return new C3b( Col.ByteInFloatToByteClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3), Col.ByteInFloatToByteClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3), Col.ByteInFloatToByteClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f LinComRawF( C3b p0, C3b p1, C3b p2, C3b p3, ref Tup4 w) { return new C3f( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b LinCom( C3b p0, C3b p1, C3b p2, C3b p3, ref Tup4 w) { return new C3b( Col.ByteInDoubleToByteClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3), Col.ByteInDoubleToByteClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3), Col.ByteInDoubleToByteClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d LinComRawD( C3b p0, C3b p1, C3b p2, C3b p3, ref Tup4 w) { return new C3d( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b LinCom( C3b p0, C3b p1, C3b p2, C3b p3, C3b p4, C3b p5, ref Tup6 w) { return new C3b( Col.ByteInFloatToByteClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5), Col.ByteInFloatToByteClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5), Col.ByteInFloatToByteClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f LinComRawF( C3b p0, C3b p1, C3b p2, C3b p3, C3b p4, C3b p5, ref Tup6 w) { return new C3f( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3b LinCom( C3b p0, C3b p1, C3b p2, C3b p3, C3b p4, C3b p5, ref Tup6 w) { return new C3b( Col.ByteInDoubleToByteClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5), Col.ByteInDoubleToByteClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5), Col.ByteInDoubleToByteClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d LinComRawD( C3b p0, C3b p1, C3b p2, C3b p3, C3b p4, C3b p5, ref Tup6 w) { return new C3d( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5); } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this C3b c, byte epsilon) => c.R.IsTiny(epsilon) || c.G.IsTiny(epsilon) || c.B.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this C3b c, byte epsilon) => c.R.IsTiny(epsilon) && c.G.IsTiny(epsilon) && c.B.IsTiny(epsilon); #endregion } #endregion #region C3us /// /// Represents an RGB color with each channel stored as a value within [0, 2^16 - 1]. /// [Serializable] public partial struct C3us : IFormattable, IEquatable, IRGB { #region Constructors /// /// Creates a color from the given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(ushort r, ushort g, ushort b) { R = r; G = g; B = b; } /// /// Creates a color from the given values. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(int r, int g, int b) { R = (ushort)r; G = (ushort)g; B = (ushort)b; } /// /// Creates a color from the given values. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(long r, long g, long b) { R = (ushort)r; G = (ushort)g; B = (ushort)b; } /// /// Creates a color from the given values. /// The values are mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(float r, float g, float b) { R = Col.FloatToUShortClamped(r); G = Col.FloatToUShortClamped(g); B = Col.FloatToUShortClamped(b); } /// /// Creates a color from the given values. /// The values are mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(double r, double g, double b) { R = Col.DoubleToUShortClamped(r); G = Col.DoubleToUShortClamped(g); B = Col.DoubleToUShortClamped(b); } /// /// Creates a color from a single value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(ushort gray) { R = gray; G = gray; B = gray; } /// /// Creates a color from a single value. /// The value is mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(float gray) { var value = Col.FloatToUShortClamped(gray); R = value; G = value; B = value; } /// /// Creates a color from a single value. /// The value is mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(double gray) { var value = Col.DoubleToUShortClamped(gray); R = value; G = value; B = value; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(C3b color) { R = Col.ByteToUShort(color.R); G = Col.ByteToUShort(color.G); B = Col.ByteToUShort(color.B); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(C3us color) { R = (color.R); G = (color.G); B = (color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(C3ui color) { R = Col.UIntToUShort(color.R); G = Col.UIntToUShort(color.G); B = Col.UIntToUShort(color.B); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(C3f color) { R = Col.FloatToUShortClamped(color.R); G = Col.FloatToUShortClamped(color.G); B = Col.FloatToUShortClamped(color.B); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(C3d color) { R = Col.DoubleToUShortClamped(color.R); G = Col.DoubleToUShortClamped(color.G); B = Col.DoubleToUShortClamped(color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(C4b color) { R = Col.ByteToUShort(color.R); G = Col.ByteToUShort(color.G); B = Col.ByteToUShort(color.B); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(C4us color) { R = (color.R); G = (color.G); B = (color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(C4ui color) { R = Col.UIntToUShort(color.R); G = Col.UIntToUShort(color.G); B = Col.UIntToUShort(color.B); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(C4f color) { R = Col.FloatToUShortClamped(color.R); G = Col.FloatToUShortClamped(color.G); B = Col.FloatToUShortClamped(color.B); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(C4d color) { R = Col.DoubleToUShortClamped(color.R); G = Col.DoubleToUShortClamped(color.G); B = Col.DoubleToUShortClamped(color.B); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(V3i vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(V3ui vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(V3l vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(V3f vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(V3d vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(V4i vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(V4ui vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(V4l vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(V4f vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(V4d vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); } /// /// Creates a color from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(Func index_fun) { R = index_fun(0); G = index_fun(1); B = index_fun(2); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(byte[] values) { R = Col.ByteToUShort(values[0]); G = Col.ByteToUShort(values[1]); B = Col.ByteToUShort(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(byte[] values, int start) { R = Col.ByteToUShort(values[start + 0]); G = Col.ByteToUShort(values[start + 1]); B = Col.ByteToUShort(values[start + 2]); } /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(ushort[] values) { R = (values[0]); G = (values[1]); B = (values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(ushort[] values, int start) { R = (values[start + 0]); G = (values[start + 1]); B = (values[start + 2]); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(uint[] values) { R = Col.UIntToUShort(values[0]); G = Col.UIntToUShort(values[1]); B = Col.UIntToUShort(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(uint[] values, int start) { R = Col.UIntToUShort(values[start + 0]); G = Col.UIntToUShort(values[start + 1]); B = Col.UIntToUShort(values[start + 2]); } /// /// Creates a new color from the given array. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(float[] values) { R = Col.FloatToUShortClamped(values[0]); G = Col.FloatToUShortClamped(values[1]); B = Col.FloatToUShortClamped(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(float[] values, int start) { R = Col.FloatToUShortClamped(values[start + 0]); G = Col.FloatToUShortClamped(values[start + 1]); B = Col.FloatToUShortClamped(values[start + 2]); } /// /// Creates a new color from the given array. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(double[] values) { R = Col.DoubleToUShortClamped(values[0]); G = Col.DoubleToUShortClamped(values[1]); B = Col.DoubleToUShortClamped(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3us(double[] values, int start) { R = Col.DoubleToUShortClamped(values[start + 0]); G = Col.DoubleToUShortClamped(values[start + 1]); B = Col.DoubleToUShortClamped(values[start + 2]); } #endregion #region Conversions /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(C3b color) => new C3us(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromC3b(C3b c) => new C3us(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(C3ui color) => new C3us(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromC3ui(C3ui c) => new C3us(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(C3f color) => new C3us(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f ToC3f() => (C3f)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromC3f(C3f c) => new C3us(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(C3d color) => new C3us(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d ToC3d() => (C3d)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromC3d(C3d c) => new C3us(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(C4b color) => new C3us(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromC4b(C4b c) => new C3us(c); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(C4us color) => new C3us(color); /// /// Converts the given color to a color. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromC4us(C4us c) => new C3us(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(C4ui color) => new C3us(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromC4ui(C4ui c) => new C3us(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(C4f color) => new C3us(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f ToC4f() => (C4f)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromC4f(C4f c) => new C3us(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(C4d color) => new C3us(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d ToC4d() => (C4d)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromC4d(C4d c) => new C3us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(V3i v) => new C3us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromV3i(V3i c) => new C3us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(V3ui v) => new C3us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromV3ui(V3ui c) => new C3us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(V3l v) => new C3us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromV3l(V3l c) => new C3us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(V3f v) => new C3us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromV3f(V3f c) => new C3us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(V3d v) => new C3us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromV3d(V3d c) => new C3us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(V4i v) => new C3us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromV4i(V4i c) => new C3us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(V4ui v) => new C3us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromV4ui(V4ui c) => new C3us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(V4l v) => new C3us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromV4l(V4l c) => new C3us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(V4f v) => new C3us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromV4f(V4f c) => new C3us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(V4d v) => new C3us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us FromV4d(V4d c) => new C3us(c); /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(byte[] values) => new C3us(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator byte[](C3us color) => new byte[] { Col.UShortToByte(color.R), Col.UShortToByte(color.G), Col.UShortToByte(color.B) }; /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(ushort[] values) => new C3us(values); /// /// Creates a new array from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ushort[](C3us color) => new ushort[] { (color.R), (color.G), (color.B) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(uint[] values) => new C3us(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](C3us color) => new uint[] { Col.UShortToUInt(color.R), Col.UShortToUInt(color.G), Col.UShortToUInt(color.B) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(float[] values) => new C3us(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](C3us color) => new float[] { Col.UShortToFloat(color.R), Col.UShortToFloat(color.G), Col.UShortToFloat(color.B) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3us(double[] values) => new C3us(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](C3us color) => new double[] { Col.UShortToDouble(color.R), Col.UShortToDouble(color.G), Col.UShortToDouble(color.B) }; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b Map(Func channel_fun) { return new C3b(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us Map(Func channel_fun) { return new C3us(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui Map(Func channel_fun) { return new C3ui(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f Map(Func channel_fun) { return new C3f(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d Map(Func channel_fun) { return new C3d(channel_fun(R), channel_fun(G), channel_fun(B)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(R); array[start + 1] = element_fun(G); array[start + 2] = element_fun(B); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(R, 0); array[start + 1] = element_index_fun(G, 1); array[start + 2] = element_index_fun(B, 2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly ushort[] ToArray() => (ushort[])this; #endregion #region Indexer /// /// Indexer in canonical order 0=R, 1=G, 2=B, 3=A (availability depending on color type). /// public unsafe ushort this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (ushort* ptr = &R) { ptr[i] = value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (ushort* ptr = &R) { return ptr[i]; } } } #endregion #region Constants /// /// C3us with all components zero. /// public static C3us Zero => new C3us(0, 0, 0); // Web colors public static C3us AliceBlue => new C3us(Col.DoubleToUShortClamped(0.941176), Col.DoubleToUShortClamped(0.972549), Col.DoubleToUShortClamped(1)); public static C3us AntiqueWhite => new C3us(Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.921569), Col.DoubleToUShortClamped(0.843137)); public static C3us Aqua => new C3us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1)); public static C3us Aquamarine => new C3us(Col.DoubleToUShortClamped(0.498039), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.831373)); public static C3us Azure => new C3us(Col.DoubleToUShortClamped(0.941176), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1)); public static C3us Beige => new C3us(Col.DoubleToUShortClamped(0.960784), Col.DoubleToUShortClamped(0.960784), Col.DoubleToUShortClamped(0.862745)); public static C3us Bisque => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.894118), Col.DoubleToUShortClamped(0.768627)); public static C3us Black => new C3us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0)); public static C3us BlanchedAlmond => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.921569), Col.DoubleToUShortClamped(0.803922)); public static C3us Blue => new C3us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(1)); public static C3us BlueViolet => new C3us(Col.DoubleToUShortClamped(0.541176), Col.DoubleToUShortClamped(0.168627), Col.DoubleToUShortClamped(0.886275)); public static C3us Brown => new C3us(Col.DoubleToUShortClamped(0.647059), Col.DoubleToUShortClamped(0.164706), Col.DoubleToUShortClamped(0.164706)); public static C3us BurlyWood => new C3us(Col.DoubleToUShortClamped(0.870588), Col.DoubleToUShortClamped(0.721569), Col.DoubleToUShortClamped(0.529412)); public static C3us CadetBlue => new C3us(Col.DoubleToUShortClamped(0.372549), Col.DoubleToUShortClamped(0.619608), Col.DoubleToUShortClamped(0.627451)); public static C3us Chartreuse => new C3us(Col.DoubleToUShortClamped(0.498039), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0)); public static C3us Chocolate => new C3us(Col.DoubleToUShortClamped(0.823529), Col.DoubleToUShortClamped(0.411765), Col.DoubleToUShortClamped(0.117647)); public static C3us Coral => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.498039), Col.DoubleToUShortClamped(0.313725)); public static C3us CornflowerBlue => new C3us(Col.DoubleToUShortClamped(0.392157), Col.DoubleToUShortClamped(0.584314), Col.DoubleToUShortClamped(0.929412)); public static C3us Cornsilk => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.972549), Col.DoubleToUShortClamped(0.862745)); public static C3us Crimson => new C3us(Col.DoubleToUShortClamped(0.862745), Col.DoubleToUShortClamped(0.078431), Col.DoubleToUShortClamped(0.235294)); public static C3us Cyan => new C3us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1)); public static C3us DarkBlue => new C3us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.545098)); public static C3us DarkCyan => new C3us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.545098), Col.DoubleToUShortClamped(0.545098)); public static C3us DarkGoldenRod => new C3us(Col.DoubleToUShortClamped(0.721569), Col.DoubleToUShortClamped(0.52549), Col.DoubleToUShortClamped(0.043137)); public static C3us DarkGray => new C3us(Col.DoubleToUShortClamped(0.662745), Col.DoubleToUShortClamped(0.662745), Col.DoubleToUShortClamped(0.662745)); public static C3us DarkGrey => new C3us(Col.DoubleToUShortClamped(0.662745), Col.DoubleToUShortClamped(0.662745), Col.DoubleToUShortClamped(0.662745)); public static C3us DarkGreen => new C3us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.392157), Col.DoubleToUShortClamped(0)); public static C3us DarkKhaki => new C3us(Col.DoubleToUShortClamped(0.741176), Col.DoubleToUShortClamped(0.717647), Col.DoubleToUShortClamped(0.419608)); public static C3us DarkMagenta => new C3us(Col.DoubleToUShortClamped(0.545098), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.545098)); public static C3us DarkOliveGreen => new C3us(Col.DoubleToUShortClamped(0.333333), Col.DoubleToUShortClamped(0.419608), Col.DoubleToUShortClamped(0.184314)); public static C3us DarkOrange => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.54902), Col.DoubleToUShortClamped(0)); public static C3us DarkOrchid => new C3us(Col.DoubleToUShortClamped(0.6), Col.DoubleToUShortClamped(0.196078), Col.DoubleToUShortClamped(0.8)); public static C3us DarkRed => new C3us(Col.DoubleToUShortClamped(0.545098), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0)); public static C3us DarkSalmon => new C3us(Col.DoubleToUShortClamped(0.913725), Col.DoubleToUShortClamped(0.588235), Col.DoubleToUShortClamped(0.478431)); public static C3us DarkSeaGreen => new C3us(Col.DoubleToUShortClamped(0.560784), Col.DoubleToUShortClamped(0.737255), Col.DoubleToUShortClamped(0.560784)); public static C3us DarkSlateBlue => new C3us(Col.DoubleToUShortClamped(0.282353), Col.DoubleToUShortClamped(0.239216), Col.DoubleToUShortClamped(0.545098)); public static C3us DarkSlateGray => new C3us(Col.DoubleToUShortClamped(0.184314), Col.DoubleToUShortClamped(0.309804), Col.DoubleToUShortClamped(0.309804)); public static C3us DarkSlateGrey => new C3us(Col.DoubleToUShortClamped(0.184314), Col.DoubleToUShortClamped(0.309804), Col.DoubleToUShortClamped(0.309804)); public static C3us DarkTurquoise => new C3us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.807843), Col.DoubleToUShortClamped(0.819608)); public static C3us DarkViolet => new C3us(Col.DoubleToUShortClamped(0.580392), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.827451)); public static C3us DeepPink => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.078431), Col.DoubleToUShortClamped(0.576471)); public static C3us DeepSkyBlue => new C3us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.74902), Col.DoubleToUShortClamped(1)); public static C3us DimGray => new C3us(Col.DoubleToUShortClamped(0.411765), Col.DoubleToUShortClamped(0.411765), Col.DoubleToUShortClamped(0.411765)); public static C3us DimGrey => new C3us(Col.DoubleToUShortClamped(0.411765), Col.DoubleToUShortClamped(0.411765), Col.DoubleToUShortClamped(0.411765)); public static C3us DodgerBlue => new C3us(Col.DoubleToUShortClamped(0.117647), Col.DoubleToUShortClamped(0.564706), Col.DoubleToUShortClamped(1)); public static C3us FireBrick => new C3us(Col.DoubleToUShortClamped(0.698039), Col.DoubleToUShortClamped(0.133333), Col.DoubleToUShortClamped(0.133333)); public static C3us FloralWhite => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.941176)); public static C3us ForestGreen => new C3us(Col.DoubleToUShortClamped(0.133333), Col.DoubleToUShortClamped(0.545098), Col.DoubleToUShortClamped(0.133333)); public static C3us Fuchsia => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(1)); public static C3us Gainsboro => new C3us(Col.DoubleToUShortClamped(0.862745), Col.DoubleToUShortClamped(0.862745), Col.DoubleToUShortClamped(0.862745)); public static C3us GhostWhite => new C3us(Col.DoubleToUShortClamped(0.972549), Col.DoubleToUShortClamped(0.972549), Col.DoubleToUShortClamped(1)); public static C3us Gold => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.843137), Col.DoubleToUShortClamped(0)); public static C3us GoldenRod => new C3us(Col.DoubleToUShortClamped(0.854902), Col.DoubleToUShortClamped(0.647059), Col.DoubleToUShortClamped(0.12549)); public static C3us Gray => new C3us(Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.501961)); public static C3us Grey => new C3us(Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.501961)); public static C3us Green => new C3us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0)); public static C3us GreenYellow => new C3us(Col.DoubleToUShortClamped(0.678431), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.184314)); public static C3us HoneyDew => new C3us(Col.DoubleToUShortClamped(0.941176), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.941176)); public static C3us HotPink => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.411765), Col.DoubleToUShortClamped(0.705882)); public static C3us IndianRed => new C3us(Col.DoubleToUShortClamped(0.803922), Col.DoubleToUShortClamped(0.360784), Col.DoubleToUShortClamped(0.360784)); public static C3us Indigo => new C3us(Col.DoubleToUShortClamped(0.294118), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.509804)); public static C3us Ivory => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.941176)); public static C3us Khaki => new C3us(Col.DoubleToUShortClamped(0.941176), Col.DoubleToUShortClamped(0.901961), Col.DoubleToUShortClamped(0.54902)); public static C3us Lavender => new C3us(Col.DoubleToUShortClamped(0.901961), Col.DoubleToUShortClamped(0.901961), Col.DoubleToUShortClamped(0.980392)); public static C3us LavenderBlush => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.941176), Col.DoubleToUShortClamped(0.960784)); public static C3us LawnGreen => new C3us(Col.DoubleToUShortClamped(0.486275), Col.DoubleToUShortClamped(0.988235), Col.DoubleToUShortClamped(0)); public static C3us LemonChiffon => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.803922)); public static C3us LightBlue => new C3us(Col.DoubleToUShortClamped(0.678431), Col.DoubleToUShortClamped(0.847059), Col.DoubleToUShortClamped(0.901961)); public static C3us LightCoral => new C3us(Col.DoubleToUShortClamped(0.941176), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.501961)); public static C3us LightCyan => new C3us(Col.DoubleToUShortClamped(0.878431), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1)); public static C3us LightGoldenRodYellow => new C3us(Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.823529)); public static C3us LightGray => new C3us(Col.DoubleToUShortClamped(0.827451), Col.DoubleToUShortClamped(0.827451), Col.DoubleToUShortClamped(0.827451)); public static C3us LightGrey => new C3us(Col.DoubleToUShortClamped(0.827451), Col.DoubleToUShortClamped(0.827451), Col.DoubleToUShortClamped(0.827451)); public static C3us LightGreen => new C3us(Col.DoubleToUShortClamped(0.564706), Col.DoubleToUShortClamped(0.933333), Col.DoubleToUShortClamped(0.564706)); public static C3us LightPink => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.713725), Col.DoubleToUShortClamped(0.756863)); public static C3us LightSalmon => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.627451), Col.DoubleToUShortClamped(0.478431)); public static C3us LightSeaGreen => new C3us(Col.DoubleToUShortClamped(0.12549), Col.DoubleToUShortClamped(0.698039), Col.DoubleToUShortClamped(0.666667)); public static C3us LightSkyBlue => new C3us(Col.DoubleToUShortClamped(0.529412), Col.DoubleToUShortClamped(0.807843), Col.DoubleToUShortClamped(0.980392)); public static C3us LightSlateGray => new C3us(Col.DoubleToUShortClamped(0.466667), Col.DoubleToUShortClamped(0.533333), Col.DoubleToUShortClamped(0.6)); public static C3us LightSlateGrey => new C3us(Col.DoubleToUShortClamped(0.466667), Col.DoubleToUShortClamped(0.533333), Col.DoubleToUShortClamped(0.6)); public static C3us LightSteelBlue => new C3us(Col.DoubleToUShortClamped(0.690196), Col.DoubleToUShortClamped(0.768627), Col.DoubleToUShortClamped(0.870588)); public static C3us LightYellow => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.878431)); public static C3us Lime => new C3us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0)); public static C3us LimeGreen => new C3us(Col.DoubleToUShortClamped(0.196078), Col.DoubleToUShortClamped(0.803922), Col.DoubleToUShortClamped(0.196078)); public static C3us Linen => new C3us(Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.941176), Col.DoubleToUShortClamped(0.901961)); public static C3us Magenta => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(1)); public static C3us Maroon => new C3us(Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0)); public static C3us MediumAquaMarine => new C3us(Col.DoubleToUShortClamped(0.4), Col.DoubleToUShortClamped(0.803922), Col.DoubleToUShortClamped(0.666667)); public static C3us MediumBlue => new C3us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.803922)); public static C3us MediumOrchid => new C3us(Col.DoubleToUShortClamped(0.729412), Col.DoubleToUShortClamped(0.333333), Col.DoubleToUShortClamped(0.827451)); public static C3us MediumPurple => new C3us(Col.DoubleToUShortClamped(0.576471), Col.DoubleToUShortClamped(0.439216), Col.DoubleToUShortClamped(0.847059)); public static C3us MediumSeaGreen => new C3us(Col.DoubleToUShortClamped(0.235294), Col.DoubleToUShortClamped(0.701961), Col.DoubleToUShortClamped(0.443137)); public static C3us MediumSlateBlue => new C3us(Col.DoubleToUShortClamped(0.482353), Col.DoubleToUShortClamped(0.407843), Col.DoubleToUShortClamped(0.933333)); public static C3us MediumSpringGreen => new C3us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.603922)); public static C3us MediumTurquoise => new C3us(Col.DoubleToUShortClamped(0.282353), Col.DoubleToUShortClamped(0.819608), Col.DoubleToUShortClamped(0.8)); public static C3us MediumVioletRed => new C3us(Col.DoubleToUShortClamped(0.780392), Col.DoubleToUShortClamped(0.082353), Col.DoubleToUShortClamped(0.521569)); public static C3us MidnightBlue => new C3us(Col.DoubleToUShortClamped(0.098039), Col.DoubleToUShortClamped(0.098039), Col.DoubleToUShortClamped(0.439216)); public static C3us MintCream => new C3us(Col.DoubleToUShortClamped(0.960784), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.980392)); public static C3us MistyRose => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.894118), Col.DoubleToUShortClamped(0.882353)); public static C3us Moccasin => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.894118), Col.DoubleToUShortClamped(0.709804)); public static C3us NavajoWhite => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.870588), Col.DoubleToUShortClamped(0.678431)); public static C3us Navy => new C3us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.501961)); public static C3us OldLace => new C3us(Col.DoubleToUShortClamped(0.992157), Col.DoubleToUShortClamped(0.960784), Col.DoubleToUShortClamped(0.901961)); public static C3us Olive => new C3us(Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0)); public static C3us OliveDrab => new C3us(Col.DoubleToUShortClamped(0.419608), Col.DoubleToUShortClamped(0.556863), Col.DoubleToUShortClamped(0.137255)); public static C3us Orange => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.647059), Col.DoubleToUShortClamped(0)); public static C3us OrangeRed => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.270588), Col.DoubleToUShortClamped(0)); public static C3us Orchid => new C3us(Col.DoubleToUShortClamped(0.854902), Col.DoubleToUShortClamped(0.439216), Col.DoubleToUShortClamped(0.839216)); public static C3us PaleGoldenRod => new C3us(Col.DoubleToUShortClamped(0.933333), Col.DoubleToUShortClamped(0.909804), Col.DoubleToUShortClamped(0.666667)); public static C3us PaleGreen => new C3us(Col.DoubleToUShortClamped(0.596078), Col.DoubleToUShortClamped(0.984314), Col.DoubleToUShortClamped(0.596078)); public static C3us PaleTurquoise => new C3us(Col.DoubleToUShortClamped(0.686275), Col.DoubleToUShortClamped(0.933333), Col.DoubleToUShortClamped(0.933333)); public static C3us PaleVioletRed => new C3us(Col.DoubleToUShortClamped(0.847059), Col.DoubleToUShortClamped(0.439216), Col.DoubleToUShortClamped(0.576471)); public static C3us PapayaWhip => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.937255), Col.DoubleToUShortClamped(0.835294)); public static C3us PeachPuff => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.854902), Col.DoubleToUShortClamped(0.72549)); public static C3us Peru => new C3us(Col.DoubleToUShortClamped(0.803922), Col.DoubleToUShortClamped(0.521569), Col.DoubleToUShortClamped(0.247059)); public static C3us Pink => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.752941), Col.DoubleToUShortClamped(0.796078)); public static C3us Plum => new C3us(Col.DoubleToUShortClamped(0.866667), Col.DoubleToUShortClamped(0.627451), Col.DoubleToUShortClamped(0.866667)); public static C3us PowderBlue => new C3us(Col.DoubleToUShortClamped(0.690196), Col.DoubleToUShortClamped(0.878431), Col.DoubleToUShortClamped(0.901961)); public static C3us Purple => new C3us(Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.501961)); public static C3us Red => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0)); public static C3us RosyBrown => new C3us(Col.DoubleToUShortClamped(0.737255), Col.DoubleToUShortClamped(0.560784), Col.DoubleToUShortClamped(0.560784)); public static C3us RoyalBlue => new C3us(Col.DoubleToUShortClamped(0.254902), Col.DoubleToUShortClamped(0.411765), Col.DoubleToUShortClamped(0.882353)); public static C3us SaddleBrown => new C3us(Col.DoubleToUShortClamped(0.545098), Col.DoubleToUShortClamped(0.270588), Col.DoubleToUShortClamped(0.07451)); public static C3us Salmon => new C3us(Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.447059)); public static C3us SandyBrown => new C3us(Col.DoubleToUShortClamped(0.956863), Col.DoubleToUShortClamped(0.643137), Col.DoubleToUShortClamped(0.376471)); public static C3us SeaGreen => new C3us(Col.DoubleToUShortClamped(0.180392), Col.DoubleToUShortClamped(0.545098), Col.DoubleToUShortClamped(0.341176)); public static C3us SeaShell => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.960784), Col.DoubleToUShortClamped(0.933333)); public static C3us Sienna => new C3us(Col.DoubleToUShortClamped(0.627451), Col.DoubleToUShortClamped(0.321569), Col.DoubleToUShortClamped(0.176471)); public static C3us Silver => new C3us(Col.DoubleToUShortClamped(0.752941), Col.DoubleToUShortClamped(0.752941), Col.DoubleToUShortClamped(0.752941)); public static C3us SkyBlue => new C3us(Col.DoubleToUShortClamped(0.529412), Col.DoubleToUShortClamped(0.807843), Col.DoubleToUShortClamped(0.921569)); public static C3us SlateBlue => new C3us(Col.DoubleToUShortClamped(0.415686), Col.DoubleToUShortClamped(0.352941), Col.DoubleToUShortClamped(0.803922)); public static C3us SlateGray => new C3us(Col.DoubleToUShortClamped(0.439216), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.564706)); public static C3us SlateGrey => new C3us(Col.DoubleToUShortClamped(0.439216), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.564706)); public static C3us Snow => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.980392)); public static C3us SpringGreen => new C3us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.498039)); public static C3us SteelBlue => new C3us(Col.DoubleToUShortClamped(0.27451), Col.DoubleToUShortClamped(0.509804), Col.DoubleToUShortClamped(0.705882)); public static C3us Tan => new C3us(Col.DoubleToUShortClamped(0.823529), Col.DoubleToUShortClamped(0.705882), Col.DoubleToUShortClamped(0.54902)); public static C3us Teal => new C3us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.501961)); public static C3us Thistle => new C3us(Col.DoubleToUShortClamped(0.847059), Col.DoubleToUShortClamped(0.74902), Col.DoubleToUShortClamped(0.847059)); public static C3us Tomato => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.388235), Col.DoubleToUShortClamped(0.278431)); public static C3us Turquoise => new C3us(Col.DoubleToUShortClamped(0.25098), Col.DoubleToUShortClamped(0.878431), Col.DoubleToUShortClamped(0.815686)); public static C3us Violet => new C3us(Col.DoubleToUShortClamped(0.933333), Col.DoubleToUShortClamped(0.509804), Col.DoubleToUShortClamped(0.933333)); public static C3us Wheat => new C3us(Col.DoubleToUShortClamped(0.960784), Col.DoubleToUShortClamped(0.870588), Col.DoubleToUShortClamped(0.701961)); public static C3us White => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1)); public static C3us WhiteSmoke => new C3us(Col.DoubleToUShortClamped(0.960784), Col.DoubleToUShortClamped(0.960784), Col.DoubleToUShortClamped(0.960784)); public static C3us Yellow => new C3us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0)); public static C3us YellowGreen => new C3us(Col.DoubleToUShortClamped(0.603922), Col.DoubleToUShortClamped(0.803922), Col.DoubleToUShortClamped(0.196078)); public static C3us DarkYellow => Olive; public static C3us VRVisGreen => new C3us(Col.DoubleToUShortClamped(0.698), Col.DoubleToUShortClamped(0.851), Col.DoubleToUShortClamped(0.008)); public static C3us Gray10 => new C3us(Col.DoubleToUShortClamped(0.1)); public static C3us Gray20 => new C3us(Col.DoubleToUShortClamped(0.2)); public static C3us Gray30 => new C3us(Col.DoubleToUShortClamped(0.3)); public static C3us Gray40 => new C3us(Col.DoubleToUShortClamped(0.4)); public static C3us Gray50 => new C3us(Col.DoubleToUShortClamped(0.5)); public static C3us Gray60 => new C3us(Col.DoubleToUShortClamped(0.6)); public static C3us Gray70 => new C3us(Col.DoubleToUShortClamped(0.7)); public static C3us Gray80 => new C3us(Col.DoubleToUShortClamped(0.8)); public static C3us Gray90 => new C3us(Col.DoubleToUShortClamped(0.9)); #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(C3us a, C3us b) { return a.R == b.R && a.G == b.G && a.B == b.B; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(C3us a, C3us b) { return a.R != b.R || a.G != b.G || a.B != b.B; } #endregion #region Color Arithmetic [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator *(C3us col, float scalar) { return new C3us( Col.FloatToUShortClamped(Col.UShortToFloat(col.R) * scalar), Col.FloatToUShortClamped(Col.UShortToFloat(col.G) * scalar), Col.FloatToUShortClamped(Col.UShortToFloat(col.B) * scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator *(float scalar, C3us col) => col * scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator /(C3us col, float scalar) => col * (1 / scalar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator /(float scalar, C3us col) { return new C3us( Col.FloatToUShortClamped(scalar / Col.UShortToFloat(col.R)), Col.FloatToUShortClamped(scalar / Col.UShortToFloat(col.G)), Col.FloatToUShortClamped(scalar / Col.UShortToFloat(col.B))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator *(C3us col, double scalar) { return new C3us( Col.DoubleToUShortClamped(Col.UShortToDouble(col.R) * scalar), Col.DoubleToUShortClamped(Col.UShortToDouble(col.G) * scalar), Col.DoubleToUShortClamped(Col.UShortToDouble(col.B) * scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator *(double scalar, C3us col) => col * scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator /(C3us col, double scalar) => col * (1 / scalar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator /(double scalar, C3us col) { return new C3us( Col.DoubleToUShortClamped(scalar / Col.UShortToDouble(col.R)), Col.DoubleToUShortClamped(scalar / Col.UShortToDouble(col.G)), Col.DoubleToUShortClamped(scalar / Col.UShortToDouble(col.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator +(C3us c0, C3b c1) { return new C3us( (ushort)(c0.R + Col.ByteToUShort(c1.R)), (ushort)(c0.G + Col.ByteToUShort(c1.G)), (ushort)(c0.B + Col.ByteToUShort(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator -(C3us c0, C3b c1) { return new C3us( (ushort)(c0.R - Col.ByteToUShort(c1.R)), (ushort)(c0.G - Col.ByteToUShort(c1.G)), (ushort)(c0.B - Col.ByteToUShort(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator +(C3us c0, C3ui c1) { return new C3us( (ushort)(c0.R + Col.UIntToUShort(c1.R)), (ushort)(c0.G + Col.UIntToUShort(c1.G)), (ushort)(c0.B + Col.UIntToUShort(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator -(C3us c0, C3ui c1) { return new C3us( (ushort)(c0.R - Col.UIntToUShort(c1.R)), (ushort)(c0.G - Col.UIntToUShort(c1.G)), (ushort)(c0.B - Col.UIntToUShort(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator +(C3us c0, C3f c1) { return new C3us( (ushort)(c0.R + Col.FloatToUShort(c1.R)), (ushort)(c0.G + Col.FloatToUShort(c1.G)), (ushort)(c0.B + Col.FloatToUShort(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator -(C3us c0, C3f c1) { return new C3us( (ushort)(c0.R - Col.FloatToUShort(c1.R)), (ushort)(c0.G - Col.FloatToUShort(c1.G)), (ushort)(c0.B - Col.FloatToUShort(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator +(C3us c0, C3d c1) { return new C3us( (ushort)(c0.R + Col.DoubleToUShort(c1.R)), (ushort)(c0.G + Col.DoubleToUShort(c1.G)), (ushort)(c0.B + Col.DoubleToUShort(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator -(C3us c0, C3d c1) { return new C3us( (ushort)(c0.R - Col.DoubleToUShort(c1.R)), (ushort)(c0.G - Col.DoubleToUShort(c1.G)), (ushort)(c0.B - Col.DoubleToUShort(c1.B))); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator *(C3us col, ushort scalar) { return new C3us((ushort)(col.R * scalar), (ushort)(col.G * scalar), (ushort)(col.B * scalar)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator *(ushort scalar, C3us col) { return new C3us((ushort)(scalar * col.R), (ushort)(scalar * col.G), (ushort)(scalar * col.B)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator /(C3us col, ushort scalar) { return new C3us((ushort)(col.R / scalar), (ushort)(col.G / scalar), (ushort)(col.B / scalar)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator /(ushort scalar, C3us col) { return new C3us((ushort)(scalar / col.R), (ushort)(scalar / col.G), (ushort)(scalar / col.B)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator *(C3us c0, C3us c1) { return new C3us((ushort)(c0.R * c1.R), (ushort)(c0.G * c1.G), (ushort)(c0.B * c1.B)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator /(C3us c0, C3us c1) { return new C3us((ushort)(c0.R / c1.R), (ushort)(c0.G / c1.G), (ushort)(c0.B / c1.B)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator +(C3us c0, C3us c1) { return new C3us( (65535 - c0.R > c1.R) ? c0.R + c1.R : 65535, (65535 - c0.G > c1.G) ? c0.G + c1.G : 65535, (65535 - c0.B > c1.B) ? c0.B + c1.B : 65535 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator +(C3us col, ushort scalar) { return new C3us( (65535 - col.R > scalar) ? col.R + scalar : 65535, (65535 - col.G > scalar) ? col.G + scalar : 65535, (65535 - col.B > scalar) ? col.B + scalar : 65535 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator +(ushort scalar, C3us col) => col + scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator -(C3us c0, C3us c1) { return new C3us( (c0.R > c1.R) ? c0.R - c1.R : 0, (c0.G > c1.G) ? c0.G - c1.G : 0, (c0.B > c1.B) ? c0.B - c1.B : 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator -(C3us col, ushort scalar) { return new C3us( (col.R > scalar) ? col.R - scalar : 0, (col.G > scalar) ? col.G - scalar : 0, (col.B > scalar) ? col.B - scalar : 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us operator -(ushort scalar, C3us col) { return new C3us( (scalar > col.R) ? scalar - col.R : 0, (scalar > col.G) ? scalar - col.G : 0, (scalar > col.B) ? scalar - col.B : 0 ); } /// /// Clamps the color channels to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clamp(ushort min, ushort max) { R = R.Clamp(min, max); G = G.Clamp(min, max); B = B.Clamp(min, max); } /// /// Returns a copy with the color channels clamped to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us Clamped(ushort min, ushort max) { return new C3us(R.Clamp(min, max), G.Clamp(min, max), B.Clamp(min, max)); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |R| + |G| + |B|. /// public readonly int Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return R + G + B; } } /// /// Returns the Euclidean (or 2-) norm of the color. This is calculated /// as sqrt(R^2 + G^2 + B^2). /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(R * R + G * G + B * B); } } /// /// Returns the infinite (or maximum) norm of the color. This is /// calculated as max(|R|, |G|, |B|). /// public readonly ushort NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(R, G, B); } } /// /// Returns the minimum norm of the color. This is calculated as /// min(|R|, |G|, |B|). /// public readonly ushort NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(R, G, B); } } #endregion #region Overrides public override readonly bool Equals(object other) => (other is C3us o) ? Equals(o) : false; public override readonly int GetHashCode() { return HashCode.GetCombined(R, G, B); } public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + R.ToString(null, CultureInfo.InvariantCulture) + ", " + G.ToString(null, CultureInfo.InvariantCulture) + ", " + B.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref C3us color, int i, ushort value) => { switch (i) { case 0: color.R = value; return; case 1: color.G = value; return; case 2: color.B = value; return; default: throw new IndexOutOfRangeException(); } }; [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us LinearInterp(float t, C3us a, C3us b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us LinearInterp(V3f t, C3us a, C3us b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us LinearInterp(double t, C3us a, C3us b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us LinearInterp(V3d t, C3us a, C3us b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us DivideByInt(C3us c, int x) => c / x; #endregion #region Parsing /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C3us.Zero otherwise. /// True on success, false otherwise. public static bool TryParse(Text t, out C3us result) { if (Col.TryParseHex(t, out C4b tmp)) { result = tmp.ToC3us(); return true; } else { bool success = true; ushort[] values = new ushort[4] { 65535, 65535, 65535, 65535 }; ushort parse(Text t) { if (!ushort.TryParse(t.ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out ushort value)) success = false; return value; }; var count = t.NestedBracketSplitCount2(1); if (count == 3 || count == 4) t.NestedBracketSplit(1, parse, () => values); else success = false; result = success ? new C3us(values) : Zero; return success; } } /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C3us.Zero otherwise. /// True on success, false otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParse(string s, out C3us result) => TryParse(new Text(s), out result); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C3us color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us Parse(string s) => Parse(new Text(s)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us Parse(Text t, int bracketLevel = 1) => t.NestedBracketSplit(bracketLevel, Text.Parse, C3us.Setter); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C3us color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us Parse(Text t) => TryParse(t, out C3us result) ? result : throw new FormatException($"{t} is not a valid C3us color."); #endregion #region IFormattable Members public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + R.ToString(format, fp) + between + G.ToString(format, fp) + between + B.ToString(format, fp) + end; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(C3us other) { return R.Equals(other.R) && G.Equals(other.G) && B.Equals(other.B); } #endregion #region IRGB Members double IRGB.Red { readonly get { return Col.UShortToDouble(R); } set { R = Col.DoubleToUShortClamped(value); } } double IRGB.Green { readonly get { return Col.UShortToDouble(G); } set { G = Col.DoubleToUShortClamped(value); } } double IRGB.Blue { readonly get { return Col.UShortToDouble(B); } set { B = Col.DoubleToUShortClamped(value); } } #endregion } public static partial class Fun { #region Interpolation /// /// Returns the linearly interpolated color between a and b. /// public static C3us Lerp(this float t, C3us a, C3us b) => new C3us(Lerp(t, a.R, b.R), Lerp(t, a.G, b.G), Lerp(t, a.B, b.B)); /// /// Returns the linearly interpolated color between a and b. /// public static C3us Lerp(this V3f t, C3us a, C3us b) => new C3us(Lerp(t.X, a.R, b.R), Lerp(t.Y, a.G, b.G), Lerp(t.Z, a.B, b.B)); /// /// Returns the linearly interpolated color between a and b. /// public static C3us Lerp(this double t, C3us a, C3us b) => new C3us(Lerp(t, a.R, b.R), Lerp(t, a.G, b.G), Lerp(t, a.B, b.B)); /// /// Returns the linearly interpolated color between a and b. /// public static C3us Lerp(this V3d t, C3us a, C3us b) => new C3us(Lerp(t.X, a.R, b.R), Lerp(t.Y, a.G, b.G), Lerp(t.Z, a.B, b.B)); #endregion #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this C3us a, C3us b, ushort tolerance) { return ApproximateEquals(a.R, b.R, tolerance) && ApproximateEquals(a.G, b.G, tolerance) && ApproximateEquals(a.B, b.B, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this C3us c, ushort epsilon) => Col.AllTiny(c, epsilon); #endregion } public static partial class Col { #region ToHexString /// /// Returns the hexadecimal representation with format RRGGBB. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToHexString(this C3us c) => c.ToC3b().ToHexString(); #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C3us a, C3us b) { return (a.R < b.R && a.G < b.G && a.B < b.B); } /// /// Returns whether ALL elements of col are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C3us col, ushort s) { return (col.R < s && col.G < s && col.B < s); } /// /// Returns whether a is Smaller ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(ushort s, C3us col) { return (s < col.R && s < col.G && s < col.B); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C3us a, C3us b) { return (a.R < b.R || a.G < b.G || a.B < b.B); } /// /// Returns whether AT LEAST ONE element of col is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C3us col, ushort s) { return (col.R < s || col.G < s || col.B < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(ushort s, C3us col) { return (s < col.R || s < col.G || s < col.B); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C3us a, C3us b) { return (a.R > b.R && a.G > b.G && a.B > b.B); } /// /// Returns whether ALL elements of col are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C3us col, ushort s) { return (col.R > s && col.G > s && col.B > s); } /// /// Returns whether a is Greater ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(ushort s, C3us col) { return (s > col.R && s > col.G && s > col.B); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C3us a, C3us b) { return (a.R > b.R || a.G > b.G || a.B > b.B); } /// /// Returns whether AT LEAST ONE element of col is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C3us col, ushort s) { return (col.R > s || col.G > s || col.B > s); } /// /// Returns whether a is Greater AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(ushort s, C3us col) { return (s > col.R || s > col.G || s > col.B); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C3us a, C3us b) { return (a.R <= b.R && a.G <= b.G && a.B <= b.B); } /// /// Returns whether ALL elements of col are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C3us col, ushort s) { return (col.R <= s && col.G <= s && col.B <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(ushort s, C3us col) { return (s <= col.R && s <= col.G && s <= col.B); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C3us a, C3us b) { return (a.R <= b.R || a.G <= b.G || a.B <= b.B); } /// /// Returns whether AT LEAST ONE element of col is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C3us col, ushort s) { return (col.R <= s || col.G <= s || col.B <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(ushort s, C3us col) { return (s <= col.R || s <= col.G || s <= col.B); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C3us a, C3us b) { return (a.R >= b.R && a.G >= b.G && a.B >= b.B); } /// /// Returns whether ALL elements of col are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C3us col, ushort s) { return (col.R >= s && col.G >= s && col.B >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(ushort s, C3us col) { return (s >= col.R && s >= col.G && s >= col.B); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C3us a, C3us b) { return (a.R >= b.R || a.G >= b.G || a.B >= b.B); } /// /// Returns whether AT LEAST ONE element of col is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C3us col, ushort s) { return (col.R >= s || col.G >= s || col.B >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(ushort s, C3us col) { return (s >= col.R || s >= col.G || s >= col.B); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C3us a, C3us b) { return (a.R == b.R && a.G == b.G && a.B == b.B); } /// /// Returns whether ALL elements of col are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C3us col, ushort s) { return (col.R == s && col.G == s && col.B == s); } /// /// Returns whether a is Equal ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(ushort s, C3us col) { return (s == col.R && s == col.G && s == col.B); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C3us a, C3us b) { return (a.R == b.R || a.G == b.G || a.B == b.B); } /// /// Returns whether AT LEAST ONE element of col is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C3us col, ushort s) { return (col.R == s || col.G == s || col.B == s); } /// /// Returns whether a is Equal AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(ushort s, C3us col) { return (s == col.R || s == col.G || s == col.B); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C3us a, C3us b) { return (a.R != b.R && a.G != b.G && a.B != b.B); } /// /// Returns whether ALL elements of col are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C3us col, ushort s) { return (col.R != s && col.G != s && col.B != s); } /// /// Returns whether a is Different ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(ushort s, C3us col) { return (s != col.R && s != col.G && s != col.B); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C3us a, C3us b) { return (a.R != b.R || a.G != b.G || a.B != b.B); } /// /// Returns whether AT LEAST ONE element of col is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C3us col, ushort s) { return (col.R != s || col.G != s || col.B != s); } /// /// Returns whether a is Different AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(ushort s, C3us col) { return (s != col.R || s != col.G || s != col.B); } #endregion #region Linear Combination /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us LinCom( C3us p0, C3us p1, C3us p2, C3us p3, ref Tup4 w) { return new C3us( Col.UShortInFloatToUShortClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3), Col.UShortInFloatToUShortClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3), Col.UShortInFloatToUShortClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f LinComRawF( C3us p0, C3us p1, C3us p2, C3us p3, ref Tup4 w) { return new C3f( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us LinCom( C3us p0, C3us p1, C3us p2, C3us p3, ref Tup4 w) { return new C3us( Col.UShortInDoubleToUShortClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3), Col.UShortInDoubleToUShortClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3), Col.UShortInDoubleToUShortClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d LinComRawD( C3us p0, C3us p1, C3us p2, C3us p3, ref Tup4 w) { return new C3d( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us LinCom( C3us p0, C3us p1, C3us p2, C3us p3, C3us p4, C3us p5, ref Tup6 w) { return new C3us( Col.UShortInFloatToUShortClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5), Col.UShortInFloatToUShortClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5), Col.UShortInFloatToUShortClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f LinComRawF( C3us p0, C3us p1, C3us p2, C3us p3, C3us p4, C3us p5, ref Tup6 w) { return new C3f( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3us LinCom( C3us p0, C3us p1, C3us p2, C3us p3, C3us p4, C3us p5, ref Tup6 w) { return new C3us( Col.UShortInDoubleToUShortClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5), Col.UShortInDoubleToUShortClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5), Col.UShortInDoubleToUShortClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d LinComRawD( C3us p0, C3us p1, C3us p2, C3us p3, C3us p4, C3us p5, ref Tup6 w) { return new C3d( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5); } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this C3us c, ushort epsilon) => c.R.IsTiny(epsilon) || c.G.IsTiny(epsilon) || c.B.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this C3us c, ushort epsilon) => c.R.IsTiny(epsilon) && c.G.IsTiny(epsilon) && c.B.IsTiny(epsilon); #endregion } #endregion #region C3ui /// /// Represents an RGB color with each channel stored as a value within [0, 2^32 - 1]. /// [Serializable] public partial struct C3ui : IFormattable, IEquatable, IRGB { #region Constructors /// /// Creates a color from the given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(uint r, uint g, uint b) { R = r; G = g; B = b; } /// /// Creates a color from the given values. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(int r, int g, int b) { R = (uint)r; G = (uint)g; B = (uint)b; } /// /// Creates a color from the given values. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(long r, long g, long b) { R = (uint)r; G = (uint)g; B = (uint)b; } /// /// Creates a color from the given values. /// The values are mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(float r, float g, float b) { R = Col.FloatToUIntClamped(r); G = Col.FloatToUIntClamped(g); B = Col.FloatToUIntClamped(b); } /// /// Creates a color from the given values. /// The values are mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(double r, double g, double b) { R = Col.DoubleToUIntClamped(r); G = Col.DoubleToUIntClamped(g); B = Col.DoubleToUIntClamped(b); } /// /// Creates a color from a single value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(uint gray) { R = gray; G = gray; B = gray; } /// /// Creates a color from a single value. /// The value is mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(float gray) { var value = Col.FloatToUIntClamped(gray); R = value; G = value; B = value; } /// /// Creates a color from a single value. /// The value is mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(double gray) { var value = Col.DoubleToUIntClamped(gray); R = value; G = value; B = value; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(C3b color) { R = Col.ByteToUInt(color.R); G = Col.ByteToUInt(color.G); B = Col.ByteToUInt(color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(C3us color) { R = Col.UShortToUInt(color.R); G = Col.UShortToUInt(color.G); B = Col.UShortToUInt(color.B); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(C3ui color) { R = (color.R); G = (color.G); B = (color.B); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(C3f color) { R = Col.FloatToUIntClamped(color.R); G = Col.FloatToUIntClamped(color.G); B = Col.FloatToUIntClamped(color.B); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(C3d color) { R = Col.DoubleToUIntClamped(color.R); G = Col.DoubleToUIntClamped(color.G); B = Col.DoubleToUIntClamped(color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(C4b color) { R = Col.ByteToUInt(color.R); G = Col.ByteToUInt(color.G); B = Col.ByteToUInt(color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(C4us color) { R = Col.UShortToUInt(color.R); G = Col.UShortToUInt(color.G); B = Col.UShortToUInt(color.B); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(C4ui color) { R = (color.R); G = (color.G); B = (color.B); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(C4f color) { R = Col.FloatToUIntClamped(color.R); G = Col.FloatToUIntClamped(color.G); B = Col.FloatToUIntClamped(color.B); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(C4d color) { R = Col.DoubleToUIntClamped(color.R); G = Col.DoubleToUIntClamped(color.G); B = Col.DoubleToUIntClamped(color.B); } /// /// Creates a color from the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(V3ui vec) { R = (vec.X); G = (vec.Y); B = (vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(V3l vec) { R = (uint)(vec.X); G = (uint)(vec.Y); B = (uint)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(V3f vec) { R = (uint)(vec.X); G = (uint)(vec.Y); B = (uint)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(V3d vec) { R = (uint)(vec.X); G = (uint)(vec.Y); B = (uint)(vec.Z); } /// /// Creates a color from the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(V4ui vec) { R = (vec.X); G = (vec.Y); B = (vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(V4l vec) { R = (uint)(vec.X); G = (uint)(vec.Y); B = (uint)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(V4f vec) { R = (uint)(vec.X); G = (uint)(vec.Y); B = (uint)(vec.Z); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(V4d vec) { R = (uint)(vec.X); G = (uint)(vec.Y); B = (uint)(vec.Z); } /// /// Creates a color from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(Func index_fun) { R = index_fun(0); G = index_fun(1); B = index_fun(2); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(byte[] values) { R = Col.ByteToUInt(values[0]); G = Col.ByteToUInt(values[1]); B = Col.ByteToUInt(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(byte[] values, int start) { R = Col.ByteToUInt(values[start + 0]); G = Col.ByteToUInt(values[start + 1]); B = Col.ByteToUInt(values[start + 2]); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(ushort[] values) { R = Col.UShortToUInt(values[0]); G = Col.UShortToUInt(values[1]); B = Col.UShortToUInt(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(ushort[] values, int start) { R = Col.UShortToUInt(values[start + 0]); G = Col.UShortToUInt(values[start + 1]); B = Col.UShortToUInt(values[start + 2]); } /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(uint[] values) { R = (values[0]); G = (values[1]); B = (values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(uint[] values, int start) { R = (values[start + 0]); G = (values[start + 1]); B = (values[start + 2]); } /// /// Creates a new color from the given array. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(float[] values) { R = Col.FloatToUIntClamped(values[0]); G = Col.FloatToUIntClamped(values[1]); B = Col.FloatToUIntClamped(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(float[] values, int start) { R = Col.FloatToUIntClamped(values[start + 0]); G = Col.FloatToUIntClamped(values[start + 1]); B = Col.FloatToUIntClamped(values[start + 2]); } /// /// Creates a new color from the given array. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(double[] values) { R = Col.DoubleToUIntClamped(values[0]); G = Col.DoubleToUIntClamped(values[1]); B = Col.DoubleToUIntClamped(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3ui(double[] values, int start) { R = Col.DoubleToUIntClamped(values[start + 0]); G = Col.DoubleToUIntClamped(values[start + 1]); B = Col.DoubleToUIntClamped(values[start + 2]); } #endregion #region Conversions /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(C3b color) => new C3ui(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromC3b(C3b c) => new C3ui(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(C3us color) => new C3ui(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromC3us(C3us c) => new C3ui(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(C3f color) => new C3ui(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f ToC3f() => (C3f)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromC3f(C3f c) => new C3ui(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(C3d color) => new C3ui(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d ToC3d() => (C3d)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromC3d(C3d c) => new C3ui(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(C4b color) => new C3ui(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromC4b(C4b c) => new C3ui(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(C4us color) => new C3ui(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromC4us(C4us c) => new C3ui(c); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(C4ui color) => new C3ui(color); /// /// Converts the given color to a color. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromC4ui(C4ui c) => new C3ui(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(C4f color) => new C3ui(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f ToC4f() => (C4f)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromC4f(C4f c) => new C3ui(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(C4d color) => new C3ui(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d ToC4d() => (C4d)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromC4d(C4d c) => new C3ui(c); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(V3ui v) => new C3ui(v); /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; /// /// Creates a color from a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromV3ui(V3ui c) => new C3ui(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(V3l v) => new C3ui(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromV3l(V3l c) => new C3ui(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(V3f v) => new C3ui(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromV3f(V3f c) => new C3ui(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(V3d v) => new C3ui(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromV3d(V3d c) => new C3ui(c); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(V4ui v) => new C3ui(v); /// /// Converts the given color to a vector. /// W is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; /// /// Creates a color from a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromV4ui(V4ui c) => new C3ui(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(V4l v) => new C3ui(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromV4l(V4l c) => new C3ui(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(V4f v) => new C3ui(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromV4f(V4f c) => new C3ui(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(V4d v) => new C3ui(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui FromV4d(V4d c) => new C3ui(c); /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(byte[] values) => new C3ui(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator byte[](C3ui color) => new byte[] { Col.UIntToByte(color.R), Col.UIntToByte(color.G), Col.UIntToByte(color.B) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(ushort[] values) => new C3ui(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ushort[](C3ui color) => new ushort[] { Col.UIntToUShort(color.R), Col.UIntToUShort(color.G), Col.UIntToUShort(color.B) }; /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(uint[] values) => new C3ui(values); /// /// Creates a new array from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](C3ui color) => new uint[] { (color.R), (color.G), (color.B) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(float[] values) => new C3ui(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](C3ui color) => new float[] { Col.UIntToFloat(color.R), Col.UIntToFloat(color.G), Col.UIntToFloat(color.B) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3ui(double[] values) => new C3ui(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](C3ui color) => new double[] { Col.UIntToDouble(color.R), Col.UIntToDouble(color.G), Col.UIntToDouble(color.B) }; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b Map(Func channel_fun) { return new C3b(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us Map(Func channel_fun) { return new C3us(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui Map(Func channel_fun) { return new C3ui(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f Map(Func channel_fun) { return new C3f(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d Map(Func channel_fun) { return new C3d(channel_fun(R), channel_fun(G), channel_fun(B)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(R); array[start + 1] = element_fun(G); array[start + 2] = element_fun(B); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(R, 0); array[start + 1] = element_index_fun(G, 1); array[start + 2] = element_index_fun(B, 2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly uint[] ToArray() => (uint[])this; #endregion #region Indexer /// /// Indexer in canonical order 0=R, 1=G, 2=B, 3=A (availability depending on color type). /// public unsafe uint this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (uint* ptr = &R) { ptr[i] = value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (uint* ptr = &R) { return ptr[i]; } } } #endregion #region Constants /// /// C3ui with all components zero. /// public static C3ui Zero => new C3ui(0, 0, 0); // Web colors public static C3ui AliceBlue => new C3ui(Col.DoubleToUIntClamped(0.941176), Col.DoubleToUIntClamped(0.972549), Col.DoubleToUIntClamped(1)); public static C3ui AntiqueWhite => new C3ui(Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.921569), Col.DoubleToUIntClamped(0.843137)); public static C3ui Aqua => new C3ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1)); public static C3ui Aquamarine => new C3ui(Col.DoubleToUIntClamped(0.498039), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.831373)); public static C3ui Azure => new C3ui(Col.DoubleToUIntClamped(0.941176), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1)); public static C3ui Beige => new C3ui(Col.DoubleToUIntClamped(0.960784), Col.DoubleToUIntClamped(0.960784), Col.DoubleToUIntClamped(0.862745)); public static C3ui Bisque => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.894118), Col.DoubleToUIntClamped(0.768627)); public static C3ui Black => new C3ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0)); public static C3ui BlanchedAlmond => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.921569), Col.DoubleToUIntClamped(0.803922)); public static C3ui Blue => new C3ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(1)); public static C3ui BlueViolet => new C3ui(Col.DoubleToUIntClamped(0.541176), Col.DoubleToUIntClamped(0.168627), Col.DoubleToUIntClamped(0.886275)); public static C3ui Brown => new C3ui(Col.DoubleToUIntClamped(0.647059), Col.DoubleToUIntClamped(0.164706), Col.DoubleToUIntClamped(0.164706)); public static C3ui BurlyWood => new C3ui(Col.DoubleToUIntClamped(0.870588), Col.DoubleToUIntClamped(0.721569), Col.DoubleToUIntClamped(0.529412)); public static C3ui CadetBlue => new C3ui(Col.DoubleToUIntClamped(0.372549), Col.DoubleToUIntClamped(0.619608), Col.DoubleToUIntClamped(0.627451)); public static C3ui Chartreuse => new C3ui(Col.DoubleToUIntClamped(0.498039), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0)); public static C3ui Chocolate => new C3ui(Col.DoubleToUIntClamped(0.823529), Col.DoubleToUIntClamped(0.411765), Col.DoubleToUIntClamped(0.117647)); public static C3ui Coral => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.498039), Col.DoubleToUIntClamped(0.313725)); public static C3ui CornflowerBlue => new C3ui(Col.DoubleToUIntClamped(0.392157), Col.DoubleToUIntClamped(0.584314), Col.DoubleToUIntClamped(0.929412)); public static C3ui Cornsilk => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.972549), Col.DoubleToUIntClamped(0.862745)); public static C3ui Crimson => new C3ui(Col.DoubleToUIntClamped(0.862745), Col.DoubleToUIntClamped(0.078431), Col.DoubleToUIntClamped(0.235294)); public static C3ui Cyan => new C3ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1)); public static C3ui DarkBlue => new C3ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.545098)); public static C3ui DarkCyan => new C3ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.545098), Col.DoubleToUIntClamped(0.545098)); public static C3ui DarkGoldenRod => new C3ui(Col.DoubleToUIntClamped(0.721569), Col.DoubleToUIntClamped(0.52549), Col.DoubleToUIntClamped(0.043137)); public static C3ui DarkGray => new C3ui(Col.DoubleToUIntClamped(0.662745), Col.DoubleToUIntClamped(0.662745), Col.DoubleToUIntClamped(0.662745)); public static C3ui DarkGrey => new C3ui(Col.DoubleToUIntClamped(0.662745), Col.DoubleToUIntClamped(0.662745), Col.DoubleToUIntClamped(0.662745)); public static C3ui DarkGreen => new C3ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.392157), Col.DoubleToUIntClamped(0)); public static C3ui DarkKhaki => new C3ui(Col.DoubleToUIntClamped(0.741176), Col.DoubleToUIntClamped(0.717647), Col.DoubleToUIntClamped(0.419608)); public static C3ui DarkMagenta => new C3ui(Col.DoubleToUIntClamped(0.545098), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.545098)); public static C3ui DarkOliveGreen => new C3ui(Col.DoubleToUIntClamped(0.333333), Col.DoubleToUIntClamped(0.419608), Col.DoubleToUIntClamped(0.184314)); public static C3ui DarkOrange => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.54902), Col.DoubleToUIntClamped(0)); public static C3ui DarkOrchid => new C3ui(Col.DoubleToUIntClamped(0.6), Col.DoubleToUIntClamped(0.196078), Col.DoubleToUIntClamped(0.8)); public static C3ui DarkRed => new C3ui(Col.DoubleToUIntClamped(0.545098), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0)); public static C3ui DarkSalmon => new C3ui(Col.DoubleToUIntClamped(0.913725), Col.DoubleToUIntClamped(0.588235), Col.DoubleToUIntClamped(0.478431)); public static C3ui DarkSeaGreen => new C3ui(Col.DoubleToUIntClamped(0.560784), Col.DoubleToUIntClamped(0.737255), Col.DoubleToUIntClamped(0.560784)); public static C3ui DarkSlateBlue => new C3ui(Col.DoubleToUIntClamped(0.282353), Col.DoubleToUIntClamped(0.239216), Col.DoubleToUIntClamped(0.545098)); public static C3ui DarkSlateGray => new C3ui(Col.DoubleToUIntClamped(0.184314), Col.DoubleToUIntClamped(0.309804), Col.DoubleToUIntClamped(0.309804)); public static C3ui DarkSlateGrey => new C3ui(Col.DoubleToUIntClamped(0.184314), Col.DoubleToUIntClamped(0.309804), Col.DoubleToUIntClamped(0.309804)); public static C3ui DarkTurquoise => new C3ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.807843), Col.DoubleToUIntClamped(0.819608)); public static C3ui DarkViolet => new C3ui(Col.DoubleToUIntClamped(0.580392), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.827451)); public static C3ui DeepPink => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.078431), Col.DoubleToUIntClamped(0.576471)); public static C3ui DeepSkyBlue => new C3ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.74902), Col.DoubleToUIntClamped(1)); public static C3ui DimGray => new C3ui(Col.DoubleToUIntClamped(0.411765), Col.DoubleToUIntClamped(0.411765), Col.DoubleToUIntClamped(0.411765)); public static C3ui DimGrey => new C3ui(Col.DoubleToUIntClamped(0.411765), Col.DoubleToUIntClamped(0.411765), Col.DoubleToUIntClamped(0.411765)); public static C3ui DodgerBlue => new C3ui(Col.DoubleToUIntClamped(0.117647), Col.DoubleToUIntClamped(0.564706), Col.DoubleToUIntClamped(1)); public static C3ui FireBrick => new C3ui(Col.DoubleToUIntClamped(0.698039), Col.DoubleToUIntClamped(0.133333), Col.DoubleToUIntClamped(0.133333)); public static C3ui FloralWhite => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.941176)); public static C3ui ForestGreen => new C3ui(Col.DoubleToUIntClamped(0.133333), Col.DoubleToUIntClamped(0.545098), Col.DoubleToUIntClamped(0.133333)); public static C3ui Fuchsia => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(1)); public static C3ui Gainsboro => new C3ui(Col.DoubleToUIntClamped(0.862745), Col.DoubleToUIntClamped(0.862745), Col.DoubleToUIntClamped(0.862745)); public static C3ui GhostWhite => new C3ui(Col.DoubleToUIntClamped(0.972549), Col.DoubleToUIntClamped(0.972549), Col.DoubleToUIntClamped(1)); public static C3ui Gold => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.843137), Col.DoubleToUIntClamped(0)); public static C3ui GoldenRod => new C3ui(Col.DoubleToUIntClamped(0.854902), Col.DoubleToUIntClamped(0.647059), Col.DoubleToUIntClamped(0.12549)); public static C3ui Gray => new C3ui(Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.501961)); public static C3ui Grey => new C3ui(Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.501961)); public static C3ui Green => new C3ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0)); public static C3ui GreenYellow => new C3ui(Col.DoubleToUIntClamped(0.678431), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.184314)); public static C3ui HoneyDew => new C3ui(Col.DoubleToUIntClamped(0.941176), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.941176)); public static C3ui HotPink => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.411765), Col.DoubleToUIntClamped(0.705882)); public static C3ui IndianRed => new C3ui(Col.DoubleToUIntClamped(0.803922), Col.DoubleToUIntClamped(0.360784), Col.DoubleToUIntClamped(0.360784)); public static C3ui Indigo => new C3ui(Col.DoubleToUIntClamped(0.294118), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.509804)); public static C3ui Ivory => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.941176)); public static C3ui Khaki => new C3ui(Col.DoubleToUIntClamped(0.941176), Col.DoubleToUIntClamped(0.901961), Col.DoubleToUIntClamped(0.54902)); public static C3ui Lavender => new C3ui(Col.DoubleToUIntClamped(0.901961), Col.DoubleToUIntClamped(0.901961), Col.DoubleToUIntClamped(0.980392)); public static C3ui LavenderBlush => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.941176), Col.DoubleToUIntClamped(0.960784)); public static C3ui LawnGreen => new C3ui(Col.DoubleToUIntClamped(0.486275), Col.DoubleToUIntClamped(0.988235), Col.DoubleToUIntClamped(0)); public static C3ui LemonChiffon => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.803922)); public static C3ui LightBlue => new C3ui(Col.DoubleToUIntClamped(0.678431), Col.DoubleToUIntClamped(0.847059), Col.DoubleToUIntClamped(0.901961)); public static C3ui LightCoral => new C3ui(Col.DoubleToUIntClamped(0.941176), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.501961)); public static C3ui LightCyan => new C3ui(Col.DoubleToUIntClamped(0.878431), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1)); public static C3ui LightGoldenRodYellow => new C3ui(Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.823529)); public static C3ui LightGray => new C3ui(Col.DoubleToUIntClamped(0.827451), Col.DoubleToUIntClamped(0.827451), Col.DoubleToUIntClamped(0.827451)); public static C3ui LightGrey => new C3ui(Col.DoubleToUIntClamped(0.827451), Col.DoubleToUIntClamped(0.827451), Col.DoubleToUIntClamped(0.827451)); public static C3ui LightGreen => new C3ui(Col.DoubleToUIntClamped(0.564706), Col.DoubleToUIntClamped(0.933333), Col.DoubleToUIntClamped(0.564706)); public static C3ui LightPink => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.713725), Col.DoubleToUIntClamped(0.756863)); public static C3ui LightSalmon => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.627451), Col.DoubleToUIntClamped(0.478431)); public static C3ui LightSeaGreen => new C3ui(Col.DoubleToUIntClamped(0.12549), Col.DoubleToUIntClamped(0.698039), Col.DoubleToUIntClamped(0.666667)); public static C3ui LightSkyBlue => new C3ui(Col.DoubleToUIntClamped(0.529412), Col.DoubleToUIntClamped(0.807843), Col.DoubleToUIntClamped(0.980392)); public static C3ui LightSlateGray => new C3ui(Col.DoubleToUIntClamped(0.466667), Col.DoubleToUIntClamped(0.533333), Col.DoubleToUIntClamped(0.6)); public static C3ui LightSlateGrey => new C3ui(Col.DoubleToUIntClamped(0.466667), Col.DoubleToUIntClamped(0.533333), Col.DoubleToUIntClamped(0.6)); public static C3ui LightSteelBlue => new C3ui(Col.DoubleToUIntClamped(0.690196), Col.DoubleToUIntClamped(0.768627), Col.DoubleToUIntClamped(0.870588)); public static C3ui LightYellow => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.878431)); public static C3ui Lime => new C3ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0)); public static C3ui LimeGreen => new C3ui(Col.DoubleToUIntClamped(0.196078), Col.DoubleToUIntClamped(0.803922), Col.DoubleToUIntClamped(0.196078)); public static C3ui Linen => new C3ui(Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.941176), Col.DoubleToUIntClamped(0.901961)); public static C3ui Magenta => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(1)); public static C3ui Maroon => new C3ui(Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0)); public static C3ui MediumAquaMarine => new C3ui(Col.DoubleToUIntClamped(0.4), Col.DoubleToUIntClamped(0.803922), Col.DoubleToUIntClamped(0.666667)); public static C3ui MediumBlue => new C3ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.803922)); public static C3ui MediumOrchid => new C3ui(Col.DoubleToUIntClamped(0.729412), Col.DoubleToUIntClamped(0.333333), Col.DoubleToUIntClamped(0.827451)); public static C3ui MediumPurple => new C3ui(Col.DoubleToUIntClamped(0.576471), Col.DoubleToUIntClamped(0.439216), Col.DoubleToUIntClamped(0.847059)); public static C3ui MediumSeaGreen => new C3ui(Col.DoubleToUIntClamped(0.235294), Col.DoubleToUIntClamped(0.701961), Col.DoubleToUIntClamped(0.443137)); public static C3ui MediumSlateBlue => new C3ui(Col.DoubleToUIntClamped(0.482353), Col.DoubleToUIntClamped(0.407843), Col.DoubleToUIntClamped(0.933333)); public static C3ui MediumSpringGreen => new C3ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.603922)); public static C3ui MediumTurquoise => new C3ui(Col.DoubleToUIntClamped(0.282353), Col.DoubleToUIntClamped(0.819608), Col.DoubleToUIntClamped(0.8)); public static C3ui MediumVioletRed => new C3ui(Col.DoubleToUIntClamped(0.780392), Col.DoubleToUIntClamped(0.082353), Col.DoubleToUIntClamped(0.521569)); public static C3ui MidnightBlue => new C3ui(Col.DoubleToUIntClamped(0.098039), Col.DoubleToUIntClamped(0.098039), Col.DoubleToUIntClamped(0.439216)); public static C3ui MintCream => new C3ui(Col.DoubleToUIntClamped(0.960784), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.980392)); public static C3ui MistyRose => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.894118), Col.DoubleToUIntClamped(0.882353)); public static C3ui Moccasin => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.894118), Col.DoubleToUIntClamped(0.709804)); public static C3ui NavajoWhite => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.870588), Col.DoubleToUIntClamped(0.678431)); public static C3ui Navy => new C3ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.501961)); public static C3ui OldLace => new C3ui(Col.DoubleToUIntClamped(0.992157), Col.DoubleToUIntClamped(0.960784), Col.DoubleToUIntClamped(0.901961)); public static C3ui Olive => new C3ui(Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0)); public static C3ui OliveDrab => new C3ui(Col.DoubleToUIntClamped(0.419608), Col.DoubleToUIntClamped(0.556863), Col.DoubleToUIntClamped(0.137255)); public static C3ui Orange => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.647059), Col.DoubleToUIntClamped(0)); public static C3ui OrangeRed => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.270588), Col.DoubleToUIntClamped(0)); public static C3ui Orchid => new C3ui(Col.DoubleToUIntClamped(0.854902), Col.DoubleToUIntClamped(0.439216), Col.DoubleToUIntClamped(0.839216)); public static C3ui PaleGoldenRod => new C3ui(Col.DoubleToUIntClamped(0.933333), Col.DoubleToUIntClamped(0.909804), Col.DoubleToUIntClamped(0.666667)); public static C3ui PaleGreen => new C3ui(Col.DoubleToUIntClamped(0.596078), Col.DoubleToUIntClamped(0.984314), Col.DoubleToUIntClamped(0.596078)); public static C3ui PaleTurquoise => new C3ui(Col.DoubleToUIntClamped(0.686275), Col.DoubleToUIntClamped(0.933333), Col.DoubleToUIntClamped(0.933333)); public static C3ui PaleVioletRed => new C3ui(Col.DoubleToUIntClamped(0.847059), Col.DoubleToUIntClamped(0.439216), Col.DoubleToUIntClamped(0.576471)); public static C3ui PapayaWhip => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.937255), Col.DoubleToUIntClamped(0.835294)); public static C3ui PeachPuff => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.854902), Col.DoubleToUIntClamped(0.72549)); public static C3ui Peru => new C3ui(Col.DoubleToUIntClamped(0.803922), Col.DoubleToUIntClamped(0.521569), Col.DoubleToUIntClamped(0.247059)); public static C3ui Pink => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.752941), Col.DoubleToUIntClamped(0.796078)); public static C3ui Plum => new C3ui(Col.DoubleToUIntClamped(0.866667), Col.DoubleToUIntClamped(0.627451), Col.DoubleToUIntClamped(0.866667)); public static C3ui PowderBlue => new C3ui(Col.DoubleToUIntClamped(0.690196), Col.DoubleToUIntClamped(0.878431), Col.DoubleToUIntClamped(0.901961)); public static C3ui Purple => new C3ui(Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.501961)); public static C3ui Red => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0)); public static C3ui RosyBrown => new C3ui(Col.DoubleToUIntClamped(0.737255), Col.DoubleToUIntClamped(0.560784), Col.DoubleToUIntClamped(0.560784)); public static C3ui RoyalBlue => new C3ui(Col.DoubleToUIntClamped(0.254902), Col.DoubleToUIntClamped(0.411765), Col.DoubleToUIntClamped(0.882353)); public static C3ui SaddleBrown => new C3ui(Col.DoubleToUIntClamped(0.545098), Col.DoubleToUIntClamped(0.270588), Col.DoubleToUIntClamped(0.07451)); public static C3ui Salmon => new C3ui(Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.447059)); public static C3ui SandyBrown => new C3ui(Col.DoubleToUIntClamped(0.956863), Col.DoubleToUIntClamped(0.643137), Col.DoubleToUIntClamped(0.376471)); public static C3ui SeaGreen => new C3ui(Col.DoubleToUIntClamped(0.180392), Col.DoubleToUIntClamped(0.545098), Col.DoubleToUIntClamped(0.341176)); public static C3ui SeaShell => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.960784), Col.DoubleToUIntClamped(0.933333)); public static C3ui Sienna => new C3ui(Col.DoubleToUIntClamped(0.627451), Col.DoubleToUIntClamped(0.321569), Col.DoubleToUIntClamped(0.176471)); public static C3ui Silver => new C3ui(Col.DoubleToUIntClamped(0.752941), Col.DoubleToUIntClamped(0.752941), Col.DoubleToUIntClamped(0.752941)); public static C3ui SkyBlue => new C3ui(Col.DoubleToUIntClamped(0.529412), Col.DoubleToUIntClamped(0.807843), Col.DoubleToUIntClamped(0.921569)); public static C3ui SlateBlue => new C3ui(Col.DoubleToUIntClamped(0.415686), Col.DoubleToUIntClamped(0.352941), Col.DoubleToUIntClamped(0.803922)); public static C3ui SlateGray => new C3ui(Col.DoubleToUIntClamped(0.439216), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.564706)); public static C3ui SlateGrey => new C3ui(Col.DoubleToUIntClamped(0.439216), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.564706)); public static C3ui Snow => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.980392)); public static C3ui SpringGreen => new C3ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.498039)); public static C3ui SteelBlue => new C3ui(Col.DoubleToUIntClamped(0.27451), Col.DoubleToUIntClamped(0.509804), Col.DoubleToUIntClamped(0.705882)); public static C3ui Tan => new C3ui(Col.DoubleToUIntClamped(0.823529), Col.DoubleToUIntClamped(0.705882), Col.DoubleToUIntClamped(0.54902)); public static C3ui Teal => new C3ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.501961)); public static C3ui Thistle => new C3ui(Col.DoubleToUIntClamped(0.847059), Col.DoubleToUIntClamped(0.74902), Col.DoubleToUIntClamped(0.847059)); public static C3ui Tomato => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.388235), Col.DoubleToUIntClamped(0.278431)); public static C3ui Turquoise => new C3ui(Col.DoubleToUIntClamped(0.25098), Col.DoubleToUIntClamped(0.878431), Col.DoubleToUIntClamped(0.815686)); public static C3ui Violet => new C3ui(Col.DoubleToUIntClamped(0.933333), Col.DoubleToUIntClamped(0.509804), Col.DoubleToUIntClamped(0.933333)); public static C3ui Wheat => new C3ui(Col.DoubleToUIntClamped(0.960784), Col.DoubleToUIntClamped(0.870588), Col.DoubleToUIntClamped(0.701961)); public static C3ui White => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1)); public static C3ui WhiteSmoke => new C3ui(Col.DoubleToUIntClamped(0.960784), Col.DoubleToUIntClamped(0.960784), Col.DoubleToUIntClamped(0.960784)); public static C3ui Yellow => new C3ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0)); public static C3ui YellowGreen => new C3ui(Col.DoubleToUIntClamped(0.603922), Col.DoubleToUIntClamped(0.803922), Col.DoubleToUIntClamped(0.196078)); public static C3ui DarkYellow => Olive; public static C3ui VRVisGreen => new C3ui(Col.DoubleToUIntClamped(0.698), Col.DoubleToUIntClamped(0.851), Col.DoubleToUIntClamped(0.008)); public static C3ui Gray10 => new C3ui(Col.DoubleToUIntClamped(0.1)); public static C3ui Gray20 => new C3ui(Col.DoubleToUIntClamped(0.2)); public static C3ui Gray30 => new C3ui(Col.DoubleToUIntClamped(0.3)); public static C3ui Gray40 => new C3ui(Col.DoubleToUIntClamped(0.4)); public static C3ui Gray50 => new C3ui(Col.DoubleToUIntClamped(0.5)); public static C3ui Gray60 => new C3ui(Col.DoubleToUIntClamped(0.6)); public static C3ui Gray70 => new C3ui(Col.DoubleToUIntClamped(0.7)); public static C3ui Gray80 => new C3ui(Col.DoubleToUIntClamped(0.8)); public static C3ui Gray90 => new C3ui(Col.DoubleToUIntClamped(0.9)); #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(C3ui a, C3ui b) { return a.R == b.R && a.G == b.G && a.B == b.B; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(C3ui a, C3ui b) { return a.R != b.R || a.G != b.G || a.B != b.B; } #endregion #region Color Arithmetic [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator *(C3ui col, float scalar) { return new C3ui( Col.FloatToUIntClamped(Col.UIntToFloat(col.R) * scalar), Col.FloatToUIntClamped(Col.UIntToFloat(col.G) * scalar), Col.FloatToUIntClamped(Col.UIntToFloat(col.B) * scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator *(float scalar, C3ui col) => col * scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator /(C3ui col, float scalar) => col * (1 / scalar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator /(float scalar, C3ui col) { return new C3ui( Col.FloatToUIntClamped(scalar / Col.UIntToFloat(col.R)), Col.FloatToUIntClamped(scalar / Col.UIntToFloat(col.G)), Col.FloatToUIntClamped(scalar / Col.UIntToFloat(col.B))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator *(C3ui col, double scalar) { return new C3ui( Col.DoubleToUIntClamped(Col.UIntToDouble(col.R) * scalar), Col.DoubleToUIntClamped(Col.UIntToDouble(col.G) * scalar), Col.DoubleToUIntClamped(Col.UIntToDouble(col.B) * scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator *(double scalar, C3ui col) => col * scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator /(C3ui col, double scalar) => col * (1 / scalar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator /(double scalar, C3ui col) { return new C3ui( Col.DoubleToUIntClamped(scalar / Col.UIntToDouble(col.R)), Col.DoubleToUIntClamped(scalar / Col.UIntToDouble(col.G)), Col.DoubleToUIntClamped(scalar / Col.UIntToDouble(col.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator +(C3ui c0, C3b c1) { return new C3ui( (uint)(c0.R + Col.ByteToUInt(c1.R)), (uint)(c0.G + Col.ByteToUInt(c1.G)), (uint)(c0.B + Col.ByteToUInt(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator -(C3ui c0, C3b c1) { return new C3ui( (uint)(c0.R - Col.ByteToUInt(c1.R)), (uint)(c0.G - Col.ByteToUInt(c1.G)), (uint)(c0.B - Col.ByteToUInt(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator +(C3ui c0, C3us c1) { return new C3ui( (uint)(c0.R + Col.UShortToUInt(c1.R)), (uint)(c0.G + Col.UShortToUInt(c1.G)), (uint)(c0.B + Col.UShortToUInt(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator -(C3ui c0, C3us c1) { return new C3ui( (uint)(c0.R - Col.UShortToUInt(c1.R)), (uint)(c0.G - Col.UShortToUInt(c1.G)), (uint)(c0.B - Col.UShortToUInt(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator +(C3ui c0, C3f c1) { return new C3ui( (uint)(c0.R + Col.FloatToUInt(c1.R)), (uint)(c0.G + Col.FloatToUInt(c1.G)), (uint)(c0.B + Col.FloatToUInt(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator -(C3ui c0, C3f c1) { return new C3ui( (uint)(c0.R - Col.FloatToUInt(c1.R)), (uint)(c0.G - Col.FloatToUInt(c1.G)), (uint)(c0.B - Col.FloatToUInt(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator +(C3ui c0, C3d c1) { return new C3ui( (uint)(c0.R + Col.DoubleToUInt(c1.R)), (uint)(c0.G + Col.DoubleToUInt(c1.G)), (uint)(c0.B + Col.DoubleToUInt(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator -(C3ui c0, C3d c1) { return new C3ui( (uint)(c0.R - Col.DoubleToUInt(c1.R)), (uint)(c0.G - Col.DoubleToUInt(c1.G)), (uint)(c0.B - Col.DoubleToUInt(c1.B))); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator *(C3ui col, uint scalar) { return new C3ui((uint)(col.R * scalar), (uint)(col.G * scalar), (uint)(col.B * scalar)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator *(uint scalar, C3ui col) { return new C3ui((uint)(scalar * col.R), (uint)(scalar * col.G), (uint)(scalar * col.B)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator /(C3ui col, uint scalar) { return new C3ui((uint)(col.R / scalar), (uint)(col.G / scalar), (uint)(col.B / scalar)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator /(uint scalar, C3ui col) { return new C3ui((uint)(scalar / col.R), (uint)(scalar / col.G), (uint)(scalar / col.B)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator *(C3ui c0, C3ui c1) { return new C3ui((uint)(c0.R * c1.R), (uint)(c0.G * c1.G), (uint)(c0.B * c1.B)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator /(C3ui c0, C3ui c1) { return new C3ui((uint)(c0.R / c1.R), (uint)(c0.G / c1.G), (uint)(c0.B / c1.B)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator +(C3ui c0, C3ui c1) { return new C3ui( (UInt32.MaxValue - c0.R > c1.R) ? c0.R + c1.R : UInt32.MaxValue, (UInt32.MaxValue - c0.G > c1.G) ? c0.G + c1.G : UInt32.MaxValue, (UInt32.MaxValue - c0.B > c1.B) ? c0.B + c1.B : UInt32.MaxValue ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator +(C3ui col, uint scalar) { return new C3ui( (UInt32.MaxValue - col.R > scalar) ? col.R + scalar : UInt32.MaxValue, (UInt32.MaxValue - col.G > scalar) ? col.G + scalar : UInt32.MaxValue, (UInt32.MaxValue - col.B > scalar) ? col.B + scalar : UInt32.MaxValue ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator +(uint scalar, C3ui col) => col + scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator -(C3ui c0, C3ui c1) { return new C3ui( (c0.R > c1.R) ? c0.R - c1.R : 0, (c0.G > c1.G) ? c0.G - c1.G : 0, (c0.B > c1.B) ? c0.B - c1.B : 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator -(C3ui col, uint scalar) { return new C3ui( (col.R > scalar) ? col.R - scalar : 0, (col.G > scalar) ? col.G - scalar : 0, (col.B > scalar) ? col.B - scalar : 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui operator -(uint scalar, C3ui col) { return new C3ui( (scalar > col.R) ? scalar - col.R : 0, (scalar > col.G) ? scalar - col.G : 0, (scalar > col.B) ? scalar - col.B : 0 ); } /// /// Clamps the color channels to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clamp(uint min, uint max) { R = R.Clamp(min, max); G = G.Clamp(min, max); B = B.Clamp(min, max); } /// /// Returns a copy with the color channels clamped to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui Clamped(uint min, uint max) { return new C3ui(R.Clamp(min, max), G.Clamp(min, max), B.Clamp(min, max)); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |R| + |G| + |B|. /// public readonly long Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return R + G + B; } } /// /// Returns the Euclidean (or 2-) norm of the color. This is calculated /// as sqrt(R^2 + G^2 + B^2). /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(R * R + G * G + B * B); } } /// /// Returns the infinite (or maximum) norm of the color. This is /// calculated as max(|R|, |G|, |B|). /// public readonly uint NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(R, G, B); } } /// /// Returns the minimum norm of the color. This is calculated as /// min(|R|, |G|, |B|). /// public readonly uint NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(R, G, B); } } #endregion #region Overrides public override readonly bool Equals(object other) => (other is C3ui o) ? Equals(o) : false; public override readonly int GetHashCode() { return HashCode.GetCombined(R, G, B); } public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + R.ToString(null, CultureInfo.InvariantCulture) + ", " + G.ToString(null, CultureInfo.InvariantCulture) + ", " + B.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref C3ui color, int i, uint value) => { switch (i) { case 0: color.R = value; return; case 1: color.G = value; return; case 2: color.B = value; return; default: throw new IndexOutOfRangeException(); } }; [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui LinearInterp(float t, C3ui a, C3ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui LinearInterp(V3f t, C3ui a, C3ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui LinearInterp(double t, C3ui a, C3ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui LinearInterp(V3d t, C3ui a, C3ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui DivideByInt(C3ui c, int x) => c / x; #endregion #region Parsing /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C3ui.Zero otherwise. /// True on success, false otherwise. public static bool TryParse(Text t, out C3ui result) { if (Col.TryParseHex(t, out C4b tmp)) { result = tmp.ToC3ui(); return true; } else { bool success = true; uint[] values = new uint[4] { UInt32.MaxValue, UInt32.MaxValue, UInt32.MaxValue, UInt32.MaxValue }; uint parse(Text t) { if (!uint.TryParse(t.ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out uint value)) success = false; return value; }; var count = t.NestedBracketSplitCount2(1); if (count == 3 || count == 4) t.NestedBracketSplit(1, parse, () => values); else success = false; result = success ? new C3ui(values) : Zero; return success; } } /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C3ui.Zero otherwise. /// True on success, false otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParse(string s, out C3ui result) => TryParse(new Text(s), out result); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C3ui color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui Parse(string s) => Parse(new Text(s)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui Parse(Text t, int bracketLevel = 1) => t.NestedBracketSplit(bracketLevel, Text.Parse, C3ui.Setter); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C3ui color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui Parse(Text t) => TryParse(t, out C3ui result) ? result : throw new FormatException($"{t} is not a valid C3ui color."); #endregion #region IFormattable Members public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + R.ToString(format, fp) + between + G.ToString(format, fp) + between + B.ToString(format, fp) + end; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(C3ui other) { return R.Equals(other.R) && G.Equals(other.G) && B.Equals(other.B); } #endregion #region IRGB Members double IRGB.Red { readonly get { return Col.UIntToDouble(R); } set { R = Col.DoubleToUIntClamped(value); } } double IRGB.Green { readonly get { return Col.UIntToDouble(G); } set { G = Col.DoubleToUIntClamped(value); } } double IRGB.Blue { readonly get { return Col.UIntToDouble(B); } set { B = Col.DoubleToUIntClamped(value); } } #endregion } public static partial class Fun { #region Interpolation /// /// Returns the linearly interpolated color between a and b. /// public static C3ui Lerp(this float t, C3ui a, C3ui b) => new C3ui(Lerp(t, a.R, b.R), Lerp(t, a.G, b.G), Lerp(t, a.B, b.B)); /// /// Returns the linearly interpolated color between a and b. /// public static C3ui Lerp(this V3f t, C3ui a, C3ui b) => new C3ui(Lerp(t.X, a.R, b.R), Lerp(t.Y, a.G, b.G), Lerp(t.Z, a.B, b.B)); /// /// Returns the linearly interpolated color between a and b. /// public static C3ui Lerp(this double t, C3ui a, C3ui b) => new C3ui(Lerp(t, a.R, b.R), Lerp(t, a.G, b.G), Lerp(t, a.B, b.B)); /// /// Returns the linearly interpolated color between a and b. /// public static C3ui Lerp(this V3d t, C3ui a, C3ui b) => new C3ui(Lerp(t.X, a.R, b.R), Lerp(t.Y, a.G, b.G), Lerp(t.Z, a.B, b.B)); #endregion #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this C3ui a, C3ui b, uint tolerance) { return ApproximateEquals(a.R, b.R, tolerance) && ApproximateEquals(a.G, b.G, tolerance) && ApproximateEquals(a.B, b.B, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this C3ui c, uint epsilon) => Col.AllTiny(c, epsilon); #endregion } public static partial class Col { #region ToHexString /// /// Returns the hexadecimal representation with format RRGGBB. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToHexString(this C3ui c) => c.ToC3b().ToHexString(); #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C3ui a, C3ui b) { return (a.R < b.R && a.G < b.G && a.B < b.B); } /// /// Returns whether ALL elements of col are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C3ui col, uint s) { return (col.R < s && col.G < s && col.B < s); } /// /// Returns whether a is Smaller ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(uint s, C3ui col) { return (s < col.R && s < col.G && s < col.B); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C3ui a, C3ui b) { return (a.R < b.R || a.G < b.G || a.B < b.B); } /// /// Returns whether AT LEAST ONE element of col is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C3ui col, uint s) { return (col.R < s || col.G < s || col.B < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(uint s, C3ui col) { return (s < col.R || s < col.G || s < col.B); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C3ui a, C3ui b) { return (a.R > b.R && a.G > b.G && a.B > b.B); } /// /// Returns whether ALL elements of col are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C3ui col, uint s) { return (col.R > s && col.G > s && col.B > s); } /// /// Returns whether a is Greater ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(uint s, C3ui col) { return (s > col.R && s > col.G && s > col.B); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C3ui a, C3ui b) { return (a.R > b.R || a.G > b.G || a.B > b.B); } /// /// Returns whether AT LEAST ONE element of col is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C3ui col, uint s) { return (col.R > s || col.G > s || col.B > s); } /// /// Returns whether a is Greater AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(uint s, C3ui col) { return (s > col.R || s > col.G || s > col.B); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C3ui a, C3ui b) { return (a.R <= b.R && a.G <= b.G && a.B <= b.B); } /// /// Returns whether ALL elements of col are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C3ui col, uint s) { return (col.R <= s && col.G <= s && col.B <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(uint s, C3ui col) { return (s <= col.R && s <= col.G && s <= col.B); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C3ui a, C3ui b) { return (a.R <= b.R || a.G <= b.G || a.B <= b.B); } /// /// Returns whether AT LEAST ONE element of col is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C3ui col, uint s) { return (col.R <= s || col.G <= s || col.B <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(uint s, C3ui col) { return (s <= col.R || s <= col.G || s <= col.B); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C3ui a, C3ui b) { return (a.R >= b.R && a.G >= b.G && a.B >= b.B); } /// /// Returns whether ALL elements of col are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C3ui col, uint s) { return (col.R >= s && col.G >= s && col.B >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(uint s, C3ui col) { return (s >= col.R && s >= col.G && s >= col.B); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C3ui a, C3ui b) { return (a.R >= b.R || a.G >= b.G || a.B >= b.B); } /// /// Returns whether AT LEAST ONE element of col is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C3ui col, uint s) { return (col.R >= s || col.G >= s || col.B >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(uint s, C3ui col) { return (s >= col.R || s >= col.G || s >= col.B); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C3ui a, C3ui b) { return (a.R == b.R && a.G == b.G && a.B == b.B); } /// /// Returns whether ALL elements of col are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C3ui col, uint s) { return (col.R == s && col.G == s && col.B == s); } /// /// Returns whether a is Equal ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(uint s, C3ui col) { return (s == col.R && s == col.G && s == col.B); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C3ui a, C3ui b) { return (a.R == b.R || a.G == b.G || a.B == b.B); } /// /// Returns whether AT LEAST ONE element of col is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C3ui col, uint s) { return (col.R == s || col.G == s || col.B == s); } /// /// Returns whether a is Equal AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(uint s, C3ui col) { return (s == col.R || s == col.G || s == col.B); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C3ui a, C3ui b) { return (a.R != b.R && a.G != b.G && a.B != b.B); } /// /// Returns whether ALL elements of col are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C3ui col, uint s) { return (col.R != s && col.G != s && col.B != s); } /// /// Returns whether a is Different ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(uint s, C3ui col) { return (s != col.R && s != col.G && s != col.B); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C3ui a, C3ui b) { return (a.R != b.R || a.G != b.G || a.B != b.B); } /// /// Returns whether AT LEAST ONE element of col is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C3ui col, uint s) { return (col.R != s || col.G != s || col.B != s); } /// /// Returns whether a is Different AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(uint s, C3ui col) { return (s != col.R || s != col.G || s != col.B); } #endregion #region Linear Combination /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui LinCom( C3ui p0, C3ui p1, C3ui p2, C3ui p3, ref Tup4 w) { return new C3ui( Col.UIntInDoubleToUIntClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3), Col.UIntInDoubleToUIntClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3), Col.UIntInDoubleToUIntClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f LinComRawF( C3ui p0, C3ui p1, C3ui p2, C3ui p3, ref Tup4 w) { return new C3f( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui LinCom( C3ui p0, C3ui p1, C3ui p2, C3ui p3, ref Tup4 w) { return new C3ui( Col.UIntInDoubleToUIntClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3), Col.UIntInDoubleToUIntClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3), Col.UIntInDoubleToUIntClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d LinComRawD( C3ui p0, C3ui p1, C3ui p2, C3ui p3, ref Tup4 w) { return new C3d( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui LinCom( C3ui p0, C3ui p1, C3ui p2, C3ui p3, C3ui p4, C3ui p5, ref Tup6 w) { return new C3ui( Col.UIntInDoubleToUIntClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5), Col.UIntInDoubleToUIntClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5), Col.UIntInDoubleToUIntClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f LinComRawF( C3ui p0, C3ui p1, C3ui p2, C3ui p3, C3ui p4, C3ui p5, ref Tup6 w) { return new C3f( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui LinCom( C3ui p0, C3ui p1, C3ui p2, C3ui p3, C3ui p4, C3ui p5, ref Tup6 w) { return new C3ui( Col.UIntInDoubleToUIntClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5), Col.UIntInDoubleToUIntClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5), Col.UIntInDoubleToUIntClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d LinComRawD( C3ui p0, C3ui p1, C3ui p2, C3ui p3, C3ui p4, C3ui p5, ref Tup6 w) { return new C3d( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5); } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this C3ui c, uint epsilon) => c.R.IsTiny(epsilon) || c.G.IsTiny(epsilon) || c.B.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this C3ui c, uint epsilon) => c.R.IsTiny(epsilon) && c.G.IsTiny(epsilon) && c.B.IsTiny(epsilon); #endregion } public static class IRandomUniformC3uiExtensions { #region IRandomUniform extensions for C3ui /// /// Uses UniformUInt() to generate the elements of a C3ui color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3ui UniformC3ui(this IRandomUniform rnd) { return new C3ui(rnd.UniformUInt(), rnd.UniformUInt(), rnd.UniformUInt()); } #endregion } #endregion #region C3f /// /// Represents an RGB color with each channel stored as a value within [0, 1]. /// [Serializable] public partial struct C3f : IFormattable, IEquatable, IRGB { #region Constructors /// /// Creates a color from the given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(float r, float g, float b) { R = r; G = g; B = b; } /// /// Creates a color from the given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(double r, double g, double b) { R = (float)(r); G = (float)(g); B = (float)(b); } /// /// Creates a color from a single value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(float gray) { R = gray; G = gray; B = gray; } /// /// Creates a color from a single value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(double gray) { var value = (float)(gray); R = value; G = value; B = value; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(C3b color) { R = Col.ByteToFloat(color.R); G = Col.ByteToFloat(color.G); B = Col.ByteToFloat(color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(C3us color) { R = Col.UShortToFloat(color.R); G = Col.UShortToFloat(color.G); B = Col.UShortToFloat(color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(C3ui color) { R = Col.UIntToFloat(color.R); G = Col.UIntToFloat(color.G); B = Col.UIntToFloat(color.B); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(C3f color) { R = (color.R); G = (color.G); B = (color.B); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(C3d color) { R = Col.DoubleToFloat(color.R); G = Col.DoubleToFloat(color.G); B = Col.DoubleToFloat(color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(C4b color) { R = Col.ByteToFloat(color.R); G = Col.ByteToFloat(color.G); B = Col.ByteToFloat(color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(C4us color) { R = Col.UShortToFloat(color.R); G = Col.UShortToFloat(color.G); B = Col.UShortToFloat(color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(C4ui color) { R = Col.UIntToFloat(color.R); G = Col.UIntToFloat(color.G); B = Col.UIntToFloat(color.B); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(C4f color) { R = (color.R); G = (color.G); B = (color.B); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(C4d color) { R = Col.DoubleToFloat(color.R); G = Col.DoubleToFloat(color.G); B = Col.DoubleToFloat(color.B); } /// /// Creates a color from the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(V3f vec) { R = (vec.X); G = (vec.Y); B = (vec.Z); } /// /// Creates a color from the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(V3d vec) { R = (float)(vec.X); G = (float)(vec.Y); B = (float)(vec.Z); } /// /// Creates a color from the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(V4f vec) { R = (vec.X); G = (vec.Y); B = (vec.Z); } /// /// Creates a color from the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(V4d vec) { R = (float)(vec.X); G = (float)(vec.Y); B = (float)(vec.Z); } /// /// Creates a color from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(Func index_fun) { R = index_fun(0); G = index_fun(1); B = index_fun(2); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(byte[] values) { R = Col.ByteToFloat(values[0]); G = Col.ByteToFloat(values[1]); B = Col.ByteToFloat(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(byte[] values, int start) { R = Col.ByteToFloat(values[start + 0]); G = Col.ByteToFloat(values[start + 1]); B = Col.ByteToFloat(values[start + 2]); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(ushort[] values) { R = Col.UShortToFloat(values[0]); G = Col.UShortToFloat(values[1]); B = Col.UShortToFloat(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(ushort[] values, int start) { R = Col.UShortToFloat(values[start + 0]); G = Col.UShortToFloat(values[start + 1]); B = Col.UShortToFloat(values[start + 2]); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(uint[] values) { R = Col.UIntToFloat(values[0]); G = Col.UIntToFloat(values[1]); B = Col.UIntToFloat(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(uint[] values, int start) { R = Col.UIntToFloat(values[start + 0]); G = Col.UIntToFloat(values[start + 1]); B = Col.UIntToFloat(values[start + 2]); } /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(float[] values) { R = (values[0]); G = (values[1]); B = (values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(float[] values, int start) { R = (values[start + 0]); G = (values[start + 1]); B = (values[start + 2]); } /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(double[] values) { R = Col.DoubleToFloat(values[0]); G = Col.DoubleToFloat(values[1]); B = Col.DoubleToFloat(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3f(double[] values, int start) { R = Col.DoubleToFloat(values[start + 0]); G = Col.DoubleToFloat(values[start + 1]); B = Col.DoubleToFloat(values[start + 2]); } #endregion #region Properities public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNaN(R) || float.IsNaN(G) || float.IsNaN(B); } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNaN(R) && float.IsNaN(G) && float.IsNaN(B); } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsInfinity(R) || float.IsInfinity(G) || float.IsInfinity(B); } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsInfinity(R) && float.IsInfinity(G) && float.IsInfinity(B); } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsPositiveInfinity(R) || float.IsPositiveInfinity(G) || float.IsPositiveInfinity(B); } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsPositiveInfinity(R) && float.IsPositiveInfinity(G) && float.IsPositiveInfinity(B); } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNegativeInfinity(R) || float.IsNegativeInfinity(G) || float.IsNegativeInfinity(B); } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNegativeInfinity(R) && float.IsNegativeInfinity(G) && float.IsNegativeInfinity(B); } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(R) || Fun.IsTiny(G) || Fun.IsTiny(B); } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(R) && Fun.IsTiny(G) && Fun.IsTiny(B); } /// /// Returns true if the absolute value of each component of the color is smaller than Constant<float>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any component of the color is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any component of the color is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any component of the color is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any component of the color is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all components of the color are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Conversions /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(C3b color) => new C3f(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f FromC3b(C3b c) => new C3f(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(C3us color) => new C3f(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f FromC3us(C3us c) => new C3f(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(C3ui color) => new C3f(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f FromC3ui(C3ui c) => new C3f(c); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(C3d color) => new C3f(color); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d ToC3d() => (C3d)this; /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f FromC3d(C3d c) => new C3f(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(C4b color) => new C3f(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f FromC4b(C4b c) => new C3f(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(C4us color) => new C3f(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f FromC4us(C4us c) => new C3f(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(C4ui color) => new C3f(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f FromC4ui(C4ui c) => new C3f(c); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(C4f color) => new C3f(color); /// /// Converts the given color to a color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f ToC4f() => (C4f)this; /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f FromC4f(C4f c) => new C3f(c); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(C4d color) => new C3f(color); /// /// Converts the given color to a color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d ToC4d() => (C4d)this; /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f FromC4d(C4d c) => new C3f(c); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(V3f v) => new C3f(v); /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; /// /// Creates a color from a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f FromV3f(V3f c) => new C3f(c); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(V3d v) => new C3f(v); /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; /// /// Creates a color from a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f FromV3d(V3d c) => new C3f(c); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(V4f v) => new C3f(v); /// /// Converts the given color to a vector. /// W is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; /// /// Creates a color from a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f FromV4f(V4f c) => new C3f(c); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(V4d v) => new C3f(v); /// /// Converts the given color to a vector. /// W is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; /// /// Creates a color from a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f FromV4d(V4d c) => new C3f(c); /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(byte[] values) => new C3f(values); /// /// Creates a new array from the given color. /// The values are mapped and clamped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator byte[](C3f color) => new byte[] { Col.FloatToByteClamped(color.R), Col.FloatToByteClamped(color.G), Col.FloatToByteClamped(color.B) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(ushort[] values) => new C3f(values); /// /// Creates a new array from the given color. /// The values are mapped and clamped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ushort[](C3f color) => new ushort[] { Col.FloatToUShortClamped(color.R), Col.FloatToUShortClamped(color.G), Col.FloatToUShortClamped(color.B) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(uint[] values) => new C3f(values); /// /// Creates a new array from the given color. /// The values are mapped and clamped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](C3f color) => new uint[] { Col.FloatToUIntClamped(color.R), Col.FloatToUIntClamped(color.G), Col.FloatToUIntClamped(color.B) }; /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(float[] values) => new C3f(values); /// /// Creates a new array from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](C3f color) => new float[] { (color.R), (color.G), (color.B) }; /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3f(double[] values) => new C3f(values); /// /// Creates a new array from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](C3f color) => new double[] { Col.FloatToDouble(color.R), Col.FloatToDouble(color.G), Col.FloatToDouble(color.B) }; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b Map(Func channel_fun) { return new C3b(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us Map(Func channel_fun) { return new C3us(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui Map(Func channel_fun) { return new C3ui(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f Map(Func channel_fun) { return new C3f(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d Map(Func channel_fun) { return new C3d(channel_fun(R), channel_fun(G), channel_fun(B)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(R); array[start + 1] = element_fun(G); array[start + 2] = element_fun(B); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(R, 0); array[start + 1] = element_index_fun(G, 1); array[start + 2] = element_index_fun(B, 2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float[] ToArray() => (float[])this; #endregion #region Indexer /// /// Indexer in canonical order 0=R, 1=G, 2=B, 3=A (availability depending on color type). /// public unsafe float this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &R) { ptr[i] = value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &R) { return ptr[i]; } } } #endregion #region Constants /// /// C3f with all components zero. /// public static C3f Zero => new C3f(0.0f, 0.0f, 0.0f); // Web colors public static C3f AliceBlue => new C3f((float)(0.941176), (float)(0.972549), (float)(1)); public static C3f AntiqueWhite => new C3f((float)(0.980392), (float)(0.921569), (float)(0.843137)); public static C3f Aqua => new C3f((float)(0), (float)(1), (float)(1)); public static C3f Aquamarine => new C3f((float)(0.498039), (float)(1), (float)(0.831373)); public static C3f Azure => new C3f((float)(0.941176), (float)(1), (float)(1)); public static C3f Beige => new C3f((float)(0.960784), (float)(0.960784), (float)(0.862745)); public static C3f Bisque => new C3f((float)(1), (float)(0.894118), (float)(0.768627)); public static C3f Black => new C3f((float)(0), (float)(0), (float)(0)); public static C3f BlanchedAlmond => new C3f((float)(1), (float)(0.921569), (float)(0.803922)); public static C3f Blue => new C3f((float)(0), (float)(0), (float)(1)); public static C3f BlueViolet => new C3f((float)(0.541176), (float)(0.168627), (float)(0.886275)); public static C3f Brown => new C3f((float)(0.647059), (float)(0.164706), (float)(0.164706)); public static C3f BurlyWood => new C3f((float)(0.870588), (float)(0.721569), (float)(0.529412)); public static C3f CadetBlue => new C3f((float)(0.372549), (float)(0.619608), (float)(0.627451)); public static C3f Chartreuse => new C3f((float)(0.498039), (float)(1), (float)(0)); public static C3f Chocolate => new C3f((float)(0.823529), (float)(0.411765), (float)(0.117647)); public static C3f Coral => new C3f((float)(1), (float)(0.498039), (float)(0.313725)); public static C3f CornflowerBlue => new C3f((float)(0.392157), (float)(0.584314), (float)(0.929412)); public static C3f Cornsilk => new C3f((float)(1), (float)(0.972549), (float)(0.862745)); public static C3f Crimson => new C3f((float)(0.862745), (float)(0.078431), (float)(0.235294)); public static C3f Cyan => new C3f((float)(0), (float)(1), (float)(1)); public static C3f DarkBlue => new C3f((float)(0), (float)(0), (float)(0.545098)); public static C3f DarkCyan => new C3f((float)(0), (float)(0.545098), (float)(0.545098)); public static C3f DarkGoldenRod => new C3f((float)(0.721569), (float)(0.52549), (float)(0.043137)); public static C3f DarkGray => new C3f((float)(0.662745), (float)(0.662745), (float)(0.662745)); public static C3f DarkGrey => new C3f((float)(0.662745), (float)(0.662745), (float)(0.662745)); public static C3f DarkGreen => new C3f((float)(0), (float)(0.392157), (float)(0)); public static C3f DarkKhaki => new C3f((float)(0.741176), (float)(0.717647), (float)(0.419608)); public static C3f DarkMagenta => new C3f((float)(0.545098), (float)(0), (float)(0.545098)); public static C3f DarkOliveGreen => new C3f((float)(0.333333), (float)(0.419608), (float)(0.184314)); public static C3f DarkOrange => new C3f((float)(1), (float)(0.54902), (float)(0)); public static C3f DarkOrchid => new C3f((float)(0.6), (float)(0.196078), (float)(0.8)); public static C3f DarkRed => new C3f((float)(0.545098), (float)(0), (float)(0)); public static C3f DarkSalmon => new C3f((float)(0.913725), (float)(0.588235), (float)(0.478431)); public static C3f DarkSeaGreen => new C3f((float)(0.560784), (float)(0.737255), (float)(0.560784)); public static C3f DarkSlateBlue => new C3f((float)(0.282353), (float)(0.239216), (float)(0.545098)); public static C3f DarkSlateGray => new C3f((float)(0.184314), (float)(0.309804), (float)(0.309804)); public static C3f DarkSlateGrey => new C3f((float)(0.184314), (float)(0.309804), (float)(0.309804)); public static C3f DarkTurquoise => new C3f((float)(0), (float)(0.807843), (float)(0.819608)); public static C3f DarkViolet => new C3f((float)(0.580392), (float)(0), (float)(0.827451)); public static C3f DeepPink => new C3f((float)(1), (float)(0.078431), (float)(0.576471)); public static C3f DeepSkyBlue => new C3f((float)(0), (float)(0.74902), (float)(1)); public static C3f DimGray => new C3f((float)(0.411765), (float)(0.411765), (float)(0.411765)); public static C3f DimGrey => new C3f((float)(0.411765), (float)(0.411765), (float)(0.411765)); public static C3f DodgerBlue => new C3f((float)(0.117647), (float)(0.564706), (float)(1)); public static C3f FireBrick => new C3f((float)(0.698039), (float)(0.133333), (float)(0.133333)); public static C3f FloralWhite => new C3f((float)(1), (float)(0.980392), (float)(0.941176)); public static C3f ForestGreen => new C3f((float)(0.133333), (float)(0.545098), (float)(0.133333)); public static C3f Fuchsia => new C3f((float)(1), (float)(0), (float)(1)); public static C3f Gainsboro => new C3f((float)(0.862745), (float)(0.862745), (float)(0.862745)); public static C3f GhostWhite => new C3f((float)(0.972549), (float)(0.972549), (float)(1)); public static C3f Gold => new C3f((float)(1), (float)(0.843137), (float)(0)); public static C3f GoldenRod => new C3f((float)(0.854902), (float)(0.647059), (float)(0.12549)); public static C3f Gray => new C3f((float)(0.501961), (float)(0.501961), (float)(0.501961)); public static C3f Grey => new C3f((float)(0.501961), (float)(0.501961), (float)(0.501961)); public static C3f Green => new C3f((float)(0), (float)(0.501961), (float)(0)); public static C3f GreenYellow => new C3f((float)(0.678431), (float)(1), (float)(0.184314)); public static C3f HoneyDew => new C3f((float)(0.941176), (float)(1), (float)(0.941176)); public static C3f HotPink => new C3f((float)(1), (float)(0.411765), (float)(0.705882)); public static C3f IndianRed => new C3f((float)(0.803922), (float)(0.360784), (float)(0.360784)); public static C3f Indigo => new C3f((float)(0.294118), (float)(0), (float)(0.509804)); public static C3f Ivory => new C3f((float)(1), (float)(1), (float)(0.941176)); public static C3f Khaki => new C3f((float)(0.941176), (float)(0.901961), (float)(0.54902)); public static C3f Lavender => new C3f((float)(0.901961), (float)(0.901961), (float)(0.980392)); public static C3f LavenderBlush => new C3f((float)(1), (float)(0.941176), (float)(0.960784)); public static C3f LawnGreen => new C3f((float)(0.486275), (float)(0.988235), (float)(0)); public static C3f LemonChiffon => new C3f((float)(1), (float)(0.980392), (float)(0.803922)); public static C3f LightBlue => new C3f((float)(0.678431), (float)(0.847059), (float)(0.901961)); public static C3f LightCoral => new C3f((float)(0.941176), (float)(0.501961), (float)(0.501961)); public static C3f LightCyan => new C3f((float)(0.878431), (float)(1), (float)(1)); public static C3f LightGoldenRodYellow => new C3f((float)(0.980392), (float)(0.980392), (float)(0.823529)); public static C3f LightGray => new C3f((float)(0.827451), (float)(0.827451), (float)(0.827451)); public static C3f LightGrey => new C3f((float)(0.827451), (float)(0.827451), (float)(0.827451)); public static C3f LightGreen => new C3f((float)(0.564706), (float)(0.933333), (float)(0.564706)); public static C3f LightPink => new C3f((float)(1), (float)(0.713725), (float)(0.756863)); public static C3f LightSalmon => new C3f((float)(1), (float)(0.627451), (float)(0.478431)); public static C3f LightSeaGreen => new C3f((float)(0.12549), (float)(0.698039), (float)(0.666667)); public static C3f LightSkyBlue => new C3f((float)(0.529412), (float)(0.807843), (float)(0.980392)); public static C3f LightSlateGray => new C3f((float)(0.466667), (float)(0.533333), (float)(0.6)); public static C3f LightSlateGrey => new C3f((float)(0.466667), (float)(0.533333), (float)(0.6)); public static C3f LightSteelBlue => new C3f((float)(0.690196), (float)(0.768627), (float)(0.870588)); public static C3f LightYellow => new C3f((float)(1), (float)(1), (float)(0.878431)); public static C3f Lime => new C3f((float)(0), (float)(1), (float)(0)); public static C3f LimeGreen => new C3f((float)(0.196078), (float)(0.803922), (float)(0.196078)); public static C3f Linen => new C3f((float)(0.980392), (float)(0.941176), (float)(0.901961)); public static C3f Magenta => new C3f((float)(1), (float)(0), (float)(1)); public static C3f Maroon => new C3f((float)(0.501961), (float)(0), (float)(0)); public static C3f MediumAquaMarine => new C3f((float)(0.4), (float)(0.803922), (float)(0.666667)); public static C3f MediumBlue => new C3f((float)(0), (float)(0), (float)(0.803922)); public static C3f MediumOrchid => new C3f((float)(0.729412), (float)(0.333333), (float)(0.827451)); public static C3f MediumPurple => new C3f((float)(0.576471), (float)(0.439216), (float)(0.847059)); public static C3f MediumSeaGreen => new C3f((float)(0.235294), (float)(0.701961), (float)(0.443137)); public static C3f MediumSlateBlue => new C3f((float)(0.482353), (float)(0.407843), (float)(0.933333)); public static C3f MediumSpringGreen => new C3f((float)(0), (float)(0.980392), (float)(0.603922)); public static C3f MediumTurquoise => new C3f((float)(0.282353), (float)(0.819608), (float)(0.8)); public static C3f MediumVioletRed => new C3f((float)(0.780392), (float)(0.082353), (float)(0.521569)); public static C3f MidnightBlue => new C3f((float)(0.098039), (float)(0.098039), (float)(0.439216)); public static C3f MintCream => new C3f((float)(0.960784), (float)(1), (float)(0.980392)); public static C3f MistyRose => new C3f((float)(1), (float)(0.894118), (float)(0.882353)); public static C3f Moccasin => new C3f((float)(1), (float)(0.894118), (float)(0.709804)); public static C3f NavajoWhite => new C3f((float)(1), (float)(0.870588), (float)(0.678431)); public static C3f Navy => new C3f((float)(0), (float)(0), (float)(0.501961)); public static C3f OldLace => new C3f((float)(0.992157), (float)(0.960784), (float)(0.901961)); public static C3f Olive => new C3f((float)(0.501961), (float)(0.501961), (float)(0)); public static C3f OliveDrab => new C3f((float)(0.419608), (float)(0.556863), (float)(0.137255)); public static C3f Orange => new C3f((float)(1), (float)(0.647059), (float)(0)); public static C3f OrangeRed => new C3f((float)(1), (float)(0.270588), (float)(0)); public static C3f Orchid => new C3f((float)(0.854902), (float)(0.439216), (float)(0.839216)); public static C3f PaleGoldenRod => new C3f((float)(0.933333), (float)(0.909804), (float)(0.666667)); public static C3f PaleGreen => new C3f((float)(0.596078), (float)(0.984314), (float)(0.596078)); public static C3f PaleTurquoise => new C3f((float)(0.686275), (float)(0.933333), (float)(0.933333)); public static C3f PaleVioletRed => new C3f((float)(0.847059), (float)(0.439216), (float)(0.576471)); public static C3f PapayaWhip => new C3f((float)(1), (float)(0.937255), (float)(0.835294)); public static C3f PeachPuff => new C3f((float)(1), (float)(0.854902), (float)(0.72549)); public static C3f Peru => new C3f((float)(0.803922), (float)(0.521569), (float)(0.247059)); public static C3f Pink => new C3f((float)(1), (float)(0.752941), (float)(0.796078)); public static C3f Plum => new C3f((float)(0.866667), (float)(0.627451), (float)(0.866667)); public static C3f PowderBlue => new C3f((float)(0.690196), (float)(0.878431), (float)(0.901961)); public static C3f Purple => new C3f((float)(0.501961), (float)(0), (float)(0.501961)); public static C3f Red => new C3f((float)(1), (float)(0), (float)(0)); public static C3f RosyBrown => new C3f((float)(0.737255), (float)(0.560784), (float)(0.560784)); public static C3f RoyalBlue => new C3f((float)(0.254902), (float)(0.411765), (float)(0.882353)); public static C3f SaddleBrown => new C3f((float)(0.545098), (float)(0.270588), (float)(0.07451)); public static C3f Salmon => new C3f((float)(0.980392), (float)(0.501961), (float)(0.447059)); public static C3f SandyBrown => new C3f((float)(0.956863), (float)(0.643137), (float)(0.376471)); public static C3f SeaGreen => new C3f((float)(0.180392), (float)(0.545098), (float)(0.341176)); public static C3f SeaShell => new C3f((float)(1), (float)(0.960784), (float)(0.933333)); public static C3f Sienna => new C3f((float)(0.627451), (float)(0.321569), (float)(0.176471)); public static C3f Silver => new C3f((float)(0.752941), (float)(0.752941), (float)(0.752941)); public static C3f SkyBlue => new C3f((float)(0.529412), (float)(0.807843), (float)(0.921569)); public static C3f SlateBlue => new C3f((float)(0.415686), (float)(0.352941), (float)(0.803922)); public static C3f SlateGray => new C3f((float)(0.439216), (float)(0.501961), (float)(0.564706)); public static C3f SlateGrey => new C3f((float)(0.439216), (float)(0.501961), (float)(0.564706)); public static C3f Snow => new C3f((float)(1), (float)(0.980392), (float)(0.980392)); public static C3f SpringGreen => new C3f((float)(0), (float)(1), (float)(0.498039)); public static C3f SteelBlue => new C3f((float)(0.27451), (float)(0.509804), (float)(0.705882)); public static C3f Tan => new C3f((float)(0.823529), (float)(0.705882), (float)(0.54902)); public static C3f Teal => new C3f((float)(0), (float)(0.501961), (float)(0.501961)); public static C3f Thistle => new C3f((float)(0.847059), (float)(0.74902), (float)(0.847059)); public static C3f Tomato => new C3f((float)(1), (float)(0.388235), (float)(0.278431)); public static C3f Turquoise => new C3f((float)(0.25098), (float)(0.878431), (float)(0.815686)); public static C3f Violet => new C3f((float)(0.933333), (float)(0.509804), (float)(0.933333)); public static C3f Wheat => new C3f((float)(0.960784), (float)(0.870588), (float)(0.701961)); public static C3f White => new C3f((float)(1), (float)(1), (float)(1)); public static C3f WhiteSmoke => new C3f((float)(0.960784), (float)(0.960784), (float)(0.960784)); public static C3f Yellow => new C3f((float)(1), (float)(1), (float)(0)); public static C3f YellowGreen => new C3f((float)(0.603922), (float)(0.803922), (float)(0.196078)); public static C3f DarkYellow => Olive; public static C3f VRVisGreen => new C3f((float)(0.698), (float)(0.851), (float)(0.008)); public static C3f Gray10 => new C3f((float)(0.1)); public static C3f Gray20 => new C3f((float)(0.2)); public static C3f Gray30 => new C3f((float)(0.3)); public static C3f Gray40 => new C3f((float)(0.4)); public static C3f Gray50 => new C3f((float)(0.5)); public static C3f Gray60 => new C3f((float)(0.6)); public static C3f Gray70 => new C3f((float)(0.7)); public static C3f Gray80 => new C3f((float)(0.8)); public static C3f Gray90 => new C3f((float)(0.9)); #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(C3f a, C3f b) { return a.R == b.R && a.G == b.G && a.B == b.B; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(C3f a, C3f b) { return a.R != b.R || a.G != b.G || a.B != b.B; } #endregion #region Color Arithmetic [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator +(C3f c0, C3b c1) { return new C3f( (float)(c0.R + Col.ByteToFloat(c1.R)), (float)(c0.G + Col.ByteToFloat(c1.G)), (float)(c0.B + Col.ByteToFloat(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator -(C3f c0, C3b c1) { return new C3f( (float)(c0.R - Col.ByteToFloat(c1.R)), (float)(c0.G - Col.ByteToFloat(c1.G)), (float)(c0.B - Col.ByteToFloat(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator +(C3f c0, C3us c1) { return new C3f( (float)(c0.R + Col.UShortToFloat(c1.R)), (float)(c0.G + Col.UShortToFloat(c1.G)), (float)(c0.B + Col.UShortToFloat(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator -(C3f c0, C3us c1) { return new C3f( (float)(c0.R - Col.UShortToFloat(c1.R)), (float)(c0.G - Col.UShortToFloat(c1.G)), (float)(c0.B - Col.UShortToFloat(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator +(C3f c0, C3ui c1) { return new C3f( (float)(c0.R + Col.UIntToFloat(c1.R)), (float)(c0.G + Col.UIntToFloat(c1.G)), (float)(c0.B + Col.UIntToFloat(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator -(C3f c0, C3ui c1) { return new C3f( (float)(c0.R - Col.UIntToFloat(c1.R)), (float)(c0.G - Col.UIntToFloat(c1.G)), (float)(c0.B - Col.UIntToFloat(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator +(C3f c0, C3d c1) { return new C3f( (float)(c0.R + (float)(c1.R)), (float)(c0.G + (float)(c1.G)), (float)(c0.B + (float)(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator -(C3f c0, C3d c1) { return new C3f( (float)(c0.R - (float)(c1.R)), (float)(c0.G - (float)(c1.G)), (float)(c0.B - (float)(c1.B))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator *(C3f col, float scalar) { return new C3f((float)(col.R * scalar), (float)(col.G * scalar), (float)(col.B * scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator *(float scalar, C3f col) { return new C3f((float)(scalar * col.R), (float)(scalar * col.G), (float)(scalar * col.B)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator /(C3f col, float scalar) { return new C3f((float)(col.R / scalar), (float)(col.G / scalar), (float)(col.B / scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator /(float scalar, C3f col) { return new C3f((float)(scalar / col.R), (float)(scalar / col.G), (float)(scalar / col.B)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator *(C3f c0, C3f c1) { return new C3f((float)(c0.R * c1.R), (float)(c0.G * c1.G), (float)(c0.B * c1.B)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator /(C3f c0, C3f c1) { return new C3f((float)(c0.R / c1.R), (float)(c0.G / c1.G), (float)(c0.B / c1.B)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator +(C3f c0, C3f c1) { return new C3f(c0.R + c1.R, c0.G + c1.G, c0.B + c1.B); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator +(C3f col, float scalar) { return new C3f(col.R + scalar, col.G + scalar, col.B + scalar); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator +(float scalar, C3f col) => col + scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator -(C3f c0, C3f c1) { return new C3f(c0.R - c1.R, c0.G - c1.G, c0.B - c1.B); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator -(C3f col, float scalar) { return new C3f(col.R - scalar, col.G - scalar, col.B - scalar); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f operator -(float scalar, C3f col) { return new C3f(scalar - col.R, scalar - col.G, scalar - col.B); } /// /// Clamps the color channels to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clamp(float min, float max) { R = R.Clamp(min, max); G = G.Clamp(min, max); B = B.Clamp(min, max); } /// /// Returns a copy with the color channels clamped to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f Clamped(float min, float max) { return new C3f(R.Clamp(min, max), G.Clamp(min, max), B.Clamp(min, max)); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |R| + |G| + |B|. /// public readonly float Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Abs(R) + Fun.Abs(G) + Fun.Abs(B); } } /// /// Returns the Euclidean (or 2-) norm of the color. This is calculated /// as sqrt(R^2 + G^2 + B^2). /// public readonly float Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(R * R + G * G + B * B); } } /// /// Returns the infinite (or maximum) norm of the color. This is /// calculated as max(|R|, |G|, |B|). /// public readonly float NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(Fun.Abs(R), Fun.Abs(G), Fun.Abs(B)); } } /// /// Returns the minimum norm of the color. This is calculated as /// min(|R|, |G|, |B|). /// public readonly float NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(Fun.Abs(R), Fun.Abs(G), Fun.Abs(B)); } } #endregion #region Overrides public override readonly bool Equals(object other) => (other is C3f o) ? Equals(o) : false; public override readonly int GetHashCode() { return HashCode.GetCombined(R, G, B); } public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + R.ToString(null, CultureInfo.InvariantCulture) + ", " + G.ToString(null, CultureInfo.InvariantCulture) + ", " + B.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref C3f color, int i, float value) => { switch (i) { case 0: color.R = value; return; case 1: color.G = value; return; case 2: color.B = value; return; default: throw new IndexOutOfRangeException(); } }; [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f LinearInterp(float t, C3f a, C3f b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f LinearInterp(V3f t, C3f a, C3f b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f DivideByInt(C3f c, int x) => c / x; #endregion #region Parsing /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C3f.Zero otherwise. /// True on success, false otherwise. public static bool TryParse(Text t, out C3f result) { if (Col.TryParseHex(t, out C4b tmp)) { result = tmp.ToC3f(); return true; } else { bool success = true; float[] values = new float[4] { 1.0f, 1.0f, 1.0f, 1.0f }; float parse(Text t) { if (!float.TryParse(t.ToString(), NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out float value)) success = false; return value; }; var count = t.NestedBracketSplitCount2(1); if (count == 3 || count == 4) t.NestedBracketSplit(1, parse, () => values); else success = false; result = success ? new C3f(values) : Zero; return success; } } /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C3f.Zero otherwise. /// True on success, false otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParse(string s, out C3f result) => TryParse(new Text(s), out result); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C3f color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f Parse(string s) => Parse(new Text(s)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f Parse(Text t, int bracketLevel = 1) => t.NestedBracketSplit(bracketLevel, Text.Parse, C3f.Setter); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C3f color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f Parse(Text t) => TryParse(t, out C3f result) ? result : throw new FormatException($"{t} is not a valid C3f color."); #endregion #region IFormattable Members public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + R.ToString(format, fp) + between + G.ToString(format, fp) + between + B.ToString(format, fp) + end; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(C3f other) { return R.Equals(other.R) && G.Equals(other.G) && B.Equals(other.B); } #endregion #region IRGB Members double IRGB.Red { readonly get { return (double)(R); } set { R = (float)(value); } } double IRGB.Green { readonly get { return (double)(G); } set { G = (float)(value); } } double IRGB.Blue { readonly get { return (double)(B); } set { B = (float)(value); } } #endregion } public static partial class Fun { #region Interpolation /// /// Returns the linearly interpolated color between a and b. /// public static C3f Lerp(this float t, C3f a, C3f b) => new C3f(Lerp(t, a.R, b.R), Lerp(t, a.G, b.G), Lerp(t, a.B, b.B)); /// /// Returns the linearly interpolated color between a and b. /// public static C3f Lerp(this V3f t, C3f a, C3f b) => new C3f(Lerp(t.X, a.R, b.R), Lerp(t.Y, a.G, b.G), Lerp(t.Z, a.B, b.B)); #endregion #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this C3f a, C3f b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this C3f a, C3f b, float tolerance) { return ApproximateEquals(a.R, b.R, tolerance) && ApproximateEquals(a.G, b.G, tolerance) && ApproximateEquals(a.B, b.B, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this C3f c, float epsilon) => Col.AllTiny(c, epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(C3f c) => c.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any component of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(C3f c) => c.IsNaN; /// /// Returns whether any component of the the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(C3f c) => c.IsInfinity; /// /// Returns whether any component of the the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(C3f c) => c.IsPositiveInfinity; /// /// Returns whether any component of the the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(C3f c) => c.IsNegativeInfinity; /// /// Returns whether all components of the the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(C3f c) => c.IsFinite; #endregion } public static partial class Col { #region ToHexString /// /// Returns the hexadecimal representation with format RRGGBB. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToHexString(this C3f c) => c.ToC3b().ToHexString(); #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C3f a, C3f b) { return (a.R < b.R && a.G < b.G && a.B < b.B); } /// /// Returns whether ALL elements of col are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C3f col, float s) { return (col.R < s && col.G < s && col.B < s); } /// /// Returns whether a is Smaller ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(float s, C3f col) { return (s < col.R && s < col.G && s < col.B); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C3f a, C3f b) { return (a.R < b.R || a.G < b.G || a.B < b.B); } /// /// Returns whether AT LEAST ONE element of col is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C3f col, float s) { return (col.R < s || col.G < s || col.B < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(float s, C3f col) { return (s < col.R || s < col.G || s < col.B); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C3f a, C3f b) { return (a.R > b.R && a.G > b.G && a.B > b.B); } /// /// Returns whether ALL elements of col are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C3f col, float s) { return (col.R > s && col.G > s && col.B > s); } /// /// Returns whether a is Greater ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(float s, C3f col) { return (s > col.R && s > col.G && s > col.B); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C3f a, C3f b) { return (a.R > b.R || a.G > b.G || a.B > b.B); } /// /// Returns whether AT LEAST ONE element of col is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C3f col, float s) { return (col.R > s || col.G > s || col.B > s); } /// /// Returns whether a is Greater AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(float s, C3f col) { return (s > col.R || s > col.G || s > col.B); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C3f a, C3f b) { return (a.R <= b.R && a.G <= b.G && a.B <= b.B); } /// /// Returns whether ALL elements of col are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C3f col, float s) { return (col.R <= s && col.G <= s && col.B <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(float s, C3f col) { return (s <= col.R && s <= col.G && s <= col.B); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C3f a, C3f b) { return (a.R <= b.R || a.G <= b.G || a.B <= b.B); } /// /// Returns whether AT LEAST ONE element of col is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C3f col, float s) { return (col.R <= s || col.G <= s || col.B <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(float s, C3f col) { return (s <= col.R || s <= col.G || s <= col.B); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C3f a, C3f b) { return (a.R >= b.R && a.G >= b.G && a.B >= b.B); } /// /// Returns whether ALL elements of col are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C3f col, float s) { return (col.R >= s && col.G >= s && col.B >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(float s, C3f col) { return (s >= col.R && s >= col.G && s >= col.B); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C3f a, C3f b) { return (a.R >= b.R || a.G >= b.G || a.B >= b.B); } /// /// Returns whether AT LEAST ONE element of col is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C3f col, float s) { return (col.R >= s || col.G >= s || col.B >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(float s, C3f col) { return (s >= col.R || s >= col.G || s >= col.B); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C3f a, C3f b) { return (a.R == b.R && a.G == b.G && a.B == b.B); } /// /// Returns whether ALL elements of col are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C3f col, float s) { return (col.R == s && col.G == s && col.B == s); } /// /// Returns whether a is Equal ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(float s, C3f col) { return (s == col.R && s == col.G && s == col.B); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C3f a, C3f b) { return (a.R == b.R || a.G == b.G || a.B == b.B); } /// /// Returns whether AT LEAST ONE element of col is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C3f col, float s) { return (col.R == s || col.G == s || col.B == s); } /// /// Returns whether a is Equal AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(float s, C3f col) { return (s == col.R || s == col.G || s == col.B); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C3f a, C3f b) { return (a.R != b.R && a.G != b.G && a.B != b.B); } /// /// Returns whether ALL elements of col are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C3f col, float s) { return (col.R != s && col.G != s && col.B != s); } /// /// Returns whether a is Different ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(float s, C3f col) { return (s != col.R && s != col.G && s != col.B); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C3f a, C3f b) { return (a.R != b.R || a.G != b.G || a.B != b.B); } /// /// Returns whether AT LEAST ONE element of col is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C3f col, float s) { return (col.R != s || col.G != s || col.B != s); } /// /// Returns whether a is Different AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(float s, C3f col) { return (s != col.R || s != col.G || s != col.B); } #endregion #region Linear Combination /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f LinCom( C3f p0, C3f p1, C3f p2, C3f p3, ref Tup4 w) { return new C3f( (p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3), (p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3), (p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3)); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f LinCom( C3f p0, C3f p1, C3f p2, C3f p3, C3f p4, C3f p5, ref Tup6 w) { return new C3f( (p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5), (p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5), (p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5)); } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this C3f c, float epsilon) => c.R.IsTiny(epsilon) || c.G.IsTiny(epsilon) || c.B.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this C3f c, float epsilon) => c.R.IsTiny(epsilon) && c.G.IsTiny(epsilon) && c.B.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(C3f c) => c.AnyNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(C3f c) => c.AllNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(C3f c) => c.AnyInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(C3f c) => c.AllInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(C3f c) => c.AnyPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(C3f c) => c.AllPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(C3f c) => c.AnyNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(C3f c) => c.AllNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(C3f c) => c.AnyTiny; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(C3f c) => c.AllTiny; #endregion } public static class IRandomUniformC3fExtensions { #region IRandomUniform extensions for C3f /// /// Uses UniformFloat() to generate the elements of a C3f color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f UniformC3f(this IRandomUniform rnd) { return new C3f(rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat()); } /// /// Uses UniformFloatClosed() to generate the elements of a C3f color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f UniformC3fClosed(this IRandomUniform rnd) { return new C3f(rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed()); } /// /// Uses UniformFloatOpen() to generate the elements of a C3f color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3f UniformC3fOpen(this IRandomUniform rnd) { return new C3f(rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen()); } #endregion } #endregion #region C3d /// /// Represents an RGB color with each channel stored as a value within [0, 1]. /// [Serializable] public partial struct C3d : IFormattable, IEquatable, IRGB { #region Constructors /// /// Creates a color from the given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(double r, double g, double b) { R = r; G = g; B = b; } /// /// Creates a color from the given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(float r, float g, float b) { R = (double)(r); G = (double)(g); B = (double)(b); } /// /// Creates a color from a single value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(double gray) { R = gray; G = gray; B = gray; } /// /// Creates a color from a single value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(float gray) { var value = (double)(gray); R = value; G = value; B = value; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(C3b color) { R = Col.ByteToDouble(color.R); G = Col.ByteToDouble(color.G); B = Col.ByteToDouble(color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(C3us color) { R = Col.UShortToDouble(color.R); G = Col.UShortToDouble(color.G); B = Col.UShortToDouble(color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(C3ui color) { R = Col.UIntToDouble(color.R); G = Col.UIntToDouble(color.G); B = Col.UIntToDouble(color.B); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(C3f color) { R = Col.FloatToDouble(color.R); G = Col.FloatToDouble(color.G); B = Col.FloatToDouble(color.B); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(C3d color) { R = (color.R); G = (color.G); B = (color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(C4b color) { R = Col.ByteToDouble(color.R); G = Col.ByteToDouble(color.G); B = Col.ByteToDouble(color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(C4us color) { R = Col.UShortToDouble(color.R); G = Col.UShortToDouble(color.G); B = Col.UShortToDouble(color.B); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(C4ui color) { R = Col.UIntToDouble(color.R); G = Col.UIntToDouble(color.G); B = Col.UIntToDouble(color.B); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(C4f color) { R = Col.FloatToDouble(color.R); G = Col.FloatToDouble(color.G); B = Col.FloatToDouble(color.B); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(C4d color) { R = (color.R); G = (color.G); B = (color.B); } /// /// Creates a color from the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(V3f vec) { R = (double)(vec.X); G = (double)(vec.Y); B = (double)(vec.Z); } /// /// Creates a color from the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(V3d vec) { R = (vec.X); G = (vec.Y); B = (vec.Z); } /// /// Creates a color from the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(V4f vec) { R = (double)(vec.X); G = (double)(vec.Y); B = (double)(vec.Z); } /// /// Creates a color from the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(V4d vec) { R = (vec.X); G = (vec.Y); B = (vec.Z); } /// /// Creates a color from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(Func index_fun) { R = index_fun(0); G = index_fun(1); B = index_fun(2); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(byte[] values) { R = Col.ByteToDouble(values[0]); G = Col.ByteToDouble(values[1]); B = Col.ByteToDouble(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(byte[] values, int start) { R = Col.ByteToDouble(values[start + 0]); G = Col.ByteToDouble(values[start + 1]); B = Col.ByteToDouble(values[start + 2]); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(ushort[] values) { R = Col.UShortToDouble(values[0]); G = Col.UShortToDouble(values[1]); B = Col.UShortToDouble(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(ushort[] values, int start) { R = Col.UShortToDouble(values[start + 0]); G = Col.UShortToDouble(values[start + 1]); B = Col.UShortToDouble(values[start + 2]); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(uint[] values) { R = Col.UIntToDouble(values[0]); G = Col.UIntToDouble(values[1]); B = Col.UIntToDouble(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(uint[] values, int start) { R = Col.UIntToDouble(values[start + 0]); G = Col.UIntToDouble(values[start + 1]); B = Col.UIntToDouble(values[start + 2]); } /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(float[] values) { R = Col.FloatToDouble(values[0]); G = Col.FloatToDouble(values[1]); B = Col.FloatToDouble(values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(float[] values, int start) { R = Col.FloatToDouble(values[start + 0]); G = Col.FloatToDouble(values[start + 1]); B = Col.FloatToDouble(values[start + 2]); } /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(double[] values) { R = (values[0]); G = (values[1]); B = (values[2]); } /// /// Creates a new color from the given array, starting at the specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C3d(double[] values, int start) { R = (values[start + 0]); G = (values[start + 1]); B = (values[start + 2]); } #endregion #region Properities public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNaN(R) || double.IsNaN(G) || double.IsNaN(B); } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNaN(R) && double.IsNaN(G) && double.IsNaN(B); } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsInfinity(R) || double.IsInfinity(G) || double.IsInfinity(B); } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsInfinity(R) && double.IsInfinity(G) && double.IsInfinity(B); } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsPositiveInfinity(R) || double.IsPositiveInfinity(G) || double.IsPositiveInfinity(B); } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsPositiveInfinity(R) && double.IsPositiveInfinity(G) && double.IsPositiveInfinity(B); } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNegativeInfinity(R) || double.IsNegativeInfinity(G) || double.IsNegativeInfinity(B); } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNegativeInfinity(R) && double.IsNegativeInfinity(G) && double.IsNegativeInfinity(B); } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(R) || Fun.IsTiny(G) || Fun.IsTiny(B); } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(R) && Fun.IsTiny(G) && Fun.IsTiny(B); } /// /// Returns true if the absolute value of each component of the color is smaller than Constant<double>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any component of the color is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any component of the color is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any component of the color is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any component of the color is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all components of the color are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Conversions /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(C3b color) => new C3d(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d FromC3b(C3b c) => new C3d(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(C3us color) => new C3d(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d FromC3us(C3us c) => new C3d(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(C3ui color) => new C3d(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d FromC3ui(C3ui c) => new C3d(c); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(C3f color) => new C3d(color); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f ToC3f() => (C3f)this; /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d FromC3f(C3f c) => new C3d(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(C4b color) => new C3d(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d FromC4b(C4b c) => new C3d(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(C4us color) => new C3d(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d FromC4us(C4us c) => new C3d(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(C4ui color) => new C3d(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d FromC4ui(C4ui c) => new C3d(c); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(C4f color) => new C3d(color); /// /// Converts the given color to a color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f ToC4f() => (C4f)this; /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d FromC4f(C4f c) => new C3d(c); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(C4d color) => new C3d(color); /// /// Converts the given color to a color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d ToC4d() => (C4d)this; /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d FromC4d(C4d c) => new C3d(c); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(V3f v) => new C3d(v); /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; /// /// Creates a color from a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d FromV3f(V3f c) => new C3d(c); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(V3d v) => new C3d(v); /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; /// /// Creates a color from a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d FromV3d(V3d c) => new C3d(c); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(V4f v) => new C3d(v); /// /// Converts the given color to a vector. /// W is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; /// /// Creates a color from a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d FromV4f(V4f c) => new C3d(c); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(V4d v) => new C3d(v); /// /// Converts the given color to a vector. /// W is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; /// /// Creates a color from a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d FromV4d(V4d c) => new C3d(c); /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(byte[] values) => new C3d(values); /// /// Creates a new array from the given color. /// The values are mapped and clamped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator byte[](C3d color) => new byte[] { Col.DoubleToByteClamped(color.R), Col.DoubleToByteClamped(color.G), Col.DoubleToByteClamped(color.B) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(ushort[] values) => new C3d(values); /// /// Creates a new array from the given color. /// The values are mapped and clamped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ushort[](C3d color) => new ushort[] { Col.DoubleToUShortClamped(color.R), Col.DoubleToUShortClamped(color.G), Col.DoubleToUShortClamped(color.B) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(uint[] values) => new C3d(values); /// /// Creates a new array from the given color. /// The values are mapped and clamped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](C3d color) => new uint[] { Col.DoubleToUIntClamped(color.R), Col.DoubleToUIntClamped(color.G), Col.DoubleToUIntClamped(color.B) }; /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(float[] values) => new C3d(values); /// /// Creates a new array from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](C3d color) => new float[] { Col.DoubleToFloat(color.R), Col.DoubleToFloat(color.G), Col.DoubleToFloat(color.B) }; /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C3d(double[] values) => new C3d(values); /// /// Creates a new array from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](C3d color) => new double[] { (color.R), (color.G), (color.B) }; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b Map(Func channel_fun) { return new C3b(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us Map(Func channel_fun) { return new C3us(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui Map(Func channel_fun) { return new C3ui(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f Map(Func channel_fun) { return new C3f(channel_fun(R), channel_fun(G), channel_fun(B)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d Map(Func channel_fun) { return new C3d(channel_fun(R), channel_fun(G), channel_fun(B)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(R); array[start + 1] = element_fun(G); array[start + 2] = element_fun(B); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(R, 0); array[start + 1] = element_index_fun(G, 1); array[start + 2] = element_index_fun(B, 2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double[] ToArray() => (double[])this; #endregion #region Indexer /// /// Indexer in canonical order 0=R, 1=G, 2=B, 3=A (availability depending on color type). /// public unsafe double this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &R) { ptr[i] = value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &R) { return ptr[i]; } } } #endregion #region Constants /// /// C3d with all components zero. /// public static C3d Zero => new C3d(0, 0, 0); // Web colors public static C3d AliceBlue => new C3d((0.941176), (0.972549), (1)); public static C3d AntiqueWhite => new C3d((0.980392), (0.921569), (0.843137)); public static C3d Aqua => new C3d((0), (1), (1)); public static C3d Aquamarine => new C3d((0.498039), (1), (0.831373)); public static C3d Azure => new C3d((0.941176), (1), (1)); public static C3d Beige => new C3d((0.960784), (0.960784), (0.862745)); public static C3d Bisque => new C3d((1), (0.894118), (0.768627)); public static C3d Black => new C3d((0), (0), (0)); public static C3d BlanchedAlmond => new C3d((1), (0.921569), (0.803922)); public static C3d Blue => new C3d((0), (0), (1)); public static C3d BlueViolet => new C3d((0.541176), (0.168627), (0.886275)); public static C3d Brown => new C3d((0.647059), (0.164706), (0.164706)); public static C3d BurlyWood => new C3d((0.870588), (0.721569), (0.529412)); public static C3d CadetBlue => new C3d((0.372549), (0.619608), (0.627451)); public static C3d Chartreuse => new C3d((0.498039), (1), (0)); public static C3d Chocolate => new C3d((0.823529), (0.411765), (0.117647)); public static C3d Coral => new C3d((1), (0.498039), (0.313725)); public static C3d CornflowerBlue => new C3d((0.392157), (0.584314), (0.929412)); public static C3d Cornsilk => new C3d((1), (0.972549), (0.862745)); public static C3d Crimson => new C3d((0.862745), (0.078431), (0.235294)); public static C3d Cyan => new C3d((0), (1), (1)); public static C3d DarkBlue => new C3d((0), (0), (0.545098)); public static C3d DarkCyan => new C3d((0), (0.545098), (0.545098)); public static C3d DarkGoldenRod => new C3d((0.721569), (0.52549), (0.043137)); public static C3d DarkGray => new C3d((0.662745), (0.662745), (0.662745)); public static C3d DarkGrey => new C3d((0.662745), (0.662745), (0.662745)); public static C3d DarkGreen => new C3d((0), (0.392157), (0)); public static C3d DarkKhaki => new C3d((0.741176), (0.717647), (0.419608)); public static C3d DarkMagenta => new C3d((0.545098), (0), (0.545098)); public static C3d DarkOliveGreen => new C3d((0.333333), (0.419608), (0.184314)); public static C3d DarkOrange => new C3d((1), (0.54902), (0)); public static C3d DarkOrchid => new C3d((0.6), (0.196078), (0.8)); public static C3d DarkRed => new C3d((0.545098), (0), (0)); public static C3d DarkSalmon => new C3d((0.913725), (0.588235), (0.478431)); public static C3d DarkSeaGreen => new C3d((0.560784), (0.737255), (0.560784)); public static C3d DarkSlateBlue => new C3d((0.282353), (0.239216), (0.545098)); public static C3d DarkSlateGray => new C3d((0.184314), (0.309804), (0.309804)); public static C3d DarkSlateGrey => new C3d((0.184314), (0.309804), (0.309804)); public static C3d DarkTurquoise => new C3d((0), (0.807843), (0.819608)); public static C3d DarkViolet => new C3d((0.580392), (0), (0.827451)); public static C3d DeepPink => new C3d((1), (0.078431), (0.576471)); public static C3d DeepSkyBlue => new C3d((0), (0.74902), (1)); public static C3d DimGray => new C3d((0.411765), (0.411765), (0.411765)); public static C3d DimGrey => new C3d((0.411765), (0.411765), (0.411765)); public static C3d DodgerBlue => new C3d((0.117647), (0.564706), (1)); public static C3d FireBrick => new C3d((0.698039), (0.133333), (0.133333)); public static C3d FloralWhite => new C3d((1), (0.980392), (0.941176)); public static C3d ForestGreen => new C3d((0.133333), (0.545098), (0.133333)); public static C3d Fuchsia => new C3d((1), (0), (1)); public static C3d Gainsboro => new C3d((0.862745), (0.862745), (0.862745)); public static C3d GhostWhite => new C3d((0.972549), (0.972549), (1)); public static C3d Gold => new C3d((1), (0.843137), (0)); public static C3d GoldenRod => new C3d((0.854902), (0.647059), (0.12549)); public static C3d Gray => new C3d((0.501961), (0.501961), (0.501961)); public static C3d Grey => new C3d((0.501961), (0.501961), (0.501961)); public static C3d Green => new C3d((0), (0.501961), (0)); public static C3d GreenYellow => new C3d((0.678431), (1), (0.184314)); public static C3d HoneyDew => new C3d((0.941176), (1), (0.941176)); public static C3d HotPink => new C3d((1), (0.411765), (0.705882)); public static C3d IndianRed => new C3d((0.803922), (0.360784), (0.360784)); public static C3d Indigo => new C3d((0.294118), (0), (0.509804)); public static C3d Ivory => new C3d((1), (1), (0.941176)); public static C3d Khaki => new C3d((0.941176), (0.901961), (0.54902)); public static C3d Lavender => new C3d((0.901961), (0.901961), (0.980392)); public static C3d LavenderBlush => new C3d((1), (0.941176), (0.960784)); public static C3d LawnGreen => new C3d((0.486275), (0.988235), (0)); public static C3d LemonChiffon => new C3d((1), (0.980392), (0.803922)); public static C3d LightBlue => new C3d((0.678431), (0.847059), (0.901961)); public static C3d LightCoral => new C3d((0.941176), (0.501961), (0.501961)); public static C3d LightCyan => new C3d((0.878431), (1), (1)); public static C3d LightGoldenRodYellow => new C3d((0.980392), (0.980392), (0.823529)); public static C3d LightGray => new C3d((0.827451), (0.827451), (0.827451)); public static C3d LightGrey => new C3d((0.827451), (0.827451), (0.827451)); public static C3d LightGreen => new C3d((0.564706), (0.933333), (0.564706)); public static C3d LightPink => new C3d((1), (0.713725), (0.756863)); public static C3d LightSalmon => new C3d((1), (0.627451), (0.478431)); public static C3d LightSeaGreen => new C3d((0.12549), (0.698039), (0.666667)); public static C3d LightSkyBlue => new C3d((0.529412), (0.807843), (0.980392)); public static C3d LightSlateGray => new C3d((0.466667), (0.533333), (0.6)); public static C3d LightSlateGrey => new C3d((0.466667), (0.533333), (0.6)); public static C3d LightSteelBlue => new C3d((0.690196), (0.768627), (0.870588)); public static C3d LightYellow => new C3d((1), (1), (0.878431)); public static C3d Lime => new C3d((0), (1), (0)); public static C3d LimeGreen => new C3d((0.196078), (0.803922), (0.196078)); public static C3d Linen => new C3d((0.980392), (0.941176), (0.901961)); public static C3d Magenta => new C3d((1), (0), (1)); public static C3d Maroon => new C3d((0.501961), (0), (0)); public static C3d MediumAquaMarine => new C3d((0.4), (0.803922), (0.666667)); public static C3d MediumBlue => new C3d((0), (0), (0.803922)); public static C3d MediumOrchid => new C3d((0.729412), (0.333333), (0.827451)); public static C3d MediumPurple => new C3d((0.576471), (0.439216), (0.847059)); public static C3d MediumSeaGreen => new C3d((0.235294), (0.701961), (0.443137)); public static C3d MediumSlateBlue => new C3d((0.482353), (0.407843), (0.933333)); public static C3d MediumSpringGreen => new C3d((0), (0.980392), (0.603922)); public static C3d MediumTurquoise => new C3d((0.282353), (0.819608), (0.8)); public static C3d MediumVioletRed => new C3d((0.780392), (0.082353), (0.521569)); public static C3d MidnightBlue => new C3d((0.098039), (0.098039), (0.439216)); public static C3d MintCream => new C3d((0.960784), (1), (0.980392)); public static C3d MistyRose => new C3d((1), (0.894118), (0.882353)); public static C3d Moccasin => new C3d((1), (0.894118), (0.709804)); public static C3d NavajoWhite => new C3d((1), (0.870588), (0.678431)); public static C3d Navy => new C3d((0), (0), (0.501961)); public static C3d OldLace => new C3d((0.992157), (0.960784), (0.901961)); public static C3d Olive => new C3d((0.501961), (0.501961), (0)); public static C3d OliveDrab => new C3d((0.419608), (0.556863), (0.137255)); public static C3d Orange => new C3d((1), (0.647059), (0)); public static C3d OrangeRed => new C3d((1), (0.270588), (0)); public static C3d Orchid => new C3d((0.854902), (0.439216), (0.839216)); public static C3d PaleGoldenRod => new C3d((0.933333), (0.909804), (0.666667)); public static C3d PaleGreen => new C3d((0.596078), (0.984314), (0.596078)); public static C3d PaleTurquoise => new C3d((0.686275), (0.933333), (0.933333)); public static C3d PaleVioletRed => new C3d((0.847059), (0.439216), (0.576471)); public static C3d PapayaWhip => new C3d((1), (0.937255), (0.835294)); public static C3d PeachPuff => new C3d((1), (0.854902), (0.72549)); public static C3d Peru => new C3d((0.803922), (0.521569), (0.247059)); public static C3d Pink => new C3d((1), (0.752941), (0.796078)); public static C3d Plum => new C3d((0.866667), (0.627451), (0.866667)); public static C3d PowderBlue => new C3d((0.690196), (0.878431), (0.901961)); public static C3d Purple => new C3d((0.501961), (0), (0.501961)); public static C3d Red => new C3d((1), (0), (0)); public static C3d RosyBrown => new C3d((0.737255), (0.560784), (0.560784)); public static C3d RoyalBlue => new C3d((0.254902), (0.411765), (0.882353)); public static C3d SaddleBrown => new C3d((0.545098), (0.270588), (0.07451)); public static C3d Salmon => new C3d((0.980392), (0.501961), (0.447059)); public static C3d SandyBrown => new C3d((0.956863), (0.643137), (0.376471)); public static C3d SeaGreen => new C3d((0.180392), (0.545098), (0.341176)); public static C3d SeaShell => new C3d((1), (0.960784), (0.933333)); public static C3d Sienna => new C3d((0.627451), (0.321569), (0.176471)); public static C3d Silver => new C3d((0.752941), (0.752941), (0.752941)); public static C3d SkyBlue => new C3d((0.529412), (0.807843), (0.921569)); public static C3d SlateBlue => new C3d((0.415686), (0.352941), (0.803922)); public static C3d SlateGray => new C3d((0.439216), (0.501961), (0.564706)); public static C3d SlateGrey => new C3d((0.439216), (0.501961), (0.564706)); public static C3d Snow => new C3d((1), (0.980392), (0.980392)); public static C3d SpringGreen => new C3d((0), (1), (0.498039)); public static C3d SteelBlue => new C3d((0.27451), (0.509804), (0.705882)); public static C3d Tan => new C3d((0.823529), (0.705882), (0.54902)); public static C3d Teal => new C3d((0), (0.501961), (0.501961)); public static C3d Thistle => new C3d((0.847059), (0.74902), (0.847059)); public static C3d Tomato => new C3d((1), (0.388235), (0.278431)); public static C3d Turquoise => new C3d((0.25098), (0.878431), (0.815686)); public static C3d Violet => new C3d((0.933333), (0.509804), (0.933333)); public static C3d Wheat => new C3d((0.960784), (0.870588), (0.701961)); public static C3d White => new C3d((1), (1), (1)); public static C3d WhiteSmoke => new C3d((0.960784), (0.960784), (0.960784)); public static C3d Yellow => new C3d((1), (1), (0)); public static C3d YellowGreen => new C3d((0.603922), (0.803922), (0.196078)); public static C3d DarkYellow => Olive; public static C3d VRVisGreen => new C3d((0.698), (0.851), (0.008)); public static C3d Gray10 => new C3d((0.1)); public static C3d Gray20 => new C3d((0.2)); public static C3d Gray30 => new C3d((0.3)); public static C3d Gray40 => new C3d((0.4)); public static C3d Gray50 => new C3d((0.5)); public static C3d Gray60 => new C3d((0.6)); public static C3d Gray70 => new C3d((0.7)); public static C3d Gray80 => new C3d((0.8)); public static C3d Gray90 => new C3d((0.9)); #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(C3d a, C3d b) { return a.R == b.R && a.G == b.G && a.B == b.B; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(C3d a, C3d b) { return a.R != b.R || a.G != b.G || a.B != b.B; } #endregion #region Color Arithmetic [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator +(C3d c0, C3b c1) { return new C3d( (double)(c0.R + Col.ByteToDouble(c1.R)), (double)(c0.G + Col.ByteToDouble(c1.G)), (double)(c0.B + Col.ByteToDouble(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator -(C3d c0, C3b c1) { return new C3d( (double)(c0.R - Col.ByteToDouble(c1.R)), (double)(c0.G - Col.ByteToDouble(c1.G)), (double)(c0.B - Col.ByteToDouble(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator +(C3d c0, C3us c1) { return new C3d( (double)(c0.R + Col.UShortToDouble(c1.R)), (double)(c0.G + Col.UShortToDouble(c1.G)), (double)(c0.B + Col.UShortToDouble(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator -(C3d c0, C3us c1) { return new C3d( (double)(c0.R - Col.UShortToDouble(c1.R)), (double)(c0.G - Col.UShortToDouble(c1.G)), (double)(c0.B - Col.UShortToDouble(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator +(C3d c0, C3ui c1) { return new C3d( (double)(c0.R + Col.UIntToDouble(c1.R)), (double)(c0.G + Col.UIntToDouble(c1.G)), (double)(c0.B + Col.UIntToDouble(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator -(C3d c0, C3ui c1) { return new C3d( (double)(c0.R - Col.UIntToDouble(c1.R)), (double)(c0.G - Col.UIntToDouble(c1.G)), (double)(c0.B - Col.UIntToDouble(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator +(C3d c0, C3f c1) { return new C3d( (double)(c0.R + (double)(c1.R)), (double)(c0.G + (double)(c1.G)), (double)(c0.B + (double)(c1.B))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator -(C3d c0, C3f c1) { return new C3d( (double)(c0.R - (double)(c1.R)), (double)(c0.G - (double)(c1.G)), (double)(c0.B - (double)(c1.B))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator *(C3d col, double scalar) { return new C3d((double)(col.R * scalar), (double)(col.G * scalar), (double)(col.B * scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator *(double scalar, C3d col) { return new C3d((double)(scalar * col.R), (double)(scalar * col.G), (double)(scalar * col.B)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator /(C3d col, double scalar) { return new C3d((double)(col.R / scalar), (double)(col.G / scalar), (double)(col.B / scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator /(double scalar, C3d col) { return new C3d((double)(scalar / col.R), (double)(scalar / col.G), (double)(scalar / col.B)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator *(C3d c0, C3d c1) { return new C3d((double)(c0.R * c1.R), (double)(c0.G * c1.G), (double)(c0.B * c1.B)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator /(C3d c0, C3d c1) { return new C3d((double)(c0.R / c1.R), (double)(c0.G / c1.G), (double)(c0.B / c1.B)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator +(C3d c0, C3d c1) { return new C3d(c0.R + c1.R, c0.G + c1.G, c0.B + c1.B); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator +(C3d col, double scalar) { return new C3d(col.R + scalar, col.G + scalar, col.B + scalar); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator +(double scalar, C3d col) => col + scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator -(C3d c0, C3d c1) { return new C3d(c0.R - c1.R, c0.G - c1.G, c0.B - c1.B); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator -(C3d col, double scalar) { return new C3d(col.R - scalar, col.G - scalar, col.B - scalar); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d operator -(double scalar, C3d col) { return new C3d(scalar - col.R, scalar - col.G, scalar - col.B); } /// /// Clamps the color channels to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clamp(double min, double max) { R = R.Clamp(min, max); G = G.Clamp(min, max); B = B.Clamp(min, max); } /// /// Returns a copy with the color channels clamped to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d Clamped(double min, double max) { return new C3d(R.Clamp(min, max), G.Clamp(min, max), B.Clamp(min, max)); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |R| + |G| + |B|. /// public readonly double Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Abs(R) + Fun.Abs(G) + Fun.Abs(B); } } /// /// Returns the Euclidean (or 2-) norm of the color. This is calculated /// as sqrt(R^2 + G^2 + B^2). /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(R * R + G * G + B * B); } } /// /// Returns the infinite (or maximum) norm of the color. This is /// calculated as max(|R|, |G|, |B|). /// public readonly double NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(Fun.Abs(R), Fun.Abs(G), Fun.Abs(B)); } } /// /// Returns the minimum norm of the color. This is calculated as /// min(|R|, |G|, |B|). /// public readonly double NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(Fun.Abs(R), Fun.Abs(G), Fun.Abs(B)); } } #endregion #region Overrides public override readonly bool Equals(object other) => (other is C3d o) ? Equals(o) : false; public override readonly int GetHashCode() { return HashCode.GetCombined(R, G, B); } public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + R.ToString(null, CultureInfo.InvariantCulture) + ", " + G.ToString(null, CultureInfo.InvariantCulture) + ", " + B.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref C3d color, int i, double value) => { switch (i) { case 0: color.R = value; return; case 1: color.G = value; return; case 2: color.B = value; return; default: throw new IndexOutOfRangeException(); } }; [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d LinearInterp(double t, C3d a, C3d b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d LinearInterp(V3d t, C3d a, C3d b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d DivideByInt(C3d c, int x) => c / x; #endregion #region Parsing /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C3d.Zero otherwise. /// True on success, false otherwise. public static bool TryParse(Text t, out C3d result) { if (Col.TryParseHex(t, out C4b tmp)) { result = tmp.ToC3d(); return true; } else { bool success = true; double[] values = new double[4] { 1.0, 1.0, 1.0, 1.0 }; double parse(Text t) { if (!double.TryParse(t.ToString(), NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out double value)) success = false; return value; }; var count = t.NestedBracketSplitCount2(1); if (count == 3 || count == 4) t.NestedBracketSplit(1, parse, () => values); else success = false; result = success ? new C3d(values) : Zero; return success; } } /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C3d.Zero otherwise. /// True on success, false otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParse(string s, out C3d result) => TryParse(new Text(s), out result); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C3d color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d Parse(string s) => Parse(new Text(s)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d Parse(Text t, int bracketLevel = 1) => t.NestedBracketSplit(bracketLevel, Text.Parse, C3d.Setter); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional and discarded. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C3d color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d Parse(Text t) => TryParse(t, out C3d result) ? result : throw new FormatException($"{t} is not a valid C3d color."); #endregion #region IFormattable Members public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + R.ToString(format, fp) + between + G.ToString(format, fp) + between + B.ToString(format, fp) + end; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(C3d other) { return R.Equals(other.R) && G.Equals(other.G) && B.Equals(other.B); } #endregion #region IRGB Members double IRGB.Red { readonly get { return (R); } set { R = (value); } } double IRGB.Green { readonly get { return (G); } set { G = (value); } } double IRGB.Blue { readonly get { return (B); } set { B = (value); } } #endregion } public static partial class Fun { #region Interpolation /// /// Returns the linearly interpolated color between a and b. /// public static C3d Lerp(this double t, C3d a, C3d b) => new C3d(Lerp(t, a.R, b.R), Lerp(t, a.G, b.G), Lerp(t, a.B, b.B)); /// /// Returns the linearly interpolated color between a and b. /// public static C3d Lerp(this V3d t, C3d a, C3d b) => new C3d(Lerp(t.X, a.R, b.R), Lerp(t.Y, a.G, b.G), Lerp(t.Z, a.B, b.B)); #endregion #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this C3d a, C3d b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this C3d a, C3d b, double tolerance) { return ApproximateEquals(a.R, b.R, tolerance) && ApproximateEquals(a.G, b.G, tolerance) && ApproximateEquals(a.B, b.B, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this C3d c, double epsilon) => Col.AllTiny(c, epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(C3d c) => c.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any component of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(C3d c) => c.IsNaN; /// /// Returns whether any component of the the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(C3d c) => c.IsInfinity; /// /// Returns whether any component of the the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(C3d c) => c.IsPositiveInfinity; /// /// Returns whether any component of the the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(C3d c) => c.IsNegativeInfinity; /// /// Returns whether all components of the the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(C3d c) => c.IsFinite; #endregion } public static partial class Col { #region ToHexString /// /// Returns the hexadecimal representation with format RRGGBB. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToHexString(this C3d c) => c.ToC3b().ToHexString(); #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C3d a, C3d b) { return (a.R < b.R && a.G < b.G && a.B < b.B); } /// /// Returns whether ALL elements of col are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C3d col, double s) { return (col.R < s && col.G < s && col.B < s); } /// /// Returns whether a is Smaller ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(double s, C3d col) { return (s < col.R && s < col.G && s < col.B); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C3d a, C3d b) { return (a.R < b.R || a.G < b.G || a.B < b.B); } /// /// Returns whether AT LEAST ONE element of col is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C3d col, double s) { return (col.R < s || col.G < s || col.B < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(double s, C3d col) { return (s < col.R || s < col.G || s < col.B); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C3d a, C3d b) { return (a.R > b.R && a.G > b.G && a.B > b.B); } /// /// Returns whether ALL elements of col are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C3d col, double s) { return (col.R > s && col.G > s && col.B > s); } /// /// Returns whether a is Greater ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(double s, C3d col) { return (s > col.R && s > col.G && s > col.B); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C3d a, C3d b) { return (a.R > b.R || a.G > b.G || a.B > b.B); } /// /// Returns whether AT LEAST ONE element of col is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C3d col, double s) { return (col.R > s || col.G > s || col.B > s); } /// /// Returns whether a is Greater AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(double s, C3d col) { return (s > col.R || s > col.G || s > col.B); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C3d a, C3d b) { return (a.R <= b.R && a.G <= b.G && a.B <= b.B); } /// /// Returns whether ALL elements of col are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C3d col, double s) { return (col.R <= s && col.G <= s && col.B <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(double s, C3d col) { return (s <= col.R && s <= col.G && s <= col.B); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C3d a, C3d b) { return (a.R <= b.R || a.G <= b.G || a.B <= b.B); } /// /// Returns whether AT LEAST ONE element of col is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C3d col, double s) { return (col.R <= s || col.G <= s || col.B <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(double s, C3d col) { return (s <= col.R || s <= col.G || s <= col.B); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C3d a, C3d b) { return (a.R >= b.R && a.G >= b.G && a.B >= b.B); } /// /// Returns whether ALL elements of col are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C3d col, double s) { return (col.R >= s && col.G >= s && col.B >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(double s, C3d col) { return (s >= col.R && s >= col.G && s >= col.B); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C3d a, C3d b) { return (a.R >= b.R || a.G >= b.G || a.B >= b.B); } /// /// Returns whether AT LEAST ONE element of col is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C3d col, double s) { return (col.R >= s || col.G >= s || col.B >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(double s, C3d col) { return (s >= col.R || s >= col.G || s >= col.B); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C3d a, C3d b) { return (a.R == b.R && a.G == b.G && a.B == b.B); } /// /// Returns whether ALL elements of col are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C3d col, double s) { return (col.R == s && col.G == s && col.B == s); } /// /// Returns whether a is Equal ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(double s, C3d col) { return (s == col.R && s == col.G && s == col.B); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C3d a, C3d b) { return (a.R == b.R || a.G == b.G || a.B == b.B); } /// /// Returns whether AT LEAST ONE element of col is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C3d col, double s) { return (col.R == s || col.G == s || col.B == s); } /// /// Returns whether a is Equal AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(double s, C3d col) { return (s == col.R || s == col.G || s == col.B); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C3d a, C3d b) { return (a.R != b.R && a.G != b.G && a.B != b.B); } /// /// Returns whether ALL elements of col are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C3d col, double s) { return (col.R != s && col.G != s && col.B != s); } /// /// Returns whether a is Different ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(double s, C3d col) { return (s != col.R && s != col.G && s != col.B); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C3d a, C3d b) { return (a.R != b.R || a.G != b.G || a.B != b.B); } /// /// Returns whether AT LEAST ONE element of col is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C3d col, double s) { return (col.R != s || col.G != s || col.B != s); } /// /// Returns whether a is Different AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(double s, C3d col) { return (s != col.R || s != col.G || s != col.B); } #endregion #region Linear Combination /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d LinCom( C3d p0, C3d p1, C3d p2, C3d p3, ref Tup4 w) { return new C3d( (p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3), (p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3), (p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3)); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d LinCom( C3d p0, C3d p1, C3d p2, C3d p3, C3d p4, C3d p5, ref Tup6 w) { return new C3d( (p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5), (p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5), (p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5)); } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this C3d c, double epsilon) => c.R.IsTiny(epsilon) || c.G.IsTiny(epsilon) || c.B.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this C3d c, double epsilon) => c.R.IsTiny(epsilon) && c.G.IsTiny(epsilon) && c.B.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(C3d c) => c.AnyNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(C3d c) => c.AllNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(C3d c) => c.AnyInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(C3d c) => c.AllInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(C3d c) => c.AnyPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(C3d c) => c.AllPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(C3d c) => c.AnyNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(C3d c) => c.AllNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(C3d c) => c.AnyTiny; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(C3d c) => c.AllTiny; #endregion } public static class IRandomUniformC3dExtensions { #region IRandomUniform extensions for C3d /// /// Uses UniformDouble() to generate the elements of a C3d color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d UniformC3d(this IRandomUniform rnd) { return new C3d(rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble()); } /// /// Uses UniformDoubleClosed() to generate the elements of a C3d color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d UniformC3dClosed(this IRandomUniform rnd) { return new C3d(rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed()); } /// /// Uses UniformDoubleOpen() to generate the elements of a C3d color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d UniformC3dOpen(this IRandomUniform rnd) { return new C3d(rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen()); } /// /// Uses UniformDoubleFull() to generate the elements of a C3d color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d UniformC3dFull(this IRandomUniform rnd) { return new C3d(rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull()); } /// /// Uses UniformDoubleFullClosed() to generate the elements of a C3d color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d UniformC3dFullClosed(this IRandomUniform rnd) { return new C3d(rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed()); } /// /// Uses UniformDoubleFullOpen() to generate the elements of a C3d color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C3d UniformC3dFullOpen(this IRandomUniform rnd) { return new C3d(rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen()); } #endregion } #endregion #region C4b /// /// Represents an RGBA color with each channel stored as a value within [0, 255]. /// [Serializable] public partial struct C4b : IFormattable, IEquatable, IRGB, IOpacity { #region Constructors /// /// Creates a color from the given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(byte r, byte g, byte b, byte a) { R = r; G = g; B = b; A = a; } /// /// Creates a color from the given values. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(int r, int g, int b, int a) { R = (byte)r; G = (byte)g; B = (byte)b; A = (byte)a; } /// /// Creates a color from the given values. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(long r, long g, long b, long a) { R = (byte)r; G = (byte)g; B = (byte)b; A = (byte)a; } /// /// Creates a color from the given values. /// The values are mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(float r, float g, float b, float a) { R = Col.FloatToByteClamped(r); G = Col.FloatToByteClamped(g); B = Col.FloatToByteClamped(b); A = Col.FloatToByteClamped(a); } /// /// Creates a color from the given values. /// The values are mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(double r, double g, double b, double a) { R = Col.DoubleToByteClamped(r); G = Col.DoubleToByteClamped(g); B = Col.DoubleToByteClamped(b); A = Col.DoubleToByteClamped(a); } /// /// Creates a color from the given RGB values. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(byte r, byte g, byte b) { R = r; G = g; B = b; A = 255; } /// /// Creates a color from the given RGB values. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(int r, int g, int b) { R = (byte)r; G = (byte)g; B = (byte)b; A = 255; } /// /// Creates a color from the given RGB values. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(long r, long g, long b) { R = (byte)r; G = (byte)g; B = (byte)b; A = 255; } /// /// Creates a color from the given RGB values. /// The values are mapped and clamped from [0, 1] to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(float r, float g, float b) { R = Col.FloatToByteClamped(r); G = Col.FloatToByteClamped(g); B = Col.FloatToByteClamped(b); A = 255; } /// /// Creates a color from the given RGB values. /// The values are mapped and clamped from [0, 1] to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(double r, double g, double b) { R = Col.DoubleToByteClamped(r); G = Col.DoubleToByteClamped(g); B = Col.DoubleToByteClamped(b); A = 255; } /// /// Creates a color from a single value. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(byte gray) { R = gray; G = gray; B = gray; A = 255; } /// /// Creates a color from a single value. /// The value is mapped and clamped from [0, 1] to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(float gray) { var value = Col.FloatToByteClamped(gray); R = value; G = value; B = value; A = 255; } /// /// Creates a color from a single value. /// The value is mapped and clamped from [0, 1] to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(double gray) { var value = Col.DoubleToByteClamped(gray); R = value; G = value; B = value; A = 255; } /// /// Creates a color from the given color. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(C3b color) { R = (color.R); G = (color.G); B = (color.B); A = 255; } /// /// Creates a color from the given color and an alpha value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(C3b color, byte alpha) { R = (color.R); G = (color.G); B = (color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(C3us color) { R = Col.UShortToByte(color.R); G = Col.UShortToByte(color.G); B = Col.UShortToByte(color.B); A = 255; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(C3us color, byte alpha) { R = Col.UShortToByte(color.R); G = Col.UShortToByte(color.G); B = Col.UShortToByte(color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(C3ui color) { R = Col.UIntToByte(color.R); G = Col.UIntToByte(color.G); B = Col.UIntToByte(color.B); A = 255; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(C3ui color, byte alpha) { R = Col.UIntToByte(color.R); G = Col.UIntToByte(color.G); B = Col.UIntToByte(color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(C3f color) { R = Col.FloatToByteClamped(color.R); G = Col.FloatToByteClamped(color.G); B = Col.FloatToByteClamped(color.B); A = 255; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(C3f color, byte alpha) { R = Col.FloatToByteClamped(color.R); G = Col.FloatToByteClamped(color.G); B = Col.FloatToByteClamped(color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(C3d color) { R = Col.DoubleToByteClamped(color.R); G = Col.DoubleToByteClamped(color.G); B = Col.DoubleToByteClamped(color.B); A = 255; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(C3d color, byte alpha) { R = Col.DoubleToByteClamped(color.R); G = Col.DoubleToByteClamped(color.G); B = Col.DoubleToByteClamped(color.B); A = alpha; } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(C4b color) { R = (color.R); G = (color.G); B = (color.B); A = (color.A); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(C4us color) { R = Col.UShortToByte(color.R); G = Col.UShortToByte(color.G); B = Col.UShortToByte(color.B); A = Col.UShortToByte(color.A); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(C4ui color) { R = Col.UIntToByte(color.R); G = Col.UIntToByte(color.G); B = Col.UIntToByte(color.B); A = Col.UIntToByte(color.A); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(C4f color) { R = Col.FloatToByteClamped(color.R); G = Col.FloatToByteClamped(color.G); B = Col.FloatToByteClamped(color.B); A = Col.FloatToByteClamped(color.A); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(C4d color) { R = Col.DoubleToByteClamped(color.R); G = Col.DoubleToByteClamped(color.G); B = Col.DoubleToByteClamped(color.B); A = Col.DoubleToByteClamped(color.A); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(V3i vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); A = 255; } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(V3ui vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); A = 255; } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(V3l vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); A = 255; } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(V3f vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); A = 255; } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(V3d vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); A = 255; } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(V4i vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); A = (byte)(vec.W); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(V4ui vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); A = (byte)(vec.W); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(V4l vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); A = (byte)(vec.W); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(V4f vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); A = (byte)(vec.W); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(V4d vec) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); A = (byte)(vec.W); } /// /// Creates a color from the given vector and an alpha value. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(V3i vec, byte alpha) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); A = alpha; } /// /// Creates a color from the given vector and an alpha value. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(V3ui vec, byte alpha) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); A = alpha; } /// /// Creates a color from the given vector and an alpha value. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(V3l vec, byte alpha) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); A = alpha; } /// /// Creates a color from the given vector and an alpha value. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(V3f vec, byte alpha) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); A = alpha; } /// /// Creates a color from the given vector and an alpha value. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(V3d vec, byte alpha) { R = (byte)(vec.X); G = (byte)(vec.Y); B = (byte)(vec.Z); A = alpha; } /// /// Creates a color from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(Func index_fun) { R = index_fun(0); G = index_fun(1); B = index_fun(2); A = index_fun(3); } /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(byte[] values) { R = (values[0]); G = (values[1]); B = (values[2]); A = (values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(byte[] values, int start) { R = (values[start + 0]); G = (values[start + 1]); B = (values[start + 2]); A = (values[start + 3]); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(ushort[] values) { R = Col.UShortToByte(values[0]); G = Col.UShortToByte(values[1]); B = Col.UShortToByte(values[2]); A = Col.UShortToByte(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(ushort[] values, int start) { R = Col.UShortToByte(values[start + 0]); G = Col.UShortToByte(values[start + 1]); B = Col.UShortToByte(values[start + 2]); A = Col.UShortToByte(values[start + 3]); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(uint[] values) { R = Col.UIntToByte(values[0]); G = Col.UIntToByte(values[1]); B = Col.UIntToByte(values[2]); A = Col.UIntToByte(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(uint[] values, int start) { R = Col.UIntToByte(values[start + 0]); G = Col.UIntToByte(values[start + 1]); B = Col.UIntToByte(values[start + 2]); A = Col.UIntToByte(values[start + 3]); } /// /// Creates a new color from the given array. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(float[] values) { R = Col.FloatToByteClamped(values[0]); G = Col.FloatToByteClamped(values[1]); B = Col.FloatToByteClamped(values[2]); A = Col.FloatToByteClamped(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(float[] values, int start) { R = Col.FloatToByteClamped(values[start + 0]); G = Col.FloatToByteClamped(values[start + 1]); B = Col.FloatToByteClamped(values[start + 2]); A = Col.FloatToByteClamped(values[start + 3]); } /// /// Creates a new color from the given array. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(double[] values) { R = Col.DoubleToByteClamped(values[0]); G = Col.DoubleToByteClamped(values[1]); B = Col.DoubleToByteClamped(values[2]); A = Col.DoubleToByteClamped(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4b(double[] values, int start) { R = Col.DoubleToByteClamped(values[start + 0]); G = Col.DoubleToByteClamped(values[start + 1]); B = Col.DoubleToByteClamped(values[start + 2]); A = Col.DoubleToByteClamped(values[start + 3]); } #endregion #region Properities public readonly C3b RGB => (C3b)this; #endregion #region Conversions /// /// Converts the given color to a color. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(C3b color) => new C4b(color); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Creates a color from the given color. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromC3b(C3b c) => new C4b(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(C3us color) => new C4b(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromC3us(C3us c) => new C4b(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(C3ui color) => new C4b(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromC3ui(C3ui c) => new C4b(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(C3f color) => new C4b(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f ToC3f() => (C3f)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromC3f(C3f c) => new C4b(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(C3d color) => new C4b(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d ToC3d() => (C3d)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromC3d(C3d c) => new C4b(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(C4us color) => new C4b(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromC4us(C4us c) => new C4b(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(C4ui color) => new C4b(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromC4ui(C4ui c) => new C4b(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(C4f color) => new C4b(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f ToC4f() => (C4f)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromC4f(C4f c) => new C4b(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(C4d color) => new C4b(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d ToC4d() => (C4d)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromC4d(C4d c) => new C4b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(V3i v) => new C4b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromV3i(V3i c) => new C4b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(V3ui v) => new C4b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromV3ui(V3ui c) => new C4b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(V3l v) => new C4b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromV3l(V3l c) => new C4b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(V3f v) => new C4b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromV3f(V3f c) => new C4b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(V3d v) => new C4b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromV3d(V3d c) => new C4b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(V4i v) => new C4b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromV4i(V4i c) => new C4b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(V4ui v) => new C4b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromV4ui(V4ui c) => new C4b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(V4l v) => new C4b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromV4l(V4l c) => new C4b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(V4f v) => new C4b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromV4f(V4f c) => new C4b(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(V4d v) => new C4b(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b FromV4d(V4d c) => new C4b(c); /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(byte[] values) => new C4b(values); /// /// Creates a new array from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator byte[](C4b color) => new byte[] { (color.R), (color.G), (color.B), (color.A) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(ushort[] values) => new C4b(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ushort[](C4b color) => new ushort[] { Col.ByteToUShort(color.R), Col.ByteToUShort(color.G), Col.ByteToUShort(color.B), Col.ByteToUShort(color.A) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(uint[] values) => new C4b(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](C4b color) => new uint[] { Col.ByteToUInt(color.R), Col.ByteToUInt(color.G), Col.ByteToUInt(color.B), Col.ByteToUInt(color.A) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(float[] values) => new C4b(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](C4b color) => new float[] { Col.ByteToFloat(color.R), Col.ByteToFloat(color.G), Col.ByteToFloat(color.B), Col.ByteToFloat(color.A) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4b(double[] values) => new C4b(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](C4b color) => new double[] { Col.ByteToDouble(color.R), Col.ByteToDouble(color.G), Col.ByteToDouble(color.B), Col.ByteToDouble(color.A) }; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b Map(Func channel_fun) { return new C4b(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us Map(Func channel_fun) { return new C4us(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui Map(Func channel_fun) { return new C4ui(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f Map(Func channel_fun) { return new C4f(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d Map(Func channel_fun) { return new C4d(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(R); array[start + 1] = element_fun(G); array[start + 2] = element_fun(B); array[start + 3] = element_fun(A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(R, 0); array[start + 1] = element_index_fun(G, 1); array[start + 2] = element_index_fun(B, 2); array[start + 3] = element_index_fun(A, 3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly byte[] ToArray() => (byte[])this; #endregion #region Indexer // Byte colors have a different byte order (red and blue are swapped) private static readonly byte[] IndexMapping = new byte[] { 2, 1, 0, 3 }; /// /// Indexer in canonical order 0=R, 1=G, 2=B, 3=A (availability depending on color type). /// public unsafe byte this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (byte* ptr = &B) { ptr[IndexMapping[i]] = value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (byte* ptr = &B) { return ptr[IndexMapping[i]]; } } } #endregion #region Constants /// /// C4b with all components zero. /// public static C4b Zero => new C4b(0, 0, 0, 0); // Web colors public static C4b AliceBlue => new C4b(Col.DoubleToByteClamped(0.941176), Col.DoubleToByteClamped(0.972549), Col.DoubleToByteClamped(1)); public static C4b AntiqueWhite => new C4b(Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.921569), Col.DoubleToByteClamped(0.843137)); public static C4b Aqua => new C4b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1)); public static C4b Aquamarine => new C4b(Col.DoubleToByteClamped(0.498039), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.831373)); public static C4b Azure => new C4b(Col.DoubleToByteClamped(0.941176), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1)); public static C4b Beige => new C4b(Col.DoubleToByteClamped(0.960784), Col.DoubleToByteClamped(0.960784), Col.DoubleToByteClamped(0.862745)); public static C4b Bisque => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.894118), Col.DoubleToByteClamped(0.768627)); public static C4b Black => new C4b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0)); public static C4b BlanchedAlmond => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.921569), Col.DoubleToByteClamped(0.803922)); public static C4b Blue => new C4b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(1)); public static C4b BlueViolet => new C4b(Col.DoubleToByteClamped(0.541176), Col.DoubleToByteClamped(0.168627), Col.DoubleToByteClamped(0.886275)); public static C4b Brown => new C4b(Col.DoubleToByteClamped(0.647059), Col.DoubleToByteClamped(0.164706), Col.DoubleToByteClamped(0.164706)); public static C4b BurlyWood => new C4b(Col.DoubleToByteClamped(0.870588), Col.DoubleToByteClamped(0.721569), Col.DoubleToByteClamped(0.529412)); public static C4b CadetBlue => new C4b(Col.DoubleToByteClamped(0.372549), Col.DoubleToByteClamped(0.619608), Col.DoubleToByteClamped(0.627451)); public static C4b Chartreuse => new C4b(Col.DoubleToByteClamped(0.498039), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0)); public static C4b Chocolate => new C4b(Col.DoubleToByteClamped(0.823529), Col.DoubleToByteClamped(0.411765), Col.DoubleToByteClamped(0.117647)); public static C4b Coral => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.498039), Col.DoubleToByteClamped(0.313725)); public static C4b CornflowerBlue => new C4b(Col.DoubleToByteClamped(0.392157), Col.DoubleToByteClamped(0.584314), Col.DoubleToByteClamped(0.929412)); public static C4b Cornsilk => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.972549), Col.DoubleToByteClamped(0.862745)); public static C4b Crimson => new C4b(Col.DoubleToByteClamped(0.862745), Col.DoubleToByteClamped(0.078431), Col.DoubleToByteClamped(0.235294)); public static C4b Cyan => new C4b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1)); public static C4b DarkBlue => new C4b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.545098)); public static C4b DarkCyan => new C4b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.545098), Col.DoubleToByteClamped(0.545098)); public static C4b DarkGoldenRod => new C4b(Col.DoubleToByteClamped(0.721569), Col.DoubleToByteClamped(0.52549), Col.DoubleToByteClamped(0.043137)); public static C4b DarkGray => new C4b(Col.DoubleToByteClamped(0.662745), Col.DoubleToByteClamped(0.662745), Col.DoubleToByteClamped(0.662745)); public static C4b DarkGrey => new C4b(Col.DoubleToByteClamped(0.662745), Col.DoubleToByteClamped(0.662745), Col.DoubleToByteClamped(0.662745)); public static C4b DarkGreen => new C4b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.392157), Col.DoubleToByteClamped(0)); public static C4b DarkKhaki => new C4b(Col.DoubleToByteClamped(0.741176), Col.DoubleToByteClamped(0.717647), Col.DoubleToByteClamped(0.419608)); public static C4b DarkMagenta => new C4b(Col.DoubleToByteClamped(0.545098), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.545098)); public static C4b DarkOliveGreen => new C4b(Col.DoubleToByteClamped(0.333333), Col.DoubleToByteClamped(0.419608), Col.DoubleToByteClamped(0.184314)); public static C4b DarkOrange => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.54902), Col.DoubleToByteClamped(0)); public static C4b DarkOrchid => new C4b(Col.DoubleToByteClamped(0.6), Col.DoubleToByteClamped(0.196078), Col.DoubleToByteClamped(0.8)); public static C4b DarkRed => new C4b(Col.DoubleToByteClamped(0.545098), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0)); public static C4b DarkSalmon => new C4b(Col.DoubleToByteClamped(0.913725), Col.DoubleToByteClamped(0.588235), Col.DoubleToByteClamped(0.478431)); public static C4b DarkSeaGreen => new C4b(Col.DoubleToByteClamped(0.560784), Col.DoubleToByteClamped(0.737255), Col.DoubleToByteClamped(0.560784)); public static C4b DarkSlateBlue => new C4b(Col.DoubleToByteClamped(0.282353), Col.DoubleToByteClamped(0.239216), Col.DoubleToByteClamped(0.545098)); public static C4b DarkSlateGray => new C4b(Col.DoubleToByteClamped(0.184314), Col.DoubleToByteClamped(0.309804), Col.DoubleToByteClamped(0.309804)); public static C4b DarkSlateGrey => new C4b(Col.DoubleToByteClamped(0.184314), Col.DoubleToByteClamped(0.309804), Col.DoubleToByteClamped(0.309804)); public static C4b DarkTurquoise => new C4b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.807843), Col.DoubleToByteClamped(0.819608)); public static C4b DarkViolet => new C4b(Col.DoubleToByteClamped(0.580392), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.827451)); public static C4b DeepPink => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.078431), Col.DoubleToByteClamped(0.576471)); public static C4b DeepSkyBlue => new C4b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.74902), Col.DoubleToByteClamped(1)); public static C4b DimGray => new C4b(Col.DoubleToByteClamped(0.411765), Col.DoubleToByteClamped(0.411765), Col.DoubleToByteClamped(0.411765)); public static C4b DimGrey => new C4b(Col.DoubleToByteClamped(0.411765), Col.DoubleToByteClamped(0.411765), Col.DoubleToByteClamped(0.411765)); public static C4b DodgerBlue => new C4b(Col.DoubleToByteClamped(0.117647), Col.DoubleToByteClamped(0.564706), Col.DoubleToByteClamped(1)); public static C4b FireBrick => new C4b(Col.DoubleToByteClamped(0.698039), Col.DoubleToByteClamped(0.133333), Col.DoubleToByteClamped(0.133333)); public static C4b FloralWhite => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.941176)); public static C4b ForestGreen => new C4b(Col.DoubleToByteClamped(0.133333), Col.DoubleToByteClamped(0.545098), Col.DoubleToByteClamped(0.133333)); public static C4b Fuchsia => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(1)); public static C4b Gainsboro => new C4b(Col.DoubleToByteClamped(0.862745), Col.DoubleToByteClamped(0.862745), Col.DoubleToByteClamped(0.862745)); public static C4b GhostWhite => new C4b(Col.DoubleToByteClamped(0.972549), Col.DoubleToByteClamped(0.972549), Col.DoubleToByteClamped(1)); public static C4b Gold => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.843137), Col.DoubleToByteClamped(0)); public static C4b GoldenRod => new C4b(Col.DoubleToByteClamped(0.854902), Col.DoubleToByteClamped(0.647059), Col.DoubleToByteClamped(0.12549)); public static C4b Gray => new C4b(Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.501961)); public static C4b Grey => new C4b(Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.501961)); public static C4b Green => new C4b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0)); public static C4b GreenYellow => new C4b(Col.DoubleToByteClamped(0.678431), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.184314)); public static C4b HoneyDew => new C4b(Col.DoubleToByteClamped(0.941176), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.941176)); public static C4b HotPink => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.411765), Col.DoubleToByteClamped(0.705882)); public static C4b IndianRed => new C4b(Col.DoubleToByteClamped(0.803922), Col.DoubleToByteClamped(0.360784), Col.DoubleToByteClamped(0.360784)); public static C4b Indigo => new C4b(Col.DoubleToByteClamped(0.294118), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.509804)); public static C4b Ivory => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.941176)); public static C4b Khaki => new C4b(Col.DoubleToByteClamped(0.941176), Col.DoubleToByteClamped(0.901961), Col.DoubleToByteClamped(0.54902)); public static C4b Lavender => new C4b(Col.DoubleToByteClamped(0.901961), Col.DoubleToByteClamped(0.901961), Col.DoubleToByteClamped(0.980392)); public static C4b LavenderBlush => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.941176), Col.DoubleToByteClamped(0.960784)); public static C4b LawnGreen => new C4b(Col.DoubleToByteClamped(0.486275), Col.DoubleToByteClamped(0.988235), Col.DoubleToByteClamped(0)); public static C4b LemonChiffon => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.803922)); public static C4b LightBlue => new C4b(Col.DoubleToByteClamped(0.678431), Col.DoubleToByteClamped(0.847059), Col.DoubleToByteClamped(0.901961)); public static C4b LightCoral => new C4b(Col.DoubleToByteClamped(0.941176), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.501961)); public static C4b LightCyan => new C4b(Col.DoubleToByteClamped(0.878431), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1)); public static C4b LightGoldenRodYellow => new C4b(Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.823529)); public static C4b LightGray => new C4b(Col.DoubleToByteClamped(0.827451), Col.DoubleToByteClamped(0.827451), Col.DoubleToByteClamped(0.827451)); public static C4b LightGrey => new C4b(Col.DoubleToByteClamped(0.827451), Col.DoubleToByteClamped(0.827451), Col.DoubleToByteClamped(0.827451)); public static C4b LightGreen => new C4b(Col.DoubleToByteClamped(0.564706), Col.DoubleToByteClamped(0.933333), Col.DoubleToByteClamped(0.564706)); public static C4b LightPink => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.713725), Col.DoubleToByteClamped(0.756863)); public static C4b LightSalmon => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.627451), Col.DoubleToByteClamped(0.478431)); public static C4b LightSeaGreen => new C4b(Col.DoubleToByteClamped(0.12549), Col.DoubleToByteClamped(0.698039), Col.DoubleToByteClamped(0.666667)); public static C4b LightSkyBlue => new C4b(Col.DoubleToByteClamped(0.529412), Col.DoubleToByteClamped(0.807843), Col.DoubleToByteClamped(0.980392)); public static C4b LightSlateGray => new C4b(Col.DoubleToByteClamped(0.466667), Col.DoubleToByteClamped(0.533333), Col.DoubleToByteClamped(0.6)); public static C4b LightSlateGrey => new C4b(Col.DoubleToByteClamped(0.466667), Col.DoubleToByteClamped(0.533333), Col.DoubleToByteClamped(0.6)); public static C4b LightSteelBlue => new C4b(Col.DoubleToByteClamped(0.690196), Col.DoubleToByteClamped(0.768627), Col.DoubleToByteClamped(0.870588)); public static C4b LightYellow => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.878431)); public static C4b Lime => new C4b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0)); public static C4b LimeGreen => new C4b(Col.DoubleToByteClamped(0.196078), Col.DoubleToByteClamped(0.803922), Col.DoubleToByteClamped(0.196078)); public static C4b Linen => new C4b(Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.941176), Col.DoubleToByteClamped(0.901961)); public static C4b Magenta => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(1)); public static C4b Maroon => new C4b(Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0)); public static C4b MediumAquaMarine => new C4b(Col.DoubleToByteClamped(0.4), Col.DoubleToByteClamped(0.803922), Col.DoubleToByteClamped(0.666667)); public static C4b MediumBlue => new C4b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.803922)); public static C4b MediumOrchid => new C4b(Col.DoubleToByteClamped(0.729412), Col.DoubleToByteClamped(0.333333), Col.DoubleToByteClamped(0.827451)); public static C4b MediumPurple => new C4b(Col.DoubleToByteClamped(0.576471), Col.DoubleToByteClamped(0.439216), Col.DoubleToByteClamped(0.847059)); public static C4b MediumSeaGreen => new C4b(Col.DoubleToByteClamped(0.235294), Col.DoubleToByteClamped(0.701961), Col.DoubleToByteClamped(0.443137)); public static C4b MediumSlateBlue => new C4b(Col.DoubleToByteClamped(0.482353), Col.DoubleToByteClamped(0.407843), Col.DoubleToByteClamped(0.933333)); public static C4b MediumSpringGreen => new C4b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.603922)); public static C4b MediumTurquoise => new C4b(Col.DoubleToByteClamped(0.282353), Col.DoubleToByteClamped(0.819608), Col.DoubleToByteClamped(0.8)); public static C4b MediumVioletRed => new C4b(Col.DoubleToByteClamped(0.780392), Col.DoubleToByteClamped(0.082353), Col.DoubleToByteClamped(0.521569)); public static C4b MidnightBlue => new C4b(Col.DoubleToByteClamped(0.098039), Col.DoubleToByteClamped(0.098039), Col.DoubleToByteClamped(0.439216)); public static C4b MintCream => new C4b(Col.DoubleToByteClamped(0.960784), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.980392)); public static C4b MistyRose => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.894118), Col.DoubleToByteClamped(0.882353)); public static C4b Moccasin => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.894118), Col.DoubleToByteClamped(0.709804)); public static C4b NavajoWhite => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.870588), Col.DoubleToByteClamped(0.678431)); public static C4b Navy => new C4b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.501961)); public static C4b OldLace => new C4b(Col.DoubleToByteClamped(0.992157), Col.DoubleToByteClamped(0.960784), Col.DoubleToByteClamped(0.901961)); public static C4b Olive => new C4b(Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0)); public static C4b OliveDrab => new C4b(Col.DoubleToByteClamped(0.419608), Col.DoubleToByteClamped(0.556863), Col.DoubleToByteClamped(0.137255)); public static C4b Orange => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.647059), Col.DoubleToByteClamped(0)); public static C4b OrangeRed => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.270588), Col.DoubleToByteClamped(0)); public static C4b Orchid => new C4b(Col.DoubleToByteClamped(0.854902), Col.DoubleToByteClamped(0.439216), Col.DoubleToByteClamped(0.839216)); public static C4b PaleGoldenRod => new C4b(Col.DoubleToByteClamped(0.933333), Col.DoubleToByteClamped(0.909804), Col.DoubleToByteClamped(0.666667)); public static C4b PaleGreen => new C4b(Col.DoubleToByteClamped(0.596078), Col.DoubleToByteClamped(0.984314), Col.DoubleToByteClamped(0.596078)); public static C4b PaleTurquoise => new C4b(Col.DoubleToByteClamped(0.686275), Col.DoubleToByteClamped(0.933333), Col.DoubleToByteClamped(0.933333)); public static C4b PaleVioletRed => new C4b(Col.DoubleToByteClamped(0.847059), Col.DoubleToByteClamped(0.439216), Col.DoubleToByteClamped(0.576471)); public static C4b PapayaWhip => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.937255), Col.DoubleToByteClamped(0.835294)); public static C4b PeachPuff => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.854902), Col.DoubleToByteClamped(0.72549)); public static C4b Peru => new C4b(Col.DoubleToByteClamped(0.803922), Col.DoubleToByteClamped(0.521569), Col.DoubleToByteClamped(0.247059)); public static C4b Pink => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.752941), Col.DoubleToByteClamped(0.796078)); public static C4b Plum => new C4b(Col.DoubleToByteClamped(0.866667), Col.DoubleToByteClamped(0.627451), Col.DoubleToByteClamped(0.866667)); public static C4b PowderBlue => new C4b(Col.DoubleToByteClamped(0.690196), Col.DoubleToByteClamped(0.878431), Col.DoubleToByteClamped(0.901961)); public static C4b Purple => new C4b(Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.501961)); public static C4b Red => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0)); public static C4b RosyBrown => new C4b(Col.DoubleToByteClamped(0.737255), Col.DoubleToByteClamped(0.560784), Col.DoubleToByteClamped(0.560784)); public static C4b RoyalBlue => new C4b(Col.DoubleToByteClamped(0.254902), Col.DoubleToByteClamped(0.411765), Col.DoubleToByteClamped(0.882353)); public static C4b SaddleBrown => new C4b(Col.DoubleToByteClamped(0.545098), Col.DoubleToByteClamped(0.270588), Col.DoubleToByteClamped(0.07451)); public static C4b Salmon => new C4b(Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.447059)); public static C4b SandyBrown => new C4b(Col.DoubleToByteClamped(0.956863), Col.DoubleToByteClamped(0.643137), Col.DoubleToByteClamped(0.376471)); public static C4b SeaGreen => new C4b(Col.DoubleToByteClamped(0.180392), Col.DoubleToByteClamped(0.545098), Col.DoubleToByteClamped(0.341176)); public static C4b SeaShell => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.960784), Col.DoubleToByteClamped(0.933333)); public static C4b Sienna => new C4b(Col.DoubleToByteClamped(0.627451), Col.DoubleToByteClamped(0.321569), Col.DoubleToByteClamped(0.176471)); public static C4b Silver => new C4b(Col.DoubleToByteClamped(0.752941), Col.DoubleToByteClamped(0.752941), Col.DoubleToByteClamped(0.752941)); public static C4b SkyBlue => new C4b(Col.DoubleToByteClamped(0.529412), Col.DoubleToByteClamped(0.807843), Col.DoubleToByteClamped(0.921569)); public static C4b SlateBlue => new C4b(Col.DoubleToByteClamped(0.415686), Col.DoubleToByteClamped(0.352941), Col.DoubleToByteClamped(0.803922)); public static C4b SlateGray => new C4b(Col.DoubleToByteClamped(0.439216), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.564706)); public static C4b SlateGrey => new C4b(Col.DoubleToByteClamped(0.439216), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.564706)); public static C4b Snow => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.980392), Col.DoubleToByteClamped(0.980392)); public static C4b SpringGreen => new C4b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.498039)); public static C4b SteelBlue => new C4b(Col.DoubleToByteClamped(0.27451), Col.DoubleToByteClamped(0.509804), Col.DoubleToByteClamped(0.705882)); public static C4b Tan => new C4b(Col.DoubleToByteClamped(0.823529), Col.DoubleToByteClamped(0.705882), Col.DoubleToByteClamped(0.54902)); public static C4b Teal => new C4b(Col.DoubleToByteClamped(0), Col.DoubleToByteClamped(0.501961), Col.DoubleToByteClamped(0.501961)); public static C4b Thistle => new C4b(Col.DoubleToByteClamped(0.847059), Col.DoubleToByteClamped(0.74902), Col.DoubleToByteClamped(0.847059)); public static C4b Tomato => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0.388235), Col.DoubleToByteClamped(0.278431)); public static C4b Turquoise => new C4b(Col.DoubleToByteClamped(0.25098), Col.DoubleToByteClamped(0.878431), Col.DoubleToByteClamped(0.815686)); public static C4b Violet => new C4b(Col.DoubleToByteClamped(0.933333), Col.DoubleToByteClamped(0.509804), Col.DoubleToByteClamped(0.933333)); public static C4b Wheat => new C4b(Col.DoubleToByteClamped(0.960784), Col.DoubleToByteClamped(0.870588), Col.DoubleToByteClamped(0.701961)); public static C4b White => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1)); public static C4b WhiteSmoke => new C4b(Col.DoubleToByteClamped(0.960784), Col.DoubleToByteClamped(0.960784), Col.DoubleToByteClamped(0.960784)); public static C4b Yellow => new C4b(Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(1), Col.DoubleToByteClamped(0)); public static C4b YellowGreen => new C4b(Col.DoubleToByteClamped(0.603922), Col.DoubleToByteClamped(0.803922), Col.DoubleToByteClamped(0.196078)); public static C4b DarkYellow => Olive; public static C4b VRVisGreen => new C4b(Col.DoubleToByteClamped(0.698), Col.DoubleToByteClamped(0.851), Col.DoubleToByteClamped(0.008)); public static C4b Gray10 => new C4b(Col.DoubleToByteClamped(0.1)); public static C4b Gray20 => new C4b(Col.DoubleToByteClamped(0.2)); public static C4b Gray30 => new C4b(Col.DoubleToByteClamped(0.3)); public static C4b Gray40 => new C4b(Col.DoubleToByteClamped(0.4)); public static C4b Gray50 => new C4b(Col.DoubleToByteClamped(0.5)); public static C4b Gray60 => new C4b(Col.DoubleToByteClamped(0.6)); public static C4b Gray70 => new C4b(Col.DoubleToByteClamped(0.7)); public static C4b Gray80 => new C4b(Col.DoubleToByteClamped(0.8)); public static C4b Gray90 => new C4b(Col.DoubleToByteClamped(0.9)); #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(C4b a, C4b b) { return a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(C4b a, C4b b) { return a.R != b.R || a.G != b.G || a.B != b.B || a.A != b.A; } #endregion #region Color Arithmetic [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator *(C4b col, float scalar) { return new C4b( Col.FloatToByteClamped(Col.ByteToFloat(col.R) * scalar), Col.FloatToByteClamped(Col.ByteToFloat(col.G) * scalar), Col.FloatToByteClamped(Col.ByteToFloat(col.B) * scalar), Col.FloatToByteClamped(Col.ByteToFloat(col.A) * scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator *(float scalar, C4b col) => col * scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator /(C4b col, float scalar) => col * (1 / scalar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator /(float scalar, C4b col) { return new C4b( Col.FloatToByteClamped(scalar / Col.ByteToFloat(col.R)), Col.FloatToByteClamped(scalar / Col.ByteToFloat(col.G)), Col.FloatToByteClamped(scalar / Col.ByteToFloat(col.B)), Col.FloatToByteClamped(scalar / Col.ByteToFloat(col.A))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator *(C4b col, double scalar) { return new C4b( Col.DoubleToByteClamped(Col.ByteToDouble(col.R) * scalar), Col.DoubleToByteClamped(Col.ByteToDouble(col.G) * scalar), Col.DoubleToByteClamped(Col.ByteToDouble(col.B) * scalar), Col.DoubleToByteClamped(Col.ByteToDouble(col.A) * scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator *(double scalar, C4b col) => col * scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator /(C4b col, double scalar) => col * (1 / scalar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator /(double scalar, C4b col) { return new C4b( Col.DoubleToByteClamped(scalar / Col.ByteToDouble(col.R)), Col.DoubleToByteClamped(scalar / Col.ByteToDouble(col.G)), Col.DoubleToByteClamped(scalar / Col.ByteToDouble(col.B)), Col.DoubleToByteClamped(scalar / Col.ByteToDouble(col.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator +(C4b c0, C4us c1) { return new C4b( (byte)(c0.R + Col.UShortToByte(c1.R)), (byte)(c0.G + Col.UShortToByte(c1.G)), (byte)(c0.B + Col.UShortToByte(c1.B)), (byte)(c0.A + Col.UShortToByte(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator -(C4b c0, C4us c1) { return new C4b( (byte)(c0.R - Col.UShortToByte(c1.R)), (byte)(c0.G - Col.UShortToByte(c1.G)), (byte)(c0.B - Col.UShortToByte(c1.B)), (byte)(c0.A - Col.UShortToByte(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator +(C4b c0, C4ui c1) { return new C4b( (byte)(c0.R + Col.UIntToByte(c1.R)), (byte)(c0.G + Col.UIntToByte(c1.G)), (byte)(c0.B + Col.UIntToByte(c1.B)), (byte)(c0.A + Col.UIntToByte(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator -(C4b c0, C4ui c1) { return new C4b( (byte)(c0.R - Col.UIntToByte(c1.R)), (byte)(c0.G - Col.UIntToByte(c1.G)), (byte)(c0.B - Col.UIntToByte(c1.B)), (byte)(c0.A - Col.UIntToByte(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator +(C4b c0, C4f c1) { return new C4b( (byte)(c0.R + Col.FloatToByte(c1.R)), (byte)(c0.G + Col.FloatToByte(c1.G)), (byte)(c0.B + Col.FloatToByte(c1.B)), (byte)(c0.A + Col.FloatToByte(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator -(C4b c0, C4f c1) { return new C4b( (byte)(c0.R - Col.FloatToByte(c1.R)), (byte)(c0.G - Col.FloatToByte(c1.G)), (byte)(c0.B - Col.FloatToByte(c1.B)), (byte)(c0.A - Col.FloatToByte(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator +(C4b c0, C4d c1) { return new C4b( (byte)(c0.R + Col.DoubleToByte(c1.R)), (byte)(c0.G + Col.DoubleToByte(c1.G)), (byte)(c0.B + Col.DoubleToByte(c1.B)), (byte)(c0.A + Col.DoubleToByte(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator -(C4b c0, C4d c1) { return new C4b( (byte)(c0.R - Col.DoubleToByte(c1.R)), (byte)(c0.G - Col.DoubleToByte(c1.G)), (byte)(c0.B - Col.DoubleToByte(c1.B)), (byte)(c0.A - Col.DoubleToByte(c1.A))); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator *(C4b col, byte scalar) { return new C4b((byte)(col.R * scalar), (byte)(col.G * scalar), (byte)(col.B * scalar), (byte)(col.A * scalar)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator *(byte scalar, C4b col) { return new C4b((byte)(scalar * col.R), (byte)(scalar * col.G), (byte)(scalar * col.B), (byte)(scalar * col.A)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator /(C4b col, byte scalar) { return new C4b((byte)(col.R / scalar), (byte)(col.G / scalar), (byte)(col.B / scalar), (byte)(col.A / scalar)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator /(byte scalar, C4b col) { return new C4b((byte)(scalar / col.R), (byte)(scalar / col.G), (byte)(scalar / col.B), (byte)(scalar / col.A)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator *(C4b c0, C4b c1) { return new C4b((byte)(c0.R * c1.R), (byte)(c0.G * c1.G), (byte)(c0.B * c1.B), (byte)(c0.A * c1.A)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator /(C4b c0, C4b c1) { return new C4b((byte)(c0.R / c1.R), (byte)(c0.G / c1.G), (byte)(c0.B / c1.B), (byte)(c0.A / c1.A)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator +(C4b c0, C4b c1) { return new C4b( (255 - c0.R > c1.R) ? c0.R + c1.R : 255, (255 - c0.G > c1.G) ? c0.G + c1.G : 255, (255 - c0.B > c1.B) ? c0.B + c1.B : 255, (255 - c0.A > c1.A) ? c0.A + c1.A : 255 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator +(C4b col, byte scalar) { return new C4b( (255 - col.R > scalar) ? col.R + scalar : 255, (255 - col.G > scalar) ? col.G + scalar : 255, (255 - col.B > scalar) ? col.B + scalar : 255, (255 - col.A > scalar) ? col.A + scalar : 255 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator +(byte scalar, C4b col) => col + scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator -(C4b c0, C4b c1) { return new C4b( (c0.R > c1.R) ? c0.R - c1.R : 0, (c0.G > c1.G) ? c0.G - c1.G : 0, (c0.B > c1.B) ? c0.B - c1.B : 0, (c0.A > c1.A) ? c0.A - c1.A : 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator -(C4b col, byte scalar) { return new C4b( (col.R > scalar) ? col.R - scalar : 0, (col.G > scalar) ? col.G - scalar : 0, (col.B > scalar) ? col.B - scalar : 0, (col.A > scalar) ? col.A - scalar : 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b operator -(byte scalar, C4b col) { return new C4b( (scalar > col.R) ? scalar - col.R : 0, (scalar > col.G) ? scalar - col.G : 0, (scalar > col.B) ? scalar - col.B : 0, (scalar > col.A) ? scalar - col.A : 0 ); } /// /// Clamps the color channels to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clamp(byte min, byte max) { R = R.Clamp(min, max); G = G.Clamp(min, max); B = B.Clamp(min, max); } /// /// Returns a copy with the color channels clamped to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b Clamped(byte min, byte max) { return new C4b(R.Clamp(min, max), G.Clamp(min, max), B.Clamp(min, max), A); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |R| + |G| + |B|. The alpha channel is ignored. /// public readonly int Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return R + G + B; } } /// /// Returns the Euclidean (or 2-) norm of the color. This is calculated /// as sqrt(R^2 + G^2 + B^2). The alpha channel is ignored. /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(R * R + G * G + B * B); } } /// /// Returns the infinite (or maximum) norm of the color. This is /// calculated as max(|R|, |G|, |B|). The alpha channel is ignored. /// public readonly byte NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(R, G, B); } } /// /// Returns the minimum norm of the color. This is calculated as /// min(|R|, |G|, |B|). The alpha channel is ignored. /// public readonly byte NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(R, G, B); } } #endregion #region Overrides public override readonly bool Equals(object other) => (other is C4b o) ? Equals(o) : false; public override readonly int GetHashCode() { return HashCode.GetCombined(R, G, B, A); } public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + R.ToString(null, CultureInfo.InvariantCulture) + ", " + G.ToString(null, CultureInfo.InvariantCulture) + ", " + B.ToString(null, CultureInfo.InvariantCulture) + ", " + A.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref C4b color, int i, byte value) => { switch (i) { case 0: color.R = value; return; case 1: color.G = value; return; case 2: color.B = value; return; case 3: color.A = value; return; default: throw new IndexOutOfRangeException(); } }; [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b LinearInterp(float t, C4b a, C4b b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b LinearInterp(V4f t, C4b a, C4b b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b LinearInterp(double t, C4b a, C4b b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b LinearInterp(V4d t, C4b a, C4b b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b DivideByInt(C4b c, int x) => c / x; #endregion #region Parsing /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C4b.Zero otherwise. /// True on success, false otherwise. public static bool TryParse(Text t, out C4b result) { if (Col.TryParseHex(t, out result)) { return true; } else { bool success = true; byte[] values = new byte[4] { 255, 255, 255, 255 }; byte parse(Text t) { if (!byte.TryParse(t.ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out byte value)) success = false; return value; }; var count = t.NestedBracketSplitCount2(1); if (count == 3 || count == 4) t.NestedBracketSplit(1, parse, () => values); else success = false; result = success ? new C4b(values) : Zero; return success; } } /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C4b.Zero otherwise. /// True on success, false otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParse(string s, out C4b result) => TryParse(new Text(s), out result); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C4b color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b Parse(string s) => Parse(new Text(s)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b Parse(Text t, int bracketLevel = 1) => t.NestedBracketSplit(bracketLevel, Text.Parse, C4b.Setter); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C4b color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b Parse(Text t) => TryParse(t, out C4b result) ? result : throw new FormatException($"{t} is not a valid C4b color."); #endregion #region IFormattable Members public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + R.ToString(format, fp) + between + G.ToString(format, fp) + between + B.ToString(format, fp) + between + A.ToString(format, fp) + end; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(C4b other) { return R.Equals(other.R) && G.Equals(other.G) && B.Equals(other.B) && A.Equals(other.A); } #endregion #region IRGB Members double IRGB.Red { readonly get { return Col.ByteToDouble(R); } set { R = Col.DoubleToByteClamped(value); } } double IRGB.Green { readonly get { return Col.ByteToDouble(G); } set { G = Col.DoubleToByteClamped(value); } } double IRGB.Blue { readonly get { return Col.ByteToDouble(B); } set { B = Col.DoubleToByteClamped(value); } } #endregion #region IOpacity Members [XmlIgnore] public double Opacity { readonly get { return Col.ByteToDouble(A); } set { A = Col.DoubleToByteClamped(value); } } #endregion } public static partial class Fun { #region Interpolation /// /// Returns the linearly interpolated color between a and b. /// public static C4b Lerp(this float t, C4b a, C4b b) => new C4b(Lerp(t, a.R, b.R), Lerp(t, a.G, b.G), Lerp(t, a.B, b.B), Lerp(t, a.A, b.A)); /// /// Returns the linearly interpolated color between a and b. /// public static C4b Lerp(this V4f t, C4b a, C4b b) => new C4b(Lerp(t.X, a.R, b.R), Lerp(t.Y, a.G, b.G), Lerp(t.Z, a.B, b.B), Lerp(t.W, a.A, b.A)); /// /// Returns the linearly interpolated color between a and b. /// public static C4b Lerp(this double t, C4b a, C4b b) => new C4b(Lerp(t, a.R, b.R), Lerp(t, a.G, b.G), Lerp(t, a.B, b.B), Lerp(t, a.A, b.A)); /// /// Returns the linearly interpolated color between a and b. /// public static C4b Lerp(this V4d t, C4b a, C4b b) => new C4b(Lerp(t.X, a.R, b.R), Lerp(t.Y, a.G, b.G), Lerp(t.Z, a.B, b.B), Lerp(t.W, a.A, b.A)); #endregion #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this C4b a, C4b b, byte tolerance) { return ApproximateEquals(a.R, b.R, tolerance) && ApproximateEquals(a.G, b.G, tolerance) && ApproximateEquals(a.B, b.B, tolerance) && ApproximateEquals(a.A, b.A, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this C4b c, byte epsilon) => Col.AllTiny(c, epsilon); #endregion } public static partial class Col { #region ToHexString /// /// Returns the hexadecimal representation with format RRGGBBAA. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToHexString(this C4b c) => $"{c.R:X2}{c.G:X2}{c.B:X2}{c.A:X2}"; #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C4b a, C4b b) { return (a.R < b.R && a.G < b.G && a.B < b.B && a.A < b.A); } /// /// Returns whether ALL elements of col are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C4b col, byte s) { return (col.R < s && col.G < s && col.B < s && col.A < s); } /// /// Returns whether a is Smaller ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(byte s, C4b col) { return (s < col.R && s < col.G && s < col.B && s < col.A); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C4b a, C4b b) { return (a.R < b.R || a.G < b.G || a.B < b.B || a.A < b.A); } /// /// Returns whether AT LEAST ONE element of col is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C4b col, byte s) { return (col.R < s || col.G < s || col.B < s || col.A < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(byte s, C4b col) { return (s < col.R || s < col.G || s < col.B || s < col.A); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C4b a, C4b b) { return (a.R > b.R && a.G > b.G && a.B > b.B && a.A > b.A); } /// /// Returns whether ALL elements of col are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C4b col, byte s) { return (col.R > s && col.G > s && col.B > s && col.A > s); } /// /// Returns whether a is Greater ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(byte s, C4b col) { return (s > col.R && s > col.G && s > col.B && s > col.A); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C4b a, C4b b) { return (a.R > b.R || a.G > b.G || a.B > b.B || a.A > b.A); } /// /// Returns whether AT LEAST ONE element of col is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C4b col, byte s) { return (col.R > s || col.G > s || col.B > s || col.A > s); } /// /// Returns whether a is Greater AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(byte s, C4b col) { return (s > col.R || s > col.G || s > col.B || s > col.A); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C4b a, C4b b) { return (a.R <= b.R && a.G <= b.G && a.B <= b.B && a.A <= b.A); } /// /// Returns whether ALL elements of col are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C4b col, byte s) { return (col.R <= s && col.G <= s && col.B <= s && col.A <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(byte s, C4b col) { return (s <= col.R && s <= col.G && s <= col.B && s <= col.A); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C4b a, C4b b) { return (a.R <= b.R || a.G <= b.G || a.B <= b.B || a.A <= b.A); } /// /// Returns whether AT LEAST ONE element of col is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C4b col, byte s) { return (col.R <= s || col.G <= s || col.B <= s || col.A <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(byte s, C4b col) { return (s <= col.R || s <= col.G || s <= col.B || s <= col.A); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C4b a, C4b b) { return (a.R >= b.R && a.G >= b.G && a.B >= b.B && a.A >= b.A); } /// /// Returns whether ALL elements of col are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C4b col, byte s) { return (col.R >= s && col.G >= s && col.B >= s && col.A >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(byte s, C4b col) { return (s >= col.R && s >= col.G && s >= col.B && s >= col.A); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C4b a, C4b b) { return (a.R >= b.R || a.G >= b.G || a.B >= b.B || a.A >= b.A); } /// /// Returns whether AT LEAST ONE element of col is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C4b col, byte s) { return (col.R >= s || col.G >= s || col.B >= s || col.A >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(byte s, C4b col) { return (s >= col.R || s >= col.G || s >= col.B || s >= col.A); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C4b a, C4b b) { return (a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A); } /// /// Returns whether ALL elements of col are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C4b col, byte s) { return (col.R == s && col.G == s && col.B == s && col.A == s); } /// /// Returns whether a is Equal ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(byte s, C4b col) { return (s == col.R && s == col.G && s == col.B && s == col.A); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C4b a, C4b b) { return (a.R == b.R || a.G == b.G || a.B == b.B || a.A == b.A); } /// /// Returns whether AT LEAST ONE element of col is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C4b col, byte s) { return (col.R == s || col.G == s || col.B == s || col.A == s); } /// /// Returns whether a is Equal AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(byte s, C4b col) { return (s == col.R || s == col.G || s == col.B || s == col.A); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C4b a, C4b b) { return (a.R != b.R && a.G != b.G && a.B != b.B && a.A != b.A); } /// /// Returns whether ALL elements of col are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C4b col, byte s) { return (col.R != s && col.G != s && col.B != s && col.A != s); } /// /// Returns whether a is Different ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(byte s, C4b col) { return (s != col.R && s != col.G && s != col.B && s != col.A); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C4b a, C4b b) { return (a.R != b.R || a.G != b.G || a.B != b.B || a.A != b.A); } /// /// Returns whether AT LEAST ONE element of col is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C4b col, byte s) { return (col.R != s || col.G != s || col.B != s || col.A != s); } /// /// Returns whether a is Different AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(byte s, C4b col) { return (s != col.R || s != col.G || s != col.B || s != col.A); } #endregion #region Linear Combination /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b LinCom( C4b p0, C4b p1, C4b p2, C4b p3, ref Tup4 w) { return new C4b( Col.ByteInFloatToByteClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3), Col.ByteInFloatToByteClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3), Col.ByteInFloatToByteClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f LinComRawF( C4b p0, C4b p1, C4b p2, C4b p3, ref Tup4 w) { return new C4f( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b LinCom( C4b p0, C4b p1, C4b p2, C4b p3, ref Tup4 w) { return new C4b( Col.ByteInDoubleToByteClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3), Col.ByteInDoubleToByteClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3), Col.ByteInDoubleToByteClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d LinComRawD( C4b p0, C4b p1, C4b p2, C4b p3, ref Tup4 w) { return new C4d( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b LinCom( C4b p0, C4b p1, C4b p2, C4b p3, C4b p4, C4b p5, ref Tup6 w) { return new C4b( Col.ByteInFloatToByteClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5), Col.ByteInFloatToByteClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5), Col.ByteInFloatToByteClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f LinComRawF( C4b p0, C4b p1, C4b p2, C4b p3, C4b p4, C4b p5, ref Tup6 w) { return new C4f( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4b LinCom( C4b p0, C4b p1, C4b p2, C4b p3, C4b p4, C4b p5, ref Tup6 w) { return new C4b( Col.ByteInDoubleToByteClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5), Col.ByteInDoubleToByteClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5), Col.ByteInDoubleToByteClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d LinComRawD( C4b p0, C4b p1, C4b p2, C4b p3, C4b p4, C4b p5, ref Tup6 w) { return new C4d( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5); } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this C4b c, byte epsilon) => c.R.IsTiny(epsilon) || c.G.IsTiny(epsilon) || c.B.IsTiny(epsilon) || c.A.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this C4b c, byte epsilon) => c.R.IsTiny(epsilon) && c.G.IsTiny(epsilon) && c.B.IsTiny(epsilon) && c.A.IsTiny(epsilon); #endregion } #endregion #region C4us /// /// Represents an RGBA color with each channel stored as a value within [0, 2^16 - 1]. /// [Serializable] public partial struct C4us : IFormattable, IEquatable, IRGB, IOpacity { #region Constructors /// /// Creates a color from the given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(ushort r, ushort g, ushort b, ushort a) { R = r; G = g; B = b; A = a; } /// /// Creates a color from the given values. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(int r, int g, int b, int a) { R = (ushort)r; G = (ushort)g; B = (ushort)b; A = (ushort)a; } /// /// Creates a color from the given values. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(long r, long g, long b, long a) { R = (ushort)r; G = (ushort)g; B = (ushort)b; A = (ushort)a; } /// /// Creates a color from the given values. /// The values are mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(float r, float g, float b, float a) { R = Col.FloatToUShortClamped(r); G = Col.FloatToUShortClamped(g); B = Col.FloatToUShortClamped(b); A = Col.FloatToUShortClamped(a); } /// /// Creates a color from the given values. /// The values are mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(double r, double g, double b, double a) { R = Col.DoubleToUShortClamped(r); G = Col.DoubleToUShortClamped(g); B = Col.DoubleToUShortClamped(b); A = Col.DoubleToUShortClamped(a); } /// /// Creates a color from the given RGB values. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(ushort r, ushort g, ushort b) { R = r; G = g; B = b; A = 65535; } /// /// Creates a color from the given RGB values. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(int r, int g, int b) { R = (ushort)r; G = (ushort)g; B = (ushort)b; A = 65535; } /// /// Creates a color from the given RGB values. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(long r, long g, long b) { R = (ushort)r; G = (ushort)g; B = (ushort)b; A = 65535; } /// /// Creates a color from the given RGB values. /// The values are mapped and clamped from [0, 1] to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(float r, float g, float b) { R = Col.FloatToUShortClamped(r); G = Col.FloatToUShortClamped(g); B = Col.FloatToUShortClamped(b); A = 65535; } /// /// Creates a color from the given RGB values. /// The values are mapped and clamped from [0, 1] to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(double r, double g, double b) { R = Col.DoubleToUShortClamped(r); G = Col.DoubleToUShortClamped(g); B = Col.DoubleToUShortClamped(b); A = 65535; } /// /// Creates a color from a single value. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(ushort gray) { R = gray; G = gray; B = gray; A = 65535; } /// /// Creates a color from a single value. /// The value is mapped and clamped from [0, 1] to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(float gray) { var value = Col.FloatToUShortClamped(gray); R = value; G = value; B = value; A = 65535; } /// /// Creates a color from a single value. /// The value is mapped and clamped from [0, 1] to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(double gray) { var value = Col.DoubleToUShortClamped(gray); R = value; G = value; B = value; A = 65535; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(C3b color) { R = Col.ByteToUShort(color.R); G = Col.ByteToUShort(color.G); B = Col.ByteToUShort(color.B); A = 65535; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(C3b color, ushort alpha) { R = Col.ByteToUShort(color.R); G = Col.ByteToUShort(color.G); B = Col.ByteToUShort(color.B); A = alpha; } /// /// Creates a color from the given color. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(C3us color) { R = (color.R); G = (color.G); B = (color.B); A = 65535; } /// /// Creates a color from the given color and an alpha value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(C3us color, ushort alpha) { R = (color.R); G = (color.G); B = (color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(C3ui color) { R = Col.UIntToUShort(color.R); G = Col.UIntToUShort(color.G); B = Col.UIntToUShort(color.B); A = 65535; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(C3ui color, ushort alpha) { R = Col.UIntToUShort(color.R); G = Col.UIntToUShort(color.G); B = Col.UIntToUShort(color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(C3f color) { R = Col.FloatToUShortClamped(color.R); G = Col.FloatToUShortClamped(color.G); B = Col.FloatToUShortClamped(color.B); A = 65535; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(C3f color, ushort alpha) { R = Col.FloatToUShortClamped(color.R); G = Col.FloatToUShortClamped(color.G); B = Col.FloatToUShortClamped(color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(C3d color) { R = Col.DoubleToUShortClamped(color.R); G = Col.DoubleToUShortClamped(color.G); B = Col.DoubleToUShortClamped(color.B); A = 65535; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(C3d color, ushort alpha) { R = Col.DoubleToUShortClamped(color.R); G = Col.DoubleToUShortClamped(color.G); B = Col.DoubleToUShortClamped(color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(C4b color) { R = Col.ByteToUShort(color.R); G = Col.ByteToUShort(color.G); B = Col.ByteToUShort(color.B); A = Col.ByteToUShort(color.A); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(C4us color) { R = (color.R); G = (color.G); B = (color.B); A = (color.A); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(C4ui color) { R = Col.UIntToUShort(color.R); G = Col.UIntToUShort(color.G); B = Col.UIntToUShort(color.B); A = Col.UIntToUShort(color.A); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(C4f color) { R = Col.FloatToUShortClamped(color.R); G = Col.FloatToUShortClamped(color.G); B = Col.FloatToUShortClamped(color.B); A = Col.FloatToUShortClamped(color.A); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(C4d color) { R = Col.DoubleToUShortClamped(color.R); G = Col.DoubleToUShortClamped(color.G); B = Col.DoubleToUShortClamped(color.B); A = Col.DoubleToUShortClamped(color.A); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(V3i vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); A = 65535; } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(V3ui vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); A = 65535; } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(V3l vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); A = 65535; } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(V3f vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); A = 65535; } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(V3d vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); A = 65535; } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(V4i vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); A = (ushort)(vec.W); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(V4ui vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); A = (ushort)(vec.W); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(V4l vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); A = (ushort)(vec.W); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(V4f vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); A = (ushort)(vec.W); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(V4d vec) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); A = (ushort)(vec.W); } /// /// Creates a color from the given vector and an alpha value. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(V3i vec, ushort alpha) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); A = alpha; } /// /// Creates a color from the given vector and an alpha value. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(V3ui vec, ushort alpha) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); A = alpha; } /// /// Creates a color from the given vector and an alpha value. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(V3l vec, ushort alpha) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); A = alpha; } /// /// Creates a color from the given vector and an alpha value. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(V3f vec, ushort alpha) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); A = alpha; } /// /// Creates a color from the given vector and an alpha value. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(V3d vec, ushort alpha) { R = (ushort)(vec.X); G = (ushort)(vec.Y); B = (ushort)(vec.Z); A = alpha; } /// /// Creates a color from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(Func index_fun) { R = index_fun(0); G = index_fun(1); B = index_fun(2); A = index_fun(3); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(byte[] values) { R = Col.ByteToUShort(values[0]); G = Col.ByteToUShort(values[1]); B = Col.ByteToUShort(values[2]); A = Col.ByteToUShort(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(byte[] values, int start) { R = Col.ByteToUShort(values[start + 0]); G = Col.ByteToUShort(values[start + 1]); B = Col.ByteToUShort(values[start + 2]); A = Col.ByteToUShort(values[start + 3]); } /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(ushort[] values) { R = (values[0]); G = (values[1]); B = (values[2]); A = (values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(ushort[] values, int start) { R = (values[start + 0]); G = (values[start + 1]); B = (values[start + 2]); A = (values[start + 3]); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(uint[] values) { R = Col.UIntToUShort(values[0]); G = Col.UIntToUShort(values[1]); B = Col.UIntToUShort(values[2]); A = Col.UIntToUShort(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(uint[] values, int start) { R = Col.UIntToUShort(values[start + 0]); G = Col.UIntToUShort(values[start + 1]); B = Col.UIntToUShort(values[start + 2]); A = Col.UIntToUShort(values[start + 3]); } /// /// Creates a new color from the given array. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(float[] values) { R = Col.FloatToUShortClamped(values[0]); G = Col.FloatToUShortClamped(values[1]); B = Col.FloatToUShortClamped(values[2]); A = Col.FloatToUShortClamped(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(float[] values, int start) { R = Col.FloatToUShortClamped(values[start + 0]); G = Col.FloatToUShortClamped(values[start + 1]); B = Col.FloatToUShortClamped(values[start + 2]); A = Col.FloatToUShortClamped(values[start + 3]); } /// /// Creates a new color from the given array. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(double[] values) { R = Col.DoubleToUShortClamped(values[0]); G = Col.DoubleToUShortClamped(values[1]); B = Col.DoubleToUShortClamped(values[2]); A = Col.DoubleToUShortClamped(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4us(double[] values, int start) { R = Col.DoubleToUShortClamped(values[start + 0]); G = Col.DoubleToUShortClamped(values[start + 1]); B = Col.DoubleToUShortClamped(values[start + 2]); A = Col.DoubleToUShortClamped(values[start + 3]); } #endregion #region Properities public readonly C3us RGB => (C3us)this; #endregion #region Conversions /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(C3b color) => new C4us(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromC3b(C3b c) => new C4us(c); /// /// Converts the given color to a color. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(C3us color) => new C4us(color); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Creates a color from the given color. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromC3us(C3us c) => new C4us(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(C3ui color) => new C4us(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromC3ui(C3ui c) => new C4us(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(C3f color) => new C4us(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f ToC3f() => (C3f)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromC3f(C3f c) => new C4us(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(C3d color) => new C4us(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d ToC3d() => (C3d)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromC3d(C3d c) => new C4us(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(C4b color) => new C4us(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromC4b(C4b c) => new C4us(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(C4ui color) => new C4us(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromC4ui(C4ui c) => new C4us(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(C4f color) => new C4us(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f ToC4f() => (C4f)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromC4f(C4f c) => new C4us(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(C4d color) => new C4us(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d ToC4d() => (C4d)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromC4d(C4d c) => new C4us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(V3i v) => new C4us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromV3i(V3i c) => new C4us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(V3ui v) => new C4us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromV3ui(V3ui c) => new C4us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(V3l v) => new C4us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromV3l(V3l c) => new C4us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(V3f v) => new C4us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromV3f(V3f c) => new C4us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(V3d v) => new C4us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromV3d(V3d c) => new C4us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(V4i v) => new C4us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromV4i(V4i c) => new C4us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(V4ui v) => new C4us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromV4ui(V4ui c) => new C4us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(V4l v) => new C4us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromV4l(V4l c) => new C4us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(V4f v) => new C4us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromV4f(V4f c) => new C4us(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(V4d v) => new C4us(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us FromV4d(V4d c) => new C4us(c); /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(byte[] values) => new C4us(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator byte[](C4us color) => new byte[] { Col.UShortToByte(color.R), Col.UShortToByte(color.G), Col.UShortToByte(color.B), Col.UShortToByte(color.A) }; /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(ushort[] values) => new C4us(values); /// /// Creates a new array from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ushort[](C4us color) => new ushort[] { (color.R), (color.G), (color.B), (color.A) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(uint[] values) => new C4us(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](C4us color) => new uint[] { Col.UShortToUInt(color.R), Col.UShortToUInt(color.G), Col.UShortToUInt(color.B), Col.UShortToUInt(color.A) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(float[] values) => new C4us(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](C4us color) => new float[] { Col.UShortToFloat(color.R), Col.UShortToFloat(color.G), Col.UShortToFloat(color.B), Col.UShortToFloat(color.A) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4us(double[] values) => new C4us(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](C4us color) => new double[] { Col.UShortToDouble(color.R), Col.UShortToDouble(color.G), Col.UShortToDouble(color.B), Col.UShortToDouble(color.A) }; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b Map(Func channel_fun) { return new C4b(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us Map(Func channel_fun) { return new C4us(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui Map(Func channel_fun) { return new C4ui(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f Map(Func channel_fun) { return new C4f(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d Map(Func channel_fun) { return new C4d(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(R); array[start + 1] = element_fun(G); array[start + 2] = element_fun(B); array[start + 3] = element_fun(A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(R, 0); array[start + 1] = element_index_fun(G, 1); array[start + 2] = element_index_fun(B, 2); array[start + 3] = element_index_fun(A, 3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly ushort[] ToArray() => (ushort[])this; #endregion #region Indexer /// /// Indexer in canonical order 0=R, 1=G, 2=B, 3=A (availability depending on color type). /// public unsafe ushort this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (ushort* ptr = &R) { ptr[i] = value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (ushort* ptr = &R) { return ptr[i]; } } } #endregion #region Constants /// /// C4us with all components zero. /// public static C4us Zero => new C4us(0, 0, 0, 0); // Web colors public static C4us AliceBlue => new C4us(Col.DoubleToUShortClamped(0.941176), Col.DoubleToUShortClamped(0.972549), Col.DoubleToUShortClamped(1)); public static C4us AntiqueWhite => new C4us(Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.921569), Col.DoubleToUShortClamped(0.843137)); public static C4us Aqua => new C4us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1)); public static C4us Aquamarine => new C4us(Col.DoubleToUShortClamped(0.498039), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.831373)); public static C4us Azure => new C4us(Col.DoubleToUShortClamped(0.941176), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1)); public static C4us Beige => new C4us(Col.DoubleToUShortClamped(0.960784), Col.DoubleToUShortClamped(0.960784), Col.DoubleToUShortClamped(0.862745)); public static C4us Bisque => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.894118), Col.DoubleToUShortClamped(0.768627)); public static C4us Black => new C4us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0)); public static C4us BlanchedAlmond => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.921569), Col.DoubleToUShortClamped(0.803922)); public static C4us Blue => new C4us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(1)); public static C4us BlueViolet => new C4us(Col.DoubleToUShortClamped(0.541176), Col.DoubleToUShortClamped(0.168627), Col.DoubleToUShortClamped(0.886275)); public static C4us Brown => new C4us(Col.DoubleToUShortClamped(0.647059), Col.DoubleToUShortClamped(0.164706), Col.DoubleToUShortClamped(0.164706)); public static C4us BurlyWood => new C4us(Col.DoubleToUShortClamped(0.870588), Col.DoubleToUShortClamped(0.721569), Col.DoubleToUShortClamped(0.529412)); public static C4us CadetBlue => new C4us(Col.DoubleToUShortClamped(0.372549), Col.DoubleToUShortClamped(0.619608), Col.DoubleToUShortClamped(0.627451)); public static C4us Chartreuse => new C4us(Col.DoubleToUShortClamped(0.498039), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0)); public static C4us Chocolate => new C4us(Col.DoubleToUShortClamped(0.823529), Col.DoubleToUShortClamped(0.411765), Col.DoubleToUShortClamped(0.117647)); public static C4us Coral => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.498039), Col.DoubleToUShortClamped(0.313725)); public static C4us CornflowerBlue => new C4us(Col.DoubleToUShortClamped(0.392157), Col.DoubleToUShortClamped(0.584314), Col.DoubleToUShortClamped(0.929412)); public static C4us Cornsilk => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.972549), Col.DoubleToUShortClamped(0.862745)); public static C4us Crimson => new C4us(Col.DoubleToUShortClamped(0.862745), Col.DoubleToUShortClamped(0.078431), Col.DoubleToUShortClamped(0.235294)); public static C4us Cyan => new C4us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1)); public static C4us DarkBlue => new C4us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.545098)); public static C4us DarkCyan => new C4us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.545098), Col.DoubleToUShortClamped(0.545098)); public static C4us DarkGoldenRod => new C4us(Col.DoubleToUShortClamped(0.721569), Col.DoubleToUShortClamped(0.52549), Col.DoubleToUShortClamped(0.043137)); public static C4us DarkGray => new C4us(Col.DoubleToUShortClamped(0.662745), Col.DoubleToUShortClamped(0.662745), Col.DoubleToUShortClamped(0.662745)); public static C4us DarkGrey => new C4us(Col.DoubleToUShortClamped(0.662745), Col.DoubleToUShortClamped(0.662745), Col.DoubleToUShortClamped(0.662745)); public static C4us DarkGreen => new C4us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.392157), Col.DoubleToUShortClamped(0)); public static C4us DarkKhaki => new C4us(Col.DoubleToUShortClamped(0.741176), Col.DoubleToUShortClamped(0.717647), Col.DoubleToUShortClamped(0.419608)); public static C4us DarkMagenta => new C4us(Col.DoubleToUShortClamped(0.545098), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.545098)); public static C4us DarkOliveGreen => new C4us(Col.DoubleToUShortClamped(0.333333), Col.DoubleToUShortClamped(0.419608), Col.DoubleToUShortClamped(0.184314)); public static C4us DarkOrange => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.54902), Col.DoubleToUShortClamped(0)); public static C4us DarkOrchid => new C4us(Col.DoubleToUShortClamped(0.6), Col.DoubleToUShortClamped(0.196078), Col.DoubleToUShortClamped(0.8)); public static C4us DarkRed => new C4us(Col.DoubleToUShortClamped(0.545098), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0)); public static C4us DarkSalmon => new C4us(Col.DoubleToUShortClamped(0.913725), Col.DoubleToUShortClamped(0.588235), Col.DoubleToUShortClamped(0.478431)); public static C4us DarkSeaGreen => new C4us(Col.DoubleToUShortClamped(0.560784), Col.DoubleToUShortClamped(0.737255), Col.DoubleToUShortClamped(0.560784)); public static C4us DarkSlateBlue => new C4us(Col.DoubleToUShortClamped(0.282353), Col.DoubleToUShortClamped(0.239216), Col.DoubleToUShortClamped(0.545098)); public static C4us DarkSlateGray => new C4us(Col.DoubleToUShortClamped(0.184314), Col.DoubleToUShortClamped(0.309804), Col.DoubleToUShortClamped(0.309804)); public static C4us DarkSlateGrey => new C4us(Col.DoubleToUShortClamped(0.184314), Col.DoubleToUShortClamped(0.309804), Col.DoubleToUShortClamped(0.309804)); public static C4us DarkTurquoise => new C4us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.807843), Col.DoubleToUShortClamped(0.819608)); public static C4us DarkViolet => new C4us(Col.DoubleToUShortClamped(0.580392), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.827451)); public static C4us DeepPink => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.078431), Col.DoubleToUShortClamped(0.576471)); public static C4us DeepSkyBlue => new C4us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.74902), Col.DoubleToUShortClamped(1)); public static C4us DimGray => new C4us(Col.DoubleToUShortClamped(0.411765), Col.DoubleToUShortClamped(0.411765), Col.DoubleToUShortClamped(0.411765)); public static C4us DimGrey => new C4us(Col.DoubleToUShortClamped(0.411765), Col.DoubleToUShortClamped(0.411765), Col.DoubleToUShortClamped(0.411765)); public static C4us DodgerBlue => new C4us(Col.DoubleToUShortClamped(0.117647), Col.DoubleToUShortClamped(0.564706), Col.DoubleToUShortClamped(1)); public static C4us FireBrick => new C4us(Col.DoubleToUShortClamped(0.698039), Col.DoubleToUShortClamped(0.133333), Col.DoubleToUShortClamped(0.133333)); public static C4us FloralWhite => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.941176)); public static C4us ForestGreen => new C4us(Col.DoubleToUShortClamped(0.133333), Col.DoubleToUShortClamped(0.545098), Col.DoubleToUShortClamped(0.133333)); public static C4us Fuchsia => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(1)); public static C4us Gainsboro => new C4us(Col.DoubleToUShortClamped(0.862745), Col.DoubleToUShortClamped(0.862745), Col.DoubleToUShortClamped(0.862745)); public static C4us GhostWhite => new C4us(Col.DoubleToUShortClamped(0.972549), Col.DoubleToUShortClamped(0.972549), Col.DoubleToUShortClamped(1)); public static C4us Gold => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.843137), Col.DoubleToUShortClamped(0)); public static C4us GoldenRod => new C4us(Col.DoubleToUShortClamped(0.854902), Col.DoubleToUShortClamped(0.647059), Col.DoubleToUShortClamped(0.12549)); public static C4us Gray => new C4us(Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.501961)); public static C4us Grey => new C4us(Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.501961)); public static C4us Green => new C4us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0)); public static C4us GreenYellow => new C4us(Col.DoubleToUShortClamped(0.678431), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.184314)); public static C4us HoneyDew => new C4us(Col.DoubleToUShortClamped(0.941176), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.941176)); public static C4us HotPink => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.411765), Col.DoubleToUShortClamped(0.705882)); public static C4us IndianRed => new C4us(Col.DoubleToUShortClamped(0.803922), Col.DoubleToUShortClamped(0.360784), Col.DoubleToUShortClamped(0.360784)); public static C4us Indigo => new C4us(Col.DoubleToUShortClamped(0.294118), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.509804)); public static C4us Ivory => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.941176)); public static C4us Khaki => new C4us(Col.DoubleToUShortClamped(0.941176), Col.DoubleToUShortClamped(0.901961), Col.DoubleToUShortClamped(0.54902)); public static C4us Lavender => new C4us(Col.DoubleToUShortClamped(0.901961), Col.DoubleToUShortClamped(0.901961), Col.DoubleToUShortClamped(0.980392)); public static C4us LavenderBlush => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.941176), Col.DoubleToUShortClamped(0.960784)); public static C4us LawnGreen => new C4us(Col.DoubleToUShortClamped(0.486275), Col.DoubleToUShortClamped(0.988235), Col.DoubleToUShortClamped(0)); public static C4us LemonChiffon => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.803922)); public static C4us LightBlue => new C4us(Col.DoubleToUShortClamped(0.678431), Col.DoubleToUShortClamped(0.847059), Col.DoubleToUShortClamped(0.901961)); public static C4us LightCoral => new C4us(Col.DoubleToUShortClamped(0.941176), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.501961)); public static C4us LightCyan => new C4us(Col.DoubleToUShortClamped(0.878431), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1)); public static C4us LightGoldenRodYellow => new C4us(Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.823529)); public static C4us LightGray => new C4us(Col.DoubleToUShortClamped(0.827451), Col.DoubleToUShortClamped(0.827451), Col.DoubleToUShortClamped(0.827451)); public static C4us LightGrey => new C4us(Col.DoubleToUShortClamped(0.827451), Col.DoubleToUShortClamped(0.827451), Col.DoubleToUShortClamped(0.827451)); public static C4us LightGreen => new C4us(Col.DoubleToUShortClamped(0.564706), Col.DoubleToUShortClamped(0.933333), Col.DoubleToUShortClamped(0.564706)); public static C4us LightPink => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.713725), Col.DoubleToUShortClamped(0.756863)); public static C4us LightSalmon => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.627451), Col.DoubleToUShortClamped(0.478431)); public static C4us LightSeaGreen => new C4us(Col.DoubleToUShortClamped(0.12549), Col.DoubleToUShortClamped(0.698039), Col.DoubleToUShortClamped(0.666667)); public static C4us LightSkyBlue => new C4us(Col.DoubleToUShortClamped(0.529412), Col.DoubleToUShortClamped(0.807843), Col.DoubleToUShortClamped(0.980392)); public static C4us LightSlateGray => new C4us(Col.DoubleToUShortClamped(0.466667), Col.DoubleToUShortClamped(0.533333), Col.DoubleToUShortClamped(0.6)); public static C4us LightSlateGrey => new C4us(Col.DoubleToUShortClamped(0.466667), Col.DoubleToUShortClamped(0.533333), Col.DoubleToUShortClamped(0.6)); public static C4us LightSteelBlue => new C4us(Col.DoubleToUShortClamped(0.690196), Col.DoubleToUShortClamped(0.768627), Col.DoubleToUShortClamped(0.870588)); public static C4us LightYellow => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.878431)); public static C4us Lime => new C4us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0)); public static C4us LimeGreen => new C4us(Col.DoubleToUShortClamped(0.196078), Col.DoubleToUShortClamped(0.803922), Col.DoubleToUShortClamped(0.196078)); public static C4us Linen => new C4us(Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.941176), Col.DoubleToUShortClamped(0.901961)); public static C4us Magenta => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(1)); public static C4us Maroon => new C4us(Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0)); public static C4us MediumAquaMarine => new C4us(Col.DoubleToUShortClamped(0.4), Col.DoubleToUShortClamped(0.803922), Col.DoubleToUShortClamped(0.666667)); public static C4us MediumBlue => new C4us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.803922)); public static C4us MediumOrchid => new C4us(Col.DoubleToUShortClamped(0.729412), Col.DoubleToUShortClamped(0.333333), Col.DoubleToUShortClamped(0.827451)); public static C4us MediumPurple => new C4us(Col.DoubleToUShortClamped(0.576471), Col.DoubleToUShortClamped(0.439216), Col.DoubleToUShortClamped(0.847059)); public static C4us MediumSeaGreen => new C4us(Col.DoubleToUShortClamped(0.235294), Col.DoubleToUShortClamped(0.701961), Col.DoubleToUShortClamped(0.443137)); public static C4us MediumSlateBlue => new C4us(Col.DoubleToUShortClamped(0.482353), Col.DoubleToUShortClamped(0.407843), Col.DoubleToUShortClamped(0.933333)); public static C4us MediumSpringGreen => new C4us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.603922)); public static C4us MediumTurquoise => new C4us(Col.DoubleToUShortClamped(0.282353), Col.DoubleToUShortClamped(0.819608), Col.DoubleToUShortClamped(0.8)); public static C4us MediumVioletRed => new C4us(Col.DoubleToUShortClamped(0.780392), Col.DoubleToUShortClamped(0.082353), Col.DoubleToUShortClamped(0.521569)); public static C4us MidnightBlue => new C4us(Col.DoubleToUShortClamped(0.098039), Col.DoubleToUShortClamped(0.098039), Col.DoubleToUShortClamped(0.439216)); public static C4us MintCream => new C4us(Col.DoubleToUShortClamped(0.960784), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.980392)); public static C4us MistyRose => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.894118), Col.DoubleToUShortClamped(0.882353)); public static C4us Moccasin => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.894118), Col.DoubleToUShortClamped(0.709804)); public static C4us NavajoWhite => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.870588), Col.DoubleToUShortClamped(0.678431)); public static C4us Navy => new C4us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.501961)); public static C4us OldLace => new C4us(Col.DoubleToUShortClamped(0.992157), Col.DoubleToUShortClamped(0.960784), Col.DoubleToUShortClamped(0.901961)); public static C4us Olive => new C4us(Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0)); public static C4us OliveDrab => new C4us(Col.DoubleToUShortClamped(0.419608), Col.DoubleToUShortClamped(0.556863), Col.DoubleToUShortClamped(0.137255)); public static C4us Orange => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.647059), Col.DoubleToUShortClamped(0)); public static C4us OrangeRed => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.270588), Col.DoubleToUShortClamped(0)); public static C4us Orchid => new C4us(Col.DoubleToUShortClamped(0.854902), Col.DoubleToUShortClamped(0.439216), Col.DoubleToUShortClamped(0.839216)); public static C4us PaleGoldenRod => new C4us(Col.DoubleToUShortClamped(0.933333), Col.DoubleToUShortClamped(0.909804), Col.DoubleToUShortClamped(0.666667)); public static C4us PaleGreen => new C4us(Col.DoubleToUShortClamped(0.596078), Col.DoubleToUShortClamped(0.984314), Col.DoubleToUShortClamped(0.596078)); public static C4us PaleTurquoise => new C4us(Col.DoubleToUShortClamped(0.686275), Col.DoubleToUShortClamped(0.933333), Col.DoubleToUShortClamped(0.933333)); public static C4us PaleVioletRed => new C4us(Col.DoubleToUShortClamped(0.847059), Col.DoubleToUShortClamped(0.439216), Col.DoubleToUShortClamped(0.576471)); public static C4us PapayaWhip => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.937255), Col.DoubleToUShortClamped(0.835294)); public static C4us PeachPuff => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.854902), Col.DoubleToUShortClamped(0.72549)); public static C4us Peru => new C4us(Col.DoubleToUShortClamped(0.803922), Col.DoubleToUShortClamped(0.521569), Col.DoubleToUShortClamped(0.247059)); public static C4us Pink => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.752941), Col.DoubleToUShortClamped(0.796078)); public static C4us Plum => new C4us(Col.DoubleToUShortClamped(0.866667), Col.DoubleToUShortClamped(0.627451), Col.DoubleToUShortClamped(0.866667)); public static C4us PowderBlue => new C4us(Col.DoubleToUShortClamped(0.690196), Col.DoubleToUShortClamped(0.878431), Col.DoubleToUShortClamped(0.901961)); public static C4us Purple => new C4us(Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.501961)); public static C4us Red => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0)); public static C4us RosyBrown => new C4us(Col.DoubleToUShortClamped(0.737255), Col.DoubleToUShortClamped(0.560784), Col.DoubleToUShortClamped(0.560784)); public static C4us RoyalBlue => new C4us(Col.DoubleToUShortClamped(0.254902), Col.DoubleToUShortClamped(0.411765), Col.DoubleToUShortClamped(0.882353)); public static C4us SaddleBrown => new C4us(Col.DoubleToUShortClamped(0.545098), Col.DoubleToUShortClamped(0.270588), Col.DoubleToUShortClamped(0.07451)); public static C4us Salmon => new C4us(Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.447059)); public static C4us SandyBrown => new C4us(Col.DoubleToUShortClamped(0.956863), Col.DoubleToUShortClamped(0.643137), Col.DoubleToUShortClamped(0.376471)); public static C4us SeaGreen => new C4us(Col.DoubleToUShortClamped(0.180392), Col.DoubleToUShortClamped(0.545098), Col.DoubleToUShortClamped(0.341176)); public static C4us SeaShell => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.960784), Col.DoubleToUShortClamped(0.933333)); public static C4us Sienna => new C4us(Col.DoubleToUShortClamped(0.627451), Col.DoubleToUShortClamped(0.321569), Col.DoubleToUShortClamped(0.176471)); public static C4us Silver => new C4us(Col.DoubleToUShortClamped(0.752941), Col.DoubleToUShortClamped(0.752941), Col.DoubleToUShortClamped(0.752941)); public static C4us SkyBlue => new C4us(Col.DoubleToUShortClamped(0.529412), Col.DoubleToUShortClamped(0.807843), Col.DoubleToUShortClamped(0.921569)); public static C4us SlateBlue => new C4us(Col.DoubleToUShortClamped(0.415686), Col.DoubleToUShortClamped(0.352941), Col.DoubleToUShortClamped(0.803922)); public static C4us SlateGray => new C4us(Col.DoubleToUShortClamped(0.439216), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.564706)); public static C4us SlateGrey => new C4us(Col.DoubleToUShortClamped(0.439216), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.564706)); public static C4us Snow => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.980392), Col.DoubleToUShortClamped(0.980392)); public static C4us SpringGreen => new C4us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.498039)); public static C4us SteelBlue => new C4us(Col.DoubleToUShortClamped(0.27451), Col.DoubleToUShortClamped(0.509804), Col.DoubleToUShortClamped(0.705882)); public static C4us Tan => new C4us(Col.DoubleToUShortClamped(0.823529), Col.DoubleToUShortClamped(0.705882), Col.DoubleToUShortClamped(0.54902)); public static C4us Teal => new C4us(Col.DoubleToUShortClamped(0), Col.DoubleToUShortClamped(0.501961), Col.DoubleToUShortClamped(0.501961)); public static C4us Thistle => new C4us(Col.DoubleToUShortClamped(0.847059), Col.DoubleToUShortClamped(0.74902), Col.DoubleToUShortClamped(0.847059)); public static C4us Tomato => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0.388235), Col.DoubleToUShortClamped(0.278431)); public static C4us Turquoise => new C4us(Col.DoubleToUShortClamped(0.25098), Col.DoubleToUShortClamped(0.878431), Col.DoubleToUShortClamped(0.815686)); public static C4us Violet => new C4us(Col.DoubleToUShortClamped(0.933333), Col.DoubleToUShortClamped(0.509804), Col.DoubleToUShortClamped(0.933333)); public static C4us Wheat => new C4us(Col.DoubleToUShortClamped(0.960784), Col.DoubleToUShortClamped(0.870588), Col.DoubleToUShortClamped(0.701961)); public static C4us White => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1)); public static C4us WhiteSmoke => new C4us(Col.DoubleToUShortClamped(0.960784), Col.DoubleToUShortClamped(0.960784), Col.DoubleToUShortClamped(0.960784)); public static C4us Yellow => new C4us(Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(1), Col.DoubleToUShortClamped(0)); public static C4us YellowGreen => new C4us(Col.DoubleToUShortClamped(0.603922), Col.DoubleToUShortClamped(0.803922), Col.DoubleToUShortClamped(0.196078)); public static C4us DarkYellow => Olive; public static C4us VRVisGreen => new C4us(Col.DoubleToUShortClamped(0.698), Col.DoubleToUShortClamped(0.851), Col.DoubleToUShortClamped(0.008)); public static C4us Gray10 => new C4us(Col.DoubleToUShortClamped(0.1)); public static C4us Gray20 => new C4us(Col.DoubleToUShortClamped(0.2)); public static C4us Gray30 => new C4us(Col.DoubleToUShortClamped(0.3)); public static C4us Gray40 => new C4us(Col.DoubleToUShortClamped(0.4)); public static C4us Gray50 => new C4us(Col.DoubleToUShortClamped(0.5)); public static C4us Gray60 => new C4us(Col.DoubleToUShortClamped(0.6)); public static C4us Gray70 => new C4us(Col.DoubleToUShortClamped(0.7)); public static C4us Gray80 => new C4us(Col.DoubleToUShortClamped(0.8)); public static C4us Gray90 => new C4us(Col.DoubleToUShortClamped(0.9)); #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(C4us a, C4us b) { return a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(C4us a, C4us b) { return a.R != b.R || a.G != b.G || a.B != b.B || a.A != b.A; } #endregion #region Color Arithmetic [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator *(C4us col, float scalar) { return new C4us( Col.FloatToUShortClamped(Col.UShortToFloat(col.R) * scalar), Col.FloatToUShortClamped(Col.UShortToFloat(col.G) * scalar), Col.FloatToUShortClamped(Col.UShortToFloat(col.B) * scalar), Col.FloatToUShortClamped(Col.UShortToFloat(col.A) * scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator *(float scalar, C4us col) => col * scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator /(C4us col, float scalar) => col * (1 / scalar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator /(float scalar, C4us col) { return new C4us( Col.FloatToUShortClamped(scalar / Col.UShortToFloat(col.R)), Col.FloatToUShortClamped(scalar / Col.UShortToFloat(col.G)), Col.FloatToUShortClamped(scalar / Col.UShortToFloat(col.B)), Col.FloatToUShortClamped(scalar / Col.UShortToFloat(col.A))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator *(C4us col, double scalar) { return new C4us( Col.DoubleToUShortClamped(Col.UShortToDouble(col.R) * scalar), Col.DoubleToUShortClamped(Col.UShortToDouble(col.G) * scalar), Col.DoubleToUShortClamped(Col.UShortToDouble(col.B) * scalar), Col.DoubleToUShortClamped(Col.UShortToDouble(col.A) * scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator *(double scalar, C4us col) => col * scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator /(C4us col, double scalar) => col * (1 / scalar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator /(double scalar, C4us col) { return new C4us( Col.DoubleToUShortClamped(scalar / Col.UShortToDouble(col.R)), Col.DoubleToUShortClamped(scalar / Col.UShortToDouble(col.G)), Col.DoubleToUShortClamped(scalar / Col.UShortToDouble(col.B)), Col.DoubleToUShortClamped(scalar / Col.UShortToDouble(col.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator +(C4us c0, C4b c1) { return new C4us( (ushort)(c0.R + Col.ByteToUShort(c1.R)), (ushort)(c0.G + Col.ByteToUShort(c1.G)), (ushort)(c0.B + Col.ByteToUShort(c1.B)), (ushort)(c0.A + Col.ByteToUShort(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator -(C4us c0, C4b c1) { return new C4us( (ushort)(c0.R - Col.ByteToUShort(c1.R)), (ushort)(c0.G - Col.ByteToUShort(c1.G)), (ushort)(c0.B - Col.ByteToUShort(c1.B)), (ushort)(c0.A - Col.ByteToUShort(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator +(C4us c0, C4ui c1) { return new C4us( (ushort)(c0.R + Col.UIntToUShort(c1.R)), (ushort)(c0.G + Col.UIntToUShort(c1.G)), (ushort)(c0.B + Col.UIntToUShort(c1.B)), (ushort)(c0.A + Col.UIntToUShort(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator -(C4us c0, C4ui c1) { return new C4us( (ushort)(c0.R - Col.UIntToUShort(c1.R)), (ushort)(c0.G - Col.UIntToUShort(c1.G)), (ushort)(c0.B - Col.UIntToUShort(c1.B)), (ushort)(c0.A - Col.UIntToUShort(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator +(C4us c0, C4f c1) { return new C4us( (ushort)(c0.R + Col.FloatToUShort(c1.R)), (ushort)(c0.G + Col.FloatToUShort(c1.G)), (ushort)(c0.B + Col.FloatToUShort(c1.B)), (ushort)(c0.A + Col.FloatToUShort(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator -(C4us c0, C4f c1) { return new C4us( (ushort)(c0.R - Col.FloatToUShort(c1.R)), (ushort)(c0.G - Col.FloatToUShort(c1.G)), (ushort)(c0.B - Col.FloatToUShort(c1.B)), (ushort)(c0.A - Col.FloatToUShort(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator +(C4us c0, C4d c1) { return new C4us( (ushort)(c0.R + Col.DoubleToUShort(c1.R)), (ushort)(c0.G + Col.DoubleToUShort(c1.G)), (ushort)(c0.B + Col.DoubleToUShort(c1.B)), (ushort)(c0.A + Col.DoubleToUShort(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator -(C4us c0, C4d c1) { return new C4us( (ushort)(c0.R - Col.DoubleToUShort(c1.R)), (ushort)(c0.G - Col.DoubleToUShort(c1.G)), (ushort)(c0.B - Col.DoubleToUShort(c1.B)), (ushort)(c0.A - Col.DoubleToUShort(c1.A))); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator *(C4us col, ushort scalar) { return new C4us((ushort)(col.R * scalar), (ushort)(col.G * scalar), (ushort)(col.B * scalar), (ushort)(col.A * scalar)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator *(ushort scalar, C4us col) { return new C4us((ushort)(scalar * col.R), (ushort)(scalar * col.G), (ushort)(scalar * col.B), (ushort)(scalar * col.A)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator /(C4us col, ushort scalar) { return new C4us((ushort)(col.R / scalar), (ushort)(col.G / scalar), (ushort)(col.B / scalar), (ushort)(col.A / scalar)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator /(ushort scalar, C4us col) { return new C4us((ushort)(scalar / col.R), (ushort)(scalar / col.G), (ushort)(scalar / col.B), (ushort)(scalar / col.A)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator *(C4us c0, C4us c1) { return new C4us((ushort)(c0.R * c1.R), (ushort)(c0.G * c1.G), (ushort)(c0.B * c1.B), (ushort)(c0.A * c1.A)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator /(C4us c0, C4us c1) { return new C4us((ushort)(c0.R / c1.R), (ushort)(c0.G / c1.G), (ushort)(c0.B / c1.B), (ushort)(c0.A / c1.A)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator +(C4us c0, C4us c1) { return new C4us( (65535 - c0.R > c1.R) ? c0.R + c1.R : 65535, (65535 - c0.G > c1.G) ? c0.G + c1.G : 65535, (65535 - c0.B > c1.B) ? c0.B + c1.B : 65535, (65535 - c0.A > c1.A) ? c0.A + c1.A : 65535 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator +(C4us col, ushort scalar) { return new C4us( (65535 - col.R > scalar) ? col.R + scalar : 65535, (65535 - col.G > scalar) ? col.G + scalar : 65535, (65535 - col.B > scalar) ? col.B + scalar : 65535, (65535 - col.A > scalar) ? col.A + scalar : 65535 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator +(ushort scalar, C4us col) => col + scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator -(C4us c0, C4us c1) { return new C4us( (c0.R > c1.R) ? c0.R - c1.R : 0, (c0.G > c1.G) ? c0.G - c1.G : 0, (c0.B > c1.B) ? c0.B - c1.B : 0, (c0.A > c1.A) ? c0.A - c1.A : 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator -(C4us col, ushort scalar) { return new C4us( (col.R > scalar) ? col.R - scalar : 0, (col.G > scalar) ? col.G - scalar : 0, (col.B > scalar) ? col.B - scalar : 0, (col.A > scalar) ? col.A - scalar : 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us operator -(ushort scalar, C4us col) { return new C4us( (scalar > col.R) ? scalar - col.R : 0, (scalar > col.G) ? scalar - col.G : 0, (scalar > col.B) ? scalar - col.B : 0, (scalar > col.A) ? scalar - col.A : 0 ); } /// /// Clamps the color channels to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clamp(ushort min, ushort max) { R = R.Clamp(min, max); G = G.Clamp(min, max); B = B.Clamp(min, max); } /// /// Returns a copy with the color channels clamped to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us Clamped(ushort min, ushort max) { return new C4us(R.Clamp(min, max), G.Clamp(min, max), B.Clamp(min, max), A); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |R| + |G| + |B|. The alpha channel is ignored. /// public readonly int Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return R + G + B; } } /// /// Returns the Euclidean (or 2-) norm of the color. This is calculated /// as sqrt(R^2 + G^2 + B^2). The alpha channel is ignored. /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(R * R + G * G + B * B); } } /// /// Returns the infinite (or maximum) norm of the color. This is /// calculated as max(|R|, |G|, |B|). The alpha channel is ignored. /// public readonly ushort NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(R, G, B); } } /// /// Returns the minimum norm of the color. This is calculated as /// min(|R|, |G|, |B|). The alpha channel is ignored. /// public readonly ushort NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(R, G, B); } } #endregion #region Overrides public override readonly bool Equals(object other) => (other is C4us o) ? Equals(o) : false; public override readonly int GetHashCode() { return HashCode.GetCombined(R, G, B, A); } public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + R.ToString(null, CultureInfo.InvariantCulture) + ", " + G.ToString(null, CultureInfo.InvariantCulture) + ", " + B.ToString(null, CultureInfo.InvariantCulture) + ", " + A.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref C4us color, int i, ushort value) => { switch (i) { case 0: color.R = value; return; case 1: color.G = value; return; case 2: color.B = value; return; case 3: color.A = value; return; default: throw new IndexOutOfRangeException(); } }; [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us LinearInterp(float t, C4us a, C4us b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us LinearInterp(V4f t, C4us a, C4us b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us LinearInterp(double t, C4us a, C4us b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us LinearInterp(V4d t, C4us a, C4us b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us DivideByInt(C4us c, int x) => c / x; #endregion #region Parsing /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C4us.Zero otherwise. /// True on success, false otherwise. public static bool TryParse(Text t, out C4us result) { if (Col.TryParseHex(t, out C4b tmp)) { result = tmp.ToC4us(); return true; } else { bool success = true; ushort[] values = new ushort[4] { 65535, 65535, 65535, 65535 }; ushort parse(Text t) { if (!ushort.TryParse(t.ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out ushort value)) success = false; return value; }; var count = t.NestedBracketSplitCount2(1); if (count == 3 || count == 4) t.NestedBracketSplit(1, parse, () => values); else success = false; result = success ? new C4us(values) : Zero; return success; } } /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C4us.Zero otherwise. /// True on success, false otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParse(string s, out C4us result) => TryParse(new Text(s), out result); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C4us color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us Parse(string s) => Parse(new Text(s)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us Parse(Text t, int bracketLevel = 1) => t.NestedBracketSplit(bracketLevel, Text.Parse, C4us.Setter); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C4us color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us Parse(Text t) => TryParse(t, out C4us result) ? result : throw new FormatException($"{t} is not a valid C4us color."); #endregion #region IFormattable Members public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + R.ToString(format, fp) + between + G.ToString(format, fp) + between + B.ToString(format, fp) + between + A.ToString(format, fp) + end; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(C4us other) { return R.Equals(other.R) && G.Equals(other.G) && B.Equals(other.B) && A.Equals(other.A); } #endregion #region IRGB Members double IRGB.Red { readonly get { return Col.UShortToDouble(R); } set { R = Col.DoubleToUShortClamped(value); } } double IRGB.Green { readonly get { return Col.UShortToDouble(G); } set { G = Col.DoubleToUShortClamped(value); } } double IRGB.Blue { readonly get { return Col.UShortToDouble(B); } set { B = Col.DoubleToUShortClamped(value); } } #endregion #region IOpacity Members [XmlIgnore] public double Opacity { readonly get { return Col.UShortToDouble(A); } set { A = Col.DoubleToUShortClamped(value); } } #endregion } public static partial class Fun { #region Interpolation /// /// Returns the linearly interpolated color between a and b. /// public static C4us Lerp(this float t, C4us a, C4us b) => new C4us(Lerp(t, a.R, b.R), Lerp(t, a.G, b.G), Lerp(t, a.B, b.B), Lerp(t, a.A, b.A)); /// /// Returns the linearly interpolated color between a and b. /// public static C4us Lerp(this V4f t, C4us a, C4us b) => new C4us(Lerp(t.X, a.R, b.R), Lerp(t.Y, a.G, b.G), Lerp(t.Z, a.B, b.B), Lerp(t.W, a.A, b.A)); /// /// Returns the linearly interpolated color between a and b. /// public static C4us Lerp(this double t, C4us a, C4us b) => new C4us(Lerp(t, a.R, b.R), Lerp(t, a.G, b.G), Lerp(t, a.B, b.B), Lerp(t, a.A, b.A)); /// /// Returns the linearly interpolated color between a and b. /// public static C4us Lerp(this V4d t, C4us a, C4us b) => new C4us(Lerp(t.X, a.R, b.R), Lerp(t.Y, a.G, b.G), Lerp(t.Z, a.B, b.B), Lerp(t.W, a.A, b.A)); #endregion #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this C4us a, C4us b, ushort tolerance) { return ApproximateEquals(a.R, b.R, tolerance) && ApproximateEquals(a.G, b.G, tolerance) && ApproximateEquals(a.B, b.B, tolerance) && ApproximateEquals(a.A, b.A, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this C4us c, ushort epsilon) => Col.AllTiny(c, epsilon); #endregion } public static partial class Col { #region ToHexString /// /// Returns the hexadecimal representation with format RRGGBBAA. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToHexString(this C4us c) => c.ToC4b().ToHexString(); #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C4us a, C4us b) { return (a.R < b.R && a.G < b.G && a.B < b.B && a.A < b.A); } /// /// Returns whether ALL elements of col are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C4us col, ushort s) { return (col.R < s && col.G < s && col.B < s && col.A < s); } /// /// Returns whether a is Smaller ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(ushort s, C4us col) { return (s < col.R && s < col.G && s < col.B && s < col.A); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C4us a, C4us b) { return (a.R < b.R || a.G < b.G || a.B < b.B || a.A < b.A); } /// /// Returns whether AT LEAST ONE element of col is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C4us col, ushort s) { return (col.R < s || col.G < s || col.B < s || col.A < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(ushort s, C4us col) { return (s < col.R || s < col.G || s < col.B || s < col.A); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C4us a, C4us b) { return (a.R > b.R && a.G > b.G && a.B > b.B && a.A > b.A); } /// /// Returns whether ALL elements of col are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C4us col, ushort s) { return (col.R > s && col.G > s && col.B > s && col.A > s); } /// /// Returns whether a is Greater ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(ushort s, C4us col) { return (s > col.R && s > col.G && s > col.B && s > col.A); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C4us a, C4us b) { return (a.R > b.R || a.G > b.G || a.B > b.B || a.A > b.A); } /// /// Returns whether AT LEAST ONE element of col is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C4us col, ushort s) { return (col.R > s || col.G > s || col.B > s || col.A > s); } /// /// Returns whether a is Greater AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(ushort s, C4us col) { return (s > col.R || s > col.G || s > col.B || s > col.A); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C4us a, C4us b) { return (a.R <= b.R && a.G <= b.G && a.B <= b.B && a.A <= b.A); } /// /// Returns whether ALL elements of col are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C4us col, ushort s) { return (col.R <= s && col.G <= s && col.B <= s && col.A <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(ushort s, C4us col) { return (s <= col.R && s <= col.G && s <= col.B && s <= col.A); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C4us a, C4us b) { return (a.R <= b.R || a.G <= b.G || a.B <= b.B || a.A <= b.A); } /// /// Returns whether AT LEAST ONE element of col is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C4us col, ushort s) { return (col.R <= s || col.G <= s || col.B <= s || col.A <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(ushort s, C4us col) { return (s <= col.R || s <= col.G || s <= col.B || s <= col.A); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C4us a, C4us b) { return (a.R >= b.R && a.G >= b.G && a.B >= b.B && a.A >= b.A); } /// /// Returns whether ALL elements of col are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C4us col, ushort s) { return (col.R >= s && col.G >= s && col.B >= s && col.A >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(ushort s, C4us col) { return (s >= col.R && s >= col.G && s >= col.B && s >= col.A); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C4us a, C4us b) { return (a.R >= b.R || a.G >= b.G || a.B >= b.B || a.A >= b.A); } /// /// Returns whether AT LEAST ONE element of col is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C4us col, ushort s) { return (col.R >= s || col.G >= s || col.B >= s || col.A >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(ushort s, C4us col) { return (s >= col.R || s >= col.G || s >= col.B || s >= col.A); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C4us a, C4us b) { return (a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A); } /// /// Returns whether ALL elements of col are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C4us col, ushort s) { return (col.R == s && col.G == s && col.B == s && col.A == s); } /// /// Returns whether a is Equal ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(ushort s, C4us col) { return (s == col.R && s == col.G && s == col.B && s == col.A); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C4us a, C4us b) { return (a.R == b.R || a.G == b.G || a.B == b.B || a.A == b.A); } /// /// Returns whether AT LEAST ONE element of col is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C4us col, ushort s) { return (col.R == s || col.G == s || col.B == s || col.A == s); } /// /// Returns whether a is Equal AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(ushort s, C4us col) { return (s == col.R || s == col.G || s == col.B || s == col.A); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C4us a, C4us b) { return (a.R != b.R && a.G != b.G && a.B != b.B && a.A != b.A); } /// /// Returns whether ALL elements of col are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C4us col, ushort s) { return (col.R != s && col.G != s && col.B != s && col.A != s); } /// /// Returns whether a is Different ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(ushort s, C4us col) { return (s != col.R && s != col.G && s != col.B && s != col.A); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C4us a, C4us b) { return (a.R != b.R || a.G != b.G || a.B != b.B || a.A != b.A); } /// /// Returns whether AT LEAST ONE element of col is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C4us col, ushort s) { return (col.R != s || col.G != s || col.B != s || col.A != s); } /// /// Returns whether a is Different AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(ushort s, C4us col) { return (s != col.R || s != col.G || s != col.B || s != col.A); } #endregion #region Linear Combination /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us LinCom( C4us p0, C4us p1, C4us p2, C4us p3, ref Tup4 w) { return new C4us( Col.UShortInFloatToUShortClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3), Col.UShortInFloatToUShortClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3), Col.UShortInFloatToUShortClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f LinComRawF( C4us p0, C4us p1, C4us p2, C4us p3, ref Tup4 w) { return new C4f( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us LinCom( C4us p0, C4us p1, C4us p2, C4us p3, ref Tup4 w) { return new C4us( Col.UShortInDoubleToUShortClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3), Col.UShortInDoubleToUShortClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3), Col.UShortInDoubleToUShortClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d LinComRawD( C4us p0, C4us p1, C4us p2, C4us p3, ref Tup4 w) { return new C4d( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us LinCom( C4us p0, C4us p1, C4us p2, C4us p3, C4us p4, C4us p5, ref Tup6 w) { return new C4us( Col.UShortInFloatToUShortClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5), Col.UShortInFloatToUShortClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5), Col.UShortInFloatToUShortClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f LinComRawF( C4us p0, C4us p1, C4us p2, C4us p3, C4us p4, C4us p5, ref Tup6 w) { return new C4f( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4us LinCom( C4us p0, C4us p1, C4us p2, C4us p3, C4us p4, C4us p5, ref Tup6 w) { return new C4us( Col.UShortInDoubleToUShortClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5), Col.UShortInDoubleToUShortClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5), Col.UShortInDoubleToUShortClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d LinComRawD( C4us p0, C4us p1, C4us p2, C4us p3, C4us p4, C4us p5, ref Tup6 w) { return new C4d( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5); } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this C4us c, ushort epsilon) => c.R.IsTiny(epsilon) || c.G.IsTiny(epsilon) || c.B.IsTiny(epsilon) || c.A.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this C4us c, ushort epsilon) => c.R.IsTiny(epsilon) && c.G.IsTiny(epsilon) && c.B.IsTiny(epsilon) && c.A.IsTiny(epsilon); #endregion } #endregion #region C4ui /// /// Represents an RGBA color with each channel stored as a value within [0, 2^32 - 1]. /// [Serializable] public partial struct C4ui : IFormattable, IEquatable, IRGB, IOpacity { #region Constructors /// /// Creates a color from the given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(uint r, uint g, uint b, uint a) { R = r; G = g; B = b; A = a; } /// /// Creates a color from the given values. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(int r, int g, int b, int a) { R = (uint)r; G = (uint)g; B = (uint)b; A = (uint)a; } /// /// Creates a color from the given values. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(long r, long g, long b, long a) { R = (uint)r; G = (uint)g; B = (uint)b; A = (uint)a; } /// /// Creates a color from the given values. /// The values are mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(float r, float g, float b, float a) { R = Col.FloatToUIntClamped(r); G = Col.FloatToUIntClamped(g); B = Col.FloatToUIntClamped(b); A = Col.FloatToUIntClamped(a); } /// /// Creates a color from the given values. /// The values are mapped and clamped from [0, 1] to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(double r, double g, double b, double a) { R = Col.DoubleToUIntClamped(r); G = Col.DoubleToUIntClamped(g); B = Col.DoubleToUIntClamped(b); A = Col.DoubleToUIntClamped(a); } /// /// Creates a color from the given RGB values. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(uint r, uint g, uint b) { R = r; G = g; B = b; A = UInt32.MaxValue; } /// /// Creates a color from the given RGB values. /// The values are not mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(int r, int g, int b) { R = (uint)r; G = (uint)g; B = (uint)b; A = UInt32.MaxValue; } /// /// Creates a color from the given RGB values. /// The values are not mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(long r, long g, long b) { R = (uint)r; G = (uint)g; B = (uint)b; A = UInt32.MaxValue; } /// /// Creates a color from the given RGB values. /// The values are mapped and clamped from [0, 1] to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(float r, float g, float b) { R = Col.FloatToUIntClamped(r); G = Col.FloatToUIntClamped(g); B = Col.FloatToUIntClamped(b); A = UInt32.MaxValue; } /// /// Creates a color from the given RGB values. /// The values are mapped and clamped from [0, 1] to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(double r, double g, double b) { R = Col.DoubleToUIntClamped(r); G = Col.DoubleToUIntClamped(g); B = Col.DoubleToUIntClamped(b); A = UInt32.MaxValue; } /// /// Creates a color from a single value. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(uint gray) { R = gray; G = gray; B = gray; A = UInt32.MaxValue; } /// /// Creates a color from a single value. /// The value is mapped and clamped from [0, 1] to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(float gray) { var value = Col.FloatToUIntClamped(gray); R = value; G = value; B = value; A = UInt32.MaxValue; } /// /// Creates a color from a single value. /// The value is mapped and clamped from [0, 1] to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(double gray) { var value = Col.DoubleToUIntClamped(gray); R = value; G = value; B = value; A = UInt32.MaxValue; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(C3b color) { R = Col.ByteToUInt(color.R); G = Col.ByteToUInt(color.G); B = Col.ByteToUInt(color.B); A = UInt32.MaxValue; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(C3b color, uint alpha) { R = Col.ByteToUInt(color.R); G = Col.ByteToUInt(color.G); B = Col.ByteToUInt(color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(C3us color) { R = Col.UShortToUInt(color.R); G = Col.UShortToUInt(color.G); B = Col.UShortToUInt(color.B); A = UInt32.MaxValue; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(C3us color, uint alpha) { R = Col.UShortToUInt(color.R); G = Col.UShortToUInt(color.G); B = Col.UShortToUInt(color.B); A = alpha; } /// /// Creates a color from the given color. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(C3ui color) { R = (color.R); G = (color.G); B = (color.B); A = UInt32.MaxValue; } /// /// Creates a color from the given color and an alpha value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(C3ui color, uint alpha) { R = (color.R); G = (color.G); B = (color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(C3f color) { R = Col.FloatToUIntClamped(color.R); G = Col.FloatToUIntClamped(color.G); B = Col.FloatToUIntClamped(color.B); A = UInt32.MaxValue; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(C3f color, uint alpha) { R = Col.FloatToUIntClamped(color.R); G = Col.FloatToUIntClamped(color.G); B = Col.FloatToUIntClamped(color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(C3d color) { R = Col.DoubleToUIntClamped(color.R); G = Col.DoubleToUIntClamped(color.G); B = Col.DoubleToUIntClamped(color.B); A = UInt32.MaxValue; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(C3d color, uint alpha) { R = Col.DoubleToUIntClamped(color.R); G = Col.DoubleToUIntClamped(color.G); B = Col.DoubleToUIntClamped(color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(C4b color) { R = Col.ByteToUInt(color.R); G = Col.ByteToUInt(color.G); B = Col.ByteToUInt(color.B); A = Col.ByteToUInt(color.A); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(C4us color) { R = Col.UShortToUInt(color.R); G = Col.UShortToUInt(color.G); B = Col.UShortToUInt(color.B); A = Col.UShortToUInt(color.A); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(C4ui color) { R = (color.R); G = (color.G); B = (color.B); A = (color.A); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(C4f color) { R = Col.FloatToUIntClamped(color.R); G = Col.FloatToUIntClamped(color.G); B = Col.FloatToUIntClamped(color.B); A = Col.FloatToUIntClamped(color.A); } /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(C4d color) { R = Col.DoubleToUIntClamped(color.R); G = Col.DoubleToUIntClamped(color.G); B = Col.DoubleToUIntClamped(color.B); A = Col.DoubleToUIntClamped(color.A); } /// /// Creates a color from the given vector. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(V3ui vec) { R = (vec.X); G = (vec.Y); B = (vec.Z); A = UInt32.MaxValue; } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(V3l vec) { R = (uint)(vec.X); G = (uint)(vec.Y); B = (uint)(vec.Z); A = UInt32.MaxValue; } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(V3f vec) { R = (uint)(vec.X); G = (uint)(vec.Y); B = (uint)(vec.Z); A = UInt32.MaxValue; } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(V3d vec) { R = (uint)(vec.X); G = (uint)(vec.Y); B = (uint)(vec.Z); A = UInt32.MaxValue; } /// /// Creates a color from the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(V4ui vec) { R = (vec.X); G = (vec.Y); B = (vec.Z); A = (vec.W); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(V4l vec) { R = (uint)(vec.X); G = (uint)(vec.Y); B = (uint)(vec.Z); A = (uint)(vec.W); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(V4f vec) { R = (uint)(vec.X); G = (uint)(vec.Y); B = (uint)(vec.Z); A = (uint)(vec.W); } /// /// Creates a color from the given vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(V4d vec) { R = (uint)(vec.X); G = (uint)(vec.Y); B = (uint)(vec.Z); A = (uint)(vec.W); } /// /// Creates a color from the given vector and an alpha value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(V3ui vec, uint alpha) { R = (vec.X); G = (vec.Y); B = (vec.Z); A = alpha; } /// /// Creates a color from the given vector and an alpha value. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(V3l vec, uint alpha) { R = (uint)(vec.X); G = (uint)(vec.Y); B = (uint)(vec.Z); A = alpha; } /// /// Creates a color from the given vector and an alpha value. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(V3f vec, uint alpha) { R = (uint)(vec.X); G = (uint)(vec.Y); B = (uint)(vec.Z); A = alpha; } /// /// Creates a color from the given vector and an alpha value. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(V3d vec, uint alpha) { R = (uint)(vec.X); G = (uint)(vec.Y); B = (uint)(vec.Z); A = alpha; } /// /// Creates a color from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(Func index_fun) { R = index_fun(0); G = index_fun(1); B = index_fun(2); A = index_fun(3); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(byte[] values) { R = Col.ByteToUInt(values[0]); G = Col.ByteToUInt(values[1]); B = Col.ByteToUInt(values[2]); A = Col.ByteToUInt(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(byte[] values, int start) { R = Col.ByteToUInt(values[start + 0]); G = Col.ByteToUInt(values[start + 1]); B = Col.ByteToUInt(values[start + 2]); A = Col.ByteToUInt(values[start + 3]); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(ushort[] values) { R = Col.UShortToUInt(values[0]); G = Col.UShortToUInt(values[1]); B = Col.UShortToUInt(values[2]); A = Col.UShortToUInt(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(ushort[] values, int start) { R = Col.UShortToUInt(values[start + 0]); G = Col.UShortToUInt(values[start + 1]); B = Col.UShortToUInt(values[start + 2]); A = Col.UShortToUInt(values[start + 3]); } /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(uint[] values) { R = (values[0]); G = (values[1]); B = (values[2]); A = (values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(uint[] values, int start) { R = (values[start + 0]); G = (values[start + 1]); B = (values[start + 2]); A = (values[start + 3]); } /// /// Creates a new color from the given array. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(float[] values) { R = Col.FloatToUIntClamped(values[0]); G = Col.FloatToUIntClamped(values[1]); B = Col.FloatToUIntClamped(values[2]); A = Col.FloatToUIntClamped(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(float[] values, int start) { R = Col.FloatToUIntClamped(values[start + 0]); G = Col.FloatToUIntClamped(values[start + 1]); B = Col.FloatToUIntClamped(values[start + 2]); A = Col.FloatToUIntClamped(values[start + 3]); } /// /// Creates a new color from the given array. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(double[] values) { R = Col.DoubleToUIntClamped(values[0]); G = Col.DoubleToUIntClamped(values[1]); B = Col.DoubleToUIntClamped(values[2]); A = Col.DoubleToUIntClamped(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4ui(double[] values, int start) { R = Col.DoubleToUIntClamped(values[start + 0]); G = Col.DoubleToUIntClamped(values[start + 1]); B = Col.DoubleToUIntClamped(values[start + 2]); A = Col.DoubleToUIntClamped(values[start + 3]); } #endregion #region Properities public readonly C3ui RGB => (C3ui)this; #endregion #region Conversions /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(C3b color) => new C4ui(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromC3b(C3b c) => new C4ui(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(C3us color) => new C4ui(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromC3us(C3us c) => new C4ui(c); /// /// Converts the given color to a color. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(C3ui color) => new C4ui(color); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Creates a color from the given color. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromC3ui(C3ui c) => new C4ui(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(C3f color) => new C4ui(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f ToC3f() => (C3f)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromC3f(C3f c) => new C4ui(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(C3d color) => new C4ui(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d ToC3d() => (C3d)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromC3d(C3d c) => new C4ui(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(C4b color) => new C4ui(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromC4b(C4b c) => new C4ui(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(C4us color) => new C4ui(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromC4us(C4us c) => new C4ui(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(C4f color) => new C4ui(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f ToC4f() => (C4f)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromC4f(C4f c) => new C4ui(c); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(C4d color) => new C4ui(color); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d ToC4d() => (C4d)this; /// /// Creates a color from the given color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromC4d(C4d c) => new C4ui(c); /// /// Converts the given vector to a color. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(V3ui v) => new C4ui(v); /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; /// /// Creates a color from a vector. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromV3ui(V3ui c) => new C4ui(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(V3l v) => new C4ui(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromV3l(V3l c) => new C4ui(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(V3f v) => new C4ui(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromV3f(V3f c) => new C4ui(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(V3d v) => new C4ui(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromV3d(V3d c) => new C4ui(c); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(V4ui v) => new C4ui(v); /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; /// /// Creates a color from a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromV4ui(V4ui c) => new C4ui(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(V4l v) => new C4ui(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromV4l(V4l c) => new C4ui(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(V4f v) => new C4ui(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromV4f(V4f c) => new C4ui(c); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(V4d v) => new C4ui(v); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; /// /// Creates a color from a vector. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui FromV4d(V4d c) => new C4ui(c); /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(byte[] values) => new C4ui(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator byte[](C4ui color) => new byte[] { Col.UIntToByte(color.R), Col.UIntToByte(color.G), Col.UIntToByte(color.B), Col.UIntToByte(color.A) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(ushort[] values) => new C4ui(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ushort[](C4ui color) => new ushort[] { Col.UIntToUShort(color.R), Col.UIntToUShort(color.G), Col.UIntToUShort(color.B), Col.UIntToUShort(color.A) }; /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(uint[] values) => new C4ui(values); /// /// Creates a new array from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](C4ui color) => new uint[] { (color.R), (color.G), (color.B), (color.A) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(float[] values) => new C4ui(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](C4ui color) => new float[] { Col.UIntToFloat(color.R), Col.UIntToFloat(color.G), Col.UIntToFloat(color.B), Col.UIntToFloat(color.A) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4ui(double[] values) => new C4ui(values); /// /// Creates a new array from the given color. /// The values are mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](C4ui color) => new double[] { Col.UIntToDouble(color.R), Col.UIntToDouble(color.G), Col.UIntToDouble(color.B), Col.UIntToDouble(color.A) }; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b Map(Func channel_fun) { return new C4b(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us Map(Func channel_fun) { return new C4us(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui Map(Func channel_fun) { return new C4ui(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f Map(Func channel_fun) { return new C4f(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d Map(Func channel_fun) { return new C4d(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(R); array[start + 1] = element_fun(G); array[start + 2] = element_fun(B); array[start + 3] = element_fun(A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(R, 0); array[start + 1] = element_index_fun(G, 1); array[start + 2] = element_index_fun(B, 2); array[start + 3] = element_index_fun(A, 3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly uint[] ToArray() => (uint[])this; #endregion #region Indexer /// /// Indexer in canonical order 0=R, 1=G, 2=B, 3=A (availability depending on color type). /// public unsafe uint this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (uint* ptr = &R) { ptr[i] = value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (uint* ptr = &R) { return ptr[i]; } } } #endregion #region Constants /// /// C4ui with all components zero. /// public static C4ui Zero => new C4ui(0, 0, 0, 0); // Web colors public static C4ui AliceBlue => new C4ui(Col.DoubleToUIntClamped(0.941176), Col.DoubleToUIntClamped(0.972549), Col.DoubleToUIntClamped(1)); public static C4ui AntiqueWhite => new C4ui(Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.921569), Col.DoubleToUIntClamped(0.843137)); public static C4ui Aqua => new C4ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1)); public static C4ui Aquamarine => new C4ui(Col.DoubleToUIntClamped(0.498039), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.831373)); public static C4ui Azure => new C4ui(Col.DoubleToUIntClamped(0.941176), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1)); public static C4ui Beige => new C4ui(Col.DoubleToUIntClamped(0.960784), Col.DoubleToUIntClamped(0.960784), Col.DoubleToUIntClamped(0.862745)); public static C4ui Bisque => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.894118), Col.DoubleToUIntClamped(0.768627)); public static C4ui Black => new C4ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0)); public static C4ui BlanchedAlmond => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.921569), Col.DoubleToUIntClamped(0.803922)); public static C4ui Blue => new C4ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(1)); public static C4ui BlueViolet => new C4ui(Col.DoubleToUIntClamped(0.541176), Col.DoubleToUIntClamped(0.168627), Col.DoubleToUIntClamped(0.886275)); public static C4ui Brown => new C4ui(Col.DoubleToUIntClamped(0.647059), Col.DoubleToUIntClamped(0.164706), Col.DoubleToUIntClamped(0.164706)); public static C4ui BurlyWood => new C4ui(Col.DoubleToUIntClamped(0.870588), Col.DoubleToUIntClamped(0.721569), Col.DoubleToUIntClamped(0.529412)); public static C4ui CadetBlue => new C4ui(Col.DoubleToUIntClamped(0.372549), Col.DoubleToUIntClamped(0.619608), Col.DoubleToUIntClamped(0.627451)); public static C4ui Chartreuse => new C4ui(Col.DoubleToUIntClamped(0.498039), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0)); public static C4ui Chocolate => new C4ui(Col.DoubleToUIntClamped(0.823529), Col.DoubleToUIntClamped(0.411765), Col.DoubleToUIntClamped(0.117647)); public static C4ui Coral => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.498039), Col.DoubleToUIntClamped(0.313725)); public static C4ui CornflowerBlue => new C4ui(Col.DoubleToUIntClamped(0.392157), Col.DoubleToUIntClamped(0.584314), Col.DoubleToUIntClamped(0.929412)); public static C4ui Cornsilk => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.972549), Col.DoubleToUIntClamped(0.862745)); public static C4ui Crimson => new C4ui(Col.DoubleToUIntClamped(0.862745), Col.DoubleToUIntClamped(0.078431), Col.DoubleToUIntClamped(0.235294)); public static C4ui Cyan => new C4ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1)); public static C4ui DarkBlue => new C4ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.545098)); public static C4ui DarkCyan => new C4ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.545098), Col.DoubleToUIntClamped(0.545098)); public static C4ui DarkGoldenRod => new C4ui(Col.DoubleToUIntClamped(0.721569), Col.DoubleToUIntClamped(0.52549), Col.DoubleToUIntClamped(0.043137)); public static C4ui DarkGray => new C4ui(Col.DoubleToUIntClamped(0.662745), Col.DoubleToUIntClamped(0.662745), Col.DoubleToUIntClamped(0.662745)); public static C4ui DarkGrey => new C4ui(Col.DoubleToUIntClamped(0.662745), Col.DoubleToUIntClamped(0.662745), Col.DoubleToUIntClamped(0.662745)); public static C4ui DarkGreen => new C4ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.392157), Col.DoubleToUIntClamped(0)); public static C4ui DarkKhaki => new C4ui(Col.DoubleToUIntClamped(0.741176), Col.DoubleToUIntClamped(0.717647), Col.DoubleToUIntClamped(0.419608)); public static C4ui DarkMagenta => new C4ui(Col.DoubleToUIntClamped(0.545098), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.545098)); public static C4ui DarkOliveGreen => new C4ui(Col.DoubleToUIntClamped(0.333333), Col.DoubleToUIntClamped(0.419608), Col.DoubleToUIntClamped(0.184314)); public static C4ui DarkOrange => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.54902), Col.DoubleToUIntClamped(0)); public static C4ui DarkOrchid => new C4ui(Col.DoubleToUIntClamped(0.6), Col.DoubleToUIntClamped(0.196078), Col.DoubleToUIntClamped(0.8)); public static C4ui DarkRed => new C4ui(Col.DoubleToUIntClamped(0.545098), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0)); public static C4ui DarkSalmon => new C4ui(Col.DoubleToUIntClamped(0.913725), Col.DoubleToUIntClamped(0.588235), Col.DoubleToUIntClamped(0.478431)); public static C4ui DarkSeaGreen => new C4ui(Col.DoubleToUIntClamped(0.560784), Col.DoubleToUIntClamped(0.737255), Col.DoubleToUIntClamped(0.560784)); public static C4ui DarkSlateBlue => new C4ui(Col.DoubleToUIntClamped(0.282353), Col.DoubleToUIntClamped(0.239216), Col.DoubleToUIntClamped(0.545098)); public static C4ui DarkSlateGray => new C4ui(Col.DoubleToUIntClamped(0.184314), Col.DoubleToUIntClamped(0.309804), Col.DoubleToUIntClamped(0.309804)); public static C4ui DarkSlateGrey => new C4ui(Col.DoubleToUIntClamped(0.184314), Col.DoubleToUIntClamped(0.309804), Col.DoubleToUIntClamped(0.309804)); public static C4ui DarkTurquoise => new C4ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.807843), Col.DoubleToUIntClamped(0.819608)); public static C4ui DarkViolet => new C4ui(Col.DoubleToUIntClamped(0.580392), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.827451)); public static C4ui DeepPink => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.078431), Col.DoubleToUIntClamped(0.576471)); public static C4ui DeepSkyBlue => new C4ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.74902), Col.DoubleToUIntClamped(1)); public static C4ui DimGray => new C4ui(Col.DoubleToUIntClamped(0.411765), Col.DoubleToUIntClamped(0.411765), Col.DoubleToUIntClamped(0.411765)); public static C4ui DimGrey => new C4ui(Col.DoubleToUIntClamped(0.411765), Col.DoubleToUIntClamped(0.411765), Col.DoubleToUIntClamped(0.411765)); public static C4ui DodgerBlue => new C4ui(Col.DoubleToUIntClamped(0.117647), Col.DoubleToUIntClamped(0.564706), Col.DoubleToUIntClamped(1)); public static C4ui FireBrick => new C4ui(Col.DoubleToUIntClamped(0.698039), Col.DoubleToUIntClamped(0.133333), Col.DoubleToUIntClamped(0.133333)); public static C4ui FloralWhite => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.941176)); public static C4ui ForestGreen => new C4ui(Col.DoubleToUIntClamped(0.133333), Col.DoubleToUIntClamped(0.545098), Col.DoubleToUIntClamped(0.133333)); public static C4ui Fuchsia => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(1)); public static C4ui Gainsboro => new C4ui(Col.DoubleToUIntClamped(0.862745), Col.DoubleToUIntClamped(0.862745), Col.DoubleToUIntClamped(0.862745)); public static C4ui GhostWhite => new C4ui(Col.DoubleToUIntClamped(0.972549), Col.DoubleToUIntClamped(0.972549), Col.DoubleToUIntClamped(1)); public static C4ui Gold => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.843137), Col.DoubleToUIntClamped(0)); public static C4ui GoldenRod => new C4ui(Col.DoubleToUIntClamped(0.854902), Col.DoubleToUIntClamped(0.647059), Col.DoubleToUIntClamped(0.12549)); public static C4ui Gray => new C4ui(Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.501961)); public static C4ui Grey => new C4ui(Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.501961)); public static C4ui Green => new C4ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0)); public static C4ui GreenYellow => new C4ui(Col.DoubleToUIntClamped(0.678431), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.184314)); public static C4ui HoneyDew => new C4ui(Col.DoubleToUIntClamped(0.941176), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.941176)); public static C4ui HotPink => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.411765), Col.DoubleToUIntClamped(0.705882)); public static C4ui IndianRed => new C4ui(Col.DoubleToUIntClamped(0.803922), Col.DoubleToUIntClamped(0.360784), Col.DoubleToUIntClamped(0.360784)); public static C4ui Indigo => new C4ui(Col.DoubleToUIntClamped(0.294118), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.509804)); public static C4ui Ivory => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.941176)); public static C4ui Khaki => new C4ui(Col.DoubleToUIntClamped(0.941176), Col.DoubleToUIntClamped(0.901961), Col.DoubleToUIntClamped(0.54902)); public static C4ui Lavender => new C4ui(Col.DoubleToUIntClamped(0.901961), Col.DoubleToUIntClamped(0.901961), Col.DoubleToUIntClamped(0.980392)); public static C4ui LavenderBlush => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.941176), Col.DoubleToUIntClamped(0.960784)); public static C4ui LawnGreen => new C4ui(Col.DoubleToUIntClamped(0.486275), Col.DoubleToUIntClamped(0.988235), Col.DoubleToUIntClamped(0)); public static C4ui LemonChiffon => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.803922)); public static C4ui LightBlue => new C4ui(Col.DoubleToUIntClamped(0.678431), Col.DoubleToUIntClamped(0.847059), Col.DoubleToUIntClamped(0.901961)); public static C4ui LightCoral => new C4ui(Col.DoubleToUIntClamped(0.941176), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.501961)); public static C4ui LightCyan => new C4ui(Col.DoubleToUIntClamped(0.878431), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1)); public static C4ui LightGoldenRodYellow => new C4ui(Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.823529)); public static C4ui LightGray => new C4ui(Col.DoubleToUIntClamped(0.827451), Col.DoubleToUIntClamped(0.827451), Col.DoubleToUIntClamped(0.827451)); public static C4ui LightGrey => new C4ui(Col.DoubleToUIntClamped(0.827451), Col.DoubleToUIntClamped(0.827451), Col.DoubleToUIntClamped(0.827451)); public static C4ui LightGreen => new C4ui(Col.DoubleToUIntClamped(0.564706), Col.DoubleToUIntClamped(0.933333), Col.DoubleToUIntClamped(0.564706)); public static C4ui LightPink => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.713725), Col.DoubleToUIntClamped(0.756863)); public static C4ui LightSalmon => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.627451), Col.DoubleToUIntClamped(0.478431)); public static C4ui LightSeaGreen => new C4ui(Col.DoubleToUIntClamped(0.12549), Col.DoubleToUIntClamped(0.698039), Col.DoubleToUIntClamped(0.666667)); public static C4ui LightSkyBlue => new C4ui(Col.DoubleToUIntClamped(0.529412), Col.DoubleToUIntClamped(0.807843), Col.DoubleToUIntClamped(0.980392)); public static C4ui LightSlateGray => new C4ui(Col.DoubleToUIntClamped(0.466667), Col.DoubleToUIntClamped(0.533333), Col.DoubleToUIntClamped(0.6)); public static C4ui LightSlateGrey => new C4ui(Col.DoubleToUIntClamped(0.466667), Col.DoubleToUIntClamped(0.533333), Col.DoubleToUIntClamped(0.6)); public static C4ui LightSteelBlue => new C4ui(Col.DoubleToUIntClamped(0.690196), Col.DoubleToUIntClamped(0.768627), Col.DoubleToUIntClamped(0.870588)); public static C4ui LightYellow => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.878431)); public static C4ui Lime => new C4ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0)); public static C4ui LimeGreen => new C4ui(Col.DoubleToUIntClamped(0.196078), Col.DoubleToUIntClamped(0.803922), Col.DoubleToUIntClamped(0.196078)); public static C4ui Linen => new C4ui(Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.941176), Col.DoubleToUIntClamped(0.901961)); public static C4ui Magenta => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(1)); public static C4ui Maroon => new C4ui(Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0)); public static C4ui MediumAquaMarine => new C4ui(Col.DoubleToUIntClamped(0.4), Col.DoubleToUIntClamped(0.803922), Col.DoubleToUIntClamped(0.666667)); public static C4ui MediumBlue => new C4ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.803922)); public static C4ui MediumOrchid => new C4ui(Col.DoubleToUIntClamped(0.729412), Col.DoubleToUIntClamped(0.333333), Col.DoubleToUIntClamped(0.827451)); public static C4ui MediumPurple => new C4ui(Col.DoubleToUIntClamped(0.576471), Col.DoubleToUIntClamped(0.439216), Col.DoubleToUIntClamped(0.847059)); public static C4ui MediumSeaGreen => new C4ui(Col.DoubleToUIntClamped(0.235294), Col.DoubleToUIntClamped(0.701961), Col.DoubleToUIntClamped(0.443137)); public static C4ui MediumSlateBlue => new C4ui(Col.DoubleToUIntClamped(0.482353), Col.DoubleToUIntClamped(0.407843), Col.DoubleToUIntClamped(0.933333)); public static C4ui MediumSpringGreen => new C4ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.603922)); public static C4ui MediumTurquoise => new C4ui(Col.DoubleToUIntClamped(0.282353), Col.DoubleToUIntClamped(0.819608), Col.DoubleToUIntClamped(0.8)); public static C4ui MediumVioletRed => new C4ui(Col.DoubleToUIntClamped(0.780392), Col.DoubleToUIntClamped(0.082353), Col.DoubleToUIntClamped(0.521569)); public static C4ui MidnightBlue => new C4ui(Col.DoubleToUIntClamped(0.098039), Col.DoubleToUIntClamped(0.098039), Col.DoubleToUIntClamped(0.439216)); public static C4ui MintCream => new C4ui(Col.DoubleToUIntClamped(0.960784), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.980392)); public static C4ui MistyRose => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.894118), Col.DoubleToUIntClamped(0.882353)); public static C4ui Moccasin => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.894118), Col.DoubleToUIntClamped(0.709804)); public static C4ui NavajoWhite => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.870588), Col.DoubleToUIntClamped(0.678431)); public static C4ui Navy => new C4ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.501961)); public static C4ui OldLace => new C4ui(Col.DoubleToUIntClamped(0.992157), Col.DoubleToUIntClamped(0.960784), Col.DoubleToUIntClamped(0.901961)); public static C4ui Olive => new C4ui(Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0)); public static C4ui OliveDrab => new C4ui(Col.DoubleToUIntClamped(0.419608), Col.DoubleToUIntClamped(0.556863), Col.DoubleToUIntClamped(0.137255)); public static C4ui Orange => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.647059), Col.DoubleToUIntClamped(0)); public static C4ui OrangeRed => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.270588), Col.DoubleToUIntClamped(0)); public static C4ui Orchid => new C4ui(Col.DoubleToUIntClamped(0.854902), Col.DoubleToUIntClamped(0.439216), Col.DoubleToUIntClamped(0.839216)); public static C4ui PaleGoldenRod => new C4ui(Col.DoubleToUIntClamped(0.933333), Col.DoubleToUIntClamped(0.909804), Col.DoubleToUIntClamped(0.666667)); public static C4ui PaleGreen => new C4ui(Col.DoubleToUIntClamped(0.596078), Col.DoubleToUIntClamped(0.984314), Col.DoubleToUIntClamped(0.596078)); public static C4ui PaleTurquoise => new C4ui(Col.DoubleToUIntClamped(0.686275), Col.DoubleToUIntClamped(0.933333), Col.DoubleToUIntClamped(0.933333)); public static C4ui PaleVioletRed => new C4ui(Col.DoubleToUIntClamped(0.847059), Col.DoubleToUIntClamped(0.439216), Col.DoubleToUIntClamped(0.576471)); public static C4ui PapayaWhip => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.937255), Col.DoubleToUIntClamped(0.835294)); public static C4ui PeachPuff => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.854902), Col.DoubleToUIntClamped(0.72549)); public static C4ui Peru => new C4ui(Col.DoubleToUIntClamped(0.803922), Col.DoubleToUIntClamped(0.521569), Col.DoubleToUIntClamped(0.247059)); public static C4ui Pink => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.752941), Col.DoubleToUIntClamped(0.796078)); public static C4ui Plum => new C4ui(Col.DoubleToUIntClamped(0.866667), Col.DoubleToUIntClamped(0.627451), Col.DoubleToUIntClamped(0.866667)); public static C4ui PowderBlue => new C4ui(Col.DoubleToUIntClamped(0.690196), Col.DoubleToUIntClamped(0.878431), Col.DoubleToUIntClamped(0.901961)); public static C4ui Purple => new C4ui(Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.501961)); public static C4ui Red => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0)); public static C4ui RosyBrown => new C4ui(Col.DoubleToUIntClamped(0.737255), Col.DoubleToUIntClamped(0.560784), Col.DoubleToUIntClamped(0.560784)); public static C4ui RoyalBlue => new C4ui(Col.DoubleToUIntClamped(0.254902), Col.DoubleToUIntClamped(0.411765), Col.DoubleToUIntClamped(0.882353)); public static C4ui SaddleBrown => new C4ui(Col.DoubleToUIntClamped(0.545098), Col.DoubleToUIntClamped(0.270588), Col.DoubleToUIntClamped(0.07451)); public static C4ui Salmon => new C4ui(Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.447059)); public static C4ui SandyBrown => new C4ui(Col.DoubleToUIntClamped(0.956863), Col.DoubleToUIntClamped(0.643137), Col.DoubleToUIntClamped(0.376471)); public static C4ui SeaGreen => new C4ui(Col.DoubleToUIntClamped(0.180392), Col.DoubleToUIntClamped(0.545098), Col.DoubleToUIntClamped(0.341176)); public static C4ui SeaShell => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.960784), Col.DoubleToUIntClamped(0.933333)); public static C4ui Sienna => new C4ui(Col.DoubleToUIntClamped(0.627451), Col.DoubleToUIntClamped(0.321569), Col.DoubleToUIntClamped(0.176471)); public static C4ui Silver => new C4ui(Col.DoubleToUIntClamped(0.752941), Col.DoubleToUIntClamped(0.752941), Col.DoubleToUIntClamped(0.752941)); public static C4ui SkyBlue => new C4ui(Col.DoubleToUIntClamped(0.529412), Col.DoubleToUIntClamped(0.807843), Col.DoubleToUIntClamped(0.921569)); public static C4ui SlateBlue => new C4ui(Col.DoubleToUIntClamped(0.415686), Col.DoubleToUIntClamped(0.352941), Col.DoubleToUIntClamped(0.803922)); public static C4ui SlateGray => new C4ui(Col.DoubleToUIntClamped(0.439216), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.564706)); public static C4ui SlateGrey => new C4ui(Col.DoubleToUIntClamped(0.439216), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.564706)); public static C4ui Snow => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.980392), Col.DoubleToUIntClamped(0.980392)); public static C4ui SpringGreen => new C4ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.498039)); public static C4ui SteelBlue => new C4ui(Col.DoubleToUIntClamped(0.27451), Col.DoubleToUIntClamped(0.509804), Col.DoubleToUIntClamped(0.705882)); public static C4ui Tan => new C4ui(Col.DoubleToUIntClamped(0.823529), Col.DoubleToUIntClamped(0.705882), Col.DoubleToUIntClamped(0.54902)); public static C4ui Teal => new C4ui(Col.DoubleToUIntClamped(0), Col.DoubleToUIntClamped(0.501961), Col.DoubleToUIntClamped(0.501961)); public static C4ui Thistle => new C4ui(Col.DoubleToUIntClamped(0.847059), Col.DoubleToUIntClamped(0.74902), Col.DoubleToUIntClamped(0.847059)); public static C4ui Tomato => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0.388235), Col.DoubleToUIntClamped(0.278431)); public static C4ui Turquoise => new C4ui(Col.DoubleToUIntClamped(0.25098), Col.DoubleToUIntClamped(0.878431), Col.DoubleToUIntClamped(0.815686)); public static C4ui Violet => new C4ui(Col.DoubleToUIntClamped(0.933333), Col.DoubleToUIntClamped(0.509804), Col.DoubleToUIntClamped(0.933333)); public static C4ui Wheat => new C4ui(Col.DoubleToUIntClamped(0.960784), Col.DoubleToUIntClamped(0.870588), Col.DoubleToUIntClamped(0.701961)); public static C4ui White => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1)); public static C4ui WhiteSmoke => new C4ui(Col.DoubleToUIntClamped(0.960784), Col.DoubleToUIntClamped(0.960784), Col.DoubleToUIntClamped(0.960784)); public static C4ui Yellow => new C4ui(Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(1), Col.DoubleToUIntClamped(0)); public static C4ui YellowGreen => new C4ui(Col.DoubleToUIntClamped(0.603922), Col.DoubleToUIntClamped(0.803922), Col.DoubleToUIntClamped(0.196078)); public static C4ui DarkYellow => Olive; public static C4ui VRVisGreen => new C4ui(Col.DoubleToUIntClamped(0.698), Col.DoubleToUIntClamped(0.851), Col.DoubleToUIntClamped(0.008)); public static C4ui Gray10 => new C4ui(Col.DoubleToUIntClamped(0.1)); public static C4ui Gray20 => new C4ui(Col.DoubleToUIntClamped(0.2)); public static C4ui Gray30 => new C4ui(Col.DoubleToUIntClamped(0.3)); public static C4ui Gray40 => new C4ui(Col.DoubleToUIntClamped(0.4)); public static C4ui Gray50 => new C4ui(Col.DoubleToUIntClamped(0.5)); public static C4ui Gray60 => new C4ui(Col.DoubleToUIntClamped(0.6)); public static C4ui Gray70 => new C4ui(Col.DoubleToUIntClamped(0.7)); public static C4ui Gray80 => new C4ui(Col.DoubleToUIntClamped(0.8)); public static C4ui Gray90 => new C4ui(Col.DoubleToUIntClamped(0.9)); #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(C4ui a, C4ui b) { return a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(C4ui a, C4ui b) { return a.R != b.R || a.G != b.G || a.B != b.B || a.A != b.A; } #endregion #region Color Arithmetic [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator *(C4ui col, float scalar) { return new C4ui( Col.FloatToUIntClamped(Col.UIntToFloat(col.R) * scalar), Col.FloatToUIntClamped(Col.UIntToFloat(col.G) * scalar), Col.FloatToUIntClamped(Col.UIntToFloat(col.B) * scalar), Col.FloatToUIntClamped(Col.UIntToFloat(col.A) * scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator *(float scalar, C4ui col) => col * scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator /(C4ui col, float scalar) => col * (1 / scalar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator /(float scalar, C4ui col) { return new C4ui( Col.FloatToUIntClamped(scalar / Col.UIntToFloat(col.R)), Col.FloatToUIntClamped(scalar / Col.UIntToFloat(col.G)), Col.FloatToUIntClamped(scalar / Col.UIntToFloat(col.B)), Col.FloatToUIntClamped(scalar / Col.UIntToFloat(col.A))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator *(C4ui col, double scalar) { return new C4ui( Col.DoubleToUIntClamped(Col.UIntToDouble(col.R) * scalar), Col.DoubleToUIntClamped(Col.UIntToDouble(col.G) * scalar), Col.DoubleToUIntClamped(Col.UIntToDouble(col.B) * scalar), Col.DoubleToUIntClamped(Col.UIntToDouble(col.A) * scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator *(double scalar, C4ui col) => col * scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator /(C4ui col, double scalar) => col * (1 / scalar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator /(double scalar, C4ui col) { return new C4ui( Col.DoubleToUIntClamped(scalar / Col.UIntToDouble(col.R)), Col.DoubleToUIntClamped(scalar / Col.UIntToDouble(col.G)), Col.DoubleToUIntClamped(scalar / Col.UIntToDouble(col.B)), Col.DoubleToUIntClamped(scalar / Col.UIntToDouble(col.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator +(C4ui c0, C4b c1) { return new C4ui( (uint)(c0.R + Col.ByteToUInt(c1.R)), (uint)(c0.G + Col.ByteToUInt(c1.G)), (uint)(c0.B + Col.ByteToUInt(c1.B)), (uint)(c0.A + Col.ByteToUInt(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator -(C4ui c0, C4b c1) { return new C4ui( (uint)(c0.R - Col.ByteToUInt(c1.R)), (uint)(c0.G - Col.ByteToUInt(c1.G)), (uint)(c0.B - Col.ByteToUInt(c1.B)), (uint)(c0.A - Col.ByteToUInt(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator +(C4ui c0, C4us c1) { return new C4ui( (uint)(c0.R + Col.UShortToUInt(c1.R)), (uint)(c0.G + Col.UShortToUInt(c1.G)), (uint)(c0.B + Col.UShortToUInt(c1.B)), (uint)(c0.A + Col.UShortToUInt(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator -(C4ui c0, C4us c1) { return new C4ui( (uint)(c0.R - Col.UShortToUInt(c1.R)), (uint)(c0.G - Col.UShortToUInt(c1.G)), (uint)(c0.B - Col.UShortToUInt(c1.B)), (uint)(c0.A - Col.UShortToUInt(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator +(C4ui c0, C4f c1) { return new C4ui( (uint)(c0.R + Col.FloatToUInt(c1.R)), (uint)(c0.G + Col.FloatToUInt(c1.G)), (uint)(c0.B + Col.FloatToUInt(c1.B)), (uint)(c0.A + Col.FloatToUInt(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator -(C4ui c0, C4f c1) { return new C4ui( (uint)(c0.R - Col.FloatToUInt(c1.R)), (uint)(c0.G - Col.FloatToUInt(c1.G)), (uint)(c0.B - Col.FloatToUInt(c1.B)), (uint)(c0.A - Col.FloatToUInt(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator +(C4ui c0, C4d c1) { return new C4ui( (uint)(c0.R + Col.DoubleToUInt(c1.R)), (uint)(c0.G + Col.DoubleToUInt(c1.G)), (uint)(c0.B + Col.DoubleToUInt(c1.B)), (uint)(c0.A + Col.DoubleToUInt(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator -(C4ui c0, C4d c1) { return new C4ui( (uint)(c0.R - Col.DoubleToUInt(c1.R)), (uint)(c0.G - Col.DoubleToUInt(c1.G)), (uint)(c0.B - Col.DoubleToUInt(c1.B)), (uint)(c0.A - Col.DoubleToUInt(c1.A))); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator *(C4ui col, uint scalar) { return new C4ui((uint)(col.R * scalar), (uint)(col.G * scalar), (uint)(col.B * scalar), (uint)(col.A * scalar)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator *(uint scalar, C4ui col) { return new C4ui((uint)(scalar * col.R), (uint)(scalar * col.G), (uint)(scalar * col.B), (uint)(scalar * col.A)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator /(C4ui col, uint scalar) { return new C4ui((uint)(col.R / scalar), (uint)(col.G / scalar), (uint)(col.B / scalar), (uint)(col.A / scalar)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator /(uint scalar, C4ui col) { return new C4ui((uint)(scalar / col.R), (uint)(scalar / col.G), (uint)(scalar / col.B), (uint)(scalar / col.A)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator *(C4ui c0, C4ui c1) { return new C4ui((uint)(c0.R * c1.R), (uint)(c0.G * c1.G), (uint)(c0.B * c1.B), (uint)(c0.A * c1.A)); } [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator /(C4ui c0, C4ui c1) { return new C4ui((uint)(c0.R / c1.R), (uint)(c0.G / c1.G), (uint)(c0.B / c1.B), (uint)(c0.A / c1.A)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator +(C4ui c0, C4ui c1) { return new C4ui( (UInt32.MaxValue - c0.R > c1.R) ? c0.R + c1.R : UInt32.MaxValue, (UInt32.MaxValue - c0.G > c1.G) ? c0.G + c1.G : UInt32.MaxValue, (UInt32.MaxValue - c0.B > c1.B) ? c0.B + c1.B : UInt32.MaxValue, (UInt32.MaxValue - c0.A > c1.A) ? c0.A + c1.A : UInt32.MaxValue ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator +(C4ui col, uint scalar) { return new C4ui( (UInt32.MaxValue - col.R > scalar) ? col.R + scalar : UInt32.MaxValue, (UInt32.MaxValue - col.G > scalar) ? col.G + scalar : UInt32.MaxValue, (UInt32.MaxValue - col.B > scalar) ? col.B + scalar : UInt32.MaxValue, (UInt32.MaxValue - col.A > scalar) ? col.A + scalar : UInt32.MaxValue ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator +(uint scalar, C4ui col) => col + scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator -(C4ui c0, C4ui c1) { return new C4ui( (c0.R > c1.R) ? c0.R - c1.R : 0, (c0.G > c1.G) ? c0.G - c1.G : 0, (c0.B > c1.B) ? c0.B - c1.B : 0, (c0.A > c1.A) ? c0.A - c1.A : 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator -(C4ui col, uint scalar) { return new C4ui( (col.R > scalar) ? col.R - scalar : 0, (col.G > scalar) ? col.G - scalar : 0, (col.B > scalar) ? col.B - scalar : 0, (col.A > scalar) ? col.A - scalar : 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui operator -(uint scalar, C4ui col) { return new C4ui( (scalar > col.R) ? scalar - col.R : 0, (scalar > col.G) ? scalar - col.G : 0, (scalar > col.B) ? scalar - col.B : 0, (scalar > col.A) ? scalar - col.A : 0 ); } /// /// Clamps the color channels to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clamp(uint min, uint max) { R = R.Clamp(min, max); G = G.Clamp(min, max); B = B.Clamp(min, max); } /// /// Returns a copy with the color channels clamped to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui Clamped(uint min, uint max) { return new C4ui(R.Clamp(min, max), G.Clamp(min, max), B.Clamp(min, max), A); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |R| + |G| + |B|. The alpha channel is ignored. /// public readonly long Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return R + G + B; } } /// /// Returns the Euclidean (or 2-) norm of the color. This is calculated /// as sqrt(R^2 + G^2 + B^2). The alpha channel is ignored. /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(R * R + G * G + B * B); } } /// /// Returns the infinite (or maximum) norm of the color. This is /// calculated as max(|R|, |G|, |B|). The alpha channel is ignored. /// public readonly uint NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(R, G, B); } } /// /// Returns the minimum norm of the color. This is calculated as /// min(|R|, |G|, |B|). The alpha channel is ignored. /// public readonly uint NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(R, G, B); } } #endregion #region Overrides public override readonly bool Equals(object other) => (other is C4ui o) ? Equals(o) : false; public override readonly int GetHashCode() { return HashCode.GetCombined(R, G, B, A); } public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + R.ToString(null, CultureInfo.InvariantCulture) + ", " + G.ToString(null, CultureInfo.InvariantCulture) + ", " + B.ToString(null, CultureInfo.InvariantCulture) + ", " + A.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref C4ui color, int i, uint value) => { switch (i) { case 0: color.R = value; return; case 1: color.G = value; return; case 2: color.B = value; return; case 3: color.A = value; return; default: throw new IndexOutOfRangeException(); } }; [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui LinearInterp(float t, C4ui a, C4ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui LinearInterp(V4f t, C4ui a, C4ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui LinearInterp(double t, C4ui a, C4ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui LinearInterp(V4d t, C4ui a, C4ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui DivideByInt(C4ui c, int x) => c / x; #endregion #region Parsing /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C4ui.Zero otherwise. /// True on success, false otherwise. public static bool TryParse(Text t, out C4ui result) { if (Col.TryParseHex(t, out C4b tmp)) { result = tmp.ToC4ui(); return true; } else { bool success = true; uint[] values = new uint[4] { UInt32.MaxValue, UInt32.MaxValue, UInt32.MaxValue, UInt32.MaxValue }; uint parse(Text t) { if (!uint.TryParse(t.ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out uint value)) success = false; return value; }; var count = t.NestedBracketSplitCount2(1); if (count == 3 || count == 4) t.NestedBracketSplit(1, parse, () => values); else success = false; result = success ? new C4ui(values) : Zero; return success; } } /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C4ui.Zero otherwise. /// True on success, false otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParse(string s, out C4ui result) => TryParse(new Text(s), out result); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C4ui color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui Parse(string s) => Parse(new Text(s)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui Parse(Text t, int bracketLevel = 1) => t.NestedBracketSplit(bracketLevel, Text.Parse, C4ui.Setter); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C4ui color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui Parse(Text t) => TryParse(t, out C4ui result) ? result : throw new FormatException($"{t} is not a valid C4ui color."); #endregion #region IFormattable Members public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + R.ToString(format, fp) + between + G.ToString(format, fp) + between + B.ToString(format, fp) + between + A.ToString(format, fp) + end; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(C4ui other) { return R.Equals(other.R) && G.Equals(other.G) && B.Equals(other.B) && A.Equals(other.A); } #endregion #region IRGB Members double IRGB.Red { readonly get { return Col.UIntToDouble(R); } set { R = Col.DoubleToUIntClamped(value); } } double IRGB.Green { readonly get { return Col.UIntToDouble(G); } set { G = Col.DoubleToUIntClamped(value); } } double IRGB.Blue { readonly get { return Col.UIntToDouble(B); } set { B = Col.DoubleToUIntClamped(value); } } #endregion #region IOpacity Members [XmlIgnore] public double Opacity { readonly get { return Col.UIntToDouble(A); } set { A = Col.DoubleToUIntClamped(value); } } #endregion } public static partial class Fun { #region Interpolation /// /// Returns the linearly interpolated color between a and b. /// public static C4ui Lerp(this float t, C4ui a, C4ui b) => new C4ui(Lerp(t, a.R, b.R), Lerp(t, a.G, b.G), Lerp(t, a.B, b.B), Lerp(t, a.A, b.A)); /// /// Returns the linearly interpolated color between a and b. /// public static C4ui Lerp(this V4f t, C4ui a, C4ui b) => new C4ui(Lerp(t.X, a.R, b.R), Lerp(t.Y, a.G, b.G), Lerp(t.Z, a.B, b.B), Lerp(t.W, a.A, b.A)); /// /// Returns the linearly interpolated color between a and b. /// public static C4ui Lerp(this double t, C4ui a, C4ui b) => new C4ui(Lerp(t, a.R, b.R), Lerp(t, a.G, b.G), Lerp(t, a.B, b.B), Lerp(t, a.A, b.A)); /// /// Returns the linearly interpolated color between a and b. /// public static C4ui Lerp(this V4d t, C4ui a, C4ui b) => new C4ui(Lerp(t.X, a.R, b.R), Lerp(t.Y, a.G, b.G), Lerp(t.Z, a.B, b.B), Lerp(t.W, a.A, b.A)); #endregion #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this C4ui a, C4ui b, uint tolerance) { return ApproximateEquals(a.R, b.R, tolerance) && ApproximateEquals(a.G, b.G, tolerance) && ApproximateEquals(a.B, b.B, tolerance) && ApproximateEquals(a.A, b.A, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this C4ui c, uint epsilon) => Col.AllTiny(c, epsilon); #endregion } public static partial class Col { #region ToHexString /// /// Returns the hexadecimal representation with format RRGGBBAA. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToHexString(this C4ui c) => c.ToC4b().ToHexString(); #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C4ui a, C4ui b) { return (a.R < b.R && a.G < b.G && a.B < b.B && a.A < b.A); } /// /// Returns whether ALL elements of col are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C4ui col, uint s) { return (col.R < s && col.G < s && col.B < s && col.A < s); } /// /// Returns whether a is Smaller ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(uint s, C4ui col) { return (s < col.R && s < col.G && s < col.B && s < col.A); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C4ui a, C4ui b) { return (a.R < b.R || a.G < b.G || a.B < b.B || a.A < b.A); } /// /// Returns whether AT LEAST ONE element of col is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C4ui col, uint s) { return (col.R < s || col.G < s || col.B < s || col.A < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(uint s, C4ui col) { return (s < col.R || s < col.G || s < col.B || s < col.A); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C4ui a, C4ui b) { return (a.R > b.R && a.G > b.G && a.B > b.B && a.A > b.A); } /// /// Returns whether ALL elements of col are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C4ui col, uint s) { return (col.R > s && col.G > s && col.B > s && col.A > s); } /// /// Returns whether a is Greater ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(uint s, C4ui col) { return (s > col.R && s > col.G && s > col.B && s > col.A); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C4ui a, C4ui b) { return (a.R > b.R || a.G > b.G || a.B > b.B || a.A > b.A); } /// /// Returns whether AT LEAST ONE element of col is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C4ui col, uint s) { return (col.R > s || col.G > s || col.B > s || col.A > s); } /// /// Returns whether a is Greater AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(uint s, C4ui col) { return (s > col.R || s > col.G || s > col.B || s > col.A); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C4ui a, C4ui b) { return (a.R <= b.R && a.G <= b.G && a.B <= b.B && a.A <= b.A); } /// /// Returns whether ALL elements of col are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C4ui col, uint s) { return (col.R <= s && col.G <= s && col.B <= s && col.A <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(uint s, C4ui col) { return (s <= col.R && s <= col.G && s <= col.B && s <= col.A); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C4ui a, C4ui b) { return (a.R <= b.R || a.G <= b.G || a.B <= b.B || a.A <= b.A); } /// /// Returns whether AT LEAST ONE element of col is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C4ui col, uint s) { return (col.R <= s || col.G <= s || col.B <= s || col.A <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(uint s, C4ui col) { return (s <= col.R || s <= col.G || s <= col.B || s <= col.A); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C4ui a, C4ui b) { return (a.R >= b.R && a.G >= b.G && a.B >= b.B && a.A >= b.A); } /// /// Returns whether ALL elements of col are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C4ui col, uint s) { return (col.R >= s && col.G >= s && col.B >= s && col.A >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(uint s, C4ui col) { return (s >= col.R && s >= col.G && s >= col.B && s >= col.A); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C4ui a, C4ui b) { return (a.R >= b.R || a.G >= b.G || a.B >= b.B || a.A >= b.A); } /// /// Returns whether AT LEAST ONE element of col is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C4ui col, uint s) { return (col.R >= s || col.G >= s || col.B >= s || col.A >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(uint s, C4ui col) { return (s >= col.R || s >= col.G || s >= col.B || s >= col.A); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C4ui a, C4ui b) { return (a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A); } /// /// Returns whether ALL elements of col are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C4ui col, uint s) { return (col.R == s && col.G == s && col.B == s && col.A == s); } /// /// Returns whether a is Equal ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(uint s, C4ui col) { return (s == col.R && s == col.G && s == col.B && s == col.A); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C4ui a, C4ui b) { return (a.R == b.R || a.G == b.G || a.B == b.B || a.A == b.A); } /// /// Returns whether AT LEAST ONE element of col is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C4ui col, uint s) { return (col.R == s || col.G == s || col.B == s || col.A == s); } /// /// Returns whether a is Equal AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(uint s, C4ui col) { return (s == col.R || s == col.G || s == col.B || s == col.A); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C4ui a, C4ui b) { return (a.R != b.R && a.G != b.G && a.B != b.B && a.A != b.A); } /// /// Returns whether ALL elements of col are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C4ui col, uint s) { return (col.R != s && col.G != s && col.B != s && col.A != s); } /// /// Returns whether a is Different ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(uint s, C4ui col) { return (s != col.R && s != col.G && s != col.B && s != col.A); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C4ui a, C4ui b) { return (a.R != b.R || a.G != b.G || a.B != b.B || a.A != b.A); } /// /// Returns whether AT LEAST ONE element of col is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C4ui col, uint s) { return (col.R != s || col.G != s || col.B != s || col.A != s); } /// /// Returns whether a is Different AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(uint s, C4ui col) { return (s != col.R || s != col.G || s != col.B || s != col.A); } #endregion #region Linear Combination /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui LinCom( C4ui p0, C4ui p1, C4ui p2, C4ui p3, ref Tup4 w) { return new C4ui( Col.UIntInDoubleToUIntClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3), Col.UIntInDoubleToUIntClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3), Col.UIntInDoubleToUIntClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f LinComRawF( C4ui p0, C4ui p1, C4ui p2, C4ui p3, ref Tup4 w) { return new C4f( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui LinCom( C4ui p0, C4ui p1, C4ui p2, C4ui p3, ref Tup4 w) { return new C4ui( Col.UIntInDoubleToUIntClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3), Col.UIntInDoubleToUIntClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3), Col.UIntInDoubleToUIntClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d LinComRawD( C4ui p0, C4ui p1, C4ui p2, C4ui p3, ref Tup4 w) { return new C4d( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui LinCom( C4ui p0, C4ui p1, C4ui p2, C4ui p3, C4ui p4, C4ui p5, ref Tup6 w) { return new C4ui( Col.UIntInDoubleToUIntClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5), Col.UIntInDoubleToUIntClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5), Col.UIntInDoubleToUIntClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f LinComRawF( C4ui p0, C4ui p1, C4ui p2, C4ui p3, C4ui p4, C4ui p5, ref Tup6 w) { return new C4f( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui LinCom( C4ui p0, C4ui p1, C4ui p2, C4ui p3, C4ui p4, C4ui p5, ref Tup6 w) { return new C4ui( Col.UIntInDoubleToUIntClamped(p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5), Col.UIntInDoubleToUIntClamped(p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5), Col.UIntInDoubleToUIntClamped(p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d LinComRawD( C4ui p0, C4ui p1, C4ui p2, C4ui p3, C4ui p4, C4ui p5, ref Tup6 w) { return new C4d( p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5, p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5, p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5); } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this C4ui c, uint epsilon) => c.R.IsTiny(epsilon) || c.G.IsTiny(epsilon) || c.B.IsTiny(epsilon) || c.A.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this C4ui c, uint epsilon) => c.R.IsTiny(epsilon) && c.G.IsTiny(epsilon) && c.B.IsTiny(epsilon) && c.A.IsTiny(epsilon); #endregion } public static class IRandomUniformC4uiExtensions { #region IRandomUniform extensions for C4ui /// /// Uses UniformUInt() to generate the elements of a C4ui color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4ui UniformC4ui(this IRandomUniform rnd) { return new C4ui(rnd.UniformUInt(), rnd.UniformUInt(), rnd.UniformUInt(), rnd.UniformUInt()); } #endregion } #endregion #region C4f /// /// Represents an RGBA color with each channel stored as a value within [0, 1]. /// [Serializable] public partial struct C4f : IFormattable, IEquatable, IRGB, IOpacity { #region Constructors /// /// Creates a color from the given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(float r, float g, float b, float a) { R = r; G = g; B = b; A = a; } /// /// Creates a color from the given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(double r, double g, double b, double a) { R = (float)(r); G = (float)(g); B = (float)(b); A = (float)(a); } /// /// Creates a color from the given RGB values. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(float r, float g, float b) { R = r; G = g; B = b; A = 1.0f; } /// /// Creates a color from the given RGB values. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(double r, double g, double b) { R = (float)(r); G = (float)(g); B = (float)(b); A = 1.0f; } /// /// Creates a color from a single value. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(float gray) { R = gray; G = gray; B = gray; A = 1.0f; } /// /// Creates a color from a single value. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(double gray) { var value = (float)(gray); R = value; G = value; B = value; A = 1.0f; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(C3b color) { R = Col.ByteToFloat(color.R); G = Col.ByteToFloat(color.G); B = Col.ByteToFloat(color.B); A = 1.0f; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(C3b color, float alpha) { R = Col.ByteToFloat(color.R); G = Col.ByteToFloat(color.G); B = Col.ByteToFloat(color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(C3us color) { R = Col.UShortToFloat(color.R); G = Col.UShortToFloat(color.G); B = Col.UShortToFloat(color.B); A = 1.0f; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(C3us color, float alpha) { R = Col.UShortToFloat(color.R); G = Col.UShortToFloat(color.G); B = Col.UShortToFloat(color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(C3ui color) { R = Col.UIntToFloat(color.R); G = Col.UIntToFloat(color.G); B = Col.UIntToFloat(color.B); A = 1.0f; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(C3ui color, float alpha) { R = Col.UIntToFloat(color.R); G = Col.UIntToFloat(color.G); B = Col.UIntToFloat(color.B); A = alpha; } /// /// Creates a color from the given color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(C3f color) { R = (color.R); G = (color.G); B = (color.B); A = 1.0f; } /// /// Creates a color from the given color and an alpha value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(C3f color, float alpha) { R = (color.R); G = (color.G); B = (color.B); A = alpha; } /// /// Creates a color from the given color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(C3d color) { R = Col.DoubleToFloat(color.R); G = Col.DoubleToFloat(color.G); B = Col.DoubleToFloat(color.B); A = 1.0f; } /// /// Creates a color from the given color and an alpha value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(C3d color, float alpha) { R = Col.DoubleToFloat(color.R); G = Col.DoubleToFloat(color.G); B = Col.DoubleToFloat(color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(C4b color) { R = Col.ByteToFloat(color.R); G = Col.ByteToFloat(color.G); B = Col.ByteToFloat(color.B); A = Col.ByteToFloat(color.A); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(C4us color) { R = Col.UShortToFloat(color.R); G = Col.UShortToFloat(color.G); B = Col.UShortToFloat(color.B); A = Col.UShortToFloat(color.A); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(C4ui color) { R = Col.UIntToFloat(color.R); G = Col.UIntToFloat(color.G); B = Col.UIntToFloat(color.B); A = Col.UIntToFloat(color.A); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(C4f color) { R = (color.R); G = (color.G); B = (color.B); A = (color.A); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(C4d color) { R = Col.DoubleToFloat(color.R); G = Col.DoubleToFloat(color.G); B = Col.DoubleToFloat(color.B); A = Col.DoubleToFloat(color.A); } /// /// Creates a color from the given vector. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(V3f vec) { R = (vec.X); G = (vec.Y); B = (vec.Z); A = 1.0f; } /// /// Creates a color from the given vector. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(V3d vec) { R = (float)(vec.X); G = (float)(vec.Y); B = (float)(vec.Z); A = 1.0f; } /// /// Creates a color from the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(V4f vec) { R = (vec.X); G = (vec.Y); B = (vec.Z); A = (vec.W); } /// /// Creates a color from the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(V4d vec) { R = (float)(vec.X); G = (float)(vec.Y); B = (float)(vec.Z); A = (float)(vec.W); } /// /// Creates a color from the given vector and an alpha value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(V3f vec, float alpha) { R = (vec.X); G = (vec.Y); B = (vec.Z); A = alpha; } /// /// Creates a color from the given vector and an alpha value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(V3d vec, float alpha) { R = (float)(vec.X); G = (float)(vec.Y); B = (float)(vec.Z); A = alpha; } /// /// Creates a color from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(Func index_fun) { R = index_fun(0); G = index_fun(1); B = index_fun(2); A = index_fun(3); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(byte[] values) { R = Col.ByteToFloat(values[0]); G = Col.ByteToFloat(values[1]); B = Col.ByteToFloat(values[2]); A = Col.ByteToFloat(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(byte[] values, int start) { R = Col.ByteToFloat(values[start + 0]); G = Col.ByteToFloat(values[start + 1]); B = Col.ByteToFloat(values[start + 2]); A = Col.ByteToFloat(values[start + 3]); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(ushort[] values) { R = Col.UShortToFloat(values[0]); G = Col.UShortToFloat(values[1]); B = Col.UShortToFloat(values[2]); A = Col.UShortToFloat(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(ushort[] values, int start) { R = Col.UShortToFloat(values[start + 0]); G = Col.UShortToFloat(values[start + 1]); B = Col.UShortToFloat(values[start + 2]); A = Col.UShortToFloat(values[start + 3]); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(uint[] values) { R = Col.UIntToFloat(values[0]); G = Col.UIntToFloat(values[1]); B = Col.UIntToFloat(values[2]); A = Col.UIntToFloat(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(uint[] values, int start) { R = Col.UIntToFloat(values[start + 0]); G = Col.UIntToFloat(values[start + 1]); B = Col.UIntToFloat(values[start + 2]); A = Col.UIntToFloat(values[start + 3]); } /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(float[] values) { R = (values[0]); G = (values[1]); B = (values[2]); A = (values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(float[] values, int start) { R = (values[start + 0]); G = (values[start + 1]); B = (values[start + 2]); A = (values[start + 3]); } /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(double[] values) { R = Col.DoubleToFloat(values[0]); G = Col.DoubleToFloat(values[1]); B = Col.DoubleToFloat(values[2]); A = Col.DoubleToFloat(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4f(double[] values, int start) { R = Col.DoubleToFloat(values[start + 0]); G = Col.DoubleToFloat(values[start + 1]); B = Col.DoubleToFloat(values[start + 2]); A = Col.DoubleToFloat(values[start + 3]); } #endregion #region Properities public readonly C3f RGB => (C3f)this; public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNaN(R) || float.IsNaN(G) || float.IsNaN(B) || float.IsNaN(A); } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNaN(R) && float.IsNaN(G) && float.IsNaN(B) && float.IsNaN(A); } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsInfinity(R) || float.IsInfinity(G) || float.IsInfinity(B) || float.IsInfinity(A); } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsInfinity(R) && float.IsInfinity(G) && float.IsInfinity(B) && float.IsInfinity(A); } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsPositiveInfinity(R) || float.IsPositiveInfinity(G) || float.IsPositiveInfinity(B) || float.IsPositiveInfinity(A); } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsPositiveInfinity(R) && float.IsPositiveInfinity(G) && float.IsPositiveInfinity(B) && float.IsPositiveInfinity(A); } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNegativeInfinity(R) || float.IsNegativeInfinity(G) || float.IsNegativeInfinity(B) || float.IsNegativeInfinity(A); } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNegativeInfinity(R) && float.IsNegativeInfinity(G) && float.IsNegativeInfinity(B) && float.IsNegativeInfinity(A); } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(R) || Fun.IsTiny(G) || Fun.IsTiny(B) || Fun.IsTiny(A); } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(R) && Fun.IsTiny(G) && Fun.IsTiny(B) && Fun.IsTiny(A); } /// /// Returns true if the absolute value of each component of the color is smaller than Constant<float>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any component of the color is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any component of the color is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any component of the color is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any component of the color is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all components of the color are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Conversions /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(C3b color) => new C4f(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f FromC3b(C3b c) => new C4f(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(C3us color) => new C4f(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f FromC3us(C3us c) => new C4f(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(C3ui color) => new C4f(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f FromC3ui(C3ui c) => new C4f(c); /// /// Converts the given color to a color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(C3f color) => new C4f(color); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f ToC3f() => (C3f)this; /// /// Creates a color from the given color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f FromC3f(C3f c) => new C4f(c); /// /// Converts the given color to a color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(C3d color) => new C4f(color); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d ToC3d() => (C3d)this; /// /// Creates a color from the given color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f FromC3d(C3d c) => new C4f(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(C4b color) => new C4f(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f FromC4b(C4b c) => new C4f(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(C4us color) => new C4f(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f FromC4us(C4us c) => new C4f(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(C4ui color) => new C4f(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f FromC4ui(C4ui c) => new C4f(c); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(C4d color) => new C4f(color); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d ToC4d() => (C4d)this; /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f FromC4d(C4d c) => new C4f(c); /// /// Converts the given vector to a color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(V3f v) => new C4f(v); /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; /// /// Creates a color from a vector. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f FromV3f(V3f c) => new C4f(c); /// /// Converts the given vector to a color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(V3d v) => new C4f(v); /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; /// /// Creates a color from a vector. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f FromV3d(V3d c) => new C4f(c); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(V4f v) => new C4f(v); /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; /// /// Creates a color from a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f FromV4f(V4f c) => new C4f(c); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(V4d v) => new C4f(v); /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; /// /// Creates a color from a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f FromV4d(V4d c) => new C4f(c); /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(byte[] values) => new C4f(values); /// /// Creates a new array from the given color. /// The values are mapped and clamped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator byte[](C4f color) => new byte[] { Col.FloatToByteClamped(color.R), Col.FloatToByteClamped(color.G), Col.FloatToByteClamped(color.B), Col.FloatToByteClamped(color.A) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(ushort[] values) => new C4f(values); /// /// Creates a new array from the given color. /// The values are mapped and clamped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ushort[](C4f color) => new ushort[] { Col.FloatToUShortClamped(color.R), Col.FloatToUShortClamped(color.G), Col.FloatToUShortClamped(color.B), Col.FloatToUShortClamped(color.A) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(uint[] values) => new C4f(values); /// /// Creates a new array from the given color. /// The values are mapped and clamped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](C4f color) => new uint[] { Col.FloatToUIntClamped(color.R), Col.FloatToUIntClamped(color.G), Col.FloatToUIntClamped(color.B), Col.FloatToUIntClamped(color.A) }; /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(float[] values) => new C4f(values); /// /// Creates a new array from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](C4f color) => new float[] { (color.R), (color.G), (color.B), (color.A) }; /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4f(double[] values) => new C4f(values); /// /// Creates a new array from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](C4f color) => new double[] { Col.FloatToDouble(color.R), Col.FloatToDouble(color.G), Col.FloatToDouble(color.B), Col.FloatToDouble(color.A) }; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b Map(Func channel_fun) { return new C4b(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us Map(Func channel_fun) { return new C4us(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui Map(Func channel_fun) { return new C4ui(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f Map(Func channel_fun) { return new C4f(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d Map(Func channel_fun) { return new C4d(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(R); array[start + 1] = element_fun(G); array[start + 2] = element_fun(B); array[start + 3] = element_fun(A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(R, 0); array[start + 1] = element_index_fun(G, 1); array[start + 2] = element_index_fun(B, 2); array[start + 3] = element_index_fun(A, 3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float[] ToArray() => (float[])this; #endregion #region Indexer /// /// Indexer in canonical order 0=R, 1=G, 2=B, 3=A (availability depending on color type). /// public unsafe float this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &R) { ptr[i] = value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &R) { return ptr[i]; } } } #endregion #region Constants /// /// C4f with all components zero. /// public static C4f Zero => new C4f(0.0f, 0.0f, 0.0f, 0.0f); // Web colors public static C4f AliceBlue => new C4f((float)(0.941176), (float)(0.972549), (float)(1)); public static C4f AntiqueWhite => new C4f((float)(0.980392), (float)(0.921569), (float)(0.843137)); public static C4f Aqua => new C4f((float)(0), (float)(1), (float)(1)); public static C4f Aquamarine => new C4f((float)(0.498039), (float)(1), (float)(0.831373)); public static C4f Azure => new C4f((float)(0.941176), (float)(1), (float)(1)); public static C4f Beige => new C4f((float)(0.960784), (float)(0.960784), (float)(0.862745)); public static C4f Bisque => new C4f((float)(1), (float)(0.894118), (float)(0.768627)); public static C4f Black => new C4f((float)(0), (float)(0), (float)(0)); public static C4f BlanchedAlmond => new C4f((float)(1), (float)(0.921569), (float)(0.803922)); public static C4f Blue => new C4f((float)(0), (float)(0), (float)(1)); public static C4f BlueViolet => new C4f((float)(0.541176), (float)(0.168627), (float)(0.886275)); public static C4f Brown => new C4f((float)(0.647059), (float)(0.164706), (float)(0.164706)); public static C4f BurlyWood => new C4f((float)(0.870588), (float)(0.721569), (float)(0.529412)); public static C4f CadetBlue => new C4f((float)(0.372549), (float)(0.619608), (float)(0.627451)); public static C4f Chartreuse => new C4f((float)(0.498039), (float)(1), (float)(0)); public static C4f Chocolate => new C4f((float)(0.823529), (float)(0.411765), (float)(0.117647)); public static C4f Coral => new C4f((float)(1), (float)(0.498039), (float)(0.313725)); public static C4f CornflowerBlue => new C4f((float)(0.392157), (float)(0.584314), (float)(0.929412)); public static C4f Cornsilk => new C4f((float)(1), (float)(0.972549), (float)(0.862745)); public static C4f Crimson => new C4f((float)(0.862745), (float)(0.078431), (float)(0.235294)); public static C4f Cyan => new C4f((float)(0), (float)(1), (float)(1)); public static C4f DarkBlue => new C4f((float)(0), (float)(0), (float)(0.545098)); public static C4f DarkCyan => new C4f((float)(0), (float)(0.545098), (float)(0.545098)); public static C4f DarkGoldenRod => new C4f((float)(0.721569), (float)(0.52549), (float)(0.043137)); public static C4f DarkGray => new C4f((float)(0.662745), (float)(0.662745), (float)(0.662745)); public static C4f DarkGrey => new C4f((float)(0.662745), (float)(0.662745), (float)(0.662745)); public static C4f DarkGreen => new C4f((float)(0), (float)(0.392157), (float)(0)); public static C4f DarkKhaki => new C4f((float)(0.741176), (float)(0.717647), (float)(0.419608)); public static C4f DarkMagenta => new C4f((float)(0.545098), (float)(0), (float)(0.545098)); public static C4f DarkOliveGreen => new C4f((float)(0.333333), (float)(0.419608), (float)(0.184314)); public static C4f DarkOrange => new C4f((float)(1), (float)(0.54902), (float)(0)); public static C4f DarkOrchid => new C4f((float)(0.6), (float)(0.196078), (float)(0.8)); public static C4f DarkRed => new C4f((float)(0.545098), (float)(0), (float)(0)); public static C4f DarkSalmon => new C4f((float)(0.913725), (float)(0.588235), (float)(0.478431)); public static C4f DarkSeaGreen => new C4f((float)(0.560784), (float)(0.737255), (float)(0.560784)); public static C4f DarkSlateBlue => new C4f((float)(0.282353), (float)(0.239216), (float)(0.545098)); public static C4f DarkSlateGray => new C4f((float)(0.184314), (float)(0.309804), (float)(0.309804)); public static C4f DarkSlateGrey => new C4f((float)(0.184314), (float)(0.309804), (float)(0.309804)); public static C4f DarkTurquoise => new C4f((float)(0), (float)(0.807843), (float)(0.819608)); public static C4f DarkViolet => new C4f((float)(0.580392), (float)(0), (float)(0.827451)); public static C4f DeepPink => new C4f((float)(1), (float)(0.078431), (float)(0.576471)); public static C4f DeepSkyBlue => new C4f((float)(0), (float)(0.74902), (float)(1)); public static C4f DimGray => new C4f((float)(0.411765), (float)(0.411765), (float)(0.411765)); public static C4f DimGrey => new C4f((float)(0.411765), (float)(0.411765), (float)(0.411765)); public static C4f DodgerBlue => new C4f((float)(0.117647), (float)(0.564706), (float)(1)); public static C4f FireBrick => new C4f((float)(0.698039), (float)(0.133333), (float)(0.133333)); public static C4f FloralWhite => new C4f((float)(1), (float)(0.980392), (float)(0.941176)); public static C4f ForestGreen => new C4f((float)(0.133333), (float)(0.545098), (float)(0.133333)); public static C4f Fuchsia => new C4f((float)(1), (float)(0), (float)(1)); public static C4f Gainsboro => new C4f((float)(0.862745), (float)(0.862745), (float)(0.862745)); public static C4f GhostWhite => new C4f((float)(0.972549), (float)(0.972549), (float)(1)); public static C4f Gold => new C4f((float)(1), (float)(0.843137), (float)(0)); public static C4f GoldenRod => new C4f((float)(0.854902), (float)(0.647059), (float)(0.12549)); public static C4f Gray => new C4f((float)(0.501961), (float)(0.501961), (float)(0.501961)); public static C4f Grey => new C4f((float)(0.501961), (float)(0.501961), (float)(0.501961)); public static C4f Green => new C4f((float)(0), (float)(0.501961), (float)(0)); public static C4f GreenYellow => new C4f((float)(0.678431), (float)(1), (float)(0.184314)); public static C4f HoneyDew => new C4f((float)(0.941176), (float)(1), (float)(0.941176)); public static C4f HotPink => new C4f((float)(1), (float)(0.411765), (float)(0.705882)); public static C4f IndianRed => new C4f((float)(0.803922), (float)(0.360784), (float)(0.360784)); public static C4f Indigo => new C4f((float)(0.294118), (float)(0), (float)(0.509804)); public static C4f Ivory => new C4f((float)(1), (float)(1), (float)(0.941176)); public static C4f Khaki => new C4f((float)(0.941176), (float)(0.901961), (float)(0.54902)); public static C4f Lavender => new C4f((float)(0.901961), (float)(0.901961), (float)(0.980392)); public static C4f LavenderBlush => new C4f((float)(1), (float)(0.941176), (float)(0.960784)); public static C4f LawnGreen => new C4f((float)(0.486275), (float)(0.988235), (float)(0)); public static C4f LemonChiffon => new C4f((float)(1), (float)(0.980392), (float)(0.803922)); public static C4f LightBlue => new C4f((float)(0.678431), (float)(0.847059), (float)(0.901961)); public static C4f LightCoral => new C4f((float)(0.941176), (float)(0.501961), (float)(0.501961)); public static C4f LightCyan => new C4f((float)(0.878431), (float)(1), (float)(1)); public static C4f LightGoldenRodYellow => new C4f((float)(0.980392), (float)(0.980392), (float)(0.823529)); public static C4f LightGray => new C4f((float)(0.827451), (float)(0.827451), (float)(0.827451)); public static C4f LightGrey => new C4f((float)(0.827451), (float)(0.827451), (float)(0.827451)); public static C4f LightGreen => new C4f((float)(0.564706), (float)(0.933333), (float)(0.564706)); public static C4f LightPink => new C4f((float)(1), (float)(0.713725), (float)(0.756863)); public static C4f LightSalmon => new C4f((float)(1), (float)(0.627451), (float)(0.478431)); public static C4f LightSeaGreen => new C4f((float)(0.12549), (float)(0.698039), (float)(0.666667)); public static C4f LightSkyBlue => new C4f((float)(0.529412), (float)(0.807843), (float)(0.980392)); public static C4f LightSlateGray => new C4f((float)(0.466667), (float)(0.533333), (float)(0.6)); public static C4f LightSlateGrey => new C4f((float)(0.466667), (float)(0.533333), (float)(0.6)); public static C4f LightSteelBlue => new C4f((float)(0.690196), (float)(0.768627), (float)(0.870588)); public static C4f LightYellow => new C4f((float)(1), (float)(1), (float)(0.878431)); public static C4f Lime => new C4f((float)(0), (float)(1), (float)(0)); public static C4f LimeGreen => new C4f((float)(0.196078), (float)(0.803922), (float)(0.196078)); public static C4f Linen => new C4f((float)(0.980392), (float)(0.941176), (float)(0.901961)); public static C4f Magenta => new C4f((float)(1), (float)(0), (float)(1)); public static C4f Maroon => new C4f((float)(0.501961), (float)(0), (float)(0)); public static C4f MediumAquaMarine => new C4f((float)(0.4), (float)(0.803922), (float)(0.666667)); public static C4f MediumBlue => new C4f((float)(0), (float)(0), (float)(0.803922)); public static C4f MediumOrchid => new C4f((float)(0.729412), (float)(0.333333), (float)(0.827451)); public static C4f MediumPurple => new C4f((float)(0.576471), (float)(0.439216), (float)(0.847059)); public static C4f MediumSeaGreen => new C4f((float)(0.235294), (float)(0.701961), (float)(0.443137)); public static C4f MediumSlateBlue => new C4f((float)(0.482353), (float)(0.407843), (float)(0.933333)); public static C4f MediumSpringGreen => new C4f((float)(0), (float)(0.980392), (float)(0.603922)); public static C4f MediumTurquoise => new C4f((float)(0.282353), (float)(0.819608), (float)(0.8)); public static C4f MediumVioletRed => new C4f((float)(0.780392), (float)(0.082353), (float)(0.521569)); public static C4f MidnightBlue => new C4f((float)(0.098039), (float)(0.098039), (float)(0.439216)); public static C4f MintCream => new C4f((float)(0.960784), (float)(1), (float)(0.980392)); public static C4f MistyRose => new C4f((float)(1), (float)(0.894118), (float)(0.882353)); public static C4f Moccasin => new C4f((float)(1), (float)(0.894118), (float)(0.709804)); public static C4f NavajoWhite => new C4f((float)(1), (float)(0.870588), (float)(0.678431)); public static C4f Navy => new C4f((float)(0), (float)(0), (float)(0.501961)); public static C4f OldLace => new C4f((float)(0.992157), (float)(0.960784), (float)(0.901961)); public static C4f Olive => new C4f((float)(0.501961), (float)(0.501961), (float)(0)); public static C4f OliveDrab => new C4f((float)(0.419608), (float)(0.556863), (float)(0.137255)); public static C4f Orange => new C4f((float)(1), (float)(0.647059), (float)(0)); public static C4f OrangeRed => new C4f((float)(1), (float)(0.270588), (float)(0)); public static C4f Orchid => new C4f((float)(0.854902), (float)(0.439216), (float)(0.839216)); public static C4f PaleGoldenRod => new C4f((float)(0.933333), (float)(0.909804), (float)(0.666667)); public static C4f PaleGreen => new C4f((float)(0.596078), (float)(0.984314), (float)(0.596078)); public static C4f PaleTurquoise => new C4f((float)(0.686275), (float)(0.933333), (float)(0.933333)); public static C4f PaleVioletRed => new C4f((float)(0.847059), (float)(0.439216), (float)(0.576471)); public static C4f PapayaWhip => new C4f((float)(1), (float)(0.937255), (float)(0.835294)); public static C4f PeachPuff => new C4f((float)(1), (float)(0.854902), (float)(0.72549)); public static C4f Peru => new C4f((float)(0.803922), (float)(0.521569), (float)(0.247059)); public static C4f Pink => new C4f((float)(1), (float)(0.752941), (float)(0.796078)); public static C4f Plum => new C4f((float)(0.866667), (float)(0.627451), (float)(0.866667)); public static C4f PowderBlue => new C4f((float)(0.690196), (float)(0.878431), (float)(0.901961)); public static C4f Purple => new C4f((float)(0.501961), (float)(0), (float)(0.501961)); public static C4f Red => new C4f((float)(1), (float)(0), (float)(0)); public static C4f RosyBrown => new C4f((float)(0.737255), (float)(0.560784), (float)(0.560784)); public static C4f RoyalBlue => new C4f((float)(0.254902), (float)(0.411765), (float)(0.882353)); public static C4f SaddleBrown => new C4f((float)(0.545098), (float)(0.270588), (float)(0.07451)); public static C4f Salmon => new C4f((float)(0.980392), (float)(0.501961), (float)(0.447059)); public static C4f SandyBrown => new C4f((float)(0.956863), (float)(0.643137), (float)(0.376471)); public static C4f SeaGreen => new C4f((float)(0.180392), (float)(0.545098), (float)(0.341176)); public static C4f SeaShell => new C4f((float)(1), (float)(0.960784), (float)(0.933333)); public static C4f Sienna => new C4f((float)(0.627451), (float)(0.321569), (float)(0.176471)); public static C4f Silver => new C4f((float)(0.752941), (float)(0.752941), (float)(0.752941)); public static C4f SkyBlue => new C4f((float)(0.529412), (float)(0.807843), (float)(0.921569)); public static C4f SlateBlue => new C4f((float)(0.415686), (float)(0.352941), (float)(0.803922)); public static C4f SlateGray => new C4f((float)(0.439216), (float)(0.501961), (float)(0.564706)); public static C4f SlateGrey => new C4f((float)(0.439216), (float)(0.501961), (float)(0.564706)); public static C4f Snow => new C4f((float)(1), (float)(0.980392), (float)(0.980392)); public static C4f SpringGreen => new C4f((float)(0), (float)(1), (float)(0.498039)); public static C4f SteelBlue => new C4f((float)(0.27451), (float)(0.509804), (float)(0.705882)); public static C4f Tan => new C4f((float)(0.823529), (float)(0.705882), (float)(0.54902)); public static C4f Teal => new C4f((float)(0), (float)(0.501961), (float)(0.501961)); public static C4f Thistle => new C4f((float)(0.847059), (float)(0.74902), (float)(0.847059)); public static C4f Tomato => new C4f((float)(1), (float)(0.388235), (float)(0.278431)); public static C4f Turquoise => new C4f((float)(0.25098), (float)(0.878431), (float)(0.815686)); public static C4f Violet => new C4f((float)(0.933333), (float)(0.509804), (float)(0.933333)); public static C4f Wheat => new C4f((float)(0.960784), (float)(0.870588), (float)(0.701961)); public static C4f White => new C4f((float)(1), (float)(1), (float)(1)); public static C4f WhiteSmoke => new C4f((float)(0.960784), (float)(0.960784), (float)(0.960784)); public static C4f Yellow => new C4f((float)(1), (float)(1), (float)(0)); public static C4f YellowGreen => new C4f((float)(0.603922), (float)(0.803922), (float)(0.196078)); public static C4f DarkYellow => Olive; public static C4f VRVisGreen => new C4f((float)(0.698), (float)(0.851), (float)(0.008)); public static C4f Gray10 => new C4f((float)(0.1)); public static C4f Gray20 => new C4f((float)(0.2)); public static C4f Gray30 => new C4f((float)(0.3)); public static C4f Gray40 => new C4f((float)(0.4)); public static C4f Gray50 => new C4f((float)(0.5)); public static C4f Gray60 => new C4f((float)(0.6)); public static C4f Gray70 => new C4f((float)(0.7)); public static C4f Gray80 => new C4f((float)(0.8)); public static C4f Gray90 => new C4f((float)(0.9)); #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(C4f a, C4f b) { return a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(C4f a, C4f b) { return a.R != b.R || a.G != b.G || a.B != b.B || a.A != b.A; } #endregion #region Color Arithmetic [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator +(C4f c0, C4b c1) { return new C4f( (float)(c0.R + Col.ByteToFloat(c1.R)), (float)(c0.G + Col.ByteToFloat(c1.G)), (float)(c0.B + Col.ByteToFloat(c1.B)), (float)(c0.A + Col.ByteToFloat(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator -(C4f c0, C4b c1) { return new C4f( (float)(c0.R - Col.ByteToFloat(c1.R)), (float)(c0.G - Col.ByteToFloat(c1.G)), (float)(c0.B - Col.ByteToFloat(c1.B)), (float)(c0.A - Col.ByteToFloat(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator +(C4f c0, C4us c1) { return new C4f( (float)(c0.R + Col.UShortToFloat(c1.R)), (float)(c0.G + Col.UShortToFloat(c1.G)), (float)(c0.B + Col.UShortToFloat(c1.B)), (float)(c0.A + Col.UShortToFloat(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator -(C4f c0, C4us c1) { return new C4f( (float)(c0.R - Col.UShortToFloat(c1.R)), (float)(c0.G - Col.UShortToFloat(c1.G)), (float)(c0.B - Col.UShortToFloat(c1.B)), (float)(c0.A - Col.UShortToFloat(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator +(C4f c0, C4ui c1) { return new C4f( (float)(c0.R + Col.UIntToFloat(c1.R)), (float)(c0.G + Col.UIntToFloat(c1.G)), (float)(c0.B + Col.UIntToFloat(c1.B)), (float)(c0.A + Col.UIntToFloat(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator -(C4f c0, C4ui c1) { return new C4f( (float)(c0.R - Col.UIntToFloat(c1.R)), (float)(c0.G - Col.UIntToFloat(c1.G)), (float)(c0.B - Col.UIntToFloat(c1.B)), (float)(c0.A - Col.UIntToFloat(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator +(C4f c0, C4d c1) { return new C4f( (float)(c0.R + (float)(c1.R)), (float)(c0.G + (float)(c1.G)), (float)(c0.B + (float)(c1.B)), (float)(c0.A + (float)(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator -(C4f c0, C4d c1) { return new C4f( (float)(c0.R - (float)(c1.R)), (float)(c0.G - (float)(c1.G)), (float)(c0.B - (float)(c1.B)), (float)(c0.A - (float)(c1.A))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator *(C4f col, float scalar) { return new C4f((float)(col.R * scalar), (float)(col.G * scalar), (float)(col.B * scalar), (float)(col.A * scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator *(float scalar, C4f col) { return new C4f((float)(scalar * col.R), (float)(scalar * col.G), (float)(scalar * col.B), (float)(scalar * col.A)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator /(C4f col, float scalar) { return new C4f((float)(col.R / scalar), (float)(col.G / scalar), (float)(col.B / scalar), (float)(col.A / scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator /(float scalar, C4f col) { return new C4f((float)(scalar / col.R), (float)(scalar / col.G), (float)(scalar / col.B), (float)(scalar / col.A)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator *(C4f c0, C4f c1) { return new C4f((float)(c0.R * c1.R), (float)(c0.G * c1.G), (float)(c0.B * c1.B), (float)(c0.A * c1.A)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator /(C4f c0, C4f c1) { return new C4f((float)(c0.R / c1.R), (float)(c0.G / c1.G), (float)(c0.B / c1.B), (float)(c0.A / c1.A)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator +(C4f c0, C4f c1) { return new C4f(c0.R + c1.R, c0.G + c1.G, c0.B + c1.B, c0.A + c1.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator +(C4f col, float scalar) { return new C4f(col.R + scalar, col.G + scalar, col.B + scalar, col.A + scalar); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator +(float scalar, C4f col) => col + scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator -(C4f c0, C4f c1) { return new C4f(c0.R - c1.R, c0.G - c1.G, c0.B - c1.B, c0.A - c1.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator -(C4f col, float scalar) { return new C4f(col.R - scalar, col.G - scalar, col.B - scalar, col.A - scalar); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f operator -(float scalar, C4f col) { return new C4f(scalar - col.R, scalar - col.G, scalar - col.B, scalar - col.A); } /// /// Clamps the color channels to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clamp(float min, float max) { R = R.Clamp(min, max); G = G.Clamp(min, max); B = B.Clamp(min, max); } /// /// Returns a copy with the color channels clamped to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f Clamped(float min, float max) { return new C4f(R.Clamp(min, max), G.Clamp(min, max), B.Clamp(min, max), A); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |R| + |G| + |B|. The alpha channel is ignored. /// public readonly float Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Abs(R) + Fun.Abs(G) + Fun.Abs(B); } } /// /// Returns the Euclidean (or 2-) norm of the color. This is calculated /// as sqrt(R^2 + G^2 + B^2). The alpha channel is ignored. /// public readonly float Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(R * R + G * G + B * B); } } /// /// Returns the infinite (or maximum) norm of the color. This is /// calculated as max(|R|, |G|, |B|). The alpha channel is ignored. /// public readonly float NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(Fun.Abs(R), Fun.Abs(G), Fun.Abs(B)); } } /// /// Returns the minimum norm of the color. This is calculated as /// min(|R|, |G|, |B|). The alpha channel is ignored. /// public readonly float NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(Fun.Abs(R), Fun.Abs(G), Fun.Abs(B)); } } #endregion #region Overrides public override readonly bool Equals(object other) => (other is C4f o) ? Equals(o) : false; public override readonly int GetHashCode() { return HashCode.GetCombined(R, G, B, A); } public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + R.ToString(null, CultureInfo.InvariantCulture) + ", " + G.ToString(null, CultureInfo.InvariantCulture) + ", " + B.ToString(null, CultureInfo.InvariantCulture) + ", " + A.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref C4f color, int i, float value) => { switch (i) { case 0: color.R = value; return; case 1: color.G = value; return; case 2: color.B = value; return; case 3: color.A = value; return; default: throw new IndexOutOfRangeException(); } }; [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f LinearInterp(float t, C4f a, C4f b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f LinearInterp(V4f t, C4f a, C4f b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f DivideByInt(C4f c, int x) => c / x; #endregion #region Parsing /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C4f.Zero otherwise. /// True on success, false otherwise. public static bool TryParse(Text t, out C4f result) { if (Col.TryParseHex(t, out C4b tmp)) { result = tmp.ToC4f(); return true; } else { bool success = true; float[] values = new float[4] { 1.0f, 1.0f, 1.0f, 1.0f }; float parse(Text t) { if (!float.TryParse(t.ToString(), NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out float value)) success = false; return value; }; var count = t.NestedBracketSplitCount2(1); if (count == 3 || count == 4) t.NestedBracketSplit(1, parse, () => values); else success = false; result = success ? new C4f(values) : Zero; return success; } } /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C4f.Zero otherwise. /// True on success, false otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParse(string s, out C4f result) => TryParse(new Text(s), out result); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C4f color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f Parse(string s) => Parse(new Text(s)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f Parse(Text t, int bracketLevel = 1) => t.NestedBracketSplit(bracketLevel, Text.Parse, C4f.Setter); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C4f color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f Parse(Text t) => TryParse(t, out C4f result) ? result : throw new FormatException($"{t} is not a valid C4f color."); #endregion #region IFormattable Members public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + R.ToString(format, fp) + between + G.ToString(format, fp) + between + B.ToString(format, fp) + between + A.ToString(format, fp) + end; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(C4f other) { return R.Equals(other.R) && G.Equals(other.G) && B.Equals(other.B) && A.Equals(other.A); } #endregion #region IRGB Members double IRGB.Red { readonly get { return (double)(R); } set { R = (float)(value); } } double IRGB.Green { readonly get { return (double)(G); } set { G = (float)(value); } } double IRGB.Blue { readonly get { return (double)(B); } set { B = (float)(value); } } #endregion #region IOpacity Members [XmlIgnore] public double Opacity { readonly get { return (double)(A); } set { A = (float)(value); } } #endregion } public static partial class Fun { #region Interpolation /// /// Returns the linearly interpolated color between a and b. /// public static C4f Lerp(this float t, C4f a, C4f b) => new C4f(Lerp(t, a.R, b.R), Lerp(t, a.G, b.G), Lerp(t, a.B, b.B), Lerp(t, a.A, b.A)); /// /// Returns the linearly interpolated color between a and b. /// public static C4f Lerp(this V4f t, C4f a, C4f b) => new C4f(Lerp(t.X, a.R, b.R), Lerp(t.Y, a.G, b.G), Lerp(t.Z, a.B, b.B), Lerp(t.W, a.A, b.A)); #endregion #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this C4f a, C4f b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this C4f a, C4f b, float tolerance) { return ApproximateEquals(a.R, b.R, tolerance) && ApproximateEquals(a.G, b.G, tolerance) && ApproximateEquals(a.B, b.B, tolerance) && ApproximateEquals(a.A, b.A, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this C4f c, float epsilon) => Col.AllTiny(c, epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(C4f c) => c.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any component of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(C4f c) => c.IsNaN; /// /// Returns whether any component of the the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(C4f c) => c.IsInfinity; /// /// Returns whether any component of the the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(C4f c) => c.IsPositiveInfinity; /// /// Returns whether any component of the the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(C4f c) => c.IsNegativeInfinity; /// /// Returns whether all components of the the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(C4f c) => c.IsFinite; #endregion } public static partial class Col { #region ToHexString /// /// Returns the hexadecimal representation with format RRGGBBAA. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToHexString(this C4f c) => c.ToC4b().ToHexString(); #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C4f a, C4f b) { return (a.R < b.R && a.G < b.G && a.B < b.B && a.A < b.A); } /// /// Returns whether ALL elements of col are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C4f col, float s) { return (col.R < s && col.G < s && col.B < s && col.A < s); } /// /// Returns whether a is Smaller ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(float s, C4f col) { return (s < col.R && s < col.G && s < col.B && s < col.A); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C4f a, C4f b) { return (a.R < b.R || a.G < b.G || a.B < b.B || a.A < b.A); } /// /// Returns whether AT LEAST ONE element of col is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C4f col, float s) { return (col.R < s || col.G < s || col.B < s || col.A < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(float s, C4f col) { return (s < col.R || s < col.G || s < col.B || s < col.A); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C4f a, C4f b) { return (a.R > b.R && a.G > b.G && a.B > b.B && a.A > b.A); } /// /// Returns whether ALL elements of col are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C4f col, float s) { return (col.R > s && col.G > s && col.B > s && col.A > s); } /// /// Returns whether a is Greater ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(float s, C4f col) { return (s > col.R && s > col.G && s > col.B && s > col.A); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C4f a, C4f b) { return (a.R > b.R || a.G > b.G || a.B > b.B || a.A > b.A); } /// /// Returns whether AT LEAST ONE element of col is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C4f col, float s) { return (col.R > s || col.G > s || col.B > s || col.A > s); } /// /// Returns whether a is Greater AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(float s, C4f col) { return (s > col.R || s > col.G || s > col.B || s > col.A); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C4f a, C4f b) { return (a.R <= b.R && a.G <= b.G && a.B <= b.B && a.A <= b.A); } /// /// Returns whether ALL elements of col are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C4f col, float s) { return (col.R <= s && col.G <= s && col.B <= s && col.A <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(float s, C4f col) { return (s <= col.R && s <= col.G && s <= col.B && s <= col.A); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C4f a, C4f b) { return (a.R <= b.R || a.G <= b.G || a.B <= b.B || a.A <= b.A); } /// /// Returns whether AT LEAST ONE element of col is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C4f col, float s) { return (col.R <= s || col.G <= s || col.B <= s || col.A <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(float s, C4f col) { return (s <= col.R || s <= col.G || s <= col.B || s <= col.A); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C4f a, C4f b) { return (a.R >= b.R && a.G >= b.G && a.B >= b.B && a.A >= b.A); } /// /// Returns whether ALL elements of col are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C4f col, float s) { return (col.R >= s && col.G >= s && col.B >= s && col.A >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(float s, C4f col) { return (s >= col.R && s >= col.G && s >= col.B && s >= col.A); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C4f a, C4f b) { return (a.R >= b.R || a.G >= b.G || a.B >= b.B || a.A >= b.A); } /// /// Returns whether AT LEAST ONE element of col is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C4f col, float s) { return (col.R >= s || col.G >= s || col.B >= s || col.A >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(float s, C4f col) { return (s >= col.R || s >= col.G || s >= col.B || s >= col.A); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C4f a, C4f b) { return (a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A); } /// /// Returns whether ALL elements of col are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C4f col, float s) { return (col.R == s && col.G == s && col.B == s && col.A == s); } /// /// Returns whether a is Equal ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(float s, C4f col) { return (s == col.R && s == col.G && s == col.B && s == col.A); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C4f a, C4f b) { return (a.R == b.R || a.G == b.G || a.B == b.B || a.A == b.A); } /// /// Returns whether AT LEAST ONE element of col is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C4f col, float s) { return (col.R == s || col.G == s || col.B == s || col.A == s); } /// /// Returns whether a is Equal AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(float s, C4f col) { return (s == col.R || s == col.G || s == col.B || s == col.A); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C4f a, C4f b) { return (a.R != b.R && a.G != b.G && a.B != b.B && a.A != b.A); } /// /// Returns whether ALL elements of col are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C4f col, float s) { return (col.R != s && col.G != s && col.B != s && col.A != s); } /// /// Returns whether a is Different ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(float s, C4f col) { return (s != col.R && s != col.G && s != col.B && s != col.A); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C4f a, C4f b) { return (a.R != b.R || a.G != b.G || a.B != b.B || a.A != b.A); } /// /// Returns whether AT LEAST ONE element of col is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C4f col, float s) { return (col.R != s || col.G != s || col.B != s || col.A != s); } /// /// Returns whether a is Different AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(float s, C4f col) { return (s != col.R || s != col.G || s != col.B || s != col.A); } #endregion #region Linear Combination /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f LinCom( C4f p0, C4f p1, C4f p2, C4f p3, ref Tup4 w) { return new C4f( (p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3), (p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3), (p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3)); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f LinCom( C4f p0, C4f p1, C4f p2, C4f p3, C4f p4, C4f p5, ref Tup6 w) { return new C4f( (p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5), (p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5), (p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5)); } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this C4f c, float epsilon) => c.R.IsTiny(epsilon) || c.G.IsTiny(epsilon) || c.B.IsTiny(epsilon) || c.A.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this C4f c, float epsilon) => c.R.IsTiny(epsilon) && c.G.IsTiny(epsilon) && c.B.IsTiny(epsilon) && c.A.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(C4f c) => c.AnyNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(C4f c) => c.AllNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(C4f c) => c.AnyInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(C4f c) => c.AllInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(C4f c) => c.AnyPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(C4f c) => c.AllPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(C4f c) => c.AnyNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(C4f c) => c.AllNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(C4f c) => c.AnyTiny; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(C4f c) => c.AllTiny; #endregion } public static class IRandomUniformC4fExtensions { #region IRandomUniform extensions for C4f /// /// Uses UniformFloat() to generate the elements of a C4f color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f UniformC4f(this IRandomUniform rnd) { return new C4f(rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat()); } /// /// Uses UniformFloatClosed() to generate the elements of a C4f color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f UniformC4fClosed(this IRandomUniform rnd) { return new C4f(rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed()); } /// /// Uses UniformFloatOpen() to generate the elements of a C4f color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4f UniformC4fOpen(this IRandomUniform rnd) { return new C4f(rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen()); } #endregion } #endregion #region C4d /// /// Represents an RGBA color with each channel stored as a value within [0, 1]. /// [Serializable] public partial struct C4d : IFormattable, IEquatable, IRGB, IOpacity { #region Constructors /// /// Creates a color from the given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(double r, double g, double b, double a) { R = r; G = g; B = b; A = a; } /// /// Creates a color from the given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(float r, float g, float b, float a) { R = (double)(r); G = (double)(g); B = (double)(b); A = (double)(a); } /// /// Creates a color from the given RGB values. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(double r, double g, double b) { R = r; G = g; B = b; A = 1.0; } /// /// Creates a color from the given RGB values. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(float r, float g, float b) { R = (double)(r); G = (double)(g); B = (double)(b); A = 1.0; } /// /// Creates a color from a single value. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(double gray) { R = gray; G = gray; B = gray; A = 1.0; } /// /// Creates a color from a single value. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(float gray) { var value = (double)(gray); R = value; G = value; B = value; A = 1.0; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(C3b color) { R = Col.ByteToDouble(color.R); G = Col.ByteToDouble(color.G); B = Col.ByteToDouble(color.B); A = 1.0; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(C3b color, double alpha) { R = Col.ByteToDouble(color.R); G = Col.ByteToDouble(color.G); B = Col.ByteToDouble(color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(C3us color) { R = Col.UShortToDouble(color.R); G = Col.UShortToDouble(color.G); B = Col.UShortToDouble(color.B); A = 1.0; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(C3us color, double alpha) { R = Col.UShortToDouble(color.R); G = Col.UShortToDouble(color.G); B = Col.UShortToDouble(color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(C3ui color) { R = Col.UIntToDouble(color.R); G = Col.UIntToDouble(color.G); B = Col.UIntToDouble(color.B); A = 1.0; } /// /// Creates a color from the given color and an alpha value. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(C3ui color, double alpha) { R = Col.UIntToDouble(color.R); G = Col.UIntToDouble(color.G); B = Col.UIntToDouble(color.B); A = alpha; } /// /// Creates a color from the given color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(C3f color) { R = Col.FloatToDouble(color.R); G = Col.FloatToDouble(color.G); B = Col.FloatToDouble(color.B); A = 1.0; } /// /// Creates a color from the given color and an alpha value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(C3f color, double alpha) { R = Col.FloatToDouble(color.R); G = Col.FloatToDouble(color.G); B = Col.FloatToDouble(color.B); A = alpha; } /// /// Creates a color from the given color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(C3d color) { R = (color.R); G = (color.G); B = (color.B); A = 1.0; } /// /// Creates a color from the given color and an alpha value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(C3d color, double alpha) { R = (color.R); G = (color.G); B = (color.B); A = alpha; } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(C4b color) { R = Col.ByteToDouble(color.R); G = Col.ByteToDouble(color.G); B = Col.ByteToDouble(color.B); A = Col.ByteToDouble(color.A); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(C4us color) { R = Col.UShortToDouble(color.R); G = Col.UShortToDouble(color.G); B = Col.UShortToDouble(color.B); A = Col.UShortToDouble(color.A); } /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(C4ui color) { R = Col.UIntToDouble(color.R); G = Col.UIntToDouble(color.G); B = Col.UIntToDouble(color.B); A = Col.UIntToDouble(color.A); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(C4f color) { R = Col.FloatToDouble(color.R); G = Col.FloatToDouble(color.G); B = Col.FloatToDouble(color.B); A = Col.FloatToDouble(color.A); } /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(C4d color) { R = (color.R); G = (color.G); B = (color.B); A = (color.A); } /// /// Creates a color from the given vector. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(V3f vec) { R = (double)(vec.X); G = (double)(vec.Y); B = (double)(vec.Z); A = 1.0; } /// /// Creates a color from the given vector. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(V3d vec) { R = (vec.X); G = (vec.Y); B = (vec.Z); A = 1.0; } /// /// Creates a color from the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(V4f vec) { R = (double)(vec.X); G = (double)(vec.Y); B = (double)(vec.Z); A = (double)(vec.W); } /// /// Creates a color from the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(V4d vec) { R = (vec.X); G = (vec.Y); B = (vec.Z); A = (vec.W); } /// /// Creates a color from the given vector and an alpha value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(V3f vec, double alpha) { R = (double)(vec.X); G = (double)(vec.Y); B = (double)(vec.Z); A = alpha; } /// /// Creates a color from the given vector and an alpha value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(V3d vec, double alpha) { R = (vec.X); G = (vec.Y); B = (vec.Z); A = alpha; } /// /// Creates a color from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(Func index_fun) { R = index_fun(0); G = index_fun(1); B = index_fun(2); A = index_fun(3); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(byte[] values) { R = Col.ByteToDouble(values[0]); G = Col.ByteToDouble(values[1]); B = Col.ByteToDouble(values[2]); A = Col.ByteToDouble(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(byte[] values, int start) { R = Col.ByteToDouble(values[start + 0]); G = Col.ByteToDouble(values[start + 1]); B = Col.ByteToDouble(values[start + 2]); A = Col.ByteToDouble(values[start + 3]); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(ushort[] values) { R = Col.UShortToDouble(values[0]); G = Col.UShortToDouble(values[1]); B = Col.UShortToDouble(values[2]); A = Col.UShortToDouble(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(ushort[] values, int start) { R = Col.UShortToDouble(values[start + 0]); G = Col.UShortToDouble(values[start + 1]); B = Col.UShortToDouble(values[start + 2]); A = Col.UShortToDouble(values[start + 3]); } /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(uint[] values) { R = Col.UIntToDouble(values[0]); G = Col.UIntToDouble(values[1]); B = Col.UIntToDouble(values[2]); A = Col.UIntToDouble(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(uint[] values, int start) { R = Col.UIntToDouble(values[start + 0]); G = Col.UIntToDouble(values[start + 1]); B = Col.UIntToDouble(values[start + 2]); A = Col.UIntToDouble(values[start + 3]); } /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(float[] values) { R = Col.FloatToDouble(values[0]); G = Col.FloatToDouble(values[1]); B = Col.FloatToDouble(values[2]); A = Col.FloatToDouble(values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(float[] values, int start) { R = Col.FloatToDouble(values[start + 0]); G = Col.FloatToDouble(values[start + 1]); B = Col.FloatToDouble(values[start + 2]); A = Col.FloatToDouble(values[start + 3]); } /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(double[] values) { R = (values[0]); G = (values[1]); B = (values[2]); A = (values[3]); } /// /// Creates a new color from the given array, starting at the specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public C4d(double[] values, int start) { R = (values[start + 0]); G = (values[start + 1]); B = (values[start + 2]); A = (values[start + 3]); } #endregion #region Properities public readonly C3d RGB => (C3d)this; public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNaN(R) || double.IsNaN(G) || double.IsNaN(B) || double.IsNaN(A); } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNaN(R) && double.IsNaN(G) && double.IsNaN(B) && double.IsNaN(A); } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsInfinity(R) || double.IsInfinity(G) || double.IsInfinity(B) || double.IsInfinity(A); } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsInfinity(R) && double.IsInfinity(G) && double.IsInfinity(B) && double.IsInfinity(A); } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsPositiveInfinity(R) || double.IsPositiveInfinity(G) || double.IsPositiveInfinity(B) || double.IsPositiveInfinity(A); } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsPositiveInfinity(R) && double.IsPositiveInfinity(G) && double.IsPositiveInfinity(B) && double.IsPositiveInfinity(A); } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNegativeInfinity(R) || double.IsNegativeInfinity(G) || double.IsNegativeInfinity(B) || double.IsNegativeInfinity(A); } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNegativeInfinity(R) && double.IsNegativeInfinity(G) && double.IsNegativeInfinity(B) && double.IsNegativeInfinity(A); } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(R) || Fun.IsTiny(G) || Fun.IsTiny(B) || Fun.IsTiny(A); } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(R) && Fun.IsTiny(G) && Fun.IsTiny(B) && Fun.IsTiny(A); } /// /// Returns true if the absolute value of each component of the color is smaller than Constant<double>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any component of the color is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any component of the color is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any component of the color is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any component of the color is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all components of the color are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Conversions /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(C3b color) => new C4d(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d FromC3b(C3b c) => new C4d(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(C3us color) => new C4d(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d FromC3us(C3us c) => new C4d(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(C3ui color) => new C4d(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d FromC3ui(C3ui c) => new C4d(c); /// /// Converts the given color to a color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(C3f color) => new C4d(color); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f ToC3f() => (C3f)this; /// /// Creates a color from the given color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d FromC3f(C3f c) => new C4d(c); /// /// Converts the given color to a color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(C3d color) => new C4d(color); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d ToC3d() => (C3d)this; /// /// Creates a color from the given color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d FromC3d(C3d c) => new C4d(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(C4b color) => new C4d(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d FromC4b(C4b c) => new C4d(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(C4us color) => new C4d(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d FromC4us(C4us c) => new C4d(c); /// /// Converts the given color to a color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(C4ui color) => new C4d(color); /// /// Converts the given color to a color. /// The values are mapped and clamped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Creates a color from the given color. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d FromC4ui(C4ui c) => new C4d(c); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(C4f color) => new C4d(color); /// /// Converts the given color to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f ToC4f() => (C4f)this; /// /// Creates a color from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d FromC4f(C4f c) => new C4d(c); /// /// Converts the given vector to a color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(V3f v) => new C4d(v); /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; /// /// Creates a color from a vector. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d FromV3f(V3f c) => new C4d(c); /// /// Converts the given vector to a color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(V3d v) => new C4d(v); /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; /// /// Creates a color from a vector. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d FromV3d(V3d c) => new C4d(c); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(V4f v) => new C4d(v); /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; /// /// Creates a color from a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d FromV4f(V4f c) => new C4d(c); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(V4d v) => new C4d(v); /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; /// /// Creates a color from a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d FromV4d(V4d c) => new C4d(c); /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(byte[] values) => new C4d(values); /// /// Creates a new array from the given color. /// The values are mapped and clamped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator byte[](C4d color) => new byte[] { Col.DoubleToByteClamped(color.R), Col.DoubleToByteClamped(color.G), Col.DoubleToByteClamped(color.B), Col.DoubleToByteClamped(color.A) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(ushort[] values) => new C4d(values); /// /// Creates a new array from the given color. /// The values are mapped and clamped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator ushort[](C4d color) => new ushort[] { Col.DoubleToUShortClamped(color.R), Col.DoubleToUShortClamped(color.G), Col.DoubleToUShortClamped(color.B), Col.DoubleToUShortClamped(color.A) }; /// /// Creates a new color from the given array. /// The values are mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(uint[] values) => new C4d(values); /// /// Creates a new array from the given color. /// The values are mapped and clamped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](C4d color) => new uint[] { Col.DoubleToUIntClamped(color.R), Col.DoubleToUIntClamped(color.G), Col.DoubleToUIntClamped(color.B), Col.DoubleToUIntClamped(color.A) }; /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(float[] values) => new C4d(values); /// /// Creates a new array from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](C4d color) => new float[] { Col.DoubleToFloat(color.R), Col.DoubleToFloat(color.G), Col.DoubleToFloat(color.B), Col.DoubleToFloat(color.A) }; /// /// Creates a new color from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator C4d(double[] values) => new C4d(values); /// /// Creates a new array from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](C4d color) => new double[] { (color.R), (color.G), (color.B), (color.A) }; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b Map(Func channel_fun) { return new C4b(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us Map(Func channel_fun) { return new C4us(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui Map(Func channel_fun) { return new C4ui(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f Map(Func channel_fun) { return new C4f(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d Map(Func channel_fun) { return new C4d(channel_fun(R), channel_fun(G), channel_fun(B), channel_fun(A)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(R); array[start + 1] = element_fun(G); array[start + 2] = element_fun(B); array[start + 3] = element_fun(A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(R, 0); array[start + 1] = element_index_fun(G, 1); array[start + 2] = element_index_fun(B, 2); array[start + 3] = element_index_fun(A, 3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double[] ToArray() => (double[])this; #endregion #region Indexer /// /// Indexer in canonical order 0=R, 1=G, 2=B, 3=A (availability depending on color type). /// public unsafe double this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &R) { ptr[i] = value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &R) { return ptr[i]; } } } #endregion #region Constants /// /// C4d with all components zero. /// public static C4d Zero => new C4d(0, 0, 0, 0); // Web colors public static C4d AliceBlue => new C4d((0.941176), (0.972549), (1)); public static C4d AntiqueWhite => new C4d((0.980392), (0.921569), (0.843137)); public static C4d Aqua => new C4d((0), (1), (1)); public static C4d Aquamarine => new C4d((0.498039), (1), (0.831373)); public static C4d Azure => new C4d((0.941176), (1), (1)); public static C4d Beige => new C4d((0.960784), (0.960784), (0.862745)); public static C4d Bisque => new C4d((1), (0.894118), (0.768627)); public static C4d Black => new C4d((0), (0), (0)); public static C4d BlanchedAlmond => new C4d((1), (0.921569), (0.803922)); public static C4d Blue => new C4d((0), (0), (1)); public static C4d BlueViolet => new C4d((0.541176), (0.168627), (0.886275)); public static C4d Brown => new C4d((0.647059), (0.164706), (0.164706)); public static C4d BurlyWood => new C4d((0.870588), (0.721569), (0.529412)); public static C4d CadetBlue => new C4d((0.372549), (0.619608), (0.627451)); public static C4d Chartreuse => new C4d((0.498039), (1), (0)); public static C4d Chocolate => new C4d((0.823529), (0.411765), (0.117647)); public static C4d Coral => new C4d((1), (0.498039), (0.313725)); public static C4d CornflowerBlue => new C4d((0.392157), (0.584314), (0.929412)); public static C4d Cornsilk => new C4d((1), (0.972549), (0.862745)); public static C4d Crimson => new C4d((0.862745), (0.078431), (0.235294)); public static C4d Cyan => new C4d((0), (1), (1)); public static C4d DarkBlue => new C4d((0), (0), (0.545098)); public static C4d DarkCyan => new C4d((0), (0.545098), (0.545098)); public static C4d DarkGoldenRod => new C4d((0.721569), (0.52549), (0.043137)); public static C4d DarkGray => new C4d((0.662745), (0.662745), (0.662745)); public static C4d DarkGrey => new C4d((0.662745), (0.662745), (0.662745)); public static C4d DarkGreen => new C4d((0), (0.392157), (0)); public static C4d DarkKhaki => new C4d((0.741176), (0.717647), (0.419608)); public static C4d DarkMagenta => new C4d((0.545098), (0), (0.545098)); public static C4d DarkOliveGreen => new C4d((0.333333), (0.419608), (0.184314)); public static C4d DarkOrange => new C4d((1), (0.54902), (0)); public static C4d DarkOrchid => new C4d((0.6), (0.196078), (0.8)); public static C4d DarkRed => new C4d((0.545098), (0), (0)); public static C4d DarkSalmon => new C4d((0.913725), (0.588235), (0.478431)); public static C4d DarkSeaGreen => new C4d((0.560784), (0.737255), (0.560784)); public static C4d DarkSlateBlue => new C4d((0.282353), (0.239216), (0.545098)); public static C4d DarkSlateGray => new C4d((0.184314), (0.309804), (0.309804)); public static C4d DarkSlateGrey => new C4d((0.184314), (0.309804), (0.309804)); public static C4d DarkTurquoise => new C4d((0), (0.807843), (0.819608)); public static C4d DarkViolet => new C4d((0.580392), (0), (0.827451)); public static C4d DeepPink => new C4d((1), (0.078431), (0.576471)); public static C4d DeepSkyBlue => new C4d((0), (0.74902), (1)); public static C4d DimGray => new C4d((0.411765), (0.411765), (0.411765)); public static C4d DimGrey => new C4d((0.411765), (0.411765), (0.411765)); public static C4d DodgerBlue => new C4d((0.117647), (0.564706), (1)); public static C4d FireBrick => new C4d((0.698039), (0.133333), (0.133333)); public static C4d FloralWhite => new C4d((1), (0.980392), (0.941176)); public static C4d ForestGreen => new C4d((0.133333), (0.545098), (0.133333)); public static C4d Fuchsia => new C4d((1), (0), (1)); public static C4d Gainsboro => new C4d((0.862745), (0.862745), (0.862745)); public static C4d GhostWhite => new C4d((0.972549), (0.972549), (1)); public static C4d Gold => new C4d((1), (0.843137), (0)); public static C4d GoldenRod => new C4d((0.854902), (0.647059), (0.12549)); public static C4d Gray => new C4d((0.501961), (0.501961), (0.501961)); public static C4d Grey => new C4d((0.501961), (0.501961), (0.501961)); public static C4d Green => new C4d((0), (0.501961), (0)); public static C4d GreenYellow => new C4d((0.678431), (1), (0.184314)); public static C4d HoneyDew => new C4d((0.941176), (1), (0.941176)); public static C4d HotPink => new C4d((1), (0.411765), (0.705882)); public static C4d IndianRed => new C4d((0.803922), (0.360784), (0.360784)); public static C4d Indigo => new C4d((0.294118), (0), (0.509804)); public static C4d Ivory => new C4d((1), (1), (0.941176)); public static C4d Khaki => new C4d((0.941176), (0.901961), (0.54902)); public static C4d Lavender => new C4d((0.901961), (0.901961), (0.980392)); public static C4d LavenderBlush => new C4d((1), (0.941176), (0.960784)); public static C4d LawnGreen => new C4d((0.486275), (0.988235), (0)); public static C4d LemonChiffon => new C4d((1), (0.980392), (0.803922)); public static C4d LightBlue => new C4d((0.678431), (0.847059), (0.901961)); public static C4d LightCoral => new C4d((0.941176), (0.501961), (0.501961)); public static C4d LightCyan => new C4d((0.878431), (1), (1)); public static C4d LightGoldenRodYellow => new C4d((0.980392), (0.980392), (0.823529)); public static C4d LightGray => new C4d((0.827451), (0.827451), (0.827451)); public static C4d LightGrey => new C4d((0.827451), (0.827451), (0.827451)); public static C4d LightGreen => new C4d((0.564706), (0.933333), (0.564706)); public static C4d LightPink => new C4d((1), (0.713725), (0.756863)); public static C4d LightSalmon => new C4d((1), (0.627451), (0.478431)); public static C4d LightSeaGreen => new C4d((0.12549), (0.698039), (0.666667)); public static C4d LightSkyBlue => new C4d((0.529412), (0.807843), (0.980392)); public static C4d LightSlateGray => new C4d((0.466667), (0.533333), (0.6)); public static C4d LightSlateGrey => new C4d((0.466667), (0.533333), (0.6)); public static C4d LightSteelBlue => new C4d((0.690196), (0.768627), (0.870588)); public static C4d LightYellow => new C4d((1), (1), (0.878431)); public static C4d Lime => new C4d((0), (1), (0)); public static C4d LimeGreen => new C4d((0.196078), (0.803922), (0.196078)); public static C4d Linen => new C4d((0.980392), (0.941176), (0.901961)); public static C4d Magenta => new C4d((1), (0), (1)); public static C4d Maroon => new C4d((0.501961), (0), (0)); public static C4d MediumAquaMarine => new C4d((0.4), (0.803922), (0.666667)); public static C4d MediumBlue => new C4d((0), (0), (0.803922)); public static C4d MediumOrchid => new C4d((0.729412), (0.333333), (0.827451)); public static C4d MediumPurple => new C4d((0.576471), (0.439216), (0.847059)); public static C4d MediumSeaGreen => new C4d((0.235294), (0.701961), (0.443137)); public static C4d MediumSlateBlue => new C4d((0.482353), (0.407843), (0.933333)); public static C4d MediumSpringGreen => new C4d((0), (0.980392), (0.603922)); public static C4d MediumTurquoise => new C4d((0.282353), (0.819608), (0.8)); public static C4d MediumVioletRed => new C4d((0.780392), (0.082353), (0.521569)); public static C4d MidnightBlue => new C4d((0.098039), (0.098039), (0.439216)); public static C4d MintCream => new C4d((0.960784), (1), (0.980392)); public static C4d MistyRose => new C4d((1), (0.894118), (0.882353)); public static C4d Moccasin => new C4d((1), (0.894118), (0.709804)); public static C4d NavajoWhite => new C4d((1), (0.870588), (0.678431)); public static C4d Navy => new C4d((0), (0), (0.501961)); public static C4d OldLace => new C4d((0.992157), (0.960784), (0.901961)); public static C4d Olive => new C4d((0.501961), (0.501961), (0)); public static C4d OliveDrab => new C4d((0.419608), (0.556863), (0.137255)); public static C4d Orange => new C4d((1), (0.647059), (0)); public static C4d OrangeRed => new C4d((1), (0.270588), (0)); public static C4d Orchid => new C4d((0.854902), (0.439216), (0.839216)); public static C4d PaleGoldenRod => new C4d((0.933333), (0.909804), (0.666667)); public static C4d PaleGreen => new C4d((0.596078), (0.984314), (0.596078)); public static C4d PaleTurquoise => new C4d((0.686275), (0.933333), (0.933333)); public static C4d PaleVioletRed => new C4d((0.847059), (0.439216), (0.576471)); public static C4d PapayaWhip => new C4d((1), (0.937255), (0.835294)); public static C4d PeachPuff => new C4d((1), (0.854902), (0.72549)); public static C4d Peru => new C4d((0.803922), (0.521569), (0.247059)); public static C4d Pink => new C4d((1), (0.752941), (0.796078)); public static C4d Plum => new C4d((0.866667), (0.627451), (0.866667)); public static C4d PowderBlue => new C4d((0.690196), (0.878431), (0.901961)); public static C4d Purple => new C4d((0.501961), (0), (0.501961)); public static C4d Red => new C4d((1), (0), (0)); public static C4d RosyBrown => new C4d((0.737255), (0.560784), (0.560784)); public static C4d RoyalBlue => new C4d((0.254902), (0.411765), (0.882353)); public static C4d SaddleBrown => new C4d((0.545098), (0.270588), (0.07451)); public static C4d Salmon => new C4d((0.980392), (0.501961), (0.447059)); public static C4d SandyBrown => new C4d((0.956863), (0.643137), (0.376471)); public static C4d SeaGreen => new C4d((0.180392), (0.545098), (0.341176)); public static C4d SeaShell => new C4d((1), (0.960784), (0.933333)); public static C4d Sienna => new C4d((0.627451), (0.321569), (0.176471)); public static C4d Silver => new C4d((0.752941), (0.752941), (0.752941)); public static C4d SkyBlue => new C4d((0.529412), (0.807843), (0.921569)); public static C4d SlateBlue => new C4d((0.415686), (0.352941), (0.803922)); public static C4d SlateGray => new C4d((0.439216), (0.501961), (0.564706)); public static C4d SlateGrey => new C4d((0.439216), (0.501961), (0.564706)); public static C4d Snow => new C4d((1), (0.980392), (0.980392)); public static C4d SpringGreen => new C4d((0), (1), (0.498039)); public static C4d SteelBlue => new C4d((0.27451), (0.509804), (0.705882)); public static C4d Tan => new C4d((0.823529), (0.705882), (0.54902)); public static C4d Teal => new C4d((0), (0.501961), (0.501961)); public static C4d Thistle => new C4d((0.847059), (0.74902), (0.847059)); public static C4d Tomato => new C4d((1), (0.388235), (0.278431)); public static C4d Turquoise => new C4d((0.25098), (0.878431), (0.815686)); public static C4d Violet => new C4d((0.933333), (0.509804), (0.933333)); public static C4d Wheat => new C4d((0.960784), (0.870588), (0.701961)); public static C4d White => new C4d((1), (1), (1)); public static C4d WhiteSmoke => new C4d((0.960784), (0.960784), (0.960784)); public static C4d Yellow => new C4d((1), (1), (0)); public static C4d YellowGreen => new C4d((0.603922), (0.803922), (0.196078)); public static C4d DarkYellow => Olive; public static C4d VRVisGreen => new C4d((0.698), (0.851), (0.008)); public static C4d Gray10 => new C4d((0.1)); public static C4d Gray20 => new C4d((0.2)); public static C4d Gray30 => new C4d((0.3)); public static C4d Gray40 => new C4d((0.4)); public static C4d Gray50 => new C4d((0.5)); public static C4d Gray60 => new C4d((0.6)); public static C4d Gray70 => new C4d((0.7)); public static C4d Gray80 => new C4d((0.8)); public static C4d Gray90 => new C4d((0.9)); #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(C4d a, C4d b) { return a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(C4d a, C4d b) { return a.R != b.R || a.G != b.G || a.B != b.B || a.A != b.A; } #endregion #region Color Arithmetic [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator +(C4d c0, C4b c1) { return new C4d( (double)(c0.R + Col.ByteToDouble(c1.R)), (double)(c0.G + Col.ByteToDouble(c1.G)), (double)(c0.B + Col.ByteToDouble(c1.B)), (double)(c0.A + Col.ByteToDouble(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator -(C4d c0, C4b c1) { return new C4d( (double)(c0.R - Col.ByteToDouble(c1.R)), (double)(c0.G - Col.ByteToDouble(c1.G)), (double)(c0.B - Col.ByteToDouble(c1.B)), (double)(c0.A - Col.ByteToDouble(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator +(C4d c0, C4us c1) { return new C4d( (double)(c0.R + Col.UShortToDouble(c1.R)), (double)(c0.G + Col.UShortToDouble(c1.G)), (double)(c0.B + Col.UShortToDouble(c1.B)), (double)(c0.A + Col.UShortToDouble(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator -(C4d c0, C4us c1) { return new C4d( (double)(c0.R - Col.UShortToDouble(c1.R)), (double)(c0.G - Col.UShortToDouble(c1.G)), (double)(c0.B - Col.UShortToDouble(c1.B)), (double)(c0.A - Col.UShortToDouble(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator +(C4d c0, C4ui c1) { return new C4d( (double)(c0.R + Col.UIntToDouble(c1.R)), (double)(c0.G + Col.UIntToDouble(c1.G)), (double)(c0.B + Col.UIntToDouble(c1.B)), (double)(c0.A + Col.UIntToDouble(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator -(C4d c0, C4ui c1) { return new C4d( (double)(c0.R - Col.UIntToDouble(c1.R)), (double)(c0.G - Col.UIntToDouble(c1.G)), (double)(c0.B - Col.UIntToDouble(c1.B)), (double)(c0.A - Col.UIntToDouble(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator +(C4d c0, C4f c1) { return new C4d( (double)(c0.R + (double)(c1.R)), (double)(c0.G + (double)(c1.G)), (double)(c0.B + (double)(c1.B)), (double)(c0.A + (double)(c1.A))); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator -(C4d c0, C4f c1) { return new C4d( (double)(c0.R - (double)(c1.R)), (double)(c0.G - (double)(c1.G)), (double)(c0.B - (double)(c1.B)), (double)(c0.A - (double)(c1.A))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator *(C4d col, double scalar) { return new C4d((double)(col.R * scalar), (double)(col.G * scalar), (double)(col.B * scalar), (double)(col.A * scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator *(double scalar, C4d col) { return new C4d((double)(scalar * col.R), (double)(scalar * col.G), (double)(scalar * col.B), (double)(scalar * col.A)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator /(C4d col, double scalar) { return new C4d((double)(col.R / scalar), (double)(col.G / scalar), (double)(col.B / scalar), (double)(col.A / scalar)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator /(double scalar, C4d col) { return new C4d((double)(scalar / col.R), (double)(scalar / col.G), (double)(scalar / col.B), (double)(scalar / col.A)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator *(C4d c0, C4d c1) { return new C4d((double)(c0.R * c1.R), (double)(c0.G * c1.G), (double)(c0.B * c1.B), (double)(c0.A * c1.A)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator /(C4d c0, C4d c1) { return new C4d((double)(c0.R / c1.R), (double)(c0.G / c1.G), (double)(c0.B / c1.B), (double)(c0.A / c1.A)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator +(C4d c0, C4d c1) { return new C4d(c0.R + c1.R, c0.G + c1.G, c0.B + c1.B, c0.A + c1.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator +(C4d col, double scalar) { return new C4d(col.R + scalar, col.G + scalar, col.B + scalar, col.A + scalar); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator +(double scalar, C4d col) => col + scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator -(C4d c0, C4d c1) { return new C4d(c0.R - c1.R, c0.G - c1.G, c0.B - c1.B, c0.A - c1.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator -(C4d col, double scalar) { return new C4d(col.R - scalar, col.G - scalar, col.B - scalar, col.A - scalar); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d operator -(double scalar, C4d col) { return new C4d(scalar - col.R, scalar - col.G, scalar - col.B, scalar - col.A); } /// /// Clamps the color channels to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clamp(double min, double max) { R = R.Clamp(min, max); G = G.Clamp(min, max); B = B.Clamp(min, max); } /// /// Returns a copy with the color channels clamped to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d Clamped(double min, double max) { return new C4d(R.Clamp(min, max), G.Clamp(min, max), B.Clamp(min, max), A); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |R| + |G| + |B|. The alpha channel is ignored. /// public readonly double Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Abs(R) + Fun.Abs(G) + Fun.Abs(B); } } /// /// Returns the Euclidean (or 2-) norm of the color. This is calculated /// as sqrt(R^2 + G^2 + B^2). The alpha channel is ignored. /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(R * R + G * G + B * B); } } /// /// Returns the infinite (or maximum) norm of the color. This is /// calculated as max(|R|, |G|, |B|). The alpha channel is ignored. /// public readonly double NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(Fun.Abs(R), Fun.Abs(G), Fun.Abs(B)); } } /// /// Returns the minimum norm of the color. This is calculated as /// min(|R|, |G|, |B|). The alpha channel is ignored. /// public readonly double NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(Fun.Abs(R), Fun.Abs(G), Fun.Abs(B)); } } #endregion #region Overrides public override readonly bool Equals(object other) => (other is C4d o) ? Equals(o) : false; public override readonly int GetHashCode() { return HashCode.GetCombined(R, G, B, A); } public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + R.ToString(null, CultureInfo.InvariantCulture) + ", " + G.ToString(null, CultureInfo.InvariantCulture) + ", " + B.ToString(null, CultureInfo.InvariantCulture) + ", " + A.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref C4d color, int i, double value) => { switch (i) { case 0: color.R = value; return; case 1: color.G = value; return; case 2: color.B = value; return; case 3: color.A = value; return; default: throw new IndexOutOfRangeException(); } }; [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d LinearInterp(double t, C4d a, C4d b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d LinearInterp(V4d t, C4d a, C4d b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d DivideByInt(C4d c, int x) => c / x; #endregion #region Parsing /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C4d.Zero otherwise. /// True on success, false otherwise. public static bool TryParse(Text t, out C4d result) { if (Col.TryParseHex(t, out C4b tmp)) { result = tmp.ToC4d(); return true; } else { bool success = true; double[] values = new double[4] { 1.0, 1.0, 1.0, 1.0 }; double parse(Text t) { if (!double.TryParse(t.ToString(), NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out double value)) success = false; return value; }; var count = t.NestedBracketSplitCount2(1); if (count == 3 || count == 4) t.NestedBracketSplit(1, parse, () => values); else success = false; result = success ? new C4d(values) : Zero; return success; } } /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, C4d.Zero otherwise. /// True on success, false otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParse(string s, out C4d result) => TryParse(new Text(s), out result); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C4d color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d Parse(string s) => Parse(new Text(s)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d Parse(Text t, int bracketLevel = 1) => t.NestedBracketSplit(bracketLevel, Text.Parse, C4d.Setter); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid C4d color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d Parse(Text t) => TryParse(t, out C4d result) ? result : throw new FormatException($"{t} is not a valid C4d color."); #endregion #region IFormattable Members public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + R.ToString(format, fp) + between + G.ToString(format, fp) + between + B.ToString(format, fp) + between + A.ToString(format, fp) + end; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(C4d other) { return R.Equals(other.R) && G.Equals(other.G) && B.Equals(other.B) && A.Equals(other.A); } #endregion #region IRGB Members double IRGB.Red { readonly get { return (R); } set { R = (value); } } double IRGB.Green { readonly get { return (G); } set { G = (value); } } double IRGB.Blue { readonly get { return (B); } set { B = (value); } } #endregion #region IOpacity Members [XmlIgnore] public double Opacity { readonly get { return (A); } set { A = (value); } } #endregion } public static partial class Fun { #region Interpolation /// /// Returns the linearly interpolated color between a and b. /// public static C4d Lerp(this double t, C4d a, C4d b) => new C4d(Lerp(t, a.R, b.R), Lerp(t, a.G, b.G), Lerp(t, a.B, b.B), Lerp(t, a.A, b.A)); /// /// Returns the linearly interpolated color between a and b. /// public static C4d Lerp(this V4d t, C4d a, C4d b) => new C4d(Lerp(t.X, a.R, b.R), Lerp(t.Y, a.G, b.G), Lerp(t.Z, a.B, b.B), Lerp(t.W, a.A, b.A)); #endregion #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this C4d a, C4d b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this C4d a, C4d b, double tolerance) { return ApproximateEquals(a.R, b.R, tolerance) && ApproximateEquals(a.G, b.G, tolerance) && ApproximateEquals(a.B, b.B, tolerance) && ApproximateEquals(a.A, b.A, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this C4d c, double epsilon) => Col.AllTiny(c, epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(C4d c) => c.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any component of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(C4d c) => c.IsNaN; /// /// Returns whether any component of the the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(C4d c) => c.IsInfinity; /// /// Returns whether any component of the the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(C4d c) => c.IsPositiveInfinity; /// /// Returns whether any component of the the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(C4d c) => c.IsNegativeInfinity; /// /// Returns whether all components of the the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(C4d c) => c.IsFinite; #endregion } public static partial class Col { #region ToHexString /// /// Returns the hexadecimal representation with format RRGGBBAA. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToHexString(this C4d c) => c.ToC4b().ToHexString(); #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C4d a, C4d b) { return (a.R < b.R && a.G < b.G && a.B < b.B && a.A < b.A); } /// /// Returns whether ALL elements of col are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this C4d col, double s) { return (col.R < s && col.G < s && col.B < s && col.A < s); } /// /// Returns whether a is Smaller ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(double s, C4d col) { return (s < col.R && s < col.G && s < col.B && s < col.A); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C4d a, C4d b) { return (a.R < b.R || a.G < b.G || a.B < b.B || a.A < b.A); } /// /// Returns whether AT LEAST ONE element of col is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this C4d col, double s) { return (col.R < s || col.G < s || col.B < s || col.A < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(double s, C4d col) { return (s < col.R || s < col.G || s < col.B || s < col.A); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C4d a, C4d b) { return (a.R > b.R && a.G > b.G && a.B > b.B && a.A > b.A); } /// /// Returns whether ALL elements of col are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this C4d col, double s) { return (col.R > s && col.G > s && col.B > s && col.A > s); } /// /// Returns whether a is Greater ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(double s, C4d col) { return (s > col.R && s > col.G && s > col.B && s > col.A); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C4d a, C4d b) { return (a.R > b.R || a.G > b.G || a.B > b.B || a.A > b.A); } /// /// Returns whether AT LEAST ONE element of col is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this C4d col, double s) { return (col.R > s || col.G > s || col.B > s || col.A > s); } /// /// Returns whether a is Greater AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(double s, C4d col) { return (s > col.R || s > col.G || s > col.B || s > col.A); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C4d a, C4d b) { return (a.R <= b.R && a.G <= b.G && a.B <= b.B && a.A <= b.A); } /// /// Returns whether ALL elements of col are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this C4d col, double s) { return (col.R <= s && col.G <= s && col.B <= s && col.A <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(double s, C4d col) { return (s <= col.R && s <= col.G && s <= col.B && s <= col.A); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C4d a, C4d b) { return (a.R <= b.R || a.G <= b.G || a.B <= b.B || a.A <= b.A); } /// /// Returns whether AT LEAST ONE element of col is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this C4d col, double s) { return (col.R <= s || col.G <= s || col.B <= s || col.A <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(double s, C4d col) { return (s <= col.R || s <= col.G || s <= col.B || s <= col.A); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C4d a, C4d b) { return (a.R >= b.R && a.G >= b.G && a.B >= b.B && a.A >= b.A); } /// /// Returns whether ALL elements of col are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this C4d col, double s) { return (col.R >= s && col.G >= s && col.B >= s && col.A >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(double s, C4d col) { return (s >= col.R && s >= col.G && s >= col.B && s >= col.A); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C4d a, C4d b) { return (a.R >= b.R || a.G >= b.G || a.B >= b.B || a.A >= b.A); } /// /// Returns whether AT LEAST ONE element of col is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this C4d col, double s) { return (col.R >= s || col.G >= s || col.B >= s || col.A >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(double s, C4d col) { return (s >= col.R || s >= col.G || s >= col.B || s >= col.A); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C4d a, C4d b) { return (a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A); } /// /// Returns whether ALL elements of col are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this C4d col, double s) { return (col.R == s && col.G == s && col.B == s && col.A == s); } /// /// Returns whether a is Equal ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(double s, C4d col) { return (s == col.R && s == col.G && s == col.B && s == col.A); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C4d a, C4d b) { return (a.R == b.R || a.G == b.G || a.B == b.B || a.A == b.A); } /// /// Returns whether AT LEAST ONE element of col is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this C4d col, double s) { return (col.R == s || col.G == s || col.B == s || col.A == s); } /// /// Returns whether a is Equal AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(double s, C4d col) { return (s == col.R || s == col.G || s == col.B || s == col.A); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C4d a, C4d b) { return (a.R != b.R && a.G != b.G && a.B != b.B && a.A != b.A); } /// /// Returns whether ALL elements of col are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this C4d col, double s) { return (col.R != s && col.G != s && col.B != s && col.A != s); } /// /// Returns whether a is Different ALL elements of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(double s, C4d col) { return (s != col.R && s != col.G && s != col.B && s != col.A); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C4d a, C4d b) { return (a.R != b.R || a.G != b.G || a.B != b.B || a.A != b.A); } /// /// Returns whether AT LEAST ONE element of col is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this C4d col, double s) { return (col.R != s || col.G != s || col.B != s || col.A != s); } /// /// Returns whether a is Different AT LEAST ONE element of col. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(double s, C4d col) { return (s != col.R || s != col.G || s != col.B || s != col.A); } #endregion #region Linear Combination /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d LinCom( C4d p0, C4d p1, C4d p2, C4d p3, ref Tup4 w) { return new C4d( (p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3), (p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3), (p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3)); } /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d LinCom( C4d p0, C4d p1, C4d p2, C4d p3, C4d p4, C4d p5, ref Tup6 w) { return new C4d( (p0.R * w.E0 + p1.R * w.E1 + p2.R * w.E2 + p3.R * w.E3 + p4.R * w.E4 + p5.R * w.E5), (p0.G * w.E0 + p1.G * w.E1 + p2.G * w.E2 + p3.G * w.E3 + p4.G * w.E4 + p5.G * w.E5), (p0.B * w.E0 + p1.B * w.E1 + p2.B * w.E2 + p3.B * w.E3 + p4.B * w.E4 + p5.B * w.E5)); } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this C4d c, double epsilon) => c.R.IsTiny(epsilon) || c.G.IsTiny(epsilon) || c.B.IsTiny(epsilon) || c.A.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this C4d c, double epsilon) => c.R.IsTiny(epsilon) && c.G.IsTiny(epsilon) && c.B.IsTiny(epsilon) && c.A.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(C4d c) => c.AnyNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(C4d c) => c.AllNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(C4d c) => c.AnyInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(C4d c) => c.AllInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(C4d c) => c.AnyPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(C4d c) => c.AllPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(C4d c) => c.AnyNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(C4d c) => c.AllNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(C4d c) => c.AnyTiny; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(C4d c) => c.AllTiny; #endregion } public static class IRandomUniformC4dExtensions { #region IRandomUniform extensions for C4d /// /// Uses UniformDouble() to generate the elements of a C4d color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d UniformC4d(this IRandomUniform rnd) { return new C4d(rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble()); } /// /// Uses UniformDoubleClosed() to generate the elements of a C4d color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d UniformC4dClosed(this IRandomUniform rnd) { return new C4d(rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed()); } /// /// Uses UniformDoubleOpen() to generate the elements of a C4d color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d UniformC4dOpen(this IRandomUniform rnd) { return new C4d(rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen()); } /// /// Uses UniformDoubleFull() to generate the elements of a C4d color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d UniformC4dFull(this IRandomUniform rnd) { return new C4d(rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull()); } /// /// Uses UniformDoubleFullClosed() to generate the elements of a C4d color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d UniformC4dFullClosed(this IRandomUniform rnd) { return new C4d(rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed()); } /// /// Uses UniformDoubleFullOpen() to generate the elements of a C4d color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static C4d UniformC4dFullOpen(this IRandomUniform rnd) { return new C4d(rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen()); } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Colors/Color_template.cs ================================================ using System; using System.Globalization; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# var ColorNames //# = new Dictionary() //# { //# { "AliceBlue", new V3d(0.941176, 0.972549, 1.000000) }, //# { "AntiqueWhite", new V3d(0.980392, 0.921569, 0.843137) }, //# { "Aqua", new V3d(0.000000, 1.000000, 1.000000) }, //# { "Aquamarine", new V3d(0.498039, 1.000000, 0.831373) }, //# { "Azure", new V3d(0.941176, 1.000000, 1.000000) }, //# { "Beige", new V3d(0.960784, 0.960784, 0.862745) }, //# { "Bisque", new V3d(1.000000, 0.894118, 0.768627) }, //# { "Black", new V3d(0.000000, 0.000000, 0.000000) }, //# { "BlanchedAlmond", new V3d(1.000000, 0.921569, 0.803922) }, //# { "Blue", new V3d(0.000000, 0.000000, 1.000000) }, //# { "BlueViolet", new V3d(0.541176, 0.168627, 0.886275) }, //# { "Brown", new V3d(0.647059, 0.164706, 0.164706) }, //# { "BurlyWood", new V3d(0.870588, 0.721569, 0.529412) }, //# { "CadetBlue", new V3d(0.372549, 0.619608, 0.627451) }, //# { "Chartreuse", new V3d(0.498039, 1.000000, 0.000000) }, //# { "Chocolate", new V3d(0.823529, 0.411765, 0.117647) }, //# { "Coral", new V3d(1.000000, 0.498039, 0.313725) }, //# { "CornflowerBlue", new V3d(0.392157, 0.584314, 0.929412) }, //# { "Cornsilk", new V3d(1.000000, 0.972549, 0.862745) }, //# { "Crimson", new V3d(0.862745, 0.078431, 0.235294) }, //# { "Cyan", new V3d(0.000000, 1.000000, 1.000000) }, //# { "DarkBlue", new V3d(0.000000, 0.000000, 0.545098) }, //# { "DarkCyan", new V3d(0.000000, 0.545098, 0.545098) }, //# { "DarkGoldenRod", new V3d(0.721569, 0.525490, 0.043137) }, //# { "DarkGray", new V3d(0.662745, 0.662745, 0.662745) }, //# { "DarkGrey", new V3d(0.662745, 0.662745, 0.662745) }, //# { "DarkGreen", new V3d(0.000000, 0.392157, 0.000000) }, //# { "DarkKhaki", new V3d(0.741176, 0.717647, 0.419608) }, //# { "DarkMagenta", new V3d(0.545098, 0.000000, 0.545098) }, //# { "DarkOliveGreen", new V3d(0.333333, 0.419608, 0.184314) }, //# { "DarkOrange", new V3d(1.000000, 0.549020, 0.000000) }, //# { "DarkOrchid", new V3d(0.600000, 0.196078, 0.800000) }, //# { "DarkRed", new V3d(0.545098, 0.000000, 0.000000) }, //# { "DarkSalmon", new V3d(0.913725, 0.588235, 0.478431) }, //# { "DarkSeaGreen", new V3d(0.560784, 0.737255, 0.560784) }, //# { "DarkSlateBlue", new V3d(0.282353, 0.239216, 0.545098) }, //# { "DarkSlateGray", new V3d(0.184314, 0.309804, 0.309804) }, //# { "DarkSlateGrey", new V3d(0.184314, 0.309804, 0.309804) }, //# { "DarkTurquoise", new V3d(0.000000, 0.807843, 0.819608) }, //# { "DarkViolet", new V3d(0.580392, 0.000000, 0.827451) }, //# { "DeepPink", new V3d(1.000000, 0.078431, 0.576471) }, //# { "DeepSkyBlue", new V3d(0.000000, 0.749020, 1.000000) }, //# { "DimGray", new V3d(0.411765, 0.411765, 0.411765) }, //# { "DimGrey", new V3d(0.411765, 0.411765, 0.411765) }, //# { "DodgerBlue", new V3d(0.117647, 0.564706, 1.000000) }, //# { "FireBrick", new V3d(0.698039, 0.133333, 0.133333) }, //# { "FloralWhite", new V3d(1.000000, 0.980392, 0.941176) }, //# { "ForestGreen", new V3d(0.133333, 0.545098, 0.133333) }, //# { "Fuchsia", new V3d(1.000000, 0.000000, 1.000000) }, //# { "Gainsboro", new V3d(0.862745, 0.862745, 0.862745) }, //# { "GhostWhite", new V3d(0.972549, 0.972549, 1.000000) }, //# { "Gold", new V3d(1.000000, 0.843137, 0.000000) }, //# { "GoldenRod", new V3d(0.854902, 0.647059, 0.125490) }, //# { "Gray", new V3d(0.501961, 0.501961, 0.501961) }, //# { "Grey", new V3d(0.501961, 0.501961, 0.501961) }, //# { "Green", new V3d(0.000000, 0.501961, 0.000000) }, //# { "GreenYellow", new V3d(0.678431, 1.000000, 0.184314) }, //# { "HoneyDew", new V3d(0.941176, 1.000000, 0.941176) }, //# { "HotPink", new V3d(1.000000, 0.411765, 0.705882) }, //# { "IndianRed ", new V3d(0.803922, 0.360784, 0.360784) }, //# { "Indigo ", new V3d(0.294118, 0.000000, 0.509804) }, //# { "Ivory", new V3d(1.000000, 1.000000, 0.941176) }, //# { "Khaki", new V3d(0.941176, 0.901961, 0.549020) }, //# { "Lavender", new V3d(0.901961, 0.901961, 0.980392) }, //# { "LavenderBlush", new V3d(1.000000, 0.941176, 0.960784) }, //# { "LawnGreen", new V3d(0.486275, 0.988235, 0.000000) }, //# { "LemonChiffon", new V3d(1.000000, 0.980392, 0.803922) }, //# { "LightBlue", new V3d(0.678431, 0.847059, 0.901961) }, //# { "LightCoral", new V3d(0.941176, 0.501961, 0.501961) }, //# { "LightCyan", new V3d(0.878431, 1.000000, 1.000000) }, //# { "LightGoldenRodYellow", new V3d(0.980392, 0.980392, 0.823529) }, //# { "LightGray", new V3d(0.827451, 0.827451, 0.827451) }, //# { "LightGrey", new V3d(0.827451, 0.827451, 0.827451) }, //# { "LightGreen", new V3d(0.564706, 0.933333, 0.564706) }, //# { "LightPink", new V3d(1.000000, 0.713725, 0.756863) }, //# { "LightSalmon", new V3d(1.000000, 0.627451, 0.478431) }, //# { "LightSeaGreen", new V3d(0.125490, 0.698039, 0.666667) }, //# { "LightSkyBlue", new V3d(0.529412, 0.807843, 0.980392) }, //# { "LightSlateGray", new V3d(0.466667, 0.533333, 0.600000) }, //# { "LightSlateGrey", new V3d(0.466667, 0.533333, 0.600000) }, //# { "LightSteelBlue", new V3d(0.690196, 0.768627, 0.870588) }, //# { "LightYellow", new V3d(1.000000, 1.000000, 0.878431) }, //# { "Lime", new V3d(0.000000, 1.000000, 0.000000) }, //# { "LimeGreen", new V3d(0.196078, 0.803922, 0.196078) }, //# { "Linen", new V3d(0.980392, 0.941176, 0.901961) }, //# { "Magenta", new V3d(1.000000, 0.000000, 1.000000) }, //# { "Maroon", new V3d(0.501961, 0.000000, 0.000000) }, //# { "MediumAquaMarine", new V3d(0.400000, 0.803922, 0.666667) }, //# { "MediumBlue", new V3d(0.000000, 0.000000, 0.803922) }, //# { "MediumOrchid", new V3d(0.729412, 0.333333, 0.827451) }, //# { "MediumPurple", new V3d(0.576471, 0.439216, 0.847059) }, //# { "MediumSeaGreen", new V3d(0.235294, 0.701961, 0.443137) }, //# { "MediumSlateBlue", new V3d(0.482353, 0.407843, 0.933333) }, //# { "MediumSpringGreen", new V3d(0.000000, 0.980392, 0.603922) }, //# { "MediumTurquoise", new V3d(0.282353, 0.819608, 0.800000) }, //# { "MediumVioletRed", new V3d(0.780392, 0.082353, 0.521569) }, //# { "MidnightBlue", new V3d(0.098039, 0.098039, 0.439216) }, //# { "MintCream", new V3d(0.960784, 1.000000, 0.980392) }, //# { "MistyRose", new V3d(1.000000, 0.894118, 0.882353) }, //# { "Moccasin", new V3d(1.000000, 0.894118, 0.709804) }, //# { "NavajoWhite", new V3d(1.000000, 0.870588, 0.678431) }, //# { "Navy", new V3d(0.000000, 0.000000, 0.501961) }, //# { "OldLace", new V3d(0.992157, 0.960784, 0.901961) }, //# { "Olive", new V3d(0.501961, 0.501961, 0.000000) }, //# { "OliveDrab", new V3d(0.419608, 0.556863, 0.137255) }, //# { "Orange", new V3d(1.000000, 0.647059, 0.000000) }, //# { "OrangeRed", new V3d(1.000000, 0.270588, 0.000000) }, //# { "Orchid", new V3d(0.854902, 0.439216, 0.839216) }, //# { "PaleGoldenRod", new V3d(0.933333, 0.909804, 0.666667) }, //# { "PaleGreen", new V3d(0.596078, 0.984314, 0.596078) }, //# { "PaleTurquoise", new V3d(0.686275, 0.933333, 0.933333) }, //# { "PaleVioletRed", new V3d(0.847059, 0.439216, 0.576471) }, //# { "PapayaWhip", new V3d(1.000000, 0.937255, 0.835294) }, //# { "PeachPuff", new V3d(1.000000, 0.854902, 0.725490) }, //# { "Peru", new V3d(0.803922, 0.521569, 0.247059) }, //# { "Pink", new V3d(1.000000, 0.752941, 0.796078) }, //# { "Plum", new V3d(0.866667, 0.627451, 0.866667) }, //# { "PowderBlue", new V3d(0.690196, 0.878431, 0.901961) }, //# { "Purple", new V3d(0.501961, 0.000000, 0.501961) }, //# { "Red", new V3d(1.000000, 0.000000, 0.000000) }, //# { "RosyBrown", new V3d(0.737255, 0.560784, 0.560784) }, //# { "RoyalBlue", new V3d(0.254902, 0.411765, 0.882353) }, //# { "SaddleBrown", new V3d(0.545098, 0.270588, 0.074510) }, //# { "Salmon", new V3d(0.980392, 0.501961, 0.447059) }, //# { "SandyBrown", new V3d(0.956863, 0.643137, 0.376471) }, //# { "SeaGreen", new V3d(0.180392, 0.545098, 0.341176) }, //# { "SeaShell", new V3d(1.000000, 0.960784, 0.933333) }, //# { "Sienna", new V3d(0.627451, 0.321569, 0.176471) }, //# { "Silver", new V3d(0.752941, 0.752941, 0.752941) }, //# { "SkyBlue", new V3d(0.529412, 0.807843, 0.921569) }, //# { "SlateBlue", new V3d(0.415686, 0.352941, 0.803922) }, //# { "SlateGray", new V3d(0.439216, 0.501961, 0.564706) }, //# { "SlateGrey", new V3d(0.439216, 0.501961, 0.564706) }, //# { "Snow", new V3d(1.000000, 0.980392, 0.980392) }, //# { "SpringGreen", new V3d(0.000000, 1.000000, 0.498039) }, //# { "SteelBlue", new V3d(0.274510, 0.509804, 0.705882) }, //# { "Tan", new V3d(0.823529, 0.705882, 0.549020) }, //# { "Teal", new V3d(0.000000, 0.501961, 0.501961) }, //# { "Thistle", new V3d(0.847059, 0.749020, 0.847059) }, //# { "Tomato", new V3d(1.000000, 0.388235, 0.278431) }, //# { "Turquoise", new V3d(0.250980, 0.878431, 0.815686) }, //# { "Violet", new V3d(0.933333, 0.509804, 0.933333) }, //# { "Wheat", new V3d(0.960784, 0.870588, 0.701961) }, //# { "White", new V3d(1.000000, 1.000000, 1.000000) }, //# { "WhiteSmoke", new V3d(0.960784, 0.960784, 0.960784) }, //# { "Yellow", new V3d(1.000000, 1.000000, 0.000000) }, //# { "YellowGreen", new V3d(0.603922, 0.803922, 0.196078) }, //# }; //# //# Action andand = () => Out(" && "); //# Action add = () => Out(" + "); //# Action addbetween = () => Out(" + between "); //# Action addqcommaspace = () => Out(" + \", \" "); //# Action comma = () => Out(", "); //# Action oror = () => Out(" || "); //# Action semicolon = () => Out("; "); //# Action xor = () => Out(" ^ "); //# //# Func ismapped = //# (t1, t2) => (t1 != t2) && !(t1.IsReal && t2.IsReal); //# Func isclamped = //# (t1, t2) => t1.IsReal && !t2.IsReal; //# //# Func coltovecsupported = //# (cft, vft) => (!cft.IsReal || vft.IsReal) && (cft != Meta.UIntType || vft != Meta.IntType); //# //# var f_to_ft_map = new Dictionary //# { //# { Meta.ByteType, "Col.FloatToByteClamped" }, //# { Meta.UShortType, "Col.FloatToUShortClamped" }, //# { Meta.UIntType, "Col.FloatToUIntClamped" }, //# { Meta.FloatType, "" }, //# { Meta.DoubleType, "(double)" }, //# }; //# var d_to_ft_map = new Dictionary //# { //# { Meta.ByteType, "Col.DoubleToByteClamped" }, //# { Meta.UShortType, "Col.DoubleToUShortClamped" }, //# { Meta.UIntType, "Col.DoubleToUIntClamped" }, //# { Meta.FloatType, "(float)" }, //# { Meta.DoubleType, "" }, //# }; //# var ft_to_f_map = new Dictionary //# { //# { Meta.ByteType, "Col.ByteToFloat" }, //# { Meta.UShortType, "Col.UShortToFloat" }, //# { Meta.UIntType, "Col.UIntToFloat" }, //# { Meta.FloatType, "" }, //# { Meta.DoubleType, "(float)" }, //# }; //# var ft_to_d_map = new Dictionary //# { //# { Meta.ByteType, "Col.ByteToDouble" }, //# { Meta.UShortType, "Col.UShortToDouble" }, //# { Meta.UIntType, "Col.UIntToDouble" }, //# { Meta.FloatType, "(double)" }, //# { Meta.DoubleType, "" }, //# }; //# var maxvalmap = new Dictionary //# { //# { Meta.ByteType, "255" }, //# { Meta.UShortType, "2^16 - 1" }, //# { Meta.UIntType, "2^32 - 1" }, //# { Meta.FloatType, "1" }, //# { Meta.DoubleType, "1" }, //# }; //# var fdtypes = new[] { Meta.FloatType, Meta.DoubleType }; //# foreach (var t in Meta.ColorTypes) { //# var type = t.Name; //# var ft = t.FieldType; //# var ht = (ft != Meta.FloatType) ? Meta.HighPrecisionTypeOf(ft) : ft; //# var ct = Meta.ComputationTypeOf(ft); //# var htype = ht.Name; //# var ctype = ct.Name; //# var hnd = ht != Meta.DoubleType; // high not double //# var dblt = Meta.ColorTypeOf(t.Len, Meta.DoubleType); //# var dbltype = dblt.Name; //# var fltt = Meta.ColorTypeOf(t.Len, Meta.FloatType); //# var flttype = fltt.Name; //# var isByte = ft == Meta.ByteType; //# var isUShort = ft == Meta.UShortType; //# var isFloat = ft == Meta.FloatType; //# var isDouble = ft == Meta.DoubleType; //# var isReal = ft.IsReal; //# var ftype = ft.Name; //# var fcaps = ft.Caps; //# var fields = t.Fields; //# var dim = fields.Length; //# var channels = t.Channels; //# var args = fields.ToLower(); //# var cargs = channels.ToLower(); //# var f_to_ft = f_to_ft_map[ft]; //# var d_to_ft = d_to_ft_map[ft]; //# var ft_to_f = ft_to_f_map[ft]; //# var ft_to_d = ft_to_d_map[ft]; //# var fabs_p = isReal ? "Fun.Abs(" : ""; //# var q_fabs = isReal ? ")" : ""; //# var getptr = "&" + ((ft == Meta.ByteType) ? fields[2] : fields[0]); //# var rgba = t.HasAlpha ? "RGBA" : "RGB"; //# var maxval = maxvalmap[ft]; //# var parseNumberStyle = isReal ? "NumberStyles.Float | NumberStyles.AllowThousands" : "NumberStyles.Integer"; #region __type__ /// /// Represents an __rgba__ color with each channel stored as a value within [0, __maxval__]. /// [Serializable] public partial struct __type__ : IFormattable, IEquatable<__type__>, IRGB/*# if (t.HasAlpha) { */, IOpacity/*# } */ { #region Constructors /// /// Creates a color from the given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(/*# args.ForEach(a => { */__ftype__ __a__/*# }, comma); */) { /*# fields.ForEach(args, (f,a) => { */__f__ = __a__/*# }, semicolon); */; } //# if (!isReal) { /// /// Creates a color from the given values. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(/*# args.ForEach(a => { */int __a__/*# }, comma); */) { /*# fields.ForEach(args, (f,a) => { */__f__ = (__ftype__)__a__/*# }, semicolon); */; } /// /// Creates a color from the given values. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(/*# args.ForEach(a => { */long __a__/*# }, comma); */) { /*# fields.ForEach(args, (f,a) => { */__f__ = (__ftype__)__a__/*# }, semicolon); */; } //# } //# if (!isFloat) { /// /// Creates a color from the given values. //# if (!isDouble) { /// The values are mapped and clamped from [0, 1] to the color range. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(/*# args.ForEach(a => { */float __a__/*# }, comma); */) { //# fields.ForEach(args, (f,a) => { __f__ = __f_to_ft__(__a__); //# }); } //# } //# if (!isDouble) { /// /// Creates a color from the given values. //# if (!isFloat) { /// The values are mapped and clamped from [0, 1] to the color range. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(/*# args.ForEach(a => { */double __a__/*# }, comma); */) { //# fields.ForEach(args, (f,a) => { __f__ = __d_to_ft__(__a__); //# }); } //# } //# if (t.HasAlpha) { /// /// Creates a color from the given RGB values. /// The alpha channel is set to __maxval__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(/*# cargs.ForEach(a => { */__ftype__ __a__/*# }, comma); */) { /*# channels.ForEach(args, (c, a) => { */__c__ = __a__/*# }, semicolon); */; A = __t.MaxValue__; } //# if (!isReal) { /// /// Creates a color from the given RGB values. /// The values are not mapped to the color range. /// The alpha channel is set to __maxval__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(/*# cargs.ForEach(a => { */int __a__/*# }, comma); */) { /*# channels.ForEach(args, (c, a) => { */__c__ = (__ftype__)__a__/*# }, semicolon); */; A = __t.MaxValue__; } /// /// Creates a color from the given RGB values. /// The values are not mapped to the color range. /// The alpha channel is set to __maxval__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(/*# cargs.ForEach(a => { */long __a__/*# }, comma); */) { /*# channels.ForEach(args, (c, a) => { */__c__ = (__ftype__)__a__/*# }, semicolon); */; A = __t.MaxValue__; } //# } //# if (!isFloat) { /// /// Creates a color from the given RGB values. //# if (!isDouble) { /// The values are mapped and clamped from [0, 1] to the color range. //# } /// The alpha channel is set to __maxval__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(/*# cargs.ForEach(a => { */float __a__/*# }, comma); */) { /*# channels.ForEach(args, (c,a) => { */ __c__ = __f_to_ft__(__a__)/*# }, semicolon); */; A = __t.MaxValue__; } //# } //# if (!isDouble) { /// /// Creates a color from the given RGB values. //# if (!isFloat) { /// The values are mapped and clamped from [0, 1] to the color range. //# } /// The alpha channel is set to __maxval__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(/*# cargs.ForEach(a => { */double __a__/*# }, comma); */) { /*# channels.ForEach(args, (c,a) => { */__c__ = __d_to_ft__(__a__)/*# }, semicolon); */; A = __t.MaxValue__; } //# } //# } // t.HasAlpha /// /// Creates a color from a single value. //# if (t.HasAlpha) { /// The alpha channel is set to __maxval__. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__ gray) { /*# channels.ForEach( c => { */__c__ = gray/*# }, semicolon); if (t.HasAlpha) {*/; A = __t.MaxValue__/*# } */; } //# foreach (var ft1 in Meta.RealTypes) { if (ft != ft1) { //# var ftype1 = ft1.Name; //# var convert = (ft1 == Meta.DoubleType) ? d_to_ft : f_to_ft; /// /// Creates a color from a single value. //# if (ismapped(ft, ft1)) { /// The value is mapped and clamped from [0, 1] to the color range. //# } //# if (t.HasAlpha) { /// The alpha channel is set to __maxval__. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype1__ gray) { var value = __convert__(gray); /*# channels.ForEach( c => { */__c__ = value/*# }, semicolon); if (t.HasAlpha) {*/; A = __t.MaxValue__/*# } */; } //# } } //# foreach (var t1 in Meta.ColorTypes) { //# var ft1 = t1.FieldType; //# var convert = t.FieldType != t1.FieldType //# ? "Col." + t1.FieldType.Caps + "To" + t.FieldType.Caps + (isclamped(ft1, ft) ? "Clamped" : "") //# : ""; /// /// Creates a color from the given color. //# if (ismapped(ft1, ft)) { //# if (isclamped(ft1, ft)) { /// The values are mapped and clamped to the color range. //# } else { /// The values are mapped to the color range. //# } //# } //# if (t.HasAlpha && !t1.HasAlpha) { /// The alpha channel is set to __maxval__. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__t1.Name__ color) { //# channels.ForEach(c => { __c__ = __convert__(color.__c__); //# }); //# if (t.HasAlpha) { //# if (t1.HasAlpha) { A = __convert__(color.A); //# } else { A = __t.MaxValue__; //# } //# } } //#if (t.HasAlpha && !t1.HasAlpha) { // build constructor from Color3 with explicit alpha /// /// Creates a color from the given color and an alpha value. //# if (ismapped(ft1, ft)) { //# if (isclamped(ft1, ft)) { /// The values are mapped and clamped to the color range. //# } else { /// The values are mapped to the color range. //# } //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__t1.Name__ color, __ftype__ alpha) { //# channels.ForEach(Meta.VecFields, (c, vf) => { __c__ = __convert__(color.__c__); //# }); A = alpha; } //# } //# } // end For //# for (int d = 3; d <= 4; d++) { //# foreach (var vft in Meta.VecFieldTypes) { if (coltovecsupported(ft, vft)) { //# var vt = Meta.VecTypeOf(d, vft); //# var convert = ft != vft //# ? "("+ ft.Name+")" //# : ""; /// /// Creates a color from the given vector. //# if (ismapped(ft, vft)) { /// The values are not mapped to the color range. //# } //# if (d < dim) { /// The alpha channel is set to __maxval__. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__vt.Name__ vec) { //# fields.ForEach(Meta.VecFields, (c, vf, i) => { __c__ = /*# if (i < d) { */__convert__(vec.__vf__);/*# } else {*/__t.MaxValue__;/*# }*/ //# }); } //# } } } //# if (t.HasAlpha) { //# foreach (var vft in Meta.VecFieldTypes) { if (coltovecsupported(ft, vft)) { //# var vt = Meta.VecTypeOf(3, vft); //# var convert = ft != vft //# ? "("+ ft.Name+")" //# : ""; /// /// Creates a color from the given vector and an alpha value. //# if (ismapped(ft, vft)) { /// The values are not mapped to the color range. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__vt.Name__ vec, __ftype__ alpha) { //# channels.ForEach(Meta.VecFields, (c, vf) => { __c__ = __convert__(vec.__vf__); //# }); A = alpha; } //# } } } /// /// Creates a color from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(Func index_fun) { //# fields.ForEach((f, fi) => { __f__ = index_fun(__fi__); //# }); } //# foreach (var ft1 in Meta.ColorFieldTypes) { //# var ftype1 = ft1.Name; //# var convert = ft != ft1 //# ? "Col." + ft1.Caps + "To" + ft.Caps + (isclamped(ft1, ft) ? "Clamped" : "") //# : ""; /// /// Creates a new color from the given array. //# if (ismapped(ft1, ft)) { //# if (isclamped(ft1, ft)) { /// The values are mapped and clamped to the color range. //# } else { /// The values are mapped to the color range. //# } //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype1__[] values) { //# fields.ForEach((f, i) => { __f__ = __convert__(values[__i__]); //# }); } /// /// Creates a new color from the given array, starting at the specified index. //# if (ismapped(ft1, ft)) { //# if (isclamped(ft1, ft)) { /// The values are mapped and clamped to the color range. //# } else { /// The values are mapped to the color range. //# } //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype1__[] values, int start) { //# fields.ForEach((f, i) => { __f__ = __convert__(values[start + __i__]); //# }); } //# } #endregion //# if (t.HasAlpha || isReal) { #region Properities //# if (t.HasAlpha) { //# var t1 = Meta.ColorTypeOf(3, ft); //# var type1 = t1.Name; public readonly __type1__ RGB => (__type1__)this; //# } //# if (isReal) { //# var condArray = new[] { "NaN", "Infinity", "PositiveInfinity", "NegativeInfinity", "Tiny" }; //# var scopeArray = new[] { ftype, ftype, ftype, ftype, "Fun" }; //# var quantArray = new[] { "Any", "All" }; //# var actArray = new[] { oror, andand }; //# condArray.ForEach(scopeArray, (cond, scope) => { //# quantArray.ForEach(actArray, (qant, act) => { public readonly bool __qant____cond__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => /*# fields.ForEach((f, i) => { */__scope__.Is__cond__(__f__)/*# }, act); */; } //# }); // quantArray //# }); // condArray /// /// Returns true if the absolute value of each component of the color is smaller than Constant<__ftype__>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any component of the color is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any component of the color is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any component of the color is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any component of the color is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all components of the color are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } //# } // isReal #endregion //# } #region Conversions //# foreach (var t1 in Meta.ColorTypes) if (t1 != t) { //# var type1 = t1.Name; /// /// Converts the given color to a color. //# if (ismapped(t1.FieldType, ft)) { //# if (isclamped(t1.FieldType, ft)) { /// The values are mapped and clamped to the color range. //# } else { /// The values are mapped to the color range. //# } //# } //# if (t.HasAlpha && !t1.HasAlpha) { /// The alpha channel is set to __maxvalmap[t.FieldType]__. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type__(__type1__ color) => new __type__(color); /// /// Converts the given color to a color. //# if (ismapped(ft, t1.FieldType)) { //# if (isclamped(ft, t1.FieldType)) { /// The values are mapped and clamped to the color range. //# } else { /// The values are mapped to the color range. //# } //# } //# if (t1.HasAlpha && !t.HasAlpha) { /// The alpha channel is set to __maxvalmap[t1.FieldType]__. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type1__ To__type1__() => (__type1__)this; /// /// Creates a color from the given color. //# if (ismapped(t1.FieldType, ft)) { //# if (isclamped(t1.FieldType, ft)) { /// The values are mapped and clamped to the color range. //# } else { /// The values are mapped to the color range. //# } //# } //# if (t.HasAlpha && !t1.HasAlpha) { /// The alpha channel is set to __maxval__. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__type1__(__type1__ c) => new __type__(c); //# } //# for (int d = 3; d <= 4; d++) { //# foreach (var vft in Meta.VecFieldTypes) { if (coltovecsupported(ft, vft)) { //# var vt = Meta.VecTypeOf(d, vft); //# var vtype = vt.Name; //# var convert = ft != vft ? "("+ vft.Name+")" : ""; /// /// Converts the given vector to a color. //# if (ismapped(ft, vft)) { /// The values are not mapped to the color range. //# } //# if (d == 3 && t.HasAlpha) { /// The alpha channel is set to __maxval__. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type__(__vtype__ v) => new __type__(v); /// /// Converts the given color to a vector. //# if (ismapped(ft, vft)) { /// The values are not mapped from the color range. //# } //# if (d == 4 && dim == 3) { /// W is set to __maxval__. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __vtype__ To__vtype__() => (__vtype__)this; /// /// Creates a color from a vector. //# if (ismapped(ft, vft)) { /// The values are not mapped to the color range. //# } //# if (d == 3 && t.HasAlpha) { /// The alpha channel is set to __maxval__. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__vtype__(__vtype__ c) => new __type__(c); //# } } //# } //# foreach (var ft1 in Meta.ColorFieldTypes) { //# var ftype1 = ft1.Name; //# var convert = ft != ft1 //# ? "Col." + ft.Caps + "To" + ft1.Caps + (isclamped(ft, ft1) ? "Clamped" : "") //# : ""; /// /// Creates a new color from the given array. //# if (ismapped(ft, ft1)) { /// The values are mapped to the color range. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type__(__ftype1__[] values) => new __type__(values); /// /// Creates a new array from the given color. //# if (ismapped(ft, ft1)) { //# if (isclamped(ft, ft1)) { /// The values are mapped and clamped from the color range. //# } else { /// The values are mapped from the color range. //# } //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __ftype1__[](__type__ color) => new __ftype1__[] { /*# fields.ForEach(f => {*/__convert__(color.__f__)/*# }, comma); */ }; //# } //# foreach (var t1 in Meta.ColorTypes) { //# if (t.Fields.Length != t1.Fields.Length) continue; //# var type1 = t1.Name; //# var ftype1 = t1.FieldType.Name; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type1__ Map(Func<__ftype__, __ftype1__> channel_fun) { return new __type1__(/*# fields.ForEach(f => { */channel_fun(__f__)/*# }, comma); */); } //# } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func<__ftype__, T> element_fun) { //# fields.ForEach((f, i) => { array[start + __i__] = element_fun(__f__); //# }); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func<__ftype__, int, T> element_index_fun) { //# fields.ForEach((f, i) => { array[start + __i__] = element_index_fun(__f__, __i__); //# }); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__[] ToArray() => (__ftype__[])this; #endregion #region Indexer //# if (ft == Meta.ByteType) { // Byte colors have a different byte order (red and blue are swapped) private static readonly byte[] IndexMapping = new byte[] { 2, 1, 0, 3 }; //# } /// /// Indexer in canonical order 0=R, 1=G, 2=B, 3=A (availability depending on color type). /// public unsafe __ftype__ this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (__ftype__* ptr = __getptr__) { ptr[/*#if (ft == Meta.ByteType) {*/IndexMapping[i]/*# } else {*/i/*#}*/] = value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (__ftype__* ptr = __getptr__) { return ptr[/*#if (ft == Meta.ByteType) {*/IndexMapping[i]/*# } else {*/i/*#}*/]; } } } #endregion #region Constants /// /// __type__ with all components zero. /// public static __type__ Zero => new __type__(/*# fields.ForEach(f => {*/__t.MinValue__/*#}, comma); */); // Web colors //# foreach(KeyValuePair entry in ColorNames) { //# var name = entry.Key; //# var color = new C3d(entry.Value); public static __type__ __name__ => new __type__(__d_to_ft__(__color.R__), __d_to_ft__(__color.G__), __d_to_ft__(__color.B__)); //# } public static __type__ DarkYellow => Olive; public static __type__ VRVisGreen => new __type__(__d_to_ft__(0.698), __d_to_ft__(0.851), __d_to_ft__(0.008)); //# for (int i = 1; i < 10; i++) { //# var val = (double)(0.1m * i); int percent = 10 * i; public static __type__ Gray__percent__ => new __type__(__d_to_ft__(__val__)); //# } #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ a, __type__ b) { return /*# fields.ForEach(f => { */a.__f__ == b.__f__/*# }, andand); */; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ a, __type__ b) { return /*# fields.ForEach(f => { */a.__f__ != b.__f__/*# }, oror); */; } #endregion #region Color Arithmetic //# if (!ft.IsReal) { //# fdtypes.ForEach(rt => { //# var rtype = rt.Name; //# var ft_to_r = (rt == Meta.FloatType) ? ft_to_f : ft_to_d; //# var r_to_ft = (rt == Meta.FloatType) ? f_to_ft : d_to_ft; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ col, __rtype__ scalar) { return new __type__(/*# fields.ForEach(f => { */ __r_to_ft__(__ft_to_r__(col.__f__) * scalar)/*# }, comma); */); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__rtype__ scalar, __type__ col) => col * scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator /(__type__ col, __rtype__ scalar) => col * (1 / scalar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator /(__rtype__ scalar, __type__ col) { return new __type__(/*# fields.ForEach(f => { */ __r_to_ft__(scalar / __ft_to_r__(col.__f__))/*# }, comma); */); } //# }); //# } //# foreach (var t1 in Meta.ColorTypes) { if (t1.HasAlpha != t.HasAlpha) continue; //# if (t1 == t) continue; //# var type1 = t1.Name; var ft1 = t1.FieldType; //# var ft1_from_ft = t1 != t //# ? (ft.IsReal && ft1.IsReal ? "(" + ftype + ")" : "Col." + ft1.Caps + "To" + ft.Caps) //# : ""; [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator +(__type__ c0, __type1__ c1) { return new __type__(/*# fields.ForEach(f => { */ (__ftype__)(c0.__f__ + __ft1_from_ft__(c1.__f__))/*# }, comma); */); } [Obsolete("Use operator with operands of same type instead.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator -(__type__ c0, __type1__ c1) { return new __type__(/*# fields.ForEach(f => { */ (__ftype__)(c0.__f__ - __ft1_from_ft__(c1.__f__))/*# }, comma); */); } //# } // t1 //# if (!ft.IsReal) { [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] //# } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ col, __ftype__ scalar) { return new __type__(/*# fields.ForEach(f => { */(__ftype__)(col.__f__ * scalar)/*# }, comma); */); } //# if (!ft.IsReal) { [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] //# } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__ftype__ scalar, __type__ col) { return new __type__(/*# fields.ForEach(f => { */(__ftype__)(scalar * col.__f__)/*# }, comma); */); } //# if (!ft.IsReal) { [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] //# } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator /(__type__ col, __ftype__ scalar) { return new __type__(/*# fields.ForEach(f => { */(__ftype__)(col.__f__ / scalar)/*# }, comma); */); } //# if (!ft.IsReal) { [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] //# } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator /(__ftype__ scalar, __type__ col) { return new __type__(/*# fields.ForEach(f => { */(__ftype__)(scalar / col.__f__)/*# }, comma); */); } //# if (!ft.IsReal) { [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] //# } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ c0, __type__ c1) { return new __type__(/*# fields.ForEach(f => { */(__ftype__)(c0.__f__ * c1.__f__)/*# }, comma); */); } //# if (!ft.IsReal) { [Obsolete("Multiplication and division of integer-based colors is unreasonable.")] //# } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator /(__type__ c0, __type__ c1) { return new __type__(/*# fields.ForEach(f => { */(__ftype__)(c0.__f__ / c1.__f__)/*# }, comma); */); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator +(__type__ c0, __type__ c1) { //# if (ft.IsReal) { return new __type__(/*# fields.ForEach(f => { */c0.__f__ + c1.__f__/*# }, comma); */); //# } else { return new __type__(/*# fields.ForEach(f => { */ (__t.MaxValue__ - c0.__f__ > c1.__f__) ? c0.__f__ + c1.__f__ : __t.MaxValue__/*# }, comma); */ ); //# } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator +(__type__ col, __ftype__ scalar) { //# if (ft.IsReal) { return new __type__(/*# fields.ForEach(f => { */col.__f__ + scalar/*# }, comma); */); //# } else { return new __type__(/*# fields.ForEach(f => { */ (__t.MaxValue__ - col.__f__ > scalar) ? col.__f__ + scalar : __t.MaxValue__/*# }, comma); */ ); //# } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator +(__ftype__ scalar, __type__ col) => col + scalar; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator -(__type__ c0, __type__ c1) { //# if (ft.IsReal) { return new __type__(/*# fields.ForEach(f => { */c0.__f__ - c1.__f__/*# }, comma); */); //# } else { return new __type__(/*# fields.ForEach(f => { */ (c0.__f__ > c1.__f__) ? c0.__f__ - c1.__f__ : 0/*# }, comma); */ ); //# } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator -(__type__ col, __ftype__ scalar) { //# if (ft.IsReal) { return new __type__(/*# fields.ForEach(f => { */col.__f__ - scalar/*# }, comma); */); //# } else { return new __type__(/*# fields.ForEach(f => { */ (col.__f__ > scalar) ? col.__f__ - scalar : 0/*# }, comma); */ ); //# } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator -(__ftype__ scalar, __type__ col) { //# if (ft.IsReal) { return new __type__(/*# fields.ForEach(f => { */scalar - col.__f__/*# }, comma); */); //# } else { return new __type__(/*# fields.ForEach(f => { */ (scalar > col.__f__) ? scalar - col.__f__ : 0/*# }, comma); */ ); //# } } /// /// Clamps the color channels to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clamp(__ftype__ min, __ftype__ max) { //# channels.ForEach(c => { __c__ = __c__.Clamp(min, max); //# }); } /// /// Returns a copy with the color channels clamped to the given bounds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ Clamped(__ftype__ min, __ftype__ max) { return new __type__(/*# channels.ForEach( c => { */__c__.Clamp(min, max)/*# }, comma); if (t.HasAlpha) {*/, A/*# } */); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |R| + |G| + |B|. /*# if (t.HasAlpha) { */The alpha channel is ignored./*# } */ /// public readonly __htype__ Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return /*# channels.ForEach(c => { */__fabs_p____c____q_fabs__/*# }, add); */; } } /// /// Returns the Euclidean (or 2-) norm of the color. This is calculated /// as sqrt(R^2 + G^2 + B^2). /*# if (t.HasAlpha) { */The alpha channel is ignored./*# } */ /// public readonly __ctype__ Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(/*# channels.ForEach(c => { */__c__ * __c__/*# }, add); */); } } /// /// Returns the infinite (or maximum) norm of the color. This is /// calculated as max(|R|, |G|, |B|). /*# if (t.HasAlpha) { */The alpha channel is ignored./*# } */ /// public readonly __ftype__ NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(/*# channels.ForEach(c => { */__fabs_p____c____q_fabs__/*# }, comma); */); } } /// /// Returns the minimum norm of the color. This is calculated as /// min(|R|, |G|, |B|). /*# if (t.HasAlpha) { */The alpha channel is ignored./*# } */ /// public readonly __ftype__ NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(/*# channels.ForEach(c => { */__fabs_p____c____q_fabs__/*# }, comma); */); } } #endregion #region Overrides public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; public override readonly int GetHashCode() { return HashCode.GetCombined(/*# t.Fields.ForEach(f => { */__f__/*# }, comma); */); } public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "")/*# fields.ForEach(f => {*/ + __f__.ToString(null, CultureInfo.InvariantCulture) /*# }, addqcommaspace); */ + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal<__type__, int, __ftype__> Setter = (ref __type__ color, int i, __ftype__ value) => { switch (i) { //# fields.ForEach((f, i) => { case __i__: color.__f__ = value; return; //# }); default: throw new IndexOutOfRangeException(); } }; //# foreach(var tt in fdtypes) { //# if (ft.IsReal && tt != ft) continue; //# var vtt = Meta.VecTypeOf(dim, tt); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ LinearInterp(__tt.Name__ t, __type__ a, __type__ b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ LinearInterp(__vtt.Name__ t, __type__ a, __type__ b) => Fun.Lerp(t, a, b); //#} [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ DivideByInt(__type__ c, int x) => c / x; #endregion #region Parsing /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional/*# if (!t.HasAlpha) {*/ and discarded/*#}*/. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, __type__.Zero otherwise. /// True on success, false otherwise. public static bool TryParse(Text t, out __type__ result) { //# if (type == "C4b") { if (Col.TryParseHex(t, out result)) { return true; } //# } else { if (Col.TryParseHex(t, out C4b tmp)) { result = tmp.To__type__(); return true; } //# } else { bool success = true; __ftype__[] values = new __ftype__[4] { /*# 4.ForEach(p => { */__t.MaxValue__/*# }, comma);*/ }; __ftype__ parse(Text t) { if (!__ftype__.TryParse(t.ToString(), __parseNumberStyle__, CultureInfo.InvariantCulture, out __ftype__ value)) success = false; return value; }; var count = t.NestedBracketSplitCount2(1); if (count == 3 || count == 4) t.NestedBracketSplit(1, parse, () => values); else success = false; result = success ? new __type__(values) : Zero; return success; } } /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional/*# if (!t.HasAlpha) {*/ and discarded/*#}*/. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// Contains the parsed color on success, __type__.Zero otherwise. /// True on success, false otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParse(string s, out __type__ result) => TryParse(new Text(s), out result); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional/*# if (!t.HasAlpha) {*/ and discarded/*#}*/. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid __type__ color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Parse(string s) => Parse(new Text(s)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Parse(Text t, int bracketLevel = 1) => t.NestedBracketSplit(bracketLevel, Text<__ftype__>.Parse, __type__.Setter); /// /// Parses a color string with decimal format [R, G, B, A], or hexadecimal formats RRGGBBAA or RGBA. /// /// /// The alpha component in any format is optional/*# if (!t.HasAlpha) {*/ and discarded/*#}*/. /// For the single digit hexadecimal RGBA format, the components are duplicated (e.g. "F" is interpreted as "FF"). /// Color strings in a hexadecimal format may be prefixed by "#" or "0x". /// /// The string to be parsed. /// The parsed color. /// the input does not represent a valid __type__ color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Parse(Text t) => TryParse(t, out __type__ result) ? result : throw new FormatException($"{t} is not a valid __type__ color."); #endregion #region IFormattable Members public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin /*# fields.ForEach(f => {*/+ __f__.ToString(format, fp) /*# }, addbetween); */ + end; } #endregion #region IEquatable<__type__> Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) { return /*# fields.ForEach(f => { */__f__.Equals(other.__f__)/*# }, andand); */; } #endregion #region IRGB Members double IRGB.Red { readonly get { return __ft_to_d__(R); } set { R = __d_to_ft__(value); } } double IRGB.Green { readonly get { return __ft_to_d__(G); } set { G = __d_to_ft__(value); } } double IRGB.Blue { readonly get { return __ft_to_d__(B); } set { B = __d_to_ft__(value); } } #endregion //# if (t.HasAlpha) { #region IOpacity Members [XmlIgnore] public double Opacity { readonly get { return __ft_to_d__(A); } set { A = __d_to_ft__(value); } } #endregion //# } } public static partial class Fun { #region Interpolation //# foreach(var tt in fdtypes) { //# if (ft.IsReal && tt != ft) continue; //# var vtt = Meta.VecTypeOf(dim, tt); /// /// Returns the linearly interpolated color between a and b. /// public static __type__ Lerp(this __tt.Name__ t, __type__ a, __type__ b) => new __type__(/*# fields.ForEach(f => {*/Lerp(t, a.__f__, b.__f__)/*#}, comma); */); /// /// Returns the linearly interpolated color between a and b. /// public static __type__ Lerp(this __vtt.Name__ t, __type__ a, __type__ b) => new __type__(/*# fields.ForEach(Meta.VecFields, (cf, vf) => {*/Lerp(t.__vf__, a.__cf__, b.__cf__)/*#}, comma); */); //#} #endregion #region ApproximateEquals //# if (isReal) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b) { return ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } //# } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b, __ftype__ tolerance) { return /*# fields.ForEach(f => {*/ApproximateEquals(a.__f__, b.__f__, tolerance)/*# }, andand);*/; } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this __type__ c, __ftype__ epsilon) => Col.AllTiny(c, epsilon); //# if (ft.IsReal) { /// /// Returns whether the absolute value of each component of the given is smaller than Constant<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(__type__ c) => c.IsTiny; //# } #endregion //# if (isReal) { #region Special Floating Point Value Checks /// /// Returns whether any component of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(__type__ c) => c.IsNaN; /// /// Returns whether any component of the the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(__type__ c) => c.IsInfinity; /// /// Returns whether any component of the the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(__type__ c) => c.IsPositiveInfinity; /// /// Returns whether any component of the the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(__type__ c) => c.IsNegativeInfinity; /// /// Returns whether all components of the the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(__type__ c) => c.IsFinite; #endregion //# } } public static partial class Col { #region ToHexString /// /// Returns the hexadecimal representation with format RRGGBB/*# if (t.HasAlpha) {*/AA/*#}*/. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToHexString(this __type__ c) //# if (ft == Meta.ByteType) { => /*# if (t.HasAlpha) {*/$"{c.R:X2}{c.G:X2}{c.B:X2}{c.A:X2}"/*# } else {*/$"{c.R:X2}{c.G:X2}{c.B:X2}"/*#}*/; //# } else { => c.ToC__t.Len__b().ToHexString(); //# } #endregion #region Comparisons //# var bops = new[,] { { "<", "Smaller" }, { ">" , "Greater"}, //# { "<=", "SmallerOrEqual" }, { ">=", "GreaterOrEqual"}, //# { "==", "Equal" }, { "!=", "Different" } }; //# var attention = "ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b))."; //# for(int o = 0; o < bops.GetLength(0); o++) { //# string bop = " " + bops[o,0] + " ", opName = bops[o,1]; /// /// Returns whether ALL elements of a are __opName__ the corresponding element of b. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool All__opName__(this __type__ a, __type__ b) { return (/*# fields.ForEach(f => { */a.__f____bop__b.__f__/*# }, andand); */); } /// /// Returns whether ALL elements of col are __opName__ s. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool All__opName__(this __type__ col, __ftype__ s) { return (/*# fields.ForEach(f => { */col.__f____bop__s/*# }, andand); */); } /// /// Returns whether a is __opName__ ALL elements of col. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool All__opName__(__ftype__ s, __type__ col) { return (/*# fields.ForEach(f => { */s__bop__col.__f__/*# }, andand); */); } /// /// Returns whether AT LEAST ONE element of a is __opName__ the corresponding element of b. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Any__opName__(this __type__ a, __type__ b) { return (/*# fields.ForEach(f => { */a.__f____bop__b.__f__/*# }, oror); */); } /// /// Returns whether AT LEAST ONE element of col is __opName__ s. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Any__opName__(this __type__ col, __ftype__ s) { return (/*# fields.ForEach(f => { */col.__f____bop__s/*# }, oror); */); } /// /// Returns whether a is __opName__ AT LEAST ONE element of col. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Any__opName__(__ftype__ s, __type__ col) { return (/*# fields.ForEach(f => { */s__bop__col.__f__/*# }, oror); */); } //# } #endregion #region Linear Combination //# for (int tpc = 4; tpc < 7; tpc+=2) { //# foreach (var rt in new[] { fltt, dblt }) { var rtype = rt.Name; var wtype = rt.FieldType.Name; var rtc = rt.FieldType.Caps[0]; //# var convert = ft.IsReal ? "" //# : "Col." + ft.Caps + "In" //# + (ft.Name == "uint" ? "Double" : rt.FieldType.Caps) //# + "To" + ft.Caps + "Clamped"; //# if (!isReal || wtype == ftype) { /// /// A function that returns the linear combination fo the supplied parameters /// with the referenced weight tuple. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ LinCom( /*# tpc.ForEach(i => { */__type__ p__i__/*# }, comma); */, ref Tup__tpc__<__wtype__> w) { return new __type__(/*# channels.ForEach(ch => { */ __convert__(/*# tpc.ForEach(i => { */p__i__.__ch__ * w.E__i__/*# }, add); */)/*# }, comma); */); } //# } //# if (!isReal) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ LinComRaw__rtc__( /*# tpc.ForEach(i => { */__type__ p__i__/*# }, comma); */, ref Tup__tpc__<__wtype__> w) { return new __rtype__(/*# channels.ForEach(ch => { */ /*# tpc.ForEach(i => { */p__i__.__ch__ * w.E__i__/*# }, add); }, comma); */); } //# } // !isReal //# } // rt //# } // tpc #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this __type__ c, __ftype__ epsilon) => /*# fields.ForEach(f => { */c.__f__.IsTiny(epsilon)/*# }, oror);*/; /// /// Returns whether the absolute value of each component of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this __type__ c, __ftype__ epsilon) => /*# fields.ForEach(f => { */c.__f__.IsTiny(epsilon)/*# }, andand);*/; #endregion //# if (isReal) { #region Special Floating Point Value Checks //# var condArray = new[] { "NaN", "Infinity", "PositiveInfinity", "NegativeInfinity", "Tiny" }; //# var scopeArray = new[] { ftype, ftype, ftype, ftype, "Fun" }; //# var quantArray = new[] { "Any", "All" }; //# var actArray = new[] { oror, andand }; //# condArray.ForEach(scopeArray, (cond, scope) => { //# quantArray.ForEach(actArray, (qant, act) => { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool __qant____cond__(__type__ c) => c.__qant____cond__; //# }); // quantArray //# }); // condArray #endregion //# } } //# if (ft != Meta.ByteType && ft != Meta.UShortType) { public static class IRandomUniform__type__Extensions { #region IRandomUniform extensions for __type__ //# string[] variants; //# if (ft == Meta.FloatType) { //# variants = new string[] { "", "Closed", "Open" }; //# } else if (ft == Meta.DoubleType) { //# variants = new string[] { "", "Closed", "Open", "Full", "FullClosed", "FullOpen" }; //# } else { //# variants = new string[] { "" }; //# } //# foreach (var v in variants) { /// /// Uses Uniform__fcaps____v__() to generate the elements of a __type__ color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Uniform__type____v__(this IRandomUniform rnd) { return new __type__(/*# fields.ForEach(f => { */rnd.Uniform__fcaps____v__()/*# }, comma); */); } //# } #endregion } //# } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Math/Colors/Spectrum.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Aardvark.Base { public class Spectrum { public double FirstWaveLength; public double DeltaWaveLength; public double[] Data; public Spectrum(double firstWaveLength, double deltaWaveLength, double[] data) { FirstWaveLength = firstWaveLength; DeltaWaveLength = deltaWaveLength; Data = data; } public static readonly Spectrum CieXYZ31X = new Spectrum(360, 1, SpectralData.CieXYZ31_X_360_830_1nm); public static readonly Spectrum CieXYZ31Y = new Spectrum(360, 1, SpectralData.CieXYZ31_Y_360_830_1nm); public static readonly Spectrum CieXYZ31Z = new Spectrum(360, 1, SpectralData.CieXYZ31_Z_360_830_1nm); public static readonly Spectrum CieIlluminantA = new Spectrum(300, 1, SpectralData.CieIlluminantA_300_830_1nm); public static readonly Spectrum CieIlluminantD65 = new Spectrum(300, 1, SpectralData.CieIlluminantD65_300_830_1nm); } public static class SpectralData { #region CIE XYZ 1931 Color Matching Functions 360-830nm in 1nm steps public static readonly double[] CieXYZ31_X_360_830_1nm = { 0.0001299, 0.000145847, 0.000163802, 0.000184004, 0.00020669, 0.0002321, 0.000260728, 0.000293075, 0.000329388, 0.000369914, 0.0004149, 0.000464159, 0.000518986, 0.000581854, 0.000655235, 0.0007416, 0.00084503, 0.000964527, 0.001094949, 0.001231154, 0.001368, 0.00150205, 0.001642328, 0.001802382, 0.001995757, 0.002236, 0.002535385, 0.002892603, 0.003300829, 0.003753236, 0.004243, 0.004762389, 0.005330048, 0.005978712, 0.006741117, 0.00765, 0.008751373, 0.01002888, 0.0114217, 0.01286901, 0.01431, 0.01570443, 0.01714744, 0.01878122, 0.02074801, 0.02319, 0.02620736, 0.02978248, 0.03388092, 0.03846824, 0.04351, 0.0489956, 0.0550226, 0.0617188, 0.069212, 0.07763, 0.08695811, 0.09717672, 0.1084063, 0.1207672, 0.13438, 0.1493582, 0.1653957, 0.1819831, 0.198611, 0.21477, 0.2301868, 0.2448797, 0.2587773, 0.2718079, 0.2839, 0.2949438, 0.3048965, 0.3137873, 0.3216454, 0.3285, 0.3343513, 0.3392101, 0.3431213, 0.3461296, 0.34828, 0.3495999, 0.3501474, 0.350013, 0.349287, 0.34806, 0.3463733, 0.3442624, 0.3418088, 0.3390941, 0.3362, 0.3331977, 0.3300411, 0.3266357, 0.3228868, 0.3187, 0.3140251, 0.308884, 0.3032904, 0.2972579, 0.2908, 0.2839701, 0.2767214, 0.2689178, 0.2604227, 0.2511, 0.2408475, 0.2298512, 0.2184072, 0.2068115, 0.19536, 0.1842136, 0.1733273, 0.1626881, 0.1522833, 0.1421, 0.1321786, 0.1225696, 0.1132752, 0.1042979, 0.09564, 0.08729955, 0.07930804, 0.07171776, 0.06458099, 0.05795001, 0.05186211, 0.04628152, 0.04115088, 0.03641283, 0.03201, 0.0279172, 0.0241444, 0.020687, 0.0175404, 0.0147, 0.01216179, 0.00991996, 0.00796724, 0.006296346, 0.0049, 0.003777173, 0.00294532, 0.00242488, 0.002236293, 0.0024, 0.00292552, 0.00383656, 0.00517484, 0.00698208, 0.0093, 0.01214949, 0.01553588, 0.01947752, 0.02399277, 0.0291, 0.03481485, 0.04112016, 0.04798504, 0.05537861, 0.06327, 0.07163501, 0.08046224, 0.08973996, 0.09945645, 0.1096, 0.1201674, 0.1311145, 0.1423679, 0.1538542, 0.1655, 0.1772571, 0.18914, 0.2011694, 0.2133658, 0.2257499, 0.2383209, 0.2510668, 0.2639922, 0.2771017, 0.2904, 0.3038912, 0.3175726, 0.3314384, 0.3454828, 0.3597, 0.3740839, 0.3886396, 0.4033784, 0.4183115, 0.4334499, 0.4487953, 0.464336, 0.480064, 0.4959713, 0.5120501, 0.5282959, 0.5446916, 0.5612094, 0.5778215, 0.5945, 0.6112209, 0.6279758, 0.6447602, 0.6615697, 0.6784, 0.6952392, 0.7120586, 0.7288284, 0.7455188, 0.7621, 0.7785432, 0.7948256, 0.8109264, 0.8268248, 0.8425, 0.8579325, 0.8730816, 0.8878944, 0.9023181, 0.9163, 0.9297995, 0.9427984, 0.9552776, 0.9672179, 0.9786, 0.9893856, 0.9995488, 1.0090892, 1.0180064, 1.0263, 1.0339827, 1.040986, 1.047188, 1.0524667, 1.0567, 1.0597944, 1.0617992, 1.0628068, 1.0629096, 1.0622, 1.0607352, 1.0584436, 1.0552244, 1.0509768, 1.0456, 1.0390369, 1.0313608, 1.0226662, 1.0130477, 1.0026, 0.9913675, 0.9793314, 0.9664916, 0.9528479, 0.9384, 0.923194, 0.907244, 0.890502, 0.87292, 0.8544499, 0.835084, 0.814946, 0.794186, 0.772954, 0.7514, 0.7295836, 0.7075888, 0.6856022, 0.6638104, 0.6424, 0.6215149, 0.6011138, 0.5811052, 0.5613977, 0.5419, 0.5225995, 0.5035464, 0.4847436, 0.4661939, 0.4479, 0.4298613, 0.412098, 0.394644, 0.3775333, 0.3608, 0.3444563, 0.3285168, 0.3130192, 0.2980011, 0.2835, 0.2695448, 0.2561184, 0.2431896, 0.2307272, 0.2187, 0.2070971, 0.1959232, 0.1851708, 0.1748323, 0.1649, 0.1553667, 0.14623, 0.13749, 0.1291467, 0.1212, 0.1136397, 0.106465, 0.09969044, 0.09333061, 0.0874, 0.08190096, 0.07680428, 0.07207712, 0.06768664, 0.0636, 0.05980685, 0.05628216, 0.05297104, 0.04981861, 0.04677, 0.04378405, 0.04087536, 0.03807264, 0.03540461, 0.0329, 0.03056419, 0.02838056, 0.02634484, 0.02445275, 0.0227, 0.02108429, 0.01959988, 0.01823732, 0.01698717, 0.01584, 0.01479064, 0.01383132, 0.01294868, 0.0121292, 0.01135916, 0.01062935, 0.009938846, 0.009288422, 0.008678854, 0.008110916, 0.007582388, 0.007088746, 0.006627313, 0.006195408, 0.005790346, 0.005409826, 0.005052583, 0.004717512, 0.004403507, 0.004109457, 0.003833913, 0.003575748, 0.003334342, 0.003109075, 0.002899327, 0.002704348, 0.00252302, 0.002354168, 0.002196616, 0.00204919, 0.00191096, 0.001781438, 0.00166011, 0.001546459, 0.001439971, 0.001340042, 0.001246275, 0.001158471, 0.00107643, 0.000999949, 0.000928736, 0.000862433, 0.00080075, 0.000743396, 0.000690079, 0.000640516, 0.000594502, 0.000551865, 0.000512429, 0.000476021, 0.000442454, 0.000411512, 0.000382981, 0.000356649, 0.000332301, 0.000309759, 0.000288887, 0.000269539, 0.000251568, 0.000234826, 0.000219171, 0.000204526, 0.000190841, 0.000178065, 0.000166151, 0.000155024, 0.000144622, 0.00013491, 0.000125852, 0.000117413, 0.000109552, 0.000102225, 9.53945E-05, 8.90239E-05, 8.30753E-05, 7.75127E-05, 7.2313E-05, 6.74578E-05, 6.29284E-05, 5.87065E-05, 5.47703E-05, 5.10992E-05, 4.76765E-05, 4.44857E-05, 4.15099E-05, 3.87332E-05, 3.6142E-05, 3.37235E-05, 3.14649E-05, 2.93533E-05, 2.73757E-05, 2.55243E-05, 2.37938E-05, 2.21787E-05, 2.06738E-05, 1.92723E-05, 1.79664E-05, 1.67499E-05, 1.56165E-05, 1.45598E-05, 1.35739E-05, 1.26544E-05, 1.17972E-05, 1.09984E-05, 1.0254E-05, 9.55965E-06, 8.91204E-06, 8.30836E-06, 7.74577E-06, 7.22146E-06, 6.73248E-06, 6.27642E-06, 5.8513E-06, 5.45512E-06, 5.08587E-06, 4.74147E-06, 4.42024E-06, 4.12078E-06, 3.84172E-06, 3.58165E-06, 3.33913E-06, 3.11295E-06, 2.90212E-06, 2.70565E-06, 2.52253E-06, 2.35173E-06, 2.19242E-06, 2.0439E-06, 1.9055E-06, 1.77651E-06, 1.65622E-06, 1.54402E-06, 1.43944E-06, 1.34198E-06, 1.25114E-06 }; public static readonly double[] CieXYZ31_Y_360_830_1nm = { 0.000003917, 4.39358E-06, 4.9296E-06, 5.53214E-06, 6.20825E-06, 0.000006965, 7.81322E-06, 8.76734E-06, 9.83984E-06, 1.10432E-05, 0.00001239, 1.38864E-05, 1.55573E-05, 1.7443E-05, 1.95838E-05, 0.00002202, 2.48397E-05, 2.80413E-05, 3.1531E-05, 3.52152E-05, 0.000039, 4.28264E-05, 4.69146E-05, 5.15896E-05, 5.71764E-05, 0.000064, 7.23442E-05, 8.22122E-05, 9.35082E-05, 0.000106136, 0.00012, 0.000134984, 0.000151492, 0.000170208, 0.000191816, 0.000217, 0.000246907, 0.00028124, 0.00031852, 0.000357267, 0.000396, 0.000433715, 0.000473024, 0.000517876, 0.000572219, 0.00064, 0.00072456, 0.0008255, 0.00094116, 0.00106988, 0.00121, 0.001362091, 0.001530752, 0.001720368, 0.001935323, 0.00218, 0.0024548, 0.002764, 0.0031178, 0.0035264, 0.004, 0.00454624, 0.00515932, 0.00582928, 0.00654616, 0.0073, 0.008086507, 0.00890872, 0.00976768, 0.01066443, 0.0116, 0.01257317, 0.01358272, 0.01462968, 0.01571509, 0.01684, 0.01800736, 0.01921448, 0.02045392, 0.02171824, 0.023, 0.02429461, 0.02561024, 0.02695857, 0.02835125, 0.0298, 0.03131083, 0.03288368, 0.03452112, 0.03622571, 0.038, 0.03984667, 0.041768, 0.043766, 0.04584267, 0.048, 0.05024368, 0.05257304, 0.05498056, 0.05745872, 0.06, 0.06260197, 0.06527752, 0.06804208, 0.07091109, 0.0739, 0.077016, 0.0802664, 0.0836668, 0.0872328, 0.09098, 0.09491755, 0.09904584, 0.1033674, 0.1078846, 0.1126, 0.117532, 0.1226744, 0.1279928, 0.1334528, 0.13902, 0.1446764, 0.1504693, 0.1564619, 0.1627177, 0.1693, 0.1762431, 0.1835581, 0.1912735, 0.199418, 0.20802, 0.2171199, 0.2267345, 0.2368571, 0.2474812, 0.2586, 0.2701849, 0.2822939, 0.2950505, 0.308578, 0.323, 0.3384021, 0.3546858, 0.3716986, 0.3892875, 0.4073, 0.4256299, 0.4443096, 0.4633944, 0.4829395, 0.503, 0.5235693, 0.544512, 0.56569, 0.5869653, 0.6082, 0.6293456, 0.6503068, 0.6708752, 0.6908424, 0.71, 0.7281852, 0.7454636, 0.7619694, 0.7778368, 0.7932, 0.8081104, 0.8224962, 0.8363068, 0.8494916, 0.862, 0.8738108, 0.8849624, 0.8954936, 0.9054432, 0.9148501, 0.9237348, 0.9320924, 0.9399226, 0.9472252, 0.954, 0.9602561, 0.9660074, 0.9712606, 0.9760225, 0.9803, 0.9840924, 0.9874182, 0.9903128, 0.9928116, 0.9949501, 0.9967108, 0.9980983, 0.999112, 0.9997482, 1, 0.9998567, 0.9993046, 0.9983255, 0.9968987, 0.995, 0.9926005, 0.9897426, 0.9864444, 0.9827241, 0.9786, 0.9740837, 0.9691712, 0.9638568, 0.9581349, 0.952, 0.9454504, 0.9384992, 0.9311628, 0.9234576, 0.9154, 0.9070064, 0.8982772, 0.8892048, 0.8797816, 0.87, 0.8598613, 0.849392, 0.838622, 0.8275813, 0.8163, 0.8047947, 0.793082, 0.781192, 0.7691547, 0.757, 0.7447541, 0.7324224, 0.7200036, 0.7074965, 0.6949, 0.6822192, 0.6694716, 0.6566744, 0.6438448, 0.631, 0.6181555, 0.6053144, 0.5924756, 0.5796379, 0.5668, 0.5539611, 0.5411372, 0.5283528, 0.5156323, 0.503, 0.4904688, 0.4780304, 0.4656776, 0.4534032, 0.4412, 0.42908, 0.417036, 0.405032, 0.393032, 0.381, 0.3689184, 0.3568272, 0.3447768, 0.3328176, 0.321, 0.3093381, 0.2978504, 0.2865936, 0.2756245, 0.265, 0.2547632, 0.2448896, 0.2353344, 0.2260528, 0.217, 0.2081616, 0.1995488, 0.1911552, 0.1829744, 0.175, 0.1672235, 0.1596464, 0.1522776, 0.1451259, 0.1382, 0.1315003, 0.1250248, 0.1187792, 0.1127691, 0.107, 0.1014762, 0.09618864, 0.09112296, 0.08626485, 0.0816, 0.07712064, 0.07282552, 0.06871008, 0.06476976, 0.061, 0.05739621, 0.05395504, 0.05067376, 0.04754965, 0.04458, 0.04175872, 0.03908496, 0.03656384, 0.03420048, 0.032, 0.02996261, 0.02807664, 0.02632936, 0.02470805, 0.0232, 0.02180077, 0.02050112, 0.01928108, 0.01812069, 0.017, 0.01590379, 0.01483718, 0.01381068, 0.01283478, 0.01192, 0.01106831, 0.01027339, 0.009533311, 0.008846157, 0.00821, 0.007623781, 0.007085424, 0.006591476, 0.006138485, 0.005723, 0.005343059, 0.004995796, 0.004676404, 0.004380075, 0.004102, 0.003838453, 0.003589099, 0.003354219, 0.003134093, 0.002929, 0.002738139, 0.002559876, 0.002393244, 0.002237275, 0.002091, 0.001953587, 0.00182458, 0.00170358, 0.001590187, 0.001484, 0.001384496, 0.001291268, 0.001204092, 0.001122744, 0.001047, 0.00097659, 0.000911109, 0.000850133, 0.000793238, 0.00074, 0.000690083, 0.00064331, 0.000599496, 0.000558455, 0.00052, 0.000483914, 0.000450053, 0.000418345, 0.000388718, 0.0003611, 0.000335384, 0.00031144, 0.000289166, 0.000268454, 0.0002492, 0.000231302, 0.000214686, 0.000199288, 0.000185048, 0.0001719, 0.000159778, 0.000148604, 0.000138302, 0.000128793, 0.00012, 0.00011186, 0.000104322, 9.73356E-05, 9.08459E-05, 0.0000848, 7.91467E-05, 0.000073858, 0.000068916, 6.43027E-05, 0.00006, 5.59819E-05, 5.22256E-05, 4.87184E-05, 4.54475E-05, 0.0000424, 3.9561E-05, 3.69151E-05, 3.44487E-05, 3.21482E-05, 0.00003, 2.79913E-05, 2.61136E-05, 2.43602E-05, 2.27246E-05, 0.0000212, 1.97786E-05, 1.84529E-05, 1.72169E-05, 1.60646E-05, 0.00001499, 1.39873E-05, 1.30516E-05, 1.21782E-05, 1.13625E-05, 0.0000106, 9.88588E-06, 9.2173E-06, 8.59236E-06, 8.00913E-06, 7.4657E-06, 6.95957E-06, 6.488E-06, 6.0487E-06, 5.6394E-06, 5.2578E-06, 4.90177E-06, 4.56972E-06, 4.26019E-06, 3.97174E-06, 3.7029E-06, 3.45216E-06, 3.2183E-06, 3.0003E-06, 2.79714E-06, 2.6078E-06, 2.43122E-06, 2.26653E-06, 2.11301E-06, 1.96994E-06, 1.8366E-06, 1.71223E-06, 1.59623E-06, 1.48809E-06, 1.38731E-06, 1.2934E-06, 1.20582E-06, 1.12414E-06, 1.04801E-06, 9.77058E-07, 9.1093E-07, 8.49251E-07, 7.91721E-07, 7.3809E-07, 6.8811E-07, 6.4153E-07, 5.9809E-07, 5.57575E-07, 5.19808E-07, 4.84612E-07, 4.5181E-07 }; public static readonly double[] CieXYZ31_Z_360_830_1nm = { 0.0006061, 0.000680879, 0.000765146, 0.000860012, 0.000966593, 0.001086, 0.001220586, 0.001372729, 0.001543579, 0.001734286, 0.001946, 0.002177777, 0.002435809, 0.002731953, 0.003078064, 0.003486, 0.003975227, 0.00454088, 0.00515832, 0.005802907, 0.006450001, 0.007083216, 0.007745488, 0.008501152, 0.009414544, 0.01054999, 0.0119658, 0.01365587, 0.01558805, 0.01773015, 0.02005001, 0.02251136, 0.02520288, 0.02827972, 0.03189704, 0.03621, 0.04143771, 0.04750372, 0.05411988, 0.06099803, 0.06785001, 0.07448632, 0.08136156, 0.08915364, 0.09854048, 0.1102, 0.1246133, 0.1417017, 0.1613035, 0.1832568, 0.2074, 0.2336921, 0.2626114, 0.2947746, 0.3307985, 0.3713, 0.4162091, 0.4654642, 0.5196948, 0.5795303, 0.6456, 0.7184838, 0.7967133, 0.8778459, 0.959439, 1.0390501, 1.1153673, 1.1884971, 1.2581233, 1.3239296, 1.3856, 1.4426352, 1.4948035, 1.5421903, 1.5848807, 1.62296, 1.6564048, 1.6852959, 1.7098745, 1.7303821, 1.74706, 1.7600446, 1.7696233, 1.7762637, 1.7804334, 1.7826, 1.7829682, 1.7816998, 1.7791982, 1.7758671, 1.77211, 1.7682589, 1.764039, 1.7589438, 1.7524663, 1.7441, 1.7335595, 1.7208581, 1.7059369, 1.6887372, 1.6692, 1.6475287, 1.6234127, 1.5960223, 1.564528, 1.5281, 1.4861114, 1.4395215, 1.3898799, 1.3387362, 1.28764, 1.2374223, 1.1878243, 1.1387611, 1.090148, 1.0419, 0.9941976, 0.9473473, 0.9014531, 0.8566193, 0.8129501, 0.7705173, 0.7294448, 0.6899136, 0.6521049, 0.6162, 0.5823286, 0.5504162, 0.5203376, 0.4919673, 0.46518, 0.4399246, 0.4161836, 0.3938822, 0.3729459, 0.3533, 0.3348578, 0.3175521, 0.3013375, 0.2861686, 0.272, 0.2588171, 0.2464838, 0.2347718, 0.2234533, 0.2123, 0.2011692, 0.1901196, 0.1792254, 0.1685608, 0.1582, 0.1481383, 0.1383758, 0.1289942, 0.1200751, 0.1117, 0.1039048, 0.09666748, 0.08998272, 0.08384531, 0.07824999, 0.07320899, 0.06867816, 0.06456784, 0.06078835, 0.05725001, 0.05390435, 0.05074664, 0.04775276, 0.04489859, 0.04216, 0.03950728, 0.03693564, 0.03445836, 0.03208872, 0.02984, 0.02771181, 0.02569444, 0.02378716, 0.02198925, 0.0203, 0.01871805, 0.01724036, 0.01586364, 0.01458461, 0.0134, 0.01230723, 0.01130188, 0.01037792, 0.009529306, 0.008749999, 0.0080352, 0.0073816, 0.0067854, 0.0062428, 0.005749999, 0.0053036, 0.0048998, 0.0045342, 0.0042024, 0.0039, 0.0036232, 0.0033706, 0.0031414, 0.0029348, 0.002749999, 0.0025852, 0.0024386, 0.0023094, 0.0021968, 0.0021, 0.002017733, 0.0019482, 0.0018898, 0.001840933, 0.0018, 0.001766267, 0.0017378, 0.0017112, 0.001683067, 0.001650001, 0.001610133, 0.0015644, 0.0015136, 0.001458533, 0.0014, 0.001336667, 0.00127, 0.001205, 0.001146667, 0.0011, 0.0010688, 0.0010494, 0.0010356, 0.0010212, 0.001, 0.00096864, 0.00092992, 0.00088688, 0.00084256, 0.0008, 0.00076096, 0.00072368, 0.00068592, 0.00064544, 0.0006, 0.000547867, 0.0004916, 0.0004354, 0.000383467, 0.00034, 0.000307253, 0.00028316, 0.00026544, 0.000251813, 0.00024, 0.000229547, 0.00022064, 0.00021196, 0.000202187, 0.00019, 0.000174213, 0.00015564, 0.00013596, 0.000116853, 0.0001, 8.61333E-05, 0.0000746, 0.000065, 5.69333E-05, 5E-05, 0.00004416, 0.00003948, 0.00003572, 0.00003264, 0.00003, 2.76533E-05, 0.00002556, 0.00002364, 2.18133E-05, 0.00002, 1.81333E-05, 0.0000162, 0.0000142, 1.21333E-05, 0.00001, 7.73333E-06, 0.0000054, 0.0000032, 1.33333E-06, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; #endregion #region CIE Illuminant A Spectral Distribution 300-830nm in 1nm steps public static readonly double[] CieIlluminantA_300_830_1nm = { 0.930483, 0.967643, 1.00597, 1.04549, 1.08623, 1.12821, 1.17147, 1.21602, 1.26188, 1.3091, 1.35769, 1.40768, 1.4591, 1.51198, 1.56633, 1.62219, 1.67959, 1.73855, 1.7991, 1.86127, 1.92508, 1.99057, 2.05776, 2.12667, 2.19734, 2.2698, 2.34406, 2.42017, 2.49814, 2.57801, 2.65981, 2.74355, 2.82928, 2.91701, 3.00678, 3.09861, 3.19253, 3.28857, 3.38676, 3.48712, 3.58968, 3.69447, 3.80152, 3.91085, 4.0225, 4.13648, 4.25282, 4.37156, 4.49272, 4.61631, 4.74238, 4.87095, 5.00204, 5.13568, 5.27189, 5.4107, 5.55213, 5.69622, 5.84298, 5.99244, 6.14462, 6.29955, 6.45724, 6.61774, 6.78105, 6.9472, 7.11621, 7.28811, 7.46292, 7.64066, 7.82135, 8.00501, 8.19167, 8.38134, 8.57404, 8.7698, 8.96864, 9.17056, 9.37561, 9.58378, 9.7951, 10.0096, 10.2273, 10.4481, 10.6722, 10.8996, 11.1302, 11.364, 11.6012, 11.8416, 12.0853, 12.3324, 12.5828, 12.8366, 13.0938, 13.3543, 13.6182, 13.8855, 14.1563, 14.4304, 14.708, 14.9891, 15.2736, 15.5616, 15.853, 16.148, 16.4464, 16.7484, 17.0538, 17.3628, 17.6753, 17.9913, 18.3108, 18.6339, 18.9605, 19.2907, 19.6244, 19.9617, 20.3026, 20.647, 20.995, 21.3465, 21.7016, 22.0603, 22.4225, 22.7883, 23.1577, 23.5307, 23.9072, 24.2873, 24.6709, 25.0581, 25.4489, 25.8432, 26.2411, 26.6425, 27.0475, 27.456, 27.8681, 28.2836, 28.7027, 29.1253, 29.5515, 29.9811, 30.4142, 30.8508, 31.2909, 31.7345, 32.1815, 32.632, 33.0859, 33.5432, 34.004, 34.4682, 34.9358, 35.4068, 35.8811, 36.3588, 36.8399, 37.3243, 37.8121, 38.3031, 38.7975, 39.2951, 39.796, 40.3002, 40.8076, 41.3182, 41.832, 42.3491, 42.8693, 43.3926, 43.9192, 44.4488, 44.9816, 45.5174, 46.0563, 46.5983, 47.1433, 47.6913, 48.2423, 48.7963, 49.3533, 49.9132, 50.476, 51.0418, 51.6104, 52.1818, 52.7561, 53.3332, 53.9132, 54.4958, 55.0813, 55.6694, 56.2603, 56.8539, 57.4501, 58.0489, 58.6504, 59.2545, 59.8611, 60.4703, 61.082, 61.6962, 62.3128, 62.932, 63.5535, 64.1775, 64.8038, 65.4325, 66.0635, 66.6968, 67.3324, 67.9702, 68.6102, 69.2525, 69.8969, 70.5435, 71.1922, 71.843, 72.4959, 73.1508, 73.8077, 74.4666, 75.1275, 75.7903, 76.4551, 77.1217, 77.7902, 78.4605, 79.1326, 79.8065, 80.4821, 81.1595, 81.8386, 82.5193, 83.2017, 83.8856, 84.5712, 85.2584, 85.947, 86.6372, 87.3288, 88.0219, 88.7165, 89.4124, 90.1097, 90.8083, 91.5082, 92.2095, 92.912, 93.6157, 94.3206, 95.0267, 95.7339, 96.4423, 97.1518, 97.8623, 98.5739, 99.2864, 100, 100.715, 101.43, 102.146, 102.864, 103.582, 104.301, 105.02, 105.741, 106.462, 107.184, 107.906, 108.63, 109.354, 110.078, 110.803, 111.529, 112.255, 112.982, 113.709, 114.436, 115.164, 115.893, 116.622, 117.351, 118.08, 118.81, 119.54, 120.27, 121.001, 121.731, 122.462, 123.193, 123.924, 124.655, 125.386, 126.118, 126.849, 127.58, 128.312, 129.043, 129.774, 130.505, 131.236, 131.966, 132.697, 133.427, 134.157, 134.887, 135.617, 136.346, 137.075, 137.804, 138.532, 139.26, 139.988, 140.715, 141.441, 142.167, 142.893, 143.618, 144.343, 145.067, 145.79, 146.513, 147.235, 147.957, 148.678, 149.398, 150.117, 150.836, 151.554, 152.271, 152.988, 153.704, 154.418, 155.132, 155.845, 156.558, 157.269, 157.979, 158.689, 159.397, 160.104, 160.811, 161.516, 162.221, 162.924, 163.626, 164.327, 165.028, 165.726, 166.424, 167.121, 167.816, 168.51, 169.203, 169.895, 170.586, 171.275, 171.963, 172.65, 173.335, 174.019, 174.702, 175.383, 176.063, 176.741, 177.419, 178.094, 178.769, 179.441, 180.113, 180.783, 181.451, 182.118, 182.783, 183.447, 184.109, 184.77, 185.429, 186.087, 186.743, 187.397, 188.05, 188.701, 189.35, 189.998, 190.644, 191.288, 191.931, 192.572, 193.211, 193.849, 194.484, 195.118, 195.75, 196.381, 197.009, 197.636, 198.261, 198.884, 199.506, 200.125, 200.743, 201.359, 201.972, 202.584, 203.195, 203.803, 204.409, 205.013, 205.616, 206.216, 206.815, 207.411, 208.006, 208.599, 209.189, 209.778, 210.365, 210.949, 211.532, 212.112, 212.691, 213.268, 213.842, 214.415, 214.985, 215.553, 216.12, 216.684, 217.246, 217.806, 218.364, 218.92, 219.473, 220.025, 220.574, 221.122, 221.667, 222.21, 222.751, 223.29, 223.826, 224.361, 224.893, 225.423, 225.951, 226.477, 227, 227.522, 228.041, 228.558, 229.073, 229.585, 230.096, 230.604, 231.11, 231.614, 232.115, 232.615, 233.112, 233.606, 234.099, 234.589, 235.078, 235.564, 236.047, 236.529, 237.008, 237.485, 237.959, 238.432, 238.902, 239.37, 239.836, 240.299, 240.76, 241.219, 241.675, 242.13, 242.582, 243.031, 243.479, 243.924, 244.367, 244.808, 245.246, 245.682, 246.116, 246.548, 246.977, 247.404, 247.829, 248.251, 248.671, 249.089, 249.505, 249.918, 250.329, 250.738, 251.144, 251.548, 251.95, 252.35, 252.747, 253.142, 253.535, 253.925, 254.314, 254.7, 255.083, 255.465, 255.844, 256.221, 256.595, 256.968, 257.338, 257.706, 258.071, 258.434, 258.795, 259.154, 259.511, 259.865, 260.217, 260.567, 260.914, 261.259, 261.602 }; #endregion #region CIE Illuminant D65 Spectral Distribution 300-830nm in 1nm steps public static readonly double[] CieIlluminantD65_300_830_1nm = { 0.0341, 0.36014, 0.68618, 1.01222, 1.33826, 1.6643, 1.99034, 2.31638, 2.64242, 2.96846, 3.2945, 4.98865, 6.6828, 8.37695, 10.0711, 11.7652, 13.4594, 15.1535, 16.8477, 18.5418, 20.236, 21.9177, 23.5995, 25.2812, 26.963, 28.6447, 30.3265, 32.0082, 33.69, 35.3717, 37.0535, 37.343, 37.6326, 37.9221, 38.2116, 38.5011, 38.7907, 39.0802, 39.3697, 39.6593, 39.9488, 40.4451, 40.9414, 41.4377, 41.934, 42.4302, 42.9265, 43.4228, 43.9191, 44.4154, 44.9117, 45.0844, 45.257, 45.4297, 45.6023, 45.775, 45.9477, 46.1203, 46.293, 46.4656, 46.6383, 47.1834, 47.7285, 48.2735, 48.8186, 49.3637, 49.9088, 50.4539, 50.9989, 51.544, 52.0891, 51.8777, 51.6664, 51.455, 51.2437, 51.0323, 50.8209, 50.6096, 50.3982, 50.1869, 49.9755, 50.4428, 50.91, 51.3773, 51.8446, 52.3118, 52.7791, 53.2464, 53.7137, 54.1809, 54.6482, 57.4589, 60.2695, 63.0802, 65.8909, 68.7015, 71.5122, 74.3229, 77.1336, 79.9442, 82.7549, 83.628, 84.5011, 85.3742, 86.2473, 87.1204, 87.9936, 88.8667, 89.7398, 90.6129, 91.486, 91.6806, 91.8752, 92.0697, 92.2643, 92.4589, 92.6535, 92.8481, 93.0426, 93.2372, 93.4318, 92.7568, 92.0819, 91.4069, 90.732, 90.057, 89.3821, 88.7071, 88.0322, 87.3572, 86.6823, 88.5006, 90.3188, 92.1371, 93.9554, 95.7736, 97.5919, 99.4102, 101.228, 103.047, 104.865, 106.079, 107.294, 108.508, 109.722, 110.936, 112.151, 113.365, 114.579, 115.794, 117.008, 117.088, 117.169, 117.249, 117.33, 117.41, 117.49, 117.571, 117.651, 117.732, 117.812, 117.517, 117.222, 116.927, 116.632, 116.336, 116.041, 115.746, 115.451, 115.156, 114.861, 114.967, 115.073, 115.18, 115.286, 115.392, 115.498, 115.604, 115.711, 115.817, 115.923, 115.212, 114.501, 113.789, 113.078, 112.367, 111.656, 110.945, 110.233, 109.522, 108.811, 108.865, 108.92, 108.974, 109.028, 109.082, 109.137, 109.191, 109.245, 109.3, 109.354, 109.199, 109.044, 108.888, 108.733, 108.578, 108.423, 108.268, 108.112, 107.957, 107.802, 107.501, 107.2, 106.898, 106.597, 106.296, 105.995, 105.694, 105.392, 105.091, 104.79, 105.08, 105.37, 105.66, 105.95, 106.239, 106.529, 106.819, 107.109, 107.399, 107.689, 107.361, 107.032, 106.704, 106.375, 106.047, 105.719, 105.39, 105.062, 104.733, 104.405, 104.369, 104.333, 104.297, 104.261, 104.225, 104.19, 104.154, 104.118, 104.082, 104.046, 103.641, 103.237, 102.832, 102.428, 102.023, 101.618, 101.214, 100.809, 100.405, 100, 99.6334, 99.2668, 98.9003, 98.5337, 98.1671, 97.8005, 97.4339, 97.0674, 96.7008, 96.3342, 96.2796, 96.225, 96.1703, 96.1157, 96.0611, 96.0065, 95.9519, 95.8972, 95.8426, 95.788, 95.0778, 94.3675, 93.6573, 92.947, 92.2368, 91.5266, 90.8163, 90.1061, 89.3958, 88.6856, 88.8177, 88.9497, 89.0818, 89.2138, 89.3459, 89.478, 89.61, 89.7421, 89.8741, 90.0062, 89.9655, 89.9248, 89.8841, 89.8434, 89.8026, 89.7619, 89.7212, 89.6805, 89.6398, 89.5991, 89.4091, 89.219, 89.029, 88.8389, 88.6489, 88.4589, 88.2688, 88.0788, 87.8887, 87.6987, 87.2577, 86.8167, 86.3757, 85.9347, 85.4936, 85.0526, 84.6116, 84.1706, 83.7296, 83.2886, 83.3297, 83.3707, 83.4118, 83.4528, 83.4939, 83.535, 83.576, 83.6171, 83.6581, 83.6992, 83.332, 82.9647, 82.5975, 82.2302, 81.863, 81.4958, 81.1285, 80.7613, 80.394, 80.0268, 80.0456, 80.0644, 80.0831, 80.1019, 80.1207, 80.1395, 80.1583, 80.177, 80.1958, 80.2146, 80.4209, 80.6272, 80.8336, 81.0399, 81.2462, 81.4525, 81.6588, 81.8652, 82.0715, 82.2778, 81.8784, 81.4791, 81.0797, 80.6804, 80.281, 79.8816, 79.4823, 79.0829, 78.6836, 78.2842, 77.4279, 76.5716, 75.7153, 74.859, 74.0027, 73.1465, 72.2902, 71.4339, 70.5776, 69.7213, 69.9101, 70.0989, 70.2876, 70.4764, 70.6652, 70.854, 71.0428, 71.2315, 71.4203, 71.6091, 71.8831, 72.1571, 72.4311, 72.7051, 72.979, 73.253, 73.527, 73.801, 74.075, 74.349, 73.0745, 71.8, 70.5255, 69.251, 67.9765, 66.702, 65.4275, 64.153, 62.8785, 61.604, 62.4322, 63.2603, 64.0885, 64.9166, 65.7448, 66.573, 67.4011, 68.2293, 69.0574, 69.8856, 70.4057, 70.9259, 71.446, 71.9662, 72.4863, 73.0064, 73.5266, 74.0467, 74.5669, 75.087, 73.9376, 72.7881, 71.6387, 70.4893, 69.3398, 68.1904, 67.041, 65.8916, 64.7421, 63.5927, 61.8752, 60.1578, 58.4403, 56.7229, 55.0054, 53.288, 51.5705, 49.8531, 48.1356, 46.4182, 48.4569, 50.4956, 52.5344, 54.5731, 56.6118, 58.6505, 60.6892, 62.728, 64.7667, 66.8054, 66.4631, 66.1209, 65.7786, 65.4364, 65.0941, 64.7518, 64.4096, 64.0673, 63.7251, 63.3828, 63.4749, 63.567, 63.6592, 63.7513, 63.8434, 63.9355, 64.0276, 64.1198, 64.2119, 64.304, 63.8188, 63.3336, 62.8484, 62.3632, 61.8779, 61.3927, 60.9075, 60.4223, 59.9371, 59.4519, 58.7026, 57.9533, 57.204, 56.4547, 55.7054, 54.9562, 54.2069, 53.4576, 52.7083, 51.959, 52.5072, 53.0553, 53.6035, 54.1516, 54.6998, 55.248, 55.7961, 56.3443, 56.8924, 57.4406, 57.7278, 58.015, 58.3022, 58.5894, 58.8765, 59.1637, 59.4509, 59.7381, 60.0253, 60.3125 }; #endregion #region Preetham Sky Spectrum to XYZ Conversion /// /// sun color spectrum S0 from 380 - 780nm in 10nm steps (taken from preetham Table 2) /// public static readonly double[] SpecS0_380_780_10nm = { 63.4, 65.8, 94.8, 104.8, 105.9, 96.8, 113.9, 125.6, 125.5, 121.3, 121.3, 113.5, 113.1, 110.8, 106.5, 108.8, 105.3, 104.4, 100.0, 96.0, 95.1, 89.1, 90.5, 90.3, 88.4, 84.0, 85.1, 81.9, 82.6, 84.9, 81.3, 71.9, 74.3, 76.4, 63.3, 71.7, 77.0, 65.2, 47.7, 68.6, 65.0 }; /// /// sun color spectrum S1 from 380 - 780nm in 10nm steps (taken from preetham Table 2) /// public static readonly double[] SpecS1_380_780_10nm = { 38.5, 35.0, 43.4, 46.3, 43.9, 37.1, 36.7, 35.9, 32.6, 27.9, 24.3, 20.1, 16.2, 13.2, 8.6, 6.1, 4.2, 1.9, 0.0, -1.6, -3.5, -3.5, -5.8, -7.2, -8.6, -9.5, -10.9, -10.7, -12.0, -14.0, -13.6, -12.0, -13.3, -12.9, -10.6, -11.6, -12.2, -10.2, -7.8, -11.2, -10.4 }; /// /// sun color spectrum S2 from 380 - 780nm in 10nm steps (taken from preetham Table 2) /// public static readonly double[] SpecS2_380_780_10nm = { 3.0, 1.2, -1.1, -0.5, -0.7, -1.2, -2.6, -2.9, -2.8, -2.6, -2.6, -1.8, -1.5, -1.3, -1.2, -1.0, -0.5, -0.3, 0.0, 0.2, 0.5, 2.1, 3.2, 4.1, 4.7, 5.1, 6.7, 7.3, 8.6, 9.8, 10.2, 8.3, 9.6, 8.5, 7.0, 7.6, 8.0, 6.7, 5.2, 7.4, 6.8 }; /// /// CIE XYZ standard observer sensitivity function X in 10mn steps. /// public static readonly double[] Ciexyz31X_380_780_10nm = { 0.001368000000, 0.004243000000, 0.014310000000, 0.043510000000, 0.134380000000, 0.283900000000, 0.348280000000, 0.336200000000, 0.290800000000, 0.195360000000, 0.095640000000, 0.032010000000, 0.004900000000, 0.009300000000, 0.063270000000, 0.165500000000, 0.290400000000, 0.433449900000, 0.594500000000, 0.762100000000, 0.916300000000, 1.026300000000, 1.062200000000, 1.002600000000, 0.854449900000, 0.642400000000, 0.447900000000, 0.283500000000, 0.164900000000, 0.087400000000, 0.046770000000, 0.022700000000, 0.011359160000, 0.005790346000, 0.002899327000, 0.001439971000, 0.000690078600, 0.000332301100, 0.000166150500, 0.000083075270, 0.000041509940 }; /// /// CIE XYZ standard observer sensitivity function Y in 10mn steps. /// public static readonly double[] Ciexyz31Y_380_780_10nm = { 0.000039000000, 0.000120000000, 0.000396000000, 0.001210000000, 0.004000000000, 0.011600000000, 0.023000000000, 0.038000000000, 0.060000000000, 0.090980000000, 0.139020000000, 0.208020000000, 0.323000000000, 0.503000000000, 0.710000000000, 0.862000000000, 0.954000000000, 0.994950100000, 0.995000000000, 0.952000000000, 0.870000000000, 0.757000000000, 0.631000000000, 0.503000000000, 0.381000000000, 0.265000000000, 0.175000000000, 0.107000000000, 0.061000000000, 0.032000000000, 0.017000000000, 0.008210000000, 0.004102000000, 0.002091000000, 0.001047000000, 0.000520000000, 0.000249200000, 0.000120000000, 0.000060000000, 0.000030000000, 0.000014990000 }; /// /// CIE XYZ standard observer sensitivity function Z in 10mn steps. /// public static readonly double[] Ciexyz31Z_380_780_10nm = { 0.006450001000, 0.020050010000, 0.067850010000, 0.207400000000, 0.645600000000, 1.385600000000, 1.747060000000, 1.772110000000, 1.669200000000, 1.287640000000, 0.812950100000, 0.465180000000, 0.272000000000, 0.158200000000, 0.078249990000, 0.042160000000, 0.020300000000, 0.008749999000, 0.003900000000, 0.002100000000, 0.001650001000, 0.001100000000, 0.000800000000, 0.000340000000, 0.000190000000, 0.000049999990, 0.000020000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000 }; #endregion } } ================================================ FILE: src/Aardvark.Base/Math/Curves/Curves.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace Aardvark.Base { public static partial class Ipol { public static partial class CubicHermite { public static Func Fun(int derivative) { if (derivative < 0) throw new IndexOutOfRangeException(); switch (derivative) { case 0: return Eval; case 1: return EvalD1; case 2: return EvalD2; case 3: return EvalD3; default: return (t, a, b, tIn, tOut) => V3d.Zero; } } public static double Eval(double t, double a, double b, double tIn, double tOut) { var w = Weights(t); return w[0] * a + w[1] * tIn + w[2] * tOut + w[3] * b; } public static V2d Eval(double t, V2d a, V2d b, V2d tIn, V2d tOut) { var w = Weights(t); return w[0] * a + w[1] * tIn + w[2] * tOut + w[3] * b; } public static V3d Eval(double t, V3d a, V3d b, V3d tIn, V3d tOut) { var w = Weights(t); return w[0] * a + w[1] * tIn + w[2] * tOut + w[3] * b; } public static double EvalD1(double t, double a, double b, double tIn, double tOut) { var w = WeightsD1(t); return w[0] * a + w[1] * tIn + w[2] * tOut + w[3] * b; } public static V2d EvalD1(double t, V2d a, V2d b, V2d tIn, V2d tOut) { var w = WeightsD1(t); return w[0] * a + w[1] * tIn + w[2] * tOut + w[3] * b; } public static V3d EvalD1(double t, V3d a, V3d b, V3d tIn, V3d tOut) { var w = WeightsD1(t); return w[0] * a + w[1] * tIn + w[2] * tOut + w[3] * b; } public static double EvalD2(double t, double a, double b, double tIn, double tOut) { var w = WeightsD2(t); return w[0] * a + w[1] * tIn + w[2] * tOut + w[3] * b; } public static V2d EvalD2(double t, V2d a, V2d b, V2d tIn, V2d tOut) { var w = WeightsD2(t); return w[0] * a + w[1] * tIn + w[2] * tOut + w[3] * b; } public static V3d EvalD2(double t, V3d a, V3d b, V3d tIn, V3d tOut) { var w = WeightsD2(t); return w[0] * a + w[1] * tIn + w[2] * tOut + w[3] * b; } public static double EvalD3(double t, double a, double b, double tIn, double tOut) { var w = WeightsD3(t); return w[0] * a + w[1] * tIn + w[2] * tOut + w[3] * b; } public static V2d EvalD3(double t, V2d a, V2d b, V2d tIn, V2d tOut) { var w = WeightsD3(t); return w[0] * a + w[1] * tIn + w[2] * tOut + w[3] * b; } public static V3d EvalD3(double t, V3d a, V3d b, V3d tIn, V3d tOut) { var w = WeightsD3(t); return w[0] * a + w[1] * tIn + w[2] * tOut + w[3] * b; } internal static double[] Weights(double t) { var tt = t * t; var ttt = tt * t; var tt3 = tt * 3; var ttt2 = ttt * 2; return new double[] { ttt2 - tt3 + 1, ttt - 2 * tt + t, ttt - tt, -ttt2 + tt3 }; } internal static double[] WeightsD1(double t) { var tt = t * t; var tt6 = tt * 6; var tt3 = tt * 3; var t6 = t * 6; return new double[] { tt6 - t6, tt3 - 4 * t + 1, tt3 - 2 * t, -tt6 + t6 }; } internal static double[] WeightsD2(double t) { var t12 = t * 12; var t6 = t * 6; return new double[] { t12 - 6, t6 - 4, t6 - 2, -t12 + 6 }; } internal static double[] WeightsD3(double t) { return new double[] { 12, 6, 6, -12 }; } } public static partial class CatmullRom { public static Func Fun(int derivative) { if (derivative < 0) throw new IndexOutOfRangeException(); switch (derivative) { case 0: return Eval; case 1: return EvalD1; case 2: return EvalD2; case 3: return EvalD3; default: return (t, p0, p1, p2, p3) => V3d.Zero; } } public static double Eval(double t, double p0, double p1, double p2, double p3) { var m0 = (p2 - p0) * 0.5; var m1 = (p3 - p1) * 0.5; return CubicHermite.Eval(t, p1, p2, m0, m1); } public static V2d Eval(double t, V2d p0, V2d p1, V2d p2, V2d p3) { var m0 = (p2 - p0) * 0.5; var m1 = (p3 - p1) * 0.5; return CubicHermite.Eval(t, p1, p2, m0, m1); } public static V3d Eval(double t, V3d p0, V3d p1, V3d p2, V3d p3) { var m0 = (p2 - p0) * 0.5; var m1 = (p3 - p1) * 0.5; return CubicHermite.Eval(t, p1, p2, m0, m1); } public static double EvalD1(double t, double p0, double p1, double p2, double p3) { var m0 = (p2 - p0) * 0.5; var m1 = (p3 - p1) * 0.5; return CubicHermite.EvalD1(t, p1, p2, m0, m1); } public static V2d EvalD1(double t, V2d p0, V2d p1, V2d p2, V2d p3) { var m0 = (p2 - p0) * 0.5; var m1 = (p3 - p1) * 0.5; return CubicHermite.EvalD1(t, p1, p2, m0, m1); } public static V3d EvalD1(double t, V3d p0, V3d p1, V3d p2, V3d p3) { var m0 = (p2 - p0) * 0.5; var m1 = (p3 - p1) * 0.5; return CubicHermite.EvalD1(t, p1, p2, m0, m1); } public static double EvalD2(double t, double p0, double p1, double p2, double p3) { var m0 = (p2 - p0) * 0.5; var m1 = (p3 - p1) * 0.5; return CubicHermite.EvalD2(t, p1, p2, m0, m1); } public static V2d EvalD2(double t, V2d p0, V2d p1, V2d p2, V2d p3) { var m0 = (p2 - p0) * 0.5; var m1 = (p3 - p1) * 0.5; return CubicHermite.EvalD2(t, p1, p2, m0, m1); } public static V3d EvalD2(double t, V3d p0, V3d p1, V3d p2, V3d p3) { var m0 = (p2 - p0) * 0.5; var m1 = (p3 - p1) * 0.5; return CubicHermite.EvalD2(t, p1, p2, m0, m1); } public static double EvalD3(double t, double p0, double p1, double p2, double p3) { var m0 = (p2 - p0) * 0.5; var m1 = (p3 - p1) * 0.5; return CubicHermite.EvalD3(t, p1, p2, m0, m1); } public static V2d EvalD3(double t, V2d p0, V2d p1, V2d p2, V2d p3) { var m0 = (p2 - p0) * 0.5; var m1 = (p3 - p1) * 0.5; return CubicHermite.EvalD3(t, p1, p2, m0, m1); } public static V3d EvalD3(double t, V3d p0, V3d p1, V3d p2, V3d p3) { var m0 = (p2 - p0) * 0.5; var m1 = (p3 - p1) * 0.5; return CubicHermite.EvalD3(t, p1, p2, m0, m1); } } public static partial class KochanekBartels { public static Func Fun(int derivative) { if (derivative < 0) throw new IndexOutOfRangeException(); switch (derivative) { case 0: return Eval; case 1: return EvalD1; case 2: return EvalD2; case 3: return EvalD3; default: return (t, p0, p1, p2, p3, tension, bias) => V3d.Zero; } } public static double Eval(double t, double p0, double p1, double p2, double p3, double tension, double bias) { var tangents = Tangents(p0, p1, p2, p3, tension, bias); return CubicHermite.Eval(t, p1, p2, tangents.Item1, tangents.Item2); } public static V2d Eval(double t, V2d p0, V2d p1, V2d p2, V2d p3, double tension, double bias) { var tangents = Tangents(p0, p1, p2, p3, tension, bias); return CubicHermite.Eval(t, p1, p2, tangents.Item1, tangents.Item2); } public static V3d Eval(double t, V3d p0, V3d p1, V3d p2, V3d p3, double tension, double bias) { var tangents = Tangents(p0, p1, p2, p3, tension, bias); return CubicHermite.Eval(t, p1, p2, tangents.Item1, tangents.Item2); } public static double EvalD1(double t, double p0, double p1, double p2, double p3, double tension, double bias) { var tangents = Tangents(p0, p1, p2, p3, tension, bias); return CubicHermite.EvalD1(t, p1, p2, tangents.Item1, tangents.Item2); } public static V2d EvalD1(double t, V2d p0, V2d p1, V2d p2, V2d p3, double tension, double bias) { var tangents = Tangents(p0, p1, p2, p3, tension, bias); return CubicHermite.EvalD1(t, p1, p2, tangents.Item1, tangents.Item2); } public static V3d EvalD1(double t, V3d p0, V3d p1, V3d p2, V3d p3, double tension, double bias) { var tangents = Tangents(p0, p1, p2, p3, tension, bias); return CubicHermite.EvalD1(t, p1, p2, tangents.Item1, tangents.Item2); } public static double EvalD2(double t, double p0, double p1, double p2, double p3, double tension, double bias) { var tangents = Tangents(p0, p1, p2, p3, tension, bias); return CubicHermite.EvalD2(t, p1, p2, tangents.Item1, tangents.Item2); } public static V2d EvalD2(double t, V2d p0, V2d p1, V2d p2, V2d p3, double tension, double bias) { var tangents = Tangents(p0, p1, p2, p3, tension, bias); return CubicHermite.EvalD2(t, p1, p2, tangents.Item1, tangents.Item2); } public static V3d EvalD2(double t, V3d p0, V3d p1, V3d p2, V3d p3, double tension, double bias) { var tangents = Tangents(p0, p1, p2, p3, tension, bias); return CubicHermite.EvalD2(t, p1, p2, tangents.Item1, tangents.Item2); } public static double EvalD3(double t, double p0, double p1, double p2, double p3, double tension, double bias) { var tangents = Tangents(p0, p1, p2, p3, tension, bias); return CubicHermite.EvalD3(t, p1, p2, tangents.Item1, tangents.Item2); } public static V2d EvalD3(double t, V2d p0, V2d p1, V2d p2, V2d p3, double tension, double bias) { var tangents = Tangents(p0, p1, p2, p3, tension, bias); return CubicHermite.EvalD3(t, p1, p2, tangents.Item1, tangents.Item2); } public static V3d EvalD3(double t, V3d p0, V3d p1, V3d p2, V3d p3, double tension, double bias) { var tangents = Tangents(p0, p1, p2, p3, tension, bias); return CubicHermite.EvalD3(t, p1, p2, tangents.Item1, tangents.Item2); } /// /// Computes the bounding box for interval [0, 1] of the /// Kochanek-Bartels spline defined by the specified points, /// tension, and bias. /// public static Box3d Bounds( V3d p0, V3d p1, V3d p2, V3d p3, double tension, double bias) { return Bounds(Range1d.Unit, p0, p1, p2, p3, tension, bias); } /// /// Computes the bounding box for interval [0, 1] of the /// Kochanek-Bartels spline defined by the specified points. /// public static Box3d Bounds(V3d p0, V3d p1, V3d p2, V3d p3) { return Bounds(Range1d.Unit, p0, p1, p2, p3, 0, 0); } /// /// Computes the bounding box of the Kochanek-Bartels spline /// defined by points the specified points, tension, and bias. /// public static Box3d Bounds(Range1d domain, V3d p0, V3d p1, V3d p2, V3d p3, double tension, double bias) { var oneMinusTensionHalf = (1 - tension) * 0.5; var x1 = oneMinusTensionHalf * (1 + bias); var x2 = oneMinusTensionHalf * (1 - bias); var s0 = p1 - p0; var s1 = p2 - p1; var s2 = p3 - p2; var m0 = x1 * s0 + x2 * s1; var m1 = x1 * s1 + x2 * s2; var bb = Box3d.Invalid; bb.ExtendBy(domain.Min > 0 ? Eval(domain.Min, p0, p1, p2, p3, tension, bias) : p1); bb.ExtendBy(domain.Max < 1 ? Eval(domain.Max, p0, p1, p2, p3, tension, bias) : p2); var a = 6 * p1 + 3 * m0 + 3 * m1 - 6 * p2; var b = -6 * p1 - 4 * m0 - 2 * m1 + 6 * p2; var c = m0; for (int i = 0; i < 3; i++) { var t = Polynomial.RealRootsOf(a[i], b[i], c[i]); var p0x = p0[i]; var p1x = p1[i]; var p2x = p2[i]; var p3x = p3[i]; if (t.Item1 > domain.Min && t.Item1 < domain.Max) bb.ExtendDimBy(i, Eval(t.Item1, p0x, p1x, p2x, p3x, tension, bias) ); if (t.Item2 > domain.Min && t.Item2 < domain.Max) bb.ExtendDimBy(i, Eval(t.Item2, p0x, p1x, p2x, p3x, tension, bias) ); } return bb; } /// /// Computes incoming (Item1) and outgoing (Item2) tangent. /// private static (double, double) Tangents( double p0, double p1, double p2, double p3, double tension, double bias) { var oneMinusTensionHalf = (1 - tension) * 0.5; var x1 = oneMinusTensionHalf * (1 + bias); var x2 = oneMinusTensionHalf * (1 - bias); var s0 = p1 - p0; var s1 = p2 - p1; var s2 = p3 - p2; return (x1 * s0 + x2 * s1, x1 * s1 + x2 * s2); } /// /// Computes incoming (Item1) and outgoing (Item2) tangent. /// private static (V2d, V2d) Tangents( V2d p0, V2d p1, V2d p2, V2d p3, double tension, double bias) { var oneMinusTensionHalf = (1 - tension) * 0.5; var x1 = oneMinusTensionHalf * (1 + bias); var x2 = oneMinusTensionHalf * (1 - bias); var s0 = p1 - p0; var s1 = p2 - p1; var s2 = p3 - p2; return (x1 * s0 + x2 * s1, x1 * s1 + x2 * s2); } /// /// Computes incoming (Item1) and outgoing (Item2) tangent. /// private static (V3d, V3d) Tangents( V3d p0, V3d p1, V3d p2, V3d p3, double tension, double bias) { var oneMinusTensionHalf = (1 - tension) * 0.5; var x1 = oneMinusTensionHalf * (1 + bias); var x2 = oneMinusTensionHalf * (1 - bias); var s0 = p1 - p0; var s1 = p2 - p1; var s2 = p3 - p2; return (x1 * s0 + x2 * s1, x1 * s1 + x2 * s2); } } } public class CurvePoints { private readonly double[] m_params; private readonly T[] m_items; private Range1i m_indexes; public CurvePoints(double[] parameters, T[] items) { if (parameters.Length != items.Length) throw new ArgumentException(); if (!parameters.IsStrictlyIncreasing()) throw new ArgumentException(); m_params = parameters; m_items = items; Init(); } public CurvePoints(IEnumerable> items) { var ordered = items.OrderBy(item => item.E0).ToArray(); m_params = ordered.Select(x => x.E0).ToArray(); m_items = ordered.Select(x => x.E1).ToArray(); Init(); } private void Init() { m_indexes = new Range1i(0, m_items.Length - 1); } public Tup[] Neighbourhood(double t) { int i = m_params.IndexOfLargestLessOrEqual(t).Clamp(m_indexes); int j = (i + 1).Clamp(m_indexes); return new Tup[] { new Tup(m_params[i], m_items[i]), new Tup(m_params[j], m_items[j]), }; } public Tup[] Neighbourhood( double t, int extendLeft, int extendRight) { int floor = m_params.IndexOfLargestLessOrEqual(t).Clamp(m_indexes); var result = new Tup[2 + extendLeft + extendRight]; int imin = floor - extendLeft; for (int i = imin; i <= floor + 1 + extendRight; i++) { int index = i.Clamp(m_indexes); result[i - imin] = new Tup(m_params[index], m_items[index]); } return result; } } } ================================================ FILE: src/Aardvark.Base/Math/Interfaces/IMatrix.cs ================================================ using System; using System.Collections.Generic; using System.Text; namespace Aardvark.Base { /// /// Non-generic Interface for Dim.X x Dim.Y - dimensional matrices. /// public interface IMatrix { V2l Dim { get; } object GetValue(long x, long y); void SetValue(object value, long x, long y); object GetValue(V2l v); void SetValue(object value, V2l v); } /// /// Generic Interface for NxM-dimensional matrix of Type T. /// The indexer of this interface has arguments of type long. /// public interface IMatrix : IMatrix { T this[long x, long y] { get; set; } T this[V2l v] { get; set; } } } ================================================ FILE: src/Aardvark.Base/Math/Interfaces/IOpacity.cs ================================================ namespace Aardvark.Base { public interface IOpacity { /// /// In range [0,1], where 0 means fully transparent, and 1 is fully opaque. /// double Opacity { get; set; } } } ================================================ FILE: src/Aardvark.Base/Math/Interfaces/IRGB.cs ================================================ using System; using System.Collections.Generic; using System.Text; namespace Aardvark.Base { public interface IRGB { double Red { get; set; } double Green { get; set; } double Blue { get; set; } } } ================================================ FILE: src/Aardvark.Base/Math/Interfaces/IRange.cs ================================================ using System; using System.Collections.Generic; using System.Text; namespace Aardvark.Base { /// /// IRange enforces a uniform design of all range types. /// This non-generic interface contains all the methods and properties /// that are independent of type. It serves as a base interface to /// the generic IRange interface. /// public interface IRange : IValidity { bool IsEmpty { get; } bool IsNonEmpty { get; } } /// /// ISimpleRange enforces a uniform interface of range operations that /// ony require comparison of boundaries. /// public interface ISimpleRange : IRange { /// /// Checks if the range is still valid and repairs if not. /// TRange Repair(); /// /// Returns whether range contains given value. /// bool Contains(TValue value); /// /// Returns whether range completely contains given range. /// bool Contains(TRange range); /// /// Checks if 2 ranges intersect each other. /// bool Intersects(TRange range); /// /// Returns the range extended to contain the supplied value. /// TRange ExtendedBy(TValue value); /// /// Returns the range extended to contain the supplied range. /// Returns this. /// TRange ExtendedBy(TRange range); /// /// Extends the range to contain the supplied value. /// void ExtendBy(TValue value); /// /// Extends the range to contain the supplied range. /// void ExtendBy(TRange range); } /// /// IRange enforces a uniform design of all range types. /// /// Type of range boundaries. /// Type of differences of TValue. /// Given values a and b of type TValue: typeof(TDiff) == typeof(a-b). /// Type of the concrete (implementing) range type. public interface IRange : IRange, IFormattable, ISimpleRange { // TValue Minimum { get; set; } // TValue Maximum { get; set; } TValue Center { get; } TDiff Size { get; } TRange SplitRight(TValue splitValue); TRange SplitLeft(TValue splitValue); /// /// Checks if 2 ranges intersect each other with tolerance parameter. /// bool Intersects(TRange range, TDiff eps); /// /// Returns range enlarged by specified vector in BOTH directions. /// TRange EnlargedBy(TDiff v); /// /// Returns range by shrunk specified vector in BOTH directions. /// The returned range may be invalid if vector is too large. /// TRange ShrunkBy(TDiff v); /// /// Returns range enlarged by given values (paddings). /// TRange EnlargedBy(TDiff left, TDiff right); /// /// Returns range shrunk by given values (paddings). /// The returned range may be invalid if the paddings are too large. /// TRange ShrunkBy(TDiff left, TDiff right); /// /// Enlarges range by specified vector in BOTH directions. /// void EnlargeBy(TDiff v); /// /// Shrinks range by specified vector in BOTH directions. /// Range may become invalid if vector is too large. /// void ShrinkBy(TDiff v); /// /// Enlarges range by given values (paddings). /// void EnlargeBy(TDiff left, TDiff right); /// /// Shrinks range by given values (paddings). /// void ShrinkBy(TDiff left, TDiff right); } /// /// IRange enforces a uniform design of all range types. /// /// Type of min and max elements of the range. /// Type of the concrete (implementing) range type. public interface IRange : IRange { } } ================================================ FILE: src/Aardvark.Base/Math/Interfaces/ISize_auto.cs ================================================ using System; using System.Collections.Generic; using System.Text; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! /// /// A Size2i reprents the size of an object in two dimensions. /// public interface ISize2i { V2i Size2i { get; } } /// /// A Size3i reprents the size of an object in three dimensions. /// public interface ISize3i { V3i Size3i { get; } } /// /// A Size4d reprents the size of an object in four dimensions. /// public interface ISize4i { V4i Size4i { get; } } /// /// A Size2ui reprents the size of an object in two dimensions. /// public interface ISize2ui { V2ui Size2ui { get; } } /// /// A Size3ui reprents the size of an object in three dimensions. /// public interface ISize3ui { V3ui Size3ui { get; } } /// /// A Size4d reprents the size of an object in four dimensions. /// public interface ISize4ui { V4ui Size4ui { get; } } /// /// A Size2l reprents the size of an object in two dimensions. /// public interface ISize2l { V2l Size2l { get; } } /// /// A Size3l reprents the size of an object in three dimensions. /// public interface ISize3l { V3l Size3l { get; } } /// /// A Size4d reprents the size of an object in four dimensions. /// public interface ISize4l { V4l Size4l { get; } } /// /// A Size2f reprents the size of an object in two dimensions. /// public interface ISize2f { V2f Size2f { get; } } /// /// A Size3f reprents the size of an object in three dimensions. /// public interface ISize3f { V3f Size3f { get; } } /// /// A Size4d reprents the size of an object in four dimensions. /// public interface ISize4f { V4f Size4f { get; } } /// /// A Size2d reprents the size of an object in two dimensions. /// public interface ISize2d { V2d Size2d { get; } } /// /// A Size3d reprents the size of an object in three dimensions. /// public interface ISize3d { V3d Size3d { get; } } /// /// A Size4d reprents the size of an object in four dimensions. /// public interface ISize4d { V4d Size4d { get; } } } ================================================ FILE: src/Aardvark.Base/Math/Interfaces/ISize_template.cs ================================================ using System; using System.Collections.Generic; using System.Text; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var ft in Meta.VecFieldTypes) { //# var ftype = ft.Name; //# var tc = ft.Char; /// /// A Size2__tc__ reprents the size of an object in two dimensions. /// public interface ISize2__tc__ { V2__tc__ Size2__tc__ { get; } } /// /// A Size3__tc__ reprents the size of an object in three dimensions. /// public interface ISize3__tc__ { V3__tc__ Size3__tc__ { get; } } /// /// A Size4d reprents the size of an object in four dimensions. /// public interface ISize4__tc__ { V4__tc__ Size4__tc__ { get; } } //# } } ================================================ FILE: src/Aardvark.Base/Math/Interfaces/ITensor.cs ================================================ namespace Aardvark.Base { /// /// Non-generic Interface for Dim.X x Dim.Y x Dim.Z, Dim.W - dimensional volumes. /// public interface ITensor4 { V4l Dim { get; } object GetValue(long x, long y, long z, long w); void SetValue(object value, long x, long y, long z, long w); object GetValue(V4l v); void SetValue(object value, V4l v); } /// /// Non-generic Interface for arbitrarily sized tensors. /// public interface ITensor { long[] Dim { get; } object GetValue(params long[] v); void SetValue(object value, params long[] v); } /// /// Generic Interface for NxMxLXK-dimensional volume of Type T. /// The indexer of this interface has arguments of type long. /// public interface ITensor4 : ITensor4 { T this[long x, long y, long z, long w] { get; set; } T this[V4l v] { get; set; } } /// /// Generic Interface for arbitrarily sized tensors of Type T. /// The indexer of this interface has arguments of type long. /// public interface ITensor : ITensor { int Rank { get; } T this[params long[] v] { get; set; } } } ================================================ FILE: src/Aardvark.Base/Math/Interfaces/IValidity.cs ================================================ using System; using System.Collections.Generic; using System.Text; namespace Aardvark.Base { public interface IValidity { bool IsValid { get; } bool IsInvalid { get; } } } ================================================ FILE: src/Aardvark.Base/Math/Interfaces/IVector.cs ================================================ using System; using System.Collections.Generic; using System.Text; namespace Aardvark.Base { /// /// Non-generic Interface for Dim - dimensional vectors. /// /// public interface IVector { long Dim { get; } object GetValue(long index); void SetValue(object value, long index); } /// /// Generic Interface for N-dimensional vector of Type T. /// The indexer of this interface has arguments of type long. /// public interface IVector : IVector { T this[long i] { get; set; } } } ================================================ FILE: src/Aardvark.Base/Math/Interfaces/IVolume.cs ================================================ namespace Aardvark.Base { /// /// Non-generic Interface for Dim.X x Dim.Y x Dim.Z - dimensional volumes. /// public interface IVolume { V3l Dim { get; } object GetValue(long x, long y, long z); void SetValue(object value, long x, long y, long z); object GetValue(V3l v); void SetValue(object value, V3l v); } /// /// Generic Interface for NxMxL-dimensional volume of Type T. /// The indexer of this interface has arguments of type long. /// public interface IVolume : IVolume { T this[long x, long y, long z] { get; set; } T this[V3l v] { get; set; } } } ================================================ FILE: src/Aardvark.Base/Math/Interfaces.cs ================================================ //namespace Aardvark.Base //{ // #region IMutablePolygon // public interface IMutablePolygon : IPolygon // { // void Set(int index, T value); // } // #endregion //} ================================================ FILE: src/Aardvark.Base/Math/Interpolation/Interpolation.cs ================================================ using System; using Ex = System.Linq.Expressions.Expression; namespace Aardvark.Base { #region Ipol public static partial class Ipol { #region Generators public static Func Generate( T a, T b, Func interpolator) { return Ipol.Generate(a, b, interpolator); } public static Func Generate( T a, T b, T c, T d, Func interpolator) { return Ipol.Generate(a, b, c, d, interpolator); } #endregion } #endregion #region Ipol public static class Ipol { internal static Func s_lerpInterpolator; #region Generators public static Func Generate( T a, T b, Func interpolator) { return x => interpolator(a, b, x); } public static Func Generate( T a, T b, T c, T d, Func interpolator) { return x => interpolator(a, b, c, d, x); } #endregion #region Linear Interpolation /// /// Gets a function that performs linear interpolation for values of T: /// (T a, T b, U t) => a * (1 - t) + b * t. /// For t = 0.0 the funtion will return a, and for t = 1.0 the function will return b. /// public static Func Lerp { get { if (s_lerpInterpolator == null) { var a = Ex.Parameter(typeof(T), "a"); var b = Ex.Parameter(typeof(T), "b"); var x = Ex.Parameter(typeof(U), "x"); var expr = Ex.Lambda>( Ex.Add( Ex.Multiply(a, Ex.Subtract(Ex.Constant(1.0), x)), Ex.Multiply(b, x) ), a, b, x ); s_lerpInterpolator = expr.Compile(); } return s_lerpInterpolator; } } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Interpolation/Mapping.cs ================================================ using System; using static System.Math; namespace Aardvark.Base { public static class Mapping { /// /// [-inf, +inf] => [0, 1] /// public static readonly Func Trunc = x => x < 0 ? 0 : (x > 1 ? 1 : x); /// /// [-inf, +inf] => [0, 1] /// public static readonly Func Repeat = x => x - Floor(x); /// /// [-inf, +inf] => [0, 1] /// public static readonly Func RepeatAndMirror = x => { x = x - Floor(x * 0.5) * 2; return x < 1 ? x : 2 - x; }; /// /// [0, 1] => [0, 1] /// public static readonly Func Linear = x => x; /// /// [0, 1] => [0, 1] /// public static readonly Func Cosine = x => (1 - Cos(x * PI)) * 0.5; /// /// [0, 1] => [0, 1] /// public static readonly Func EaseIn = x => Pow(x, 1.3); /// /// [0, 1] => [0, 1] /// public static readonly Func EaseOut = x => 1 - EaseIn(1 - x); /// /// [0, 1] => [0, 1] /// public static readonly Func EaseInEaseOut = Cosine; /// /// [0, 1] => [0, 1] /// public static readonly Func Min = x => 0; /// /// [0, 1] => [0, 1] /// public static readonly Func Max = x => 1; /// /// [0, 1] => [0, 1] /// public static readonly Func JumpStart = x => x > 0 ? 1 : 0; /// /// [0, 1] => [0, 1] /// public static readonly Func JumpStop = x => x < 1 ? 0 : 1; } } ================================================ FILE: src/Aardvark.Base/Math/LuFactorization.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Aardvark.Base { public static partial class NumericExtensions { #region Partially pivoting LU factorization of float[,] arrays // Note that this version of the LU factorization is mostly provided // for studying the algorithm. In practice the Matrix version // is noticeably faster, since it performs incremental indexing. /// /// Perform a partially pivoting LU factorization of the supplied /// matrix, i.e A = inv(P) LU, so that any matrix equation A x = b /// can be solved using LU x = P b. The permutation matrix P is /// returns as permutation vector. WARNING: the supplied matrix A is /// overwritten with its factorization LU, both in the parameter alu. /// If the matrix is singular an ArgumentException is thrown. /// public static int[] LuFactorize(this float[,] alu) { int n = Fun.Min(alu.GetLength(0), alu.GetLength(1)); int[] perm = new int[n]; if (alu.LuFactorize(perm)) return perm; throw new ArgumentException("singular matrix"); } /// /// Perform a partially pivoting LU factorization of the supplied /// matrix, i.e A = inv(P) LU, so that any matrix equation A x = b /// can be solved using LU x = P b. The permutation matrix P is /// filled into the supplied permutation vector p, and the supplied /// matrix A is overwritten with its factorization LU, both in the /// parameter alu. The function returns true if the factorization /// is successful, otherwise the matrix is singular and false is /// returned. /// public static bool LuFactorize(this float[,] alu, int[] p) { int n = p.Length; p.SetByIndex(i => i); for (int k = 0; k < n - 1; k++) { int pi = k; float pivot = alu[pi, k], absPivot = Fun.Abs(pivot); for (int i = k + 1; i < n; i++) { float value = alu[i, k], absValue = Fun.Abs(value); if (absValue > absPivot) { pivot = value; absPivot = absValue; pi = i; } } if (Fun.IsTiny(pivot)) return false; if (pi != k) { Fun.Swap(ref p[pi], ref p[k]); for (int i = 0; i < n; i++) Fun.Swap(ref alu[pi, i], ref alu[k, i]); } for (int j = k + 1; j < n; j++) { float factor = alu[j, k] / pivot; alu[j, k] = factor; // construct L for (int i = k + 1; i < n; i++) alu[j, i] -= alu[k, i] * factor; } } return true; } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix lu, P is a permutation matrix /// supplied as a permutation array p, and b is the right hand side /// supplied as a vector. The returned x satisfies the equation. /// public static float[] LuSolve(this float[,] lu, int[] p, float[] b) { int n = Fun.Min(lu.GetLength(0), lu.GetLength(1)); if (n != p.GetLength(0)) throw new ArgumentException(); if (n > b.GetLength(0)) throw new ArgumentException(); var x = new float[n]; lu.LuSolve(p, b, x); return x; } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix lu, P is a permutation matrix /// supplied as a permutation array p, and b is the right hand side /// supplied as a vector. The result vector that satisfies the /// equation is filled into the supplied parameter x. /// public static void LuSolve(this float[,] lu, int[] p, float[] b, float[] x) { int n = p.Length; for (int i = 0; i < n; i++) x[i] = b[p[i]]; for (int j = 1; j < n; j++) { float scalar = x[j]; for (int i = 0; i < j; i++) scalar -= lu[j, i] * x[i]; x[j] = scalar; } for (int j = n - 1; j >= 0; j--) { float scalar = x[j]; for (int i = j + 1; i < n; i++) scalar -= lu[j, i] * x[i]; x[j] = scalar / lu[j, j]; } } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix, P is a permutation matrix /// supplied as a permutation array, and b is a supplied matrix. /// The returned matrix x satisfies the equation. /// public static float[,] LuSolve(this float[,] lu, int[] p, float[,] b) { int n = Fun.Min(lu.GetLength(0), lu.GetLength(1)); if (n != p.GetLength(0)) throw new ArgumentException(); if (n > b.GetLength(0)) throw new ArgumentException(); int m = b.GetLength(1); float[,] x = new float[n, m]; lu.LuSolve(p, b, x); return x; } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix, P is a permutation matrix /// supplied as a permutation array, and b is a supplied matrix. /// The result matrix that satisfies the equation is filled into the /// supplied parameter x. /// public static void LuSolve(this float[,] lu, int[] p, float[,] b, float[,] x) { int n = p.Length; int m = b.GetLength(1); for (int j = 0; j < n; j++) for (int i = 0; i < m; i++) x[j, i] = b[p[j], i]; for (int k = 1; k < n; k++) for (int j = 0; j < k; j++) for (int i = 0; i < m; i++) x[k, i] -= lu[k, j] * x[j, i]; for (int k = n - 1; k >= 0; k--) { for (int j = k + 1; j < n; j++) for (int i = 0; i < m; i++) x[k, i] -= lu[k, j] * x[j, i]; var factor = lu[k, k]; // storing the inverse would increase the mean error for (int i = 0; i < m; i++) x[k, i] /= factor; } } /// /// Return the inverse inv(A) of a the supplied LU factorized matrix /// lu, where A = inv(P) LU. The permuation matrix P is supplied as /// the permutation vector p. /// public static float[,] LuInverse(this float[,] lu, int[] p) { int n = Fun.Min(lu.GetLength(0), lu.GetLength(1)); if (n != p.GetLength(0)) throw new ArgumentException(); float[,] inv = new float[n, n]; lu.LuInverse(p, inv); return inv; } /// /// Compute the inverse inv(A) of a the supplied LU factorized matrix /// lu, where A = inv(P) LU. The permuation matrix P is supplied as /// the permutation vector p. The result matrix is filled into the /// supplied matrix. /// public static void LuInverse(this float[,] lu, int[] p, float[,] inv) { int n = p.Length; for (int j = 0; j < n; j++) for (int i = 0; i < n; i++) inv[j, i] = p[j] == i ? 1 : 0; for (int k = 1; k < n; k++) for (int j = 0; j < k; j++) for (int i = 0; i < n; i++) inv[k, i] -= lu[k, j] * inv[j, i]; for (int k = n - 1; k >= 0; k--) { for (int j = k + 1; j < n; j++) for (int i = 0; i < n; i++) inv[k, i] -= lu[k, j] * inv[j, i]; var factor = lu[k, k]; // storing the inverse would increase the mean error for (int i = 0; i < n; i++) inv[k, i] /= factor; } } #endregion #region Partially pivoting LU factorization of float[] arrays with offset and strides /// /// Perform a partially pivoting LU factorization of the supplied /// matrix in-place, i.e A = inv(P) LU, so that any matrix equation /// A x = b can be solved using LU x = P b. The permutation matrix P /// is filled into the supplied permutation vector p, and the supplied /// matrix A is overwritten with its factorization LU, both in the /// parameter alu. The function returns true if the factorization /// is successful, otherwise the matrix is singular and false is /// returned. No size checks are performed. /// public static bool LuFactorize( this float[] alu, long a0, long ax, long ay, int[] p) { long n = p.LongLength; p.SetByIndex(i => i); for (long k = 0, ak = a0, a_k = 0; k < n - 1; k++, ak += ay, a_k += ax) { long pi = k; float pivot = alu[ak + a_k], absPivot = Fun.Abs(pivot); for (long i = k + 1, aik = ak + ay + a_k; i < n; i++, aik += ay) { float value = alu[aik], absValue = Fun.Abs(value); if (absValue > absPivot) { pivot = value; absPivot = absValue; pi = i; } } if (Fun.IsTiny(pivot)) return false; if (pi != k) { long api = a0 + pi * ay; Fun.Swap(ref p[pi], ref p[k]); for (long i = 0, apii = api, aki = ak; i < n; i++, apii += ax, aki += ax) Fun.Swap(ref alu[apii], ref alu[aki]); } for (long j = k + 1, aj = ak + ay, ajk = aj + a_k; j < n; j++, aj += ay, ajk += ay) { float factor = alu[ajk] / pivot; alu[ajk] = factor; for (long i = k + 1, aji = ajk + ax, aki = ak + a_k + ax; i < n; i++, aji += ax, aki += ax) alu[aji] -= alu[aki] * factor; } } return true; } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix lu, P is a permutation matrix /// supplied as a permutation array p, and b is the right hand side /// supplied as a vector starting at b0 with element to element /// delta bD. The result vector that satisfies the equation is /// filled into the supplied parameter x beginning at index x0 /// with element to element delta xD. /// public static void LuSolve( this float[] lu, long l0, long lx, long ly, int[] p, float[] b, long b0, long bd, float[] x, long x0, long xd) { long n = p.LongLength; for (long i = 0, xi = x0; i < n; i++, xi += xd) x[xi] = b[b0 + p[i] * bd]; for (long j = 1, xj = x0 + xd, lj = l0 + ly; j < n; j++, xj += xd, lj += ly) { float scalar = x[xj]; for (long i = 0, lji = lj, xi = x0; i < j; i++, lji += lx, xi += xd) scalar -= lu[lji] * x[xi]; x[xj] = scalar; } for (long j = n - 1, xj = x0 + j * xd, lj = l0 + j * ly, ljj = lj + j * lx; j >= 0; j--, xj -= xd, lj -= ly, ljj -= ly + lx) { float scalar = x[xj]; for (long i = j + 1, xi = xj + xd, lji = ljj + lx; i < n; i++, xi += xd, lji += lx) scalar -= lu[lji] * x[xi]; x[xj] = scalar / lu[ljj]; } } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix, P is a permutation matrix /// supplied as a permutation array, and b is a supplied matrix. /// The result matrix that satisfies the equation is filled into the /// supplied parameter x. /// public static void LuSolve( this float[] lu, long l0, long lx, long ly, int[] p, long m, float[] b, long b0, long bx, long by, float[] x, long x0, long xx, long xy) { int n = p.Length; for (long j = 0, xj = x0; j < n; j++, xj += xy) for (long i = 0, bpji = b0 + p[j] * by, xji = xj; i < m; i++, bpji += bx, xji += xx) x[xji] = b[bpji]; for (long k = 1, xk = x0 + xy, lk = l0 + ly; k < n; k++, xk += xy, lk += ly) for (long j = 0, xj = x0, lkj = lk; j < k; j++, xj += xy, lkj += lx) for (long i = 0, xki = xk, xji = xj; i < m; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; for (long k = n - 1, xk = x0 + k * xy, lk = l0 + k * ly, lkk = lk + k * lx; k >= 0; k--, xk -= xy, lk -= ly, lkk -= ly + lx) { for (long j = k + 1, lkj = lkk + lx, xj = xk + xy; j < n; j++, lkj += lx, xj += xy) for (long i = 0, xki = xk, xji = xj; i < m; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; var factor = lu[lkk]; // storing the inverse would increase the mean error for (long i = 0, xki = xk; i < m; i++, xki += xx) x[xki] /= factor; } } /// /// Compute the inverse inv(A) of a the supplied LU factorized matrix /// lu, where A = inv(P) LU. The permuation matrix P is supplied as /// the permutation vector p. The inverse matrix is filled into the /// supplied matrix x. /// public static void LuInverse( this float[] lu, long l0, long lx, long ly, int[] p, float[] x, long x0, long xx, long xy) { int n = p.Length; for (long j = 0, xj = x0; j < n; j++, xj += xy) for (long i = 0, xji = xj; i < n; i++, xji += xx) x[xji] = p[j] == i ? 1 : 0; for (long k = 1, xk = x0 + xy, lk = l0 + ly; k < n; k++, xk += xy, lk += ly) for (long j = 0, xj = x0, lkj = lk; j < k; j++, xj += xy, lkj += lx) for (long i = 0, xki = xk, xji = xj; i < n; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; for (long k = n - 1, xk = x0 + k * xy, lk = l0 + k * ly, lkk = lk + k * lx; k >= 0; k--, xk -= xy, lk -= ly, lkk -= ly + lx) { for (long j = k + 1, lkj = lkk + lx, xj = xk + xy; j < n; j++, lkj += lx, xj += xy) for (long i = 0, xki = xk, xji = xj; i < n; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; var factor = lu[lkk]; // storing the inverse would increase the mean error for (long i = 0, xki = xk; i < n; i++, xki += xx) x[xki] /= factor; } } #endregion #region Partially pivoting LU factorization of float* pointers with offset and strides /// /// Perform a partially pivoting LU factorization of the supplied /// matrix in-place, i.e A = inv(P) LU, so that any matrix equation /// A x = b can be solved using LU x = P b. The permutation matrix P /// is filled into the supplied permutation vector p, and the supplied /// matrix A is overwritten with its factorization LU, both in the /// parameter alu. The function returns true if the factorization /// is successful, otherwise the matrix is singular and false is /// returned. No size checks are performed. /// public static unsafe bool LuFactorize( float* alu, long a0, long ax, long ay, int* p, long n) { for (long i = 0; i < n; i++) p[i] = (int)i; for (long k = 0, ak = a0, a_k = 0; k < n - 1; k++, ak += ay, a_k += ax) { long pi = k; float pivot = alu[ak + a_k], absPivot = Fun.Abs(pivot); for (long i = k + 1, aik = ak + ay + a_k; i < n; i++, aik += ay) { float value = alu[aik], absValue = Fun.Abs(value); if (absValue > absPivot) { pivot = value; absPivot = absValue; pi = i; } } if (Fun.IsTiny(pivot)) return false; if (pi != k) { long api = a0 + pi * ay; Fun.Swap(ref p[pi], ref p[k]); for (long i = 0, apii = api, aki = ak; i < n; i++, apii += ax, aki += ax) Fun.Swap(ref alu[apii], ref alu[aki]); } for (long j = k + 1, aj = ak + ay, ajk = aj + a_k; j < n; j++, aj += ay, ajk += ay) { float factor = alu[ajk] / pivot; alu[ajk] = factor; for (long i = k + 1, aji = ajk + ax, aki = ak + a_k + ax; i < n; i++, aji += ax, aki += ax) alu[aji] -= alu[aki] * factor; } } return true; } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix lu, P is a permutation matrix /// supplied as a permutation array p, and b is the right hand side /// supplied as a vector starting at b0 with element to element /// delta bD. The result vector that satisfies the equation is /// filled into the supplied parameter x beginning at index x0 /// with element to element delta xD. /// public static unsafe void LuSolve( float* lu, long l0, long lx, long ly, int* p, float* b, long b0, long bd, float* x, long x0, long xd, long n) { for (long i = 0, xi = x0; i < n; i++, xi += xd) x[xi] = b[b0 + p[i] * bd]; for (long j = 1, xj = x0 + xd, lj = l0 + ly; j < n; j++, xj += xd, lj += ly) { float scalar = x[xj]; for (long i = 0, lji = lj, xi = x0; i < j; i++, lji += lx, xi += xd) scalar -= lu[lji] * x[xi]; x[xj] = scalar; } for (long j = n - 1, xj = x0 + j * xd, lj = l0 + j * ly, ljj = lj + j * lx; j >= 0; j--, xj -= xd, lj -= ly, ljj -= ly + lx) { float scalar = x[xj]; for (long i = j + 1, xi = xj + xd, lji = ljj + lx; i < n; i++, xi += xd, lji += lx) scalar -= lu[lji] * x[xi]; x[xj] = scalar / lu[ljj]; } } /// /// Compute the inverse inv(A) of a the supplied LU factorized matrix /// lu, where A = inv(P) LU. The permuation matrix P is supplied as /// the permutation vector p. The inverse matrix is filled into the /// supplied matrix x. /// public static unsafe void LuInverse( float* lu, long l0, long lx, long ly, int* p, float* x, long x0, long xx, long xy, long n) { for (long j = 0, xj = x0; j < n; j++, xj += xy) for (long i = 0, xji = xj; i < n; i++, xji += xx) x[xji] = p[j] == i ? 1 : 0; for (long k = 1, xk = x0 + xy, lk = l0 + ly; k < n; k++, xk += xy, lk += ly) for (long j = 0, xj = x0, lkj = lk; j < k; j++, xj += xy, lkj += lx) for (long i = 0, xki = xk, xji = xj; i < n; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; for (long k = n - 1, xk = x0 + k * xy, lk = l0 + k * ly, lkk = lk + k * lx; k >= 0; k--, xk -= xy, lk -= ly, lkk -= ly + lx) { for (long j = k + 1, lkj = lkk + lx, xj = xk + xy; j < n; j++, lkj += lx, xj += xy) for (long i = 0, xki = xk, xji = xj; i < n; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; var factor = lu[lkk]; // storing the inverse would increase the mean error for (long i = 0, xki = xk; i < n; i++, xki += xx) x[xki] /= factor; } } #endregion #region Partially pivoting LU factorization of double[,] arrays // Note that this version of the LU factorization is mostly provided // for studying the algorithm. In practice the Matrix version // is noticeably faster, since it performs incremental indexing. /// /// Perform a partially pivoting LU factorization of the supplied /// matrix, i.e A = inv(P) LU, so that any matrix equation A x = b /// can be solved using LU x = P b. The permutation matrix P is /// returns as permutation vector. WARNING: the supplied matrix A is /// overwritten with its factorization LU, both in the parameter alu. /// If the matrix is singular an ArgumentException is thrown. /// public static int[] LuFactorize(this double[,] alu) { int n = Fun.Min(alu.GetLength(0), alu.GetLength(1)); int[] perm = new int[n]; if (alu.LuFactorize(perm)) return perm; throw new ArgumentException("singular matrix"); } /// /// Perform a partially pivoting LU factorization of the supplied /// matrix, i.e A = inv(P) LU, so that any matrix equation A x = b /// can be solved using LU x = P b. The permutation matrix P is /// filled into the supplied permutation vector p, and the supplied /// matrix A is overwritten with its factorization LU, both in the /// parameter alu. The function returns true if the factorization /// is successful, otherwise the matrix is singular and false is /// returned. /// public static bool LuFactorize(this double[,] alu, int[] p) { int n = p.Length; p.SetByIndex(i => i); for (int k = 0; k < n - 1; k++) { int pi = k; double pivot = alu[pi, k], absPivot = Fun.Abs(pivot); for (int i = k + 1; i < n; i++) { double value = alu[i, k], absValue = Fun.Abs(value); if (absValue > absPivot) { pivot = value; absPivot = absValue; pi = i; } } if (Fun.IsTiny(pivot)) return false; if (pi != k) { Fun.Swap(ref p[pi], ref p[k]); for (int i = 0; i < n; i++) Fun.Swap(ref alu[pi, i], ref alu[k, i]); } for (int j = k + 1; j < n; j++) { double factor = alu[j, k] / pivot; alu[j, k] = factor; // construct L for (int i = k + 1; i < n; i++) alu[j, i] -= alu[k, i] * factor; } } return true; } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix lu, P is a permutation matrix /// supplied as a permutation array p, and b is the right hand side /// supplied as a vector. The returned x satisfies the equation. /// public static double[] LuSolve(this double[,] lu, int[] p, double[] b) { int n = Fun.Min(lu.GetLength(0), lu.GetLength(1)); if (n != p.GetLength(0)) throw new ArgumentException(); if (n > b.GetLength(0)) throw new ArgumentException(); var x = new double[n]; lu.LuSolve(p, b, x); return x; } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix lu, P is a permutation matrix /// supplied as a permutation array p, and b is the right hand side /// supplied as a vector. The result vector that satisfies the /// equation is filled into the supplied parameter x. /// public static void LuSolve(this double[,] lu, int[] p, double[] b, double[] x) { int n = p.Length; for (int i = 0; i < n; i++) x[i] = b[p[i]]; for (int j = 1; j < n; j++) { double scalar = x[j]; for (int i = 0; i < j; i++) scalar -= lu[j, i] * x[i]; x[j] = scalar; } for (int j = n - 1; j >= 0; j--) { double scalar = x[j]; for (int i = j + 1; i < n; i++) scalar -= lu[j, i] * x[i]; x[j] = scalar / lu[j, j]; } } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix, P is a permutation matrix /// supplied as a permutation array, and b is a supplied matrix. /// The returned matrix x satisfies the equation. /// public static double[,] LuSolve(this double[,] lu, int[] p, double[,] b) { int n = Fun.Min(lu.GetLength(0), lu.GetLength(1)); if (n != p.GetLength(0)) throw new ArgumentException(); if (n > b.GetLength(0)) throw new ArgumentException(); int m = b.GetLength(1); double[,] x = new double[n, m]; lu.LuSolve(p, b, x); return x; } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix, P is a permutation matrix /// supplied as a permutation array, and b is a supplied matrix. /// The result matrix that satisfies the equation is filled into the /// supplied parameter x. /// public static void LuSolve(this double[,] lu, int[] p, double[,] b, double[,] x) { int n = p.Length; int m = b.GetLength(1); for (int j = 0; j < n; j++) for (int i = 0; i < m; i++) x[j, i] = b[p[j], i]; for (int k = 1; k < n; k++) for (int j = 0; j < k; j++) for (int i = 0; i < m; i++) x[k, i] -= lu[k, j] * x[j, i]; for (int k = n - 1; k >= 0; k--) { for (int j = k + 1; j < n; j++) for (int i = 0; i < m; i++) x[k, i] -= lu[k, j] * x[j, i]; var factor = lu[k, k]; // storing the inverse would increase the mean error for (int i = 0; i < m; i++) x[k, i] /= factor; } } /// /// Return the inverse inv(A) of a the supplied LU factorized matrix /// lu, where A = inv(P) LU. The permuation matrix P is supplied as /// the permutation vector p. /// public static double[,] LuInverse(this double[,] lu, int[] p) { int n = Fun.Min(lu.GetLength(0), lu.GetLength(1)); if (n != p.GetLength(0)) throw new ArgumentException(); double[,] inv = new double[n, n]; lu.LuInverse(p, inv); return inv; } /// /// Compute the inverse inv(A) of a the supplied LU factorized matrix /// lu, where A = inv(P) LU. The permuation matrix P is supplied as /// the permutation vector p. The result matrix is filled into the /// supplied matrix. /// public static void LuInverse(this double[,] lu, int[] p, double[,] inv) { int n = p.Length; for (int j = 0; j < n; j++) for (int i = 0; i < n; i++) inv[j, i] = p[j] == i ? 1 : 0; for (int k = 1; k < n; k++) for (int j = 0; j < k; j++) for (int i = 0; i < n; i++) inv[k, i] -= lu[k, j] * inv[j, i]; for (int k = n - 1; k >= 0; k--) { for (int j = k + 1; j < n; j++) for (int i = 0; i < n; i++) inv[k, i] -= lu[k, j] * inv[j, i]; var factor = lu[k, k]; // storing the inverse would increase the mean error for (int i = 0; i < n; i++) inv[k, i] /= factor; } } #endregion #region Partially pivoting LU factorization of double[] arrays with offset and strides /// /// Perform a partially pivoting LU factorization of the supplied /// matrix in-place, i.e A = inv(P) LU, so that any matrix equation /// A x = b can be solved using LU x = P b. The permutation matrix P /// is filled into the supplied permutation vector p, and the supplied /// matrix A is overwritten with its factorization LU, both in the /// parameter alu. The function returns true if the factorization /// is successful, otherwise the matrix is singular and false is /// returned. No size checks are performed. /// public static bool LuFactorize( this double[] alu, long a0, long ax, long ay, int[] p) { long n = p.LongLength; p.SetByIndex(i => i); for (long k = 0, ak = a0, a_k = 0; k < n - 1; k++, ak += ay, a_k += ax) { long pi = k; double pivot = alu[ak + a_k], absPivot = Fun.Abs(pivot); for (long i = k + 1, aik = ak + ay + a_k; i < n; i++, aik += ay) { double value = alu[aik], absValue = Fun.Abs(value); if (absValue > absPivot) { pivot = value; absPivot = absValue; pi = i; } } if (Fun.IsTiny(pivot)) return false; if (pi != k) { long api = a0 + pi * ay; Fun.Swap(ref p[pi], ref p[k]); for (long i = 0, apii = api, aki = ak; i < n; i++, apii += ax, aki += ax) Fun.Swap(ref alu[apii], ref alu[aki]); } for (long j = k + 1, aj = ak + ay, ajk = aj + a_k; j < n; j++, aj += ay, ajk += ay) { double factor = alu[ajk] / pivot; alu[ajk] = factor; for (long i = k + 1, aji = ajk + ax, aki = ak + a_k + ax; i < n; i++, aji += ax, aki += ax) alu[aji] -= alu[aki] * factor; } } return true; } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix lu, P is a permutation matrix /// supplied as a permutation array p, and b is the right hand side /// supplied as a vector starting at b0 with element to element /// delta bD. The result vector that satisfies the equation is /// filled into the supplied parameter x beginning at index x0 /// with element to element delta xD. /// public static void LuSolve( this double[] lu, long l0, long lx, long ly, int[] p, double[] b, long b0, long bd, double[] x, long x0, long xd) { long n = p.LongLength; for (long i = 0, xi = x0; i < n; i++, xi += xd) x[xi] = b[b0 + p[i] * bd]; for (long j = 1, xj = x0 + xd, lj = l0 + ly; j < n; j++, xj += xd, lj += ly) { double scalar = x[xj]; for (long i = 0, lji = lj, xi = x0; i < j; i++, lji += lx, xi += xd) scalar -= lu[lji] * x[xi]; x[xj] = scalar; } for (long j = n - 1, xj = x0 + j * xd, lj = l0 + j * ly, ljj = lj + j * lx; j >= 0; j--, xj -= xd, lj -= ly, ljj -= ly + lx) { double scalar = x[xj]; for (long i = j + 1, xi = xj + xd, lji = ljj + lx; i < n; i++, xi += xd, lji += lx) scalar -= lu[lji] * x[xi]; x[xj] = scalar / lu[ljj]; } } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix, P is a permutation matrix /// supplied as a permutation array, and b is a supplied matrix. /// The result matrix that satisfies the equation is filled into the /// supplied parameter x. /// public static void LuSolve( this double[] lu, long l0, long lx, long ly, int[] p, long m, double[] b, long b0, long bx, long by, double[] x, long x0, long xx, long xy) { int n = p.Length; for (long j = 0, xj = x0; j < n; j++, xj += xy) for (long i = 0, bpji = b0 + p[j] * by, xji = xj; i < m; i++, bpji += bx, xji += xx) x[xji] = b[bpji]; for (long k = 1, xk = x0 + xy, lk = l0 + ly; k < n; k++, xk += xy, lk += ly) for (long j = 0, xj = x0, lkj = lk; j < k; j++, xj += xy, lkj += lx) for (long i = 0, xki = xk, xji = xj; i < m; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; for (long k = n - 1, xk = x0 + k * xy, lk = l0 + k * ly, lkk = lk + k * lx; k >= 0; k--, xk -= xy, lk -= ly, lkk -= ly + lx) { for (long j = k + 1, lkj = lkk + lx, xj = xk + xy; j < n; j++, lkj += lx, xj += xy) for (long i = 0, xki = xk, xji = xj; i < m; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; var factor = lu[lkk]; // storing the inverse would increase the mean error for (long i = 0, xki = xk; i < m; i++, xki += xx) x[xki] /= factor; } } /// /// Compute the inverse inv(A) of a the supplied LU factorized matrix /// lu, where A = inv(P) LU. The permuation matrix P is supplied as /// the permutation vector p. The inverse matrix is filled into the /// supplied matrix x. /// public static void LuInverse( this double[] lu, long l0, long lx, long ly, int[] p, double[] x, long x0, long xx, long xy) { int n = p.Length; for (long j = 0, xj = x0; j < n; j++, xj += xy) for (long i = 0, xji = xj; i < n; i++, xji += xx) x[xji] = p[j] == i ? 1 : 0; for (long k = 1, xk = x0 + xy, lk = l0 + ly; k < n; k++, xk += xy, lk += ly) for (long j = 0, xj = x0, lkj = lk; j < k; j++, xj += xy, lkj += lx) for (long i = 0, xki = xk, xji = xj; i < n; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; for (long k = n - 1, xk = x0 + k * xy, lk = l0 + k * ly, lkk = lk + k * lx; k >= 0; k--, xk -= xy, lk -= ly, lkk -= ly + lx) { for (long j = k + 1, lkj = lkk + lx, xj = xk + xy; j < n; j++, lkj += lx, xj += xy) for (long i = 0, xki = xk, xji = xj; i < n; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; var factor = lu[lkk]; // storing the inverse would increase the mean error for (long i = 0, xki = xk; i < n; i++, xki += xx) x[xki] /= factor; } } #endregion #region Partially pivoting LU factorization of double* pointers with offset and strides /// /// Perform a partially pivoting LU factorization of the supplied /// matrix in-place, i.e A = inv(P) LU, so that any matrix equation /// A x = b can be solved using LU x = P b. The permutation matrix P /// is filled into the supplied permutation vector p, and the supplied /// matrix A is overwritten with its factorization LU, both in the /// parameter alu. The function returns true if the factorization /// is successful, otherwise the matrix is singular and false is /// returned. No size checks are performed. /// public static unsafe bool LuFactorize( double* alu, long a0, long ax, long ay, int* p, long n) { for (long i = 0; i < n; i++) p[i] = (int)i; for (long k = 0, ak = a0, a_k = 0; k < n - 1; k++, ak += ay, a_k += ax) { long pi = k; double pivot = alu[ak + a_k], absPivot = Fun.Abs(pivot); for (long i = k + 1, aik = ak + ay + a_k; i < n; i++, aik += ay) { double value = alu[aik], absValue = Fun.Abs(value); if (absValue > absPivot) { pivot = value; absPivot = absValue; pi = i; } } if (Fun.IsTiny(pivot)) return false; if (pi != k) { long api = a0 + pi * ay; Fun.Swap(ref p[pi], ref p[k]); for (long i = 0, apii = api, aki = ak; i < n; i++, apii += ax, aki += ax) Fun.Swap(ref alu[apii], ref alu[aki]); } for (long j = k + 1, aj = ak + ay, ajk = aj + a_k; j < n; j++, aj += ay, ajk += ay) { double factor = alu[ajk] / pivot; alu[ajk] = factor; for (long i = k + 1, aji = ajk + ax, aki = ak + a_k + ax; i < n; i++, aji += ax, aki += ax) alu[aji] -= alu[aki] * factor; } } return true; } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix lu, P is a permutation matrix /// supplied as a permutation array p, and b is the right hand side /// supplied as a vector starting at b0 with element to element /// delta bD. The result vector that satisfies the equation is /// filled into the supplied parameter x beginning at index x0 /// with element to element delta xD. /// public static unsafe void LuSolve( double* lu, long l0, long lx, long ly, int* p, double* b, long b0, long bd, double* x, long x0, long xd, long n) { for (long i = 0, xi = x0; i < n; i++, xi += xd) x[xi] = b[b0 + p[i] * bd]; for (long j = 1, xj = x0 + xd, lj = l0 + ly; j < n; j++, xj += xd, lj += ly) { double scalar = x[xj]; for (long i = 0, lji = lj, xi = x0; i < j; i++, lji += lx, xi += xd) scalar -= lu[lji] * x[xi]; x[xj] = scalar; } for (long j = n - 1, xj = x0 + j * xd, lj = l0 + j * ly, ljj = lj + j * lx; j >= 0; j--, xj -= xd, lj -= ly, ljj -= ly + lx) { double scalar = x[xj]; for (long i = j + 1, xi = xj + xd, lji = ljj + lx; i < n; i++, xi += xd, lji += lx) scalar -= lu[lji] * x[xi]; x[xj] = scalar / lu[ljj]; } } /// /// Compute the inverse inv(A) of a the supplied LU factorized matrix /// lu, where A = inv(P) LU. The permuation matrix P is supplied as /// the permutation vector p. The inverse matrix is filled into the /// supplied matrix x. /// public static unsafe void LuInverse( double* lu, long l0, long lx, long ly, int* p, double* x, long x0, long xx, long xy, long n) { for (long j = 0, xj = x0; j < n; j++, xj += xy) for (long i = 0, xji = xj; i < n; i++, xji += xx) x[xji] = p[j] == i ? 1 : 0; for (long k = 1, xk = x0 + xy, lk = l0 + ly; k < n; k++, xk += xy, lk += ly) for (long j = 0, xj = x0, lkj = lk; j < k; j++, xj += xy, lkj += lx) for (long i = 0, xki = xk, xji = xj; i < n; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; for (long k = n - 1, xk = x0 + k * xy, lk = l0 + k * ly, lkk = lk + k * lx; k >= 0; k--, xk -= xy, lk -= ly, lkk -= ly + lx) { for (long j = k + 1, lkj = lkk + lx, xj = xk + xy; j < n; j++, lkj += lx, xj += xy) for (long i = 0, xki = xk, xji = xj; i < n; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; var factor = lu[lkk]; // storing the inverse would increase the mean error for (long i = 0, xki = xk; i < n; i++, xki += xx) x[xki] /= factor; } } #endregion #region Partially pivoting LU factorization of ComplexD[,] arrays // Note that this version of the LU factorization is mostly provided // for studying the algorithm. In practice the Matrix version // is noticeably faster, since it performs incremental indexing. /// /// Perform a partially pivoting LU factorization of the supplied /// matrix, i.e A = inv(P) LU, so that any matrix equation A x = b /// can be solved using LU x = P b. The permutation matrix P is /// returns as permutation vector. WARNING: the supplied matrix A is /// overwritten with its factorization LU, both in the parameter alu. /// If the matrix is singular an ArgumentException is thrown. /// public static int[] LuFactorize(this ComplexD[,] alu) { int n = Fun.Min(alu.GetLength(0), alu.GetLength(1)); int[] perm = new int[n]; if (alu.LuFactorize(perm)) return perm; throw new ArgumentException("singular matrix"); } /// /// Perform a partially pivoting LU factorization of the supplied /// matrix, i.e A = inv(P) LU, so that any matrix equation A x = b /// can be solved using LU x = P b. The permutation matrix P is /// filled into the supplied permutation vector p, and the supplied /// matrix A is overwritten with its factorization LU, both in the /// parameter alu. The function returns true if the factorization /// is successful, otherwise the matrix is singular and false is /// returned. /// public static bool LuFactorize(this ComplexD[,] alu, int[] p) { int n = p.Length; p.SetByIndex(i => i); for (int k = 0; k < n - 1; k++) { int pi = k; ComplexD pivot = alu[pi, k]; double absPivot = pivot.NormSquared; for (int i = k + 1; i < n; i++) { ComplexD value = alu[i, k]; double absValue = value.NormSquared; if (absValue > absPivot) { pivot = value; absPivot = absValue; pi = i; } } if (Fun.IsTiny(pivot.Real) && Fun.IsTiny(pivot.Imag)) return false; if (pi != k) { Fun.Swap(ref p[pi], ref p[k]); for (int i = 0; i < n; i++) Fun.Swap(ref alu[pi, i], ref alu[k, i]); } for (int j = k + 1; j < n; j++) { ComplexD factor = alu[j, k] / pivot; alu[j, k] = factor; // construct L for (int i = k + 1; i < n; i++) alu[j, i] -= alu[k, i] * factor; } } return true; } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix lu, P is a permutation matrix /// supplied as a permutation array p, and b is the right hand side /// supplied as a vector. The returned x satisfies the equation. /// public static ComplexD[] LuSolve(this ComplexD[,] lu, int[] p, ComplexD[] b) { int n = Fun.Min(lu.GetLength(0), lu.GetLength(1)); if (n != p.GetLength(0)) throw new ArgumentException(); if (n > b.GetLength(0)) throw new ArgumentException(); var x = new ComplexD[n]; lu.LuSolve(p, b, x); return x; } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix lu, P is a permutation matrix /// supplied as a permutation array p, and b is the right hand side /// supplied as a vector. The result vector that satisfies the /// equation is filled into the supplied parameter x. /// public static void LuSolve(this ComplexD[,] lu, int[] p, ComplexD[] b, ComplexD[] x) { int n = p.Length; for (int i = 0; i < n; i++) x[i] = b[p[i]]; for (int j = 1; j < n; j++) { ComplexD scalar = x[j]; for (int i = 0; i < j; i++) scalar -= lu[j, i] * x[i]; x[j] = scalar; } for (int j = n - 1; j >= 0; j--) { ComplexD scalar = x[j]; for (int i = j + 1; i < n; i++) scalar -= lu[j, i] * x[i]; x[j] = scalar / lu[j, j]; } } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix, P is a permutation matrix /// supplied as a permutation array, and b is a supplied matrix. /// The returned matrix x satisfies the equation. /// public static ComplexD[,] LuSolve(this ComplexD[,] lu, int[] p, ComplexD[,] b) { int n = Fun.Min(lu.GetLength(0), lu.GetLength(1)); if (n != p.GetLength(0)) throw new ArgumentException(); if (n > b.GetLength(0)) throw new ArgumentException(); int m = b.GetLength(1); ComplexD[,] x = new ComplexD[n, m]; lu.LuSolve(p, b, x); return x; } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix, P is a permutation matrix /// supplied as a permutation array, and b is a supplied matrix. /// The result matrix that satisfies the equation is filled into the /// supplied parameter x. /// public static void LuSolve(this ComplexD[,] lu, int[] p, ComplexD[,] b, ComplexD[,] x) { int n = p.Length; int m = b.GetLength(1); for (int j = 0; j < n; j++) for (int i = 0; i < m; i++) x[j, i] = b[p[j], i]; for (int k = 1; k < n; k++) for (int j = 0; j < k; j++) for (int i = 0; i < m; i++) x[k, i] -= lu[k, j] * x[j, i]; for (int k = n - 1; k >= 0; k--) { for (int j = k + 1; j < n; j++) for (int i = 0; i < m; i++) x[k, i] -= lu[k, j] * x[j, i]; var factor = lu[k, k]; // storing the inverse would increase the mean error for (int i = 0; i < m; i++) x[k, i] /= factor; } } /// /// Return the inverse inv(A) of a the supplied LU factorized matrix /// lu, where A = inv(P) LU. The permuation matrix P is supplied as /// the permutation vector p. /// public static ComplexD[,] LuInverse(this ComplexD[,] lu, int[] p) { int n = Fun.Min(lu.GetLength(0), lu.GetLength(1)); if (n != p.GetLength(0)) throw new ArgumentException(); ComplexD[,] inv = new ComplexD[n, n]; lu.LuInverse(p, inv); return inv; } /// /// Compute the inverse inv(A) of a the supplied LU factorized matrix /// lu, where A = inv(P) LU. The permuation matrix P is supplied as /// the permutation vector p. The result matrix is filled into the /// supplied matrix. /// public static void LuInverse(this ComplexD[,] lu, int[] p, ComplexD[,] inv) { int n = p.Length; for (int j = 0; j < n; j++) for (int i = 0; i < n; i++) inv[j, i] = p[j] == i ? 1 : 0; for (int k = 1; k < n; k++) for (int j = 0; j < k; j++) for (int i = 0; i < n; i++) inv[k, i] -= lu[k, j] * inv[j, i]; for (int k = n - 1; k >= 0; k--) { for (int j = k + 1; j < n; j++) for (int i = 0; i < n; i++) inv[k, i] -= lu[k, j] * inv[j, i]; var factor = lu[k, k]; // storing the inverse would increase the mean error for (int i = 0; i < n; i++) inv[k, i] /= factor; } } #endregion #region Partially pivoting LU factorization of ComplexD[] arrays with offset and strides /// /// Perform a partially pivoting LU factorization of the supplied /// matrix in-place, i.e A = inv(P) LU, so that any matrix equation /// A x = b can be solved using LU x = P b. The permutation matrix P /// is filled into the supplied permutation vector p, and the supplied /// matrix A is overwritten with its factorization LU, both in the /// parameter alu. The function returns true if the factorization /// is successful, otherwise the matrix is singular and false is /// returned. No size checks are performed. /// public static bool LuFactorize( this ComplexD[] alu, long a0, long ax, long ay, int[] p) { long n = p.LongLength; p.SetByIndex(i => i); for (long k = 0, ak = a0, a_k = 0; k < n - 1; k++, ak += ay, a_k += ax) { long pi = k; ComplexD pivot = alu[ak + a_k]; double absPivot = pivot.NormSquared; for (long i = k + 1, aik = ak + ay + a_k; i < n; i++, aik += ay) { ComplexD value = alu[aik]; double absValue = value.NormSquared; if (absValue > absPivot) { pivot = value; absPivot = absValue; pi = i; } } if (Fun.IsTiny(pivot.Real) && Fun.IsTiny(pivot.Imag)) return false; if (pi != k) { long api = a0 + pi * ay; Fun.Swap(ref p[pi], ref p[k]); for (long i = 0, apii = api, aki = ak; i < n; i++, apii += ax, aki += ax) Fun.Swap(ref alu[apii], ref alu[aki]); } for (long j = k + 1, aj = ak + ay, ajk = aj + a_k; j < n; j++, aj += ay, ajk += ay) { ComplexD factor = alu[ajk] / pivot; alu[ajk] = factor; for (long i = k + 1, aji = ajk + ax, aki = ak + a_k + ax; i < n; i++, aji += ax, aki += ax) alu[aji] -= alu[aki] * factor; } } return true; } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix lu, P is a permutation matrix /// supplied as a permutation array p, and b is the right hand side /// supplied as a vector starting at b0 with element to element /// delta bD. The result vector that satisfies the equation is /// filled into the supplied parameter x beginning at index x0 /// with element to element delta xD. /// public static void LuSolve( this ComplexD[] lu, long l0, long lx, long ly, int[] p, ComplexD[] b, long b0, long bd, ComplexD[] x, long x0, long xd) { long n = p.LongLength; for (long i = 0, xi = x0; i < n; i++, xi += xd) x[xi] = b[b0 + p[i] * bd]; for (long j = 1, xj = x0 + xd, lj = l0 + ly; j < n; j++, xj += xd, lj += ly) { ComplexD scalar = x[xj]; for (long i = 0, lji = lj, xi = x0; i < j; i++, lji += lx, xi += xd) scalar -= lu[lji] * x[xi]; x[xj] = scalar; } for (long j = n - 1, xj = x0 + j * xd, lj = l0 + j * ly, ljj = lj + j * lx; j >= 0; j--, xj -= xd, lj -= ly, ljj -= ly + lx) { ComplexD scalar = x[xj]; for (long i = j + 1, xi = xj + xd, lji = ljj + lx; i < n; i++, xi += xd, lji += lx) scalar -= lu[lji] * x[xi]; x[xj] = scalar / lu[ljj]; } } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix, P is a permutation matrix /// supplied as a permutation array, and b is a supplied matrix. /// The result matrix that satisfies the equation is filled into the /// supplied parameter x. /// public static void LuSolve( this ComplexD[] lu, long l0, long lx, long ly, int[] p, long m, ComplexD[] b, long b0, long bx, long by, ComplexD[] x, long x0, long xx, long xy) { int n = p.Length; for (long j = 0, xj = x0; j < n; j++, xj += xy) for (long i = 0, bpji = b0 + p[j] * by, xji = xj; i < m; i++, bpji += bx, xji += xx) x[xji] = b[bpji]; for (long k = 1, xk = x0 + xy, lk = l0 + ly; k < n; k++, xk += xy, lk += ly) for (long j = 0, xj = x0, lkj = lk; j < k; j++, xj += xy, lkj += lx) for (long i = 0, xki = xk, xji = xj; i < m; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; for (long k = n - 1, xk = x0 + k * xy, lk = l0 + k * ly, lkk = lk + k * lx; k >= 0; k--, xk -= xy, lk -= ly, lkk -= ly + lx) { for (long j = k + 1, lkj = lkk + lx, xj = xk + xy; j < n; j++, lkj += lx, xj += xy) for (long i = 0, xki = xk, xji = xj; i < m; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; var factor = lu[lkk]; // storing the inverse would increase the mean error for (long i = 0, xki = xk; i < m; i++, xki += xx) x[xki] /= factor; } } /// /// Compute the inverse inv(A) of a the supplied LU factorized matrix /// lu, where A = inv(P) LU. The permuation matrix P is supplied as /// the permutation vector p. The inverse matrix is filled into the /// supplied matrix x. /// public static void LuInverse( this ComplexD[] lu, long l0, long lx, long ly, int[] p, ComplexD[] x, long x0, long xx, long xy) { int n = p.Length; for (long j = 0, xj = x0; j < n; j++, xj += xy) for (long i = 0, xji = xj; i < n; i++, xji += xx) x[xji] = p[j] == i ? 1 : 0; for (long k = 1, xk = x0 + xy, lk = l0 + ly; k < n; k++, xk += xy, lk += ly) for (long j = 0, xj = x0, lkj = lk; j < k; j++, xj += xy, lkj += lx) for (long i = 0, xki = xk, xji = xj; i < n; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; for (long k = n - 1, xk = x0 + k * xy, lk = l0 + k * ly, lkk = lk + k * lx; k >= 0; k--, xk -= xy, lk -= ly, lkk -= ly + lx) { for (long j = k + 1, lkj = lkk + lx, xj = xk + xy; j < n; j++, lkj += lx, xj += xy) for (long i = 0, xki = xk, xji = xj; i < n; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; var factor = lu[lkk]; // storing the inverse would increase the mean error for (long i = 0, xki = xk; i < n; i++, xki += xx) x[xki] /= factor; } } #endregion #region Partially pivoting LU factorization of ComplexD* pointers with offset and strides /// /// Perform a partially pivoting LU factorization of the supplied /// matrix in-place, i.e A = inv(P) LU, so that any matrix equation /// A x = b can be solved using LU x = P b. The permutation matrix P /// is filled into the supplied permutation vector p, and the supplied /// matrix A is overwritten with its factorization LU, both in the /// parameter alu. The function returns true if the factorization /// is successful, otherwise the matrix is singular and false is /// returned. No size checks are performed. /// public static unsafe bool LuFactorize( ComplexD* alu, long a0, long ax, long ay, int* p, long n) { for (long i = 0; i < n; i++) p[i] = (int)i; for (long k = 0, ak = a0, a_k = 0; k < n - 1; k++, ak += ay, a_k += ax) { long pi = k; ComplexD pivot = alu[ak + a_k]; double absPivot = pivot.NormSquared; for (long i = k + 1, aik = ak + ay + a_k; i < n; i++, aik += ay) { ComplexD value = alu[aik]; double absValue = value.NormSquared; if (absValue > absPivot) { pivot = value; absPivot = absValue; pi = i; } } if (Fun.IsTiny(pivot.Real) && Fun.IsTiny(pivot.Imag)) return false; if (pi != k) { long api = a0 + pi * ay; Fun.Swap(ref p[pi], ref p[k]); for (long i = 0, apii = api, aki = ak; i < n; i++, apii += ax, aki += ax) Fun.Swap(ref alu[apii], ref alu[aki]); } for (long j = k + 1, aj = ak + ay, ajk = aj + a_k; j < n; j++, aj += ay, ajk += ay) { ComplexD factor = alu[ajk] / pivot; alu[ajk] = factor; for (long i = k + 1, aji = ajk + ax, aki = ak + a_k + ax; i < n; i++, aji += ax, aki += ax) alu[aji] -= alu[aki] * factor; } } return true; } /// /// Solve a matrix equation of the form LU x = P b. /// LU is the supplied factorized matrix lu, P is a permutation matrix /// supplied as a permutation array p, and b is the right hand side /// supplied as a vector starting at b0 with element to element /// delta bD. The result vector that satisfies the equation is /// filled into the supplied parameter x beginning at index x0 /// with element to element delta xD. /// public static unsafe void LuSolve( ComplexD* lu, long l0, long lx, long ly, int* p, ComplexD* b, long b0, long bd, ComplexD* x, long x0, long xd, long n) { for (long i = 0, xi = x0; i < n; i++, xi += xd) x[xi] = b[b0 + p[i] * bd]; for (long j = 1, xj = x0 + xd, lj = l0 + ly; j < n; j++, xj += xd, lj += ly) { ComplexD scalar = x[xj]; for (long i = 0, lji = lj, xi = x0; i < j; i++, lji += lx, xi += xd) scalar -= lu[lji] * x[xi]; x[xj] = scalar; } for (long j = n - 1, xj = x0 + j * xd, lj = l0 + j * ly, ljj = lj + j * lx; j >= 0; j--, xj -= xd, lj -= ly, ljj -= ly + lx) { ComplexD scalar = x[xj]; for (long i = j + 1, xi = xj + xd, lji = ljj + lx; i < n; i++, xi += xd, lji += lx) scalar -= lu[lji] * x[xi]; x[xj] = scalar / lu[ljj]; } } /// /// Compute the inverse inv(A) of a the supplied LU factorized matrix /// lu, where A = inv(P) LU. The permuation matrix P is supplied as /// the permutation vector p. The inverse matrix is filled into the /// supplied matrix x. /// public static unsafe void LuInverse( ComplexD* lu, long l0, long lx, long ly, int* p, ComplexD* x, long x0, long xx, long xy, long n) { for (long j = 0, xj = x0; j < n; j++, xj += xy) for (long i = 0, xji = xj; i < n; i++, xji += xx) x[xji] = p[j] == i ? 1 : 0; for (long k = 1, xk = x0 + xy, lk = l0 + ly; k < n; k++, xk += xy, lk += ly) for (long j = 0, xj = x0, lkj = lk; j < k; j++, xj += xy, lkj += lx) for (long i = 0, xki = xk, xji = xj; i < n; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; for (long k = n - 1, xk = x0 + k * xy, lk = l0 + k * ly, lkk = lk + k * lx; k >= 0; k--, xk -= xy, lk -= ly, lkk -= ly + lx) { for (long j = k + 1, lkj = lkk + lx, xj = xk + xy; j < n; j++, lkj += lx, xj += xy) for (long i = 0, xki = xk, xji = xj; i < n; i++, xki += xx, xji += xx) x[xki] -= lu[lkj] * x[xji]; var factor = lu[lkk]; // storing the inverse would increase the mean error for (long i = 0, xki = xk; i < n; i++, xki += xx) x[xki] /= factor; } } #endregion } } ================================================ FILE: src/Aardvark.Base/Math/Numerics/CovarianceMatrix.cs ================================================ using System.Collections.Generic; namespace Aardvark.Base { /// /// Covariance matrix. /// public static class CovarianceMatrixExtensions { #region V3d /// /// Computes outer product (tensor product) of vector v with itself. /// public static M33d OuterProduct(this in V3d v) => new M33d( v.X * v.X, v.X * v.Y, v.X * v.Z, v.Y * v.X, v.Y * v.Y, v.Y * v.Z, v.Z * v.X, v.Z * v.Y, v.Z * v.Z ); /// /// Adds outer product (tensor product) of vector v with itself to matrix m. /// public static void AddOuterProduct(this ref M33d m, in V3d v) { m.M00 += v.X * v.X; m.M01 += v.X * v.Y; m.M02 += v.X * v.Z; m.M10 += v.Y * v.X; m.M11 += v.Y * v.Y; m.M12 += v.Y * v.Z; m.M20 += v.Z * v.X; m.M21 += v.Z * v.Y; m.M22 += v.Z * v.Z; } /// /// Computes covariance matrix for given points. /// public static M33d ComputeCovarianceMatrix(this V3d[] points) { var cvm = M33d.Zero; for (var i = 0; i < points.Length; i++) cvm.AddOuterProduct(points[i]); return cvm / points.Length; } /// /// Computes covariance matrix for points given by indices into points array. /// public static M33d ComputeCovarianceMatrix(this V3d[] points, int[] indices) { var cvm = M33d.Zero; for (var i = 0; i < indices.Length; i++) cvm.AddOuterProduct(points[indices[i]]); return cvm / indices.Length; } /// /// Computes covariance matrix from points relative to given center. /// public static M33d ComputeCovarianceMatrix(this V3d[] points, V3d center) { var cvm = M33d.Zero; for (var i = 0; i < points.Length; i++) cvm.AddOuterProduct(points[i] - center); return cvm / points.Length; } /// /// Computes covariance matrix for points given by indices into points array, relative to given center. /// public static M33d ComputeCovarianceMatrix(this V3d[] points, int[] indices, V3d center) { var cvm = M33d.Zero; for (var i = 0; i < indices.Length; i++) cvm.AddOuterProduct(points[indices[i]] - center); return cvm / indices.Length; } /// /// Computes covariance matrix for given points. /// public static M33d ComputeCovarianceMatrix(this IEnumerable points) { var count = 0; var cvm = M33d.Zero; foreach (var p in points) { cvm.AddOuterProduct(p); count++; } return cvm / count; } /// /// Computes covariance matrix from points relative to given center. /// public static M33d ComputeCovarianceMatrix(this IEnumerable points, V3d center) { var count = 0; var cvm = M33d.Zero; foreach (var p in points) { cvm.AddOuterProduct(p - center); count++; } return cvm / count; } #endregion #region V3f /// /// Computes outer product (tensor product) of vector v with itself. /// public static M33f OuterProduct(this in V3f v) => new M33f( v.X * v.X, v.X * v.Y, v.X * v.Z, v.Y * v.X, v.Y * v.Y, v.Y * v.Z, v.Z * v.X, v.Z * v.Y, v.Z * v.Z ); /// /// Adds outer product (tensor product) of vector v with itself to matrix m. /// public static void AddOuterProduct(this ref M33f m, in V3f v) { m.M00 += v.X * v.X; m.M01 += v.X * v.Y; m.M02 += v.X * v.Z; m.M10 += v.Y * v.X; m.M11 += v.Y * v.Y; m.M12 += v.Y * v.Z; m.M20 += v.Z * v.X; m.M21 += v.Z * v.Y; m.M22 += v.Z * v.Z; } /// /// Computes covariance matrix for given points. /// public static M33f ComputeCovarianceMatrix(this V3f[] points) { var cvm = M33f.Zero; for (var i = 0; i < points.Length; i++) cvm.AddOuterProduct(points[i]); return cvm / points.Length; } /// /// Computes covariance matrix for points given by indices into points array. /// public static M33f ComputeCovarianceMatrix(this V3f[] points, int[] indices) { var cvm = M33f.Zero; for (var i = 0; i < indices.Length; i++) cvm.AddOuterProduct(points[indices[i]]); return cvm / indices.Length; } /// /// Computes covariance matrix from points relative to given center. /// public static M33f ComputeCovarianceMatrix(this V3f[] points, V3f center) { var cvm = M33f.Zero; for (var i = 0; i < points.Length; i++) cvm.AddOuterProduct(points[i] - center); return cvm / points.Length; } /// /// Computes covariance matrix for points given by indices into points array, relative to given center. /// public static M33f ComputeCovarianceMatrix(this V3f[] points, int[] indices, V3f center) { var cvm = M33f.Zero; for (var i = 0; i < indices.Length; i++) cvm.AddOuterProduct(points[indices[i]] - center); return cvm / indices.Length; } /// /// Computes covariance matrix for given points. /// public static M33f ComputeCovarianceMatrix(this IEnumerable points) { var count = 0; var cvm = M33f.Zero; foreach (var p in points) { cvm.AddOuterProduct(p); count++; } return cvm / count; } /// /// Computes covariance matrix from points relative to given center. /// public static M33f ComputeCovarianceMatrix(this IEnumerable points, V3f center) { var count = 0; var cvm = M33f.Zero; foreach (var p in points) { cvm.AddOuterProduct(p - center); count++; } return cvm / count; } #endregion } } ================================================ FILE: src/Aardvark.Base/Math/Numerics/Polynomial.cs ================================================ using System; using System.Collections.Generic; namespace Aardvark.Base { public static class Polynomial { /// /// Return the polynomial derivative of the supplied polynomial that /// is stored with ascending coefficients: /// coeff[0] + coeff[1] x + coeff[2] x^2 + ... + coeff[n-1] x^(n-1) /// public static double[] Derivative(this double[] coeff) { int len = coeff.Length - 1; if (len < 1) throw new ArgumentException(); var r = new double[len]; r[0] = coeff[1]; if (len < 2) return r; for (int i = 1, j = 2; i < len; i = j++) r[i] = j * coeff[j]; return r; } /// /// Return the polynomial product of two polynomials that are supplied /// with ascending coefficients: /// ( c0[0] + c0[1] x + c0[2] x^2 + ... + c0[n-1] x^(n-1) ) /// * ( c1[0] + c1[1] x + c1[2] x^2 + ... + c1[n-1] x^(n-1) ) /// public static double[] Multiply(this double[] c0, double[] c1) { int l0 = c0.Length; int l1 = c1.Length; var r = new double[l0 + l1 - 1].Set(0.0); for (int i0 = 0; i0 < l0; i0++) for (int i1 = 0; i1 < l1; i1++) r[i0 + i1] += c0[i0] * c1[i1]; return r; } /// /// Evaluate the supplied polynomial that is stored with ascending /// coefficients at the supplied agrument x: /// coeff[0] + coeff[1] x + coeff[2] x^2 + ... + coeff[n-1] x^(n-1) /// public static double Evaluate(this double[] coeff, double x) { int i = coeff.Length - 1; if (i < 0) throw new ArgumentException(); double value = coeff[i--]; while (i >= 0) value = x * value + coeff[i--]; return value; } /// /// Evaluate the derivative of the supplied polynomial that is stored /// with ascending coefficients at the supplied agrument x: /// coeff[1] + 2 coeff[2] x + ... + (n-1) coeff[n-1] x^(n-2) /// public static double EvaluateDerivative(this double[] coeff, double x) { int i = coeff.Length - 1; if (i < 0) throw new ArgumentException(); double value = i * coeff[i]; --i; while (i > 0) { value = x * value + i * coeff[i]; --i; } return value; } #if !TRAVIS_CI /// /// Return the real roots of the supplied polynomial, that is stored /// with ascending coefficients: /// coeff[0] + coeff[1] x + coeff[2] x^2 + ... + coeff[n-1] x^(n-1) /// Note that double and triple roots are returned as repeated values. /// WARNING: currently only polynomials up to the 4th order can be solved. /// public static double[] RealRoots(this double[] coeff) { switch (coeff.Length) { case 0: case 1: return Array.Empty(); case 2: return RealRootOf(coeff[1], coeff[0]).NonNanToArray(); case 3: return RealRootsOf(coeff[2], coeff[1], coeff[0]) .NonNanToArray(); case 4: return RealRootsOf(coeff[3], coeff[2], coeff[1], coeff[0]) .NonNanToArray(); case 5: return RealRootsOf(coeff[4], coeff[3], coeff[2], coeff[1], coeff[0]).NonNanToArray(); default: throw new NotImplementedException(); } } /// /// Return the real roots of the supplied normalized polynomial, that /// is stored with ascending coefficients: /// coeff[0] + coeff[1] x + coeff[2] x^2 + coeff[3] x^3 ... + x^n /// The last coefficient with value 1.0 must not be part of the /// supplied array. /// Note that double and triple roots are returned as repeated values. /// WARNING: currently only polynomials up to the 4th order can be solved. /// public static double[] RealRootsNormed(this double[] coeff) { switch (coeff.Length) { case 0: return Array.Empty(); case 1: return RealRootOfNormed(coeff[0]).IntoArray(); case 2: return RealRootsOfNormed(coeff[1], coeff[0]) .NonNanToArray(); case 3: return RealRootsOfNormed(coeff[2], coeff[1], coeff[0]) .NonNanToArray(); case 4: return RealRootsOfNormed(coeff[3], coeff[2], coeff[1], coeff[0]).NonNanToArray(); default: throw new NotImplementedException(); } } #endif private static double[] NonNanToArray(this double root) { if (double.IsNaN(root)) return Array.Empty(); return new double[] { root }; } private static double[] NonNanToArray(this (double, double) p) { if (double.IsNaN(p.Item1)) { if (double.IsNaN(p.Item2)) return Array.Empty(); return new double[] { p.Item2 }; } if (double.IsNaN(p.Item2)) return new double[] { p.Item1 }; return new double[] { p.Item1, p.Item2 }; } private static double[] NonNanToArray(this (double, double, double) t) { int c = 0; bool v0 = !double.IsNaN(t.Item1); if (v0) c++; bool v1 = !double.IsNaN(t.Item2); if (v1) c++; bool v2 = !double.IsNaN(t.Item3); if (v2) c++; var a = new double[c]; if (v2) a[--c] = t.Item3; if (v1) a[--c] = t.Item2; if (v0) a[--c] = t.Item1; return a; } private static double[] NonNanToArray(this (double, double, double, double) q) { int c = 0; bool v0 = !double.IsNaN(q.Item1); if (v0) c++; bool v1 = !double.IsNaN(q.Item2); if (v1) c++; bool v2 = !double.IsNaN(q.Item3); if (v2) c++; bool v3 = !double.IsNaN(q.Item4); if (v3) c++; var a = new double[c]; if (v3) a[--c] = q.Item4; if (v2) a[--c] = q.Item3; if (v1) a[--c] = q.Item2; if (v0) a[--c] = q.Item1; return a; } /// /// Return root of the equation ax + b = 0. /// Returns NaN if no root exists (a = 0). /// public static double RealRootOf(double a, double b) { if (Fun.IsTiny(a)) return double.NaN; return -b / a; } /// /// Return -p as the root of x + p = 0. /// public static double RealRootOfNormed(double p) { return -p; } /// /// Return real roots of the equation ax^2 + bx + c = 0. /// Double roots are returned as a pair of identical values. /// If only one (linear) roots exists, it is stored in the first /// entry and the second entry is NaN. /// If no real roots exists, then both entries are NaN. /// public static (double, double) RealRootsOf(double a, double b, double c) { if (Fun.IsTiny(a)) { if (Fun.IsTiny(b)) return (double.NaN, double.NaN); return (-c / b, double.NaN); } var r = b * b - 4 * a * c; if (r < 0) return (double.NaN, double.NaN); if (b < 0) // prevent cancellation { double d = -b + Fun.Sqrt(r); return (2 * c / d, d / (2 * a)); } else { double d = -b - Fun.Sqrt(r); return (d / (2 * a), 2 * c / d); } } /// /// Return real roots of the equation x^2 + px + q = 0. /// Double roots are returned as a pair of identical values. /// If no real roots exists, then both entries are NaN. /// public static (double, double) RealRootsOfNormed(double p, double q) { double p2 = p / 2.0; double d = p2 * p2 - q; if (d < 0) return (double.NaN, double.NaN); if (p2 > 0.0) // prevent cancellation { double r = -(p2 + Fun.Sqrt(d)); return (r, q / r); } else { double r = Fun.Sqrt(d) - p2; return (q / r, r); } } /// /// Return real roots of the equation: a x^3 + b x^2 + c x + d = 0. /// Double and triple solutions are returned as replicated values. /// Imaginary and non existing solutions are returned as NaNs. /// public static (double, double, double) RealRootsOf( double a, double b, double c, double d) { if (Fun.IsTiny(a)) { var r = RealRootsOf(b, c, d); return (r.Item1, r.Item2, double.NaN); } return RealRootsOfNormed(b / a, c / a, d / a); } /// /// Return real roots of the equation: x^3 + c2 x^2 + c1 x + c0 = 0 /// Double and triple solutions are returned as replicated values. /// Imaginary and non existing solutions are returned as NaNs. /// public static (double, double, double) RealRootsOfNormed( double c2, double c1, double c0) { // ------ eliminate quadric term (x = y - c2/3): x^3 + p x + q = 0 double d = c2 * c2; double p3 = 1/3.0 * /* p */(-1/3.0 * d + c1); double q2 = 1/2.0 * /* q */((2/27.0 * d - 1/3.0 * c1) * c2 + c0); double p3c = p3 * p3 * p3; double shift = 1/3.0 * c2; d = q2 * q2 + p3c; if (d < 0) // casus irreducibilis: three real solutions { double phi = 1 / 3.0 * Fun.Acos(-q2 / Fun.Sqrt(-p3c)); double t = 2 * Fun.Sqrt(-p3); double r0 = t * Fun.Cos(phi) - shift; double r1 = -t * Fun.Cos(phi + Constant.Pi / 3.0) - shift; double r2 = -t * Fun.Cos(phi - Constant.Pi / 3.0) - shift; return TupleExtensions.CreateAscending(r0, r1, r2); } // else if (Fun.IsTiny(q2)) // one triple root // { // too unlikely for // double r = -1/3.0 * c2; // special handling // return (r, r, r); // to pay off // } d = Fun.Sqrt(d); // one single and one double root double uav = Fun.Cbrt(d - q2) - Fun.Cbrt(d + q2); double s0 = uav - shift, s1 = -0.5 * uav - shift; return s0 < s1 ? (s0, s1, s1) : (s1, s1, s0); } /// /// Return real roots of the equation: x^3 + p x + q = 0 /// Double and triple solutions are returned as replicated values. /// Imaginary and non existing solutions are returned as NaNs. /// public static (double, double, double) RealRootsOfDepressed( double p, double q) { double p3 = 1/3.0 * p, q2 = 1/2.0 * q; double p3c = p3 * p3 * p3, d = q2 * q2 + p3c; if (d < 0) // ---------- casus irreducibilis: three real solutions { double phi = 1 / 3.0 * Fun.Acos(-q2 / Fun.Sqrt(-p3c)); double t = 2 * Fun.Sqrt(-p3); double r0 = t * Fun.Cos(phi); double r1 = -t * Fun.Cos(phi + Constant.Pi / 3.0); double r2 = -t * Fun.Cos(phi - Constant.Pi / 3.0); return TupleExtensions.CreateAscending(r0, r1, r2); } d = Fun.Sqrt(d); // one triple root or a single and a double root double s0 = Fun.Cbrt(d - q2) - Fun.Cbrt(d + q2); double s1 = -0.5 * s0; return s0 < s1 ? (s0, s1, s1) : (s1, s1, s0); } /// /// One real root of the equation: x^3 + c2 x^2 + c1 x + c0 = 0. /// public static double OneRealRootOfNormed( double c2, double c1, double c0 ) { // ------ eliminate quadric term (x = y - c2/3): x^3 + p x + q = 0 double d = c2 * c2; double p3 = 1/3.0 * /* p */(-1/3.0 * d + c1); double q2 = 1/2.0 * /* q */((2/27.0 * d - 1/3.0 * c1) * c2 + c0); double p3c = p3 * p3 * p3; d = q2 * q2 + p3c; if (d < 0) // -------------- casus irreducibilis: three real roots return 2 * Fun.Sqrt(-p3) * Fun.Cos(1/3.0 * Fun.Acos(-q2 / Fun.Sqrt(-p3c))) - 1/3.0 * c2; d = Fun.Sqrt(d); // one triple root or a single and a double root return Fun.Cbrt(d - q2) - Fun.Cbrt(d + q2) - 1/3.0 * c2; } #if !TRAVIS_CI /// /// Return real roots of: a x^4 + b x^3 + c x^2 + d x + e = 0 /// Double and triple solutions are returned as replicated values. /// Imaginary and non existing solutions are returned as NaNs. /// public static (double, double, double, double) RealRootsOf( double a, double b, double c, double d, double e) { if (Fun.IsTiny(a)) { var r = RealRootsOf(b, c, d, e); return (r.Item1, r.Item2, r.Item3, double.NaN); } return RealRootsOfNormed(b / a, c / a, d / a, e / a); } /// /// Return real roots of: x^4 + c3 x^3 + c2 x^2 + c1 x + c0 = 0. /// Double and triple solutions are returned as replicated values. /// Imaginary and non existing solutions are returned as NaNs. /// public static (double, double, double, double) RealRootsOfNormed( double c3, double c2, double c1, double c0) { // eliminate cubic term (x = y - c3/4): x^4 + p x^2 + q x + r = 0 double e = c3 * c3; double p = -3/8.0 * e + c2; double q = (1/8.0 * e - 1/2.0 * c2) * c3 + c1; double r = (1/16.0 * c2 - 3/256.0 * e) * e - 1/4.0 * c3 * c1 + c0; if (Fun.IsTiny(r)) // ---- no absolute term: y (y^3 + p y + q) = 0 return MergeSortedAndShift( RealRootsOfDepressed(p, q), 0.0, -1/4.0 * c3); // ----------------------- take one root of the resolvent cubic... double z = OneRealRootOfNormed( -1/2.0 * p, -r, 1/2.0 * r * p - 1/8.0 * q * q); // --------------------------- ...to build two quadratic equations double u = z * z - r; double v = 2.0 * z - p; if (u < Constant.PositiveTinyValue) // +tiny instead of 0 u = 0.0; // improves unique else // root accuracy by a u = Fun.Sqrt(u); // factor of 10^5! if (v < Constant.PositiveTinyValue) // values greater than v = 0.0; // +tiny == 4 * eps else // do not seem to v = Fun.Sqrt(v); // improve accuraccy! double q1 = q < 0 ? -v : v; return MergeSortedAndShift(RealRootsOfNormed(q1, z - u), RealRootsOfNormed(-q1, z + u), -1/4.0 * c3); } static (double, double, double, double) MergeSortedAndShift( (double, double, double) t, double d, double shift) { var q = (0.0, 0.0, 0.0, 0.0); int tc = t.CountNonNaNs(); int i = 0, ti = 0; while (ti < tc) { if (t.Get(ti) < d) q.Set(i++, t.Get(ti++) + shift); else { q.Set(i++, d + shift); break; } } while (ti < tc) q.Set(i++, t.Get(ti++) + shift); while (i < 4) q.Set(i++, double.NaN); return q; } static (double, double, double, double) MergeSortedAndShift( (double, double) p0, (double, double) p1, double shift) { var q = (0.0, 0.0, 0.0, 0.0); int c0 = p0.CountNonNaNs(); int c1 = p1.CountNonNaNs(); int i = 0, i0 = 0, i1 = 0; while (i0 < c0 && i1 < c1) { if (p0.Get(i0) < p1.Get(i1)) q.Set(i++, p0.Get(i0++) + shift); else q.Set(i++, p1.Get(i1++) + shift); } while (i0 < c0) q.Set(i++, p0.Get(i0++) + shift); while (i1 < c1) q.Set(i++, p1.Get(i1++) + shift); while (i < 4) q.Set(i++, double.NaN); return q; } #endif /// /// Returns a copy of an array of roots without any double roots with /// an absolute difference that is smaller than the supplied epsilon. /// Roots with odd multiplicity will be left as single roots. /// public static double[] WithoutDoubleRoots( this double[] a, double epsilon) { int last = a.Length - 1; if (last < 4) return WithoutDoubleRoots4(a, epsilon); var r = new List(last + 1); int i = 0; while (i < last) { int j = i + 1; if (Fun.Abs(a[i] - a[j]) < epsilon) { i += 2; continue; } r.Add(a[i]); i = j; } if (i == last) r.Add(a[i]); return r.ToArray(); } private static double[] WithoutDoubleRoots4(double[] a, double eps) { int len = a.Length; if (len < 2) return a; if ((a[0] - a[1]).Abs() < eps) { if (len < 3) return Array.Empty(); if (len < 4) return new double[] { a[2] }; if ((a[2] - a[3]).Abs() < eps) return Array.Empty(); else return new double[] { a[2], a[3] }; } else { if (len < 3) return a; if ((a[1] - a[2]).Abs() < eps) { if (len < 4) return new double[] { a[0] }; return new double[] { a[0], a[3] }; } else { if (len < 4) return a; if ((a[2] - a[3]).Abs() < eps) return new double[] { a[0], a[1] }; else return a; } } } } } ================================================ FILE: src/Aardvark.Base/Math/QrFactorization.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Aardvark.Base { public static class QRHelpers { #region Helpers /// /// L2 norm of matrix row elemnts including start and excluding end. /// public static double RowNorm2( this double[] matrix, long m0, long mx, long my, long row, long start, long end) { m0 += row * my; var norm = 0.0; for (long mi = m0 + start * mx, me = m0 + end * mx; mi != me; mi += mx) norm += matrix[mi] * matrix[mi]; return Fun.Sqrt(norm); } /// /// L2 norm of matrix column elemnts including start and excluding end. /// public static double ColNorm2( this double[] matrix, long m0, long mx, long my, long col, long start, long end) { m0 += col * mx; var norm = 0.0; for (long mi = m0 + start * my, me = m0 + end * my; mi != me; mi += my) norm += matrix[mi] * matrix[mi]; return Fun.Sqrt(norm); } /// /// Dot product of matrix row elements including start and excluding end. /// public static double RowDotRow( this double[] matrix, long m0, long mx, long my, long row0, long row1, long start, long end) { m0 += start * mx; var dot = 0.0; for (long i0 = m0 + row0 * my, i1 = m0 + row1 * my, e0 = i0 + (end - start) * mx; i0 != e0; i0 += mx, i1 += mx) dot += matrix[i0] * matrix[i1]; return dot; } /// /// Dot product of matrix column elements including start and excluding end. /// public static double ColDotCol( this double[] matrix, long m0, long mx, long my, long col0, long col1, long start, long end) { m0 += start * my; var dot = 0.0; for (long i0 = m0 + col0 * mx, i1 = m0 + col1 * mx, e0 = i0 + (end - start) * my; i0 != e0; i0 += my, i1 += my) dot += matrix[i0] * matrix[i1]; return dot; } public static void FlipWithNormalizedColHouseholder( this double[] vector, double[] matrix, long m0, long mx, long my, long col, long end) { m0 += col * (mx + my); double p = 0.0; for (long i = col, mi = m0; i < end; i++, mi += my) p += 2.0 * vector[i] * matrix[mi]; for (long i = col, mi = m0; i < end; i++, mi += my) vector[i] -= p * matrix[mi]; } public static void FlipWithNormalizedRowHouseholder( this double[] vector, long v0, long vd, double[] matrix, long m0, long mx, long my, long row, long end) { m0 += row * (mx + my); double p = 0.0; for (long i = row, vi = v0, mi = m0; i < end; i++, vi += vd, mi += mx) p += 2.0 * vector[vi] * matrix[mi]; for (long i = row, vi = v0, mi = m0; i < end; i++, vi += vd, mi += mx) vector[vi] -= p * matrix[mi]; } #endregion } public static partial class NumericExtensions { #region double[,] array helpers /// /// L2 norm of complete matrix row. /// public static double RowNorm2( this double[,] array, long row) { return array.RowNorm2(row, 0, array.GetLongLength(1)); } /// /// L2 norm of complete matrix column. /// public static double ColNorm2( this double[,] array, long col) { return array.ColNorm2(col, 0, array.GetLongLength(0)); } /// /// L2 norm of matrix row elemnts including start and excluding end. /// public static double RowNorm2( this double[,] array, long row, long start, long end) { double sum = 0.0; for (long i = start; i < end; i++) sum += array[row, i] * array[row, i]; return Fun.Sqrt(sum); } /// /// L2 norm of matrix column elemnts including start and excluding end. /// public static double ColNorm2( this double[,] array, long col, long start, long end) { double sum = 0.0; for (long i = start; i < end; i++) sum += array[i, col] * array[i, col]; return Fun.Sqrt(sum); } /// /// Dot product of complete matrix rows. /// public static double RowDotRow( this double[,] array, long r0, long r1) { return array.RowDotRow(r0, r1, 0, array.GetLongLength(1)); } /// /// Dot product of complete matrix columns. /// public static double ColDotCol( this double[,] array, long c0, long c1) { return array.ColDotCol(c0, c1, 0, array.GetLongLength(0)); } /// /// Dot product of matrix row elements including start and excluding end. /// public static double RowDotRow( this double[,] array, long r0, long r1, long start, long end) { double sum = 0.0; for (long i = start; i < end; i++) sum += array[r0, i] * array[r1, i]; return sum; } /// /// Dot product of matrix column elements including start and excluding end. /// public static double ColDotCol( this double[,] array, long c0, long c1, long start, long end) { double sum = 0.0; for (long i = start; i < end; i++) sum += array[i, c0] * array[i, c1]; return sum; } #endregion #region QR factorization of double[,] arrays using Householder transformations // Note that this version of the QR factorization is mostly provided // for studying the algorithm. In practice the Matrix version // is noticeably faster, since it performs incremental indexing. #region Helpers private static void FlipWithNormalizedColHouseholder( this double[] vector, double[,] A, int col, int end) { double p = 0.0; for (int i = col; i < end; i++) p += 2.0 * vector[i] * A[i, col]; for (int i = col; i < end; i++) vector[i] -= p * A[i, col]; } private static void FlipWithNormalizedRowHouseholder( this double[] vector, double[,] A, int row, int end) { double p = 0.0; for (int i = row; i < end; i++) p += 2.0 * vector[i] * A[row, i]; for (int i = row; i < end; i++) vector[i] -= p * A[row, i]; } #endregion private static void QrFactorize(this double[,] A, double[] diagonal) { int rows = A.GetLength(0); int cols = A.GetLength(1); if (rows < cols) { for (int r = 0; r < rows; r++) { double alpha = -System.Math.Sign(A[r, r]) * A.RowNorm2(r, r, cols); double norm_v = System.Math.Sqrt(-2.0 * alpha * (A[r, r] - alpha)); diagonal[r] = alpha; A[r, r] = (A[r, r] - alpha) / norm_v; for (int c = r + 1; c < cols; c++) A[r, c] /= norm_v; for (int j = r + 1; j < rows; j++) { double p_j = 2.0 * A.RowDotRow(r, j, r, cols); for (int c = r; c < cols; c++) A[j, c] -= p_j * A[r, c]; } } } else { for (int c = 0; c < cols; c++) { double alpha = -System.Math.Sign(A[c, c]) * A.ColNorm2(c, c, rows); double norm_v = System.Math.Sqrt(-2.0 * alpha * (A[c, c] - alpha)); diagonal[c] = alpha; A[c, c] = (A[c, c] - alpha) / norm_v; for (int r = c + 1; r < rows; r++) A[r, c] /= norm_v; for (int j = c + 1; j < cols; j++) { double p_j = 2.0 * A.ColDotCol(c, j, c, rows); for (int r = c; r < rows; r++) A[r, j] -= p_j * A[r, c]; } } } } /// /// Perform a QR factorization of the supplied m x n matrix using /// Householder transofmations, i.e. A = QR, where Q is orthogonal /// (a product of n-2 Householder-Transformations) and R is a right /// upper n x n triangular matrix. An array of the diagonal elements /// of R is returned. WARNING: the supplied matrix A is overwritten /// with its factorization QR, both in the parameter aqr. /// public static double[] QrFactorize(this double[,] aqr) { double[] diag = new double[Fun.Min(aqr.GetLength(0), aqr.GetLength(1))]; aqr.QrFactorize(diag); return diag; } /// /// Solves the Equation QR x = b. QR must be a factorized matrix (QrFactorize). /// diag provides the diagonal elements of R (QrFactorize) /// If QR is not quadratic the x where |QR*x - b| == min is calculated /// residual holds the minimal value of |QR*x - b| /// public static void QrSolve( this double[,] qr, double[] diag, double[] b, double[] x, out double residual) { int rows = qr.GetLength(0); int cols = qr.GetLength(1); if (rows < cols) { for (int r = 0; r < rows; r++) { var value = b[r]; for (int j = 0; j < r; j++) value -= qr[r, j] * x[j]; x[r] = value / diag[r]; } for (int i = rows; i < cols; i++) x[i] = 0.0; for (int c = rows - 1; c >= 0; c--) x.FlipWithNormalizedRowHouseholder(qr, c, cols); residual = 0.0; } else { var c = b.Copy(rows); for (int i = 0; i < cols; i++) c.FlipWithNormalizedColHouseholder(qr, i, rows); for (int r = cols - 1; r >= 0; r--) { var value = c[r]; for (int j = r + 1; j < cols; j++) value -= qr[r, j] * x[j]; x[r] = value / diag[r]; } residual = 0.0; if (cols < rows) { for (int i = cols; i < b.Length; i++) residual += c[i] * c[i]; residual = Fun.Sqrt(residual); } } } /// /// Solves the Equation QR*x = b. QR must be a factorized matrix (QRFactorize). /// diag provides the diagonal elements of R (QRFactorize) /// If QR is not quadratic the x where |QR*x - b| == min is calculated /// public static double[] QrSolve( this double[,] qr, double[] diag, double[] b) { double unusedResidual; double[] x = new double[qr.GetLength(1)]; QrSolve(qr, diag, b, x, out unusedResidual); return x; } /// /// Solves the Equation QR*x = b. QR must be a factorized matrix (QRFactorize). /// diag provides the diagonal elements of R (QRFactorize) /// If QR is not quadratic the x where |QR*x - b| == min is returned /// residual holds the minimal value of |QR*x - b| /// public static double[] QrSolve( this double[,] qr, double[] diag, double[] b, out double residual) { double[] x = new double[qr.GetLength(1)]; QrSolve(qr, diag, b, x, out residual); return x; } public static void QrInverse(this double[,] QR, double[] diag, double[,] inv) { int m = QR.GetLength(0); int n = QR.GetLength(1); if (m != n) throw new ArgumentException("Can only invert quadratic matrices"); double[] temp = new double[n]; double[] b = new double[n]; double err; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) b[j] = (i == j ? 1.0 : 0.0); QR.QrSolve(diag, b, temp, out err); for (int j = 0; j < n; j++) inv[j, i] = temp[j]; } } /// /// Calculates the inverse Matrix to A using Householder-Transformations /// A has to be Quadratic /// public static double[,] QrInverse(this double[,] matrix) { double[,] qr = (double[,])matrix.Clone(); double[] diag = qr.QrFactorize(); double[,] inv = new double[matrix.GetLength(1), matrix.GetLength(0)]; qr.QrInverse(diag, inv); return inv; } #endregion #region QR factorization of double[] with offset and strides using Householder transformations /// /// Perform a QR factorization of the supplied m x n matrix using /// Householder transofmations, i.e. A = QR, where Q is orthogonal /// (a product of n-2 Householder-Transformations) and R is a right /// upper n x n triangular matrix. The diagonal elements of R are /// put in the supplied array diagonal. WARNING: the supplied /// matrix A is overwritten with its factorization QR, both in the /// parameter aqr. /// public static void QrFactorize( this double[] aqr, long a0, long ax, long ay, long cols, long rows, double[] diagonal) { if (rows < cols) { for (long r = 0, arr = a0; r < rows; r++, arr += ax + ay) { var value = aqr[arr]; double alpha = -System.Math.Sign(value) * aqr.RowNorm2(a0, ax, ay, r, r, cols); value -= alpha; double norm_v = System.Math.Sqrt(-2.0 * alpha * value); diagonal[r] = alpha; aqr[arr] = value / norm_v; for (long c = r + 1, arc = arr + ax; c < cols; c++, arc += ax) aqr[arc] /= norm_v; for (long j = r + 1, aj_ = arr + ay; j < rows; j++, aj_ += ay) { double p_j = 2.0 * aqr.RowDotRow(a0, ax, ay, r, j, r, cols); for (long c = r, ajc = aj_, arc = arr; c < cols; c++, ajc += ax, arc += ax) aqr[ajc] -= p_j * aqr[arc]; } } } else { for (long c = 0, acc = a0; c < cols; c++, acc += ax + ay) { var value = aqr[acc]; double alpha = -System.Math.Sign(value) * aqr.ColNorm2(a0, ax, ay, c, c, rows); value -= alpha; double norm_v = System.Math.Sqrt(-2.0 * alpha * value); diagonal[c] = alpha; aqr[acc] = value / norm_v; for (long r = c + 1, arc = acc + ay; r < rows; r++, arc += ay) aqr[arc] /= norm_v; for (long j = c + 1, a_j = acc + ax; j < cols; j++, a_j += ax) { double p_j = 2.0 * aqr.ColDotCol(a0, ax, ay, c, j, c, rows); for (long r = c, arj = a_j, arc = acc; r < rows; r++, arj += ay, arc += ay) aqr[arj] -= p_j * aqr[arc]; } } } } /// /// Solves the Equation QR x = b. QR must be a factorized matrix (QrFactorize). /// diag provides the diagonal elements of R (QrFactorize) /// If QR is not quadratic the x where |QR x - b| == min is calculated /// residual holds the minimal value of |QR x - b| /// public static void QrSolve( this double[] qr, long q0, long qx, long qy, long cols, long rows, double[] diag, double[] b, long b0, long bd, double[] x, long x0, long xd, out double residual) { if (rows < cols) { var xr = x0; for (long r = 0, br = b0, qr_ = q0; r < rows; r++, br += bd, qr_ += qy, xr += xd) { var value = b[br]; for (long j = 0, qrj = qr_, xj = x0; j < r; j++, qrj += qx, xj += xd) value -= qr[qrj] * x[xj]; x[xr] = value / diag[r]; } for (long i = rows; i < cols; i++, xr += xd) x[xr] = 0.0; for (long c = rows - 1; c >= 0; c--) x.FlipWithNormalizedRowHouseholder(x0, xd, qr, q0, qx, qy, c, cols); residual = 0.0; } else { double[] c = new double[rows]; for (long i = 0, bi = b0; i < rows; i++, bi += bd) c[i] = b[bi]; for (long i = 0; i < cols; i++) c.FlipWithNormalizedColHouseholder(qr, q0, qx, qy, i, rows); for (long r = cols - 1, xr = x0 + r * xd, qr_ = q0 + r * qy; r >= 0; r--, xr -= xd, qr_ -= qy) { var value = c[r]; for (long j = r + 1, qrj = qr_ + j * qx, xj = x0 + j * xd; j < cols; j++, qrj += qx, xj += xd) value -= qr[qrj] * x[xj]; x[xr] = value / diag[r]; } residual = 0.0; if (cols < rows) { for (long i = cols; i < rows; i++) residual += c[i] * c[i]; residual = Fun.Sqrt(residual); } } } #endregion } } ================================================ FILE: src/Aardvark.Base/Math/RangesBoxes/Box.cs ================================================ using System.Runtime.Serialization; namespace Aardvark.Base { #region OctoBox2d [DataContract] public struct OctoBox2d { [DataMember] public double PX, PY, NX, NY, PXPY, PXNY, NXPY, NXNY; #region Constructors public OctoBox2d( double px, double py, double nx, double ny, double pxpy, double pxny, double nxpy, double nxny) { PX = px; PY = py; NX = nx; NY = ny; PXPY = pxpy; PXNY = pxny; NXPY = nxpy; NXNY = nxny; } #endregion #region Constants public static readonly OctoBox2d Invalid = new OctoBox2d(double.MinValue, double.MinValue, double.MinValue, double.MinValue, double.MinValue, double.MinValue, double.MinValue, double.MinValue); public static readonly OctoBox2d Zero = new OctoBox2d(0, 0, 0, 0, 0, 0, 0, 0); #endregion #region Properties public readonly double Area { get { return (PX + NX) * (PY + NY) - 0.5 * (Fun.Square(PX + PY - PXPY) + Fun.Square(PX + NY - PXNY) + Fun.Square(NX + PY - NXPY) + Fun.Square(NX + NY - NXNY)); } } #endregion #region Manipulation public void ExtendBy(V2d p) { ExtendBy(p.X, p.Y); } public void ExtendBy(double x, double y) { if (x > PX) PX = x; if (y > PY) PY = y; var nx = -x; if (nx > NX) NX = nx; var ny = -y; if (ny > NY) NY = ny; var pxpy = x + y; if (pxpy > PXPY) PXPY = pxpy; var pxny = x - y; if (pxny > PXNY) PXNY = pxny; var nxpy = -x + y; if (nxpy > NXPY) NXPY = nxpy; var nxny = -x - y; if (nxny > NXNY) NXNY = nxny; } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/RangesBoxes/Box_auto.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { // AUTOGENERATED CODE - DO NOT CHANGE! #region Flags public static partial class Box { [Flags] public enum Flags { None = 0x00000000, /* --------------------------------------------------------------- flags that mark the faces of a box --------------------------------------------------------------- */ MinX0 = 0x00000001, MinY0 = 0x00000002, MinZ0 = 0x00000004, MaxX0 = 0x00000008, MaxY0 = 0x00000010, MaxZ0 = 0x00000020, Min0 = MinX0 | MinY0 | MinZ0, Max0 = MaxX0 | MaxY0 | MaxZ0, X0 = MinX0 | MaxX0, Y0 = MinY0 | MaxY0, Z0 = MinZ0 | MaxZ0, All0 = Min0 | Max0, /* --------------------------------------------------------------- flags that mark the faces of a second, independent box --------------------------------------------------------------- */ MinX1 = MinX0 << 6, MinY1 = MinY0 << 6, MinZ1 = MinZ0 << 6, MaxX1 = MaxX0 << 6, MaxY1 = MaxY0 << 6, MaxZ1 = MaxZ0 << 6, Min1 = Min0 << 6, Max1 = Max0 << 6, X1 = X0 << 6, Y1 = Y0 << 6, Z1 = Z0 << 6, All1 = All0 << 6, /* --------------------------------------------------------------- flags that operate on both face bits together --------------------------------------------------------------- */ MinX = MinX0 | MinX1, MinY = MinY0 | MinY1, MinZ = MinZ0 | MinZ1, MaxX = MaxX0 | MaxX1, MaxY = MaxY0 | MaxY1, MaxZ = MaxZ0 | MaxZ1, Min = Min0 | Min1, Max = Max0 | Max1, MinXMinY = MinX | MinY, MinXMaxY = MinX | MaxY, MaxXMinY = MaxX | MinY, MaxXMaxY = MaxX | MaxY, X = X0 | X1, Y = Y0 | Y1, Z = Z0 | Z1, All = All0 | All1, /* --------------------------------------------------------------- flags that mark the edges of the box --------------------------------------------------------------- */ Edge01 = 0x00001000, Edge23 = 0x00002000, Edge45 = 0x00004000, Edge67 = 0x00008000, Edge02 = 0x00010000, Edge13 = 0x00020000, Edge46 = 0x00040000, Edge57 = 0x00080000, Edge04 = 0x00100000, Edge15 = 0x00200000, Edge26 = 0x00400000, Edge37 = 0x00800000, /* --------------------------------------------------------------- flags that mark the corners of the box --------------------------------------------------------------- */ Corner0 = 0x01000000, Corner1 = 0x02000000, Corner2 = 0x04000000, Corner3 = 0x08000000, Corner4 = 0x10000000, Corner5 = 0x20000000, Corner6 = 0x40000000, Corner7 = (int)-0x80000000, } } #endregion #region Range1b [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Range1b : IEquatable, IRange, IFormattable { [DataMember] public byte Min; [DataMember] public byte Max; #region Constructors /// /// Construct a Range1b from a Range1sb. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(Range1sb b) { Min = (byte) b.Min; Max = (byte) b.Max; } /// /// Construct a Range1b from a Range1s. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(Range1s b) { Min = (byte) b.Min; Max = (byte) b.Max; } /// /// Construct a Range1b from a Range1us. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(Range1us b) { Min = (byte) b.Min; Max = (byte) b.Max; } /// /// Construct a Range1b from a Range1i. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(Range1i b) { Min = (byte) b.Min; Max = (byte) b.Max; } /// /// Construct a Range1b from a Range1ui. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(Range1ui b) { Min = (byte) b.Min; Max = (byte) b.Max; } /// /// Construct a Range1b from a Range1l. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(Range1l b) { Min = (byte) b.Min; Max = (byte) b.Max; } /// /// Construct a Range1b from a Range1ul. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(Range1ul b) { Min = (byte) b.Min; Max = (byte) b.Max; } /// /// Construct a Range1b from a Range1f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(Range1f b) { Min = (byte) b.Min; Max = (byte) b.Max; } /// /// Construct a Range1b from a Range1d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(Range1d b) { Min = (byte) b.Min; Max = (byte) b.Max; } /// /// Creates a range from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(byte min, byte max) { Min = min; Max = max; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(byte pnt) { Min = pnt; Max = pnt; } /// /// Creates a range from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(byte p0, byte p1, byte p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a range from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(byte p0, byte p1, byte p2, byte p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(Range1b range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(Range1b b0, Range1b b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(Range1b b0, Range1b b1, Range1b b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(Range1b b0, Range1b b1, Range1b b2, Range1b b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates range as the bounding range of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(byte[] values) { Min = byte.MaxValue; Max = byte.MinValue; if (values == null) return; long count = values.LongLength; for (long i = 0; i < count; i++) ExtendBy(values[i]); } /// /// Creates range as the bounding range of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(byte[] values, long start, long count) { if (count <= 0) { Min = byte.MaxValue; Max = byte.MinValue; } else { Min = Max = values[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(values[i]); } } /// /// Creates range as the bounding range of given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b(IEnumerable values) { Min = byte.MaxValue; Max = byte.MinValue; if (values == null) return; foreach (byte v in values) ExtendBy(v); } /// /// Returns new range [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1b FromMinAndSize(byte min, byte size) { return new Range1b(min, (byte)(min + size)); } /// /// Returns new range [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1b FromCenterAndSize(byte center, byte size) { return new Range1b((byte)(center - size / 2), (byte)(center + size / 2)); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1b(Range1sb b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1b(Range1s b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1b(Range1us b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1b(Range1i b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1b(Range1ui b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1b(Range1l b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1b(Range1ul b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1b(Range1f b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1b(Range1d b) => new(b); #endregion #region Constants /// /// A range with crossed limits. /// public static Range1b Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(byte.MaxValue, byte.MinValue); } /// /// The largest possible range. /// public static Range1b Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(byte.MinValue, byte.MaxValue); } /// /// The unit interval [0, 1]. /// public static Range1b Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(0, 1); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min >= Max; } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min <= Max; } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min > Max; } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Calculates size of the range. /// [XmlIgnore] public byte Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (byte)(Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (byte)(Min + value); } } public readonly byte Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (byte)((Min + Max) / 2); } } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (IsInvalid) yield break; //Todo: check should not be necessary for (var i = Min; i <= Max; i++) yield return i; } } #endregion #region Size Manipulations /// /// Return range enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1b EnlargedBy(byte increment) { return new Range1b((byte)(Min - increment), (byte)(Max + increment)); } /// /// Return range enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1b EnlargedBy(byte deltaMin, byte deltaMax) { return new Range1b((byte)(Min - deltaMin), (byte)(Max + deltaMax)); } /// /// Return range shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1b ShrunkBy(byte delta) { return new Range1b((byte)(Min + delta), (byte)(Max - delta)); } /// /// Return range shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1b ShrunkBy(byte deltaMin, byte deltaMax) { return new Range1b((byte)(Min + deltaMin), (byte)(Max - deltaMax)); } /// /// Enlarges range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(byte delta) { Min -= delta; Max += delta; } /// /// Enlarges range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(byte deltaMin, byte deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(byte delta) { Min += delta; Max -= delta; } /// /// Shrinks range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(byte deltaMin, byte deltaMax) { Min += deltaMin; Max -= deltaMax; } #endregion #region Box Arithmetics /// /// Return the value in the Range that is closest to the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly byte Clamped(byte x) { return x < Min ? Min : (x > Max ? Max : x); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly byte Lerp(float t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly byte Lerp(double t) => Fun.Lerp(t, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double InvLerp(byte y) => Fun.InvLerp(y, Min, Max); /// /// Returns the range with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1b SplitRight(byte splitValue) { if (splitValue > Max) return Range1b.Invalid; if (splitValue <= Min) return this; return new Range1b(splitValue, Max); } /// /// Returns the range with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1b SplitLeft(byte splitValue) { if (splitValue < Min) return Range1b.Invalid; if (splitValue >= Max) return this; return new Range1b(Min, splitValue); } /// /// Returns the range extended to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1b ExtendedBy(Range1b range) { return new Range1b( range.Min < Min ? range.Min : Min, range.Max > Max ? range.Max : Max); } /// /// Returns the range extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1b ExtendedBy(byte value) { return new Range1b( value < Min ? value : Min, value > Max ? value : Max); } /// /// Extends the range to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Range1b range) { if (range.Min < Min) Min = range.Min; if (range.Max > Max) Max = range.Max; } /// /// Extends the range to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(byte value) { if (value < Min) Min = value; if (value > Max) Max = value; } /// /// Returns true if the range contains the given value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(byte value) { return value >= Min && value <= Max; } /// /// Returns true if the range completely contains the given range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Range1b b) { return b.Min >= Min && b.Max <= Max; } /// /// Checks if 2 ranges intersect each other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1b range) { if (Min >= range.Max) return false; if (Max <= range.Min) return false; return true; } /// /// Checks if 2 ranges intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1b range, byte eps) { if (Min - eps >= range.Max) return false; if (Max + eps <= range.Min) return false; return true; } /// /// Checks if the range is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1b Repair() { if (this.Equals(Range1b.Invalid)) return this; if (Min > Max) Fun.Swap(ref Min, ref Max); return this; } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Range1b a, Range1b b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Range1b a, Range1b b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a range shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1b operator +(Range1b box, byte v) { return new Range1b((byte)(box.Min + v), (byte)(box.Max + v)); } /// /// Returns a range shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1b operator -(Range1b box, byte v) { return new Range1b((byte)(box.Min - v), (byte)(box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Range1b other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Range1b o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Range1b box, int i, byte value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Range1b Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Range1b(byte.Parse(x[0], CultureInfo.InvariantCulture), byte.Parse(x[1], CultureInfo.InvariantCulture)); } public static Range1b Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, Range1b.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { fp ??= CultureInfo.InvariantCulture; return begin + Min.ToString(format, fp) + between + Max.ToString(format, fp) + end; } #endregion } public static partial class Range { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1b Union(this Range1b a, Range1b b) { return new Range1b(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1b Intersection(this Range1b a, Range1b b) { return new Range1b(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } /// /// Checks if two ranges intersect each other with a tolerance parameter. /// // TODO: Implement for d > 2 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Range1b a, Range1b b, byte eps, out Range1b result) { result = Range1b.Invalid; if (a.Min - eps > b.Max) return false; else if (a.Max + eps < b.Min) return false; else { result = new Range1b(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); if (result.Size < eps) { byte center = result.Center; result.Min = (byte)(center - eps); result.Max = (byte)(center + eps); } return true; } } #endregion #region Bounding range for arrays /// /// Returns the bounding range of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1b GetBoundingRange(this byte[] pointArray) { return pointArray.GetBoundingRange(0, pointArray.LongLength); } /// /// Returns the bounding range of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1b GetBoundingRange(this byte[] pointArray, long count) { return pointArray.GetBoundingRange(0, count); } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1b GetBoundingRange( this byte[] pointArray, long start, long count) { if (count <= 0) return Range1b.Invalid; var box = new Range1b(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1b GetBoundingRange(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Range1b.Invalid; var box = new Range1b(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding range for lists /// /// Returns the bounding range of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1b GetBoundingRange(this List pointList) { return pointList.GetBoundingRange(pointList.Count); } /// /// Returns the bounding range of the first count elements of the list. /// public static Range1b GetBoundingRange(this List pointList, int count) { if (count <= 0) return Range1b.Invalid; var box = new Range1b(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding range for indexed arrays /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1b GetBoundingRange(this int[] indexArray, byte[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.Length, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1b GetBoundingRange(this int[] indexArray, int count, byte[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1b GetBoundingRange(this int[] indexArray, int start, int count, byte[] pointArray) { if (count <= 0) return Range1b.Invalid; var box = new Range1b(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1b GetBoundingRange(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Range1b.Invalid; var box = new Range1b(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1b GetBoundingRange(this long[] indexArray, byte[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1b GetBoundingRange(this long[] indexArray, long count, byte[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1b GetBoundingRange(this long[] indexArray, long start, long count, byte[] pointArray) { if (count <= 0) return Range1b.Invalid; var box = new Range1b(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1b GetBoundingRange(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Range1b.Invalid; var box = new Range1b(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding range for IEnumerable /// /// Returns the bounding range of the elements of the collection. /// public static Range1b GetBoundingRange(this IEnumerable points) { var box = Range1b.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion } #region Range extensions public static partial class RangeExtensions { /// /// Returns the int sequence 0 ... count-1. /// public static IEnumerable Range(this byte count) { for (byte i = 0; i < count; i++) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpTo(this byte self, byte upToInclusive) { return self.UpTo(upToInclusive, 1); } public static IEnumerable UpTo(this byte self, byte upToInclusive, byte step) { for (byte i = self; i <= upToInclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpToExclusive(this byte self, byte upToExclusive) { return self.UpToExclusive(upToExclusive, 1); } public static IEnumerable UpToExclusive(this byte self, byte upToExclusive, byte step) { for (byte i = self; i < upToExclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable DownTo(this byte self, byte downToInclusive) { return self.DownTo(downToInclusive, 1); } public static IEnumerable DownTo(this byte self, byte downToInclusive, byte step) { for (byte i = self; i >= downToInclusive; i -= step) yield return i; } } #endregion public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1b a, Range1b b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1b a, Range1b b, byte tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Range1sb [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Range1sb : IEquatable, IRange, IFormattable { [DataMember] public sbyte Min; [DataMember] public sbyte Max; #region Constructors /// /// Construct a Range1sb from a Range1b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(Range1b b) { Min = (sbyte) b.Min; Max = (sbyte) b.Max; } /// /// Construct a Range1sb from a Range1s. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(Range1s b) { Min = (sbyte) b.Min; Max = (sbyte) b.Max; } /// /// Construct a Range1sb from a Range1us. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(Range1us b) { Min = (sbyte) b.Min; Max = (sbyte) b.Max; } /// /// Construct a Range1sb from a Range1i. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(Range1i b) { Min = (sbyte) b.Min; Max = (sbyte) b.Max; } /// /// Construct a Range1sb from a Range1ui. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(Range1ui b) { Min = (sbyte) b.Min; Max = (sbyte) b.Max; } /// /// Construct a Range1sb from a Range1l. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(Range1l b) { Min = (sbyte) b.Min; Max = (sbyte) b.Max; } /// /// Construct a Range1sb from a Range1ul. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(Range1ul b) { Min = (sbyte) b.Min; Max = (sbyte) b.Max; } /// /// Construct a Range1sb from a Range1f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(Range1f b) { Min = (sbyte) b.Min; Max = (sbyte) b.Max; } /// /// Construct a Range1sb from a Range1d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(Range1d b) { Min = (sbyte) b.Min; Max = (sbyte) b.Max; } /// /// Creates a range from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(sbyte min, sbyte max) { Min = min; Max = max; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(sbyte pnt) { Min = pnt; Max = pnt; } /// /// Creates a range from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(sbyte p0, sbyte p1, sbyte p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a range from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(sbyte p0, sbyte p1, sbyte p2, sbyte p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(Range1sb range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(Range1sb b0, Range1sb b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(Range1sb b0, Range1sb b1, Range1sb b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(Range1sb b0, Range1sb b1, Range1sb b2, Range1sb b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates range as the bounding range of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(sbyte[] values) { Min = sbyte.MaxValue; Max = sbyte.MinValue; if (values == null) return; long count = values.LongLength; for (long i = 0; i < count; i++) ExtendBy(values[i]); } /// /// Creates range as the bounding range of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(sbyte[] values, long start, long count) { if (count <= 0) { Min = sbyte.MaxValue; Max = sbyte.MinValue; } else { Min = Max = values[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(values[i]); } } /// /// Creates range as the bounding range of given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb(IEnumerable values) { Min = sbyte.MaxValue; Max = sbyte.MinValue; if (values == null) return; foreach (sbyte v in values) ExtendBy(v); } /// /// Returns new range [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1sb FromMinAndSize(sbyte min, sbyte size) { return new Range1sb(min, (sbyte)(min + size)); } /// /// Returns new range [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1sb FromCenterAndSize(sbyte center, sbyte size) { return new Range1sb((sbyte)(center - size / 2), (sbyte)(center + size / 2)); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1sb(Range1b b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1sb(Range1s b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1sb(Range1us b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1sb(Range1i b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1sb(Range1ui b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1sb(Range1l b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1sb(Range1ul b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1sb(Range1f b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1sb(Range1d b) => new(b); #endregion #region Constants /// /// A range with crossed limits. /// public static Range1sb Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(sbyte.MaxValue, sbyte.MinValue); } /// /// The largest possible range. /// public static Range1sb Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(sbyte.MinValue, sbyte.MaxValue); } /// /// The unit interval [0, 1]. /// public static Range1sb Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(0, 1); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min >= Max; } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min <= Max; } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min > Max; } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Calculates size of the range. /// [XmlIgnore] public sbyte Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (sbyte)(Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (sbyte)(Min + value); } } public readonly sbyte Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (sbyte)((Min + Max) / 2); } } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (IsInvalid) yield break; //Todo: check should not be necessary for (var i = Min; i <= Max; i++) yield return i; } } #endregion #region Size Manipulations /// /// Return range enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1sb EnlargedBy(sbyte increment) { return new Range1sb((sbyte)(Min - increment), (sbyte)(Max + increment)); } /// /// Return range enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1sb EnlargedBy(sbyte deltaMin, sbyte deltaMax) { return new Range1sb((sbyte)(Min - deltaMin), (sbyte)(Max + deltaMax)); } /// /// Return range shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1sb ShrunkBy(sbyte delta) { return new Range1sb((sbyte)(Min + delta), (sbyte)(Max - delta)); } /// /// Return range shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1sb ShrunkBy(sbyte deltaMin, sbyte deltaMax) { return new Range1sb((sbyte)(Min + deltaMin), (sbyte)(Max - deltaMax)); } /// /// Enlarges range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(sbyte delta) { Min -= delta; Max += delta; } /// /// Enlarges range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(sbyte deltaMin, sbyte deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(sbyte delta) { Min += delta; Max -= delta; } /// /// Shrinks range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(sbyte deltaMin, sbyte deltaMax) { Min += deltaMin; Max -= deltaMax; } #endregion #region Box Arithmetics /// /// Return the value in the Range that is closest to the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly sbyte Clamped(sbyte x) { return x < Min ? Min : (x > Max ? Max : x); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly sbyte Lerp(float t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly sbyte Lerp(double t) => Fun.Lerp(t, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double InvLerp(sbyte y) => Fun.InvLerp(y, Min, Max); /// /// Returns the range with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1sb SplitRight(sbyte splitValue) { if (splitValue > Max) return Range1sb.Invalid; if (splitValue <= Min) return this; return new Range1sb(splitValue, Max); } /// /// Returns the range with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1sb SplitLeft(sbyte splitValue) { if (splitValue < Min) return Range1sb.Invalid; if (splitValue >= Max) return this; return new Range1sb(Min, splitValue); } /// /// Returns the range extended to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1sb ExtendedBy(Range1sb range) { return new Range1sb( range.Min < Min ? range.Min : Min, range.Max > Max ? range.Max : Max); } /// /// Returns the range extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1sb ExtendedBy(sbyte value) { return new Range1sb( value < Min ? value : Min, value > Max ? value : Max); } /// /// Extends the range to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Range1sb range) { if (range.Min < Min) Min = range.Min; if (range.Max > Max) Max = range.Max; } /// /// Extends the range to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(sbyte value) { if (value < Min) Min = value; if (value > Max) Max = value; } /// /// Returns true if the range contains the given value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(sbyte value) { return value >= Min && value <= Max; } /// /// Returns true if the range completely contains the given range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Range1sb b) { return b.Min >= Min && b.Max <= Max; } /// /// Checks if 2 ranges intersect each other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1sb range) { if (Min >= range.Max) return false; if (Max <= range.Min) return false; return true; } /// /// Checks if 2 ranges intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1sb range, sbyte eps) { if (Min - eps >= range.Max) return false; if (Max + eps <= range.Min) return false; return true; } /// /// Checks if the range is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1sb Repair() { if (this.Equals(Range1sb.Invalid)) return this; if (Min > Max) Fun.Swap(ref Min, ref Max); return this; } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Range1sb a, Range1sb b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Range1sb a, Range1sb b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a range shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1sb operator +(Range1sb box, sbyte v) { return new Range1sb((sbyte)(box.Min + v), (sbyte)(box.Max + v)); } /// /// Returns a range shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1sb operator -(Range1sb box, sbyte v) { return new Range1sb((sbyte)(box.Min - v), (sbyte)(box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Range1sb other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Range1sb o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Range1sb box, int i, sbyte value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Range1sb Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Range1sb(sbyte.Parse(x[0], CultureInfo.InvariantCulture), sbyte.Parse(x[1], CultureInfo.InvariantCulture)); } public static Range1sb Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, Range1sb.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { fp ??= CultureInfo.InvariantCulture; return begin + Min.ToString(format, fp) + between + Max.ToString(format, fp) + end; } #endregion } public static partial class Range { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1sb Union(this Range1sb a, Range1sb b) { return new Range1sb(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1sb Intersection(this Range1sb a, Range1sb b) { return new Range1sb(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } /// /// Checks if two ranges intersect each other with a tolerance parameter. /// // TODO: Implement for d > 2 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Range1sb a, Range1sb b, sbyte eps, out Range1sb result) { result = Range1sb.Invalid; if (a.Min - eps > b.Max) return false; else if (a.Max + eps < b.Min) return false; else { result = new Range1sb(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); if (result.Size < eps) { sbyte center = result.Center; result.Min = (sbyte)(center - eps); result.Max = (sbyte)(center + eps); } return true; } } #endregion #region Bounding range for arrays /// /// Returns the bounding range of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1sb GetBoundingRange(this sbyte[] pointArray) { return pointArray.GetBoundingRange(0, pointArray.LongLength); } /// /// Returns the bounding range of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1sb GetBoundingRange(this sbyte[] pointArray, long count) { return pointArray.GetBoundingRange(0, count); } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1sb GetBoundingRange( this sbyte[] pointArray, long start, long count) { if (count <= 0) return Range1sb.Invalid; var box = new Range1sb(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1sb GetBoundingRange(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Range1sb.Invalid; var box = new Range1sb(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding range for lists /// /// Returns the bounding range of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1sb GetBoundingRange(this List pointList) { return pointList.GetBoundingRange(pointList.Count); } /// /// Returns the bounding range of the first count elements of the list. /// public static Range1sb GetBoundingRange(this List pointList, int count) { if (count <= 0) return Range1sb.Invalid; var box = new Range1sb(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding range for indexed arrays /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1sb GetBoundingRange(this int[] indexArray, sbyte[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.Length, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1sb GetBoundingRange(this int[] indexArray, int count, sbyte[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1sb GetBoundingRange(this int[] indexArray, int start, int count, sbyte[] pointArray) { if (count <= 0) return Range1sb.Invalid; var box = new Range1sb(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1sb GetBoundingRange(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Range1sb.Invalid; var box = new Range1sb(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1sb GetBoundingRange(this long[] indexArray, sbyte[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1sb GetBoundingRange(this long[] indexArray, long count, sbyte[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1sb GetBoundingRange(this long[] indexArray, long start, long count, sbyte[] pointArray) { if (count <= 0) return Range1sb.Invalid; var box = new Range1sb(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1sb GetBoundingRange(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Range1sb.Invalid; var box = new Range1sb(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding range for IEnumerable /// /// Returns the bounding range of the elements of the collection. /// public static Range1sb GetBoundingRange(this IEnumerable points) { var box = Range1sb.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion } #region Range extensions public static partial class RangeExtensions { /// /// Returns the int sequence 0 ... count-1. /// public static IEnumerable Range(this sbyte count) { for (sbyte i = 0; i < count; i++) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpTo(this sbyte self, sbyte upToInclusive) { return self.UpTo(upToInclusive, 1); } public static IEnumerable UpTo(this sbyte self, sbyte upToInclusive, sbyte step) { for (sbyte i = self; i <= upToInclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpToExclusive(this sbyte self, sbyte upToExclusive) { return self.UpToExclusive(upToExclusive, 1); } public static IEnumerable UpToExclusive(this sbyte self, sbyte upToExclusive, sbyte step) { for (sbyte i = self; i < upToExclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable DownTo(this sbyte self, sbyte downToInclusive) { return self.DownTo(downToInclusive, 1); } public static IEnumerable DownTo(this sbyte self, sbyte downToInclusive, sbyte step) { for (sbyte i = self; i >= downToInclusive; i -= step) yield return i; } } #endregion public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1sb a, Range1sb b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1sb a, Range1sb b, sbyte tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Range1s [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Range1s : IEquatable, IRange, IFormattable { [DataMember] public short Min; [DataMember] public short Max; #region Constructors /// /// Construct a Range1s from a Range1b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(Range1b b) { Min = (short) b.Min; Max = (short) b.Max; } /// /// Construct a Range1s from a Range1sb. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(Range1sb b) { Min = (short) b.Min; Max = (short) b.Max; } /// /// Construct a Range1s from a Range1us. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(Range1us b) { Min = (short) b.Min; Max = (short) b.Max; } /// /// Construct a Range1s from a Range1i. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(Range1i b) { Min = (short) b.Min; Max = (short) b.Max; } /// /// Construct a Range1s from a Range1ui. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(Range1ui b) { Min = (short) b.Min; Max = (short) b.Max; } /// /// Construct a Range1s from a Range1l. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(Range1l b) { Min = (short) b.Min; Max = (short) b.Max; } /// /// Construct a Range1s from a Range1ul. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(Range1ul b) { Min = (short) b.Min; Max = (short) b.Max; } /// /// Construct a Range1s from a Range1f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(Range1f b) { Min = (short) b.Min; Max = (short) b.Max; } /// /// Construct a Range1s from a Range1d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(Range1d b) { Min = (short) b.Min; Max = (short) b.Max; } /// /// Creates a range from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(short min, short max) { Min = min; Max = max; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(short pnt) { Min = pnt; Max = pnt; } /// /// Creates a range from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(short p0, short p1, short p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a range from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(short p0, short p1, short p2, short p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(Range1s range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(Range1s b0, Range1s b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(Range1s b0, Range1s b1, Range1s b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(Range1s b0, Range1s b1, Range1s b2, Range1s b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates range as the bounding range of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(short[] values) { Min = short.MaxValue; Max = short.MinValue; if (values == null) return; long count = values.LongLength; for (long i = 0; i < count; i++) ExtendBy(values[i]); } /// /// Creates range as the bounding range of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(short[] values, long start, long count) { if (count <= 0) { Min = short.MaxValue; Max = short.MinValue; } else { Min = Max = values[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(values[i]); } } /// /// Creates range as the bounding range of given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s(IEnumerable values) { Min = short.MaxValue; Max = short.MinValue; if (values == null) return; foreach (short v in values) ExtendBy(v); } /// /// Returns new range [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1s FromMinAndSize(short min, short size) { return new Range1s(min, (short)(min + size)); } /// /// Returns new range [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1s FromCenterAndSize(short center, short size) { return new Range1s((short)(center - size / 2), (short)(center + size / 2)); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1s(Range1b b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1s(Range1sb b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1s(Range1us b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1s(Range1i b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1s(Range1ui b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1s(Range1l b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1s(Range1ul b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1s(Range1f b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1s(Range1d b) => new(b); #endregion #region Constants /// /// A range with crossed limits. /// public static Range1s Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(short.MaxValue, short.MinValue); } /// /// The largest possible range. /// public static Range1s Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(short.MinValue, short.MaxValue); } /// /// The unit interval [0, 1]. /// public static Range1s Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(0, 1); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min >= Max; } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min <= Max; } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min > Max; } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Calculates size of the range. /// [XmlIgnore] public short Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (short)(Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (short)(Min + value); } } public readonly short Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (short)((Min + Max) / 2); } } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (IsInvalid) yield break; //Todo: check should not be necessary for (var i = Min; i <= Max; i++) yield return i; } } #endregion #region Size Manipulations /// /// Return range enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1s EnlargedBy(short increment) { return new Range1s((short)(Min - increment), (short)(Max + increment)); } /// /// Return range enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1s EnlargedBy(short deltaMin, short deltaMax) { return new Range1s((short)(Min - deltaMin), (short)(Max + deltaMax)); } /// /// Return range shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1s ShrunkBy(short delta) { return new Range1s((short)(Min + delta), (short)(Max - delta)); } /// /// Return range shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1s ShrunkBy(short deltaMin, short deltaMax) { return new Range1s((short)(Min + deltaMin), (short)(Max - deltaMax)); } /// /// Enlarges range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(short delta) { Min -= delta; Max += delta; } /// /// Enlarges range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(short deltaMin, short deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(short delta) { Min += delta; Max -= delta; } /// /// Shrinks range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(short deltaMin, short deltaMax) { Min += deltaMin; Max -= deltaMax; } #endregion #region Box Arithmetics /// /// Return the value in the Range that is closest to the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly short Clamped(short x) { return x < Min ? Min : (x > Max ? Max : x); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly short Lerp(float t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly short Lerp(double t) => Fun.Lerp(t, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double InvLerp(short y) => Fun.InvLerp(y, Min, Max); /// /// Returns the range with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1s SplitRight(short splitValue) { if (splitValue > Max) return Range1s.Invalid; if (splitValue <= Min) return this; return new Range1s(splitValue, Max); } /// /// Returns the range with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1s SplitLeft(short splitValue) { if (splitValue < Min) return Range1s.Invalid; if (splitValue >= Max) return this; return new Range1s(Min, splitValue); } /// /// Returns the range extended to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1s ExtendedBy(Range1s range) { return new Range1s( range.Min < Min ? range.Min : Min, range.Max > Max ? range.Max : Max); } /// /// Returns the range extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1s ExtendedBy(short value) { return new Range1s( value < Min ? value : Min, value > Max ? value : Max); } /// /// Extends the range to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Range1s range) { if (range.Min < Min) Min = range.Min; if (range.Max > Max) Max = range.Max; } /// /// Extends the range to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(short value) { if (value < Min) Min = value; if (value > Max) Max = value; } /// /// Returns true if the range contains the given value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(short value) { return value >= Min && value <= Max; } /// /// Returns true if the range completely contains the given range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Range1s b) { return b.Min >= Min && b.Max <= Max; } /// /// Checks if 2 ranges intersect each other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1s range) { if (Min >= range.Max) return false; if (Max <= range.Min) return false; return true; } /// /// Checks if 2 ranges intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1s range, short eps) { if (Min - eps >= range.Max) return false; if (Max + eps <= range.Min) return false; return true; } /// /// Checks if the range is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1s Repair() { if (this.Equals(Range1s.Invalid)) return this; if (Min > Max) Fun.Swap(ref Min, ref Max); return this; } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Range1s a, Range1s b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Range1s a, Range1s b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a range shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1s operator +(Range1s box, short v) { return new Range1s((short)(box.Min + v), (short)(box.Max + v)); } /// /// Returns a range shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1s operator -(Range1s box, short v) { return new Range1s((short)(box.Min - v), (short)(box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Range1s other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Range1s o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Range1s box, int i, short value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Range1s Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Range1s(short.Parse(x[0], CultureInfo.InvariantCulture), short.Parse(x[1], CultureInfo.InvariantCulture)); } public static Range1s Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, Range1s.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { fp ??= CultureInfo.InvariantCulture; return begin + Min.ToString(format, fp) + between + Max.ToString(format, fp) + end; } #endregion } public static partial class Range { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1s Union(this Range1s a, Range1s b) { return new Range1s(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1s Intersection(this Range1s a, Range1s b) { return new Range1s(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } /// /// Checks if two ranges intersect each other with a tolerance parameter. /// // TODO: Implement for d > 2 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Range1s a, Range1s b, short eps, out Range1s result) { result = Range1s.Invalid; if (a.Min - eps > b.Max) return false; else if (a.Max + eps < b.Min) return false; else { result = new Range1s(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); if (result.Size < eps) { short center = result.Center; result.Min = (short)(center - eps); result.Max = (short)(center + eps); } return true; } } #endregion #region Bounding range for arrays /// /// Returns the bounding range of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1s GetBoundingRange(this short[] pointArray) { return pointArray.GetBoundingRange(0, pointArray.LongLength); } /// /// Returns the bounding range of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1s GetBoundingRange(this short[] pointArray, long count) { return pointArray.GetBoundingRange(0, count); } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1s GetBoundingRange( this short[] pointArray, long start, long count) { if (count <= 0) return Range1s.Invalid; var box = new Range1s(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1s GetBoundingRange(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Range1s.Invalid; var box = new Range1s(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding range for lists /// /// Returns the bounding range of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1s GetBoundingRange(this List pointList) { return pointList.GetBoundingRange(pointList.Count); } /// /// Returns the bounding range of the first count elements of the list. /// public static Range1s GetBoundingRange(this List pointList, int count) { if (count <= 0) return Range1s.Invalid; var box = new Range1s(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding range for indexed arrays /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1s GetBoundingRange(this int[] indexArray, short[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.Length, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1s GetBoundingRange(this int[] indexArray, int count, short[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1s GetBoundingRange(this int[] indexArray, int start, int count, short[] pointArray) { if (count <= 0) return Range1s.Invalid; var box = new Range1s(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1s GetBoundingRange(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Range1s.Invalid; var box = new Range1s(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1s GetBoundingRange(this long[] indexArray, short[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1s GetBoundingRange(this long[] indexArray, long count, short[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1s GetBoundingRange(this long[] indexArray, long start, long count, short[] pointArray) { if (count <= 0) return Range1s.Invalid; var box = new Range1s(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1s GetBoundingRange(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Range1s.Invalid; var box = new Range1s(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding range for IEnumerable /// /// Returns the bounding range of the elements of the collection. /// public static Range1s GetBoundingRange(this IEnumerable points) { var box = Range1s.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion } #region Range extensions public static partial class RangeExtensions { /// /// Returns the int sequence 0 ... count-1. /// public static IEnumerable Range(this short count) { for (short i = 0; i < count; i++) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpTo(this short self, short upToInclusive) { return self.UpTo(upToInclusive, 1); } public static IEnumerable UpTo(this short self, short upToInclusive, short step) { for (short i = self; i <= upToInclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpToExclusive(this short self, short upToExclusive) { return self.UpToExclusive(upToExclusive, 1); } public static IEnumerable UpToExclusive(this short self, short upToExclusive, short step) { for (short i = self; i < upToExclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable DownTo(this short self, short downToInclusive) { return self.DownTo(downToInclusive, 1); } public static IEnumerable DownTo(this short self, short downToInclusive, short step) { for (short i = self; i >= downToInclusive; i -= step) yield return i; } } #endregion public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1s a, Range1s b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1s a, Range1s b, short tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Range1us [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Range1us : IEquatable, IRange, IFormattable { [DataMember] public ushort Min; [DataMember] public ushort Max; #region Constructors /// /// Construct a Range1us from a Range1b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(Range1b b) { Min = (ushort) b.Min; Max = (ushort) b.Max; } /// /// Construct a Range1us from a Range1sb. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(Range1sb b) { Min = (ushort) b.Min; Max = (ushort) b.Max; } /// /// Construct a Range1us from a Range1s. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(Range1s b) { Min = (ushort) b.Min; Max = (ushort) b.Max; } /// /// Construct a Range1us from a Range1i. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(Range1i b) { Min = (ushort) b.Min; Max = (ushort) b.Max; } /// /// Construct a Range1us from a Range1ui. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(Range1ui b) { Min = (ushort) b.Min; Max = (ushort) b.Max; } /// /// Construct a Range1us from a Range1l. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(Range1l b) { Min = (ushort) b.Min; Max = (ushort) b.Max; } /// /// Construct a Range1us from a Range1ul. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(Range1ul b) { Min = (ushort) b.Min; Max = (ushort) b.Max; } /// /// Construct a Range1us from a Range1f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(Range1f b) { Min = (ushort) b.Min; Max = (ushort) b.Max; } /// /// Construct a Range1us from a Range1d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(Range1d b) { Min = (ushort) b.Min; Max = (ushort) b.Max; } /// /// Creates a range from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(ushort min, ushort max) { Min = min; Max = max; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(ushort pnt) { Min = pnt; Max = pnt; } /// /// Creates a range from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(ushort p0, ushort p1, ushort p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a range from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(ushort p0, ushort p1, ushort p2, ushort p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(Range1us range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(Range1us b0, Range1us b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(Range1us b0, Range1us b1, Range1us b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(Range1us b0, Range1us b1, Range1us b2, Range1us b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates range as the bounding range of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(ushort[] values) { Min = ushort.MaxValue; Max = ushort.MinValue; if (values == null) return; long count = values.LongLength; for (long i = 0; i < count; i++) ExtendBy(values[i]); } /// /// Creates range as the bounding range of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(ushort[] values, long start, long count) { if (count <= 0) { Min = ushort.MaxValue; Max = ushort.MinValue; } else { Min = Max = values[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(values[i]); } } /// /// Creates range as the bounding range of given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us(IEnumerable values) { Min = ushort.MaxValue; Max = ushort.MinValue; if (values == null) return; foreach (ushort v in values) ExtendBy(v); } /// /// Returns new range [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1us FromMinAndSize(ushort min, ushort size) { return new Range1us(min, (ushort)(min + size)); } /// /// Returns new range [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1us FromCenterAndSize(ushort center, ushort size) { return new Range1us((ushort)(center - size / 2), (ushort)(center + size / 2)); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1us(Range1b b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1us(Range1sb b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1us(Range1s b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1us(Range1i b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1us(Range1ui b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1us(Range1l b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1us(Range1ul b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1us(Range1f b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1us(Range1d b) => new(b); #endregion #region Constants /// /// A range with crossed limits. /// public static Range1us Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(ushort.MaxValue, ushort.MinValue); } /// /// The largest possible range. /// public static Range1us Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(ushort.MinValue, ushort.MaxValue); } /// /// The unit interval [0, 1]. /// public static Range1us Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(0, 1); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min >= Max; } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min <= Max; } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min > Max; } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Calculates size of the range. /// [XmlIgnore] public ushort Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (ushort)(Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (ushort)(Min + value); } } public readonly ushort Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (ushort)((Min + Max) / 2); } } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (IsInvalid) yield break; //Todo: check should not be necessary for (var i = Min; i <= Max; i++) yield return i; } } #endregion #region Size Manipulations /// /// Return range enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1us EnlargedBy(ushort increment) { return new Range1us((ushort)(Min - increment), (ushort)(Max + increment)); } /// /// Return range enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1us EnlargedBy(ushort deltaMin, ushort deltaMax) { return new Range1us((ushort)(Min - deltaMin), (ushort)(Max + deltaMax)); } /// /// Return range shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1us ShrunkBy(ushort delta) { return new Range1us((ushort)(Min + delta), (ushort)(Max - delta)); } /// /// Return range shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1us ShrunkBy(ushort deltaMin, ushort deltaMax) { return new Range1us((ushort)(Min + deltaMin), (ushort)(Max - deltaMax)); } /// /// Enlarges range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(ushort delta) { Min -= delta; Max += delta; } /// /// Enlarges range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(ushort deltaMin, ushort deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(ushort delta) { Min += delta; Max -= delta; } /// /// Shrinks range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(ushort deltaMin, ushort deltaMax) { Min += deltaMin; Max -= deltaMax; } #endregion #region Box Arithmetics /// /// Return the value in the Range that is closest to the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly ushort Clamped(ushort x) { return x < Min ? Min : (x > Max ? Max : x); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly ushort Lerp(float t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly ushort Lerp(double t) => Fun.Lerp(t, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double InvLerp(ushort y) => Fun.InvLerp(y, Min, Max); /// /// Returns the range with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1us SplitRight(ushort splitValue) { if (splitValue > Max) return Range1us.Invalid; if (splitValue <= Min) return this; return new Range1us(splitValue, Max); } /// /// Returns the range with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1us SplitLeft(ushort splitValue) { if (splitValue < Min) return Range1us.Invalid; if (splitValue >= Max) return this; return new Range1us(Min, splitValue); } /// /// Returns the range extended to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1us ExtendedBy(Range1us range) { return new Range1us( range.Min < Min ? range.Min : Min, range.Max > Max ? range.Max : Max); } /// /// Returns the range extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1us ExtendedBy(ushort value) { return new Range1us( value < Min ? value : Min, value > Max ? value : Max); } /// /// Extends the range to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Range1us range) { if (range.Min < Min) Min = range.Min; if (range.Max > Max) Max = range.Max; } /// /// Extends the range to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(ushort value) { if (value < Min) Min = value; if (value > Max) Max = value; } /// /// Returns true if the range contains the given value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(ushort value) { return value >= Min && value <= Max; } /// /// Returns true if the range completely contains the given range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Range1us b) { return b.Min >= Min && b.Max <= Max; } /// /// Checks if 2 ranges intersect each other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1us range) { if (Min >= range.Max) return false; if (Max <= range.Min) return false; return true; } /// /// Checks if 2 ranges intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1us range, ushort eps) { if (Min - eps >= range.Max) return false; if (Max + eps <= range.Min) return false; return true; } /// /// Checks if the range is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1us Repair() { if (this.Equals(Range1us.Invalid)) return this; if (Min > Max) Fun.Swap(ref Min, ref Max); return this; } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Range1us a, Range1us b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Range1us a, Range1us b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a range shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1us operator +(Range1us box, ushort v) { return new Range1us((ushort)(box.Min + v), (ushort)(box.Max + v)); } /// /// Returns a range shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1us operator -(Range1us box, ushort v) { return new Range1us((ushort)(box.Min - v), (ushort)(box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Range1us other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Range1us o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Range1us box, int i, ushort value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Range1us Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Range1us(ushort.Parse(x[0], CultureInfo.InvariantCulture), ushort.Parse(x[1], CultureInfo.InvariantCulture)); } public static Range1us Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, Range1us.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { fp ??= CultureInfo.InvariantCulture; return begin + Min.ToString(format, fp) + between + Max.ToString(format, fp) + end; } #endregion } public static partial class Range { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1us Union(this Range1us a, Range1us b) { return new Range1us(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1us Intersection(this Range1us a, Range1us b) { return new Range1us(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } /// /// Checks if two ranges intersect each other with a tolerance parameter. /// // TODO: Implement for d > 2 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Range1us a, Range1us b, ushort eps, out Range1us result) { result = Range1us.Invalid; if (a.Min - eps > b.Max) return false; else if (a.Max + eps < b.Min) return false; else { result = new Range1us(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); if (result.Size < eps) { ushort center = result.Center; result.Min = (ushort)(center - eps); result.Max = (ushort)(center + eps); } return true; } } #endregion #region Bounding range for arrays /// /// Returns the bounding range of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1us GetBoundingRange(this ushort[] pointArray) { return pointArray.GetBoundingRange(0, pointArray.LongLength); } /// /// Returns the bounding range of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1us GetBoundingRange(this ushort[] pointArray, long count) { return pointArray.GetBoundingRange(0, count); } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1us GetBoundingRange( this ushort[] pointArray, long start, long count) { if (count <= 0) return Range1us.Invalid; var box = new Range1us(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1us GetBoundingRange(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Range1us.Invalid; var box = new Range1us(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding range for lists /// /// Returns the bounding range of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1us GetBoundingRange(this List pointList) { return pointList.GetBoundingRange(pointList.Count); } /// /// Returns the bounding range of the first count elements of the list. /// public static Range1us GetBoundingRange(this List pointList, int count) { if (count <= 0) return Range1us.Invalid; var box = new Range1us(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding range for indexed arrays /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1us GetBoundingRange(this int[] indexArray, ushort[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.Length, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1us GetBoundingRange(this int[] indexArray, int count, ushort[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1us GetBoundingRange(this int[] indexArray, int start, int count, ushort[] pointArray) { if (count <= 0) return Range1us.Invalid; var box = new Range1us(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1us GetBoundingRange(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Range1us.Invalid; var box = new Range1us(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1us GetBoundingRange(this long[] indexArray, ushort[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1us GetBoundingRange(this long[] indexArray, long count, ushort[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1us GetBoundingRange(this long[] indexArray, long start, long count, ushort[] pointArray) { if (count <= 0) return Range1us.Invalid; var box = new Range1us(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1us GetBoundingRange(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Range1us.Invalid; var box = new Range1us(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding range for IEnumerable /// /// Returns the bounding range of the elements of the collection. /// public static Range1us GetBoundingRange(this IEnumerable points) { var box = Range1us.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion } #region Range extensions public static partial class RangeExtensions { /// /// Returns the int sequence 0 ... count-1. /// public static IEnumerable Range(this ushort count) { for (ushort i = 0; i < count; i++) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpTo(this ushort self, ushort upToInclusive) { return self.UpTo(upToInclusive, 1); } public static IEnumerable UpTo(this ushort self, ushort upToInclusive, ushort step) { for (ushort i = self; i <= upToInclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpToExclusive(this ushort self, ushort upToExclusive) { return self.UpToExclusive(upToExclusive, 1); } public static IEnumerable UpToExclusive(this ushort self, ushort upToExclusive, ushort step) { for (ushort i = self; i < upToExclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable DownTo(this ushort self, ushort downToInclusive) { return self.DownTo(downToInclusive, 1); } public static IEnumerable DownTo(this ushort self, ushort downToInclusive, ushort step) { for (ushort i = self; i >= downToInclusive; i -= step) yield return i; } } #endregion public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1us a, Range1us b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1us a, Range1us b, ushort tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Range1i [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Range1i : IEquatable, IRange, IFormattable { [DataMember] public int Min; [DataMember] public int Max; #region Constructors /// /// Construct a Range1i from a Range1b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(Range1b b) { Min = (int) b.Min; Max = (int) b.Max; } /// /// Construct a Range1i from a Range1sb. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(Range1sb b) { Min = (int) b.Min; Max = (int) b.Max; } /// /// Construct a Range1i from a Range1s. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(Range1s b) { Min = (int) b.Min; Max = (int) b.Max; } /// /// Construct a Range1i from a Range1us. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(Range1us b) { Min = (int) b.Min; Max = (int) b.Max; } /// /// Construct a Range1i from a Range1ui. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(Range1ui b) { Min = (int) b.Min; Max = (int) b.Max; } /// /// Construct a Range1i from a Range1l. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(Range1l b) { Min = (int) b.Min; Max = (int) b.Max; } /// /// Construct a Range1i from a Range1ul. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(Range1ul b) { Min = (int) b.Min; Max = (int) b.Max; } /// /// Construct a Range1i from a Range1f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(Range1f b) { Min = (int) b.Min; Max = (int) b.Max; } /// /// Construct a Range1i from a Range1d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(Range1d b) { Min = (int) b.Min; Max = (int) b.Max; } /// /// Construct a Range1i from a V2i. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(V2i v) { Min = v.X; Max = v.Y; } /// /// Creates a range from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(int min, int max) { Min = min; Max = max; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(int pnt) { Min = pnt; Max = pnt; } /// /// Creates a range from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(int p0, int p1, int p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a range from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(int p0, int p1, int p2, int p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(Range1i range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(Range1i b0, Range1i b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(Range1i b0, Range1i b1, Range1i b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(Range1i b0, Range1i b1, Range1i b2, Range1i b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates range as the bounding range of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(int[] values) { Min = int.MaxValue; Max = int.MinValue; if (values == null) return; long count = values.LongLength; for (long i = 0; i < count; i++) ExtendBy(values[i]); } /// /// Creates range as the bounding range of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(int[] values, long start, long count) { if (count <= 0) { Min = int.MaxValue; Max = int.MinValue; } else { Min = Max = values[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(values[i]); } } /// /// Creates range as the bounding range of given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i(IEnumerable values) { Min = int.MaxValue; Max = int.MinValue; if (values == null) return; foreach (int v in values) ExtendBy(v); } /// /// Returns new range [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1i FromMinAndSize(int min, int size) { return new Range1i(min, (min + size)); } /// /// Returns new range [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1i FromCenterAndSize(int center, int size) { return new Range1i((center - size / 2), (center + size / 2)); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1i(Range1b b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1i(Range1sb b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1i(Range1s b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1i(Range1us b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1i(Range1ui b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1i(Range1l b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1i(Range1ul b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1i(Range1f b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1i(Range1d b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1i(V2i v) => new(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(Range1i r) => new(r.Min, r.Max); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToV2i() => (V2i)this; #endregion #region Constants /// /// A range with crossed limits. /// public static Range1i Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(int.MaxValue, int.MinValue); } /// /// The largest possible range. /// public static Range1i Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(int.MinValue, int.MaxValue); } /// /// The unit interval [0, 1]. /// public static Range1i Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(0, 1); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min >= Max; } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min <= Max; } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min > Max; } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Calculates size of the range. /// [XmlIgnore] public int Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (Min + value); } } public readonly int Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return ((Min + Max) / 2); } } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (IsInvalid) yield break; //Todo: check should not be necessary for (var i = Min; i <= Max; i++) yield return i; } } #endregion #region Size Manipulations /// /// Return range enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1i EnlargedBy(int increment) { return new Range1i((Min - increment), (Max + increment)); } /// /// Return range enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1i EnlargedBy(int deltaMin, int deltaMax) { return new Range1i((Min - deltaMin), (Max + deltaMax)); } /// /// Return range shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1i ShrunkBy(int delta) { return new Range1i((Min + delta), (Max - delta)); } /// /// Return range shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1i ShrunkBy(int deltaMin, int deltaMax) { return new Range1i((Min + deltaMin), (Max - deltaMax)); } /// /// Enlarges range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(int delta) { Min -= delta; Max += delta; } /// /// Enlarges range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(int deltaMin, int deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(int delta) { Min += delta; Max -= delta; } /// /// Shrinks range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(int deltaMin, int deltaMax) { Min += deltaMin; Max -= deltaMax; } #endregion #region Box Arithmetics /// /// Return the value in the Range that is closest to the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int Clamped(int x) { return x < Min ? Min : (x > Max ? Max : x); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int Lerp(float t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int Lerp(double t) => Fun.Lerp(t, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double InvLerp(int y) => Fun.InvLerp(y, Min, Max); /// /// Returns the range with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1i SplitRight(int splitValue) { if (splitValue > Max) return Range1i.Invalid; if (splitValue <= Min) return this; return new Range1i(splitValue, Max); } /// /// Returns the range with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1i SplitLeft(int splitValue) { if (splitValue < Min) return Range1i.Invalid; if (splitValue >= Max) return this; return new Range1i(Min, splitValue); } /// /// Returns the range extended to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1i ExtendedBy(Range1i range) { return new Range1i( range.Min < Min ? range.Min : Min, range.Max > Max ? range.Max : Max); } /// /// Returns the range extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1i ExtendedBy(int value) { return new Range1i( value < Min ? value : Min, value > Max ? value : Max); } /// /// Extends the range to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Range1i range) { if (range.Min < Min) Min = range.Min; if (range.Max > Max) Max = range.Max; } /// /// Extends the range to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(int value) { if (value < Min) Min = value; if (value > Max) Max = value; } /// /// Returns true if the range contains the given value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(int value) { return value >= Min && value <= Max; } /// /// Returns true if the range completely contains the given range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Range1i b) { return b.Min >= Min && b.Max <= Max; } /// /// Checks if 2 ranges intersect each other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1i range) { if (Min >= range.Max) return false; if (Max <= range.Min) return false; return true; } /// /// Checks if 2 ranges intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1i range, int eps) { if (Min - eps >= range.Max) return false; if (Max + eps <= range.Min) return false; return true; } /// /// Checks if the range is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1i Repair() { if (this.Equals(Range1i.Invalid)) return this; if (Min > Max) Fun.Swap(ref Min, ref Max); return this; } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Range1i a, Range1i b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Range1i a, Range1i b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a range shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1i operator +(Range1i box, int v) { return new Range1i((box.Min + v), (box.Max + v)); } /// /// Returns a range shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1i operator -(Range1i box, int v) { return new Range1i((box.Min - v), (box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Range1i other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Range1i o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Range1i box, int i, int value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Range1i Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Range1i(int.Parse(x[0], CultureInfo.InvariantCulture), int.Parse(x[1], CultureInfo.InvariantCulture)); } public static Range1i Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, Range1i.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { fp ??= CultureInfo.InvariantCulture; return begin + Min.ToString(format, fp) + between + Max.ToString(format, fp) + end; } #endregion } public static partial class Range { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1i Union(this Range1i a, Range1i b) { return new Range1i(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1i Intersection(this Range1i a, Range1i b) { return new Range1i(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } /// /// Checks if two ranges intersect each other with a tolerance parameter. /// // TODO: Implement for d > 2 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Range1i a, Range1i b, int eps, out Range1i result) { result = Range1i.Invalid; if (a.Min - eps > b.Max) return false; else if (a.Max + eps < b.Min) return false; else { result = new Range1i(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); if (result.Size < eps) { int center = result.Center; result.Min = (center - eps); result.Max = (center + eps); } return true; } } #endregion #region Bounding range for arrays /// /// Returns the bounding range of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1i GetBoundingRange(this int[] pointArray) { return pointArray.GetBoundingRange(0, pointArray.LongLength); } /// /// Returns the bounding range of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1i GetBoundingRange(this int[] pointArray, long count) { return pointArray.GetBoundingRange(0, count); } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1i GetBoundingRange( this int[] pointArray, long start, long count) { if (count <= 0) return Range1i.Invalid; var box = new Range1i(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1i GetBoundingRange(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Range1i.Invalid; var box = new Range1i(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding range for lists /// /// Returns the bounding range of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1i GetBoundingRange(this List pointList) { return pointList.GetBoundingRange(pointList.Count); } /// /// Returns the bounding range of the first count elements of the list. /// public static Range1i GetBoundingRange(this List pointList, int count) { if (count <= 0) return Range1i.Invalid; var box = new Range1i(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding range for indexed arrays /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1i GetBoundingRange(this int[] indexArray, int[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.Length, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1i GetBoundingRange(this int[] indexArray, int count, int[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1i GetBoundingRange(this int[] indexArray, int start, int count, int[] pointArray) { if (count <= 0) return Range1i.Invalid; var box = new Range1i(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1i GetBoundingRange(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Range1i.Invalid; var box = new Range1i(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1i GetBoundingRange(this long[] indexArray, int[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1i GetBoundingRange(this long[] indexArray, long count, int[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1i GetBoundingRange(this long[] indexArray, long start, long count, int[] pointArray) { if (count <= 0) return Range1i.Invalid; var box = new Range1i(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1i GetBoundingRange(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Range1i.Invalid; var box = new Range1i(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding range for IEnumerable /// /// Returns the bounding range of the elements of the collection. /// public static Range1i GetBoundingRange(this IEnumerable points) { var box = Range1i.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion } #region Range extensions public static partial class RangeExtensions { /// /// Returns the int sequence 0 ... count-1. /// public static IEnumerable Range(this int count) { for (int i = 0; i < count; i++) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpTo(this int self, int upToInclusive) { return self.UpTo(upToInclusive, 1); } public static IEnumerable UpTo(this int self, int upToInclusive, int step) { for (int i = self; i <= upToInclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpToExclusive(this int self, int upToExclusive) { return self.UpToExclusive(upToExclusive, 1); } public static IEnumerable UpToExclusive(this int self, int upToExclusive, int step) { for (int i = self; i < upToExclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable DownTo(this int self, int downToInclusive) { return self.DownTo(downToInclusive, 1); } public static IEnumerable DownTo(this int self, int downToInclusive, int step) { for (int i = self; i >= downToInclusive; i -= step) yield return i; } } #endregion public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1i a, Range1i b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1i a, Range1i b, int tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Range1ui [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Range1ui : IEquatable, IRange, IFormattable { [DataMember] public uint Min; [DataMember] public uint Max; #region Constructors /// /// Construct a Range1ui from a Range1b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(Range1b b) { Min = (uint) b.Min; Max = (uint) b.Max; } /// /// Construct a Range1ui from a Range1sb. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(Range1sb b) { Min = (uint) b.Min; Max = (uint) b.Max; } /// /// Construct a Range1ui from a Range1s. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(Range1s b) { Min = (uint) b.Min; Max = (uint) b.Max; } /// /// Construct a Range1ui from a Range1us. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(Range1us b) { Min = (uint) b.Min; Max = (uint) b.Max; } /// /// Construct a Range1ui from a Range1i. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(Range1i b) { Min = (uint) b.Min; Max = (uint) b.Max; } /// /// Construct a Range1ui from a Range1l. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(Range1l b) { Min = (uint) b.Min; Max = (uint) b.Max; } /// /// Construct a Range1ui from a Range1ul. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(Range1ul b) { Min = (uint) b.Min; Max = (uint) b.Max; } /// /// Construct a Range1ui from a Range1f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(Range1f b) { Min = (uint) b.Min; Max = (uint) b.Max; } /// /// Construct a Range1ui from a Range1d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(Range1d b) { Min = (uint) b.Min; Max = (uint) b.Max; } /// /// Construct a Range1ui from a V2ui. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(V2ui v) { Min = v.X; Max = v.Y; } /// /// Creates a range from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(uint min, uint max) { Min = min; Max = max; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(uint pnt) { Min = pnt; Max = pnt; } /// /// Creates a range from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(uint p0, uint p1, uint p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a range from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(uint p0, uint p1, uint p2, uint p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(Range1ui range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(Range1ui b0, Range1ui b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(Range1ui b0, Range1ui b1, Range1ui b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(Range1ui b0, Range1ui b1, Range1ui b2, Range1ui b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates range as the bounding range of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(uint[] values) { Min = uint.MaxValue; Max = uint.MinValue; if (values == null) return; long count = values.LongLength; for (long i = 0; i < count; i++) ExtendBy(values[i]); } /// /// Creates range as the bounding range of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(uint[] values, long start, long count) { if (count <= 0) { Min = uint.MaxValue; Max = uint.MinValue; } else { Min = Max = values[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(values[i]); } } /// /// Creates range as the bounding range of given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui(IEnumerable values) { Min = uint.MaxValue; Max = uint.MinValue; if (values == null) return; foreach (uint v in values) ExtendBy(v); } /// /// Returns new range [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ui FromMinAndSize(uint min, uint size) { return new Range1ui(min, (uint)(min + size)); } /// /// Returns new range [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ui FromCenterAndSize(uint center, uint size) { return new Range1ui((uint)(center - size / 2), (uint)(center + size / 2)); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ui(Range1b b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ui(Range1sb b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ui(Range1s b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ui(Range1us b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ui(Range1i b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ui(Range1l b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ui(Range1ul b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ui(Range1f b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ui(Range1d b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ui(V2ui v) => new(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(Range1ui r) => new(r.Min, r.Max); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui ToV2ui() => (V2ui)this; #endregion #region Constants /// /// A range with crossed limits. /// public static Range1ui Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(uint.MaxValue, uint.MinValue); } /// /// The largest possible range. /// public static Range1ui Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(uint.MinValue, uint.MaxValue); } /// /// The unit interval [0, 1]. /// public static Range1ui Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(0, 1); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min >= Max; } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min <= Max; } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min > Max; } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Calculates size of the range. /// [XmlIgnore] public uint Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (uint)(Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (uint)(Min + value); } } public readonly uint Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (uint)((Min + Max) / 2); } } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (IsInvalid) yield break; //Todo: check should not be necessary for (var i = Min; i <= Max; i++) yield return i; } } #endregion #region Size Manipulations /// /// Return range enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1ui EnlargedBy(uint increment) { return new Range1ui((uint)(Min - increment), (uint)(Max + increment)); } /// /// Return range enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1ui EnlargedBy(uint deltaMin, uint deltaMax) { return new Range1ui((uint)(Min - deltaMin), (uint)(Max + deltaMax)); } /// /// Return range shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1ui ShrunkBy(uint delta) { return new Range1ui((uint)(Min + delta), (uint)(Max - delta)); } /// /// Return range shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1ui ShrunkBy(uint deltaMin, uint deltaMax) { return new Range1ui((uint)(Min + deltaMin), (uint)(Max - deltaMax)); } /// /// Enlarges range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(uint delta) { Min -= delta; Max += delta; } /// /// Enlarges range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(uint deltaMin, uint deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(uint delta) { Min += delta; Max -= delta; } /// /// Shrinks range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(uint deltaMin, uint deltaMax) { Min += deltaMin; Max -= deltaMax; } #endregion #region Box Arithmetics /// /// Return the value in the Range that is closest to the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly uint Clamped(uint x) { return x < Min ? Min : (x > Max ? Max : x); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly uint Lerp(float t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly uint Lerp(double t) => Fun.Lerp(t, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double InvLerp(uint y) => Fun.InvLerp(y, Min, Max); /// /// Returns the range with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1ui SplitRight(uint splitValue) { if (splitValue > Max) return Range1ui.Invalid; if (splitValue <= Min) return this; return new Range1ui(splitValue, Max); } /// /// Returns the range with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1ui SplitLeft(uint splitValue) { if (splitValue < Min) return Range1ui.Invalid; if (splitValue >= Max) return this; return new Range1ui(Min, splitValue); } /// /// Returns the range extended to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1ui ExtendedBy(Range1ui range) { return new Range1ui( range.Min < Min ? range.Min : Min, range.Max > Max ? range.Max : Max); } /// /// Returns the range extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1ui ExtendedBy(uint value) { return new Range1ui( value < Min ? value : Min, value > Max ? value : Max); } /// /// Extends the range to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Range1ui range) { if (range.Min < Min) Min = range.Min; if (range.Max > Max) Max = range.Max; } /// /// Extends the range to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(uint value) { if (value < Min) Min = value; if (value > Max) Max = value; } /// /// Returns true if the range contains the given value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(uint value) { return value >= Min && value <= Max; } /// /// Returns true if the range completely contains the given range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Range1ui b) { return b.Min >= Min && b.Max <= Max; } /// /// Checks if 2 ranges intersect each other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1ui range) { if (Min >= range.Max) return false; if (Max <= range.Min) return false; return true; } /// /// Checks if 2 ranges intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1ui range, uint eps) { if (Min - eps >= range.Max) return false; if (Max + eps <= range.Min) return false; return true; } /// /// Checks if the range is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ui Repair() { if (this.Equals(Range1ui.Invalid)) return this; if (Min > Max) Fun.Swap(ref Min, ref Max); return this; } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Range1ui a, Range1ui b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Range1ui a, Range1ui b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a range shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ui operator +(Range1ui box, uint v) { return new Range1ui((uint)(box.Min + v), (uint)(box.Max + v)); } /// /// Returns a range shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ui operator -(Range1ui box, uint v) { return new Range1ui((uint)(box.Min - v), (uint)(box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Range1ui other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Range1ui o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Range1ui box, int i, uint value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Range1ui Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Range1ui(uint.Parse(x[0], CultureInfo.InvariantCulture), uint.Parse(x[1], CultureInfo.InvariantCulture)); } public static Range1ui Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, Range1ui.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { fp ??= CultureInfo.InvariantCulture; return begin + Min.ToString(format, fp) + between + Max.ToString(format, fp) + end; } #endregion } public static partial class Range { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ui Union(this Range1ui a, Range1ui b) { return new Range1ui(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ui Intersection(this Range1ui a, Range1ui b) { return new Range1ui(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } /// /// Checks if two ranges intersect each other with a tolerance parameter. /// // TODO: Implement for d > 2 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Range1ui a, Range1ui b, uint eps, out Range1ui result) { result = Range1ui.Invalid; if (a.Min - eps > b.Max) return false; else if (a.Max + eps < b.Min) return false; else { result = new Range1ui(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); if (result.Size < eps) { uint center = result.Center; result.Min = (uint)(center - eps); result.Max = (uint)(center + eps); } return true; } } #endregion #region Bounding range for arrays /// /// Returns the bounding range of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ui GetBoundingRange(this uint[] pointArray) { return pointArray.GetBoundingRange(0, pointArray.LongLength); } /// /// Returns the bounding range of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ui GetBoundingRange(this uint[] pointArray, long count) { return pointArray.GetBoundingRange(0, count); } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1ui GetBoundingRange( this uint[] pointArray, long start, long count) { if (count <= 0) return Range1ui.Invalid; var box = new Range1ui(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1ui GetBoundingRange(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Range1ui.Invalid; var box = new Range1ui(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding range for lists /// /// Returns the bounding range of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ui GetBoundingRange(this List pointList) { return pointList.GetBoundingRange(pointList.Count); } /// /// Returns the bounding range of the first count elements of the list. /// public static Range1ui GetBoundingRange(this List pointList, int count) { if (count <= 0) return Range1ui.Invalid; var box = new Range1ui(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding range for indexed arrays /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ui GetBoundingRange(this int[] indexArray, uint[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.Length, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ui GetBoundingRange(this int[] indexArray, int count, uint[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1ui GetBoundingRange(this int[] indexArray, int start, int count, uint[] pointArray) { if (count <= 0) return Range1ui.Invalid; var box = new Range1ui(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1ui GetBoundingRange(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Range1ui.Invalid; var box = new Range1ui(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ui GetBoundingRange(this long[] indexArray, uint[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ui GetBoundingRange(this long[] indexArray, long count, uint[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1ui GetBoundingRange(this long[] indexArray, long start, long count, uint[] pointArray) { if (count <= 0) return Range1ui.Invalid; var box = new Range1ui(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1ui GetBoundingRange(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Range1ui.Invalid; var box = new Range1ui(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding range for IEnumerable /// /// Returns the bounding range of the elements of the collection. /// public static Range1ui GetBoundingRange(this IEnumerable points) { var box = Range1ui.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion } #region Range extensions public static partial class RangeExtensions { /// /// Returns the int sequence 0 ... count-1. /// public static IEnumerable Range(this uint count) { for (uint i = 0; i < count; i++) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpTo(this uint self, uint upToInclusive) { return self.UpTo(upToInclusive, 1); } public static IEnumerable UpTo(this uint self, uint upToInclusive, uint step) { for (uint i = self; i <= upToInclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpToExclusive(this uint self, uint upToExclusive) { return self.UpToExclusive(upToExclusive, 1); } public static IEnumerable UpToExclusive(this uint self, uint upToExclusive, uint step) { for (uint i = self; i < upToExclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable DownTo(this uint self, uint downToInclusive) { return self.DownTo(downToInclusive, 1); } public static IEnumerable DownTo(this uint self, uint downToInclusive, uint step) { for (uint i = self; i >= downToInclusive; i -= step) yield return i; } } #endregion public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1ui a, Range1ui b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1ui a, Range1ui b, uint tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Range1l [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Range1l : IEquatable, IRange, IFormattable { [DataMember] public long Min; [DataMember] public long Max; #region Constructors /// /// Construct a Range1l from a Range1b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(Range1b b) { Min = (long) b.Min; Max = (long) b.Max; } /// /// Construct a Range1l from a Range1sb. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(Range1sb b) { Min = (long) b.Min; Max = (long) b.Max; } /// /// Construct a Range1l from a Range1s. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(Range1s b) { Min = (long) b.Min; Max = (long) b.Max; } /// /// Construct a Range1l from a Range1us. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(Range1us b) { Min = (long) b.Min; Max = (long) b.Max; } /// /// Construct a Range1l from a Range1i. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(Range1i b) { Min = (long) b.Min; Max = (long) b.Max; } /// /// Construct a Range1l from a Range1ui. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(Range1ui b) { Min = (long) b.Min; Max = (long) b.Max; } /// /// Construct a Range1l from a Range1ul. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(Range1ul b) { Min = (long) b.Min; Max = (long) b.Max; } /// /// Construct a Range1l from a Range1f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(Range1f b) { Min = (long) b.Min; Max = (long) b.Max; } /// /// Construct a Range1l from a Range1d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(Range1d b) { Min = (long) b.Min; Max = (long) b.Max; } /// /// Construct a Range1l from a V2l. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(V2l v) { Min = v.X; Max = v.Y; } /// /// Creates a range from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(long min, long max) { Min = min; Max = max; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(long pnt) { Min = pnt; Max = pnt; } /// /// Creates a range from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(long p0, long p1, long p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a range from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(long p0, long p1, long p2, long p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(Range1l range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(Range1l b0, Range1l b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(Range1l b0, Range1l b1, Range1l b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(Range1l b0, Range1l b1, Range1l b2, Range1l b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates range as the bounding range of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(long[] values) { Min = long.MaxValue; Max = long.MinValue; if (values == null) return; long count = values.LongLength; for (long i = 0; i < count; i++) ExtendBy(values[i]); } /// /// Creates range as the bounding range of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(long[] values, long start, long count) { if (count <= 0) { Min = long.MaxValue; Max = long.MinValue; } else { Min = Max = values[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(values[i]); } } /// /// Creates range as the bounding range of given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l(IEnumerable values) { Min = long.MaxValue; Max = long.MinValue; if (values == null) return; foreach (long v in values) ExtendBy(v); } /// /// Returns new range [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1l FromMinAndSize(long min, long size) { return new Range1l(min, (long)(min + size)); } /// /// Returns new range [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1l FromCenterAndSize(long center, long size) { return new Range1l((long)(center - size / 2), (long)(center + size / 2)); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1l(Range1b b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1l(Range1sb b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1l(Range1s b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1l(Range1us b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1l(Range1i b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1l(Range1ui b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1l(Range1ul b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1l(Range1f b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1l(Range1d b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1l(V2l v) => new(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(Range1l r) => new(r.Min, r.Max); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToV2l() => (V2l)this; #endregion #region Constants /// /// A range with crossed limits. /// public static Range1l Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(long.MaxValue, long.MinValue); } /// /// The largest possible range. /// public static Range1l Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(long.MinValue, long.MaxValue); } /// /// The unit interval [0, 1]. /// public static Range1l Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(0, 1); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min >= Max; } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min <= Max; } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min > Max; } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Calculates size of the range. /// [XmlIgnore] public long Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (long)(Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (long)(Min + value); } } public readonly long Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (long)((Min + Max) / 2); } } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (IsInvalid) yield break; //Todo: check should not be necessary for (var i = Min; i <= Max; i++) yield return i; } } #endregion #region Size Manipulations /// /// Return range enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1l EnlargedBy(long increment) { return new Range1l((long)(Min - increment), (long)(Max + increment)); } /// /// Return range enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1l EnlargedBy(long deltaMin, long deltaMax) { return new Range1l((long)(Min - deltaMin), (long)(Max + deltaMax)); } /// /// Return range shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1l ShrunkBy(long delta) { return new Range1l((long)(Min + delta), (long)(Max - delta)); } /// /// Return range shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1l ShrunkBy(long deltaMin, long deltaMax) { return new Range1l((long)(Min + deltaMin), (long)(Max - deltaMax)); } /// /// Enlarges range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(long delta) { Min -= delta; Max += delta; } /// /// Enlarges range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(long deltaMin, long deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(long delta) { Min += delta; Max -= delta; } /// /// Shrinks range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(long deltaMin, long deltaMax) { Min += deltaMin; Max -= deltaMax; } #endregion #region Box Arithmetics /// /// Return the value in the Range that is closest to the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly long Clamped(long x) { return x < Min ? Min : (x > Max ? Max : x); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly long Lerp(float t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly long Lerp(double t) => Fun.Lerp(t, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double InvLerp(long y) => Fun.InvLerp(y, Min, Max); /// /// Returns the range with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1l SplitRight(long splitValue) { if (splitValue > Max) return Range1l.Invalid; if (splitValue <= Min) return this; return new Range1l(splitValue, Max); } /// /// Returns the range with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1l SplitLeft(long splitValue) { if (splitValue < Min) return Range1l.Invalid; if (splitValue >= Max) return this; return new Range1l(Min, splitValue); } /// /// Returns the range extended to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1l ExtendedBy(Range1l range) { return new Range1l( range.Min < Min ? range.Min : Min, range.Max > Max ? range.Max : Max); } /// /// Returns the range extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1l ExtendedBy(long value) { return new Range1l( value < Min ? value : Min, value > Max ? value : Max); } /// /// Extends the range to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Range1l range) { if (range.Min < Min) Min = range.Min; if (range.Max > Max) Max = range.Max; } /// /// Extends the range to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(long value) { if (value < Min) Min = value; if (value > Max) Max = value; } /// /// Returns true if the range contains the given value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(long value) { return value >= Min && value <= Max; } /// /// Returns true if the range completely contains the given range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Range1l b) { return b.Min >= Min && b.Max <= Max; } /// /// Checks if 2 ranges intersect each other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1l range) { if (Min >= range.Max) return false; if (Max <= range.Min) return false; return true; } /// /// Checks if 2 ranges intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1l range, long eps) { if (Min - eps >= range.Max) return false; if (Max + eps <= range.Min) return false; return true; } /// /// Checks if the range is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1l Repair() { if (this.Equals(Range1l.Invalid)) return this; if (Min > Max) Fun.Swap(ref Min, ref Max); return this; } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Range1l a, Range1l b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Range1l a, Range1l b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a range shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1l operator +(Range1l box, long v) { return new Range1l((long)(box.Min + v), (long)(box.Max + v)); } /// /// Returns a range shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1l operator -(Range1l box, long v) { return new Range1l((long)(box.Min - v), (long)(box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Range1l other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Range1l o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Range1l box, int i, long value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Range1l Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Range1l(long.Parse(x[0], CultureInfo.InvariantCulture), long.Parse(x[1], CultureInfo.InvariantCulture)); } public static Range1l Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, Range1l.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { fp ??= CultureInfo.InvariantCulture; return begin + Min.ToString(format, fp) + between + Max.ToString(format, fp) + end; } #endregion } public static partial class Range { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1l Union(this Range1l a, Range1l b) { return new Range1l(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1l Intersection(this Range1l a, Range1l b) { return new Range1l(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } /// /// Checks if two ranges intersect each other with a tolerance parameter. /// // TODO: Implement for d > 2 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Range1l a, Range1l b, long eps, out Range1l result) { result = Range1l.Invalid; if (a.Min - eps > b.Max) return false; else if (a.Max + eps < b.Min) return false; else { result = new Range1l(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); if (result.Size < eps) { long center = result.Center; result.Min = (long)(center - eps); result.Max = (long)(center + eps); } return true; } } #endregion #region Bounding range for arrays /// /// Returns the bounding range of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1l GetBoundingRange(this long[] pointArray) { return pointArray.GetBoundingRange(0, pointArray.LongLength); } /// /// Returns the bounding range of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1l GetBoundingRange(this long[] pointArray, long count) { return pointArray.GetBoundingRange(0, count); } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1l GetBoundingRange( this long[] pointArray, long start, long count) { if (count <= 0) return Range1l.Invalid; var box = new Range1l(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1l GetBoundingRange(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Range1l.Invalid; var box = new Range1l(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding range for lists /// /// Returns the bounding range of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1l GetBoundingRange(this List pointList) { return pointList.GetBoundingRange(pointList.Count); } /// /// Returns the bounding range of the first count elements of the list. /// public static Range1l GetBoundingRange(this List pointList, int count) { if (count <= 0) return Range1l.Invalid; var box = new Range1l(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding range for indexed arrays /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1l GetBoundingRange(this int[] indexArray, long[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.Length, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1l GetBoundingRange(this int[] indexArray, int count, long[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1l GetBoundingRange(this int[] indexArray, int start, int count, long[] pointArray) { if (count <= 0) return Range1l.Invalid; var box = new Range1l(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1l GetBoundingRange(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Range1l.Invalid; var box = new Range1l(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1l GetBoundingRange(this long[] indexArray, long[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1l GetBoundingRange(this long[] indexArray, long count, long[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1l GetBoundingRange(this long[] indexArray, long start, long count, long[] pointArray) { if (count <= 0) return Range1l.Invalid; var box = new Range1l(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1l GetBoundingRange(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Range1l.Invalid; var box = new Range1l(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding range for IEnumerable /// /// Returns the bounding range of the elements of the collection. /// public static Range1l GetBoundingRange(this IEnumerable points) { var box = Range1l.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion } #region Range extensions public static partial class RangeExtensions { /// /// Returns the int sequence 0 ... count-1. /// public static IEnumerable Range(this long count) { for (long i = 0; i < count; i++) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpTo(this long self, long upToInclusive) { return self.UpTo(upToInclusive, 1); } public static IEnumerable UpTo(this long self, long upToInclusive, long step) { for (long i = self; i <= upToInclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpToExclusive(this long self, long upToExclusive) { return self.UpToExclusive(upToExclusive, 1); } public static IEnumerable UpToExclusive(this long self, long upToExclusive, long step) { for (long i = self; i < upToExclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable DownTo(this long self, long downToInclusive) { return self.DownTo(downToInclusive, 1); } public static IEnumerable DownTo(this long self, long downToInclusive, long step) { for (long i = self; i >= downToInclusive; i -= step) yield return i; } } #endregion public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1l a, Range1l b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1l a, Range1l b, long tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Range1ul [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Range1ul : IEquatable, IRange, IFormattable { [DataMember] public ulong Min; [DataMember] public ulong Max; #region Constructors /// /// Construct a Range1ul from a Range1b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(Range1b b) { Min = (ulong) b.Min; Max = (ulong) b.Max; } /// /// Construct a Range1ul from a Range1sb. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(Range1sb b) { Min = (ulong) b.Min; Max = (ulong) b.Max; } /// /// Construct a Range1ul from a Range1s. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(Range1s b) { Min = (ulong) b.Min; Max = (ulong) b.Max; } /// /// Construct a Range1ul from a Range1us. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(Range1us b) { Min = (ulong) b.Min; Max = (ulong) b.Max; } /// /// Construct a Range1ul from a Range1i. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(Range1i b) { Min = (ulong) b.Min; Max = (ulong) b.Max; } /// /// Construct a Range1ul from a Range1ui. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(Range1ui b) { Min = (ulong) b.Min; Max = (ulong) b.Max; } /// /// Construct a Range1ul from a Range1l. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(Range1l b) { Min = (ulong) b.Min; Max = (ulong) b.Max; } /// /// Construct a Range1ul from a Range1f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(Range1f b) { Min = (ulong) b.Min; Max = (ulong) b.Max; } /// /// Construct a Range1ul from a Range1d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(Range1d b) { Min = (ulong) b.Min; Max = (ulong) b.Max; } /// /// Creates a range from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(ulong min, ulong max) { Min = min; Max = max; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(ulong pnt) { Min = pnt; Max = pnt; } /// /// Creates a range from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(ulong p0, ulong p1, ulong p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a range from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(ulong p0, ulong p1, ulong p2, ulong p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(Range1ul range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(Range1ul b0, Range1ul b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(Range1ul b0, Range1ul b1, Range1ul b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(Range1ul b0, Range1ul b1, Range1ul b2, Range1ul b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates range as the bounding range of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(ulong[] values) { Min = ulong.MaxValue; Max = ulong.MinValue; if (values == null) return; long count = values.LongLength; for (long i = 0; i < count; i++) ExtendBy(values[i]); } /// /// Creates range as the bounding range of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(ulong[] values, long start, long count) { if (count <= 0) { Min = ulong.MaxValue; Max = ulong.MinValue; } else { Min = Max = values[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(values[i]); } } /// /// Creates range as the bounding range of given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul(IEnumerable values) { Min = ulong.MaxValue; Max = ulong.MinValue; if (values == null) return; foreach (ulong v in values) ExtendBy(v); } /// /// Returns new range [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ul FromMinAndSize(ulong min, ulong size) { return new Range1ul(min, (ulong)(min + size)); } /// /// Returns new range [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ul FromCenterAndSize(ulong center, ulong size) { return new Range1ul((ulong)(center - size / 2), (ulong)(center + size / 2)); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ul(Range1b b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ul(Range1sb b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ul(Range1s b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ul(Range1us b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ul(Range1i b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ul(Range1ui b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ul(Range1l b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ul(Range1f b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1ul(Range1d b) => new(b); #endregion #region Constants /// /// A range with crossed limits. /// public static Range1ul Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(ulong.MaxValue, ulong.MinValue); } /// /// The largest possible range. /// public static Range1ul Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(ulong.MinValue, ulong.MaxValue); } /// /// The unit interval [0, 1]. /// public static Range1ul Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(0, 1); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min >= Max; } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min <= Max; } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min > Max; } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Calculates size of the range. /// [XmlIgnore] public ulong Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (ulong)(Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (ulong)(Min + value); } } public readonly ulong Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (ulong)((Min + Max) / 2); } } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (IsInvalid) yield break; //Todo: check should not be necessary for (var i = Min; i <= Max; i++) yield return i; } } #endregion #region Size Manipulations /// /// Return range enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1ul EnlargedBy(ulong increment) { return new Range1ul((ulong)(Min - increment), (ulong)(Max + increment)); } /// /// Return range enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1ul EnlargedBy(ulong deltaMin, ulong deltaMax) { return new Range1ul((ulong)(Min - deltaMin), (ulong)(Max + deltaMax)); } /// /// Return range shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1ul ShrunkBy(ulong delta) { return new Range1ul((ulong)(Min + delta), (ulong)(Max - delta)); } /// /// Return range shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1ul ShrunkBy(ulong deltaMin, ulong deltaMax) { return new Range1ul((ulong)(Min + deltaMin), (ulong)(Max - deltaMax)); } /// /// Enlarges range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(ulong delta) { Min -= delta; Max += delta; } /// /// Enlarges range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(ulong deltaMin, ulong deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(ulong delta) { Min += delta; Max -= delta; } /// /// Shrinks range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(ulong deltaMin, ulong deltaMax) { Min += deltaMin; Max -= deltaMax; } #endregion #region Box Arithmetics /// /// Return the value in the Range that is closest to the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly ulong Clamped(ulong x) { return x < Min ? Min : (x > Max ? Max : x); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly ulong Lerp(float t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly ulong Lerp(double t) => Fun.Lerp(t, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double InvLerp(ulong y) => Fun.InvLerp(y, Min, Max); /// /// Returns the range with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1ul SplitRight(ulong splitValue) { if (splitValue > Max) return Range1ul.Invalid; if (splitValue <= Min) return this; return new Range1ul(splitValue, Max); } /// /// Returns the range with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1ul SplitLeft(ulong splitValue) { if (splitValue < Min) return Range1ul.Invalid; if (splitValue >= Max) return this; return new Range1ul(Min, splitValue); } /// /// Returns the range extended to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1ul ExtendedBy(Range1ul range) { return new Range1ul( range.Min < Min ? range.Min : Min, range.Max > Max ? range.Max : Max); } /// /// Returns the range extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1ul ExtendedBy(ulong value) { return new Range1ul( value < Min ? value : Min, value > Max ? value : Max); } /// /// Extends the range to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Range1ul range) { if (range.Min < Min) Min = range.Min; if (range.Max > Max) Max = range.Max; } /// /// Extends the range to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(ulong value) { if (value < Min) Min = value; if (value > Max) Max = value; } /// /// Returns true if the range contains the given value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(ulong value) { return value >= Min && value <= Max; } /// /// Returns true if the range completely contains the given range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Range1ul b) { return b.Min >= Min && b.Max <= Max; } /// /// Checks if 2 ranges intersect each other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1ul range) { if (Min >= range.Max) return false; if (Max <= range.Min) return false; return true; } /// /// Checks if 2 ranges intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1ul range, ulong eps) { if (Min - eps >= range.Max) return false; if (Max + eps <= range.Min) return false; return true; } /// /// Checks if the range is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1ul Repair() { if (this.Equals(Range1ul.Invalid)) return this; if (Min > Max) Fun.Swap(ref Min, ref Max); return this; } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Range1ul a, Range1ul b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Range1ul a, Range1ul b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a range shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ul operator +(Range1ul box, ulong v) { return new Range1ul((ulong)(box.Min + v), (ulong)(box.Max + v)); } /// /// Returns a range shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ul operator -(Range1ul box, ulong v) { return new Range1ul((ulong)(box.Min - v), (ulong)(box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Range1ul other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Range1ul o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Range1ul box, int i, ulong value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Range1ul Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Range1ul(ulong.Parse(x[0], CultureInfo.InvariantCulture), ulong.Parse(x[1], CultureInfo.InvariantCulture)); } public static Range1ul Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, Range1ul.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { fp ??= CultureInfo.InvariantCulture; return begin + Min.ToString(format, fp) + between + Max.ToString(format, fp) + end; } #endregion } public static partial class Range { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ul Union(this Range1ul a, Range1ul b) { return new Range1ul(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ul Intersection(this Range1ul a, Range1ul b) { return new Range1ul(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } /// /// Checks if two ranges intersect each other with a tolerance parameter. /// // TODO: Implement for d > 2 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Range1ul a, Range1ul b, ulong eps, out Range1ul result) { result = Range1ul.Invalid; if (a.Min - eps > b.Max) return false; else if (a.Max + eps < b.Min) return false; else { result = new Range1ul(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); if (result.Size < eps) { ulong center = result.Center; result.Min = (ulong)(center - eps); result.Max = (ulong)(center + eps); } return true; } } #endregion #region Bounding range for arrays /// /// Returns the bounding range of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ul GetBoundingRange(this ulong[] pointArray) { return pointArray.GetBoundingRange(0, pointArray.LongLength); } /// /// Returns the bounding range of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ul GetBoundingRange(this ulong[] pointArray, long count) { return pointArray.GetBoundingRange(0, count); } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1ul GetBoundingRange( this ulong[] pointArray, long start, long count) { if (count <= 0) return Range1ul.Invalid; var box = new Range1ul(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1ul GetBoundingRange(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Range1ul.Invalid; var box = new Range1ul(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding range for lists /// /// Returns the bounding range of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ul GetBoundingRange(this List pointList) { return pointList.GetBoundingRange(pointList.Count); } /// /// Returns the bounding range of the first count elements of the list. /// public static Range1ul GetBoundingRange(this List pointList, int count) { if (count <= 0) return Range1ul.Invalid; var box = new Range1ul(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding range for indexed arrays /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ul GetBoundingRange(this int[] indexArray, ulong[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.Length, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ul GetBoundingRange(this int[] indexArray, int count, ulong[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1ul GetBoundingRange(this int[] indexArray, int start, int count, ulong[] pointArray) { if (count <= 0) return Range1ul.Invalid; var box = new Range1ul(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1ul GetBoundingRange(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Range1ul.Invalid; var box = new Range1ul(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ul GetBoundingRange(this long[] indexArray, ulong[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1ul GetBoundingRange(this long[] indexArray, long count, ulong[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1ul GetBoundingRange(this long[] indexArray, long start, long count, ulong[] pointArray) { if (count <= 0) return Range1ul.Invalid; var box = new Range1ul(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1ul GetBoundingRange(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Range1ul.Invalid; var box = new Range1ul(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding range for IEnumerable /// /// Returns the bounding range of the elements of the collection. /// public static Range1ul GetBoundingRange(this IEnumerable points) { var box = Range1ul.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion } #region Range extensions public static partial class RangeExtensions { /// /// Returns the int sequence 0 ... count-1. /// public static IEnumerable Range(this ulong count) { for (ulong i = 0; i < count; i++) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpTo(this ulong self, ulong upToInclusive) { return self.UpTo(upToInclusive, 1); } public static IEnumerable UpTo(this ulong self, ulong upToInclusive, ulong step) { for (ulong i = self; i <= upToInclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpToExclusive(this ulong self, ulong upToExclusive) { return self.UpToExclusive(upToExclusive, 1); } public static IEnumerable UpToExclusive(this ulong self, ulong upToExclusive, ulong step) { for (ulong i = self; i < upToExclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable DownTo(this ulong self, ulong downToInclusive) { return self.DownTo(downToInclusive, 1); } public static IEnumerable DownTo(this ulong self, ulong downToInclusive, ulong step) { for (ulong i = self; i >= downToInclusive; i -= step) yield return i; } } #endregion public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1ul a, Range1ul b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1ul a, Range1ul b, ulong tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Range1f [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Range1f : IEquatable, IRange, IFormattable { [DataMember] public float Min; [DataMember] public float Max; #region Constructors /// /// Construct a Range1f from a Range1b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(Range1b b) { Min = (float) b.Min; Max = (float) b.Max; } /// /// Construct a Range1f from a Range1sb. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(Range1sb b) { Min = (float) b.Min; Max = (float) b.Max; } /// /// Construct a Range1f from a Range1s. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(Range1s b) { Min = (float) b.Min; Max = (float) b.Max; } /// /// Construct a Range1f from a Range1us. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(Range1us b) { Min = (float) b.Min; Max = (float) b.Max; } /// /// Construct a Range1f from a Range1i. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(Range1i b) { Min = (float) b.Min; Max = (float) b.Max; } /// /// Construct a Range1f from a Range1ui. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(Range1ui b) { Min = (float) b.Min; Max = (float) b.Max; } /// /// Construct a Range1f from a Range1l. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(Range1l b) { Min = (float) b.Min; Max = (float) b.Max; } /// /// Construct a Range1f from a Range1ul. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(Range1ul b) { Min = (float) b.Min; Max = (float) b.Max; } /// /// Construct a Range1f from a Range1d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(Range1d b) { Min = (float) b.Min; Max = (float) b.Max; } /// /// Construct a Range1f from a V2f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(V2f v) { Min = v.X; Max = v.Y; } /// /// Creates a range from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(float min, float max) { Min = min; Max = max; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(float pnt) { Min = pnt; Max = pnt; } /// /// Creates a range from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(float p0, float p1, float p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a range from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(float p0, float p1, float p2, float p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(Range1f range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(Range1f b0, Range1f b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(Range1f b0, Range1f b1, Range1f b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(Range1f b0, Range1f b1, Range1f b2, Range1f b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates range as the bounding range of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(float[] values) { Min = Constant.ParseableMaxValue; Max = Constant.ParseableMinValue; if (values == null) return; long count = values.LongLength; for (long i = 0; i < count; i++) ExtendBy(values[i]); } /// /// Creates range as the bounding range of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(float[] values, long start, long count) { if (count <= 0) { Min = Constant.ParseableMaxValue; Max = Constant.ParseableMinValue; } else { Min = Max = values[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(values[i]); } } /// /// Creates range as the bounding range of given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f(IEnumerable values) { Min = Constant.ParseableMaxValue; Max = Constant.ParseableMinValue; if (values == null) return; foreach (float v in values) ExtendBy(v); } /// /// Returns new range [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f FromMinAndSize(float min, float size) { return new Range1f(min, (float)(min + size)); } /// /// Returns new range [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f FromCenterAndSize(float center, float size) { return new Range1f((float)(center - size / 2), (float)(center + size / 2)); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1f(Range1b b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1f(Range1sb b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1f(Range1s b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1f(Range1us b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1f(Range1i b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1f(Range1ui b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1f(Range1l b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1f(Range1ul b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1f(Range1d b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1f(V2f v) => new(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(Range1f r) => new(r.Min, r.Max); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f ToV2f() => (V2f)this; #endregion #region Constants /// /// A range with crossed limits. /// public static Range1f Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(Constant.ParseableMaxValue, Constant.ParseableMinValue); } /// /// The largest possible range. /// public static Range1f Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(Constant.ParseableMinValue, Constant.ParseableMaxValue); } /// /// The unit interval [0, 1]. /// public static Range1f Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(0, 1); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min >= Max; } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min <= Max; } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min > Max; } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Calculates size of the range. /// [XmlIgnore] public float Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (float)(Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (float)(Min + value); } } public readonly float Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (float)((Min + Max) / 2); } } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (IsInvalid) yield break; //Todo: check should not be necessary for (var i = Min; i <= Max; i++) yield return i; } } #endregion #region Size Manipulations /// /// Return range enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1f EnlargedBy(float increment) { return new Range1f((float)(Min - increment), (float)(Max + increment)); } /// /// Return range enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1f EnlargedBy(float deltaMin, float deltaMax) { return new Range1f((float)(Min - deltaMin), (float)(Max + deltaMax)); } /// /// Return range shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1f ShrunkBy(float delta) { return new Range1f((float)(Min + delta), (float)(Max - delta)); } /// /// Return range shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1f ShrunkBy(float deltaMin, float deltaMax) { return new Range1f((float)(Min + deltaMin), (float)(Max - deltaMax)); } /// /// Enlarges range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(float delta) { Min -= delta; Max += delta; } /// /// Enlarges range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(float deltaMin, float deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(float delta) { Min += delta; Max -= delta; } /// /// Shrinks range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(float deltaMin, float deltaMax) { Min += deltaMin; Max -= deltaMax; } #endregion #region Box Arithmetics /// /// Return the value in the Range that is closest to the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float Clamped(float x) { return x < Min ? Min : (x > Max ? Max : x); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float Lerp(float x) => Fun.Lerp(x, Min, Max); /// /// Performs the inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float InvLerp(float x) => Fun.InvLerp(x, Min, Max); /// /// Returns the range with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1f SplitRight(float splitValue) { if (splitValue > Max) return Range1f.Invalid; if (splitValue <= Min) return this; return new Range1f(splitValue, Max); } /// /// Returns the range with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1f SplitLeft(float splitValue) { if (splitValue < Min) return Range1f.Invalid; if (splitValue >= Max) return this; return new Range1f(Min, splitValue); } /// /// Returns the range extended to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1f ExtendedBy(Range1f range) { return new Range1f( range.Min < Min ? range.Min : Min, range.Max > Max ? range.Max : Max); } /// /// Returns the range extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1f ExtendedBy(float value) { return new Range1f( value < Min ? value : Min, value > Max ? value : Max); } /// /// Extends the range to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Range1f range) { if (range.Min < Min) Min = range.Min; if (range.Max > Max) Max = range.Max; } /// /// Extends the range to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(float value) { if (value < Min) Min = value; if (value > Max) Max = value; } /// /// Returns true if the range contains the given value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(float value) { return value >= Min && value <= Max; } /// /// Returns true if the range completely contains the given range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Range1f b) { return b.Min >= Min && b.Max <= Max; } /// /// Checks if 2 ranges intersect each other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1f range) { if (Min >= range.Max) return false; if (Max <= range.Min) return false; return true; } /// /// Checks if 2 ranges intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1f range, float eps) { if (Min - eps >= range.Max) return false; if (Max + eps <= range.Min) return false; return true; } /// /// Checks if the range is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1f Repair() { if (this.Equals(Range1f.Invalid)) return this; if (Min > Max) Fun.Swap(ref Min, ref Max); return this; } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Range1f a, Range1f b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Range1f a, Range1f b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a range shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f operator +(Range1f box, float v) { return new Range1f((float)(box.Min + v), (float)(box.Max + v)); } /// /// Returns a range shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f operator -(Range1f box, float v) { return new Range1f((float)(box.Min - v), (float)(box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Range1f other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Range1f o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Range1f box, int i, float value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Range1f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Range1f(float.Parse(x[0], CultureInfo.InvariantCulture), float.Parse(x[1], CultureInfo.InvariantCulture)); } public static Range1f Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, Range1f.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { fp ??= CultureInfo.InvariantCulture; return begin + Min.ToString(format, fp) + between + Max.ToString(format, fp) + end; } #endregion } public static partial class Range { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f Union(this Range1f a, Range1f b) { return new Range1f(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f Intersection(this Range1f a, Range1f b) { return new Range1f(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } /// /// Checks if two ranges intersect each other with a tolerance parameter. /// // TODO: Implement for d > 2 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Range1f a, Range1f b, float eps, out Range1f result) { result = Range1f.Invalid; if (a.Min - eps > b.Max) return false; else if (a.Max + eps < b.Min) return false; else { result = new Range1f(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); if (result.Size < eps) { float center = result.Center; result.Min = (float)(center - eps); result.Max = (float)(center + eps); } return true; } } #endregion #region Bounding range for arrays /// /// Returns the bounding range of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f GetBoundingRange(this float[] pointArray) { return pointArray.GetBoundingRange(0, pointArray.LongLength); } /// /// Returns the bounding range of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f GetBoundingRange(this float[] pointArray, long count) { return pointArray.GetBoundingRange(0, count); } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1f GetBoundingRange( this float[] pointArray, long start, long count) { if (count <= 0) return Range1f.Invalid; var box = new Range1f(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1f GetBoundingRange(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Range1f.Invalid; var box = new Range1f(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding range for lists /// /// Returns the bounding range of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f GetBoundingRange(this List pointList) { return pointList.GetBoundingRange(pointList.Count); } /// /// Returns the bounding range of the first count elements of the list. /// public static Range1f GetBoundingRange(this List pointList, int count) { if (count <= 0) return Range1f.Invalid; var box = new Range1f(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding range for indexed arrays /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f GetBoundingRange(this int[] indexArray, float[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.Length, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f GetBoundingRange(this int[] indexArray, int count, float[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1f GetBoundingRange(this int[] indexArray, int start, int count, float[] pointArray) { if (count <= 0) return Range1f.Invalid; var box = new Range1f(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1f GetBoundingRange(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Range1f.Invalid; var box = new Range1f(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f GetBoundingRange(this long[] indexArray, float[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f GetBoundingRange(this long[] indexArray, long count, float[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1f GetBoundingRange(this long[] indexArray, long start, long count, float[] pointArray) { if (count <= 0) return Range1f.Invalid; var box = new Range1f(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1f GetBoundingRange(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Range1f.Invalid; var box = new Range1f(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding range for IEnumerable /// /// Returns the bounding range of the elements of the collection. /// public static Range1f GetBoundingRange(this IEnumerable points) { var box = Range1f.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion } #region Range extensions public static partial class Conversion { #region Angles (Radians, Degrees, Gons) /// /// Converts the angles given in degrees to radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f RadiansFromDegrees(this Range1f degrees) => new(degrees.Min.RadiansFromDegrees(), degrees.Max.RadiansFromDegrees()); /// /// Converts the angles given in gons to radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f RadiansFromGons(this Range1f gons) => new(gons.Min.RadiansFromGons(), gons.Max.RadiansFromGons()); /// /// Converts the angles given in radians to degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f DegreesFromRadians(this Range1f radians) => new(radians.Min.DegreesFromRadians(), radians.Max.DegreesFromRadians()); /// /// Converts the angles given in gons to degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f DegreesFromGons(this Range1f gons) => new(gons.Min.DegreesFromGons(), gons.Max.DegreesFromGons()); /// /// Converts the angles given in radians to gons. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f GonsFromRadians(this Range1f radians) => new(radians.Min.GonsFromRadians(), radians.Max.GonsFromRadians()); /// /// Converts the angles given in degrees to gons. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1f GonsFromDegrees(this Range1f degrees) => new(degrees.Min.GonsFromDegrees(), degrees.Max.GonsFromDegrees()); #endregion } public static partial class RangeExtensions { /// /// Returns the int sequence 0 ... count-1. /// public static IEnumerable Range(this float count) { for (float i = 0; i < count; i++) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpTo(this float self, float upToInclusive) { return self.UpTo(upToInclusive, 1); } public static IEnumerable UpTo(this float self, float upToInclusive, float step) { for (float i = self; i <= upToInclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpToExclusive(this float self, float upToExclusive) { return self.UpToExclusive(upToExclusive, 1); } public static IEnumerable UpToExclusive(this float self, float upToExclusive, float step) { for (float i = self; i < upToExclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable DownTo(this float self, float downToInclusive) { return self.DownTo(downToInclusive, 1); } public static IEnumerable DownTo(this float self, float downToInclusive, float step) { for (float i = self; i >= downToInclusive; i -= step) yield return i; } } #endregion public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1f a, Range1f b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1f a, Range1f b, float tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Range1d [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Range1d : IEquatable, IRange, IFormattable { [DataMember] public double Min; [DataMember] public double Max; #region Constructors /// /// Construct a Range1d from a Range1b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(Range1b b) { Min = (double) b.Min; Max = (double) b.Max; } /// /// Construct a Range1d from a Range1sb. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(Range1sb b) { Min = (double) b.Min; Max = (double) b.Max; } /// /// Construct a Range1d from a Range1s. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(Range1s b) { Min = (double) b.Min; Max = (double) b.Max; } /// /// Construct a Range1d from a Range1us. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(Range1us b) { Min = (double) b.Min; Max = (double) b.Max; } /// /// Construct a Range1d from a Range1i. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(Range1i b) { Min = (double) b.Min; Max = (double) b.Max; } /// /// Construct a Range1d from a Range1ui. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(Range1ui b) { Min = (double) b.Min; Max = (double) b.Max; } /// /// Construct a Range1d from a Range1l. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(Range1l b) { Min = (double) b.Min; Max = (double) b.Max; } /// /// Construct a Range1d from a Range1ul. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(Range1ul b) { Min = (double) b.Min; Max = (double) b.Max; } /// /// Construct a Range1d from a Range1f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(Range1f b) { Min = (double) b.Min; Max = (double) b.Max; } /// /// Construct a Range1d from a V2d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(V2d v) { Min = v.X; Max = v.Y; } /// /// Creates a range from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(double min, double max) { Min = min; Max = max; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(double pnt) { Min = pnt; Max = pnt; } /// /// Creates a range from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(double p0, double p1, double p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a range from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(double p0, double p1, double p2, double p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(Range1d range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(Range1d b0, Range1d b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(Range1d b0, Range1d b1, Range1d b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied ranges. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(Range1d b0, Range1d b1, Range1d b2, Range1d b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates range as the bounding range of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(double[] values) { Min = Constant.ParseableMaxValue; Max = Constant.ParseableMinValue; if (values == null) return; long count = values.LongLength; for (long i = 0; i < count; i++) ExtendBy(values[i]); } /// /// Creates range as the bounding range of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(double[] values, long start, long count) { if (count <= 0) { Min = Constant.ParseableMaxValue; Max = Constant.ParseableMinValue; } else { Min = Max = values[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(values[i]); } } /// /// Creates range as the bounding range of given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d(IEnumerable values) { Min = Constant.ParseableMaxValue; Max = Constant.ParseableMinValue; if (values == null) return; foreach (double v in values) ExtendBy(v); } /// /// Returns new range [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d FromMinAndSize(double min, double size) { return new Range1d(min, (min + size)); } /// /// Returns new range [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d FromCenterAndSize(double center, double size) { return new Range1d((center - size / 2), (center + size / 2)); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1d(Range1b b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1d(Range1sb b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1d(Range1s b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1d(Range1us b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1d(Range1i b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1d(Range1ui b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1d(Range1l b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1d(Range1ul b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1d(Range1f b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Range1d(V2d v) => new(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(Range1d r) => new(r.Min, r.Max); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d ToV2d() => (V2d)this; #endregion #region Constants /// /// A range with crossed limits. /// public static Range1d Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(Constant.ParseableMaxValue, Constant.ParseableMinValue); } /// /// The largest possible range. /// public static Range1d Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(Constant.ParseableMinValue, Constant.ParseableMaxValue); } /// /// The unit interval [0, 1]. /// public static Range1d Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(0, 1); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min >= Max; } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min <= Max; } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min > Max; } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Calculates size of the range. /// [XmlIgnore] public double Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (Min + value); } } public readonly double Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return ((Min + Max) / 2); } } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (IsInvalid) yield break; //Todo: check should not be necessary for (var i = Min; i <= Max; i++) yield return i; } } #endregion #region Size Manipulations /// /// Return range enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1d EnlargedBy(double increment) { return new Range1d((Min - increment), (Max + increment)); } /// /// Return range enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1d EnlargedBy(double deltaMin, double deltaMax) { return new Range1d((Min - deltaMin), (Max + deltaMax)); } /// /// Return range shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1d ShrunkBy(double delta) { return new Range1d((Min + delta), (Max - delta)); } /// /// Return range shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1d ShrunkBy(double deltaMin, double deltaMax) { return new Range1d((Min + deltaMin), (Max - deltaMax)); } /// /// Enlarges range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(double delta) { Min -= delta; Max += delta; } /// /// Enlarges range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(double deltaMin, double deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks range by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(double delta) { Min += delta; Max -= delta; } /// /// Shrinks range by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(double deltaMin, double deltaMax) { Min += deltaMin; Max -= deltaMax; } #endregion #region Box Arithmetics /// /// Return the value in the Range that is closest to the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double Clamped(double x) { return x < Min ? Min : (x > Max ? Max : x); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double Lerp(double x) => Fun.Lerp(x, Min, Max); /// /// Performs the inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double InvLerp(double x) => Fun.InvLerp(x, Min, Max); /// /// Returns the range with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1d SplitRight(double splitValue) { if (splitValue > Max) return Range1d.Invalid; if (splitValue <= Min) return this; return new Range1d(splitValue, Max); } /// /// Returns the range with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1d SplitLeft(double splitValue) { if (splitValue < Min) return Range1d.Invalid; if (splitValue >= Max) return this; return new Range1d(Min, splitValue); } /// /// Returns the range extended to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1d ExtendedBy(Range1d range) { return new Range1d( range.Min < Min ? range.Min : Min, range.Max > Max ? range.Max : Max); } /// /// Returns the range extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Range1d ExtendedBy(double value) { return new Range1d( value < Min ? value : Min, value > Max ? value : Max); } /// /// Extends the range to contain the supplied range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Range1d range) { if (range.Min < Min) Min = range.Min; if (range.Max > Max) Max = range.Max; } /// /// Extends the range to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(double value) { if (value < Min) Min = value; if (value > Max) Max = value; } /// /// Returns true if the range contains the given value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(double value) { return value >= Min && value <= Max; } /// /// Returns true if the range completely contains the given range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Range1d b) { return b.Min >= Min && b.Max <= Max; } /// /// Checks if 2 ranges intersect each other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1d range) { if (Min >= range.Max) return false; if (Max <= range.Min) return false; return true; } /// /// Checks if 2 ranges intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Range1d range, double eps) { if (Min - eps >= range.Max) return false; if (Max + eps <= range.Min) return false; return true; } /// /// Checks if the range is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Range1d Repair() { if (this.Equals(Range1d.Invalid)) return this; if (Min > Max) Fun.Swap(ref Min, ref Max); return this; } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Range1d a, Range1d b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Range1d a, Range1d b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a range shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d operator +(Range1d box, double v) { return new Range1d((box.Min + v), (box.Max + v)); } /// /// Returns a range shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d operator -(Range1d box, double v) { return new Range1d((box.Min - v), (box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Range1d other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Range1d o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Range1d box, int i, double value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Range1d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Range1d(double.Parse(x[0], CultureInfo.InvariantCulture), double.Parse(x[1], CultureInfo.InvariantCulture)); } public static Range1d Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, Range1d.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { fp ??= CultureInfo.InvariantCulture; return begin + Min.ToString(format, fp) + between + Max.ToString(format, fp) + end; } #endregion } public static partial class Range { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d Union(this Range1d a, Range1d b) { return new Range1d(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d Intersection(this Range1d a, Range1d b) { return new Range1d(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } /// /// Checks if two ranges intersect each other with a tolerance parameter. /// // TODO: Implement for d > 2 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this Range1d a, Range1d b, double eps, out Range1d result) { result = Range1d.Invalid; if (a.Min - eps > b.Max) return false; else if (a.Max + eps < b.Min) return false; else { result = new Range1d(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); if (result.Size < eps) { double center = result.Center; result.Min = (center - eps); result.Max = (center + eps); } return true; } } #endregion #region Bounding range for arrays /// /// Returns the bounding range of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d GetBoundingRange(this double[] pointArray) { return pointArray.GetBoundingRange(0, pointArray.LongLength); } /// /// Returns the bounding range of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d GetBoundingRange(this double[] pointArray, long count) { return pointArray.GetBoundingRange(0, count); } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1d GetBoundingRange( this double[] pointArray, long start, long count) { if (count <= 0) return Range1d.Invalid; var box = new Range1d(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding range of count elements of the array starting at start. /// public static Range1d GetBoundingRange(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Range1d.Invalid; var box = new Range1d(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding range for lists /// /// Returns the bounding range of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d GetBoundingRange(this List pointList) { return pointList.GetBoundingRange(pointList.Count); } /// /// Returns the bounding range of the first count elements of the list. /// public static Range1d GetBoundingRange(this List pointList, int count) { if (count <= 0) return Range1d.Invalid; var box = new Range1d(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding range for indexed arrays /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d GetBoundingRange(this int[] indexArray, double[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.Length, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d GetBoundingRange(this int[] indexArray, int count, double[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1d GetBoundingRange(this int[] indexArray, int start, int count, double[] pointArray) { if (count <= 0) return Range1d.Invalid; var box = new Range1d(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1d GetBoundingRange(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Range1d.Invalid; var box = new Range1d(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d GetBoundingRange(this long[] indexArray, double[] pointArray) { return indexArray.GetBoundingRange(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d GetBoundingRange(this long[] indexArray, long count, double[] pointArray) { return indexArray.GetBoundingRange(0, count, pointArray); } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1d GetBoundingRange(this long[] indexArray, long start, long count, double[] pointArray) { if (count <= 0) return Range1d.Invalid; var box = new Range1d(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding range of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Range1d GetBoundingRange(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Range1d.Invalid; var box = new Range1d(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding range for IEnumerable /// /// Returns the bounding range of the elements of the collection. /// public static Range1d GetBoundingRange(this IEnumerable points) { var box = Range1d.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion } #region Range extensions public static partial class Conversion { #region Angles (Radians, Degrees, Gons) /// /// Converts the angles given in degrees to radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d RadiansFromDegrees(this Range1d degrees) => new(degrees.Min.RadiansFromDegrees(), degrees.Max.RadiansFromDegrees()); /// /// Converts the angles given in gons to radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d RadiansFromGons(this Range1d gons) => new(gons.Min.RadiansFromGons(), gons.Max.RadiansFromGons()); /// /// Converts the angles given in radians to degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d DegreesFromRadians(this Range1d radians) => new(radians.Min.DegreesFromRadians(), radians.Max.DegreesFromRadians()); /// /// Converts the angles given in gons to degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d DegreesFromGons(this Range1d gons) => new(gons.Min.DegreesFromGons(), gons.Max.DegreesFromGons()); /// /// Converts the angles given in radians to gons. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d GonsFromRadians(this Range1d radians) => new(radians.Min.GonsFromRadians(), radians.Max.GonsFromRadians()); /// /// Converts the angles given in degrees to gons. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Range1d GonsFromDegrees(this Range1d degrees) => new(degrees.Min.GonsFromDegrees(), degrees.Max.GonsFromDegrees()); #endregion } public static partial class RangeExtensions { /// /// Returns the int sequence 0 ... count-1. /// public static IEnumerable Range(this double count) { for (double i = 0; i < count; i++) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpTo(this double self, double upToInclusive) { return self.UpTo(upToInclusive, 1); } public static IEnumerable UpTo(this double self, double upToInclusive, double step) { for (double i = self; i <= upToInclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable UpToExclusive(this double self, double upToExclusive) { return self.UpToExclusive(upToExclusive, 1); } public static IEnumerable UpToExclusive(this double self, double upToExclusive, double step) { for (double i = self; i < upToExclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable DownTo(this double self, double downToInclusive) { return self.DownTo(downToInclusive, 1); } public static IEnumerable DownTo(this double self, double downToInclusive, double step) { for (double i = self; i >= downToInclusive; i -= step) yield return i; } } #endregion public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1d a, Range1d b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Range1d a, Range1d b, double tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Box2i [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Box2i : IEquatable, IRange, IBoundingBox2i, ISize2i, IBoundingCircle2d, IFormattable { [DataMember] public V2i Min; [DataMember] public V2i Max; #region Constructors /// /// Construct a Box2i from a Box2l. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i(Box2l b) { Min = (V2i) b.Min; Max = (V2i) b.Max; } /// /// Construct a Box2i from a Box2f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i(Box2f b) { Min = (V2i) b.Min; Max = (V2i) b.Max; } /// /// Construct a Box2i from a Box2d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i(Box2d b) { Min = (V2i) b.Min; Max = (V2i) b.Max; } /// /// Creates a box from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i(V2i min, V2i max) { Min = min; Max = max; } /// /// Creates a box from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i(int minX, int minY, int maxX, int maxY) { Min.X = minX; Min.Y = minY; Max.X = maxX; Max.Y = maxY; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i(V2i pnt) { Min = pnt; Max = pnt; } /// /// Creates a box from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i(V2i p0, V2i p1, V2i p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a box from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i(V2i p0, V2i p1, V2i p2, V2i p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i(Box2i range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i(Box2i b0, Box2i b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i(Box2i b0, Box2i b1, Box2i b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i(Box2i b0, Box2i b1, Box2i b2, Box2i b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i(V2i[] points) : this((ReadOnlySpan)points) { } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i(ReadOnlySpan points) { Min = V2i.MaxValue; Max = V2i.MinValue; if (points == null) return; var count = points.Length; for (var i = 0; i < count; i++) ExtendBy(points[i]); } /// /// Creates box as the bounding box of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i(V2i[] points, long start, long count) { if (count <= 0) { Min = Invalid.Min; Max = Invalid.Max; } else { Min = Max = points[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(points[i]); } } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i(IEnumerable points) { Min = V2i.MaxValue; Max = V2i.MinValue; if (points == null) return; foreach (V2i p in points) ExtendBy(p); } /// /// Creates box as the bounding box of given boxes. /// public Box2i(IEnumerable boxes) { Min = V2i.MaxValue; Max = V2i.MinValue; if (boxes == null) return; foreach (var box in boxes) ExtendBy(box); } /// /// Creates box from a Range1 in each direction. /// public Box2i(Range1i rangeX, Range1i rangeY) { Min.X = rangeX.Min; Max.X = rangeX.Max; Min.Y = rangeY.Min; Max.Y = rangeY.Max; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box2i(Box2l b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box2i(Box2f b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box2i(Box2d b) => new(b); #endregion #region Constants /// /// A range with crossed limits. /// public static Box2i Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V2i.MaxValue, V2i.MinValue); } /// /// The largest possible range. /// public static Box2i Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V2i.MinValue, V2i.MaxValue); } /// /// The unit interval [0, 1]. /// public static Box2i Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V2i.Zero, V2i.One); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AnyGreaterOrEqual(Max); } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AllSmallerOrEqual(Max); } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AnyGreater(Max); } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Same as Min.X. /// [XmlIgnore] public int Left { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Min.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Min.X = value; } } /// /// Same as Max.X. /// [XmlIgnore] public int Right { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.X = value; } } /// /// Same as Min.Y. /// [XmlIgnore] public int Top { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Min.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Min.Y = value; } } /// /// Same as Max.Y. /// [XmlIgnore] public int Bottom { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Y = value; } } /// /// Calculates size of the box. /// [XmlIgnore] public V2i Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (Min + value); } } public readonly V2i Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return ((Min + Max) / 2); } } [XmlIgnore] public int SizeX { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.X - Min.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.X = Min.X + value; } } public readonly Range1i RangeX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1i(Min.X, Max.X); } } [XmlIgnore] public int SizeY { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Y - Min.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Y = Min.Y + value; } } public readonly Range1i RangeY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1i(Min.Y, Max.Y); } } /// /// Index of the longest dimension of the box. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return SizeY > SizeX ? 1 : 0; } } /// /// Index of the shortest dimension of the box. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return SizeY < SizeX ? 1 : 0; } } public readonly int Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return SizeX * SizeY; } } public readonly V2i OO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min; } } public readonly V2i IO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2i(Max.X, Min.Y); } } public readonly V2i OI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2i(Min.X, Max.Y); } } public readonly V2i II { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Max; } } #endregion #region Size Manipulations /// /// Return box enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i EnlargedBy(V2i increment) { return new Box2i((Min - increment), (Max + increment)); } /// /// Return box enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i EnlargedBy(V2i deltaMin, V2i deltaMax) { return new Box2i((Min - deltaMin), (Max + deltaMax)); } /// /// Return box shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i ShrunkBy(V2i delta) { return new Box2i((Min + delta), (Max - delta)); } /// /// Return box shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i ShrunkBy(V2i deltaMin, V2i deltaMax) { return new Box2i((Min + deltaMin), (Max - deltaMax)); } /// /// Enlarges box by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(V2i delta) { Min -= delta; Max += delta; } /// /// Enlarges box by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(V2i deltaMin, V2i deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks box by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(V2i delta) { Min += delta; Max -= delta; } /// /// Shrinks box by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(V2i deltaMin, V2i deltaMax) { Min += deltaMin; Max -= deltaMax; } /// /// Returns a box enlarged by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i EnlargedBy(int delta) { return new Box2i( new V2i(Min.X - delta, Min.Y - delta), new V2i(Max.X + delta, Max.Y + delta)); } /// /// Returns a box shrunk by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i ShrunkBy(int delta) { return new Box2i( new V2i(Min.X + delta, Min.Y + delta), new V2i(Max.X - delta, Max.Y - delta)); } /// /// Returns the box enlarged by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i EnlargedBy( int deltaMinX, int deltaMaxX, int deltaMinY, int deltaMaxY) { return new Box2i( new V2i(Min.X - deltaMinX, Min.Y - deltaMinY), new V2i(Max.X + deltaMaxX, Max.Y + deltaMaxY)); } /// /// Returns the box shrunk by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i ShrunkBy( int deltaMinX, int deltaMaxX, int deltaMinY, int deltaMaxY) { return new Box2i( new V2i(Min.X + deltaMinX, Min.Y + deltaMinY), new V2i(Max.X - deltaMaxX, Max.Y - deltaMaxY)); } /// /// Enlarges box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(int delta) { Min.X -= delta; Max.X += delta; Min.Y -= delta; Max.Y += delta; } /// /// Shrinks box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(int delta) { Min.X += delta; Max.X -= delta; Min.Y += delta; Max.Y -= delta; } /// /// Enlarges the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy( int deltaMinX, int deltaMaxX, int deltaMinY, int deltaMaxY) { Min.X -= deltaMinX; Max.X += deltaMaxX; Min.Y -= deltaMinY; Max.Y += deltaMaxY; } /// /// Shrinks the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy( int deltaMinX, int deltaMaxX, int deltaMinY, int deltaMaxY) { Min.X += deltaMinX; Max.X -= deltaMaxX; Min.Y += deltaMinY; Max.Y -= deltaMaxY; } #endregion #region Box Arithmetics /// /// Return the point in the Box that is closest to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i Clamped(V2i p) { return new V2i( p.X < Min.X ? Min.X : (p.X > Max.X ? Max.X : p.X), p.Y < Min.Y ? Min.Y : (p.Y > Max.Y ? Max.Y : p.Y)); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i Lerp(float t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i Lerp(V2f t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i Lerp(double t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i Lerp(V2d t) => Fun.Lerp(t, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d InvLerp(V2i y) => Fun.InvLerp(y, Min, Max); /// /// Returns the box with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i SplitRight(V2i splitValue) { var result = new Box2i(Min, Max); if (splitValue.X > result.Min.X) result.Min.X = splitValue.X; if (splitValue.Y > result.Min.Y) result.Min.Y = splitValue.Y; return result; } /// /// Returns the box with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i SplitLeft(V2i splitValue) { var result = new Box2i(Min, Max); if (splitValue.X < result.Max.X) result.Max.X = splitValue.X; if (splitValue.Y < result.Max.Y) result.Max.Y = splitValue.Y; return result; } /// /// Returns the box with Min.X clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i SplitRight(int splitAtX) { if (splitAtX > Max.X) return Box2i.Invalid; if (splitAtX <= Min.X) return this; return new Box2i(new V2i(splitAtX, Min.Y), Max); } /// /// Returns a box with Max.X clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i SplitLeft(int splitAtX) { if (splitAtX < Min.X) return Box2i.Invalid; if (splitAtX >= Max.X) return this; return new Box2i(Min, new V2i(splitAtX, Max.Y)); } /// /// Returns the box with Min.Y clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i SplitTop(int splitAtY) { if (splitAtY > Max.Y) return Box2i.Invalid; if (splitAtY <= Min.Y) return this; return new Box2i(new V2i(Min.X, splitAtY), Max); } /// /// Returns the box with Max.Y clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i SplitBottom(int splitAtY) { if (splitAtY < Min.Y) return Box2i.Invalid; if (splitAtY >= Max.Y) return this; return new Box2i(Min, new V2i(Max.X, splitAtY)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i SplitLeftBottom(V2i splitAt) { if (splitAt.X < Min.X || splitAt.Y < Min.Y) return Box2i.Invalid; return new Box2i(Min, splitAt); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i SplitRightBottom(V2i splitAt) { if (splitAt.X > Max.X || splitAt.Y < Min.Y) return Box2i.Invalid; return new Box2i(new V2i(splitAt.X, Min.Y), new V2i(Max.X, splitAt.Y)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i SplitLeftTop(V2i splitAt) { if (splitAt.X < Min.X || splitAt.Y > Max.Y) return Box2i.Invalid; return new Box2i(new V2i(Min.X, splitAt.Y), new V2i(splitAt.X, Max.Y)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i SplitRightTop(V2i splitAt) { if (splitAt.X > Max.X || splitAt.Y > Max.Y) return Box2i.Invalid; return new Box2i(splitAt, Max); } /// /// Returns the box extended to contain the supplied box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i ExtendedBy(Box2i b) { return new Box2i( new V2i( b.Min.X < Min.X ? b.Min.X : Min.X, b.Min.Y < Min.Y ? b.Min.Y : Min.Y), new V2i( b.Max.X > Max.X ? b.Max.X : Max.X, b.Max.Y > Max.Y ? b.Max.Y : Max.Y)); } /// /// Returns the box extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i ExtendedBy(V2i v) { return new Box2i( new V2i( v.X < Min.X ? v.X : Min.X, v.Y < Min.Y ? v.Y : Min.Y), new V2i( v.X > Max.X ? v.X : Max.X, v.Y > Max.Y ? v.Y : Max.Y)); } /// /// Extends the box to contain the supplied box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Box2i box) { if (box.Min.X < Min.X) Min.X = box.Min.X; if (box.Max.X > Max.X) Max.X = box.Max.X; if (box.Min.Y < Min.Y) Min.Y = box.Min.Y; if (box.Max.Y > Max.Y) Max.Y = box.Max.Y; } /// /// Extends the box to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(V2i point) { if (point.X < Min.X) Min.X = point.X; if (point.X > Max.X) Max.X = point.X; if (point.Y < Min.Y) Min.Y = point.Y; if (point.Y > Max.Y) Max.Y = point.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i ExtendXBy(int x) { if (x < Min.X) Min.X = x; if (x > Max.X) Max.X = x; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i ExtendYBy(int y) { if (y < Min.Y) Min.Y = y; if (y > Max.Y) Max.Y = y; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i ExtendDimBy(int dim, int x) { if (x < Min[dim]) Min[dim] = x; if (x > Max[dim]) Max[dim] = x; return this; } /// /// Returns true if the box contains the given point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(V2i p) { return p.X >= Min.X && p.X <= Max.X && p.Y >= Min.Y && p.Y <= Max.Y; } /// /// Returns true if the box completely contains the other box. /// A box contains itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Box2i b) { return b.Min.X >= Min.X && b.Max.X <= Max.X && b.Min.Y >= Min.Y && b.Max.Y <= Max.Y; } /// /// Checks if the box is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i Repair() { if (Equals(Box2i.Invalid)) return this; if (Min.X > Max.X) Fun.Swap(ref Min.X, ref Max.X); if (Min.Y > Max.Y) Fun.Swap(ref Min.Y, ref Max.Y); return this; } /// /// Returns true if two boxes intersect each other (or one contains the other). /// Boxes DO NOT intersect if only touching from the outside. /// A box intersects itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box2i box) { if (Min.X >= box.Max.X) return false; if (Max.X <= box.Min.X) return false; if (Min.Y >= box.Max.Y) return false; if (Max.Y <= box.Min.Y) return false; return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box2i box, V2i eps) { if (Min.X - eps.X >= box.Max.X) return false; if (Max.X + eps.X <= box.Min.X) return false; if (Min.Y - eps.Y >= box.Max.Y) return false; if (Max.Y + eps.Y <= box.Min.Y) return false; return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box2i box, int eps) { if (Min.X - eps >= box.Max.X) return false; if (Max.X + eps <= box.Min.X) return false; if (Min.Y - eps >= box.Max.Y) return false; if (Max.Y + eps <= box.Min.Y) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2i Invalidate() { Min = V2i.MaxValue; Max = V2i.MinValue; return this; } /// /// Returns where a points coordinates are outside a given box /// /// All outside Flags [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(V2i p0) { Box.Flags bf = Box.Flags.None; if (p0.X < Min.X) bf |= Box.Flags.MinX; else if (p0.X > Max.X) bf |= Box.Flags.MaxX; if (p0.Y < Min.Y) bf |= Box.Flags.MinY; else if (p0.Y > Max.Y) bf |= Box.Flags.MaxY; return bf; } /// /// Returns where the planes of the supplied box b are outside /// of the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(Box2i b) { Box.Flags bf = Box.Flags.None; if (b.Min.X < Min.X) bf |= Box.Flags.MinX; if (b.Max.X > Max.X) bf |= Box.Flags.MaxX; if (b.Min.Y < Min.Y) bf |= Box.Flags.MinY; if (b.Max.Y > Max.Y) bf |= Box.Flags.MaxY; return bf; } /// /// Gets the minimal and maximal points of the box when seen from the /// supplied direction vector v. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void GetMinMaxInDirection(V2i v, out V2i vMin, out V2i vMax) { vMin = V2i.MinValue; vMax = V2i.MaxValue; if (v.X >= 0) { vMin.X = Min.X; vMax.X = Max.X; } else { vMin.X = Max.X; vMax.X = Min.X; } if (v.Y >= 0) { vMin.Y = Min.Y; vMax.Y = Max.Y; } else { vMin.Y = Max.Y; vMax.Y = Min.Y; } } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Box2i a, Box2i b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Box2i a, Box2i b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a box shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i operator +(Box2i box, V2i v) { return new Box2i((box.Min + v), (box.Max + v)); } /// /// Returns a box shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i operator -(Box2i box, V2i v) { return new Box2i((box.Min - v), (box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Box2i other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Box2i o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Box2i box, int i, V2i value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Box2i Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Box2i(V2i.Parse(x[0].ToString()), V2i.Parse(x[1].ToString())); } public static Box2i Parse(Text t) { return t.NestedBracketSplit(1, V2i.Parse, Box2i.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string beginB, string betweenB, string endB, string beginV, string betweenV, string endV) { fp ??= CultureInfo.InvariantCulture; return beginB + Min.ToString(format, fp, beginV, betweenV, endV) + betweenB + Max.ToString(format, fp, beginV, betweenV, endV) + endB; } #endregion #region Static Factories /// /// Returns new box [0, size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i FromSize(V2i size) { return new Box2i(V2i.Zero, size); } /// /// Returns new box [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i FromMinAndSize(V2i min, V2i size) { return new Box2i(min, min + size); } /// /// Returns new box [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i FromCenterAndSize(V2i center, V2i size) { return new Box2i(center - size / 2, center + size / 2); } /// /// Returns new box [0, iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i FromSize(ISize2i iSize) { return new Box2i( V2i.Zero, iSize.Size2i); } /// /// Returns new box [min, min + iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i FromMinAndSize(V2i min, ISize2i iSize) { return new Box2i( min, min + iSize.Size2i); } /// /// Returns new box [center - iSize / 2, center + iSize / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i FromCenterAndSize(V2i center, ISize2i iSize) { var size = iSize.Size2i; return new Box2i(center - size / 2, center + size / 2); } /// /// Creates box from 2 points which need not be Min and Max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i FromPoints(V2i p0, V2i p1) { return new Box2i(Fun.Min(p0, p1), Fun.Max(p0, p1)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i FromSize(int width, int height) { return Box2i.FromSize(new V2i(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i FromMinAndSize(V2i min, int width, int height) { return new Box2i(min, min + new V2i(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i FromMinAndSize( int minX, int minY, int width, int height ) { return Box2i.FromMinAndSize(new V2i(minX, minY), new V2i(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i FromCenterAndSize(V2i center, int width, int height) { return FromCenterAndSize(center, new V2i(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i FromCenterAndSize( int centerX, int centerY, int width, int height ) { return FromCenterAndSize(new V2i(centerX, centerY), new V2i(width, height)); } #endregion #region Transforms [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i Translated(V2i shift) { return IsInvalid ? Box2i.Invalid : new Box2i(Min + shift, Max + shift); } /// /// Returns a scaled box. WARNING: scaling is performed around the origin! /// A negative scale factor will resut in an invalid box! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2i Scaled(V2i factor) { return IsInvalid ? Box2i.Invalid : new Box2i(Min * factor, Max * factor); } /// /// Transforms the box by the given transformation matrix. /// NOTE: Performs IsValid check at 10% CPU time overhead. /// -> Empty bounds (crossed min and max) will remain empty. /// public readonly Box2d Transformed(M33d trafo) { if (Min.X > Max.X || Min.Y > Max.Y) return Box2d.Invalid; var t = new V2d(trafo.M02, trafo.M12); var res = new Box2d(t, t); double av, bv; av = trafo.M00 * Min.X; bv = trafo.M00 * Max.X; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M01 * Min.Y; bv = trafo.M01 * Max.Y; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M10 * Min.X; bv = trafo.M10 * Max.X; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } av = trafo.M11 * Min.Y; bv = trafo.M11 * Max.Y; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } return res; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d Transformed(Trafo2d trafo) { return Transformed(trafo.Forward); } #endregion #region Corners /// /// Return the corner of the box with the given index. The corner /// index is constructed in such a way, that bit 0 enumerates the /// x coordinate (0 ... min, 1 ... max), bit 1 enumerates the y /// coordinate, and bit 2 enumerates the z coordinate. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i Corner(int index) { return new V2i( (index & 1) == 0 ? Min.X : Max.X, (index & 2) == 0 ? Min.Y : Max.Y); } /// /// Computes the corners of the box and returns them in an array. /// The order of the corners is determined by their index which is /// constructed as in the method . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i[] ComputeCorners() { return [ Min, new(Max.X, Min.Y), new(Min.X, Max.Y), Max ]; } // TODO: Comment and implement for dimensions other than 2. [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i[] ComputeCornersCCW() { return [ Min, new(Max.X, Min.Y), Max, new(Min.X, Max.Y), ]; } /// /// Enumeration of the corners of the box. /// public readonly IEnumerable Corners { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return Min; yield return new V2i(Max.X, Min.Y); yield return new V2i(Min.X, Max.Y); yield return Max; } } #endregion #region Swizzle methods #endregion #region Enumerators /// /// Returns all points from [Min,Max[ with X-Variable in the outer loop. /// public readonly IEnumerable EnumerateInsidePoints() { var p = new V2i(); for (p.X = Min.X; p.X < Max.X; p.X++) for (p.Y = Min.Y; p.Y < Max.Y; p.Y++) yield return p; } #endregion #region IBoundingBox2i Members public readonly Box2i BoundingBox2i { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this; } } #endregion #region IBoundingCircle2d Members public readonly Circle2d BoundingCircle2d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => IsInvalid ? Circle2d.Invalid : new Circle2d((V2d)Center, 0.5 * Size.Length); } #endregion #region ISize2i Members public readonly V2i Size2i { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Size; } } #endregion } public static partial class Box { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i Union(this Box2i a, Box2i b) { return new Box2i(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i Intersection(this Box2i a, Box2i b) { return new Box2i(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } #endregion #region Bounding box for arrays /// /// Returns the bounding box of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i GetBoundingBox(this V2i[] pointArray) { return pointArray.GetBoundingBox(0, pointArray.LongLength); } /// /// Returns the bounding box of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i GetBoundingBox(this V2i[] pointArray, long count) { return pointArray.GetBoundingBox(0, count); } /// /// Returns the bounding box of count elements of the array starting at start. /// public static Box2i GetBoundingBox( this V2i[] pointArray, long start, long count) { if (count <= 0) return Box2i.Invalid; var box = new Box2i(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding box of count elements of the array starting at start. /// public static Box2i GetBoundingBox(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Box2i.Invalid; var box = new Box2i(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding box for lists /// /// Returns the bounding box of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i GetBoundingBox(this List pointList) { return pointList.GetBoundingBox(pointList.Count); } /// /// Returns the bounding box of the first count elements of the list. /// public static Box2i GetBoundingBox(this List pointList, int count) { if (count <= 0) return Box2i.Invalid; var box = new Box2i(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding box for indexed arrays /// /// Returns the bounding box of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i GetBoundingBox(this int[] indexArray, V2i[] pointArray) { return indexArray.GetBoundingBox(0, indexArray.Length, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i GetBoundingBox(this int[] indexArray, int count, V2i[] pointArray) { return indexArray.GetBoundingBox(0, count, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box2i GetBoundingBox(this int[] indexArray, int start, int count, V2i[] pointArray) { if (count <= 0) return Box2i.Invalid; var box = new Box2i(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box2i GetBoundingBox(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Box2i.Invalid; var box = new Box2i(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i GetBoundingBox(this long[] indexArray, V2i[] pointArray) { return indexArray.GetBoundingBox(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2i GetBoundingBox(this long[] indexArray, long count, V2i[] pointArray) { return indexArray.GetBoundingBox(0, count, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box2i GetBoundingBox(this long[] indexArray, long start, long count, V2i[] pointArray) { if (count <= 0) return Box2i.Invalid; var box = new Box2i(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box2i GetBoundingBox(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Box2i.Invalid; var box = new Box2i(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding box for IEnumerable /// /// Returns the bounding box of the elements of the collection. /// public static Box2i GetBoundingBox(this IEnumerable points) { var box = Box2i.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Box2i a, Box2i b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Box2i a, Box2i b, int tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Box2l [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Box2l : IEquatable, IRange, IBoundingBox2l, ISize2l, IBoundingCircle2d, IFormattable { [DataMember] public V2l Min; [DataMember] public V2l Max; #region Constructors /// /// Construct a Box2l from a Box2i. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l(Box2i b) { Min = (V2l) b.Min; Max = (V2l) b.Max; } /// /// Construct a Box2l from a Box2f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l(Box2f b) { Min = (V2l) b.Min; Max = (V2l) b.Max; } /// /// Construct a Box2l from a Box2d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l(Box2d b) { Min = (V2l) b.Min; Max = (V2l) b.Max; } /// /// Creates a box from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l(V2l min, V2l max) { Min = min; Max = max; } /// /// Creates a box from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l(long minX, long minY, long maxX, long maxY) { Min.X = minX; Min.Y = minY; Max.X = maxX; Max.Y = maxY; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l(V2l pnt) { Min = pnt; Max = pnt; } /// /// Creates a box from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l(V2l p0, V2l p1, V2l p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a box from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l(V2l p0, V2l p1, V2l p2, V2l p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l(Box2l range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l(Box2l b0, Box2l b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l(Box2l b0, Box2l b1, Box2l b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l(Box2l b0, Box2l b1, Box2l b2, Box2l b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l(V2l[] points) : this((ReadOnlySpan)points) { } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l(ReadOnlySpan points) { Min = V2l.MaxValue; Max = V2l.MinValue; if (points == null) return; var count = points.Length; for (var i = 0; i < count; i++) ExtendBy(points[i]); } /// /// Creates box as the bounding box of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l(V2l[] points, long start, long count) { if (count <= 0) { Min = Invalid.Min; Max = Invalid.Max; } else { Min = Max = points[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(points[i]); } } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l(IEnumerable points) { Min = V2l.MaxValue; Max = V2l.MinValue; if (points == null) return; foreach (V2l p in points) ExtendBy(p); } /// /// Creates box as the bounding box of given boxes. /// public Box2l(IEnumerable boxes) { Min = V2l.MaxValue; Max = V2l.MinValue; if (boxes == null) return; foreach (var box in boxes) ExtendBy(box); } /// /// Creates box from a Range1 in each direction. /// public Box2l(Range1l rangeX, Range1l rangeY) { Min.X = rangeX.Min; Max.X = rangeX.Max; Min.Y = rangeY.Min; Max.Y = rangeY.Max; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box2l(Box2i b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box2l(Box2f b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box2l(Box2d b) => new(b); #endregion #region Constants /// /// A range with crossed limits. /// public static Box2l Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V2l.MaxValue, V2l.MinValue); } /// /// The largest possible range. /// public static Box2l Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V2l.MinValue, V2l.MaxValue); } /// /// The unit interval [0, 1]. /// public static Box2l Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V2l.Zero, V2l.One); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AnyGreaterOrEqual(Max); } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AllSmallerOrEqual(Max); } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AnyGreater(Max); } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Same as Min.X. /// [XmlIgnore] public long Left { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Min.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Min.X = value; } } /// /// Same as Max.X. /// [XmlIgnore] public long Right { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.X = value; } } /// /// Same as Min.Y. /// [XmlIgnore] public long Top { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Min.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Min.Y = value; } } /// /// Same as Max.Y. /// [XmlIgnore] public long Bottom { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Y = value; } } /// /// Calculates size of the box. /// [XmlIgnore] public V2l Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (Min + value); } } public readonly V2l Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return ((Min + Max) / 2); } } [XmlIgnore] public long SizeX { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.X - Min.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.X = Min.X + value; } } public readonly Range1l RangeX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1l(Min.X, Max.X); } } [XmlIgnore] public long SizeY { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Y - Min.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Y = Min.Y + value; } } public readonly Range1l RangeY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1l(Min.Y, Max.Y); } } /// /// Index of the longest dimension of the box. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return SizeY > SizeX ? 1 : 0; } } /// /// Index of the shortest dimension of the box. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return SizeY < SizeX ? 1 : 0; } } public readonly long Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return SizeX * SizeY; } } public readonly V2l OO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min; } } public readonly V2l IO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2l(Max.X, Min.Y); } } public readonly V2l OI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2l(Min.X, Max.Y); } } public readonly V2l II { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Max; } } #endregion #region Size Manipulations /// /// Return box enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l EnlargedBy(V2l increment) { return new Box2l((Min - increment), (Max + increment)); } /// /// Return box enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l EnlargedBy(V2l deltaMin, V2l deltaMax) { return new Box2l((Min - deltaMin), (Max + deltaMax)); } /// /// Return box shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l ShrunkBy(V2l delta) { return new Box2l((Min + delta), (Max - delta)); } /// /// Return box shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l ShrunkBy(V2l deltaMin, V2l deltaMax) { return new Box2l((Min + deltaMin), (Max - deltaMax)); } /// /// Enlarges box by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(V2l delta) { Min -= delta; Max += delta; } /// /// Enlarges box by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(V2l deltaMin, V2l deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks box by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(V2l delta) { Min += delta; Max -= delta; } /// /// Shrinks box by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(V2l deltaMin, V2l deltaMax) { Min += deltaMin; Max -= deltaMax; } /// /// Returns a box enlarged by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l EnlargedBy(long delta) { return new Box2l( new V2l(Min.X - delta, Min.Y - delta), new V2l(Max.X + delta, Max.Y + delta)); } /// /// Returns a box shrunk by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l ShrunkBy(long delta) { return new Box2l( new V2l(Min.X + delta, Min.Y + delta), new V2l(Max.X - delta, Max.Y - delta)); } /// /// Returns the box enlarged by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l EnlargedBy( long deltaMinX, long deltaMaxX, long deltaMinY, long deltaMaxY) { return new Box2l( new V2l(Min.X - deltaMinX, Min.Y - deltaMinY), new V2l(Max.X + deltaMaxX, Max.Y + deltaMaxY)); } /// /// Returns the box shrunk by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l ShrunkBy( long deltaMinX, long deltaMaxX, long deltaMinY, long deltaMaxY) { return new Box2l( new V2l(Min.X + deltaMinX, Min.Y + deltaMinY), new V2l(Max.X - deltaMaxX, Max.Y - deltaMaxY)); } /// /// Enlarges box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(long delta) { Min.X -= delta; Max.X += delta; Min.Y -= delta; Max.Y += delta; } /// /// Shrinks box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(long delta) { Min.X += delta; Max.X -= delta; Min.Y += delta; Max.Y -= delta; } /// /// Enlarges the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy( long deltaMinX, long deltaMaxX, long deltaMinY, long deltaMaxY) { Min.X -= deltaMinX; Max.X += deltaMaxX; Min.Y -= deltaMinY; Max.Y += deltaMaxY; } /// /// Shrinks the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy( long deltaMinX, long deltaMaxX, long deltaMinY, long deltaMaxY) { Min.X += deltaMinX; Max.X -= deltaMaxX; Min.Y += deltaMinY; Max.Y -= deltaMaxY; } #endregion #region Box Arithmetics /// /// Return the point in the Box that is closest to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l Clamped(V2l p) { return new V2l( p.X < Min.X ? Min.X : (p.X > Max.X ? Max.X : p.X), p.Y < Min.Y ? Min.Y : (p.Y > Max.Y ? Max.Y : p.Y)); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l Lerp(float t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l Lerp(V2f t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l Lerp(double t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l Lerp(V2d t) => Fun.Lerp(t, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d InvLerp(V2l y) => Fun.InvLerp(y, Min, Max); /// /// Returns the box with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l SplitRight(V2l splitValue) { var result = new Box2l(Min, Max); if (splitValue.X > result.Min.X) result.Min.X = splitValue.X; if (splitValue.Y > result.Min.Y) result.Min.Y = splitValue.Y; return result; } /// /// Returns the box with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l SplitLeft(V2l splitValue) { var result = new Box2l(Min, Max); if (splitValue.X < result.Max.X) result.Max.X = splitValue.X; if (splitValue.Y < result.Max.Y) result.Max.Y = splitValue.Y; return result; } /// /// Returns the box with Min.X clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l SplitRight(long splitAtX) { if (splitAtX > Max.X) return Box2l.Invalid; if (splitAtX <= Min.X) return this; return new Box2l(new V2l(splitAtX, Min.Y), Max); } /// /// Returns a box with Max.X clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l SplitLeft(long splitAtX) { if (splitAtX < Min.X) return Box2l.Invalid; if (splitAtX >= Max.X) return this; return new Box2l(Min, new V2l(splitAtX, Max.Y)); } /// /// Returns the box with Min.Y clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l SplitTop(long splitAtY) { if (splitAtY > Max.Y) return Box2l.Invalid; if (splitAtY <= Min.Y) return this; return new Box2l(new V2l(Min.X, splitAtY), Max); } /// /// Returns the box with Max.Y clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l SplitBottom(long splitAtY) { if (splitAtY < Min.Y) return Box2l.Invalid; if (splitAtY >= Max.Y) return this; return new Box2l(Min, new V2l(Max.X, splitAtY)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l SplitLeftBottom(V2l splitAt) { if (splitAt.X < Min.X || splitAt.Y < Min.Y) return Box2l.Invalid; return new Box2l(Min, splitAt); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l SplitRightBottom(V2l splitAt) { if (splitAt.X > Max.X || splitAt.Y < Min.Y) return Box2l.Invalid; return new Box2l(new V2l(splitAt.X, Min.Y), new V2l(Max.X, splitAt.Y)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l SplitLeftTop(V2l splitAt) { if (splitAt.X < Min.X || splitAt.Y > Max.Y) return Box2l.Invalid; return new Box2l(new V2l(Min.X, splitAt.Y), new V2l(splitAt.X, Max.Y)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l SplitRightTop(V2l splitAt) { if (splitAt.X > Max.X || splitAt.Y > Max.Y) return Box2l.Invalid; return new Box2l(splitAt, Max); } /// /// Returns the box extended to contain the supplied box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l ExtendedBy(Box2l b) { return new Box2l( new V2l( b.Min.X < Min.X ? b.Min.X : Min.X, b.Min.Y < Min.Y ? b.Min.Y : Min.Y), new V2l( b.Max.X > Max.X ? b.Max.X : Max.X, b.Max.Y > Max.Y ? b.Max.Y : Max.Y)); } /// /// Returns the box extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l ExtendedBy(V2l v) { return new Box2l( new V2l( v.X < Min.X ? v.X : Min.X, v.Y < Min.Y ? v.Y : Min.Y), new V2l( v.X > Max.X ? v.X : Max.X, v.Y > Max.Y ? v.Y : Max.Y)); } /// /// Extends the box to contain the supplied box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Box2l box) { if (box.Min.X < Min.X) Min.X = box.Min.X; if (box.Max.X > Max.X) Max.X = box.Max.X; if (box.Min.Y < Min.Y) Min.Y = box.Min.Y; if (box.Max.Y > Max.Y) Max.Y = box.Max.Y; } /// /// Extends the box to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(V2l point) { if (point.X < Min.X) Min.X = point.X; if (point.X > Max.X) Max.X = point.X; if (point.Y < Min.Y) Min.Y = point.Y; if (point.Y > Max.Y) Max.Y = point.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l ExtendXBy(long x) { if (x < Min.X) Min.X = x; if (x > Max.X) Max.X = x; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l ExtendYBy(long y) { if (y < Min.Y) Min.Y = y; if (y > Max.Y) Max.Y = y; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l ExtendDimBy(int dim, long x) { if (x < Min[dim]) Min[dim] = x; if (x > Max[dim]) Max[dim] = x; return this; } /// /// Returns true if the box contains the given point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(V2l p) { return p.X >= Min.X && p.X <= Max.X && p.Y >= Min.Y && p.Y <= Max.Y; } /// /// Returns true if the box completely contains the other box. /// A box contains itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Box2l b) { return b.Min.X >= Min.X && b.Max.X <= Max.X && b.Min.Y >= Min.Y && b.Max.Y <= Max.Y; } /// /// Checks if the box is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l Repair() { if (Equals(Box2l.Invalid)) return this; if (Min.X > Max.X) Fun.Swap(ref Min.X, ref Max.X); if (Min.Y > Max.Y) Fun.Swap(ref Min.Y, ref Max.Y); return this; } /// /// Returns true if two boxes intersect each other (or one contains the other). /// Boxes DO NOT intersect if only touching from the outside. /// A box intersects itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box2l box) { if (Min.X >= box.Max.X) return false; if (Max.X <= box.Min.X) return false; if (Min.Y >= box.Max.Y) return false; if (Max.Y <= box.Min.Y) return false; return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box2l box, V2l eps) { if (Min.X - eps.X >= box.Max.X) return false; if (Max.X + eps.X <= box.Min.X) return false; if (Min.Y - eps.Y >= box.Max.Y) return false; if (Max.Y + eps.Y <= box.Min.Y) return false; return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box2l box, long eps) { if (Min.X - eps >= box.Max.X) return false; if (Max.X + eps <= box.Min.X) return false; if (Min.Y - eps >= box.Max.Y) return false; if (Max.Y + eps <= box.Min.Y) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2l Invalidate() { Min = V2l.MaxValue; Max = V2l.MinValue; return this; } /// /// Returns where a points coordinates are outside a given box /// /// All outside Flags [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(V2l p0) { Box.Flags bf = Box.Flags.None; if (p0.X < Min.X) bf |= Box.Flags.MinX; else if (p0.X > Max.X) bf |= Box.Flags.MaxX; if (p0.Y < Min.Y) bf |= Box.Flags.MinY; else if (p0.Y > Max.Y) bf |= Box.Flags.MaxY; return bf; } /// /// Returns where the planes of the supplied box b are outside /// of the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(Box2l b) { Box.Flags bf = Box.Flags.None; if (b.Min.X < Min.X) bf |= Box.Flags.MinX; if (b.Max.X > Max.X) bf |= Box.Flags.MaxX; if (b.Min.Y < Min.Y) bf |= Box.Flags.MinY; if (b.Max.Y > Max.Y) bf |= Box.Flags.MaxY; return bf; } /// /// Gets the minimal and maximal points of the box when seen from the /// supplied direction vector v. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void GetMinMaxInDirection(V2l v, out V2l vMin, out V2l vMax) { vMin = V2l.MinValue; vMax = V2l.MaxValue; if (v.X >= 0) { vMin.X = Min.X; vMax.X = Max.X; } else { vMin.X = Max.X; vMax.X = Min.X; } if (v.Y >= 0) { vMin.Y = Min.Y; vMax.Y = Max.Y; } else { vMin.Y = Max.Y; vMax.Y = Min.Y; } } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Box2l a, Box2l b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Box2l a, Box2l b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a box shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l operator +(Box2l box, V2l v) { return new Box2l((box.Min + v), (box.Max + v)); } /// /// Returns a box shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l operator -(Box2l box, V2l v) { return new Box2l((box.Min - v), (box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Box2l other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Box2l o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Box2l box, int i, V2l value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Box2l Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Box2l(V2l.Parse(x[0].ToString()), V2l.Parse(x[1].ToString())); } public static Box2l Parse(Text t) { return t.NestedBracketSplit(1, V2l.Parse, Box2l.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string beginB, string betweenB, string endB, string beginV, string betweenV, string endV) { fp ??= CultureInfo.InvariantCulture; return beginB + Min.ToString(format, fp, beginV, betweenV, endV) + betweenB + Max.ToString(format, fp, beginV, betweenV, endV) + endB; } #endregion #region Static Factories /// /// Returns new box [0, size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l FromSize(V2l size) { return new Box2l(V2l.Zero, size); } /// /// Returns new box [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l FromMinAndSize(V2l min, V2l size) { return new Box2l(min, min + size); } /// /// Returns new box [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l FromCenterAndSize(V2l center, V2l size) { return new Box2l(center - size / 2, center + size / 2); } /// /// Returns new box [0, iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l FromSize(ISize2l iSize) { return new Box2l( V2l.Zero, iSize.Size2l); } /// /// Returns new box [min, min + iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l FromMinAndSize(V2l min, ISize2l iSize) { return new Box2l( min, min + iSize.Size2l); } /// /// Returns new box [center - iSize / 2, center + iSize / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l FromCenterAndSize(V2l center, ISize2l iSize) { var size = iSize.Size2l; return new Box2l(center - size / 2, center + size / 2); } /// /// Creates box from 2 points which need not be Min and Max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l FromPoints(V2l p0, V2l p1) { return new Box2l(Fun.Min(p0, p1), Fun.Max(p0, p1)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l FromSize(long width, long height) { return Box2l.FromSize(new V2l(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l FromMinAndSize(V2l min, long width, long height) { return new Box2l(min, min + new V2l(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l FromMinAndSize( long minX, long minY, long width, long height ) { return Box2l.FromMinAndSize(new V2l(minX, minY), new V2l(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l FromCenterAndSize(V2l center, long width, long height) { return FromCenterAndSize(center, new V2l(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l FromCenterAndSize( long centerX, long centerY, long width, long height ) { return FromCenterAndSize(new V2l(centerX, centerY), new V2l(width, height)); } #endregion #region Transforms [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l Translated(V2l shift) { return IsInvalid ? Box2l.Invalid : new Box2l(Min + shift, Max + shift); } /// /// Returns a scaled box. WARNING: scaling is performed around the origin! /// A negative scale factor will resut in an invalid box! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2l Scaled(V2l factor) { return IsInvalid ? Box2l.Invalid : new Box2l(Min * factor, Max * factor); } /// /// Transforms the box by the given transformation matrix. /// NOTE: Performs IsValid check at 10% CPU time overhead. /// -> Empty bounds (crossed min and max) will remain empty. /// public readonly Box2d Transformed(M33d trafo) { if (Min.X > Max.X || Min.Y > Max.Y) return Box2d.Invalid; var t = new V2d(trafo.M02, trafo.M12); var res = new Box2d(t, t); double av, bv; av = trafo.M00 * Min.X; bv = trafo.M00 * Max.X; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M01 * Min.Y; bv = trafo.M01 * Max.Y; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M10 * Min.X; bv = trafo.M10 * Max.X; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } av = trafo.M11 * Min.Y; bv = trafo.M11 * Max.Y; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } return res; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d Transformed(Trafo2d trafo) { return Transformed(trafo.Forward); } #endregion #region Corners /// /// Return the corner of the box with the given index. The corner /// index is constructed in such a way, that bit 0 enumerates the /// x coordinate (0 ... min, 1 ... max), bit 1 enumerates the y /// coordinate, and bit 2 enumerates the z coordinate. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l Corner(int index) { return new V2l( (index & 1) == 0 ? Min.X : Max.X, (index & 2) == 0 ? Min.Y : Max.Y); } /// /// Computes the corners of the box and returns them in an array. /// The order of the corners is determined by their index which is /// constructed as in the method . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l[] ComputeCorners() { return [ Min, new(Max.X, Min.Y), new(Min.X, Max.Y), Max ]; } // TODO: Comment and implement for dimensions other than 2. [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l[] ComputeCornersCCW() { return [ Min, new(Max.X, Min.Y), Max, new(Min.X, Max.Y), ]; } /// /// Enumeration of the corners of the box. /// public readonly IEnumerable Corners { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return Min; yield return new V2l(Max.X, Min.Y); yield return new V2l(Min.X, Max.Y); yield return Max; } } #endregion #region Swizzle methods #endregion #region Enumerators /// /// Returns all points from [Min,Max[ with X-Variable in the outer loop. /// public readonly IEnumerable EnumerateInsidePoints() { var p = new V2l(); for (p.X = Min.X; p.X < Max.X; p.X++) for (p.Y = Min.Y; p.Y < Max.Y; p.Y++) yield return p; } #endregion #region IBoundingBox2l Members public readonly Box2l BoundingBox2l { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this; } } #endregion #region IBoundingCircle2d Members public readonly Circle2d BoundingCircle2d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => IsInvalid ? Circle2d.Invalid : new Circle2d((V2d)Center, 0.5 * Size.Length); } #endregion #region ISize2l Members public readonly V2l Size2l { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Size; } } #endregion } public static partial class Box { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l Union(this Box2l a, Box2l b) { return new Box2l(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l Intersection(this Box2l a, Box2l b) { return new Box2l(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } #endregion #region Bounding box for arrays /// /// Returns the bounding box of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l GetBoundingBox(this V2l[] pointArray) { return pointArray.GetBoundingBox(0, pointArray.LongLength); } /// /// Returns the bounding box of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l GetBoundingBox(this V2l[] pointArray, long count) { return pointArray.GetBoundingBox(0, count); } /// /// Returns the bounding box of count elements of the array starting at start. /// public static Box2l GetBoundingBox( this V2l[] pointArray, long start, long count) { if (count <= 0) return Box2l.Invalid; var box = new Box2l(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding box of count elements of the array starting at start. /// public static Box2l GetBoundingBox(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Box2l.Invalid; var box = new Box2l(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding box for lists /// /// Returns the bounding box of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l GetBoundingBox(this List pointList) { return pointList.GetBoundingBox(pointList.Count); } /// /// Returns the bounding box of the first count elements of the list. /// public static Box2l GetBoundingBox(this List pointList, int count) { if (count <= 0) return Box2l.Invalid; var box = new Box2l(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding box for indexed arrays /// /// Returns the bounding box of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l GetBoundingBox(this int[] indexArray, V2l[] pointArray) { return indexArray.GetBoundingBox(0, indexArray.Length, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l GetBoundingBox(this int[] indexArray, int count, V2l[] pointArray) { return indexArray.GetBoundingBox(0, count, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box2l GetBoundingBox(this int[] indexArray, int start, int count, V2l[] pointArray) { if (count <= 0) return Box2l.Invalid; var box = new Box2l(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box2l GetBoundingBox(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Box2l.Invalid; var box = new Box2l(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l GetBoundingBox(this long[] indexArray, V2l[] pointArray) { return indexArray.GetBoundingBox(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2l GetBoundingBox(this long[] indexArray, long count, V2l[] pointArray) { return indexArray.GetBoundingBox(0, count, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box2l GetBoundingBox(this long[] indexArray, long start, long count, V2l[] pointArray) { if (count <= 0) return Box2l.Invalid; var box = new Box2l(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box2l GetBoundingBox(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Box2l.Invalid; var box = new Box2l(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding box for IEnumerable /// /// Returns the bounding box of the elements of the collection. /// public static Box2l GetBoundingBox(this IEnumerable points) { var box = Box2l.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Box2l a, Box2l b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Box2l a, Box2l b, long tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Box2f [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Box2f : IEquatable, IRange, IBoundingBox2f, ISize2f, IBoundingCircle2f, IFormattable { [DataMember] public V2f Min; [DataMember] public V2f Max; #region Constructors /// /// Construct a Box2f from a Box2i. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f(Box2i b) { Min = (V2f) b.Min; Max = (V2f) b.Max; } /// /// Construct a Box2f from a Box2l. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f(Box2l b) { Min = (V2f) b.Min; Max = (V2f) b.Max; } /// /// Construct a Box2f from a Box2d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f(Box2d b) { Min = (V2f) b.Min; Max = (V2f) b.Max; } /// /// Creates a box from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f(V2f min, V2f max) { Min = min; Max = max; } /// /// Creates a box from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f(float minX, float minY, float maxX, float maxY) { Min.X = minX; Min.Y = minY; Max.X = maxX; Max.Y = maxY; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f(V2f pnt) { Min = pnt; Max = pnt; } /// /// Creates a box from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f(V2f p0, V2f p1, V2f p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a box from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f(V2f p0, V2f p1, V2f p2, V2f p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f(Box2f range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f(Box2f b0, Box2f b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f(Box2f b0, Box2f b1, Box2f b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f(Box2f b0, Box2f b1, Box2f b2, Box2f b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f(V2f[] points) : this((ReadOnlySpan)points) { } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f(ReadOnlySpan points) { Min = V2f.MaxValue; Max = V2f.MinValue; if (points == null) return; var count = points.Length; for (var i = 0; i < count; i++) ExtendBy(points[i]); } /// /// Creates box as the bounding box of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f(V2f[] points, long start, long count) { if (count <= 0) { Min = Invalid.Min; Max = Invalid.Max; } else { Min = Max = points[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(points[i]); } } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f(IEnumerable points) { Min = V2f.MaxValue; Max = V2f.MinValue; if (points == null) return; foreach (V2f p in points) ExtendBy(p); } /// /// Creates box as the bounding box of given boxes. /// public Box2f(IEnumerable boxes) { Min = V2f.MaxValue; Max = V2f.MinValue; if (boxes == null) return; foreach (var box in boxes) ExtendBy(box); } /// /// Creates box from a Range1 in each direction. /// public Box2f(Range1f rangeX, Range1f rangeY) { Min.X = rangeX.Min; Max.X = rangeX.Max; Min.Y = rangeY.Min; Max.Y = rangeY.Max; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box2f(Box2i b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box2f(Box2l b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box2f(Box2d b) => new(b); #endregion #region Constants /// /// A range with crossed limits. /// public static Box2f Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V2f.MaxValue, V2f.MinValue); } /// /// The largest possible range. /// public static Box2f Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V2f.MinValue, V2f.MaxValue); } /// /// The unit interval [0, 1]. /// public static Box2f Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V2f.Zero, V2f.One); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AnyGreaterOrEqual(Max); } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AllSmallerOrEqual(Max); } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AnyGreater(Max) || Min.IsNaN || Max.IsNaN; } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Same as Min.X. /// [XmlIgnore] public float Left { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Min.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Min.X = value; } } /// /// Same as Max.X. /// [XmlIgnore] public float Right { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.X = value; } } /// /// Same as Min.Y. /// [XmlIgnore] public float Top { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Min.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Min.Y = value; } } /// /// Same as Max.Y. /// [XmlIgnore] public float Bottom { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Y = value; } } /// /// Calculates size of the box. /// [XmlIgnore] public V2f Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (Min + value); } } public readonly V2f Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return ((Min + Max) / 2); } } [XmlIgnore] public float SizeX { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.X - Min.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.X = Min.X + value; } } public readonly Range1f RangeX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1f(Min.X, Max.X); } } [XmlIgnore] public float SizeY { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Y - Min.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Y = Min.Y + value; } } public readonly Range1f RangeY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1f(Min.Y, Max.Y); } } /// /// Index of the longest dimension of the box. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return SizeY > SizeX ? 1 : 0; } } /// /// Index of the shortest dimension of the box. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return SizeY < SizeX ? 1 : 0; } } public readonly float Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return SizeX * SizeY; } } public readonly V2f OO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min; } } public readonly V2f IO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2f(Max.X, Min.Y); } } public readonly V2f OI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2f(Min.X, Max.Y); } } public readonly V2f II { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Max; } } #endregion #region Size Manipulations /// /// Return box enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f EnlargedBy(V2f increment) { return new Box2f((Min - increment), (Max + increment)); } /// /// Return box enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f EnlargedBy(V2f deltaMin, V2f deltaMax) { return new Box2f((Min - deltaMin), (Max + deltaMax)); } /// /// Return box shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f ShrunkBy(V2f delta) { return new Box2f((Min + delta), (Max - delta)); } /// /// Return box shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f ShrunkBy(V2f deltaMin, V2f deltaMax) { return new Box2f((Min + deltaMin), (Max - deltaMax)); } /// /// Enlarges box by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(V2f delta) { Min -= delta; Max += delta; } /// /// Enlarges box by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(V2f deltaMin, V2f deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks box by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(V2f delta) { Min += delta; Max -= delta; } /// /// Shrinks box by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(V2f deltaMin, V2f deltaMax) { Min += deltaMin; Max -= deltaMax; } /// /// Returns a box enlarged by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f EnlargedBy(float delta) { return new Box2f( new V2f(Min.X - delta, Min.Y - delta), new V2f(Max.X + delta, Max.Y + delta)); } /// /// Returns a box shrunk by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f ShrunkBy(float delta) { return new Box2f( new V2f(Min.X + delta, Min.Y + delta), new V2f(Max.X - delta, Max.Y - delta)); } /// /// Returns the box enlarged by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f EnlargedBy( float deltaMinX, float deltaMaxX, float deltaMinY, float deltaMaxY) { return new Box2f( new V2f(Min.X - deltaMinX, Min.Y - deltaMinY), new V2f(Max.X + deltaMaxX, Max.Y + deltaMaxY)); } /// /// Returns the box shrunk by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f ShrunkBy( float deltaMinX, float deltaMaxX, float deltaMinY, float deltaMaxY) { return new Box2f( new V2f(Min.X + deltaMinX, Min.Y + deltaMinY), new V2f(Max.X - deltaMaxX, Max.Y - deltaMaxY)); } /// /// Enlarges box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(float delta) { Min.X -= delta; Max.X += delta; Min.Y -= delta; Max.Y += delta; } /// /// Shrinks box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(float delta) { Min.X += delta; Max.X -= delta; Min.Y += delta; Max.Y -= delta; } /// /// Enlarges the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy( float deltaMinX, float deltaMaxX, float deltaMinY, float deltaMaxY) { Min.X -= deltaMinX; Max.X += deltaMaxX; Min.Y -= deltaMinY; Max.Y += deltaMaxY; } /// /// Shrinks the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy( float deltaMinX, float deltaMaxX, float deltaMinY, float deltaMaxY) { Min.X += deltaMinX; Max.X -= deltaMaxX; Min.Y += deltaMinY; Max.Y -= deltaMaxY; } /// /// Return box scaled by the supplied factor around its center. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f ScaledFromCenterBy(float factor) { var size = Size; var increment = (size * factor - size) / 2; return new Box2f(Min - increment, Max + increment); } /// /// Return box scaled by the supplied factor around its center. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f ScaledFromCenterBy(V2f vectorFactor) { var size = Size; var increment = (size * vectorFactor - size) / 2; return new Box2f(Min - increment, Max + increment); } /// /// Return a box enlarged in all directions by the supplied epsilon which is /// measured with respect to the box diagonal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f EnlargedByRelativeEps(float eps) { return EnlargedBy(eps * Size.Length); } /// /// Enlarge the box in all directions by the supplied epsilon which is /// measured with respect to the box diagonal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeByRelativeEps(float eps) { EnlargeBy(eps * Size.Length); } #endregion #region Box Arithmetics /// /// Return the point in the Box that is closest to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f Clamped(V2f p) { return new V2f( p.X < Min.X ? Min.X : (p.X > Max.X ? Max.X : p.X), p.Y < Min.Y ? Min.Y : (p.Y > Max.Y ? Max.Y : p.Y)); } /// /// Returns the squared distance to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double DistanceSquared(V2f p) { return (p.X < Min.X ? (Min.X - p.X) * (Min.X - p.X) : (p.X > Max.X ? (p.X - Max.X) * (p.X - Max.X) : 0.0)) + (p.Y < Min.Y ? (Min.Y - p.Y) * (Min.Y - p.Y) : (p.Y > Max.Y ? (p.Y - Max.Y) * (p.Y - Max.Y) : 0.0)); } /// /// Returns the distance to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double Distance(V2f p) { return Fun.Sqrt( (p.X < Min.X ? (Min.X - p.X) * (Min.X - p.X) : (p.X > Max.X ? (p.X - Max.X) * (p.X - Max.X) : 0.0)) + (p.Y < Min.Y ? (Min.Y - p.Y) * (Min.Y - p.Y) : (p.Y > Max.Y ? (p.Y - Max.Y) * (p.Y - Max.Y) : 0.0))); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f Lerp(float x) => Fun.Lerp(x, Min, Max); /// /// Interpolate linearly in each dimension. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f Lerp(V2f p) => Fun.Lerp(p, Min, Max); /// /// Interpolate linearly in each dimension. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f Lerp(float x, float y) => Fun.Lerp(new V2f(x, y), Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f InvLerp(V2f p) => Fun.InvLerp(p, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f InvLerp(float x, float y) => Fun.InvLerp(new V2f(x, y), Min, Max); /// /// Returns the box with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f SplitRight(V2f splitValue) { var result = new Box2f(Min, Max); if (splitValue.X > result.Min.X) result.Min.X = splitValue.X; if (splitValue.Y > result.Min.Y) result.Min.Y = splitValue.Y; return result; } /// /// Returns the box with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f SplitLeft(V2f splitValue) { var result = new Box2f(Min, Max); if (splitValue.X < result.Max.X) result.Max.X = splitValue.X; if (splitValue.Y < result.Max.Y) result.Max.Y = splitValue.Y; return result; } /// /// Returns the box with Min.X clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f SplitRight(float splitAtX) { if (splitAtX > Max.X) return Box2f.Invalid; if (splitAtX <= Min.X) return this; return new Box2f(new V2f(splitAtX, Min.Y), Max); } /// /// Returns a box with Max.X clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f SplitLeft(float splitAtX) { if (splitAtX < Min.X) return Box2f.Invalid; if (splitAtX >= Max.X) return this; return new Box2f(Min, new V2f(splitAtX, Max.Y)); } /// /// Returns the box with Min.Y clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f SplitTop(float splitAtY) { if (splitAtY > Max.Y) return Box2f.Invalid; if (splitAtY <= Min.Y) return this; return new Box2f(new V2f(Min.X, splitAtY), Max); } /// /// Returns the box with Max.Y clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f SplitBottom(float splitAtY) { if (splitAtY < Min.Y) return Box2f.Invalid; if (splitAtY >= Max.Y) return this; return new Box2f(Min, new V2f(Max.X, splitAtY)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f SplitLeftBottom(V2f splitAt) { if (splitAt.X < Min.X || splitAt.Y < Min.Y) return Box2f.Invalid; return new Box2f(Min, splitAt); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f SplitRightBottom(V2f splitAt) { if (splitAt.X > Max.X || splitAt.Y < Min.Y) return Box2f.Invalid; return new Box2f(new V2f(splitAt.X, Min.Y), new V2f(Max.X, splitAt.Y)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f SplitLeftTop(V2f splitAt) { if (splitAt.X < Min.X || splitAt.Y > Max.Y) return Box2f.Invalid; return new Box2f(new V2f(Min.X, splitAt.Y), new V2f(splitAt.X, Max.Y)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f SplitRightTop(V2f splitAt) { if (splitAt.X > Max.X || splitAt.Y > Max.Y) return Box2f.Invalid; return new Box2f(splitAt, Max); } /// /// Returns the box extended to contain the supplied box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f ExtendedBy(Box2f b) { return new Box2f( new V2f( b.Min.X < Min.X ? b.Min.X : Min.X, b.Min.Y < Min.Y ? b.Min.Y : Min.Y), new V2f( b.Max.X > Max.X ? b.Max.X : Max.X, b.Max.Y > Max.Y ? b.Max.Y : Max.Y)); } /// /// Returns the box extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f ExtendedBy(V2f v) { return new Box2f( new V2f( v.X < Min.X ? v.X : Min.X, v.Y < Min.Y ? v.Y : Min.Y), new V2f( v.X > Max.X ? v.X : Max.X, v.Y > Max.Y ? v.Y : Max.Y)); } /// /// Extends the box to contain the supplied box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Box2f box) { if (box.Min.X < Min.X) Min.X = box.Min.X; if (box.Max.X > Max.X) Max.X = box.Max.X; if (box.Min.Y < Min.Y) Min.Y = box.Min.Y; if (box.Max.Y > Max.Y) Max.Y = box.Max.Y; } /// /// Extends the box to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(V2f point) { if (point.X < Min.X) Min.X = point.X; if (point.X > Max.X) Max.X = point.X; if (point.Y < Min.Y) Min.Y = point.Y; if (point.Y > Max.Y) Max.Y = point.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f ExtendXBy(float x) { if (x < Min.X) Min.X = x; if (x > Max.X) Max.X = x; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f ExtendYBy(float y) { if (y < Min.Y) Min.Y = y; if (y > Max.Y) Max.Y = y; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f ExtendDimBy(int dim, float x) { if (x < Min[dim]) Min[dim] = x; if (x > Max[dim]) Max[dim] = x; return this; } /// /// Returns true if the box contains the given point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(V2f p) { return p.X >= Min.X && p.X <= Max.X && p.Y >= Min.Y && p.Y <= Max.Y; } /// /// Returns true if the box completely contains the other box. /// A box contains itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Box2f b) { return b.Min.X >= Min.X && b.Max.X <= Max.X && b.Min.Y >= Min.Y && b.Max.Y <= Max.Y; } /// /// Checks if the box is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f Repair() { if (Equals(Box2f.Invalid)) return this; if (Min.X > Max.X) Fun.Swap(ref Min.X, ref Max.X); if (Min.Y > Max.Y) Fun.Swap(ref Min.Y, ref Max.Y); return this; } /// /// Returns true if two boxes intersect each other (or one contains the other). /// Boxes DO NOT intersect if only touching from the outside. /// A box intersects itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box2f box) { if (Min.X >= box.Max.X) return false; if (Max.X <= box.Min.X) return false; if (Min.Y >= box.Max.Y) return false; if (Max.Y <= box.Min.Y) return false; return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box2f box, V2f eps) { if (Min.X - eps.X >= box.Max.X) return false; if (Max.X + eps.X <= box.Min.X) return false; if (Min.Y - eps.Y >= box.Max.Y) return false; if (Max.Y + eps.Y <= box.Min.Y) return false; return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box2f box, float eps) { if (Min.X - eps >= box.Max.X) return false; if (Max.X + eps <= box.Min.X) return false; if (Min.Y - eps >= box.Max.Y) return false; if (Max.Y + eps <= box.Min.Y) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2f Invalidate() { Min = V2f.MaxValue; Max = V2f.MinValue; return this; } /// /// Returns where a points coordinates are outside a given box /// /// All outside Flags [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(V2f p0) { Box.Flags bf = Box.Flags.None; if (p0.X < Min.X) bf |= Box.Flags.MinX; else if (p0.X > Max.X) bf |= Box.Flags.MaxX; if (p0.Y < Min.Y) bf |= Box.Flags.MinY; else if (p0.Y > Max.Y) bf |= Box.Flags.MaxY; return bf; } /// /// Returns where the planes of the supplied box b are outside /// of the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(Box2f b) { Box.Flags bf = Box.Flags.None; if (b.Min.X < Min.X) bf |= Box.Flags.MinX; if (b.Max.X > Max.X) bf |= Box.Flags.MaxX; if (b.Min.Y < Min.Y) bf |= Box.Flags.MinY; if (b.Max.Y > Max.Y) bf |= Box.Flags.MaxY; return bf; } /// /// Gets the minimal and maximal points of the box when seen from the /// supplied direction vector v. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void GetMinMaxInDirection(V2f v, out V2f vMin, out V2f vMax) { vMin = V2f.MinValue; vMax = V2f.MaxValue; if (v.X >= 0) { vMin.X = Min.X; vMax.X = Max.X; } else { vMin.X = Max.X; vMax.X = Min.X; } if (v.Y >= 0) { vMin.Y = Min.Y; vMax.Y = Max.Y; } else { vMin.Y = Max.Y; vMax.Y = Min.Y; } } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Box2f a, Box2f b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Box2f a, Box2f b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a box shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f operator +(Box2f box, V2f v) { return new Box2f((box.Min + v), (box.Max + v)); } /// /// Returns a box shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f operator -(Box2f box, V2f v) { return new Box2f((box.Min - v), (box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Box2f other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Box2f o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Box2f box, int i, V2f value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Box2f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Box2f(V2f.Parse(x[0].ToString()), V2f.Parse(x[1].ToString())); } public static Box2f Parse(Text t) { return t.NestedBracketSplit(1, V2f.Parse, Box2f.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string beginB, string betweenB, string endB, string beginV, string betweenV, string endV) { fp ??= CultureInfo.InvariantCulture; return beginB + Min.ToString(format, fp, beginV, betweenV, endV) + betweenB + Max.ToString(format, fp, beginV, betweenV, endV) + endB; } #endregion #region Static Factories /// /// Returns new box [0, size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f FromSize(V2f size) { return new Box2f(V2f.Zero, size); } /// /// Returns new box [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f FromMinAndSize(V2f min, V2f size) { return new Box2f(min, min + size); } /// /// Returns new box [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f FromCenterAndSize(V2f center, V2f size) { return new Box2f(center - size / 2, center + size / 2); } /// /// Returns new box [0, iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f FromSize(ISize2f iSize) { return new Box2f( V2f.Zero, iSize.Size2f); } /// /// Returns new box [min, min + iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f FromMinAndSize(V2f min, ISize2f iSize) { return new Box2f( min, min + iSize.Size2f); } /// /// Returns new box [center - iSize / 2, center + iSize / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f FromCenterAndSize(V2f center, ISize2f iSize) { var size = iSize.Size2f; return new Box2f(center - size / 2, center + size / 2); } /// /// Creates box from 2 points which need not be Min and Max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f FromPoints(V2f p0, V2f p1) { return new Box2f(Fun.Min(p0, p1), Fun.Max(p0, p1)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f FromSize(float width, float height) { return Box2f.FromSize(new V2f(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f FromMinAndSize(V2f min, float width, float height) { return new Box2f(min, min + new V2f(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f FromMinAndSize( float minX, float minY, float width, float height ) { return Box2f.FromMinAndSize(new V2f(minX, minY), new V2f(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f FromCenterAndSize(V2f center, float width, float height) { return FromCenterAndSize(center, new V2f(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f FromCenterAndSize( float centerX, float centerY, float width, float height ) { return FromCenterAndSize(new V2f(centerX, centerY), new V2f(width, height)); } #endregion #region Transforms [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f Translated(V2f shift) { return IsInvalid ? Box2f.Invalid : new Box2f(Min + shift, Max + shift); } /// /// Returns a scaled box. WARNING: scaling is performed around the origin! /// A negative scale factor will resut in an invalid box! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f Scaled(V2f factor) { return IsInvalid ? Box2f.Invalid : new Box2f(Min * factor, Max * factor); } /// /// Transforms the box by the given transformation matrix. /// NOTE: Performs IsValid check at 10% CPU time overhead. /// -> Empty bounds (crossed min and max) will remain empty. /// public readonly Box2f Transformed(M33f trafo) { if (Min.X > Max.X || Min.Y > Max.Y) return Box2f.Invalid; var t = new V2f(trafo.M02, trafo.M12); var res = new Box2f(t, t); float av, bv; av = trafo.M00 * Min.X; bv = trafo.M00 * Max.X; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M01 * Min.Y; bv = trafo.M01 * Max.Y; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M10 * Min.X; bv = trafo.M10 * Max.X; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } av = trafo.M11 * Min.Y; bv = trafo.M11 * Max.Y; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } return res; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2f Transformed(Trafo2f trafo) { return Transformed(trafo.Forward); } #endregion #region Corners /// /// Return the corner of the box with the given index. The corner /// index is constructed in such a way, that bit 0 enumerates the /// x coordinate (0 ... min, 1 ... max), bit 1 enumerates the y /// coordinate, and bit 2 enumerates the z coordinate. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f Corner(int index) { return new V2f( (index & 1) == 0 ? Min.X : Max.X, (index & 2) == 0 ? Min.Y : Max.Y); } /// /// Computes the corners of the box and returns them in an array. /// The order of the corners is determined by their index which is /// constructed as in the method . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f[] ComputeCorners() { return [ Min, new(Max.X, Min.Y), new(Min.X, Max.Y), Max ]; } // TODO: Comment and implement for dimensions other than 2. [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f[] ComputeCornersCCW() { return [ Min, new(Max.X, Min.Y), Max, new(Min.X, Max.Y), ]; } /// /// Enumeration of the corners of the box. /// public readonly IEnumerable Corners { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return Min; yield return new V2f(Max.X, Min.Y); yield return new V2f(Min.X, Max.Y); yield return Max; } } #endregion #region Swizzle methods #endregion #region Enumerators #endregion #region IBoundingBox2f Members public readonly Box2f BoundingBox2f { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this; } } #endregion #region IBoundingCircle2f Members public readonly Circle2f BoundingCircle2f { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => IsInvalid ? Circle2f.Invalid : new Circle2f(Center, 0.5f * Size.Length); } #endregion #region ISize2f Members public readonly V2f Size2f { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Size; } } #endregion } public static partial class Box { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f Union(this Box2f a, Box2f b) { return new Box2f(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f Intersection(this Box2f a, Box2f b) { return new Box2f(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } #endregion #region Bounding box for arrays /// /// Returns the bounding box of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f GetBoundingBox(this V2f[] pointArray) { return pointArray.GetBoundingBox(0, pointArray.LongLength); } /// /// Returns the bounding box of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f GetBoundingBox(this V2f[] pointArray, long count) { return pointArray.GetBoundingBox(0, count); } /// /// Returns the bounding box of count elements of the array starting at start. /// public static Box2f GetBoundingBox( this V2f[] pointArray, long start, long count) { if (count <= 0) return Box2f.Invalid; var box = new Box2f(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding box of count elements of the array starting at start. /// public static Box2f GetBoundingBox(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Box2f.Invalid; var box = new Box2f(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding box for lists /// /// Returns the bounding box of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f GetBoundingBox(this List pointList) { return pointList.GetBoundingBox(pointList.Count); } /// /// Returns the bounding box of the first count elements of the list. /// public static Box2f GetBoundingBox(this List pointList, int count) { if (count <= 0) return Box2f.Invalid; var box = new Box2f(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding box for indexed arrays /// /// Returns the bounding box of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f GetBoundingBox(this int[] indexArray, V2f[] pointArray) { return indexArray.GetBoundingBox(0, indexArray.Length, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f GetBoundingBox(this int[] indexArray, int count, V2f[] pointArray) { return indexArray.GetBoundingBox(0, count, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box2f GetBoundingBox(this int[] indexArray, int start, int count, V2f[] pointArray) { if (count <= 0) return Box2f.Invalid; var box = new Box2f(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box2f GetBoundingBox(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Box2f.Invalid; var box = new Box2f(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f GetBoundingBox(this long[] indexArray, V2f[] pointArray) { return indexArray.GetBoundingBox(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2f GetBoundingBox(this long[] indexArray, long count, V2f[] pointArray) { return indexArray.GetBoundingBox(0, count, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box2f GetBoundingBox(this long[] indexArray, long start, long count, V2f[] pointArray) { if (count <= 0) return Box2f.Invalid; var box = new Box2f(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box2f GetBoundingBox(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Box2f.Invalid; var box = new Box2f(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding box for IEnumerable /// /// Returns the bounding box of the elements of the collection. /// public static Box2f GetBoundingBox(this IEnumerable points) { var box = Box2f.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Box2f a, Box2f b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Box2f a, Box2f b, float tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Box2d [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Box2d : IEquatable, IRange, IBoundingBox2d, ISize2d, IBoundingCircle2d, IFormattable { [DataMember] public V2d Min; [DataMember] public V2d Max; #region Constructors /// /// Construct a Box2d from a Box2i. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d(Box2i b) { Min = (V2d) b.Min; Max = (V2d) b.Max; } /// /// Construct a Box2d from a Box2l. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d(Box2l b) { Min = (V2d) b.Min; Max = (V2d) b.Max; } /// /// Construct a Box2d from a Box2f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d(Box2f b) { Min = (V2d) b.Min; Max = (V2d) b.Max; } /// /// Creates a box from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d(V2d min, V2d max) { Min = min; Max = max; } /// /// Creates a box from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d(double minX, double minY, double maxX, double maxY) { Min.X = minX; Min.Y = minY; Max.X = maxX; Max.Y = maxY; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d(V2d pnt) { Min = pnt; Max = pnt; } /// /// Creates a box from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d(V2d p0, V2d p1, V2d p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a box from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d(V2d p0, V2d p1, V2d p2, V2d p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d(Box2d range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d(Box2d b0, Box2d b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d(Box2d b0, Box2d b1, Box2d b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d(Box2d b0, Box2d b1, Box2d b2, Box2d b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d(V2d[] points) : this((ReadOnlySpan)points) { } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d(ReadOnlySpan points) { Min = V2d.MaxValue; Max = V2d.MinValue; if (points == null) return; var count = points.Length; for (var i = 0; i < count; i++) ExtendBy(points[i]); } /// /// Creates box as the bounding box of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d(V2d[] points, long start, long count) { if (count <= 0) { Min = Invalid.Min; Max = Invalid.Max; } else { Min = Max = points[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(points[i]); } } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d(IEnumerable points) { Min = V2d.MaxValue; Max = V2d.MinValue; if (points == null) return; foreach (V2d p in points) ExtendBy(p); } /// /// Creates box as the bounding box of given boxes. /// public Box2d(IEnumerable boxes) { Min = V2d.MaxValue; Max = V2d.MinValue; if (boxes == null) return; foreach (var box in boxes) ExtendBy(box); } /// /// Creates box from a Range1 in each direction. /// public Box2d(Range1d rangeX, Range1d rangeY) { Min.X = rangeX.Min; Max.X = rangeX.Max; Min.Y = rangeY.Min; Max.Y = rangeY.Max; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box2d(Box2i b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box2d(Box2l b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box2d(Box2f b) => new(b); #endregion #region Constants /// /// A range with crossed limits. /// public static Box2d Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V2d.MaxValue, V2d.MinValue); } /// /// The largest possible range. /// public static Box2d Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V2d.MinValue, V2d.MaxValue); } /// /// The unit interval [0, 1]. /// public static Box2d Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V2d.Zero, V2d.One); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AnyGreaterOrEqual(Max); } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AllSmallerOrEqual(Max); } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AnyGreater(Max) || Min.IsNaN || Max.IsNaN; } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Same as Min.X. /// [XmlIgnore] public double Left { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Min.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Min.X = value; } } /// /// Same as Max.X. /// [XmlIgnore] public double Right { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.X = value; } } /// /// Same as Min.Y. /// [XmlIgnore] public double Top { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Min.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Min.Y = value; } } /// /// Same as Max.Y. /// [XmlIgnore] public double Bottom { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Y = value; } } /// /// Calculates size of the box. /// [XmlIgnore] public V2d Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (Min + value); } } public readonly V2d Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return ((Min + Max) / 2); } } [XmlIgnore] public double SizeX { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.X - Min.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.X = Min.X + value; } } public readonly Range1d RangeX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1d(Min.X, Max.X); } } [XmlIgnore] public double SizeY { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Y - Min.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Y = Min.Y + value; } } public readonly Range1d RangeY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1d(Min.Y, Max.Y); } } /// /// Index of the longest dimension of the box. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return SizeY > SizeX ? 1 : 0; } } /// /// Index of the shortest dimension of the box. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return SizeY < SizeX ? 1 : 0; } } public readonly double Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return SizeX * SizeY; } } public readonly V2d OO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min; } } public readonly V2d IO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2d(Max.X, Min.Y); } } public readonly V2d OI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2d(Min.X, Max.Y); } } public readonly V2d II { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Max; } } #endregion #region Size Manipulations /// /// Return box enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d EnlargedBy(V2d increment) { return new Box2d((Min - increment), (Max + increment)); } /// /// Return box enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d EnlargedBy(V2d deltaMin, V2d deltaMax) { return new Box2d((Min - deltaMin), (Max + deltaMax)); } /// /// Return box shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d ShrunkBy(V2d delta) { return new Box2d((Min + delta), (Max - delta)); } /// /// Return box shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d ShrunkBy(V2d deltaMin, V2d deltaMax) { return new Box2d((Min + deltaMin), (Max - deltaMax)); } /// /// Enlarges box by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(V2d delta) { Min -= delta; Max += delta; } /// /// Enlarges box by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(V2d deltaMin, V2d deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks box by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(V2d delta) { Min += delta; Max -= delta; } /// /// Shrinks box by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(V2d deltaMin, V2d deltaMax) { Min += deltaMin; Max -= deltaMax; } /// /// Returns a box enlarged by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d EnlargedBy(double delta) { return new Box2d( new V2d(Min.X - delta, Min.Y - delta), new V2d(Max.X + delta, Max.Y + delta)); } /// /// Returns a box shrunk by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d ShrunkBy(double delta) { return new Box2d( new V2d(Min.X + delta, Min.Y + delta), new V2d(Max.X - delta, Max.Y - delta)); } /// /// Returns the box enlarged by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d EnlargedBy( double deltaMinX, double deltaMaxX, double deltaMinY, double deltaMaxY) { return new Box2d( new V2d(Min.X - deltaMinX, Min.Y - deltaMinY), new V2d(Max.X + deltaMaxX, Max.Y + deltaMaxY)); } /// /// Returns the box shrunk by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d ShrunkBy( double deltaMinX, double deltaMaxX, double deltaMinY, double deltaMaxY) { return new Box2d( new V2d(Min.X + deltaMinX, Min.Y + deltaMinY), new V2d(Max.X - deltaMaxX, Max.Y - deltaMaxY)); } /// /// Enlarges box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(double delta) { Min.X -= delta; Max.X += delta; Min.Y -= delta; Max.Y += delta; } /// /// Shrinks box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(double delta) { Min.X += delta; Max.X -= delta; Min.Y += delta; Max.Y -= delta; } /// /// Enlarges the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy( double deltaMinX, double deltaMaxX, double deltaMinY, double deltaMaxY) { Min.X -= deltaMinX; Max.X += deltaMaxX; Min.Y -= deltaMinY; Max.Y += deltaMaxY; } /// /// Shrinks the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy( double deltaMinX, double deltaMaxX, double deltaMinY, double deltaMaxY) { Min.X += deltaMinX; Max.X -= deltaMaxX; Min.Y += deltaMinY; Max.Y -= deltaMaxY; } /// /// Return box scaled by the supplied factor around its center. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d ScaledFromCenterBy(double factor) { var size = Size; var increment = (size * factor - size) / 2; return new Box2d(Min - increment, Max + increment); } /// /// Return box scaled by the supplied factor around its center. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d ScaledFromCenterBy(V2d vectorFactor) { var size = Size; var increment = (size * vectorFactor - size) / 2; return new Box2d(Min - increment, Max + increment); } /// /// Return a box enlarged in all directions by the supplied epsilon which is /// measured with respect to the box diagonal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d EnlargedByRelativeEps(double eps) { return EnlargedBy(eps * Size.Length); } /// /// Enlarge the box in all directions by the supplied epsilon which is /// measured with respect to the box diagonal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeByRelativeEps(double eps) { EnlargeBy(eps * Size.Length); } #endregion #region Box Arithmetics /// /// Return the point in the Box that is closest to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d Clamped(V2d p) { return new V2d( p.X < Min.X ? Min.X : (p.X > Max.X ? Max.X : p.X), p.Y < Min.Y ? Min.Y : (p.Y > Max.Y ? Max.Y : p.Y)); } /// /// Returns the squared distance to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double DistanceSquared(V2d p) { return (p.X < Min.X ? (Min.X - p.X) * (Min.X - p.X) : (p.X > Max.X ? (p.X - Max.X) * (p.X - Max.X) : 0.0)) + (p.Y < Min.Y ? (Min.Y - p.Y) * (Min.Y - p.Y) : (p.Y > Max.Y ? (p.Y - Max.Y) * (p.Y - Max.Y) : 0.0)); } /// /// Returns the distance to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double Distance(V2d p) { return Fun.Sqrt( (p.X < Min.X ? (Min.X - p.X) * (Min.X - p.X) : (p.X > Max.X ? (p.X - Max.X) * (p.X - Max.X) : 0.0)) + (p.Y < Min.Y ? (Min.Y - p.Y) * (Min.Y - p.Y) : (p.Y > Max.Y ? (p.Y - Max.Y) * (p.Y - Max.Y) : 0.0))); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d Lerp(double x) => Fun.Lerp(x, Min, Max); /// /// Interpolate linearly in each dimension. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d Lerp(V2d p) => Fun.Lerp(p, Min, Max); /// /// Interpolate linearly in each dimension. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d Lerp(double x, double y) => Fun.Lerp(new V2d(x, y), Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d InvLerp(V2d p) => Fun.InvLerp(p, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d InvLerp(double x, double y) => Fun.InvLerp(new V2d(x, y), Min, Max); /// /// Returns the box with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d SplitRight(V2d splitValue) { var result = new Box2d(Min, Max); if (splitValue.X > result.Min.X) result.Min.X = splitValue.X; if (splitValue.Y > result.Min.Y) result.Min.Y = splitValue.Y; return result; } /// /// Returns the box with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d SplitLeft(V2d splitValue) { var result = new Box2d(Min, Max); if (splitValue.X < result.Max.X) result.Max.X = splitValue.X; if (splitValue.Y < result.Max.Y) result.Max.Y = splitValue.Y; return result; } /// /// Returns the box with Min.X clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d SplitRight(double splitAtX) { if (splitAtX > Max.X) return Box2d.Invalid; if (splitAtX <= Min.X) return this; return new Box2d(new V2d(splitAtX, Min.Y), Max); } /// /// Returns a box with Max.X clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d SplitLeft(double splitAtX) { if (splitAtX < Min.X) return Box2d.Invalid; if (splitAtX >= Max.X) return this; return new Box2d(Min, new V2d(splitAtX, Max.Y)); } /// /// Returns the box with Min.Y clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d SplitTop(double splitAtY) { if (splitAtY > Max.Y) return Box2d.Invalid; if (splitAtY <= Min.Y) return this; return new Box2d(new V2d(Min.X, splitAtY), Max); } /// /// Returns the box with Max.Y clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d SplitBottom(double splitAtY) { if (splitAtY < Min.Y) return Box2d.Invalid; if (splitAtY >= Max.Y) return this; return new Box2d(Min, new V2d(Max.X, splitAtY)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d SplitLeftBottom(V2d splitAt) { if (splitAt.X < Min.X || splitAt.Y < Min.Y) return Box2d.Invalid; return new Box2d(Min, splitAt); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d SplitRightBottom(V2d splitAt) { if (splitAt.X > Max.X || splitAt.Y < Min.Y) return Box2d.Invalid; return new Box2d(new V2d(splitAt.X, Min.Y), new V2d(Max.X, splitAt.Y)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d SplitLeftTop(V2d splitAt) { if (splitAt.X < Min.X || splitAt.Y > Max.Y) return Box2d.Invalid; return new Box2d(new V2d(Min.X, splitAt.Y), new V2d(splitAt.X, Max.Y)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d SplitRightTop(V2d splitAt) { if (splitAt.X > Max.X || splitAt.Y > Max.Y) return Box2d.Invalid; return new Box2d(splitAt, Max); } /// /// Returns the box extended to contain the supplied box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d ExtendedBy(Box2d b) { return new Box2d( new V2d( b.Min.X < Min.X ? b.Min.X : Min.X, b.Min.Y < Min.Y ? b.Min.Y : Min.Y), new V2d( b.Max.X > Max.X ? b.Max.X : Max.X, b.Max.Y > Max.Y ? b.Max.Y : Max.Y)); } /// /// Returns the box extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d ExtendedBy(V2d v) { return new Box2d( new V2d( v.X < Min.X ? v.X : Min.X, v.Y < Min.Y ? v.Y : Min.Y), new V2d( v.X > Max.X ? v.X : Max.X, v.Y > Max.Y ? v.Y : Max.Y)); } /// /// Extends the box to contain the supplied box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Box2d box) { if (box.Min.X < Min.X) Min.X = box.Min.X; if (box.Max.X > Max.X) Max.X = box.Max.X; if (box.Min.Y < Min.Y) Min.Y = box.Min.Y; if (box.Max.Y > Max.Y) Max.Y = box.Max.Y; } /// /// Extends the box to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(V2d point) { if (point.X < Min.X) Min.X = point.X; if (point.X > Max.X) Max.X = point.X; if (point.Y < Min.Y) Min.Y = point.Y; if (point.Y > Max.Y) Max.Y = point.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d ExtendXBy(double x) { if (x < Min.X) Min.X = x; if (x > Max.X) Max.X = x; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d ExtendYBy(double y) { if (y < Min.Y) Min.Y = y; if (y > Max.Y) Max.Y = y; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d ExtendDimBy(int dim, double x) { if (x < Min[dim]) Min[dim] = x; if (x > Max[dim]) Max[dim] = x; return this; } /// /// Returns true if the box contains the given point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(V2d p) { return p.X >= Min.X && p.X <= Max.X && p.Y >= Min.Y && p.Y <= Max.Y; } /// /// Returns true if the box completely contains the other box. /// A box contains itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Box2d b) { return b.Min.X >= Min.X && b.Max.X <= Max.X && b.Min.Y >= Min.Y && b.Max.Y <= Max.Y; } /// /// Checks if the box is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d Repair() { if (Equals(Box2d.Invalid)) return this; if (Min.X > Max.X) Fun.Swap(ref Min.X, ref Max.X); if (Min.Y > Max.Y) Fun.Swap(ref Min.Y, ref Max.Y); return this; } /// /// Returns true if two boxes intersect each other (or one contains the other). /// Boxes DO NOT intersect if only touching from the outside. /// A box intersects itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box2d box) { if (Min.X >= box.Max.X) return false; if (Max.X <= box.Min.X) return false; if (Min.Y >= box.Max.Y) return false; if (Max.Y <= box.Min.Y) return false; return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box2d box, V2d eps) { if (Min.X - eps.X >= box.Max.X) return false; if (Max.X + eps.X <= box.Min.X) return false; if (Min.Y - eps.Y >= box.Max.Y) return false; if (Max.Y + eps.Y <= box.Min.Y) return false; return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box2d box, double eps) { if (Min.X - eps >= box.Max.X) return false; if (Max.X + eps <= box.Min.X) return false; if (Min.Y - eps >= box.Max.Y) return false; if (Max.Y + eps <= box.Min.Y) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box2d Invalidate() { Min = V2d.MaxValue; Max = V2d.MinValue; return this; } /// /// Returns where a points coordinates are outside a given box /// /// All outside Flags [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(V2d p0) { Box.Flags bf = Box.Flags.None; if (p0.X < Min.X) bf |= Box.Flags.MinX; else if (p0.X > Max.X) bf |= Box.Flags.MaxX; if (p0.Y < Min.Y) bf |= Box.Flags.MinY; else if (p0.Y > Max.Y) bf |= Box.Flags.MaxY; return bf; } /// /// Returns where the planes of the supplied box b are outside /// of the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(Box2d b) { Box.Flags bf = Box.Flags.None; if (b.Min.X < Min.X) bf |= Box.Flags.MinX; if (b.Max.X > Max.X) bf |= Box.Flags.MaxX; if (b.Min.Y < Min.Y) bf |= Box.Flags.MinY; if (b.Max.Y > Max.Y) bf |= Box.Flags.MaxY; return bf; } /// /// Gets the minimal and maximal points of the box when seen from the /// supplied direction vector v. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void GetMinMaxInDirection(V2d v, out V2d vMin, out V2d vMax) { vMin = V2d.MinValue; vMax = V2d.MaxValue; if (v.X >= 0) { vMin.X = Min.X; vMax.X = Max.X; } else { vMin.X = Max.X; vMax.X = Min.X; } if (v.Y >= 0) { vMin.Y = Min.Y; vMax.Y = Max.Y; } else { vMin.Y = Max.Y; vMax.Y = Min.Y; } } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Box2d a, Box2d b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Box2d a, Box2d b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a box shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d operator +(Box2d box, V2d v) { return new Box2d((box.Min + v), (box.Max + v)); } /// /// Returns a box shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d operator -(Box2d box, V2d v) { return new Box2d((box.Min - v), (box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Box2d other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Box2d o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Box2d box, int i, V2d value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Box2d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Box2d(V2d.Parse(x[0].ToString()), V2d.Parse(x[1].ToString())); } public static Box2d Parse(Text t) { return t.NestedBracketSplit(1, V2d.Parse, Box2d.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string beginB, string betweenB, string endB, string beginV, string betweenV, string endV) { fp ??= CultureInfo.InvariantCulture; return beginB + Min.ToString(format, fp, beginV, betweenV, endV) + betweenB + Max.ToString(format, fp, beginV, betweenV, endV) + endB; } #endregion #region Static Factories /// /// Returns new box [0, size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d FromSize(V2d size) { return new Box2d(V2d.Zero, size); } /// /// Returns new box [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d FromMinAndSize(V2d min, V2d size) { return new Box2d(min, min + size); } /// /// Returns new box [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d FromCenterAndSize(V2d center, V2d size) { return new Box2d(center - size / 2, center + size / 2); } /// /// Returns new box [0, iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d FromSize(ISize2d iSize) { return new Box2d( V2d.Zero, iSize.Size2d); } /// /// Returns new box [min, min + iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d FromMinAndSize(V2d min, ISize2d iSize) { return new Box2d( min, min + iSize.Size2d); } /// /// Returns new box [center - iSize / 2, center + iSize / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d FromCenterAndSize(V2d center, ISize2d iSize) { var size = iSize.Size2d; return new Box2d(center - size / 2, center + size / 2); } /// /// Creates box from 2 points which need not be Min and Max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d FromPoints(V2d p0, V2d p1) { return new Box2d(Fun.Min(p0, p1), Fun.Max(p0, p1)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d FromSize(double width, double height) { return Box2d.FromSize(new V2d(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d FromMinAndSize(V2d min, double width, double height) { return new Box2d(min, min + new V2d(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d FromMinAndSize( double minX, double minY, double width, double height ) { return Box2d.FromMinAndSize(new V2d(minX, minY), new V2d(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d FromCenterAndSize(V2d center, double width, double height) { return FromCenterAndSize(center, new V2d(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d FromCenterAndSize( double centerX, double centerY, double width, double height ) { return FromCenterAndSize(new V2d(centerX, centerY), new V2d(width, height)); } #endregion #region Transforms [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d Translated(V2d shift) { return IsInvalid ? Box2d.Invalid : new Box2d(Min + shift, Max + shift); } /// /// Returns a scaled box. WARNING: scaling is performed around the origin! /// A negative scale factor will resut in an invalid box! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d Scaled(V2d factor) { return IsInvalid ? Box2d.Invalid : new Box2d(Min * factor, Max * factor); } /// /// Transforms the box by the given transformation matrix. /// NOTE: Performs IsValid check at 10% CPU time overhead. /// -> Empty bounds (crossed min and max) will remain empty. /// public readonly Box2d Transformed(M33d trafo) { if (Min.X > Max.X || Min.Y > Max.Y) return Box2d.Invalid; var t = new V2d(trafo.M02, trafo.M12); var res = new Box2d(t, t); double av, bv; av = trafo.M00 * Min.X; bv = trafo.M00 * Max.X; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M01 * Min.Y; bv = trafo.M01 * Max.Y; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M10 * Min.X; bv = trafo.M10 * Max.X; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } av = trafo.M11 * Min.Y; bv = trafo.M11 * Max.Y; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } return res; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box2d Transformed(Trafo2d trafo) { return Transformed(trafo.Forward); } #endregion #region Corners /// /// Return the corner of the box with the given index. The corner /// index is constructed in such a way, that bit 0 enumerates the /// x coordinate (0 ... min, 1 ... max), bit 1 enumerates the y /// coordinate, and bit 2 enumerates the z coordinate. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d Corner(int index) { return new V2d( (index & 1) == 0 ? Min.X : Max.X, (index & 2) == 0 ? Min.Y : Max.Y); } /// /// Computes the corners of the box and returns them in an array. /// The order of the corners is determined by their index which is /// constructed as in the method . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d[] ComputeCorners() { return [ Min, new(Max.X, Min.Y), new(Min.X, Max.Y), Max ]; } // TODO: Comment and implement for dimensions other than 2. [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d[] ComputeCornersCCW() { return [ Min, new(Max.X, Min.Y), Max, new(Min.X, Max.Y), ]; } /// /// Enumeration of the corners of the box. /// public readonly IEnumerable Corners { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return Min; yield return new V2d(Max.X, Min.Y); yield return new V2d(Min.X, Max.Y); yield return Max; } } #endregion #region Swizzle methods #endregion #region Enumerators #endregion #region IBoundingBox2d Members public readonly Box2d BoundingBox2d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this; } } #endregion #region IBoundingCircle2d Members public readonly Circle2d BoundingCircle2d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => IsInvalid ? Circle2d.Invalid : new Circle2d(Center, 0.5 * Size.Length); } #endregion #region ISize2d Members public readonly V2d Size2d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Size; } } #endregion } public static partial class Box { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d Union(this Box2d a, Box2d b) { return new Box2d(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d Intersection(this Box2d a, Box2d b) { return new Box2d(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } #endregion #region Bounding box for arrays /// /// Returns the bounding box of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d GetBoundingBox(this V2d[] pointArray) { return pointArray.GetBoundingBox(0, pointArray.LongLength); } /// /// Returns the bounding box of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d GetBoundingBox(this V2d[] pointArray, long count) { return pointArray.GetBoundingBox(0, count); } /// /// Returns the bounding box of count elements of the array starting at start. /// public static Box2d GetBoundingBox( this V2d[] pointArray, long start, long count) { if (count <= 0) return Box2d.Invalid; var box = new Box2d(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding box of count elements of the array starting at start. /// public static Box2d GetBoundingBox(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Box2d.Invalid; var box = new Box2d(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding box for lists /// /// Returns the bounding box of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d GetBoundingBox(this List pointList) { return pointList.GetBoundingBox(pointList.Count); } /// /// Returns the bounding box of the first count elements of the list. /// public static Box2d GetBoundingBox(this List pointList, int count) { if (count <= 0) return Box2d.Invalid; var box = new Box2d(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding box for indexed arrays /// /// Returns the bounding box of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d GetBoundingBox(this int[] indexArray, V2d[] pointArray) { return indexArray.GetBoundingBox(0, indexArray.Length, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d GetBoundingBox(this int[] indexArray, int count, V2d[] pointArray) { return indexArray.GetBoundingBox(0, count, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box2d GetBoundingBox(this int[] indexArray, int start, int count, V2d[] pointArray) { if (count <= 0) return Box2d.Invalid; var box = new Box2d(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box2d GetBoundingBox(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Box2d.Invalid; var box = new Box2d(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d GetBoundingBox(this long[] indexArray, V2d[] pointArray) { return indexArray.GetBoundingBox(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box2d GetBoundingBox(this long[] indexArray, long count, V2d[] pointArray) { return indexArray.GetBoundingBox(0, count, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box2d GetBoundingBox(this long[] indexArray, long start, long count, V2d[] pointArray) { if (count <= 0) return Box2d.Invalid; var box = new Box2d(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box2d GetBoundingBox(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Box2d.Invalid; var box = new Box2d(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding box for IEnumerable /// /// Returns the bounding box of the elements of the collection. /// public static Box2d GetBoundingBox(this IEnumerable points) { var box = Box2d.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Box2d a, Box2d b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Box2d a, Box2d b, double tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Box3i [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Box3i : IEquatable, IRange, IBoundingBox3i, ISize3i, IBoundingSphere3d, IFormattable { [DataMember] public V3i Min; [DataMember] public V3i Max; #region Constructors /// /// Construct a Box3i from a Box3l. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i(Box3l b) { Min = (V3i) b.Min; Max = (V3i) b.Max; } /// /// Construct a Box3i from a Box3f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i(Box3f b) { Min = (V3i) b.Min; Max = (V3i) b.Max; } /// /// Construct a Box3i from a Box3d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i(Box3d b) { Min = (V3i) b.Min; Max = (V3i) b.Max; } /// /// Creates a box from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i(V3i min, V3i max) { Min = min; Max = max; } /// /// Creates a box from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { Min.X = minX; Min.Y = minY; Min.Z = minZ; Max.X = maxX; Max.Y = maxY; Max.Z = maxZ; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i(V3i pnt) { Min = pnt; Max = pnt; } /// /// Creates a box from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i(V3i p0, V3i p1, V3i p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a box from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i(V3i p0, V3i p1, V3i p2, V3i p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i(Box3i range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i(Box3i b0, Box3i b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i(Box3i b0, Box3i b1, Box3i b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i(Box3i b0, Box3i b1, Box3i b2, Box3i b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i(V3i[] points) : this((ReadOnlySpan)points) { } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i(ReadOnlySpan points) { Min = V3i.MaxValue; Max = V3i.MinValue; if (points == null) return; var count = points.Length; for (var i = 0; i < count; i++) ExtendBy(points[i]); } /// /// Creates box as the bounding box of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i(V3i[] points, long start, long count) { if (count <= 0) { Min = Invalid.Min; Max = Invalid.Max; } else { Min = Max = points[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(points[i]); } } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i(IEnumerable points) { Min = V3i.MaxValue; Max = V3i.MinValue; if (points == null) return; foreach (V3i p in points) ExtendBy(p); } /// /// Creates box as the bounding box of given boxes. /// public Box3i(IEnumerable boxes) { Min = V3i.MaxValue; Max = V3i.MinValue; if (boxes == null) return; foreach (var box in boxes) ExtendBy(box); } /// /// Creates box from a Range1 in each direction. /// public Box3i(Range1i rangeX, Range1i rangeY, Range1i rangeZ) { Min.X = rangeX.Min; Max.X = rangeX.Max; Min.Y = rangeY.Min; Max.Y = rangeY.Max; Min.Z = rangeZ.Min; Max.Z = rangeZ.Max; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box3i(Box3l b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box3i(Box3f b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box3i(Box3d b) => new(b); #endregion #region Constants /// /// A range with crossed limits. /// public static Box3i Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V3i.MaxValue, V3i.MinValue); } /// /// The largest possible range. /// public static Box3i Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V3i.MinValue, V3i.MaxValue); } /// /// The unit interval [0, 1]. /// public static Box3i Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V3i.Zero, V3i.One); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AnyGreaterOrEqual(Max); } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AllSmallerOrEqual(Max); } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AnyGreater(Max); } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Calculates size of the box. /// [XmlIgnore] public V3i Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (Min + value); } } public readonly V3i Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return ((Min + Max) / 2); } } [XmlIgnore] public int SizeX { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.X - Min.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.X = Min.X + value; } } public readonly Range1i RangeX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1i(Min.X, Max.X); } } [XmlIgnore] public int SizeY { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Y - Min.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Y = Min.Y + value; } } public readonly Range1i RangeY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1i(Min.Y, Max.Y); } } [XmlIgnore] public int SizeZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Z - Min.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Z = Min.Z + value; } } public readonly Range1i RangeZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1i(Min.Z, Max.Z); } } /// /// Index of the longest dimension of the box. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { int major = 0; var s = Size; if (s.Y > s.X) major = 1; if (s.Z > s[major]) major = 2; return major; } } /// /// Index of the shortest dimension of the box. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { int minor = 0; var s = Size; if (s.Y < s.X) minor = 1; if (s.Z < s[minor]) minor = 2; return minor; } } public readonly int SurfaceArea { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Size; return (s.X * s.Y + s.X * s.Z + s.Y * s.Z) * 2; } } public readonly int Volume { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (IsInvalid) return 0; return SizeX * SizeY * SizeZ; } } public readonly V3i OOO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min; } } public readonly V3i IOO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3i(Max.X, Min.Y, Min.Z); } } public readonly V3i OIO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3i(Min.X, Max.Y, Min.Z); } } public readonly V3i IIO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3i(Max.X, Max.Y, Min.Z); } } public readonly V3i OOI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3i(Min.X, Min.Y, Max.Z); } } public readonly V3i IOI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3i(Max.X, Min.Y, Max.Z); } } public readonly V3i OII { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3i(Min.X, Max.Y, Max.Z); } } public readonly V3i III { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Max; } } #endregion #region Size Manipulations /// /// Return box enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3i EnlargedBy(V3i increment) { return new Box3i((Min - increment), (Max + increment)); } /// /// Return box enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3i EnlargedBy(V3i deltaMin, V3i deltaMax) { return new Box3i((Min - deltaMin), (Max + deltaMax)); } /// /// Return box shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3i ShrunkBy(V3i delta) { return new Box3i((Min + delta), (Max - delta)); } /// /// Return box shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3i ShrunkBy(V3i deltaMin, V3i deltaMax) { return new Box3i((Min + deltaMin), (Max - deltaMax)); } /// /// Enlarges box by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(V3i delta) { Min -= delta; Max += delta; } /// /// Enlarges box by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(V3i deltaMin, V3i deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks box by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(V3i delta) { Min += delta; Max -= delta; } /// /// Shrinks box by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(V3i deltaMin, V3i deltaMax) { Min += deltaMin; Max -= deltaMax; } /// /// Returns a box enlarged by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3i EnlargedBy(int delta) { return new Box3i( new V3i(Min.X - delta, Min.Y - delta, Min.Z - delta), new V3i(Max.X + delta, Max.Y + delta, Max.Z + delta)); } /// /// Returns a box shrunk by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3i ShrunkBy(int delta) { return new Box3i( new V3i(Min.X + delta, Min.Y + delta, Min.Z + delta), new V3i(Max.X - delta, Max.Y - delta, Max.Z - delta)); } /// /// Returns the box enlarged by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3i EnlargedBy( int deltaMinX, int deltaMaxX, int deltaMinY, int deltaMaxY, int deltaMinZ, int deltaMaxZ) { return new Box3i( new V3i(Min.X - deltaMinX, Min.Y - deltaMinY, Min.Z - deltaMinZ), new V3i(Max.X + deltaMaxX, Max.Y + deltaMaxY, Max.Z + deltaMaxZ)); } /// /// Returns the box shrunk by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3i ShrunkBy( int deltaMinX, int deltaMaxX, int deltaMinY, int deltaMaxY, int deltaMinZ, int deltaMaxZ) { return new Box3i( new V3i(Min.X + deltaMinX, Min.Y + deltaMinY, Min.Z + deltaMinZ), new V3i(Max.X - deltaMaxX, Max.Y - deltaMaxY, Max.Z - deltaMaxZ)); } /// /// Enlarges box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(int delta) { Min.X -= delta; Max.X += delta; Min.Y -= delta; Max.Y += delta; Min.Z -= delta; Max.Z += delta; } /// /// Shrinks box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(int delta) { Min.X += delta; Max.X -= delta; Min.Y += delta; Max.Y -= delta; Min.Z += delta; Max.Z -= delta; } /// /// Enlarges the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy( int deltaMinX, int deltaMaxX, int deltaMinY, int deltaMaxY, int deltaMinZ, int deltaMaxZ) { Min.X -= deltaMinX; Max.X += deltaMaxX; Min.Y -= deltaMinY; Max.Y += deltaMaxY; Min.Z -= deltaMinZ; Max.Z += deltaMaxZ; } /// /// Shrinks the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy( int deltaMinX, int deltaMaxX, int deltaMinY, int deltaMaxY, int deltaMinZ, int deltaMaxZ) { Min.X += deltaMinX; Max.X -= deltaMaxX; Min.Y += deltaMinY; Max.Y -= deltaMaxY; Min.Z += deltaMinZ; Max.Z -= deltaMaxZ; } #endregion #region Box Arithmetics /// /// Return the point in the Box that is closest to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i Clamped(V3i p) { return new V3i( p.X < Min.X ? Min.X : (p.X > Max.X ? Max.X : p.X), p.Y < Min.Y ? Min.Y : (p.Y > Max.Y ? Max.Y : p.Y), p.Z < Min.Z ? Min.Z : (p.Z > Max.Z ? Max.Z : p.Z)); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i Lerp(float t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i Lerp(V3f t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i Lerp(double t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i Lerp(V3d t) => Fun.Lerp(t, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d InvLerp(V3i y) => Fun.InvLerp(y, Min, Max); /// /// Returns the box with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3i SplitRight(V3i splitValue) { var result = new Box3i(Min, Max); if (splitValue.X > result.Min.X) result.Min.X = splitValue.X; if (splitValue.Y > result.Min.Y) result.Min.Y = splitValue.Y; if (splitValue.Z > result.Min.Z) result.Min.Z = splitValue.Z; return result; } /// /// Returns the box with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3i SplitLeft(V3i splitValue) { var result = new Box3i(Min, Max); if (splitValue.X < result.Max.X) result.Max.X = splitValue.X; if (splitValue.Y < result.Max.Y) result.Max.Y = splitValue.Y; if (splitValue.Z < result.Max.Z) result.Max.Z = splitValue.Z; return result; } /// /// Returns the box extended to contain the supplied box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3i ExtendedBy(Box3i b) { return new Box3i( new V3i( b.Min.X < Min.X ? b.Min.X : Min.X, b.Min.Y < Min.Y ? b.Min.Y : Min.Y, b.Min.Z < Min.Z ? b.Min.Z : Min.Z), new V3i( b.Max.X > Max.X ? b.Max.X : Max.X, b.Max.Y > Max.Y ? b.Max.Y : Max.Y, b.Max.Z > Max.Z ? b.Max.Z : Max.Z)); } /// /// Returns the box extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3i ExtendedBy(V3i v) { return new Box3i( new V3i( v.X < Min.X ? v.X : Min.X, v.Y < Min.Y ? v.Y : Min.Y, v.Z < Min.Z ? v.Z : Min.Z), new V3i( v.X > Max.X ? v.X : Max.X, v.Y > Max.Y ? v.Y : Max.Y, v.Z > Max.Z ? v.Z : Max.Z)); } /// /// Extends the box to contain the supplied box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Box3i box) { if (box.Min.X < Min.X) Min.X = box.Min.X; if (box.Max.X > Max.X) Max.X = box.Max.X; if (box.Min.Y < Min.Y) Min.Y = box.Min.Y; if (box.Max.Y > Max.Y) Max.Y = box.Max.Y; if (box.Min.Z < Min.Z) Min.Z = box.Min.Z; if (box.Max.Z > Max.Z) Max.Z = box.Max.Z; } /// /// Extends the box to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(V3i point) { if (point.X < Min.X) Min.X = point.X; if (point.X > Max.X) Max.X = point.X; if (point.Y < Min.Y) Min.Y = point.Y; if (point.Y > Max.Y) Max.Y = point.Y; if (point.Z < Min.Z) Min.Z = point.Z; if (point.Z > Max.Z) Max.Z = point.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i ExtendXBy(int x) { if (x < Min.X) Min.X = x; if (x > Max.X) Max.X = x; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i ExtendYBy(int y) { if (y < Min.Y) Min.Y = y; if (y > Max.Y) Max.Y = y; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i ExtendZBy(int z) { if (z < Min.Z) Min.Z = z; if (z > Max.Z) Max.Z = z; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i ExtendDimBy(int dim, int x) { if (x < Min[dim]) Min[dim] = x; if (x > Max[dim]) Max[dim] = x; return this; } /// /// Returns true if the box contains the given point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(V3i p) { return p.X >= Min.X && p.X <= Max.X && p.Y >= Min.Y && p.Y <= Max.Y && p.Z >= Min.Z && p.Z <= Max.Z; } /// /// Returns true if the box completely contains the other box. /// A box contains itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Box3i b) { return b.Min.X >= Min.X && b.Max.X <= Max.X && b.Min.Y >= Min.Y && b.Max.Y <= Max.Y && b.Min.Z >= Min.Z && b.Max.Z <= Max.Z; } /// /// Checks if the box is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i Repair() { if (Equals(Box3i.Invalid)) return this; if (Min.X > Max.X) Fun.Swap(ref Min.X, ref Max.X); if (Min.Y > Max.Y) Fun.Swap(ref Min.Y, ref Max.Y); if (Min.Z > Max.Z) Fun.Swap(ref Min.Z, ref Max.Z); return this; } /// /// Returns true if two boxes intersect each other (or one contains the other). /// Boxes DO NOT intersect if only touching from the outside. /// A box intersects itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box3i box) { if (Min.X >= box.Max.X) return false; if (Max.X <= box.Min.X) return false; if (Min.Y >= box.Max.Y) return false; if (Max.Y <= box.Min.Y) return false; if (Min.Z >= box.Max.Z) return false; if (Max.Z <= box.Min.Z) return false; return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box3i box, V3i eps) { if (Min.X - eps.X >= box.Max.X) return false; if (Max.X + eps.X <= box.Min.X) return false; if (Min.Y - eps.Y >= box.Max.Y) return false; if (Max.Y + eps.Y <= box.Min.Y) return false; if (Min.Z - eps.Z >= box.Max.Z) return false; if (Max.Z + eps.Z <= box.Min.Z) return false; return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box3i box, int eps) { if (Min.X - eps >= box.Max.X) return false; if (Max.X + eps <= box.Min.X) return false; if (Min.Y - eps >= box.Max.Y) return false; if (Max.Y + eps <= box.Min.Y) return false; if (Min.Z - eps >= box.Max.Z) return false; if (Max.Z + eps <= box.Min.Z) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3i Invalidate() { Min = V3i.MaxValue; Max = V3i.MinValue; return this; } /// /// Returns where a points coordinates are outside a given box /// /// All outside Flags [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(V3i p0) { Box.Flags bf = Box.Flags.None; if (p0.X < Min.X) bf |= Box.Flags.MinX; else if (p0.X > Max.X) bf |= Box.Flags.MaxX; if (p0.Y < Min.Y) bf |= Box.Flags.MinY; else if (p0.Y > Max.Y) bf |= Box.Flags.MaxY; if (p0.Z < Min.Z) bf |= Box.Flags.MinZ; else if (p0.Z > Max.Z) bf |= Box.Flags.MaxZ; return bf; } /// /// Returns where the planes of the supplied box b are outside /// of the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(Box3i b) { Box.Flags bf = Box.Flags.None; if (b.Min.X < Min.X) bf |= Box.Flags.MinX; if (b.Max.X > Max.X) bf |= Box.Flags.MaxX; if (b.Min.Y < Min.Y) bf |= Box.Flags.MinY; if (b.Max.Y > Max.Y) bf |= Box.Flags.MaxY; if (b.Min.Z < Min.Z) bf |= Box.Flags.MinZ; if (b.Max.Z > Max.Z) bf |= Box.Flags.MaxZ; return bf; } /// /// Gets the minimal and maximal points of the box when seen from the /// supplied direction vector v. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void GetMinMaxInDirection(V3i v, out V3i vMin, out V3i vMax) { vMin = V3i.MinValue; vMax = V3i.MaxValue; if (v.X >= 0) { vMin.X = Min.X; vMax.X = Max.X; } else { vMin.X = Max.X; vMax.X = Min.X; } if (v.Y >= 0) { vMin.Y = Min.Y; vMax.Y = Max.Y; } else { vMin.Y = Max.Y; vMax.Y = Min.Y; } if (v.Z >= 0) { vMin.Z = Min.Z; vMax.Z = Max.Z; } else { vMin.Z = Max.Z; vMax.Z = Min.Z; } } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Box3i a, Box3i b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Box3i a, Box3i b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a box shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i operator +(Box3i box, V3i v) { return new Box3i((box.Min + v), (box.Max + v)); } /// /// Returns a box shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i operator -(Box3i box, V3i v) { return new Box3i((box.Min - v), (box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Box3i other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Box3i o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Box3i box, int i, V3i value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Box3i Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Box3i(V3i.Parse(x[0].ToString()), V3i.Parse(x[1].ToString())); } public static Box3i Parse(Text t) { return t.NestedBracketSplit(1, V3i.Parse, Box3i.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string beginB, string betweenB, string endB, string beginV, string betweenV, string endV) { fp ??= CultureInfo.InvariantCulture; return beginB + Min.ToString(format, fp, beginV, betweenV, endV) + betweenB + Max.ToString(format, fp, beginV, betweenV, endV) + endB; } #endregion #region Static Factories /// /// Returns new box [0, size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i FromSize(V3i size) { return new Box3i(V3i.Zero, size); } /// /// Returns new box [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i FromMinAndSize(V3i min, V3i size) { return new Box3i(min, min + size); } /// /// Returns new box [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i FromCenterAndSize(V3i center, V3i size) { return new Box3i(center - size / 2, center + size / 2); } /// /// Returns new box [0, iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i FromSize(ISize3i iSize) { return new Box3i( V3i.Zero, iSize.Size3i); } /// /// Returns new box [min, min + iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i FromMinAndSize(V3i min, ISize3i iSize) { return new Box3i( min, min + iSize.Size3i); } /// /// Returns new box [center - iSize / 2, center + iSize / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i FromCenterAndSize(V3i center, ISize3i iSize) { var size = iSize.Size3i; return new Box3i(center - size / 2, center + size / 2); } /// /// Creates box from 2 points which need not be Min and Max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i FromPoints(V3i p0, V3i p1) { return new Box3i(Fun.Min(p0, p1), Fun.Max(p0, p1)); } #endregion #region Transforms [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3i Translated(V3i shift) { return IsInvalid ? Box3i.Invalid : new Box3i(Min + shift, Max + shift); } /// /// Returns a scaled box. WARNING: scaling is performed around the origin! /// A negative scale factor will resut in an invalid box! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3i Scaled(V3i factor) { return IsInvalid ? Box3i.Invalid : new Box3i(Min * factor, Max * factor); } /// /// Transforms the box by the given transformation matrix. /// NOTE: Performs IsValid check at 10% CPU time overhead. /// -> Empty bounds (crossed min and max) will remain empty. /// public readonly Box3d Transformed(M44d trafo) { if (Min.X > Max.X || Min.Y > Max.Y || Min.Z > Max.Z) return Box3d.Invalid; var t = new V3d(trafo.M03, trafo.M13, trafo.M23); var res = new Box3d(t, t); double av, bv; av = trafo.M00 * Min.X; bv = trafo.M00 * Max.X; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M01 * Min.Y; bv = trafo.M01 * Max.Y; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M02 * Min.Z; bv = trafo.M02 * Max.Z; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M10 * Min.X; bv = trafo.M10 * Max.X; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } av = trafo.M11 * Min.Y; bv = trafo.M11 * Max.Y; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } av = trafo.M12 * Min.Z; bv = trafo.M12 * Max.Z; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } av = trafo.M20 * Min.X; bv = trafo.M20 * Max.X; if (av < bv) { res.Min.Z += av; res.Max.Z += bv; } else { res.Min.Z += bv; res.Max.Z += av; } av = trafo.M21 * Min.Y; bv = trafo.M21 * Max.Y; if (av < bv) { res.Min.Z += av; res.Max.Z += bv; } else { res.Min.Z += bv; res.Max.Z += av; } av = trafo.M22 * Min.Z; bv = trafo.M22 * Max.Z; if (av < bv) { res.Min.Z += av; res.Max.Z += bv; } else { res.Min.Z += bv; res.Max.Z += av; } return res; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d Transformed(Trafo3d trafo) { return Transformed(trafo.Forward); } #endregion #region Corners /// /// Return the corner of the box with the given index. The corner /// index is constructed in such a way, that bit 0 enumerates the /// x coordinate (0 ... min, 1 ... max), bit 1 enumerates the y /// coordinate, and bit 2 enumerates the z coordinate. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i Corner(int index) { return new V3i( (index & 1) == 0 ? Min.X : Max.X, (index & 2) == 0 ? Min.Y : Max.Y, (index & 4) == 0 ? Min.Z : Max.Z); } /// /// Computes the corners of the box and returns them in an array. /// The order of the corners is determined by their index which is /// constructed as in the method . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i[] ComputeCorners() { return [ Min, new(Max.X, Min.Y, Min.Z), new(Min.X, Max.Y, Min.Z), new(Max.X, Max.Y, Min.Z), new(Min.X, Min.Y, Max.Z), new(Max.X, Min.Y, Max.Z), new(Min.X, Max.Y, Max.Z), Max ]; } /// /// Enumeration of the corners of the box. /// public readonly IEnumerable Corners { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return Min; yield return new V3i(Max.X, Min.Y, Min.Z); yield return new V3i(Min.X, Max.Y, Min.Z); yield return new V3i(Max.X, Max.Y, Min.Z); yield return new V3i(Min.X, Min.Y, Max.Z); yield return new V3i(Max.X, Min.Y, Max.Z); yield return new V3i(Min.X, Max.Y, Max.Z); yield return Max; } } #endregion #region Swizzle methods // TODO: Implement for other dimensions public readonly Range1i X { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1i(Min.X, Max.X); } } public readonly Range1i Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1i(Min.Y, Max.Y); } } public readonly Range1i Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1i(Min.Z, Max.Z); } } public readonly Box2i XY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2i(Min.XY, Max.XY); } } public readonly Box2i XZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2i(Min.XZ, Max.XZ); } } public readonly Box2i YX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2i(Min.YX, Max.YX); } } public readonly Box2i YZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2i(Min.YZ, Max.YZ); } } public readonly Box2i ZX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2i(Min.ZX, Max.ZX); } } public readonly Box2i ZY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2i(Min.ZY, Max.ZY); } } #endregion #region Enumerators /// /// Returns all points from [Min,Max[ with X-Variable in the outer loop. /// public readonly IEnumerable EnumerateInsidePoints() { var p = new V3i(); for (p.X = Min.X; p.X < Max.X; p.X++) for (p.Y = Min.Y; p.Y < Max.Y; p.Y++) for (p.Z = Min.Z; p.Z < Max.Z; p.Z++) yield return p; } #endregion #region IBoundingBox3i Members public readonly Box3i BoundingBox3i { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this; } } #endregion #region IBoundingSphere3d Members public readonly Sphere3d BoundingSphere3d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => IsInvalid ? Sphere3d.Invalid : new Sphere3d((V3d)Center, 0.5 * Size.Length); } #endregion #region ISize3i Members public readonly V3i Size3i { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Size; } } #endregion } public static partial class Box { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i Union(this Box3i a, Box3i b) { return new Box3i(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i Intersection(this Box3i a, Box3i b) { return new Box3i(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } #endregion #region Bounding box for arrays /// /// Returns the bounding box of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i GetBoundingBox(this V3i[] pointArray) { return pointArray.GetBoundingBox(0, pointArray.LongLength); } /// /// Returns the bounding box of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i GetBoundingBox(this V3i[] pointArray, long count) { return pointArray.GetBoundingBox(0, count); } /// /// Returns the bounding box of count elements of the array starting at start. /// public static Box3i GetBoundingBox( this V3i[] pointArray, long start, long count) { if (count <= 0) return Box3i.Invalid; var box = new Box3i(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding box of count elements of the array starting at start. /// public static Box3i GetBoundingBox(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Box3i.Invalid; var box = new Box3i(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding box for lists /// /// Returns the bounding box of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i GetBoundingBox(this List pointList) { return pointList.GetBoundingBox(pointList.Count); } /// /// Returns the bounding box of the first count elements of the list. /// public static Box3i GetBoundingBox(this List pointList, int count) { if (count <= 0) return Box3i.Invalid; var box = new Box3i(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding box for indexed arrays /// /// Returns the bounding box of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i GetBoundingBox(this int[] indexArray, V3i[] pointArray) { return indexArray.GetBoundingBox(0, indexArray.Length, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i GetBoundingBox(this int[] indexArray, int count, V3i[] pointArray) { return indexArray.GetBoundingBox(0, count, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box3i GetBoundingBox(this int[] indexArray, int start, int count, V3i[] pointArray) { if (count <= 0) return Box3i.Invalid; var box = new Box3i(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box3i GetBoundingBox(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Box3i.Invalid; var box = new Box3i(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i GetBoundingBox(this long[] indexArray, V3i[] pointArray) { return indexArray.GetBoundingBox(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3i GetBoundingBox(this long[] indexArray, long count, V3i[] pointArray) { return indexArray.GetBoundingBox(0, count, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box3i GetBoundingBox(this long[] indexArray, long start, long count, V3i[] pointArray) { if (count <= 0) return Box3i.Invalid; var box = new Box3i(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box3i GetBoundingBox(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Box3i.Invalid; var box = new Box3i(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding box for IEnumerable /// /// Returns the bounding box of the elements of the collection. /// public static Box3i GetBoundingBox(this IEnumerable points) { var box = Box3i.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion #region Get octant /// /// Octant 0-7. /// 0th, 1st and 2nd bit encodes x-, y-, z-axis, respectively. /// E.g. 0 is octant [box.Min, box.Center], 7 is octant [box.Center, box.Max]. /// public static Box3i GetOctant(this Box3i box, int i) { if (i < 0 || i > 7) throw new IndexOutOfRangeException(); int x0, x1, y0, y1, z0, z1; var c = box.Center; if ((i & 1) == 0) { x0 = box.Min.X; x1 = c.X; } else { x0 = c.X; x1 = box.Max.X; } if ((i & 2) == 0) { y0 = box.Min.Y; y1 = c.Y; } else { y0 = c.Y; y1 = box.Max.Y; } if (i < 4) { z0 = box.Min.Z; z1 = c.Z; } else { z0 = c.Z; z1 = box.Max.Z; } return new Box3i(new V3i(x0, y0, z0), new V3i(x1, y1, z1)); } #endregion #region Outline corners /// /// Gets outline corner indices of a box as seen from given position (in counter-clockwise order). /// Returns null if position is inside the box. /// public static int[] GetOutlineCornerIndicesCCW(this Box3i box, V3i fromPosition) { if (fromPosition.X < box.Min.X) { //-X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // -X -Y -Z return [1, 5, 4, 6, 2, 3]; } else if (fromPosition.Z > box.Max.Z) { // -X -Y +Z return [0, 1, 5, 7, 6, 2]; } else { // -X -Y Z return [1, 5, 6, 2]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // -X +Y -Z return [0, 4, 6, 7, 3, 1]; } else if (fromPosition.Z > box.Max.Z) { // -X +Y +Z return [0, 4, 5, 7, 3, 2]; } else { // -X +Y Z return [0, 4, 7, 3]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // -X Y -Z return [1, 4, 6, 3]; } else if (fromPosition.Z > box.Max.Z) { // -X Y +Z return [0, 5, 7, 2]; } else { // -X Y Z return [0, 4, 6, 2]; } } } else if (fromPosition.X > box.Max.X) { // +X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // +X -Y -Z return [0, 2, 3, 7, 5, 4]; } else if (fromPosition.Z > box.Max.Z) { // +X -Y +Z return [0, 1, 3, 7, 6, 4]; } else { // +X -Y Z return [0, 3, 7, 4]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // +X +Y -Z return [0, 2, 6, 7, 5, 1]; } else if (fromPosition.Z > box.Max.Z) { // +X +Y +Z return [1, 3, 2, 6, 4, 5]; } else { // +X +Y Z return [1, 2, 6, 5]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // +X Y -Z return [0, 2, 7, 5]; } else if (fromPosition.Z > box.Max.Z) { // +X Y +Z return [1, 3, 6, 4]; } else { // +X Y Z return [1, 3, 7, 5]; } } } else { // X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // X -Y -Z return [2, 3, 5, 4]; } else if (fromPosition.Z > box.Max.Z) { // X -Y +Z return [0, 1, 7, 6]; } else { // X -Y Z return [0, 1, 5, 4]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // X +Y -Z return [0, 6, 7, 1]; } else if (fromPosition.Z > box.Max.Z) { // X +Y +Z return [2, 4, 5, 3]; } else { // X +Y Z return [2, 6, 7, 3]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // X Y -Z return [0, 2, 3, 1]; } else if (fromPosition.Z > box.Max.Z) { // X Y +Z return [4, 5, 7, 6]; } else { // X Y Z return null; } } } } /// /// Gets outline corner indices of a box as seen from given position (in clockwise order). /// Returns null if position is inside the box. /// public static int[] GetOutlineCornerIndicesCW(this Box3i box, V3i fromPosition) { if (fromPosition.X < box.Min.X) { //-X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // -X -Y -Z return [1, 3, 2, 6, 4, 5]; } else if (fromPosition.Z > box.Max.Z) { // -X -Y +Z return [0, 2, 6, 7, 5, 1]; } else { // -X -Y Z return [1, 2, 6, 5]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // -X +Y -Z return [0, 1, 3, 7, 6, 4]; } else if (fromPosition.Z > box.Max.Z) { // -X +Y +Z return [0, 2, 3, 7, 5, 4]; } else { // -X +Y Z return [0, 3, 7, 4]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // -X Y -Z return [1, 3, 6, 4]; } else if (fromPosition.Z > box.Max.Z) { // -X Y +Z return [0, 2, 7, 5]; } else { // -X Y Z return [0, 2, 6, 4]; } } } else if (fromPosition.X > box.Max.X) { // +X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // +X -Y -Z return [0, 4, 5, 7, 3, 2]; } else if (fromPosition.Z > box.Max.Z) { // +X -Y +Z return [0, 4, 6, 7, 3, 1]; } else { // +X -Y Z return [0, 4, 7, 3]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // +X +Y -Z return [0, 1, 5, 7, 6, 2]; } else if (fromPosition.Z > box.Max.Z) { // +X +Y +Z return [1, 5, 4, 6, 2, 3]; } else { // +X +Y Z return [1, 5, 6, 2]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // +X Y -Z return [0, 5, 7, 2]; } else if (fromPosition.Z > box.Max.Z) { // +X Y +Z return [1, 4, 6, 3]; } else { // +X Y Z return [1, 5, 7, 3]; } } } else { // X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // X -Y -Z return [2, 4, 5, 3]; } else if (fromPosition.Z > box.Max.Z) { // X -Y +Z return [0, 6, 7, 1]; } else { // X -Y Z return [0, 4, 5, 1]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // X +Y -Z return [0, 1, 7, 6]; } else if (fromPosition.Z > box.Max.Z) { // X +Y +Z return [2, 3, 5, 4]; } else { // X +Y Z return [2, 3, 7, 6]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // X Y -Z return [0, 1, 3, 2]; } else if (fromPosition.Z > box.Max.Z) { // X Y +Z return [4, 6, 7, 5]; } else { // X Y Z return null; } } } } /// /// Gets outline corners of a box as seen from given position (in counter-clockwise order). /// Returns null if position is inside the box. /// public static V3i[] GetOutlineCornersCCW(this Box3i box, V3i fromPosition) { var cs = box.ComputeCorners(); return GetOutlineCornerIndicesCCW(box, fromPosition)?.Map(i => cs[i]); } /// /// Gets outline corners of a box as seen from given position (in clockwise order). /// Returns null if position is inside the box. /// public static V3i[] GetOutlineCornersCW(this Box3i box, V3i fromPosition) { var cs = box.ComputeCorners(); return GetOutlineCornerIndicesCW(box, fromPosition)?.Map(i => cs[i]); } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Box3i a, Box3i b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Box3i a, Box3i b, int tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Box3iAndFlags [DataContract] public struct Box3iAndFlags { [DataMember] public Box.Flags BFlags; [DataMember] public Box3i BBox; public Box3iAndFlags(Box3i union, Box3i box0, Box3i box1) { BFlags = 0; BBox = union; if (box0.Min.X > union.Min.X) { BBox.Min.X = box0.Min.X; BFlags |= Box.Flags.MinX0; } if (box0.Min.Y > union.Min.Y) { BBox.Min.Y = box0.Min.Y; BFlags |= Box.Flags.MinY0; } if (box0.Min.Z > union.Min.Z) { BBox.Min.Z = box0.Min.Z; BFlags |= Box.Flags.MinZ0; } if (box0.Max.X < union.Max.X) { BBox.Max.X = box0.Max.X; BFlags |= Box.Flags.MaxX0; } if (box0.Max.Y < union.Max.Y) { BBox.Max.Y = box0.Max.Y; BFlags |= Box.Flags.MaxY0; } if (box0.Max.Z < union.Max.Z) { BBox.Max.Z = box0.Max.Z; BFlags |= Box.Flags.MaxZ0; } if (box1.Min.X > union.Min.X) { BBox.Min.X = box1.Min.X; BFlags |= Box.Flags.MinX1; } if (box1.Min.Y > union.Min.Y) { BBox.Min.Y = box1.Min.Y; BFlags |= Box.Flags.MinY1; } if (box1.Min.Z > union.Min.Z) { BBox.Min.Z = box1.Min.Z; BFlags |= Box.Flags.MinZ1; } if (box1.Max.X < union.Max.X) { BBox.Max.X = box1.Max.X; BFlags |= Box.Flags.MaxX1; } if (box1.Max.Y < union.Max.Y) { BBox.Max.Y = box1.Max.Y; BFlags |= Box.Flags.MaxY1; } if (box1.Max.Z < union.Max.Z) { BBox.Max.Z = box1.Max.Z; BFlags |= Box.Flags.MaxZ1; } } } #endregion #region Box3l [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Box3l : IEquatable, IRange, IBoundingBox3l, ISize3l, IBoundingSphere3d, IFormattable { [DataMember] public V3l Min; [DataMember] public V3l Max; #region Constructors /// /// Construct a Box3l from a Box3i. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l(Box3i b) { Min = (V3l) b.Min; Max = (V3l) b.Max; } /// /// Construct a Box3l from a Box3f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l(Box3f b) { Min = (V3l) b.Min; Max = (V3l) b.Max; } /// /// Construct a Box3l from a Box3d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l(Box3d b) { Min = (V3l) b.Min; Max = (V3l) b.Max; } /// /// Creates a box from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l(V3l min, V3l max) { Min = min; Max = max; } /// /// Creates a box from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l(long minX, long minY, long minZ, long maxX, long maxY, long maxZ) { Min.X = minX; Min.Y = minY; Min.Z = minZ; Max.X = maxX; Max.Y = maxY; Max.Z = maxZ; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l(V3l pnt) { Min = pnt; Max = pnt; } /// /// Creates a box from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l(V3l p0, V3l p1, V3l p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a box from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l(V3l p0, V3l p1, V3l p2, V3l p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l(Box3l range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l(Box3l b0, Box3l b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l(Box3l b0, Box3l b1, Box3l b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l(Box3l b0, Box3l b1, Box3l b2, Box3l b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l(V3l[] points) : this((ReadOnlySpan)points) { } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l(ReadOnlySpan points) { Min = V3l.MaxValue; Max = V3l.MinValue; if (points == null) return; var count = points.Length; for (var i = 0; i < count; i++) ExtendBy(points[i]); } /// /// Creates box as the bounding box of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l(V3l[] points, long start, long count) { if (count <= 0) { Min = Invalid.Min; Max = Invalid.Max; } else { Min = Max = points[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(points[i]); } } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l(IEnumerable points) { Min = V3l.MaxValue; Max = V3l.MinValue; if (points == null) return; foreach (V3l p in points) ExtendBy(p); } /// /// Creates box as the bounding box of given boxes. /// public Box3l(IEnumerable boxes) { Min = V3l.MaxValue; Max = V3l.MinValue; if (boxes == null) return; foreach (var box in boxes) ExtendBy(box); } /// /// Creates box from a Range1 in each direction. /// public Box3l(Range1l rangeX, Range1l rangeY, Range1l rangeZ) { Min.X = rangeX.Min; Max.X = rangeX.Max; Min.Y = rangeY.Min; Max.Y = rangeY.Max; Min.Z = rangeZ.Min; Max.Z = rangeZ.Max; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box3l(Box3i b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box3l(Box3f b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box3l(Box3d b) => new(b); #endregion #region Constants /// /// A range with crossed limits. /// public static Box3l Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V3l.MaxValue, V3l.MinValue); } /// /// The largest possible range. /// public static Box3l Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V3l.MinValue, V3l.MaxValue); } /// /// The unit interval [0, 1]. /// public static Box3l Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V3l.Zero, V3l.One); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AnyGreaterOrEqual(Max); } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AllSmallerOrEqual(Max); } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AnyGreater(Max); } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Calculates size of the box. /// [XmlIgnore] public V3l Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (Min + value); } } public readonly V3l Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return ((Min + Max) / 2); } } [XmlIgnore] public long SizeX { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.X - Min.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.X = Min.X + value; } } public readonly Range1l RangeX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1l(Min.X, Max.X); } } [XmlIgnore] public long SizeY { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Y - Min.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Y = Min.Y + value; } } public readonly Range1l RangeY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1l(Min.Y, Max.Y); } } [XmlIgnore] public long SizeZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Z - Min.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Z = Min.Z + value; } } public readonly Range1l RangeZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1l(Min.Z, Max.Z); } } /// /// Index of the longest dimension of the box. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { int major = 0; var s = Size; if (s.Y > s.X) major = 1; if (s.Z > s[major]) major = 2; return major; } } /// /// Index of the shortest dimension of the box. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { int minor = 0; var s = Size; if (s.Y < s.X) minor = 1; if (s.Z < s[minor]) minor = 2; return minor; } } public readonly long SurfaceArea { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Size; return (s.X * s.Y + s.X * s.Z + s.Y * s.Z) * 2; } } public readonly long Volume { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (IsInvalid) return 0; return SizeX * SizeY * SizeZ; } } public readonly V3l OOO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min; } } public readonly V3l IOO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3l(Max.X, Min.Y, Min.Z); } } public readonly V3l OIO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3l(Min.X, Max.Y, Min.Z); } } public readonly V3l IIO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3l(Max.X, Max.Y, Min.Z); } } public readonly V3l OOI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3l(Min.X, Min.Y, Max.Z); } } public readonly V3l IOI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3l(Max.X, Min.Y, Max.Z); } } public readonly V3l OII { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3l(Min.X, Max.Y, Max.Z); } } public readonly V3l III { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Max; } } #endregion #region Size Manipulations /// /// Return box enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3l EnlargedBy(V3l increment) { return new Box3l((Min - increment), (Max + increment)); } /// /// Return box enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3l EnlargedBy(V3l deltaMin, V3l deltaMax) { return new Box3l((Min - deltaMin), (Max + deltaMax)); } /// /// Return box shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3l ShrunkBy(V3l delta) { return new Box3l((Min + delta), (Max - delta)); } /// /// Return box shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3l ShrunkBy(V3l deltaMin, V3l deltaMax) { return new Box3l((Min + deltaMin), (Max - deltaMax)); } /// /// Enlarges box by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(V3l delta) { Min -= delta; Max += delta; } /// /// Enlarges box by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(V3l deltaMin, V3l deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks box by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(V3l delta) { Min += delta; Max -= delta; } /// /// Shrinks box by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(V3l deltaMin, V3l deltaMax) { Min += deltaMin; Max -= deltaMax; } /// /// Returns a box enlarged by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3l EnlargedBy(long delta) { return new Box3l( new V3l(Min.X - delta, Min.Y - delta, Min.Z - delta), new V3l(Max.X + delta, Max.Y + delta, Max.Z + delta)); } /// /// Returns a box shrunk by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3l ShrunkBy(long delta) { return new Box3l( new V3l(Min.X + delta, Min.Y + delta, Min.Z + delta), new V3l(Max.X - delta, Max.Y - delta, Max.Z - delta)); } /// /// Returns the box enlarged by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3l EnlargedBy( long deltaMinX, long deltaMaxX, long deltaMinY, long deltaMaxY, long deltaMinZ, long deltaMaxZ) { return new Box3l( new V3l(Min.X - deltaMinX, Min.Y - deltaMinY, Min.Z - deltaMinZ), new V3l(Max.X + deltaMaxX, Max.Y + deltaMaxY, Max.Z + deltaMaxZ)); } /// /// Returns the box shrunk by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3l ShrunkBy( long deltaMinX, long deltaMaxX, long deltaMinY, long deltaMaxY, long deltaMinZ, long deltaMaxZ) { return new Box3l( new V3l(Min.X + deltaMinX, Min.Y + deltaMinY, Min.Z + deltaMinZ), new V3l(Max.X - deltaMaxX, Max.Y - deltaMaxY, Max.Z - deltaMaxZ)); } /// /// Enlarges box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(long delta) { Min.X -= delta; Max.X += delta; Min.Y -= delta; Max.Y += delta; Min.Z -= delta; Max.Z += delta; } /// /// Shrinks box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(long delta) { Min.X += delta; Max.X -= delta; Min.Y += delta; Max.Y -= delta; Min.Z += delta; Max.Z -= delta; } /// /// Enlarges the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy( long deltaMinX, long deltaMaxX, long deltaMinY, long deltaMaxY, long deltaMinZ, long deltaMaxZ) { Min.X -= deltaMinX; Max.X += deltaMaxX; Min.Y -= deltaMinY; Max.Y += deltaMaxY; Min.Z -= deltaMinZ; Max.Z += deltaMaxZ; } /// /// Shrinks the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy( long deltaMinX, long deltaMaxX, long deltaMinY, long deltaMaxY, long deltaMinZ, long deltaMaxZ) { Min.X += deltaMinX; Max.X -= deltaMaxX; Min.Y += deltaMinY; Max.Y -= deltaMaxY; Min.Z += deltaMinZ; Max.Z -= deltaMaxZ; } #endregion #region Box Arithmetics /// /// Return the point in the Box that is closest to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l Clamped(V3l p) { return new V3l( p.X < Min.X ? Min.X : (p.X > Max.X ? Max.X : p.X), p.Y < Min.Y ? Min.Y : (p.Y > Max.Y ? Max.Y : p.Y), p.Z < Min.Z ? Min.Z : (p.Z > Max.Z ? Max.Z : p.Z)); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l Lerp(float t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l Lerp(V3f t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l Lerp(double t) => Fun.Lerp(t, Min, Max); /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l Lerp(V3d t) => Fun.Lerp(t, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d InvLerp(V3l y) => Fun.InvLerp(y, Min, Max); /// /// Returns the box with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3l SplitRight(V3l splitValue) { var result = new Box3l(Min, Max); if (splitValue.X > result.Min.X) result.Min.X = splitValue.X; if (splitValue.Y > result.Min.Y) result.Min.Y = splitValue.Y; if (splitValue.Z > result.Min.Z) result.Min.Z = splitValue.Z; return result; } /// /// Returns the box with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3l SplitLeft(V3l splitValue) { var result = new Box3l(Min, Max); if (splitValue.X < result.Max.X) result.Max.X = splitValue.X; if (splitValue.Y < result.Max.Y) result.Max.Y = splitValue.Y; if (splitValue.Z < result.Max.Z) result.Max.Z = splitValue.Z; return result; } /// /// Returns the box extended to contain the supplied box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3l ExtendedBy(Box3l b) { return new Box3l( new V3l( b.Min.X < Min.X ? b.Min.X : Min.X, b.Min.Y < Min.Y ? b.Min.Y : Min.Y, b.Min.Z < Min.Z ? b.Min.Z : Min.Z), new V3l( b.Max.X > Max.X ? b.Max.X : Max.X, b.Max.Y > Max.Y ? b.Max.Y : Max.Y, b.Max.Z > Max.Z ? b.Max.Z : Max.Z)); } /// /// Returns the box extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3l ExtendedBy(V3l v) { return new Box3l( new V3l( v.X < Min.X ? v.X : Min.X, v.Y < Min.Y ? v.Y : Min.Y, v.Z < Min.Z ? v.Z : Min.Z), new V3l( v.X > Max.X ? v.X : Max.X, v.Y > Max.Y ? v.Y : Max.Y, v.Z > Max.Z ? v.Z : Max.Z)); } /// /// Extends the box to contain the supplied box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Box3l box) { if (box.Min.X < Min.X) Min.X = box.Min.X; if (box.Max.X > Max.X) Max.X = box.Max.X; if (box.Min.Y < Min.Y) Min.Y = box.Min.Y; if (box.Max.Y > Max.Y) Max.Y = box.Max.Y; if (box.Min.Z < Min.Z) Min.Z = box.Min.Z; if (box.Max.Z > Max.Z) Max.Z = box.Max.Z; } /// /// Extends the box to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(V3l point) { if (point.X < Min.X) Min.X = point.X; if (point.X > Max.X) Max.X = point.X; if (point.Y < Min.Y) Min.Y = point.Y; if (point.Y > Max.Y) Max.Y = point.Y; if (point.Z < Min.Z) Min.Z = point.Z; if (point.Z > Max.Z) Max.Z = point.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l ExtendXBy(long x) { if (x < Min.X) Min.X = x; if (x > Max.X) Max.X = x; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l ExtendYBy(long y) { if (y < Min.Y) Min.Y = y; if (y > Max.Y) Max.Y = y; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l ExtendZBy(long z) { if (z < Min.Z) Min.Z = z; if (z > Max.Z) Max.Z = z; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l ExtendDimBy(int dim, long x) { if (x < Min[dim]) Min[dim] = x; if (x > Max[dim]) Max[dim] = x; return this; } /// /// Returns true if the box contains the given point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(V3l p) { return p.X >= Min.X && p.X <= Max.X && p.Y >= Min.Y && p.Y <= Max.Y && p.Z >= Min.Z && p.Z <= Max.Z; } /// /// Returns true if the box completely contains the other box. /// A box contains itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Box3l b) { return b.Min.X >= Min.X && b.Max.X <= Max.X && b.Min.Y >= Min.Y && b.Max.Y <= Max.Y && b.Min.Z >= Min.Z && b.Max.Z <= Max.Z; } /// /// Checks if the box is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l Repair() { if (Equals(Box3l.Invalid)) return this; if (Min.X > Max.X) Fun.Swap(ref Min.X, ref Max.X); if (Min.Y > Max.Y) Fun.Swap(ref Min.Y, ref Max.Y); if (Min.Z > Max.Z) Fun.Swap(ref Min.Z, ref Max.Z); return this; } /// /// Returns true if two boxes intersect each other (or one contains the other). /// Boxes DO NOT intersect if only touching from the outside. /// A box intersects itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box3l box) { if (Min.X >= box.Max.X) return false; if (Max.X <= box.Min.X) return false; if (Min.Y >= box.Max.Y) return false; if (Max.Y <= box.Min.Y) return false; if (Min.Z >= box.Max.Z) return false; if (Max.Z <= box.Min.Z) return false; return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box3l box, V3l eps) { if (Min.X - eps.X >= box.Max.X) return false; if (Max.X + eps.X <= box.Min.X) return false; if (Min.Y - eps.Y >= box.Max.Y) return false; if (Max.Y + eps.Y <= box.Min.Y) return false; if (Min.Z - eps.Z >= box.Max.Z) return false; if (Max.Z + eps.Z <= box.Min.Z) return false; return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box3l box, long eps) { if (Min.X - eps >= box.Max.X) return false; if (Max.X + eps <= box.Min.X) return false; if (Min.Y - eps >= box.Max.Y) return false; if (Max.Y + eps <= box.Min.Y) return false; if (Min.Z - eps >= box.Max.Z) return false; if (Max.Z + eps <= box.Min.Z) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3l Invalidate() { Min = V3l.MaxValue; Max = V3l.MinValue; return this; } /// /// Returns where a points coordinates are outside a given box /// /// All outside Flags [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(V3l p0) { Box.Flags bf = Box.Flags.None; if (p0.X < Min.X) bf |= Box.Flags.MinX; else if (p0.X > Max.X) bf |= Box.Flags.MaxX; if (p0.Y < Min.Y) bf |= Box.Flags.MinY; else if (p0.Y > Max.Y) bf |= Box.Flags.MaxY; if (p0.Z < Min.Z) bf |= Box.Flags.MinZ; else if (p0.Z > Max.Z) bf |= Box.Flags.MaxZ; return bf; } /// /// Returns where the planes of the supplied box b are outside /// of the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(Box3l b) { Box.Flags bf = Box.Flags.None; if (b.Min.X < Min.X) bf |= Box.Flags.MinX; if (b.Max.X > Max.X) bf |= Box.Flags.MaxX; if (b.Min.Y < Min.Y) bf |= Box.Flags.MinY; if (b.Max.Y > Max.Y) bf |= Box.Flags.MaxY; if (b.Min.Z < Min.Z) bf |= Box.Flags.MinZ; if (b.Max.Z > Max.Z) bf |= Box.Flags.MaxZ; return bf; } /// /// Gets the minimal and maximal points of the box when seen from the /// supplied direction vector v. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void GetMinMaxInDirection(V3l v, out V3l vMin, out V3l vMax) { vMin = V3l.MinValue; vMax = V3l.MaxValue; if (v.X >= 0) { vMin.X = Min.X; vMax.X = Max.X; } else { vMin.X = Max.X; vMax.X = Min.X; } if (v.Y >= 0) { vMin.Y = Min.Y; vMax.Y = Max.Y; } else { vMin.Y = Max.Y; vMax.Y = Min.Y; } if (v.Z >= 0) { vMin.Z = Min.Z; vMax.Z = Max.Z; } else { vMin.Z = Max.Z; vMax.Z = Min.Z; } } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Box3l a, Box3l b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Box3l a, Box3l b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a box shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l operator +(Box3l box, V3l v) { return new Box3l((box.Min + v), (box.Max + v)); } /// /// Returns a box shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l operator -(Box3l box, V3l v) { return new Box3l((box.Min - v), (box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Box3l other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Box3l o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Box3l box, int i, V3l value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Box3l Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Box3l(V3l.Parse(x[0].ToString()), V3l.Parse(x[1].ToString())); } public static Box3l Parse(Text t) { return t.NestedBracketSplit(1, V3l.Parse, Box3l.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string beginB, string betweenB, string endB, string beginV, string betweenV, string endV) { fp ??= CultureInfo.InvariantCulture; return beginB + Min.ToString(format, fp, beginV, betweenV, endV) + betweenB + Max.ToString(format, fp, beginV, betweenV, endV) + endB; } #endregion #region Static Factories /// /// Returns new box [0, size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l FromSize(V3l size) { return new Box3l(V3l.Zero, size); } /// /// Returns new box [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l FromMinAndSize(V3l min, V3l size) { return new Box3l(min, min + size); } /// /// Returns new box [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l FromCenterAndSize(V3l center, V3l size) { return new Box3l(center - size / 2, center + size / 2); } /// /// Returns new box [0, iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l FromSize(ISize3l iSize) { return new Box3l( V3l.Zero, iSize.Size3l); } /// /// Returns new box [min, min + iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l FromMinAndSize(V3l min, ISize3l iSize) { return new Box3l( min, min + iSize.Size3l); } /// /// Returns new box [center - iSize / 2, center + iSize / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l FromCenterAndSize(V3l center, ISize3l iSize) { var size = iSize.Size3l; return new Box3l(center - size / 2, center + size / 2); } /// /// Creates box from 2 points which need not be Min and Max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l FromPoints(V3l p0, V3l p1) { return new Box3l(Fun.Min(p0, p1), Fun.Max(p0, p1)); } #endregion #region Transforms [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3l Translated(V3l shift) { return IsInvalid ? Box3l.Invalid : new Box3l(Min + shift, Max + shift); } /// /// Returns a scaled box. WARNING: scaling is performed around the origin! /// A negative scale factor will resut in an invalid box! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3l Scaled(V3l factor) { return IsInvalid ? Box3l.Invalid : new Box3l(Min * factor, Max * factor); } /// /// Transforms the box by the given transformation matrix. /// NOTE: Performs IsValid check at 10% CPU time overhead. /// -> Empty bounds (crossed min and max) will remain empty. /// public readonly Box3d Transformed(M44d trafo) { if (Min.X > Max.X || Min.Y > Max.Y || Min.Z > Max.Z) return Box3d.Invalid; var t = new V3d(trafo.M03, trafo.M13, trafo.M23); var res = new Box3d(t, t); double av, bv; av = trafo.M00 * Min.X; bv = trafo.M00 * Max.X; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M01 * Min.Y; bv = trafo.M01 * Max.Y; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M02 * Min.Z; bv = trafo.M02 * Max.Z; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M10 * Min.X; bv = trafo.M10 * Max.X; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } av = trafo.M11 * Min.Y; bv = trafo.M11 * Max.Y; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } av = trafo.M12 * Min.Z; bv = trafo.M12 * Max.Z; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } av = trafo.M20 * Min.X; bv = trafo.M20 * Max.X; if (av < bv) { res.Min.Z += av; res.Max.Z += bv; } else { res.Min.Z += bv; res.Max.Z += av; } av = trafo.M21 * Min.Y; bv = trafo.M21 * Max.Y; if (av < bv) { res.Min.Z += av; res.Max.Z += bv; } else { res.Min.Z += bv; res.Max.Z += av; } av = trafo.M22 * Min.Z; bv = trafo.M22 * Max.Z; if (av < bv) { res.Min.Z += av; res.Max.Z += bv; } else { res.Min.Z += bv; res.Max.Z += av; } return res; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d Transformed(Trafo3d trafo) { return Transformed(trafo.Forward); } #endregion #region Corners /// /// Return the corner of the box with the given index. The corner /// index is constructed in such a way, that bit 0 enumerates the /// x coordinate (0 ... min, 1 ... max), bit 1 enumerates the y /// coordinate, and bit 2 enumerates the z coordinate. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l Corner(int index) { return new V3l( (index & 1) == 0 ? Min.X : Max.X, (index & 2) == 0 ? Min.Y : Max.Y, (index & 4) == 0 ? Min.Z : Max.Z); } /// /// Computes the corners of the box and returns them in an array. /// The order of the corners is determined by their index which is /// constructed as in the method . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l[] ComputeCorners() { return [ Min, new(Max.X, Min.Y, Min.Z), new(Min.X, Max.Y, Min.Z), new(Max.X, Max.Y, Min.Z), new(Min.X, Min.Y, Max.Z), new(Max.X, Min.Y, Max.Z), new(Min.X, Max.Y, Max.Z), Max ]; } /// /// Enumeration of the corners of the box. /// public readonly IEnumerable Corners { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return Min; yield return new V3l(Max.X, Min.Y, Min.Z); yield return new V3l(Min.X, Max.Y, Min.Z); yield return new V3l(Max.X, Max.Y, Min.Z); yield return new V3l(Min.X, Min.Y, Max.Z); yield return new V3l(Max.X, Min.Y, Max.Z); yield return new V3l(Min.X, Max.Y, Max.Z); yield return Max; } } #endregion #region Swizzle methods // TODO: Implement for other dimensions public readonly Range1l X { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1l(Min.X, Max.X); } } public readonly Range1l Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1l(Min.Y, Max.Y); } } public readonly Range1l Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1l(Min.Z, Max.Z); } } public readonly Box2l XY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2l(Min.XY, Max.XY); } } public readonly Box2l XZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2l(Min.XZ, Max.XZ); } } public readonly Box2l YX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2l(Min.YX, Max.YX); } } public readonly Box2l YZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2l(Min.YZ, Max.YZ); } } public readonly Box2l ZX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2l(Min.ZX, Max.ZX); } } public readonly Box2l ZY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2l(Min.ZY, Max.ZY); } } #endregion #region Enumerators /// /// Returns all points from [Min,Max[ with X-Variable in the outer loop. /// public readonly IEnumerable EnumerateInsidePoints() { var p = new V3l(); for (p.X = Min.X; p.X < Max.X; p.X++) for (p.Y = Min.Y; p.Y < Max.Y; p.Y++) for (p.Z = Min.Z; p.Z < Max.Z; p.Z++) yield return p; } #endregion #region IBoundingBox3l Members public readonly Box3l BoundingBox3l { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this; } } #endregion #region IBoundingSphere3d Members public readonly Sphere3d BoundingSphere3d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => IsInvalid ? Sphere3d.Invalid : new Sphere3d((V3d)Center, 0.5 * Size.Length); } #endregion #region ISize3l Members public readonly V3l Size3l { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Size; } } #endregion } public static partial class Box { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l Union(this Box3l a, Box3l b) { return new Box3l(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l Intersection(this Box3l a, Box3l b) { return new Box3l(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } #endregion #region Bounding box for arrays /// /// Returns the bounding box of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l GetBoundingBox(this V3l[] pointArray) { return pointArray.GetBoundingBox(0, pointArray.LongLength); } /// /// Returns the bounding box of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l GetBoundingBox(this V3l[] pointArray, long count) { return pointArray.GetBoundingBox(0, count); } /// /// Returns the bounding box of count elements of the array starting at start. /// public static Box3l GetBoundingBox( this V3l[] pointArray, long start, long count) { if (count <= 0) return Box3l.Invalid; var box = new Box3l(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding box of count elements of the array starting at start. /// public static Box3l GetBoundingBox(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Box3l.Invalid; var box = new Box3l(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding box for lists /// /// Returns the bounding box of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l GetBoundingBox(this List pointList) { return pointList.GetBoundingBox(pointList.Count); } /// /// Returns the bounding box of the first count elements of the list. /// public static Box3l GetBoundingBox(this List pointList, int count) { if (count <= 0) return Box3l.Invalid; var box = new Box3l(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding box for indexed arrays /// /// Returns the bounding box of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l GetBoundingBox(this int[] indexArray, V3l[] pointArray) { return indexArray.GetBoundingBox(0, indexArray.Length, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l GetBoundingBox(this int[] indexArray, int count, V3l[] pointArray) { return indexArray.GetBoundingBox(0, count, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box3l GetBoundingBox(this int[] indexArray, int start, int count, V3l[] pointArray) { if (count <= 0) return Box3l.Invalid; var box = new Box3l(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box3l GetBoundingBox(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Box3l.Invalid; var box = new Box3l(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l GetBoundingBox(this long[] indexArray, V3l[] pointArray) { return indexArray.GetBoundingBox(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3l GetBoundingBox(this long[] indexArray, long count, V3l[] pointArray) { return indexArray.GetBoundingBox(0, count, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box3l GetBoundingBox(this long[] indexArray, long start, long count, V3l[] pointArray) { if (count <= 0) return Box3l.Invalid; var box = new Box3l(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box3l GetBoundingBox(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Box3l.Invalid; var box = new Box3l(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding box for IEnumerable /// /// Returns the bounding box of the elements of the collection. /// public static Box3l GetBoundingBox(this IEnumerable points) { var box = Box3l.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion #region Get octant /// /// Octant 0-7. /// 0th, 1st and 2nd bit encodes x-, y-, z-axis, respectively. /// E.g. 0 is octant [box.Min, box.Center], 7 is octant [box.Center, box.Max]. /// public static Box3l GetOctant(this Box3l box, int i) { if (i < 0 || i > 7) throw new IndexOutOfRangeException(); long x0, x1, y0, y1, z0, z1; var c = box.Center; if ((i & 1) == 0) { x0 = box.Min.X; x1 = c.X; } else { x0 = c.X; x1 = box.Max.X; } if ((i & 2) == 0) { y0 = box.Min.Y; y1 = c.Y; } else { y0 = c.Y; y1 = box.Max.Y; } if (i < 4) { z0 = box.Min.Z; z1 = c.Z; } else { z0 = c.Z; z1 = box.Max.Z; } return new Box3l(new V3l(x0, y0, z0), new V3l(x1, y1, z1)); } #endregion #region Outline corners /// /// Gets outline corner indices of a box as seen from given position (in counter-clockwise order). /// Returns null if position is inside the box. /// public static int[] GetOutlineCornerIndicesCCW(this Box3l box, V3l fromPosition) { if (fromPosition.X < box.Min.X) { //-X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // -X -Y -Z return [1, 5, 4, 6, 2, 3]; } else if (fromPosition.Z > box.Max.Z) { // -X -Y +Z return [0, 1, 5, 7, 6, 2]; } else { // -X -Y Z return [1, 5, 6, 2]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // -X +Y -Z return [0, 4, 6, 7, 3, 1]; } else if (fromPosition.Z > box.Max.Z) { // -X +Y +Z return [0, 4, 5, 7, 3, 2]; } else { // -X +Y Z return [0, 4, 7, 3]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // -X Y -Z return [1, 4, 6, 3]; } else if (fromPosition.Z > box.Max.Z) { // -X Y +Z return [0, 5, 7, 2]; } else { // -X Y Z return [0, 4, 6, 2]; } } } else if (fromPosition.X > box.Max.X) { // +X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // +X -Y -Z return [0, 2, 3, 7, 5, 4]; } else if (fromPosition.Z > box.Max.Z) { // +X -Y +Z return [0, 1, 3, 7, 6, 4]; } else { // +X -Y Z return [0, 3, 7, 4]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // +X +Y -Z return [0, 2, 6, 7, 5, 1]; } else if (fromPosition.Z > box.Max.Z) { // +X +Y +Z return [1, 3, 2, 6, 4, 5]; } else { // +X +Y Z return [1, 2, 6, 5]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // +X Y -Z return [0, 2, 7, 5]; } else if (fromPosition.Z > box.Max.Z) { // +X Y +Z return [1, 3, 6, 4]; } else { // +X Y Z return [1, 3, 7, 5]; } } } else { // X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // X -Y -Z return [2, 3, 5, 4]; } else if (fromPosition.Z > box.Max.Z) { // X -Y +Z return [0, 1, 7, 6]; } else { // X -Y Z return [0, 1, 5, 4]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // X +Y -Z return [0, 6, 7, 1]; } else if (fromPosition.Z > box.Max.Z) { // X +Y +Z return [2, 4, 5, 3]; } else { // X +Y Z return [2, 6, 7, 3]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // X Y -Z return [0, 2, 3, 1]; } else if (fromPosition.Z > box.Max.Z) { // X Y +Z return [4, 5, 7, 6]; } else { // X Y Z return null; } } } } /// /// Gets outline corner indices of a box as seen from given position (in clockwise order). /// Returns null if position is inside the box. /// public static int[] GetOutlineCornerIndicesCW(this Box3l box, V3l fromPosition) { if (fromPosition.X < box.Min.X) { //-X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // -X -Y -Z return [1, 3, 2, 6, 4, 5]; } else if (fromPosition.Z > box.Max.Z) { // -X -Y +Z return [0, 2, 6, 7, 5, 1]; } else { // -X -Y Z return [1, 2, 6, 5]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // -X +Y -Z return [0, 1, 3, 7, 6, 4]; } else if (fromPosition.Z > box.Max.Z) { // -X +Y +Z return [0, 2, 3, 7, 5, 4]; } else { // -X +Y Z return [0, 3, 7, 4]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // -X Y -Z return [1, 3, 6, 4]; } else if (fromPosition.Z > box.Max.Z) { // -X Y +Z return [0, 2, 7, 5]; } else { // -X Y Z return [0, 2, 6, 4]; } } } else if (fromPosition.X > box.Max.X) { // +X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // +X -Y -Z return [0, 4, 5, 7, 3, 2]; } else if (fromPosition.Z > box.Max.Z) { // +X -Y +Z return [0, 4, 6, 7, 3, 1]; } else { // +X -Y Z return [0, 4, 7, 3]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // +X +Y -Z return [0, 1, 5, 7, 6, 2]; } else if (fromPosition.Z > box.Max.Z) { // +X +Y +Z return [1, 5, 4, 6, 2, 3]; } else { // +X +Y Z return [1, 5, 6, 2]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // +X Y -Z return [0, 5, 7, 2]; } else if (fromPosition.Z > box.Max.Z) { // +X Y +Z return [1, 4, 6, 3]; } else { // +X Y Z return [1, 5, 7, 3]; } } } else { // X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // X -Y -Z return [2, 4, 5, 3]; } else if (fromPosition.Z > box.Max.Z) { // X -Y +Z return [0, 6, 7, 1]; } else { // X -Y Z return [0, 4, 5, 1]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // X +Y -Z return [0, 1, 7, 6]; } else if (fromPosition.Z > box.Max.Z) { // X +Y +Z return [2, 3, 5, 4]; } else { // X +Y Z return [2, 3, 7, 6]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // X Y -Z return [0, 1, 3, 2]; } else if (fromPosition.Z > box.Max.Z) { // X Y +Z return [4, 6, 7, 5]; } else { // X Y Z return null; } } } } /// /// Gets outline corners of a box as seen from given position (in counter-clockwise order). /// Returns null if position is inside the box. /// public static V3l[] GetOutlineCornersCCW(this Box3l box, V3l fromPosition) { var cs = box.ComputeCorners(); return GetOutlineCornerIndicesCCW(box, fromPosition)?.Map(i => cs[i]); } /// /// Gets outline corners of a box as seen from given position (in clockwise order). /// Returns null if position is inside the box. /// public static V3l[] GetOutlineCornersCW(this Box3l box, V3l fromPosition) { var cs = box.ComputeCorners(); return GetOutlineCornerIndicesCW(box, fromPosition)?.Map(i => cs[i]); } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Box3l a, Box3l b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Box3l a, Box3l b, long tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Box3lAndFlags [DataContract] public struct Box3lAndFlags { [DataMember] public Box.Flags BFlags; [DataMember] public Box3l BBox; public Box3lAndFlags(Box3l union, Box3l box0, Box3l box1) { BFlags = 0; BBox = union; if (box0.Min.X > union.Min.X) { BBox.Min.X = box0.Min.X; BFlags |= Box.Flags.MinX0; } if (box0.Min.Y > union.Min.Y) { BBox.Min.Y = box0.Min.Y; BFlags |= Box.Flags.MinY0; } if (box0.Min.Z > union.Min.Z) { BBox.Min.Z = box0.Min.Z; BFlags |= Box.Flags.MinZ0; } if (box0.Max.X < union.Max.X) { BBox.Max.X = box0.Max.X; BFlags |= Box.Flags.MaxX0; } if (box0.Max.Y < union.Max.Y) { BBox.Max.Y = box0.Max.Y; BFlags |= Box.Flags.MaxY0; } if (box0.Max.Z < union.Max.Z) { BBox.Max.Z = box0.Max.Z; BFlags |= Box.Flags.MaxZ0; } if (box1.Min.X > union.Min.X) { BBox.Min.X = box1.Min.X; BFlags |= Box.Flags.MinX1; } if (box1.Min.Y > union.Min.Y) { BBox.Min.Y = box1.Min.Y; BFlags |= Box.Flags.MinY1; } if (box1.Min.Z > union.Min.Z) { BBox.Min.Z = box1.Min.Z; BFlags |= Box.Flags.MinZ1; } if (box1.Max.X < union.Max.X) { BBox.Max.X = box1.Max.X; BFlags |= Box.Flags.MaxX1; } if (box1.Max.Y < union.Max.Y) { BBox.Max.Y = box1.Max.Y; BFlags |= Box.Flags.MaxY1; } if (box1.Max.Z < union.Max.Z) { BBox.Max.Z = box1.Max.Z; BFlags |= Box.Flags.MaxZ1; } } } #endregion #region Box3f [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Box3f : IEquatable, IRange, IBoundingBox3f, ISize3f, IBoundingSphere3f, IFormattable { [DataMember] public V3f Min; [DataMember] public V3f Max; #region Constructors /// /// Construct a Box3f from a Box3i. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f(Box3i b) { Min = (V3f) b.Min; Max = (V3f) b.Max; } /// /// Construct a Box3f from a Box3l. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f(Box3l b) { Min = (V3f) b.Min; Max = (V3f) b.Max; } /// /// Construct a Box3f from a Box3d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f(Box3d b) { Min = (V3f) b.Min; Max = (V3f) b.Max; } /// /// Creates a box from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f(V3f min, V3f max) { Min = min; Max = max; } /// /// Creates a box from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { Min.X = minX; Min.Y = minY; Min.Z = minZ; Max.X = maxX; Max.Y = maxY; Max.Z = maxZ; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f(V3f pnt) { Min = pnt; Max = pnt; } /// /// Creates a box from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f(V3f p0, V3f p1, V3f p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a box from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f(V3f p0, V3f p1, V3f p2, V3f p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f(Box3f range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f(Box3f b0, Box3f b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f(Box3f b0, Box3f b1, Box3f b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f(Box3f b0, Box3f b1, Box3f b2, Box3f b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f(V3f[] points) : this((ReadOnlySpan)points) { } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f(ReadOnlySpan points) { Min = V3f.MaxValue; Max = V3f.MinValue; if (points == null) return; var count = points.Length; for (var i = 0; i < count; i++) ExtendBy(points[i]); } /// /// Creates box as the bounding box of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f(V3f[] points, long start, long count) { if (count <= 0) { Min = Invalid.Min; Max = Invalid.Max; } else { Min = Max = points[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(points[i]); } } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f(IEnumerable points) { Min = V3f.MaxValue; Max = V3f.MinValue; if (points == null) return; foreach (V3f p in points) ExtendBy(p); } /// /// Creates box as the bounding box of given boxes. /// public Box3f(IEnumerable boxes) { Min = V3f.MaxValue; Max = V3f.MinValue; if (boxes == null) return; foreach (var box in boxes) ExtendBy(box); } /// /// Creates box from a Range1 in each direction. /// public Box3f(Range1f rangeX, Range1f rangeY, Range1f rangeZ) { Min.X = rangeX.Min; Max.X = rangeX.Max; Min.Y = rangeY.Min; Max.Y = rangeY.Max; Min.Z = rangeZ.Min; Max.Z = rangeZ.Max; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box3f(Box3i b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box3f(Box3l b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box3f(Box3d b) => new(b); #endregion #region Constants /// /// A range with crossed limits. /// public static Box3f Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V3f.MaxValue, V3f.MinValue); } /// /// The largest possible range. /// public static Box3f Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V3f.MinValue, V3f.MaxValue); } /// /// The unit interval [0, 1]. /// public static Box3f Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V3f.Zero, V3f.One); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AnyGreaterOrEqual(Max); } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AllSmallerOrEqual(Max); } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AnyGreater(Max) || Min.IsNaN || Max.IsNaN; } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Calculates size of the box. /// [XmlIgnore] public V3f Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (Min + value); } } public readonly V3f Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return ((Min + Max) / 2); } } [XmlIgnore] public float SizeX { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.X - Min.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.X = Min.X + value; } } public readonly Range1f RangeX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1f(Min.X, Max.X); } } [XmlIgnore] public float SizeY { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Y - Min.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Y = Min.Y + value; } } public readonly Range1f RangeY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1f(Min.Y, Max.Y); } } [XmlIgnore] public float SizeZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Z - Min.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Z = Min.Z + value; } } public readonly Range1f RangeZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1f(Min.Z, Max.Z); } } /// /// Index of the longest dimension of the box. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { int major = 0; var s = Size; if (s.Y > s.X) major = 1; if (s.Z > s[major]) major = 2; return major; } } /// /// Index of the shortest dimension of the box. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { int minor = 0; var s = Size; if (s.Y < s.X) minor = 1; if (s.Z < s[minor]) minor = 2; return minor; } } public readonly float SurfaceArea { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Size; return (s.X * s.Y + s.X * s.Z + s.Y * s.Z) * 2; } } public readonly float Volume { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (IsInvalid) return 0; return SizeX * SizeY * SizeZ; } } public readonly V3f OOO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min; } } public readonly V3f IOO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3f(Max.X, Min.Y, Min.Z); } } public readonly V3f OIO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3f(Min.X, Max.Y, Min.Z); } } public readonly V3f IIO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3f(Max.X, Max.Y, Min.Z); } } public readonly V3f OOI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3f(Min.X, Min.Y, Max.Z); } } public readonly V3f IOI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3f(Max.X, Min.Y, Max.Z); } } public readonly V3f OII { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3f(Min.X, Max.Y, Max.Z); } } public readonly V3f III { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Max; } } #endregion #region Size Manipulations /// /// Return box enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f EnlargedBy(V3f increment) { return new Box3f((Min - increment), (Max + increment)); } /// /// Return box enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f EnlargedBy(V3f deltaMin, V3f deltaMax) { return new Box3f((Min - deltaMin), (Max + deltaMax)); } /// /// Return box shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f ShrunkBy(V3f delta) { return new Box3f((Min + delta), (Max - delta)); } /// /// Return box shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f ShrunkBy(V3f deltaMin, V3f deltaMax) { return new Box3f((Min + deltaMin), (Max - deltaMax)); } /// /// Enlarges box by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(V3f delta) { Min -= delta; Max += delta; } /// /// Enlarges box by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(V3f deltaMin, V3f deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks box by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(V3f delta) { Min += delta; Max -= delta; } /// /// Shrinks box by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(V3f deltaMin, V3f deltaMax) { Min += deltaMin; Max -= deltaMax; } /// /// Returns a box enlarged by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f EnlargedBy(float delta) { return new Box3f( new V3f(Min.X - delta, Min.Y - delta, Min.Z - delta), new V3f(Max.X + delta, Max.Y + delta, Max.Z + delta)); } /// /// Returns a box shrunk by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f ShrunkBy(float delta) { return new Box3f( new V3f(Min.X + delta, Min.Y + delta, Min.Z + delta), new V3f(Max.X - delta, Max.Y - delta, Max.Z - delta)); } /// /// Returns the box enlarged by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f EnlargedBy( float deltaMinX, float deltaMaxX, float deltaMinY, float deltaMaxY, float deltaMinZ, float deltaMaxZ) { return new Box3f( new V3f(Min.X - deltaMinX, Min.Y - deltaMinY, Min.Z - deltaMinZ), new V3f(Max.X + deltaMaxX, Max.Y + deltaMaxY, Max.Z + deltaMaxZ)); } /// /// Returns the box shrunk by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f ShrunkBy( float deltaMinX, float deltaMaxX, float deltaMinY, float deltaMaxY, float deltaMinZ, float deltaMaxZ) { return new Box3f( new V3f(Min.X + deltaMinX, Min.Y + deltaMinY, Min.Z + deltaMinZ), new V3f(Max.X - deltaMaxX, Max.Y - deltaMaxY, Max.Z - deltaMaxZ)); } /// /// Enlarges box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(float delta) { Min.X -= delta; Max.X += delta; Min.Y -= delta; Max.Y += delta; Min.Z -= delta; Max.Z += delta; } /// /// Shrinks box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(float delta) { Min.X += delta; Max.X -= delta; Min.Y += delta; Max.Y -= delta; Min.Z += delta; Max.Z -= delta; } /// /// Enlarges the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy( float deltaMinX, float deltaMaxX, float deltaMinY, float deltaMaxY, float deltaMinZ, float deltaMaxZ) { Min.X -= deltaMinX; Max.X += deltaMaxX; Min.Y -= deltaMinY; Max.Y += deltaMaxY; Min.Z -= deltaMinZ; Max.Z += deltaMaxZ; } /// /// Shrinks the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy( float deltaMinX, float deltaMaxX, float deltaMinY, float deltaMaxY, float deltaMinZ, float deltaMaxZ) { Min.X += deltaMinX; Max.X -= deltaMaxX; Min.Y += deltaMinY; Max.Y -= deltaMaxY; Min.Z += deltaMinZ; Max.Z -= deltaMaxZ; } /// /// Return box scaled by the supplied factor around its center. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f ScaledFromCenterBy(float factor) { var size = Size; var increment = (size * factor - size) / 2; return new Box3f(Min - increment, Max + increment); } /// /// Return box scaled by the supplied factor around its center. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f ScaledFromCenterBy(V3f vectorFactor) { var size = Size; var increment = (size * vectorFactor - size) / 2; return new Box3f(Min - increment, Max + increment); } /// /// Return a box enlarged in all directions by the supplied epsilon which is /// measured with respect to the box diagonal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f EnlargedByRelativeEps(float eps) { return EnlargedBy(eps * Size.Length); } /// /// Enlarge the box in all directions by the supplied epsilon which is /// measured with respect to the box diagonal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeByRelativeEps(float eps) { EnlargeBy(eps * Size.Length); } #endregion #region Box Arithmetics /// /// Return the point in the Box that is closest to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f Clamped(V3f p) { return new V3f( p.X < Min.X ? Min.X : (p.X > Max.X ? Max.X : p.X), p.Y < Min.Y ? Min.Y : (p.Y > Max.Y ? Max.Y : p.Y), p.Z < Min.Z ? Min.Z : (p.Z > Max.Z ? Max.Z : p.Z)); } /// /// Returns the squared distance to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double DistanceSquared(V3f p) { return (p.X < Min.X ? (Min.X - p.X) * (Min.X - p.X) : (p.X > Max.X ? (p.X - Max.X) * (p.X - Max.X) : 0.0)) + (p.Y < Min.Y ? (Min.Y - p.Y) * (Min.Y - p.Y) : (p.Y > Max.Y ? (p.Y - Max.Y) * (p.Y - Max.Y) : 0.0)) + (p.Z < Min.Z ? (Min.Z - p.Z) * (Min.Z - p.Z) : (p.Z > Max.Z ? (p.Z - Max.Z) * (p.Z - Max.Z) : 0.0)); } /// /// Returns the distance to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double Distance(V3f p) { return Fun.Sqrt( (p.X < Min.X ? (Min.X - p.X) * (Min.X - p.X) : (p.X > Max.X ? (p.X - Max.X) * (p.X - Max.X) : 0.0)) + (p.Y < Min.Y ? (Min.Y - p.Y) * (Min.Y - p.Y) : (p.Y > Max.Y ? (p.Y - Max.Y) * (p.Y - Max.Y) : 0.0)) + (p.Z < Min.Z ? (Min.Z - p.Z) * (Min.Z - p.Z) : (p.Z > Max.Z ? (p.Z - Max.Z) * (p.Z - Max.Z) : 0.0))); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f Lerp(float x) => Fun.Lerp(x, Min, Max); /// /// Interpolate linearly in each dimension. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f Lerp(V3f p) => Fun.Lerp(p, Min, Max); /// /// Interpolate linearly in each dimension. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f Lerp(float x, float y, float z) => Fun.Lerp(new V3f(x, y, z), Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f InvLerp(V3f p) => Fun.InvLerp(p, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f InvLerp(float x, float y, float z) => Fun.InvLerp(new V3f(x, y, z), Min, Max); /// /// Returns the box with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f SplitRight(V3f splitValue) { var result = new Box3f(Min, Max); if (splitValue.X > result.Min.X) result.Min.X = splitValue.X; if (splitValue.Y > result.Min.Y) result.Min.Y = splitValue.Y; if (splitValue.Z > result.Min.Z) result.Min.Z = splitValue.Z; return result; } /// /// Returns the box with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f SplitLeft(V3f splitValue) { var result = new Box3f(Min, Max); if (splitValue.X < result.Max.X) result.Max.X = splitValue.X; if (splitValue.Y < result.Max.Y) result.Max.Y = splitValue.Y; if (splitValue.Z < result.Max.Z) result.Max.Z = splitValue.Z; return result; } /// /// Returns the box extended to contain the supplied box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f ExtendedBy(Box3f b) { return new Box3f( new V3f( b.Min.X < Min.X ? b.Min.X : Min.X, b.Min.Y < Min.Y ? b.Min.Y : Min.Y, b.Min.Z < Min.Z ? b.Min.Z : Min.Z), new V3f( b.Max.X > Max.X ? b.Max.X : Max.X, b.Max.Y > Max.Y ? b.Max.Y : Max.Y, b.Max.Z > Max.Z ? b.Max.Z : Max.Z)); } /// /// Returns the box extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f ExtendedBy(V3f v) { return new Box3f( new V3f( v.X < Min.X ? v.X : Min.X, v.Y < Min.Y ? v.Y : Min.Y, v.Z < Min.Z ? v.Z : Min.Z), new V3f( v.X > Max.X ? v.X : Max.X, v.Y > Max.Y ? v.Y : Max.Y, v.Z > Max.Z ? v.Z : Max.Z)); } /// /// Extends the box to contain the supplied box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Box3f box) { if (box.Min.X < Min.X) Min.X = box.Min.X; if (box.Max.X > Max.X) Max.X = box.Max.X; if (box.Min.Y < Min.Y) Min.Y = box.Min.Y; if (box.Max.Y > Max.Y) Max.Y = box.Max.Y; if (box.Min.Z < Min.Z) Min.Z = box.Min.Z; if (box.Max.Z > Max.Z) Max.Z = box.Max.Z; } /// /// Extends the box to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(V3f point) { if (point.X < Min.X) Min.X = point.X; if (point.X > Max.X) Max.X = point.X; if (point.Y < Min.Y) Min.Y = point.Y; if (point.Y > Max.Y) Max.Y = point.Y; if (point.Z < Min.Z) Min.Z = point.Z; if (point.Z > Max.Z) Max.Z = point.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f ExtendXBy(float x) { if (x < Min.X) Min.X = x; if (x > Max.X) Max.X = x; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f ExtendYBy(float y) { if (y < Min.Y) Min.Y = y; if (y > Max.Y) Max.Y = y; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f ExtendZBy(float z) { if (z < Min.Z) Min.Z = z; if (z > Max.Z) Max.Z = z; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f ExtendDimBy(int dim, float x) { if (x < Min[dim]) Min[dim] = x; if (x > Max[dim]) Max[dim] = x; return this; } /// /// Returns true if the box contains the given point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(V3f p) { return p.X >= Min.X && p.X <= Max.X && p.Y >= Min.Y && p.Y <= Max.Y && p.Z >= Min.Z && p.Z <= Max.Z; } /// /// Returns true if the box completely contains the other box. /// A box contains itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Box3f b) { return b.Min.X >= Min.X && b.Max.X <= Max.X && b.Min.Y >= Min.Y && b.Max.Y <= Max.Y && b.Min.Z >= Min.Z && b.Max.Z <= Max.Z; } /// /// Checks if the box is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f Repair() { if (Equals(Box3f.Invalid)) return this; if (Min.X > Max.X) Fun.Swap(ref Min.X, ref Max.X); if (Min.Y > Max.Y) Fun.Swap(ref Min.Y, ref Max.Y); if (Min.Z > Max.Z) Fun.Swap(ref Min.Z, ref Max.Z); return this; } /// /// Returns true if two boxes intersect each other (or one contains the other). /// Boxes DO NOT intersect if only touching from the outside. /// A box intersects itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box3f box) { if (Min.X >= box.Max.X) return false; if (Max.X <= box.Min.X) return false; if (Min.Y >= box.Max.Y) return false; if (Max.Y <= box.Min.Y) return false; if (Min.Z >= box.Max.Z) return false; if (Max.Z <= box.Min.Z) return false; return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box3f box, V3f eps) { if (Min.X - eps.X >= box.Max.X) return false; if (Max.X + eps.X <= box.Min.X) return false; if (Min.Y - eps.Y >= box.Max.Y) return false; if (Max.Y + eps.Y <= box.Min.Y) return false; if (Min.Z - eps.Z >= box.Max.Z) return false; if (Max.Z + eps.Z <= box.Min.Z) return false; return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box3f box, float eps) { if (Min.X - eps >= box.Max.X) return false; if (Max.X + eps <= box.Min.X) return false; if (Min.Y - eps >= box.Max.Y) return false; if (Max.Y + eps <= box.Min.Y) return false; if (Min.Z - eps >= box.Max.Z) return false; if (Max.Z + eps <= box.Min.Z) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3f Invalidate() { Min = V3f.MaxValue; Max = V3f.MinValue; return this; } /// /// Returns where a points coordinates are outside a given box /// /// All outside Flags [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(V3f p0) { Box.Flags bf = Box.Flags.None; if (p0.X < Min.X) bf |= Box.Flags.MinX; else if (p0.X > Max.X) bf |= Box.Flags.MaxX; if (p0.Y < Min.Y) bf |= Box.Flags.MinY; else if (p0.Y > Max.Y) bf |= Box.Flags.MaxY; if (p0.Z < Min.Z) bf |= Box.Flags.MinZ; else if (p0.Z > Max.Z) bf |= Box.Flags.MaxZ; return bf; } /// /// Returns where the planes of the supplied box b are outside /// of the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(Box3f b) { Box.Flags bf = Box.Flags.None; if (b.Min.X < Min.X) bf |= Box.Flags.MinX; if (b.Max.X > Max.X) bf |= Box.Flags.MaxX; if (b.Min.Y < Min.Y) bf |= Box.Flags.MinY; if (b.Max.Y > Max.Y) bf |= Box.Flags.MaxY; if (b.Min.Z < Min.Z) bf |= Box.Flags.MinZ; if (b.Max.Z > Max.Z) bf |= Box.Flags.MaxZ; return bf; } /// /// Gets the minimal and maximal points of the box when seen from the /// supplied direction vector v. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void GetMinMaxInDirection(V3f v, out V3f vMin, out V3f vMax) { vMin = V3f.MinValue; vMax = V3f.MaxValue; if (v.X >= 0) { vMin.X = Min.X; vMax.X = Max.X; } else { vMin.X = Max.X; vMax.X = Min.X; } if (v.Y >= 0) { vMin.Y = Min.Y; vMax.Y = Max.Y; } else { vMin.Y = Max.Y; vMax.Y = Min.Y; } if (v.Z >= 0) { vMin.Z = Min.Z; vMax.Z = Max.Z; } else { vMin.Z = Max.Z; vMax.Z = Min.Z; } } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Box3f a, Box3f b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Box3f a, Box3f b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a box shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f operator +(Box3f box, V3f v) { return new Box3f((box.Min + v), (box.Max + v)); } /// /// Returns a box shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f operator -(Box3f box, V3f v) { return new Box3f((box.Min - v), (box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Box3f other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Box3f o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Box3f box, int i, V3f value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Box3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Box3f(V3f.Parse(x[0].ToString()), V3f.Parse(x[1].ToString())); } public static Box3f Parse(Text t) { return t.NestedBracketSplit(1, V3f.Parse, Box3f.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string beginB, string betweenB, string endB, string beginV, string betweenV, string endV) { fp ??= CultureInfo.InvariantCulture; return beginB + Min.ToString(format, fp, beginV, betweenV, endV) + betweenB + Max.ToString(format, fp, beginV, betweenV, endV) + endB; } #endregion #region Static Factories /// /// Returns new box [0, size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f FromSize(V3f size) { return new Box3f(V3f.Zero, size); } /// /// Returns new box [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f FromMinAndSize(V3f min, V3f size) { return new Box3f(min, min + size); } /// /// Returns new box [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f FromCenterAndSize(V3f center, V3f size) { return new Box3f(center - size / 2, center + size / 2); } /// /// Returns new box [0, iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f FromSize(ISize3f iSize) { return new Box3f( V3f.Zero, iSize.Size3f); } /// /// Returns new box [min, min + iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f FromMinAndSize(V3f min, ISize3f iSize) { return new Box3f( min, min + iSize.Size3f); } /// /// Returns new box [center - iSize / 2, center + iSize / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f FromCenterAndSize(V3f center, ISize3f iSize) { var size = iSize.Size3f; return new Box3f(center - size / 2, center + size / 2); } /// /// Creates box from 2 points which need not be Min and Max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f FromPoints(V3f p0, V3f p1) { return new Box3f(Fun.Min(p0, p1), Fun.Max(p0, p1)); } #endregion #region Transforms [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f Translated(V3f shift) { return IsInvalid ? Box3f.Invalid : new Box3f(Min + shift, Max + shift); } /// /// Returns a scaled box. WARNING: scaling is performed around the origin! /// A negative scale factor will resut in an invalid box! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f Scaled(V3f factor) { return IsInvalid ? Box3f.Invalid : new Box3f(Min * factor, Max * factor); } /// /// Transforms the box by the given transformation matrix. /// NOTE: Performs IsValid check at 10% CPU time overhead. /// -> Empty bounds (crossed min and max) will remain empty. /// public readonly Box3f Transformed(M44f trafo) { if (Min.X > Max.X || Min.Y > Max.Y || Min.Z > Max.Z) return Box3f.Invalid; var t = new V3f(trafo.M03, trafo.M13, trafo.M23); var res = new Box3f(t, t); float av, bv; av = trafo.M00 * Min.X; bv = trafo.M00 * Max.X; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M01 * Min.Y; bv = trafo.M01 * Max.Y; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M02 * Min.Z; bv = trafo.M02 * Max.Z; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M10 * Min.X; bv = trafo.M10 * Max.X; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } av = trafo.M11 * Min.Y; bv = trafo.M11 * Max.Y; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } av = trafo.M12 * Min.Z; bv = trafo.M12 * Max.Z; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } av = trafo.M20 * Min.X; bv = trafo.M20 * Max.X; if (av < bv) { res.Min.Z += av; res.Max.Z += bv; } else { res.Min.Z += bv; res.Max.Z += av; } av = trafo.M21 * Min.Y; bv = trafo.M21 * Max.Y; if (av < bv) { res.Min.Z += av; res.Max.Z += bv; } else { res.Min.Z += bv; res.Max.Z += av; } av = trafo.M22 * Min.Z; bv = trafo.M22 * Max.Z; if (av < bv) { res.Min.Z += av; res.Max.Z += bv; } else { res.Min.Z += bv; res.Max.Z += av; } return res; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3f Transformed(Trafo3f trafo) { return Transformed(trafo.Forward); } #endregion #region Corners /// /// Return the corner of the box with the given index. The corner /// index is constructed in such a way, that bit 0 enumerates the /// x coordinate (0 ... min, 1 ... max), bit 1 enumerates the y /// coordinate, and bit 2 enumerates the z coordinate. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f Corner(int index) { return new V3f( (index & 1) == 0 ? Min.X : Max.X, (index & 2) == 0 ? Min.Y : Max.Y, (index & 4) == 0 ? Min.Z : Max.Z); } /// /// Computes the corners of the box and returns them in an array. /// The order of the corners is determined by their index which is /// constructed as in the method . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f[] ComputeCorners() { return [ Min, new(Max.X, Min.Y, Min.Z), new(Min.X, Max.Y, Min.Z), new(Max.X, Max.Y, Min.Z), new(Min.X, Min.Y, Max.Z), new(Max.X, Min.Y, Max.Z), new(Min.X, Max.Y, Max.Z), Max ]; } /// /// Enumeration of the corners of the box. /// public readonly IEnumerable Corners { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return Min; yield return new V3f(Max.X, Min.Y, Min.Z); yield return new V3f(Min.X, Max.Y, Min.Z); yield return new V3f(Max.X, Max.Y, Min.Z); yield return new V3f(Min.X, Min.Y, Max.Z); yield return new V3f(Max.X, Min.Y, Max.Z); yield return new V3f(Min.X, Max.Y, Max.Z); yield return Max; } } #endregion #region Swizzle methods // TODO: Implement for other dimensions public readonly Range1f X { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1f(Min.X, Max.X); } } public readonly Range1f Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1f(Min.Y, Max.Y); } } public readonly Range1f Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1f(Min.Z, Max.Z); } } public readonly Box2f XY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2f(Min.XY, Max.XY); } } public readonly Box2f XZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2f(Min.XZ, Max.XZ); } } public readonly Box2f YX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2f(Min.YX, Max.YX); } } public readonly Box2f YZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2f(Min.YZ, Max.YZ); } } public readonly Box2f ZX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2f(Min.ZX, Max.ZX); } } public readonly Box2f ZY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2f(Min.ZY, Max.ZY); } } #endregion #region Enumerators #endregion #region IBoundingBox3f Members public readonly Box3f BoundingBox3f { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this; } } #endregion #region IBoundingSphere3f Members public readonly Sphere3f BoundingSphere3f { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => IsInvalid ? Sphere3f.Invalid : new Sphere3f(Center, 0.5f * Size.Length); } #endregion #region ISize3f Members public readonly V3f Size3f { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Size; } } #endregion } public static partial class Box { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f Union(this Box3f a, Box3f b) { return new Box3f(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f Intersection(this Box3f a, Box3f b) { return new Box3f(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } #endregion #region Bounding box for arrays /// /// Returns the bounding box of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f GetBoundingBox(this V3f[] pointArray) { return pointArray.GetBoundingBox(0, pointArray.LongLength); } /// /// Returns the bounding box of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f GetBoundingBox(this V3f[] pointArray, long count) { return pointArray.GetBoundingBox(0, count); } /// /// Returns the bounding box of count elements of the array starting at start. /// public static Box3f GetBoundingBox( this V3f[] pointArray, long start, long count) { if (count <= 0) return Box3f.Invalid; var box = new Box3f(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding box of count elements of the array starting at start. /// public static Box3f GetBoundingBox(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Box3f.Invalid; var box = new Box3f(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding box for lists /// /// Returns the bounding box of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f GetBoundingBox(this List pointList) { return pointList.GetBoundingBox(pointList.Count); } /// /// Returns the bounding box of the first count elements of the list. /// public static Box3f GetBoundingBox(this List pointList, int count) { if (count <= 0) return Box3f.Invalid; var box = new Box3f(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding box for indexed arrays /// /// Returns the bounding box of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f GetBoundingBox(this int[] indexArray, V3f[] pointArray) { return indexArray.GetBoundingBox(0, indexArray.Length, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f GetBoundingBox(this int[] indexArray, int count, V3f[] pointArray) { return indexArray.GetBoundingBox(0, count, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box3f GetBoundingBox(this int[] indexArray, int start, int count, V3f[] pointArray) { if (count <= 0) return Box3f.Invalid; var box = new Box3f(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box3f GetBoundingBox(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Box3f.Invalid; var box = new Box3f(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f GetBoundingBox(this long[] indexArray, V3f[] pointArray) { return indexArray.GetBoundingBox(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3f GetBoundingBox(this long[] indexArray, long count, V3f[] pointArray) { return indexArray.GetBoundingBox(0, count, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box3f GetBoundingBox(this long[] indexArray, long start, long count, V3f[] pointArray) { if (count <= 0) return Box3f.Invalid; var box = new Box3f(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box3f GetBoundingBox(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Box3f.Invalid; var box = new Box3f(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding box for IEnumerable /// /// Returns the bounding box of the elements of the collection. /// public static Box3f GetBoundingBox(this IEnumerable points) { var box = Box3f.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion #region Get octant /// /// Octant 0-7. /// 0th, 1st and 2nd bit encodes x-, y-, z-axis, respectively. /// E.g. 0 is octant [box.Min, box.Center], 7 is octant [box.Center, box.Max]. /// public static Box3f GetOctant(this Box3f box, int i) { if (i < 0 || i > 7) throw new IndexOutOfRangeException(); float x0, x1, y0, y1, z0, z1; var c = box.Center; if ((i & 1) == 0) { x0 = box.Min.X; x1 = c.X; } else { x0 = c.X; x1 = box.Max.X; } if ((i & 2) == 0) { y0 = box.Min.Y; y1 = c.Y; } else { y0 = c.Y; y1 = box.Max.Y; } if (i < 4) { z0 = box.Min.Z; z1 = c.Z; } else { z0 = c.Z; z1 = box.Max.Z; } return new Box3f(new V3f(x0, y0, z0), new V3f(x1, y1, z1)); } #endregion #region Outline corners /// /// Gets outline corner indices of a box as seen from given position (in counter-clockwise order). /// Returns null if position is inside the box. /// public static int[] GetOutlineCornerIndicesCCW(this Box3f box, V3f fromPosition) { if (fromPosition.X < box.Min.X) { //-X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // -X -Y -Z return [1, 5, 4, 6, 2, 3]; } else if (fromPosition.Z > box.Max.Z) { // -X -Y +Z return [0, 1, 5, 7, 6, 2]; } else { // -X -Y Z return [1, 5, 6, 2]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // -X +Y -Z return [0, 4, 6, 7, 3, 1]; } else if (fromPosition.Z > box.Max.Z) { // -X +Y +Z return [0, 4, 5, 7, 3, 2]; } else { // -X +Y Z return [0, 4, 7, 3]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // -X Y -Z return [1, 4, 6, 3]; } else if (fromPosition.Z > box.Max.Z) { // -X Y +Z return [0, 5, 7, 2]; } else { // -X Y Z return [0, 4, 6, 2]; } } } else if (fromPosition.X > box.Max.X) { // +X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // +X -Y -Z return [0, 2, 3, 7, 5, 4]; } else if (fromPosition.Z > box.Max.Z) { // +X -Y +Z return [0, 1, 3, 7, 6, 4]; } else { // +X -Y Z return [0, 3, 7, 4]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // +X +Y -Z return [0, 2, 6, 7, 5, 1]; } else if (fromPosition.Z > box.Max.Z) { // +X +Y +Z return [1, 3, 2, 6, 4, 5]; } else { // +X +Y Z return [1, 2, 6, 5]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // +X Y -Z return [0, 2, 7, 5]; } else if (fromPosition.Z > box.Max.Z) { // +X Y +Z return [1, 3, 6, 4]; } else { // +X Y Z return [1, 3, 7, 5]; } } } else { // X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // X -Y -Z return [2, 3, 5, 4]; } else if (fromPosition.Z > box.Max.Z) { // X -Y +Z return [0, 1, 7, 6]; } else { // X -Y Z return [0, 1, 5, 4]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // X +Y -Z return [0, 6, 7, 1]; } else if (fromPosition.Z > box.Max.Z) { // X +Y +Z return [2, 4, 5, 3]; } else { // X +Y Z return [2, 6, 7, 3]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // X Y -Z return [0, 2, 3, 1]; } else if (fromPosition.Z > box.Max.Z) { // X Y +Z return [4, 5, 7, 6]; } else { // X Y Z return null; } } } } /// /// Gets outline corner indices of a box as seen from given position (in clockwise order). /// Returns null if position is inside the box. /// public static int[] GetOutlineCornerIndicesCW(this Box3f box, V3f fromPosition) { if (fromPosition.X < box.Min.X) { //-X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // -X -Y -Z return [1, 3, 2, 6, 4, 5]; } else if (fromPosition.Z > box.Max.Z) { // -X -Y +Z return [0, 2, 6, 7, 5, 1]; } else { // -X -Y Z return [1, 2, 6, 5]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // -X +Y -Z return [0, 1, 3, 7, 6, 4]; } else if (fromPosition.Z > box.Max.Z) { // -X +Y +Z return [0, 2, 3, 7, 5, 4]; } else { // -X +Y Z return [0, 3, 7, 4]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // -X Y -Z return [1, 3, 6, 4]; } else if (fromPosition.Z > box.Max.Z) { // -X Y +Z return [0, 2, 7, 5]; } else { // -X Y Z return [0, 2, 6, 4]; } } } else if (fromPosition.X > box.Max.X) { // +X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // +X -Y -Z return [0, 4, 5, 7, 3, 2]; } else if (fromPosition.Z > box.Max.Z) { // +X -Y +Z return [0, 4, 6, 7, 3, 1]; } else { // +X -Y Z return [0, 4, 7, 3]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // +X +Y -Z return [0, 1, 5, 7, 6, 2]; } else if (fromPosition.Z > box.Max.Z) { // +X +Y +Z return [1, 5, 4, 6, 2, 3]; } else { // +X +Y Z return [1, 5, 6, 2]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // +X Y -Z return [0, 5, 7, 2]; } else if (fromPosition.Z > box.Max.Z) { // +X Y +Z return [1, 4, 6, 3]; } else { // +X Y Z return [1, 5, 7, 3]; } } } else { // X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // X -Y -Z return [2, 4, 5, 3]; } else if (fromPosition.Z > box.Max.Z) { // X -Y +Z return [0, 6, 7, 1]; } else { // X -Y Z return [0, 4, 5, 1]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // X +Y -Z return [0, 1, 7, 6]; } else if (fromPosition.Z > box.Max.Z) { // X +Y +Z return [2, 3, 5, 4]; } else { // X +Y Z return [2, 3, 7, 6]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // X Y -Z return [0, 1, 3, 2]; } else if (fromPosition.Z > box.Max.Z) { // X Y +Z return [4, 6, 7, 5]; } else { // X Y Z return null; } } } } /// /// Gets outline corners of a box as seen from given position (in counter-clockwise order). /// Returns null if position is inside the box. /// public static V3f[] GetOutlineCornersCCW(this Box3f box, V3f fromPosition) { var cs = box.ComputeCorners(); return GetOutlineCornerIndicesCCW(box, fromPosition)?.Map(i => cs[i]); } /// /// Gets outline corners of a box as seen from given position (in clockwise order). /// Returns null if position is inside the box. /// public static V3f[] GetOutlineCornersCW(this Box3f box, V3f fromPosition) { var cs = box.ComputeCorners(); return GetOutlineCornerIndicesCW(box, fromPosition)?.Map(i => cs[i]); } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Box3f a, Box3f b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Box3f a, Box3f b, float tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Box3fAndFlags [DataContract] public struct Box3fAndFlags { [DataMember] public Box.Flags BFlags; [DataMember] public Box3f BBox; public Box3fAndFlags(Box3f union, Box3f box0, Box3f box1) { BFlags = 0; BBox = union; if (box0.Min.X > union.Min.X) { BBox.Min.X = box0.Min.X; BFlags |= Box.Flags.MinX0; } if (box0.Min.Y > union.Min.Y) { BBox.Min.Y = box0.Min.Y; BFlags |= Box.Flags.MinY0; } if (box0.Min.Z > union.Min.Z) { BBox.Min.Z = box0.Min.Z; BFlags |= Box.Flags.MinZ0; } if (box0.Max.X < union.Max.X) { BBox.Max.X = box0.Max.X; BFlags |= Box.Flags.MaxX0; } if (box0.Max.Y < union.Max.Y) { BBox.Max.Y = box0.Max.Y; BFlags |= Box.Flags.MaxY0; } if (box0.Max.Z < union.Max.Z) { BBox.Max.Z = box0.Max.Z; BFlags |= Box.Flags.MaxZ0; } if (box1.Min.X > union.Min.X) { BBox.Min.X = box1.Min.X; BFlags |= Box.Flags.MinX1; } if (box1.Min.Y > union.Min.Y) { BBox.Min.Y = box1.Min.Y; BFlags |= Box.Flags.MinY1; } if (box1.Min.Z > union.Min.Z) { BBox.Min.Z = box1.Min.Z; BFlags |= Box.Flags.MinZ1; } if (box1.Max.X < union.Max.X) { BBox.Max.X = box1.Max.X; BFlags |= Box.Flags.MaxX1; } if (box1.Max.Y < union.Max.Y) { BBox.Max.Y = box1.Max.Y; BFlags |= Box.Flags.MaxY1; } if (box1.Max.Z < union.Max.Z) { BBox.Max.Z = box1.Max.Z; BFlags |= Box.Flags.MaxZ1; } } } #endregion #region Box3d [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Box3d : IEquatable, IRange, IBoundingBox3d, ISize3d, IBoundingSphere3d, IFormattable { [DataMember] public V3d Min; [DataMember] public V3d Max; #region Constructors /// /// Construct a Box3d from a Box3i. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d(Box3i b) { Min = (V3d) b.Min; Max = (V3d) b.Max; } /// /// Construct a Box3d from a Box3l. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d(Box3l b) { Min = (V3d) b.Min; Max = (V3d) b.Max; } /// /// Construct a Box3d from a Box3f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d(Box3f b) { Min = (V3d) b.Min; Max = (V3d) b.Max; } /// /// Creates a box from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d(V3d min, V3d max) { Min = min; Max = max; } /// /// Creates a box from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { Min.X = minX; Min.Y = minY; Min.Z = minZ; Max.X = maxX; Max.Y = maxY; Max.Z = maxZ; } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d(V3d pnt) { Min = pnt; Max = pnt; } /// /// Creates a box from 3 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d(V3d p0, V3d p1, V3d p2) { Min = Fun.Min(p0, p1, p2); Max = Fun.Max(p0, p1, p2); } /// /// Creates a box from 4 points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d(V3d p0, V3d p1, V3d p2, V3d p3) { Min = Fun.Min(p0, p1, p2, p3); Max = Fun.Max(p0, p1, p2, p3); } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d(Box3d range) { Min = range.Min; Max = range.Max; } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d(Box3d b0, Box3d b1) { Min = Fun.Min(b0.Min, b1.Min); Max = Fun.Max(b0.Max, b1.Max); } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d(Box3d b0, Box3d b1, Box3d b2) { Min = Fun.Min(b0.Min, b1.Min, b2.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max); } /// /// Create a box containing all supplied boxs. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d(Box3d b0, Box3d b1, Box3d b2, Box3d b3) { Min = Fun.Min(b0.Min, b1.Min, b2.Min, b3.Min); Max = Fun.Max(b0.Max, b1.Max, b2.Max, b3.Max); } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d(V3d[] points) : this((ReadOnlySpan)points) { } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d(ReadOnlySpan points) { Min = V3d.MaxValue; Max = V3d.MinValue; if (points == null) return; var count = points.Length; for (var i = 0; i < count; i++) ExtendBy(points[i]); } /// /// Creates box as the bounding box of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d(V3d[] points, long start, long count) { if (count <= 0) { Min = Invalid.Min; Max = Invalid.Max; } else { Min = Max = points[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(points[i]); } } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d(IEnumerable points) { Min = V3d.MaxValue; Max = V3d.MinValue; if (points == null) return; foreach (V3d p in points) ExtendBy(p); } /// /// Creates box as the bounding box of given boxes. /// public Box3d(IEnumerable boxes) { Min = V3d.MaxValue; Max = V3d.MinValue; if (boxes == null) return; foreach (var box in boxes) ExtendBy(box); } /// /// Creates box from a Range1 in each direction. /// public Box3d(Range1d rangeX, Range1d rangeY, Range1d rangeZ) { Min.X = rangeX.Min; Max.X = rangeX.Max; Min.Y = rangeY.Min; Max.Y = rangeY.Max; Min.Z = rangeZ.Min; Max.Z = rangeZ.Max; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box3d(Box3i b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box3d(Box3l b) => new(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Box3d(Box3f b) => new(b); #endregion #region Constants /// /// A range with crossed limits. /// public static Box3d Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V3d.MaxValue, V3d.MinValue); } /// /// The largest possible range. /// public static Box3d Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V3d.MinValue, V3d.MaxValue); } /// /// The unit interval [0, 1]. /// public static Box3d Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(V3d.Zero, V3d.One); } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AnyGreaterOrEqual(Max); } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AllSmallerOrEqual(Max); } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min.AnyGreater(Max) || Min.IsNaN || Max.IsNaN; } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } /// /// Calculates size of the box. /// [XmlIgnore] public V3d Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return (Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = (Min + value); } } public readonly V3d Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return ((Min + Max) / 2); } } [XmlIgnore] public double SizeX { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.X - Min.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.X = Min.X + value; } } public readonly Range1d RangeX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1d(Min.X, Max.X); } } [XmlIgnore] public double SizeY { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Y - Min.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Y = Min.Y + value; } } public readonly Range1d RangeY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1d(Min.Y, Max.Y); } } [XmlIgnore] public double SizeZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Z - Min.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Z = Min.Z + value; } } public readonly Range1d RangeZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1d(Min.Z, Max.Z); } } /// /// Index of the longest dimension of the box. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { int major = 0; var s = Size; if (s.Y > s.X) major = 1; if (s.Z > s[major]) major = 2; return major; } } /// /// Index of the shortest dimension of the box. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { int minor = 0; var s = Size; if (s.Y < s.X) minor = 1; if (s.Z < s[minor]) minor = 2; return minor; } } public readonly double SurfaceArea { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Size; return (s.X * s.Y + s.X * s.Z + s.Y * s.Z) * 2; } } public readonly double Volume { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (IsInvalid) return 0; return SizeX * SizeY * SizeZ; } } public readonly V3d OOO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Min; } } public readonly V3d IOO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3d(Max.X, Min.Y, Min.Z); } } public readonly V3d OIO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3d(Min.X, Max.Y, Min.Z); } } public readonly V3d IIO { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3d(Max.X, Max.Y, Min.Z); } } public readonly V3d OOI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3d(Min.X, Min.Y, Max.Z); } } public readonly V3d IOI { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3d(Max.X, Min.Y, Max.Z); } } public readonly V3d OII { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3d(Min.X, Max.Y, Max.Z); } } public readonly V3d III { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Max; } } #endregion #region Size Manipulations /// /// Return box enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d EnlargedBy(V3d increment) { return new Box3d((Min - increment), (Max + increment)); } /// /// Return box enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d EnlargedBy(V3d deltaMin, V3d deltaMax) { return new Box3d((Min - deltaMin), (Max + deltaMax)); } /// /// Return box shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d ShrunkBy(V3d delta) { return new Box3d((Min + delta), (Max - delta)); } /// /// Return box shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d ShrunkBy(V3d deltaMin, V3d deltaMax) { return new Box3d((Min + deltaMin), (Max - deltaMax)); } /// /// Enlarges box by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(V3d delta) { Min -= delta; Max += delta; } /// /// Enlarges box by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(V3d deltaMin, V3d deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks box by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(V3d delta) { Min += delta; Max -= delta; } /// /// Shrinks box by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(V3d deltaMin, V3d deltaMax) { Min += deltaMin; Max -= deltaMax; } /// /// Returns a box enlarged by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d EnlargedBy(double delta) { return new Box3d( new V3d(Min.X - delta, Min.Y - delta, Min.Z - delta), new V3d(Max.X + delta, Max.Y + delta, Max.Z + delta)); } /// /// Returns a box shrunk by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d ShrunkBy(double delta) { return new Box3d( new V3d(Min.X + delta, Min.Y + delta, Min.Z + delta), new V3d(Max.X - delta, Max.Y - delta, Max.Z - delta)); } /// /// Returns the box enlarged by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d EnlargedBy( double deltaMinX, double deltaMaxX, double deltaMinY, double deltaMaxY, double deltaMinZ, double deltaMaxZ) { return new Box3d( new V3d(Min.X - deltaMinX, Min.Y - deltaMinY, Min.Z - deltaMinZ), new V3d(Max.X + deltaMaxX, Max.Y + deltaMaxY, Max.Z + deltaMaxZ)); } /// /// Returns the box shrunk by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d ShrunkBy( double deltaMinX, double deltaMaxX, double deltaMinY, double deltaMaxY, double deltaMinZ, double deltaMaxZ) { return new Box3d( new V3d(Min.X + deltaMinX, Min.Y + deltaMinY, Min.Z + deltaMinZ), new V3d(Max.X - deltaMaxX, Max.Y - deltaMaxY, Max.Z - deltaMaxZ)); } /// /// Enlarges box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(double delta) { Min.X -= delta; Max.X += delta; Min.Y -= delta; Max.Y += delta; Min.Z -= delta; Max.Z += delta; } /// /// Shrinks box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(double delta) { Min.X += delta; Max.X -= delta; Min.Y += delta; Max.Y -= delta; Min.Z += delta; Max.Z -= delta; } /// /// Enlarges the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy( double deltaMinX, double deltaMaxX, double deltaMinY, double deltaMaxY, double deltaMinZ, double deltaMaxZ) { Min.X -= deltaMinX; Max.X += deltaMaxX; Min.Y -= deltaMinY; Max.Y += deltaMaxY; Min.Z -= deltaMinZ; Max.Z += deltaMaxZ; } /// /// Shrinks the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy( double deltaMinX, double deltaMaxX, double deltaMinY, double deltaMaxY, double deltaMinZ, double deltaMaxZ) { Min.X += deltaMinX; Max.X -= deltaMaxX; Min.Y += deltaMinY; Max.Y -= deltaMaxY; Min.Z += deltaMinZ; Max.Z -= deltaMaxZ; } /// /// Return box scaled by the supplied factor around its center. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d ScaledFromCenterBy(double factor) { var size = Size; var increment = (size * factor - size) / 2; return new Box3d(Min - increment, Max + increment); } /// /// Return box scaled by the supplied factor around its center. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d ScaledFromCenterBy(V3d vectorFactor) { var size = Size; var increment = (size * vectorFactor - size) / 2; return new Box3d(Min - increment, Max + increment); } /// /// Return a box enlarged in all directions by the supplied epsilon which is /// measured with respect to the box diagonal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d EnlargedByRelativeEps(double eps) { return EnlargedBy(eps * Size.Length); } /// /// Enlarge the box in all directions by the supplied epsilon which is /// measured with respect to the box diagonal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeByRelativeEps(double eps) { EnlargeBy(eps * Size.Length); } #endregion #region Box Arithmetics /// /// Return the point in the Box that is closest to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d Clamped(V3d p) { return new V3d( p.X < Min.X ? Min.X : (p.X > Max.X ? Max.X : p.X), p.Y < Min.Y ? Min.Y : (p.Y > Max.Y ? Max.Y : p.Y), p.Z < Min.Z ? Min.Z : (p.Z > Max.Z ? Max.Z : p.Z)); } /// /// Returns the squared distance to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double DistanceSquared(V3d p) { return (p.X < Min.X ? (Min.X - p.X) * (Min.X - p.X) : (p.X > Max.X ? (p.X - Max.X) * (p.X - Max.X) : 0.0)) + (p.Y < Min.Y ? (Min.Y - p.Y) * (Min.Y - p.Y) : (p.Y > Max.Y ? (p.Y - Max.Y) * (p.Y - Max.Y) : 0.0)) + (p.Z < Min.Z ? (Min.Z - p.Z) * (Min.Z - p.Z) : (p.Z > Max.Z ? (p.Z - Max.Z) * (p.Z - Max.Z) : 0.0)); } /// /// Returns the distance to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double Distance(V3d p) { return Fun.Sqrt( (p.X < Min.X ? (Min.X - p.X) * (Min.X - p.X) : (p.X > Max.X ? (p.X - Max.X) * (p.X - Max.X) : 0.0)) + (p.Y < Min.Y ? (Min.Y - p.Y) * (Min.Y - p.Y) : (p.Y > Max.Y ? (p.Y - Max.Y) * (p.Y - Max.Y) : 0.0)) + (p.Z < Min.Z ? (Min.Z - p.Z) * (Min.Z - p.Z) : (p.Z > Max.Z ? (p.Z - Max.Z) * (p.Z - Max.Z) : 0.0))); } /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d Lerp(double x) => Fun.Lerp(x, Min, Max); /// /// Interpolate linearly in each dimension. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d Lerp(V3d p) => Fun.Lerp(p, Min, Max); /// /// Interpolate linearly in each dimension. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d Lerp(double x, double y, double z) => Fun.Lerp(new V3d(x, y, z), Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d InvLerp(V3d p) => Fun.InvLerp(p, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d InvLerp(double x, double y, double z) => Fun.InvLerp(new V3d(x, y, z), Min, Max); /// /// Returns the box with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d SplitRight(V3d splitValue) { var result = new Box3d(Min, Max); if (splitValue.X > result.Min.X) result.Min.X = splitValue.X; if (splitValue.Y > result.Min.Y) result.Min.Y = splitValue.Y; if (splitValue.Z > result.Min.Z) result.Min.Z = splitValue.Z; return result; } /// /// Returns the box with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d SplitLeft(V3d splitValue) { var result = new Box3d(Min, Max); if (splitValue.X < result.Max.X) result.Max.X = splitValue.X; if (splitValue.Y < result.Max.Y) result.Max.Y = splitValue.Y; if (splitValue.Z < result.Max.Z) result.Max.Z = splitValue.Z; return result; } /// /// Returns the box extended to contain the supplied box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d ExtendedBy(Box3d b) { return new Box3d( new V3d( b.Min.X < Min.X ? b.Min.X : Min.X, b.Min.Y < Min.Y ? b.Min.Y : Min.Y, b.Min.Z < Min.Z ? b.Min.Z : Min.Z), new V3d( b.Max.X > Max.X ? b.Max.X : Max.X, b.Max.Y > Max.Y ? b.Max.Y : Max.Y, b.Max.Z > Max.Z ? b.Max.Z : Max.Z)); } /// /// Returns the box extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d ExtendedBy(V3d v) { return new Box3d( new V3d( v.X < Min.X ? v.X : Min.X, v.Y < Min.Y ? v.Y : Min.Y, v.Z < Min.Z ? v.Z : Min.Z), new V3d( v.X > Max.X ? v.X : Max.X, v.Y > Max.Y ? v.Y : Max.Y, v.Z > Max.Z ? v.Z : Max.Z)); } /// /// Extends the box to contain the supplied box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(Box3d box) { if (box.Min.X < Min.X) Min.X = box.Min.X; if (box.Max.X > Max.X) Max.X = box.Max.X; if (box.Min.Y < Min.Y) Min.Y = box.Min.Y; if (box.Max.Y > Max.Y) Max.Y = box.Max.Y; if (box.Min.Z < Min.Z) Min.Z = box.Min.Z; if (box.Max.Z > Max.Z) Max.Z = box.Max.Z; } /// /// Extends the box to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(V3d point) { if (point.X < Min.X) Min.X = point.X; if (point.X > Max.X) Max.X = point.X; if (point.Y < Min.Y) Min.Y = point.Y; if (point.Y > Max.Y) Max.Y = point.Y; if (point.Z < Min.Z) Min.Z = point.Z; if (point.Z > Max.Z) Max.Z = point.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d ExtendXBy(double x) { if (x < Min.X) Min.X = x; if (x > Max.X) Max.X = x; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d ExtendYBy(double y) { if (y < Min.Y) Min.Y = y; if (y > Max.Y) Max.Y = y; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d ExtendZBy(double z) { if (z < Min.Z) Min.Z = z; if (z > Max.Z) Max.Z = z; return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d ExtendDimBy(int dim, double x) { if (x < Min[dim]) Min[dim] = x; if (x > Max[dim]) Max[dim] = x; return this; } /// /// Returns true if the box contains the given point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(V3d p) { return p.X >= Min.X && p.X <= Max.X && p.Y >= Min.Y && p.Y <= Max.Y && p.Z >= Min.Z && p.Z <= Max.Z; } /// /// Returns true if the box completely contains the other box. /// A box contains itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(Box3d b) { return b.Min.X >= Min.X && b.Max.X <= Max.X && b.Min.Y >= Min.Y && b.Max.Y <= Max.Y && b.Min.Z >= Min.Z && b.Max.Z <= Max.Z; } /// /// Checks if the box is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d Repair() { if (Equals(Box3d.Invalid)) return this; if (Min.X > Max.X) Fun.Swap(ref Min.X, ref Max.X); if (Min.Y > Max.Y) Fun.Swap(ref Min.Y, ref Max.Y); if (Min.Z > Max.Z) Fun.Swap(ref Min.Z, ref Max.Z); return this; } /// /// Returns true if two boxes intersect each other (or one contains the other). /// Boxes DO NOT intersect if only touching from the outside. /// A box intersects itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box3d box) { if (Min.X >= box.Max.X) return false; if (Max.X <= box.Min.X) return false; if (Min.Y >= box.Max.Y) return false; if (Max.Y <= box.Min.Y) return false; if (Min.Z >= box.Max.Z) return false; if (Max.Z <= box.Min.Z) return false; return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box3d box, V3d eps) { if (Min.X - eps.X >= box.Max.X) return false; if (Max.X + eps.X <= box.Min.X) return false; if (Min.Y - eps.Y >= box.Max.Y) return false; if (Max.Y + eps.Y <= box.Min.Y) return false; if (Min.Z - eps.Z >= box.Max.Z) return false; if (Max.Z + eps.Z <= box.Min.Z) return false; return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(Box3d box, double eps) { if (Min.X - eps >= box.Max.X) return false; if (Max.X + eps <= box.Min.X) return false; if (Min.Y - eps >= box.Max.Y) return false; if (Max.Y + eps <= box.Min.Y) return false; if (Min.Z - eps >= box.Max.Z) return false; if (Max.Z + eps <= box.Min.Z) return false; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Box3d Invalidate() { Min = V3d.MaxValue; Max = V3d.MinValue; return this; } /// /// Returns where a points coordinates are outside a given box /// /// All outside Flags [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(V3d p0) { Box.Flags bf = Box.Flags.None; if (p0.X < Min.X) bf |= Box.Flags.MinX; else if (p0.X > Max.X) bf |= Box.Flags.MaxX; if (p0.Y < Min.Y) bf |= Box.Flags.MinY; else if (p0.Y > Max.Y) bf |= Box.Flags.MaxY; if (p0.Z < Min.Z) bf |= Box.Flags.MinZ; else if (p0.Z > Max.Z) bf |= Box.Flags.MaxZ; return bf; } /// /// Returns where the planes of the supplied box b are outside /// of the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(Box3d b) { Box.Flags bf = Box.Flags.None; if (b.Min.X < Min.X) bf |= Box.Flags.MinX; if (b.Max.X > Max.X) bf |= Box.Flags.MaxX; if (b.Min.Y < Min.Y) bf |= Box.Flags.MinY; if (b.Max.Y > Max.Y) bf |= Box.Flags.MaxY; if (b.Min.Z < Min.Z) bf |= Box.Flags.MinZ; if (b.Max.Z > Max.Z) bf |= Box.Flags.MaxZ; return bf; } /// /// Gets the minimal and maximal points of the box when seen from the /// supplied direction vector v. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void GetMinMaxInDirection(V3d v, out V3d vMin, out V3d vMax) { vMin = V3d.MinValue; vMax = V3d.MaxValue; if (v.X >= 0) { vMin.X = Min.X; vMax.X = Max.X; } else { vMin.X = Max.X; vMax.X = Min.X; } if (v.Y >= 0) { vMin.Y = Min.Y; vMax.Y = Max.Y; } else { vMin.Y = Max.Y; vMax.Y = Min.Y; } if (v.Z >= 0) { vMin.Z = Min.Z; vMax.Z = Max.Z; } else { vMin.Z = Max.Z; vMax.Z = Min.Z; } } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Box3d a, Box3d b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Box3d a, Box3d b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a box shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d operator +(Box3d box, V3d v) { return new Box3d((box.Min + v), (box.Max + v)); } /// /// Returns a box shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d operator -(Box3d box, V3d v) { return new Box3d((box.Min - v), (box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Box3d other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is Box3d o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref Box3d box, int i, V3d value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static Box3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Box3d(V3d.Parse(x[0].ToString()), V3d.Parse(x[1].ToString())); } public static Box3d Parse(Text t) { return t.NestedBracketSplit(1, V3d.Parse, Box3d.Setter); } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// public readonly string ToString(string format, IFormatProvider fp, string beginB, string betweenB, string endB, string beginV, string betweenV, string endV) { fp ??= CultureInfo.InvariantCulture; return beginB + Min.ToString(format, fp, beginV, betweenV, endV) + betweenB + Max.ToString(format, fp, beginV, betweenV, endV) + endB; } #endregion #region Static Factories /// /// Returns new box [0, size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d FromSize(V3d size) { return new Box3d(V3d.Zero, size); } /// /// Returns new box [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d FromMinAndSize(V3d min, V3d size) { return new Box3d(min, min + size); } /// /// Returns new box [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d FromCenterAndSize(V3d center, V3d size) { return new Box3d(center - size / 2, center + size / 2); } /// /// Returns new box [0, iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d FromSize(ISize3d iSize) { return new Box3d( V3d.Zero, iSize.Size3d); } /// /// Returns new box [min, min + iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d FromMinAndSize(V3d min, ISize3d iSize) { return new Box3d( min, min + iSize.Size3d); } /// /// Returns new box [center - iSize / 2, center + iSize / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d FromCenterAndSize(V3d center, ISize3d iSize) { var size = iSize.Size3d; return new Box3d(center - size / 2, center + size / 2); } /// /// Creates box from 2 points which need not be Min and Max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d FromPoints(V3d p0, V3d p1) { return new Box3d(Fun.Min(p0, p1), Fun.Max(p0, p1)); } #endregion #region Transforms [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d Translated(V3d shift) { return IsInvalid ? Box3d.Invalid : new Box3d(Min + shift, Max + shift); } /// /// Returns a scaled box. WARNING: scaling is performed around the origin! /// A negative scale factor will resut in an invalid box! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d Scaled(V3d factor) { return IsInvalid ? Box3d.Invalid : new Box3d(Min * factor, Max * factor); } /// /// Transforms the box by the given transformation matrix. /// NOTE: Performs IsValid check at 10% CPU time overhead. /// -> Empty bounds (crossed min and max) will remain empty. /// public readonly Box3d Transformed(M44d trafo) { if (Min.X > Max.X || Min.Y > Max.Y || Min.Z > Max.Z) return Box3d.Invalid; var t = new V3d(trafo.M03, trafo.M13, trafo.M23); var res = new Box3d(t, t); double av, bv; av = trafo.M00 * Min.X; bv = trafo.M00 * Max.X; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M01 * Min.Y; bv = trafo.M01 * Max.Y; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M02 * Min.Z; bv = trafo.M02 * Max.Z; if (av < bv) { res.Min.X += av; res.Max.X += bv; } else { res.Min.X += bv; res.Max.X += av; } av = trafo.M10 * Min.X; bv = trafo.M10 * Max.X; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } av = trafo.M11 * Min.Y; bv = trafo.M11 * Max.Y; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } av = trafo.M12 * Min.Z; bv = trafo.M12 * Max.Z; if (av < bv) { res.Min.Y += av; res.Max.Y += bv; } else { res.Min.Y += bv; res.Max.Y += av; } av = trafo.M20 * Min.X; bv = trafo.M20 * Max.X; if (av < bv) { res.Min.Z += av; res.Max.Z += bv; } else { res.Min.Z += bv; res.Max.Z += av; } av = trafo.M21 * Min.Y; bv = trafo.M21 * Max.Y; if (av < bv) { res.Min.Z += av; res.Max.Z += bv; } else { res.Min.Z += bv; res.Max.Z += av; } av = trafo.M22 * Min.Z; bv = trafo.M22 * Max.Z; if (av < bv) { res.Min.Z += av; res.Max.Z += bv; } else { res.Min.Z += bv; res.Max.Z += av; } return res; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box3d Transformed(Trafo3d trafo) { return Transformed(trafo.Forward); } #endregion #region Corners /// /// Return the corner of the box with the given index. The corner /// index is constructed in such a way, that bit 0 enumerates the /// x coordinate (0 ... min, 1 ... max), bit 1 enumerates the y /// coordinate, and bit 2 enumerates the z coordinate. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d Corner(int index) { return new V3d( (index & 1) == 0 ? Min.X : Max.X, (index & 2) == 0 ? Min.Y : Max.Y, (index & 4) == 0 ? Min.Z : Max.Z); } /// /// Computes the corners of the box and returns them in an array. /// The order of the corners is determined by their index which is /// constructed as in the method . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d[] ComputeCorners() { return [ Min, new(Max.X, Min.Y, Min.Z), new(Min.X, Max.Y, Min.Z), new(Max.X, Max.Y, Min.Z), new(Min.X, Min.Y, Max.Z), new(Max.X, Min.Y, Max.Z), new(Min.X, Max.Y, Max.Z), Max ]; } /// /// Enumeration of the corners of the box. /// public readonly IEnumerable Corners { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return Min; yield return new V3d(Max.X, Min.Y, Min.Z); yield return new V3d(Min.X, Max.Y, Min.Z); yield return new V3d(Max.X, Max.Y, Min.Z); yield return new V3d(Min.X, Min.Y, Max.Z); yield return new V3d(Max.X, Min.Y, Max.Z); yield return new V3d(Min.X, Max.Y, Max.Z); yield return Max; } } #endregion #region Swizzle methods // TODO: Implement for other dimensions public readonly Range1d X { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1d(Min.X, Max.X); } } public readonly Range1d Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1d(Min.Y, Max.Y); } } public readonly Range1d Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1d(Min.Z, Max.Z); } } public readonly Box2d XY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2d(Min.XY, Max.XY); } } public readonly Box2d XZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2d(Min.XZ, Max.XZ); } } public readonly Box2d YX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2d(Min.YX, Max.YX); } } public readonly Box2d YZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2d(Min.YZ, Max.YZ); } } public readonly Box2d ZX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2d(Min.ZX, Max.ZX); } } public readonly Box2d ZY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Box2d(Min.ZY, Max.ZY); } } #endregion #region Enumerators #endregion #region IBoundingBox3d Members public readonly Box3d BoundingBox3d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this; } } #endregion #region IBoundingSphere3d Members public readonly Sphere3d BoundingSphere3d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => IsInvalid ? Sphere3d.Invalid : new Sphere3d(Center, 0.5 * Size.Length); } #endregion #region ISize3d Members public readonly V3d Size3d { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Size; } } #endregion } public static partial class Box { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d Union(this Box3d a, Box3d b) { return new Box3d(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d Intersection(this Box3d a, Box3d b) { return new Box3d(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } #endregion #region Bounding box for arrays /// /// Returns the bounding box of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d GetBoundingBox(this V3d[] pointArray) { return pointArray.GetBoundingBox(0, pointArray.LongLength); } /// /// Returns the bounding box of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d GetBoundingBox(this V3d[] pointArray, long count) { return pointArray.GetBoundingBox(0, count); } /// /// Returns the bounding box of count elements of the array starting at start. /// public static Box3d GetBoundingBox( this V3d[] pointArray, long start, long count) { if (count <= 0) return Box3d.Invalid; var box = new Box3d(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding box of count elements of the array starting at start. /// public static Box3d GetBoundingBox(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return Box3d.Invalid; var box = new Box3d(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding box for lists /// /// Returns the bounding box of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d GetBoundingBox(this List pointList) { return pointList.GetBoundingBox(pointList.Count); } /// /// Returns the bounding box of the first count elements of the list. /// public static Box3d GetBoundingBox(this List pointList, int count) { if (count <= 0) return Box3d.Invalid; var box = new Box3d(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding box for indexed arrays /// /// Returns the bounding box of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d GetBoundingBox(this int[] indexArray, V3d[] pointArray) { return indexArray.GetBoundingBox(0, indexArray.Length, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d GetBoundingBox(this int[] indexArray, int count, V3d[] pointArray) { return indexArray.GetBoundingBox(0, count, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box3d GetBoundingBox(this int[] indexArray, int start, int count, V3d[] pointArray) { if (count <= 0) return Box3d.Invalid; var box = new Box3d(pointArray[indexArray[start]]); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box3d GetBoundingBox(this int[] indexArray, int start, int count, T[] array, Func pointSelector) { if (count <= 0) return Box3d.Invalid; var box = new Box3d(pointSelector(array[indexArray[start]])); for (int i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d GetBoundingBox(this long[] indexArray, V3d[] pointArray) { return indexArray.GetBoundingBox(0, indexArray.LongLength, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Box3d GetBoundingBox(this long[] indexArray, long count, V3d[] pointArray) { return indexArray.GetBoundingBox(0, count, pointArray); } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box3d GetBoundingBox(this long[] indexArray, long start, long count, V3d[] pointArray) { if (count <= 0) return Box3d.Invalid; var box = new Box3d(pointArray[indexArray[start]]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding box of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static Box3d GetBoundingBox(this long[] indexArray, long start, long count, T[] array, Func pointSelector) { if (count <= 0) return Box3d.Invalid; var box = new Box3d(pointSelector(array[indexArray[start]])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } #endregion #region Bounding box for IEnumerable /// /// Returns the bounding box of the elements of the collection. /// public static Box3d GetBoundingBox(this IEnumerable points) { var box = Box3d.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion #region Get octant /// /// Octant 0-7. /// 0th, 1st and 2nd bit encodes x-, y-, z-axis, respectively. /// E.g. 0 is octant [box.Min, box.Center], 7 is octant [box.Center, box.Max]. /// public static Box3d GetOctant(this Box3d box, int i) { if (i < 0 || i > 7) throw new IndexOutOfRangeException(); double x0, x1, y0, y1, z0, z1; var c = box.Center; if ((i & 1) == 0) { x0 = box.Min.X; x1 = c.X; } else { x0 = c.X; x1 = box.Max.X; } if ((i & 2) == 0) { y0 = box.Min.Y; y1 = c.Y; } else { y0 = c.Y; y1 = box.Max.Y; } if (i < 4) { z0 = box.Min.Z; z1 = c.Z; } else { z0 = c.Z; z1 = box.Max.Z; } return new Box3d(new V3d(x0, y0, z0), new V3d(x1, y1, z1)); } #endregion #region Outline corners /// /// Gets outline corner indices of a box as seen from given position (in counter-clockwise order). /// Returns null if position is inside the box. /// public static int[] GetOutlineCornerIndicesCCW(this Box3d box, V3d fromPosition) { if (fromPosition.X < box.Min.X) { //-X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // -X -Y -Z return [1, 5, 4, 6, 2, 3]; } else if (fromPosition.Z > box.Max.Z) { // -X -Y +Z return [0, 1, 5, 7, 6, 2]; } else { // -X -Y Z return [1, 5, 6, 2]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // -X +Y -Z return [0, 4, 6, 7, 3, 1]; } else if (fromPosition.Z > box.Max.Z) { // -X +Y +Z return [0, 4, 5, 7, 3, 2]; } else { // -X +Y Z return [0, 4, 7, 3]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // -X Y -Z return [1, 4, 6, 3]; } else if (fromPosition.Z > box.Max.Z) { // -X Y +Z return [0, 5, 7, 2]; } else { // -X Y Z return [0, 4, 6, 2]; } } } else if (fromPosition.X > box.Max.X) { // +X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // +X -Y -Z return [0, 2, 3, 7, 5, 4]; } else if (fromPosition.Z > box.Max.Z) { // +X -Y +Z return [0, 1, 3, 7, 6, 4]; } else { // +X -Y Z return [0, 3, 7, 4]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // +X +Y -Z return [0, 2, 6, 7, 5, 1]; } else if (fromPosition.Z > box.Max.Z) { // +X +Y +Z return [1, 3, 2, 6, 4, 5]; } else { // +X +Y Z return [1, 2, 6, 5]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // +X Y -Z return [0, 2, 7, 5]; } else if (fromPosition.Z > box.Max.Z) { // +X Y +Z return [1, 3, 6, 4]; } else { // +X Y Z return [1, 3, 7, 5]; } } } else { // X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // X -Y -Z return [2, 3, 5, 4]; } else if (fromPosition.Z > box.Max.Z) { // X -Y +Z return [0, 1, 7, 6]; } else { // X -Y Z return [0, 1, 5, 4]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // X +Y -Z return [0, 6, 7, 1]; } else if (fromPosition.Z > box.Max.Z) { // X +Y +Z return [2, 4, 5, 3]; } else { // X +Y Z return [2, 6, 7, 3]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // X Y -Z return [0, 2, 3, 1]; } else if (fromPosition.Z > box.Max.Z) { // X Y +Z return [4, 5, 7, 6]; } else { // X Y Z return null; } } } } /// /// Gets outline corner indices of a box as seen from given position (in clockwise order). /// Returns null if position is inside the box. /// public static int[] GetOutlineCornerIndicesCW(this Box3d box, V3d fromPosition) { if (fromPosition.X < box.Min.X) { //-X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // -X -Y -Z return [1, 3, 2, 6, 4, 5]; } else if (fromPosition.Z > box.Max.Z) { // -X -Y +Z return [0, 2, 6, 7, 5, 1]; } else { // -X -Y Z return [1, 2, 6, 5]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // -X +Y -Z return [0, 1, 3, 7, 6, 4]; } else if (fromPosition.Z > box.Max.Z) { // -X +Y +Z return [0, 2, 3, 7, 5, 4]; } else { // -X +Y Z return [0, 3, 7, 4]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // -X Y -Z return [1, 3, 6, 4]; } else if (fromPosition.Z > box.Max.Z) { // -X Y +Z return [0, 2, 7, 5]; } else { // -X Y Z return [0, 2, 6, 4]; } } } else if (fromPosition.X > box.Max.X) { // +X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // +X -Y -Z return [0, 4, 5, 7, 3, 2]; } else if (fromPosition.Z > box.Max.Z) { // +X -Y +Z return [0, 4, 6, 7, 3, 1]; } else { // +X -Y Z return [0, 4, 7, 3]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // +X +Y -Z return [0, 1, 5, 7, 6, 2]; } else if (fromPosition.Z > box.Max.Z) { // +X +Y +Z return [1, 5, 4, 6, 2, 3]; } else { // +X +Y Z return [1, 5, 6, 2]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // +X Y -Z return [0, 5, 7, 2]; } else if (fromPosition.Z > box.Max.Z) { // +X Y +Z return [1, 4, 6, 3]; } else { // +X Y Z return [1, 5, 7, 3]; } } } else { // X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // X -Y -Z return [2, 4, 5, 3]; } else if (fromPosition.Z > box.Max.Z) { // X -Y +Z return [0, 6, 7, 1]; } else { // X -Y Z return [0, 4, 5, 1]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // X +Y -Z return [0, 1, 7, 6]; } else if (fromPosition.Z > box.Max.Z) { // X +Y +Z return [2, 3, 5, 4]; } else { // X +Y Z return [2, 3, 7, 6]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // X Y -Z return [0, 1, 3, 2]; } else if (fromPosition.Z > box.Max.Z) { // X Y +Z return [4, 6, 7, 5]; } else { // X Y Z return null; } } } } /// /// Gets outline corners of a box as seen from given position (in counter-clockwise order). /// Returns null if position is inside the box. /// public static V3d[] GetOutlineCornersCCW(this Box3d box, V3d fromPosition) { var cs = box.ComputeCorners(); return GetOutlineCornerIndicesCCW(box, fromPosition)?.Map(i => cs[i]); } /// /// Gets outline corners of a box as seen from given position (in clockwise order). /// Returns null if position is inside the box. /// public static V3d[] GetOutlineCornersCW(this Box3d box, V3d fromPosition) { var cs = box.ComputeCorners(); return GetOutlineCornerIndicesCW(box, fromPosition)?.Map(i => cs[i]); } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Box3d a, Box3d b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Box3d a, Box3d b, double tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion #region Box3dAndFlags [DataContract] public struct Box3dAndFlags { [DataMember] public Box.Flags BFlags; [DataMember] public Box3d BBox; public Box3dAndFlags(Box3d union, Box3d box0, Box3d box1) { BFlags = 0; BBox = union; if (box0.Min.X > union.Min.X) { BBox.Min.X = box0.Min.X; BFlags |= Box.Flags.MinX0; } if (box0.Min.Y > union.Min.Y) { BBox.Min.Y = box0.Min.Y; BFlags |= Box.Flags.MinY0; } if (box0.Min.Z > union.Min.Z) { BBox.Min.Z = box0.Min.Z; BFlags |= Box.Flags.MinZ0; } if (box0.Max.X < union.Max.X) { BBox.Max.X = box0.Max.X; BFlags |= Box.Flags.MaxX0; } if (box0.Max.Y < union.Max.Y) { BBox.Max.Y = box0.Max.Y; BFlags |= Box.Flags.MaxY0; } if (box0.Max.Z < union.Max.Z) { BBox.Max.Z = box0.Max.Z; BFlags |= Box.Flags.MaxZ0; } if (box1.Min.X > union.Min.X) { BBox.Min.X = box1.Min.X; BFlags |= Box.Flags.MinX1; } if (box1.Min.Y > union.Min.Y) { BBox.Min.Y = box1.Min.Y; BFlags |= Box.Flags.MinY1; } if (box1.Min.Z > union.Min.Z) { BBox.Min.Z = box1.Min.Z; BFlags |= Box.Flags.MinZ1; } if (box1.Max.X < union.Max.X) { BBox.Max.X = box1.Max.X; BFlags |= Box.Flags.MaxX1; } if (box1.Max.Y < union.Max.Y) { BBox.Max.Y = box1.Max.Y; BFlags |= Box.Flags.MaxY1; } if (box1.Max.Z < union.Max.Z) { BBox.Max.Z = box1.Max.Z; BFlags |= Box.Flags.MaxZ1; } } } #endregion } ================================================ FILE: src/Aardvark.Base/Math/RangesBoxes/Box_template.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { // AUTOGENERATED CODE - DO NOT CHANGE! #region Flags public static partial class Box { [Flags] public enum Flags { None = 0x00000000, /* --------------------------------------------------------------- flags that mark the faces of a box --------------------------------------------------------------- */ MinX0 = 0x00000001, MinY0 = 0x00000002, MinZ0 = 0x00000004, MaxX0 = 0x00000008, MaxY0 = 0x00000010, MaxZ0 = 0x00000020, Min0 = MinX0 | MinY0 | MinZ0, Max0 = MaxX0 | MaxY0 | MaxZ0, X0 = MinX0 | MaxX0, Y0 = MinY0 | MaxY0, Z0 = MinZ0 | MaxZ0, All0 = Min0 | Max0, /* --------------------------------------------------------------- flags that mark the faces of a second, independent box --------------------------------------------------------------- */ MinX1 = MinX0 << 6, MinY1 = MinY0 << 6, MinZ1 = MinZ0 << 6, MaxX1 = MaxX0 << 6, MaxY1 = MaxY0 << 6, MaxZ1 = MaxZ0 << 6, Min1 = Min0 << 6, Max1 = Max0 << 6, X1 = X0 << 6, Y1 = Y0 << 6, Z1 = Z0 << 6, All1 = All0 << 6, /* --------------------------------------------------------------- flags that operate on both face bits together --------------------------------------------------------------- */ MinX = MinX0 | MinX1, MinY = MinY0 | MinY1, MinZ = MinZ0 | MinZ1, MaxX = MaxX0 | MaxX1, MaxY = MaxY0 | MaxY1, MaxZ = MaxZ0 | MaxZ1, Min = Min0 | Min1, Max = Max0 | Max1, MinXMinY = MinX | MinY, MinXMaxY = MinX | MaxY, MaxXMinY = MaxX | MinY, MaxXMaxY = MaxX | MaxY, X = X0 | X1, Y = Y0 | Y1, Z = Z0 | Z1, All = All0 | All1, /* --------------------------------------------------------------- flags that mark the edges of the box --------------------------------------------------------------- */ Edge01 = 0x00001000, Edge23 = 0x00002000, Edge45 = 0x00004000, Edge67 = 0x00008000, Edge02 = 0x00010000, Edge13 = 0x00020000, Edge46 = 0x00040000, Edge57 = 0x00080000, Edge04 = 0x00100000, Edge15 = 0x00200000, Edge26 = 0x00400000, Edge37 = 0x00800000, /* --------------------------------------------------------------- flags that mark the corners of the box --------------------------------------------------------------- */ Corner0 = 0x01000000, Corner1 = 0x02000000, Corner2 = 0x04000000, Corner3 = 0x08000000, Corner4 = 0x10000000, Corner5 = 0x20000000, Corner6 = 0x40000000, Corner7 = (int)-0x80000000, } } #endregion //# Action comma = () => Out(", "); //# Action add = () => Out(" + "); //# Action andand = () => Out(" && "); //# Action oror = () => Out(" || "); //# var fdtypes = new[] { Meta.FloatType, Meta.DoubleType }; //# foreach (var t in Meta.RangeAndBoxTypes) { //# var lt = t.LimitType; var vt = lt as Meta.VecType; //# int dim = vt != null ? vt.Len : 1; //# var dlt = dim > 1 ? Meta.VecTypeOf(dim, Meta.DoubleType) : Meta.DoubleType; //# var ft = dim > 1 ? vt.FieldType : lt; //# var vtrep = dim == 1 ? Meta.TryGetVecTypeOf(2, ft) : null; //# var vtype = vtrep?.Name; //# var ch = ft.Char; //# int dplus1 = dim + 1; //# var fields = dim > 1 ? vt.Fields : null; //# var args = dim > 1 ? fields.ToLower() : null; //# var ltype = lt.Name; //# var dltype = dlt.Name; //# var lcast = dim > 1 ? "" : ft == Meta.IntType || ft == Meta.DoubleType ? "" : "(" + ltype + ")"; //# var ftype = ft.Name; //# var fcast = dim > 1 ? "" : ft == Meta.IntType || ft == Meta.DoubleType ? "" : "(" + ftype + ")"; //# var bname = dim > 1 ? "box" : "range"; //# var bnamecaps = dim > 1 ? "Box" : "Range"; //# var type = t.Name; //# var ct = (ft == Meta.FloatType || ft == Meta.DoubleType) ? ft : Meta.ComputationTypeOf(ft); //# var ctype = ct.Name; //# var cch = ct.Char; //# var iboundingbox = "IBoundingBox" + dim + ch; //# var iboundingcircle = "IBoundingCircle" + dim + cch; //# var iboundingsphere = "IBoundingSphere" + dim + cch; //# var isize = "ISize" + dim + ch; //# var minvalue = dim > 1 ? ltype + ".MinValue" //# : lt.IsReal ? "Constant<" + ltype + ">.ParseableMinValue" : ltype + ".MinValue"; //# var maxvalue = dim > 1 ? ltype + ".MaxValue" //# : lt.IsReal ? "Constant<" + ltype + ">.ParseableMaxValue" : ltype + ".MaxValue"; //# var half = (ct == Meta.DoubleType) ? "0.5" : "0.5f"; #region __type__ [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__>, IRange<__ltype__, __type__>, /*# if (dim > 1) { */__iboundingbox__, __isize__, /*# } if (dim == 2) { */__iboundingcircle__, /*# } if (dim == 3) { */__iboundingsphere__, /*# }*/IFormattable { [DataMember] public __ltype__ Min; [DataMember] public __ltype__ Max; #region Constructors //# foreach (var t1 in Meta.RangeAndBoxTypes) { //# var type1 = t1.Name; //# var lt1 = t1.LimitType; var vt1 = lt1 as Meta.VecType; //# int dim1 = vt1 != null ? vt1.Len : 1; //# if (t != t1 && dim == dim1) { /// /// Construct a __type__ from a __type1__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type1__ b) { Min = (__ltype__) b.Min; Max = (__ltype__) b.Max; } //# } //# } //# if (vtype != null) { /// /// Construct a __type__ from a __vtype__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__vtype__ v) { Min = v.X; Max = v.Y; } //# } /// /// Creates a __bname__ from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ltype__ min, __ltype__ max) { Min = min; Max = max; } //#if(dim > 1) { //#var xyz = vt.Fields; /// /// Creates a __bname__ from minimum and maximum limits. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(/*# xyz.ForEach(X => { */__ftype__ min__X__, /*# }); xyz.ForEach(X => { */__ftype__ max__X__/*# }, comma); */) { //# xyz.ForEach(X => { Min.__X__ = min__X__; //# }); //# xyz.ForEach(X => { Max.__X__ = max__X__; //# }); } //# } /// /// Creates infinitesimal box from single point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ltype__ pnt) { Min = pnt; Max = pnt; } //# for (int k = 3; k < 5; k++) { /// /// Creates a __bname__ from __k__ points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(/*# k.ForEach(i => {*/__ltype__ p__i__/*#}, comma);*/) { Min = Fun.Min(/*# k.ForEach(i => {*/p__i__/*#}, comma);*/); Max = Fun.Max(/*# k.ForEach(i => {*/p__i__/*#}, comma);*/); } //# } /// /// Creates copy of existing range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ range) { Min = range.Min; Max = range.Max; } //# for (int k = 2; k < 5; k++) { /// /// Create a box containing all supplied __bname__s. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(/*# k.ForEach(i => {*/__type__ b__i__/*#}, comma);*/) { Min = Fun.Min(/*# k.ForEach(i => {*/b__i__.Min/*#}, comma);*/); Max = Fun.Max(/*# k.ForEach(i => {*/b__i__.Max/*#}, comma);*/); } //# } //# if (dim > 1) { /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ltype__[] points) : this((ReadOnlySpan<__ltype__>)points) { } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(ReadOnlySpan<__ltype__> points) { Min = __maxvalue__; Max = __minvalue__; if (points == null) return; var count = points.Length; for (var i = 0; i < count; i++) ExtendBy(points[i]); } /// /// Creates box as the bounding box of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ltype__[] points, long start, long count) { if (count <= 0) { Min = Invalid.Min; Max = Invalid.Max; } else { Min = Max = points[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(points[i]); } } /// /// Creates box as the bounding box of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(IEnumerable<__ltype__> points) { Min = __maxvalue__; Max = __minvalue__; if (points == null) return; foreach (__ltype__ p in points) ExtendBy(p); } /// /// Creates box as the bounding box of given boxes. /// public __type__(IEnumerable<__type__> boxes) { Min = __maxvalue__; Max = __minvalue__; if (boxes == null) return; foreach (var box in boxes) ExtendBy(box); } /// /// Creates __bname__ from a Range1 in each direction. /// public __type__(/*# fields.ForEach(f => {*/Range1__ch__ range__f__/*# }, comma);*/) { //# fields.ForEach(f => { Min.__f__ = range__f__.Min; Max.__f__ = range__f__.Max; //# }); } //# } // dim > 1 //# if (dim == 1) { /// /// Creates __bname__ as the bounding range of given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__[] values) { Min = __maxvalue__; Max = __minvalue__; if (values == null) return; long count = values.LongLength; for (long i = 0; i < count; i++) ExtendBy(values[i]); } /// /// Creates __bname__ as the bounding range of count of the given points /// starting at start. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__[] values, long start, long count) { if (count <= 0) { Min = __maxvalue__; Max = __minvalue__; } else { Min = Max = values[start]; for (long i = start + 1, e = start + count; i < e; i++) ExtendBy(values[i]); } } /// /// Creates __bname__ as the bounding range of given values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(IEnumerable<__ftype__> values) { Min = __maxvalue__; Max = __minvalue__; if (values == null) return; foreach (__ftype__ v in values) ExtendBy(v); } /// /// Returns new range [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromMinAndSize(__ftype__ min, __ftype__ size) { return new __type__(min, __fcast__(min + size)); } /// /// Returns new range [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromCenterAndSize(__ftype__ center, __ftype__ size) { return new __type__(__fcast__(center - size / 2), __fcast__(center + size / 2)); } //# } #endregion #region Conversions //# foreach (var t1 in Meta.RangeAndBoxTypes) { //# var type1 = t1.Name; //# var lt1 = t1.LimitType; var vt1 = lt1 as Meta.VecType; //# int dim1 = vt1 != null ? vt1.Len : 1; //# if (t != t1 && dim == dim1) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type__(__type1__ b) => new(b); //# } //# } //# if (vtype != null) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type__(__vtype__ v) => new(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __vtype__(__type__ r) => new(r.Min, r.Max); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __vtype__ To__vtype__() => (__vtype__)this; //# } #endregion #region Constants /// /// A range with crossed limits. /// public static __type__ Invalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(__maxvalue__, __minvalue__); } /// /// The largest possible range. /// public static __type__ Infinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(__minvalue__, __maxvalue__); } /// /// The unit interval [0, 1]. /// //# if (dim == 1) { public static __type__ Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(0, 1); } //# } else { public static __type__ Unit { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(__ltype__.Zero, __ltype__.One); } //# } #endregion #region Properties /// /// True if the box is invalid or has a zero volume. /// public readonly bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return /*# if (dim == 1) { */Min >= Max;/*# } else { */Min.AnyGreaterOrEqual(Max);/*# } */ } } /// /// True if the box has a non-zero volume. /// public readonly bool IsNonEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsEmpty; } } /// /// True if the box is valid. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return /*# if (dim == 1) { */Min <= Max;/*# } else { */Min.AllSmallerOrEqual(Max);/*# } */ } } /// /// True if the box is invalid. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return /*# if (dim == 1) { */Min > Max;/*# } else { */Min.AnyGreater(Max)/*# if (ft.IsReal) {*/ || Min.IsNaN || Max.IsNaN/*# }*/;/*# } */ } } /// /// True if the box is infinite. /// public readonly bool IsInfinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this == Infinite; } } //# if (dim == 2) { /// /// Same as Min.X. /// [XmlIgnore] public __ftype__ Left { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Min.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Min.X = value; } } /// /// Same as Max.X. /// [XmlIgnore] public __ftype__ Right { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.X = value; } } /// /// Same as Min.Y. /// [XmlIgnore] public __ftype__ Top { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Min.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Min.Y = value; } } /// /// Same as Max.Y. /// [XmlIgnore] public __ftype__ Bottom { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.Y = value; } } //# } // dim = 2 /// /// Calculates size of the __bname__. /// [XmlIgnore] public __ltype__ Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return __lcast__(Max - Min); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max = __lcast__(Min + value); } } public readonly __ltype__ Center { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return __lcast__((Min + Max) / 2); } } //# if (dim == 1) { public readonly IEnumerable<__ltype__> Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (IsInvalid) yield break; //Todo: check should not be necessary for (var i = Min; i <= Max; i++) yield return i; } } //# } // dim == 1 //# if (dim > 1) { //# fields.ForEach(f => { [XmlIgnore] public __ftype__ Size__f__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Max.__f__ - Min.__f__; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Max.__f__ = Min.__f__ + value; } } public readonly Range1__ch__ Range__f__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Range1__ch__(Min.__f__, Max.__f__); } } //# }); //# if (dim == 2) { /// /// Index of the longest dimension of the box. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return SizeY > SizeX ? 1 : 0; } } /// /// Index of the shortest dimension of the box. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return SizeY < SizeX ? 1 : 0; } } public readonly __ftype__ Area { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return SizeX * SizeY; } } //# } // dim == 2 //# if (dim == 3) { /// /// Index of the longest dimension of the box. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { int major = 0; var s = Size; if (s.Y > s.X) major = 1; if (s.Z > s[major]) major = 2; return major; } } /// /// Index of the shortest dimension of the box. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { int minor = 0; var s = Size; if (s.Y < s.X) minor = 1; if (s.Z < s[minor]) minor = 2; return minor; } } public readonly __ftype__ SurfaceArea { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Size; return (s.X * s.Y + s.X * s.Z + s.Y * s.Z) * 2; } } public readonly __ftype__ Volume { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (IsInvalid) return 0; return SizeX * SizeY * SizeZ; } } //# } // dim == 3 //# for (int di = 0; di < (1 << dim); di++) { //# var pnt = dim.Range().Select(i => (di & (1 << i)) == 0 ? "O" : "I").Join(); //# var arg = dim.Range().Select(i => ((di & (1 << i)) == 0 ? "Min" : "Max") + "." + fields[i]).Join(", "); public readonly __ltype__ __pnt__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return /*# if (di == 0) {*/Min;/*#} else if (di == (1 << dim) - 1) {*/Max;/*#} else {*/new __ltype__(__arg__);/*#}*/ } } //# } //# } // dim > 1 #endregion #region Size Manipulations /// /// Return __bname__ enlarged by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ EnlargedBy(__ltype__ increment) { return new __type__(__lcast__(Min - increment), __lcast__(Max + increment)); } /// /// Return __bname__ enlarged by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ EnlargedBy(__ltype__ deltaMin, __ltype__ deltaMax) { return new __type__(__lcast__(Min - deltaMin), __lcast__(Max + deltaMax)); } /// /// Return __bname__ shrunk by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ ShrunkBy(__ltype__ delta) { return new __type__(__lcast__(Min + delta), __lcast__(Max - delta)); } /// /// Return __bname__ shrunk by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ ShrunkBy(__ltype__ deltaMin, __ltype__ deltaMax) { return new __type__(__lcast__(Min + deltaMin), __lcast__(Max - deltaMax)); } /// /// Enlarges __bname__ by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(__ltype__ delta) { Min -= delta; Max += delta; } /// /// Enlarges __bname__ by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(__ltype__ deltaMin, __ltype__ deltaMax) { Min -= deltaMin; Max += deltaMax; } /// /// Shrinks __bname__ by the supplied value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(__ltype__ delta) { Min += delta; Max -= delta; } /// /// Shrinks __bname__ by the supplied values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(__ltype__ deltaMin, __ltype__ deltaMax) { Min += deltaMin; Max -= deltaMax; } //# if (dim > 1) { /// /// Returns a box enlarged by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ EnlargedBy(__ftype__ delta) { return new __type__( new __ltype__(/*# fields.ForEach(f => { */Min.__f__ - delta/*# }, comma);*/), new __ltype__(/*# fields.ForEach(f => { */Max.__f__ + delta/*# }, comma);*/)); } /// /// Returns a box shrunk by the specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ ShrunkBy(__ftype__ delta) { return new __type__( new __ltype__(/*# fields.ForEach(f => { */Min.__f__ + delta/*# }, comma);*/), new __ltype__(/*# fields.ForEach(f => { */Max.__f__ - delta/*# }, comma);*/)); } /// /// Returns the box enlarged by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ EnlargedBy(/*# fields.ForEach(f => { */ __ftype__ deltaMin__f__, __ftype__ deltaMax__f__/*# }, comma);*/) { return new __type__( new __ltype__(/*# fields.ForEach(f => { */Min.__f__ - deltaMin__f__/*# }, comma);*/), new __ltype__(/*# fields.ForEach(f => { */Max.__f__ + deltaMax__f__/*# }, comma);*/)); } /// /// Returns the box shrunk by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ ShrunkBy(/*# fields.ForEach(f => { */ __ftype__ deltaMin__f__, __ftype__ deltaMax__f__/*# }, comma);*/) { return new __type__( new __ltype__(/*# fields.ForEach(f => { */Min.__f__ + deltaMin__f__/*# }, comma);*/), new __ltype__(/*# fields.ForEach(f => { */Max.__f__ - deltaMax__f__/*# }, comma);*/)); } /// /// Enlarges box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(__ftype__ delta) { //# fields.ForEach(f => { Min.__f__ -= delta; Max.__f__ += delta; //# }); } /// /// Shrinks box by specified value in all directions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(__ftype__ delta) { //# fields.ForEach(f => { Min.__f__ += delta; Max.__f__ -= delta; //# }); } /// /// Enlarges the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeBy(/*# fields.ForEach(f => { */ __ftype__ deltaMin__f__, __ftype__ deltaMax__f__/*# }, comma);*/) { //# fields.ForEach(f => { Min.__f__ -= deltaMin__f__; Max.__f__ += deltaMax__f__; //# }); } /// /// Shrinks the box by the specified values (paddings). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ShrinkBy(/*# fields.ForEach(f => { */ __ftype__ deltaMin__f__, __ftype__ deltaMax__f__/*# }, comma);*/) { //# fields.ForEach(f => { Min.__f__ += deltaMin__f__; Max.__f__ -= deltaMax__f__; //# }); } //# if (ft.IsReal) { /// /// Return __bname__ scaled by the supplied factor around its center. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ ScaledFromCenterBy(__ftype__ factor) { var size = Size; var increment = (size * factor - size) / 2; return new __type__(Min - increment, Max + increment); } /// /// Return __bname__ scaled by the supplied factor around its center. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ ScaledFromCenterBy(__ltype__ vectorFactor) { var size = Size; var increment = (size * vectorFactor - size) / 2; return new __type__(Min - increment, Max + increment); } /// /// Return a box enlarged in all directions by the supplied epsilon which is /// measured with respect to the box diagonal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ EnlargedByRelativeEps(__ftype__ eps) { return EnlargedBy(eps * Size.Length); } /// /// Enlarge the box in all directions by the supplied epsilon which is /// measured with respect to the box diagonal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void EnlargeByRelativeEps(__ftype__ eps) { EnlargeBy(eps * Size.Length); } //# } //# } #endregion #region Box Arithmetics //# if (dim == 1) { /// /// Return the value in the Range that is closest to the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ltype__ Clamped(__ltype__ x) { return x < Min ? Min : (x > Max ? Max : x); } //# } else { // dim > 1 /// /// Return the point in the Box that is closest to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ltype__ Clamped(__ltype__ p) { return new __ltype__(/*# fields.ForEach(f => { */ p.__f__ < Min.__f__ ? Min.__f__ : (p.__f__ > Max.__f__ ? Max.__f__ : p.__f__)/*# }, comma); */); } //# if (ft.IsReal) { /// /// Returns the squared distance to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double DistanceSquared(__ltype__ p) { return /*# fields.ForEach(f => { */ (p.__f__ < Min.__f__ ? (Min.__f__ - p.__f__) * (Min.__f__ - p.__f__) : (p.__f__ > Max.__f__ ? (p.__f__ - Max.__f__) * (p.__f__ - Max.__f__) : 0.0))/*# }, add); */; } /// /// Returns the distance to the supplied point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double Distance(__ltype__ p) { return Fun.Sqrt(/*# fields.ForEach(f => { */ (p.__f__ < Min.__f__ ? (Min.__f__ - p.__f__) * (Min.__f__ - p.__f__) : (p.__f__ > Max.__f__ ? (p.__f__ - Max.__f__) * (p.__f__ - Max.__f__) : 0.0))/*# }, add); */); } //# } // ft.IsReal //# } // dim > 1 //# if (ft.IsReal) { /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ltype__ Lerp(__ftype__ x) => Fun.Lerp(x, Min, Max); //# if (dim == 1) { /// /// Performs the inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ltype__ InvLerp(__ltype__ x) => Fun.InvLerp(x, Min, Max); //# } else { // dim > 1 /// /// Interpolate linearly in each dimension. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ltype__ Lerp(__ltype__ p) => Fun.Lerp(p, Min, Max); /// /// Interpolate linearly in each dimension. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ltype__ Lerp(/*# args.ForEach(a => { */__ftype__ __a__/*# }, comma); */) => Fun.Lerp(new __ltype__(/*# args.ForEach(a => { */__a__/*# }, comma); */), Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ltype__ InvLerp(__ltype__ p) => Fun.InvLerp(p, Min, Max); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ltype__ InvLerp(/*# args.ForEach(a => { */__ftype__ __a__/*# }, comma); */) => Fun.InvLerp(new __ltype__(/*# args.ForEach(a => { */__a__/*# }, comma); */), Min, Max); //# } // dim > 1 //# } // ftype == "float" || ftype == "double" //# else { //# fdtypes.ForEach(tt => { //# var ttype = tt.Name; /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ltype__ Lerp(__ttype__ t) => Fun.Lerp(t, Min, Max); //# if (dim > 1) { //# var vtt = Meta.VecTypeOf(dim, tt); //# var vttype = vtt.Name; /// /// Linearly interpolates between min and max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ltype__ Lerp(__vttype__ t) => Fun.Lerp(t, Min, Max); //# } // dim > 1 //# }); /// /// Inverse of Lerp. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __dltype__ InvLerp(__ltype__ y) => Fun.InvLerp(y, Min, Max); //# } // not real //# if (dim > 1) { /// /// Returns the __bname__ with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ SplitRight(__ltype__ splitValue) { var result = new __type__(Min, Max); //# fields.ForEach(f => { if (splitValue.__f__ > result.Min.__f__) result.Min.__f__ = splitValue.__f__; //# }); return result; } /// /// Returns the __bname__ with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ SplitLeft(__ltype__ splitValue) { var result = new __type__(Min, Max); //# fields.ForEach(f => { if (splitValue.__f__ < result.Max.__f__) result.Max.__f__ = splitValue.__f__; //# }); return result; } //# } //# if (dim == 1) { /// /// Returns the __bname__ with Min value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ SplitRight(__ftype__ splitValue) { if (splitValue > Max) return __type__.Invalid; if (splitValue <= Min) return this; return new __type__(splitValue, Max); } /// /// Returns the __bname__ with Max value clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ SplitLeft(__ftype__ splitValue) { if (splitValue < Min) return __type__.Invalid; if (splitValue >= Max) return this; return new __type__(Min, splitValue); } //# } //# if (dim == 2) { /// /// Returns the __bname__ with Min.X clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ SplitRight(__ftype__ splitAtX) { if (splitAtX > Max.X) return __type__.Invalid; if (splitAtX <= Min.X) return this; return new __type__(new __ltype__(splitAtX, Min.Y), Max); } /// /// Returns a __bname__ with Max.X clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ SplitLeft(__ftype__ splitAtX) { if (splitAtX < Min.X) return __type__.Invalid; if (splitAtX >= Max.X) return this; return new __type__(Min, new __ltype__(splitAtX, Max.Y)); } /// /// Returns the __bname__ with Min.Y clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ SplitTop(__ftype__ splitAtY) { if (splitAtY > Max.Y) return __type__.Invalid; if (splitAtY <= Min.Y) return this; return new __type__(new __ltype__(Min.X, splitAtY), Max); } /// /// Returns the __bname__ with Max.Y clamped to splitValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ SplitBottom(__ftype__ splitAtY) { if (splitAtY < Min.Y) return __type__.Invalid; if (splitAtY >= Max.Y) return this; return new __type__(Min, new __ltype__(Max.X, splitAtY)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ SplitLeftBottom(__ltype__ splitAt) { if (splitAt.X < Min.X || splitAt.Y < Min.Y) return __type__.Invalid; return new __type__(Min, splitAt); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ SplitRightBottom(__ltype__ splitAt) { if (splitAt.X > Max.X || splitAt.Y < Min.Y) return __type__.Invalid; return new __type__(new __ltype__(splitAt.X, Min.Y), new __ltype__(Max.X, splitAt.Y)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ SplitLeftTop(__ltype__ splitAt) { if (splitAt.X < Min.X || splitAt.Y > Max.Y) return __type__.Invalid; return new __type__(new __ltype__(Min.X, splitAt.Y), new __ltype__(splitAt.X, Max.Y)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ SplitRightTop(__ltype__ splitAt) { if (splitAt.X > Max.X || splitAt.Y > Max.Y) return __type__.Invalid; return new __type__(splitAt, Max); } //# } //# if ( dim == 1) { /// /// Returns the __bname__ extended to contain the supplied __bname__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ ExtendedBy(__type__ range) { return new __type__( range.Min < Min ? range.Min : Min, range.Max > Max ? range.Max : Max); } /// /// Returns the __bname__ extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ ExtendedBy(__ftype__ value) { return new __type__( value < Min ? value : Min, value > Max ? value : Max); } /// /// Extends the __bname__ to contain the supplied __bname__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(__type__ range) { if (range.Min < Min) Min = range.Min; if (range.Max > Max) Max = range.Max; } /// /// Extends the __bname__ to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(__ftype__ value) { if (value < Min) Min = value; if (value > Max) Max = value; } //# } //# if ( dim > 1) { /// /// Returns the __bname__ extended to contain the supplied __bname__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ ExtendedBy(__type__ b) { return new __type__( new __ltype__(/*# fields.ForEach(f => {*/ b.Min.__f__ < Min.__f__ ? b.Min.__f__ : Min.__f__/*# }, comma); */), new __ltype__(/*# fields.ForEach(f => {*/ b.Max.__f__ > Max.__f__ ? b.Max.__f__ : Max.__f__/*# }, comma); */)); } /// /// Returns the __bname__ extended to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ ExtendedBy(__ltype__ v) { return new __type__( new __ltype__(/*# fields.ForEach(f => {*/ v.__f__ < Min.__f__ ? v.__f__ : Min.__f__/*# }, comma); */), new __ltype__(/*# fields.ForEach(f => { */ v.__f__ > Max.__f__ ? v.__f__ : Max.__f__/*# }, comma); */)); } /// /// Extends the __bname__ to contain the supplied __bname__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(__type__ box) { //# fields.ForEach(f => { if (box.Min.__f__ < Min.__f__) Min.__f__ = box.Min.__f__; if (box.Max.__f__ > Max.__f__) Max.__f__ = box.Max.__f__; //# }); } /// /// Extends the __bname__ to contain the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExtendBy(__ltype__ point) { //# fields.ForEach(f => { if (point.__f__ < Min.__f__) Min.__f__ = point.__f__; if (point.__f__ > Max.__f__) Max.__f__ = point.__f__; //# }); } //# } //# if (dim == 1) { /// /// Returns true if the range contains the given value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(__ftype__ value) { return value >= Min && value <= Max; } /// /// Returns true if the range completely contains the given range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(__type__ b) { return b.Min >= Min && b.Max <= Max; } /// /// Checks if 2 ranges intersect each other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(__type__ range) { if (Min >= range.Max) return false; if (Max <= range.Min) return false; return true; } /// /// Checks if 2 ranges intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(__type__ range, __ftype__ eps) { if (Min - eps >= range.Max) return false; if (Max + eps <= range.Min) return false; return true; } /// /// Checks if the range is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__ Repair() { if (this.Equals(__type__.Invalid)) return this; if (Min > Max) Fun.Swap(ref Min, ref Max); return this; } //# } //# if (dim > 1) { //# fields.ForEach(args, (f, a) => { [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__ Extend__f__By(__ftype__ __a__) { if (__a__ < Min.__f__) Min.__f__ = __a__; if (__a__ > Max.__f__) Max.__f__ = __a__; return this; } //# }); [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__ ExtendDimBy(int dim, __ftype__ x) { if (x < Min[dim]) Min[dim] = x; if (x > Max[dim]) Max[dim] = x; return this; } /// /// Returns true if the box contains the given point. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(__ltype__ p) { return/*# fields.ForEach(f => {*/ p.__f__ >= Min.__f__ && p.__f__ <= Max.__f__/*# }, andand);*/; } /// /// Returns true if the box completely contains the other box. /// A box contains itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(__type__ b) { return/*# fields.ForEach(f => {*/ b.Min.__f__ >= Min.__f__ && b.Max.__f__ <= Max.__f__/*# }, andand);*/; } /// /// Checks if the box is still valid and repairs if not. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__ Repair() { if (Equals(__type__.Invalid)) return this; //# fields.ForEach(f => { if (Min.__f__ > Max.__f__) Fun.Swap(ref Min.__f__, ref Max.__f__); //# }); return this; } /// /// Returns true if two boxes intersect each other (or one contains the other). /// Boxes DO NOT intersect if only touching from the outside. /// A box intersects itself. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(__type__ box) { //# fields.ForEach(f => { if (Min.__f__ >= box.Max.__f__) return false; if (Max.__f__ <= box.Min.__f__) return false; //# }); return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(__type__ box, __ltype__ eps) { //# fields.ForEach(f => { if (Min.__f__ - eps.__f__ >= box.Max.__f__) return false; if (Max.__f__ + eps.__f__ <= box.Min.__f__) return false; //# }); return true; } /// /// Returns true if 2 boxes intersect each other with tolerance parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Intersects(__type__ box, __ftype__ eps) { //# fields.ForEach(f => { if (Min.__f__ - eps >= box.Max.__f__) return false; if (Max.__f__ + eps <= box.Min.__f__) return false; //# }); return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__ Invalidate() { Min = __maxvalue__; Max = __minvalue__; return this; } /// /// Returns where a points coordinates are outside a given box /// /// All outside Flags [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(__ltype__ p0) { Box.Flags bf = Box.Flags.None; //# fields.ForEach(f => { if (p0.__f__ < Min.__f__) bf |= Box.Flags.Min__f__; else if (p0.__f__ > Max.__f__) bf |= Box.Flags.Max__f__; //# }); return bf; } /// /// Returns where the planes of the supplied box b are outside /// of the box. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box.Flags OutsideFlags(__type__ b) { Box.Flags bf = Box.Flags.None; //# fields.ForEach(f => { if (b.Min.__f__ < Min.__f__) bf |= Box.Flags.Min__f__; if (b.Max.__f__ > Max.__f__) bf |= Box.Flags.Max__f__; //# }); return bf; } /// /// Gets the minimal and maximal points of the box when seen from the /// supplied direction vector v. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void GetMinMaxInDirection(__ltype__ v, out __ltype__ vMin, out __ltype__ vMax) { vMin = __minvalue__; vMax = __maxvalue__; //# fields.ForEach(f => { if (v.__f__ >= 0) { vMin.__f__ = Min.__f__; vMax.__f__ = Max.__f__; } else { vMin.__f__ = Max.__f__; vMax.__f__ = Min.__f__; } //# }); } //# } #endregion #region Operators /// /// Checks if 2 boxes are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ a, __type__ b) { return (a.Min == b.Min) && (a.Max == b.Max); } /// /// Checks if 2 boxes are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ a, __type__ b) { return (a.Min != b.Min) || (a.Max != b.Max); } /// /// Returns a __bname__ shifted by the supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator +(__type__ box, __ltype__ v) { return new __type__(__lcast__(box.Min + v), __lcast__(box.Max + v)); } /// /// Returns a __bname__ shifted by the negative supplied value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator -(__type__ box, __ltype__ v) { return new __type__(__lcast__(box.Min - v), __lcast__(box.Max - v)); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => Min.Equals(other.Min) && Max.Equals(other.Max); public override readonly bool Equals(object obj) => (obj is __type__ o) && Equals(o); public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } #endregion #region Static Methods /// /// Element setter action. /// public static readonly ActionRefValVal<__type__, int, __ltype__> Setter = (ref __type__ box, int i, __ltype__ value) => { switch (i) { case 0: box.Min = value; return; case 1: box.Max = value; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Parsing public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); //# if (dim > 1) { return new __type__(__ltype__.Parse(x[0].ToString()), __ltype__.Parse(x[1].ToString())); //# } else { return new __type__(__ftype__.Parse(x[0], CultureInfo.InvariantCulture), __ftype__.Parse(x[1], CultureInfo.InvariantCulture)); //# } } public static __type__ Parse(Text t) { //# if (dim > 1) { return t.NestedBracketSplit(1, __ltype__.Parse, __type__.Setter); //# } else { return t.NestedBracketSplit(1, Text<__ltype__>.Parse, __type__.Setter); //# } } #endregion #region IFormattable Members public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"/*# if (dim > 1) {*/, "[", ", ", "]"/*# }*/); } /// /// Outputs e.g. a Box2 in the form "(beginB)(beginV)min.x(betweenV)min.y(endV)(betweenB)(beginV)max.x(betweenV)max.y(endV)(endB)". /// //# var begin = "begin" + ((dim > 1) ? "B" : ""); //# var between = "between" + ((dim > 1) ? "B" : ""); //# var end = "end" + ((dim > 1) ? "B" : ""); public readonly string ToString(string format, IFormatProvider fp, string __begin__, string __between__, string __end__/*# if (dim > 1) {*/, string beginV, string betweenV, string endV/*# }*/) { //# var format = "format, fp" + (dim > 1 ? ", beginV, betweenV, endV" : ""); fp ??= CultureInfo.InvariantCulture; return __begin__ + Min.ToString(__format__) + __between__ + Max.ToString(__format__) + __end__; } #endregion //# if (dim > 1) { #region Static Factories /// /// Returns new box [0, size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromSize(__ltype__ size) { return new __type__(__ltype__.Zero, size); } /// /// Returns new box [min, min + size]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromMinAndSize(__ltype__ min, __ltype__ size) { return new __type__(min, min + size); } /// /// Returns new box [center - size / 2, center + size / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromCenterAndSize(__ltype__ center, __ltype__ size) { return new __type__(center - size / 2, center + size / 2); } /// /// Returns new box [0, iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromSize(ISize__dim____ch__ iSize) { return new __type__( __ltype__.Zero, iSize.Size__dim____ch__); } /// /// Returns new box [min, min + iSize]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromMinAndSize(__ltype__ min, ISize__dim____ch__ iSize) { return new __type__( min, min + iSize.Size__dim____ch__); } /// /// Returns new box [center - iSize / 2, center + iSize / 2]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromCenterAndSize(__ltype__ center, ISize__dim____ch__ iSize) { var size = iSize.Size__dim____ch__; return new __type__(center - size / 2, center + size / 2); } /// /// Creates box from 2 points which need not be Min and Max. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromPoints(__ltype__ p0, __ltype__ p1) { return new __type__(Fun.Min(p0, p1), Fun.Max(p0, p1)); } //# if (dim == 2) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromSize(__ftype__ width, __ftype__ height) { return __type__.FromSize(new __ltype__(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromMinAndSize(__ltype__ min, __ftype__ width, __ftype__ height) { return new __type__(min, min + new __ltype__(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromMinAndSize( __ftype__ minX, __ftype__ minY, __ftype__ width, __ftype__ height ) { return __type__.FromMinAndSize(new __ltype__(minX, minY), new __ltype__(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromCenterAndSize(__ltype__ center, __ftype__ width, __ftype__ height) { return FromCenterAndSize(center, new __ltype__(width, height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromCenterAndSize( __ftype__ centerX, __ftype__ centerY, __ftype__ width, __ftype__ height ) { return FromCenterAndSize(new __ltype__(centerX, centerY), new __ltype__(width, height)); } //# } #endregion #region Transforms [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ Translated(__ltype__ shift) { return IsInvalid ? __type__.Invalid : new __type__(Min + shift, Max + shift); } /// /// Returns a scaled box. WARNING: scaling is performed around the origin! /// A negative scale factor will resut in an invalid box! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type__ Scaled(__ltype__ factor) { return IsInvalid ? __type__.Invalid : new __type__(Min * factor, Max * factor); } /// /// Transforms the box by the given transformation matrix. /// NOTE: Performs IsValid check at 10% CPU time overhead. /// -> Empty bounds (crossed min and max) will remain empty. /// //# { //# var tc = (ft == Meta.FloatType) ? "f" : "d"; //# var tftype = (ft == Meta.FloatType) ? "float" : "double"; public readonly Box__dim____tc__ Transformed(M__dplus1____dplus1____tc__ trafo) { if (/*# fields.ForEach((f, i) => {*/Min.__f__ > Max.__f__/*#}, oror);*/) return Box__dim____tc__.Invalid; var t = new V__dim____tc__(/*# fields.ForEach((f, i) => {*/trafo.M__i____dim__/*#}, comma);*/); var res = new Box__dim____tc__(t, t); __tftype__ av, bv; //# for (int i = 0; i < dim; i++) { var fi = vt.Fields[i]; //# for (int j = 0; j < dim; j++) { var fj = vt.Fields[j]; av = trafo.M__i____j__ * Min.__fj__; bv = trafo.M__i____j__ * Max.__fj__; if (av < bv) { res.Min.__fi__ += av; res.Max.__fi__ += bv; } else { res.Min.__fi__ += bv; res.Max.__fi__ += av; } //# } //# } return res; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Box__dim____tc__ Transformed(Trafo__dim____tc__ trafo) { return Transformed(trafo.Forward); } //# } #endregion #region Corners /// /// Return the corner of the box with the given index. The corner /// index is constructed in such a way, that bit 0 enumerates the /// x coordinate (0 ... min, 1 ... max), bit 1 enumerates the y /// coordinate, and bit 2 enumerates the z coordinate. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ltype__ Corner(int index) { return new __ltype__(/*# fields.ForEach((f, i) => { var bit = 1 << i; */ (index & __bit__) == 0 ? Min.__f__ : Max.__f__/*#}, comma);*/); } /// /// Computes the corners of the box and returns them in an array. /// The order of the corners is determined by their index which is /// constructed as in the method . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ltype__[] ComputeCorners() { return [ Min, //# for (int i = 1; i < (1 << dim) - 1; i++) { new(/*# fields.ForEach((f, b) => { var bf = ((i & (1< /// Enumeration of the corners of the box. /// public readonly IEnumerable<__ltype__> Corners { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return Min; //# for (int i = 1; i < (1 << dim) - 1; i++) { yield return new __ltype__(/*# fields.ForEach((f, b) => { var bf = ((i & (1< 0 && !ft.IsReal) { /// /// Returns all points from [Min,Max[ with X-Variable in the outer loop. /// public readonly IEnumerable<__ltype__> EnumerateInsidePoints() { var p = new __ltype__(); //# fields.ForEach(f => { for (p.__f__ = Min.__f__; p.__f__ < Max.__f__; p.__f__++) //# }); yield return p; } //# } #endregion #region IBoundingBox__dim____ch__ Members public readonly Box__dim____ch__ BoundingBox__dim____ch__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return this; } } #endregion //# if (dim == 2) { #region IBoundingCircle__dim____cch__ Members public readonly Circle__dim____cch__ BoundingCircle__dim____cch__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => IsInvalid ? Circle__dim____cch__.Invalid : new Circle__dim____cch__(/*# if (ft != ct) {*/(V__dim____cch__)/*# }*/Center, __half__ * Size.Length); } #endregion //# } //# if (dim == 3) { #region IBoundingSphere__dim____cch__ Members public readonly Sphere__dim____cch__ BoundingSphere__dim____cch__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => IsInvalid ? Sphere__dim____cch__.Invalid : new Sphere__dim____cch__(/*# if (ft != ct) {*/(V__dim____cch__)/*# }*/Center, __half__ * Size.Length); } #endregion //# } #region ISize__dim____ch__ Members public readonly V__dim____ch__ Size__dim____ch__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Size; } } #endregion //# } } public static partial class __bnamecaps__ { #region Set operations [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Union(this __type__ a, __type__ b) { return new __type__(Fun.Min(a.Min, b.Min), Fun.Max(a.Max, b.Max)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Intersection(this __type__ a, __type__ b) { return new __type__(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); } //# if (dim == 1) { /// /// Checks if two __bname__s intersect each other with a tolerance parameter. /// // TODO: Implement for d > 2 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Intersects(this __type__ a, __type__ b, __ftype__ eps, out __type__ result) { result = __type__.Invalid; if (a.Min - eps > b.Max) return false; else if (a.Max + eps < b.Min) return false; else { result = new __type__(Fun.Max(a.Min, b.Min), Fun.Min(a.Max, b.Max)); if (result.Size < eps) { __ftype__ center = result.Center; result.Min = __lcast__(center - eps); result.Max = __lcast__(center + eps); } return true; } } //# } #endregion #region Bounding __bname__ for arrays /// /// Returns the bounding __bname__ of the elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ GetBounding__bnamecaps__(this __ltype__[] pointArray) { return pointArray.GetBounding__bnamecaps__(0, pointArray.LongLength); } /// /// Returns the bounding __bname__ of the first count elements of the array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ GetBounding__bnamecaps__(this __ltype__[] pointArray, long count) { return pointArray.GetBounding__bnamecaps__(0, count); } /// /// Returns the bounding __bname__ of count elements of the array starting at start. /// public static __type__ GetBounding__bnamecaps__( this __ltype__[] pointArray, long start, long count) { if (count <= 0) return __type__.Invalid; var box = new __type__(pointArray[start]); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[i]); return box; } /// /// Returns the bounding __bname__ of count elements of the array starting at start. /// public static __type__ GetBounding__bnamecaps__(this T[] array, long start, long count, Func pointSelector) { if (count <= 0) return __type__.Invalid; var box = new __type__(pointSelector(array[start])); for (long i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[i])); return box; } #endregion #region Bounding __bname__ for lists /// /// Returns the bounding __bname__ of the elements of the list. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ GetBounding__bnamecaps__(this List<__ltype__> pointList) { return pointList.GetBounding__bnamecaps__(pointList.Count); } /// /// Returns the bounding __bname__ of the first count elements of the list. /// public static __type__ GetBounding__bnamecaps__(this List<__ltype__> pointList, int count) { if (count <= 0) return __type__.Invalid; var box = new __type__(pointList[0]); for (int i = 1; i < count; i++) box.ExtendBy(pointList[i]); return box; } #endregion #region Bounding __bname__ for indexed arrays //# foreach (var itype in new[] { "int", "long" }) { //# var getlength = itype == "int" ? "Length" : "LongLength"; /// /// Returns the bounding __bname__ of the elements of pointArray indexed by the indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ GetBounding__bnamecaps__(this __itype__[] indexArray, __ltype__[] pointArray) { return indexArray.GetBounding__bnamecaps__(0, indexArray.__getlength__, pointArray); } /// /// Returns the bounding __bname__ of the elements of pointArray indexed by the first count indices in indexArray. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ GetBounding__bnamecaps__(this __itype__[] indexArray, __itype__ count, __ltype__[] pointArray) { return indexArray.GetBounding__bnamecaps__(0, count, pointArray); } /// /// Returns the bounding __bname__ of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static __type__ GetBounding__bnamecaps__(this __itype__[] indexArray, __itype__ start, __itype__ count, __ltype__[] pointArray) { if (count <= 0) return __type__.Invalid; var box = new __type__(pointArray[indexArray[start]]); for (__itype__ i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointArray[indexArray[i]]); return box; } /// /// Returns the bounding __bname__ of the elements of pointArray indexed by count indices /// in indexArray starting at start. /// public static __type__ GetBounding__bnamecaps__(this __itype__[] indexArray, __itype__ start, __itype__ count, T[] array, Func pointSelector) { if (count <= 0) return __type__.Invalid; var box = new __type__(pointSelector(array[indexArray[start]])); for (__itype__ i = start + 1, e = start + count; i < e; i++) box.ExtendBy(pointSelector(array[indexArray[i]])); return box; } //# } #endregion #region Bounding __bname__ for IEnumerable /// /// Returns the bounding __bname__ of the elements of the collection. /// public static __type__ GetBounding__bnamecaps__(this IEnumerable<__ltype__> points) { var box = __type__.Invalid; foreach (var p in points) box.ExtendBy(p); return box; } #endregion //# if (dim == 3) { #region Get octant /// /// Octant 0-7. /// 0th, 1st and 2nd bit encodes x-, y-, z-axis, respectively. /// E.g. 0 is octant [box.Min, box.Center], 7 is octant [box.Center, box.Max]. /// public static __type__ GetOctant(this __type__ box, int i) { if (i < 0 || i > 7) throw new IndexOutOfRangeException(); __ftype__ x0, x1, y0, y1, z0, z1; var c = box.Center; if ((i & 1) == 0) { x0 = box.Min.X; x1 = c.X; } else { x0 = c.X; x1 = box.Max.X; } if ((i & 2) == 0) { y0 = box.Min.Y; y1 = c.Y; } else { y0 = c.Y; y1 = box.Max.Y; } if (i < 4) { z0 = box.Min.Z; z1 = c.Z; } else { z0 = c.Z; z1 = box.Max.Z; } return new __type__(new __ltype__(x0, y0, z0), new __ltype__(x1, y1, z1)); } #endregion #region Outline corners /// /// Gets outline corner indices of a box as seen from given position (in counter-clockwise order). /// Returns null if position is inside the box. /// public static int[] GetOutlineCornerIndicesCCW(this __type__ box, __ltype__ fromPosition) { if (fromPosition.X < box.Min.X) { //-X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // -X -Y -Z return [1, 5, 4, 6, 2, 3]; } else if (fromPosition.Z > box.Max.Z) { // -X -Y +Z return [0, 1, 5, 7, 6, 2]; } else { // -X -Y Z return [1, 5, 6, 2]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // -X +Y -Z return [0, 4, 6, 7, 3, 1]; } else if (fromPosition.Z > box.Max.Z) { // -X +Y +Z return [0, 4, 5, 7, 3, 2]; } else { // -X +Y Z return [0, 4, 7, 3]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // -X Y -Z return [1, 4, 6, 3]; } else if (fromPosition.Z > box.Max.Z) { // -X Y +Z return [0, 5, 7, 2]; } else { // -X Y Z return [0, 4, 6, 2]; } } } else if (fromPosition.X > box.Max.X) { // +X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // +X -Y -Z return [0, 2, 3, 7, 5, 4]; } else if (fromPosition.Z > box.Max.Z) { // +X -Y +Z return [0, 1, 3, 7, 6, 4]; } else { // +X -Y Z return [0, 3, 7, 4]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // +X +Y -Z return [0, 2, 6, 7, 5, 1]; } else if (fromPosition.Z > box.Max.Z) { // +X +Y +Z return [1, 3, 2, 6, 4, 5]; } else { // +X +Y Z return [1, 2, 6, 5]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // +X Y -Z return [0, 2, 7, 5]; } else if (fromPosition.Z > box.Max.Z) { // +X Y +Z return [1, 3, 6, 4]; } else { // +X Y Z return [1, 3, 7, 5]; } } } else { // X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // X -Y -Z return [2, 3, 5, 4]; } else if (fromPosition.Z > box.Max.Z) { // X -Y +Z return [0, 1, 7, 6]; } else { // X -Y Z return [0, 1, 5, 4]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // X +Y -Z return [0, 6, 7, 1]; } else if (fromPosition.Z > box.Max.Z) { // X +Y +Z return [2, 4, 5, 3]; } else { // X +Y Z return [2, 6, 7, 3]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // X Y -Z return [0, 2, 3, 1]; } else if (fromPosition.Z > box.Max.Z) { // X Y +Z return [4, 5, 7, 6]; } else { // X Y Z return null; } } } } /// /// Gets outline corner indices of a box as seen from given position (in clockwise order). /// Returns null if position is inside the box. /// public static int[] GetOutlineCornerIndicesCW(this __type__ box, __ltype__ fromPosition) { if (fromPosition.X < box.Min.X) { //-X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // -X -Y -Z return [1, 3, 2, 6, 4, 5]; } else if (fromPosition.Z > box.Max.Z) { // -X -Y +Z return [0, 2, 6, 7, 5, 1]; } else { // -X -Y Z return [1, 2, 6, 5]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // -X +Y -Z return [0, 1, 3, 7, 6, 4]; } else if (fromPosition.Z > box.Max.Z) { // -X +Y +Z return [0, 2, 3, 7, 5, 4]; } else { // -X +Y Z return [0, 3, 7, 4]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // -X Y -Z return [1, 3, 6, 4]; } else if (fromPosition.Z > box.Max.Z) { // -X Y +Z return [0, 2, 7, 5]; } else { // -X Y Z return [0, 2, 6, 4]; } } } else if (fromPosition.X > box.Max.X) { // +X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // +X -Y -Z return [0, 4, 5, 7, 3, 2]; } else if (fromPosition.Z > box.Max.Z) { // +X -Y +Z return [0, 4, 6, 7, 3, 1]; } else { // +X -Y Z return [0, 4, 7, 3]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // +X +Y -Z return [0, 1, 5, 7, 6, 2]; } else if (fromPosition.Z > box.Max.Z) { // +X +Y +Z return [1, 5, 4, 6, 2, 3]; } else { // +X +Y Z return [1, 5, 6, 2]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // +X Y -Z return [0, 5, 7, 2]; } else if (fromPosition.Z > box.Max.Z) { // +X Y +Z return [1, 4, 6, 3]; } else { // +X Y Z return [1, 5, 7, 3]; } } } else { // X if (fromPosition.Y < box.Min.Y) { //-Y if (fromPosition.Z < box.Min.Z) { // X -Y -Z return [2, 4, 5, 3]; } else if (fromPosition.Z > box.Max.Z) { // X -Y +Z return [0, 6, 7, 1]; } else { // X -Y Z return [0, 4, 5, 1]; } } else if (fromPosition.Y > box.Max.Y) { // +Y if (fromPosition.Z < box.Min.Z) { // X +Y -Z return [0, 1, 7, 6]; } else if (fromPosition.Z > box.Max.Z) { // X +Y +Z return [2, 3, 5, 4]; } else { // X +Y Z return [2, 3, 7, 6]; } } else { // Y if (fromPosition.Z < box.Min.Z) { // X Y -Z return [0, 1, 3, 2]; } else if (fromPosition.Z > box.Max.Z) { // X Y +Z return [4, 6, 7, 5]; } else { // X Y Z return null; } } } } /// /// Gets outline corners of a box as seen from given position (in counter-clockwise order). /// Returns null if position is inside the box. /// public static __ltype__[] GetOutlineCornersCCW(this __type__ box, __ltype__ fromPosition) { var cs = box.ComputeCorners(); return GetOutlineCornerIndicesCCW(box, fromPosition)?.Map(i => cs[i]); } /// /// Gets outline corners of a box as seen from given position (in clockwise order). /// Returns null if position is inside the box. /// public static __ltype__[] GetOutlineCornersCW(this __type__ box, __ltype__ fromPosition) { var cs = box.ComputeCorners(); return GetOutlineCornerIndicesCW(box, fromPosition)?.Map(i => cs[i]); } #endregion //# } } //# if (dim == 1) { #region Range extensions //# if (ft.IsReal) { public static partial class Conversion { #region Angles (Radians, Degrees, Gons) //# var units = new[] { "Radians", "Degrees", "Gons" }; //# units.ForEach(u1 => { //# units.ForEach(u2 => { if (u1 == u2) return; //# var n1 = u1.ToLower(); //# var n2 = u2.ToLower(); /// /// Converts the angles given in __n2__ to __n1__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ __u1__From__u2__(this __type__ __n2__) => new(__n2__.Min.__u1__From__u2__(), __n2__.Max.__u1__From__u2__()); //# }); }); #endregion } //# } public static partial class __bnamecaps__Extensions { /// /// Returns the int sequence 0 ... count-1. /// public static IEnumerable<__ltype__> Range(this __ltype__ count) { for (__ltype__ i = 0; i < count; i++) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<__ltype__> UpTo(this __ltype__ self, __ltype__ upToInclusive) { return self.UpTo(upToInclusive, 1); } public static IEnumerable<__ltype__> UpTo(this __ltype__ self, __ltype__ upToInclusive, __ltype__ step) { for (__ltype__ i = self; i <= upToInclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<__ltype__> UpToExclusive(this __ltype__ self, __ltype__ upToExclusive) { return self.UpToExclusive(upToExclusive, 1); } public static IEnumerable<__ltype__> UpToExclusive(this __ltype__ self, __ltype__ upToExclusive, __ltype__ step) { for (__ltype__ i = self; i < upToExclusive; i += step) yield return i; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<__ltype__> DownTo(this __ltype__ self, __ltype__ downToInclusive) { return self.DownTo(downToInclusive, 1); } public static IEnumerable<__ltype__> DownTo(this __ltype__ self, __ltype__ downToInclusive, __ltype__ step) { for (__ltype__ i = self; i >= downToInclusive; i -= step) yield return i; } } #endregion //# } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b) { return ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b, __ftype__ tolerance) => ApproximateEquals(a.Min, b.Min, tolerance) && ApproximateEquals(a.Max, b.Max, tolerance); #endregion } #endregion //# if (dim == 3) { #region __type__AndFlags [DataContract] public struct __type__AndFlags { [DataMember] public Box.Flags BFlags; [DataMember] public __type__ BBox; public __type__AndFlags(__type__ union, __type__ box0, __type__ box1) { BFlags = 0; BBox = union; if (box0.Min.X > union.Min.X) { BBox.Min.X = box0.Min.X; BFlags |= Box.Flags.MinX0; } if (box0.Min.Y > union.Min.Y) { BBox.Min.Y = box0.Min.Y; BFlags |= Box.Flags.MinY0; } if (box0.Min.Z > union.Min.Z) { BBox.Min.Z = box0.Min.Z; BFlags |= Box.Flags.MinZ0; } if (box0.Max.X < union.Max.X) { BBox.Max.X = box0.Max.X; BFlags |= Box.Flags.MaxX0; } if (box0.Max.Y < union.Max.Y) { BBox.Max.Y = box0.Max.Y; BFlags |= Box.Flags.MaxY0; } if (box0.Max.Z < union.Max.Z) { BBox.Max.Z = box0.Max.Z; BFlags |= Box.Flags.MaxZ0; } if (box1.Min.X > union.Min.X) { BBox.Min.X = box1.Min.X; BFlags |= Box.Flags.MinX1; } if (box1.Min.Y > union.Min.Y) { BBox.Min.Y = box1.Min.Y; BFlags |= Box.Flags.MinY1; } if (box1.Min.Z > union.Min.Z) { BBox.Min.Z = box1.Min.Z; BFlags |= Box.Flags.MinZ1; } if (box1.Max.X < union.Max.X) { BBox.Max.X = box1.Max.X; BFlags |= Box.Flags.MaxX1; } if (box1.Max.Y < union.Max.Y) { BBox.Max.Y = box1.Max.Y; BFlags |= Box.Flags.MaxY1; } if (box1.Max.Z < union.Max.Z) { BBox.Max.Z = box1.Max.Z; BFlags |= Box.Flags.MaxZ1; } } } #endregion //# } //# } } ================================================ FILE: src/Aardvark.Base/Math/RangesBoxes/Cell.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Runtime.Serialization; using System.Text.Json.Serialization; namespace Aardvark.Base; /// /// An axis-aligned cube in a hierarchical spatial grid where all cells have power-of-two sizes. /// Position is (X,Y,Z) * 2^Exponent, size is 2^Exponent. /// [DataContract] public readonly partial struct Cell : IEquatable { /// /// Unit cell (0, 0, 0, 0) -> Box3d[(0.0, 0.0, 0.0), (1.0, 1.0, 1.0)] /// public static Cell Unit => new(0L, 0L, 0L, 0); /// /// Special value denoting "invalid cell". /// public static Cell Invalid => new(long.MinValue, long.MinValue, long.MinValue, int.MinValue); /// /// Grid coordinate at resolution 2^Exponent. /// [DataMember] public readonly long X; /// /// Grid coordinate at resolution 2^Exponent. /// [DataMember] public readonly long Y; /// /// Grid coordinate at resolution 2^Exponent. /// [DataMember] public readonly long Z; /// /// Power of two defining both cell size and grid resolution. /// [DataMember(Name = "E")] public readonly int Exponent; #region constructors /// /// Creates a 2^exponent sized cube positioned at (x,y,z) * 2^exponent. /// public Cell(long x, long y, long z, int exponent) { X = x; Y = y; Z = z; Exponent = exponent; } /// /// Creates copy of cell. /// public Cell(Cell cell) { X = cell.X; Y = cell.Y; Z = cell.Z; Exponent = cell.Exponent; } /// /// Cell with min corner at index*2^exponent and size 2^exponent. /// public Cell(V3l index, int exponent) : this(index.X, index.Y, index.Z, exponent) { } /// /// Special cell, which is centered at origin, with size 2^exponent. /// public Cell(int exponent) { if (exponent == int.MinValue) { X = long.MinValue; Y = long.MinValue; Z = long.MinValue; Exponent = exponent; } else { X = long.MaxValue; Y = long.MaxValue; Z = long.MaxValue; Exponent = exponent; } } /// /// Smallest cell that contains given box. /// public Cell(Box3f box) : this(new Box3d(box)) { } /// /// Smallest cell that contains given points. /// public Cell(V3f[] ps) : this(new Box3f(ps)) { } /// /// Smallest cell that contains given points. /// public Cell(ReadOnlySpan ps) : this(new Box3f(ps)) { } /// /// Smallest cell that contains given points. /// public Cell(V3d[] ps) : this(new Box3d(ps)) { } /// /// Smallest cell that contains given points. /// public Cell(ReadOnlySpan ps) : this(new Box3d(ps)) { } /// /// Smallest cell that contains given points. /// public Cell(IEnumerable ps) : this(new Box3f(ps)) { } /// /// Smallest cell that contains given points. /// public Cell(IEnumerable ps) : this(new Box3d(ps)) { } /// /// Smallest cell containing the given point. /// public Cell(V3d p) : this(new Box3d(p)) { } /// /// Smallest cell that contains given box, /// where box.Min and box.Max are both interpreted as inclusive /// (whereas a cell's maximum is defined as exclusive). /// public Cell(Box3d box) { if (!box.IsValid) throw new InvalidOperationException(); // case 1: contains origin if (box.Min.X < 0.0 && box.Max.X >= 0.0 || box.Min.Y < 0.0 && box.Max.Y >= 0.0 || box.Min.Z < 0.0 && box.Max.Z >= 0.0) { X = Y = Z = long.MaxValue; Exponent = Math.Max(box.Min.NormMax, box.Max.NormMax).Log2CeilingInt() + 1; } else // case 2: doesn't contain origin { Exponent = (box.Min == box.Max) ? (box.Min.NormMax / (long.MaxValue >> 1)).Log2CeilingInt() : box.Size.NormMax.Log2CeilingInt() ; var s = Math.Pow(2.0, Exponent); var a = (box.Min * (1.0 / s)).Floor(); X = (long)a.X; Y = (long)a.Y; Z = (long)a.Z; while (box.Max.X >= X * s + s || box.Max.Y >= Y * s + s || box.Max.Z >= Z * s + s) { X >>= 1; Y >>= 1; Z >>= 1; ++Exponent; s *= 2.0; } } } /// /// Common root of a and b. /// public Cell(Cell a, Cell b) : this(GetCommonRoot(a, b)) { } /// /// Common root of cells. /// public Cell(params Cell[] cells) : this(GetCommonRoot(cells)) { } #endregion /// /// Grid coordinates as a vector. /// [JsonIgnore] public V3l XYZ => new(X, Y, Z); /// /// True if special cell centered at the origin. /// [JsonIgnore] public bool IsCenteredAtOrigin => X == long.MaxValue && Y == long.MaxValue && Z == long.MaxValue; /// /// Returns true if this is the special invalid cell. /// [JsonIgnore] public bool IsInvalid => X == long.MinValue && Y == long.MinValue && Z == long.MinValue && Exponent == int.MinValue; /// /// Returns true if this is NOT the special invalid cell. /// [JsonIgnore] public bool IsValid => X != long.MinValue || Y != long.MinValue || Z != long.MinValue || Exponent != int.MinValue; /// /// Returns true if the cell completely contains the other cell. /// A cell contains itself. /// public bool Contains(Cell other) { if (other.Exponent > Exponent) return false; if (other.Exponent == Exponent) return other.X == X && other.Y == Y && other.Z == Z; // always true from here on: // Exponent > other.Exponent // other.Exponent < Exponent if (IsCenteredAtOrigin) { if (other.IsCenteredAtOrigin) { return true; } else { // bring other into scale of this var d = (Exponent - 1) - other.Exponent; // right-shift with long argument only uses low-order 6 bits // https://docs.microsoft.com/en-us/dotnet/articles/csharp/language-reference/operators/right-shift-operator if (d > 63) d = 63; var x = other.X >> d; var y = other.Y >> d; var z = other.Z >> d; return x >= -1 && x <= 0 && y >= -1 && y <= 0 && z >= -1 && z <= 0; } } else { if (other.IsCenteredAtOrigin) { return false; } else { // bring other into scale of this var d = Exponent - other.Exponent; // right-shift with long argument only uses low-order 6 bits // https://docs.microsoft.com/en-us/dotnet/articles/csharp/language-reference/operators/right-shift-operator if (d > 63) d = 63; var x = other.X >> d; var y = other.Y >> d; var z = other.Z >> d; return x == X && y == Y && z == Z; } } } /// /// Returns true if two cells intersect each other (or one contains the other). /// Cells DO NOT intersect if only touching from the outside. /// A cell intersects itself. /// public bool Intersects(Cell other) { if (X == other.X && Y == other.Y && Z == other.Z && Exponent == other.Exponent) return true; return BoundingBox.Intersects(other.BoundingBox); } /// /// The 8 subcells created by splitting each axis in half. /// [JsonIgnore] public Cell[] Children { get { var x0 = X << 1; var y0 = Y << 1; var z0 = Z << 1; if (IsCenteredAtOrigin) { x0++; y0++; z0++; } var x1 = x0 + 1; var y1 = y0 + 1; var z1 = z0 + 1; var e = Exponent - 1; return [ new(x0, y0, z0, e), new(x1, y0, z0, e), new(x0, y1, z0, e), new(x1, y1, z0, e), new(x0, y0, z1, e), new(x1, y0, z1, e), new(x0, y1, z1, e), new(x1, y1, z1, e), ]; } } /// /// Gets parent cell. /// [JsonIgnore] public Cell Parent => IsCenteredAtOrigin ? new(Exponent + 1) : new(X >> 1, Y >> 1, Z >> 1, Exponent + 1); /// /// True if any corner of this cell is exactly at the origin. /// [JsonIgnore] public bool TouchesOrigin => !IsCenteredAtOrigin && (X == -1 || X == 0) && (Y == -1 || Y == 0) && (Z == -1 || Z == 0); /// /// Cell's bounds as Box3d. /// [JsonIgnore] public Box3d BoundingBox => ComputeBoundingBox(X, Y, Z, Exponent); private static Box3d ComputeBoundingBox(long x, long y, long z, int e) { var d = Math.Pow(2.0, e); var isCenteredAtOrigin = x == long.MaxValue && y == long.MaxValue && z == long.MaxValue; var min = isCenteredAtOrigin ? new V3d(-0.5 * d) : new V3d(x * d, y * d, z * d); return Box3d.FromMinAndSize(min, new V3d(d, d, d)); } /// /// Computes geometric center point of this cell. /// public V3d GetCenter() => BoundingBox.Center; /// /// Octant 0-7. /// 0th, 1st and 2nd bit encodes x-, y-, z-axis, respectively. /// E.g. 0 is octant at origin, 7 is octant oposite from origin. /// public Cell GetOctant(int i) { if (i < 0 || i > 7) throw new IndexOutOfRangeException(); if (IsCenteredAtOrigin) { return new( (i & 1) == 0 ? -1 : 0, (i & 2) == 0 ? -1 : 0, (i & 4) == 0 ? -1 : 0, Exponent - 1 ); } else { return new( (X << 1) + ((i & 1) == 0 ? 0 : 1), (Y << 1) + ((i & 2) == 0 ? 0 : 1), (Z << 1) + ((i & 4) == 0 ? 0 : 1), Exponent - 1 ); } } /// /// Returns the octant of this cell, in which the other cell is contained. /// If the other cell is not contained in any octant, then no value is returned. /// public int? GetOctant(Cell other) { // if other cell is bigger or same size, // then it cannot be contained in any octant if (other.Exponent >= Exponent) return null; if (IsCenteredAtOrigin) { if (other.IsCenteredAtOrigin) return null; // scale up other to scale of this cell's octants // where coord values 0 or 1 mean left or right, // and all other values mean that the other cell is outside other <<= Exponent - other.Exponent - 1; var o = 0; if (other.X == 0) o = 1; else if (other.X != -1) return null; if (other.Y == 0) o |= 2; else if (other.Y != -1) return null; if (other.Z == 0) o |= 4; else if (other.Z != -1) return null; return o; } else { if (other.IsCenteredAtOrigin) return null; // scale up other to scale of this cell's octants, // where coord values -1 or 0 mean left or right, // and all other values mean that the other cell is outside other <<= Exponent - other.Exponent - 1; var x = X << 1; var y = Y << 1; var z = Z << 1; var o = 0; if (other.X == x + 1) o = 1; else if (other.X != x) return null; if (other.Y == y + 1) o |= 2; else if (other.Y != y) return null; if (other.Z == z + 1) o |= 4; else if (other.Z != z) return null; return o; } } /// /// Get the global octant this cell is located in, or no value if this is a centered cell. /// public int? Octant { get { if (IsCenteredAtOrigin) return null; var o = 0; if (X >= 0) o = 1; if (Y >= 0) o |= 2; if (Z >= 0) o |= 4; return o; } } /// /// Smallest cell that contains both input cells. /// public static Cell GetCommonRoot(Cell a, Cell b) { if (a == b) return a; if (a.IsCenteredAtOrigin) { if (b.IsCenteredAtOrigin) { // if both are centered, then the larger cell is the result return a.Exponent > b.Exponent ? a : b; } else { // if A is centered and B is not centered, // then enlarge A until it contains B while (!a.Contains(b)) a = a.Parent; return a; } } else { if (b.IsCenteredAtOrigin) { // if A is not centered and B is centered, // then enlarge B until it contains A while (!b.Contains(a)) b = b.Parent; return b; } else { // if no cell is centered, ... if (a.Octant == b.Octant) { // and both cells are located in the same global octant, // then recursively grow smaller cell (take parent) // until a and b meet at their common root return a.Exponent > b.Exponent ? GetCommonRoot(a, b.Parent) : GetCommonRoot(a.Parent, b); } else { // and each cell is located in a different global octant, // then take a centered cell and enlarge it until it contains both A and B var c = new Cell(Math.Max(a.Exponent, b.Exponent) + 1); // centered cell needs to be at least twice as large as the bigger one of A and B while (!c.Contains(a)) c = c.Parent; while (!c.Contains(b)) c = c.Parent; return c; } } } } /// /// Smallest cell that contains all input cells. /// public static Cell GetCommonRoot(params Cell[] cells) { if (cells == null || cells.Length == 0) throw new ArgumentException("No cells."); var r = cells[0]; for (var i = 1; i < cells.Length; i++) r = new(r, cells[i]); return r; } #region operators /// /// Makes cell 2^d times smaller. Minimum corner stays at the same position. /// public static Cell operator >>(Cell a, int d) { if (d < 1) return a; if (a.IsCenteredAtOrigin) return new(a.Exponent - d); // right-shift with long argument only uses low-order 6 bits // https://docs.microsoft.com/en-us/dotnet/articles/csharp/language-reference/operators/right-shift-operator if (d > 63) d = 63; return new(a.X << d, a.Y << d, a.Z << d, a.Exponent - d); } /// /// Makes cell 2^d times larger. Minimum corner moves to the origin of the coarse cell containing it. /// public static Cell operator <<(Cell a, int d) { if (d < 1) return a; if (a.IsCenteredAtOrigin) return new(a.Exponent + d); // right-shift with long argument only uses low-order 6 bits // https://docs.microsoft.com/en-us/dotnet/articles/csharp/language-reference/operators/right-shift-operator if (d > 63) d = 63; return new(a.X >> d, a.Y >> d, a.Z >> d, a.Exponent + d); } #endregion #region equality and hashing /// /// public bool Equals(Cell other) => this == other; /// /// public static bool operator ==(Cell a, Cell b) => a.X == b.X && a.Y == b.Y && a.Z == b.Z && a.Exponent == b.Exponent; /// /// public static bool operator !=(Cell a, Cell b) => !(a == b); /// /// public override bool Equals(object obj) => obj is Cell cell && this == cell; /// /// public override int GetHashCode() => HashCode.GetCombined(X, Y, Z, Exponent); #endregion #region string serialization /// public override string ToString() { if (IsCenteredAtOrigin || IsInvalid) { return $"[{Exponent}]"; } else { return $"[{X}, {Y}, {Z}, {Exponent}]"; } } public static Cell Parse(string s) { #if NETSTANDARD2_0 var xs = s.Substring(1, s.Length - 2).Split(','); #else var xs = s[1..^1].Split(','); #endif return xs.Length switch { 1 => new(exponent: int.Parse(xs[0])), 4 => new(x: long.Parse(xs[0]), y: long.Parse(xs[1]), z: long.Parse(xs[2]), exponent: int.Parse(xs[3])), _ => throw new FormatException( $"Expected [,,,], or [], but found {s}. " + $"Error 973f176d-6780-4f77-8736-0ed341adf136." ) }; } #endregion #region binary serialization /// /// public byte[] ToByteArray() { var buffer = new byte[28]; using (var ms = new MemoryStream(buffer)) using (var bw = new BinaryWriter(ms)) { bw.Write(X); bw.Write(Y); bw.Write(Z); bw.Write(Exponent); } return buffer; } /// /// public static Cell Parse(byte[] buffer) { using var ms = new MemoryStream(buffer, 0, 28); using var br = new BinaryReader(ms); var x = br.ReadInt64(); var y = br.ReadInt64(); var z = br.ReadInt64(); var e = br.ReadInt32(); return new(x, y, z, e); } #endregion } ================================================ FILE: src/Aardvark.Base/Math/RangesBoxes/Cell2d.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Runtime.Serialization; using System.Text.Json.Serialization; namespace Aardvark.Base; /// /// An axis-aligned square in a hierarchical spatial grid where all cells have power-of-two sizes. /// Position is (X,Y) * 2^Exponent, size is 2^Exponent. /// [DataContract] public readonly partial struct Cell2d : IEquatable { /// /// Unit cell (0, 0, 0) -> Box2d[(0.0, 0.0), (1.0, 1.0)] /// public static readonly Cell2d Unit = new(0L, 0L, 0); /// /// Special value denoting "invalid cell". /// public static Cell2d Invalid => new(long.MinValue, long.MinValue, int.MinValue); /// /// Grid coordinate at resolution 2^Exponent. /// [DataMember] public readonly long X; /// /// Grid coordinate at resolution 2^Exponent. /// [DataMember] public readonly long Y; /// /// Power of two defining both cell size and grid resolution. /// [DataMember(Name = "E")] public readonly int Exponent; #region constructors /// /// Creates a 2^exponent sized square positioned at (x,y) * 2^exponent. /// public Cell2d(long x, long y, int exponent) { X = x; Y = y; Exponent = exponent; } /// /// Creates a 2^exponent sized square positioned at (x,y) * 2^exponent. /// public Cell2d(int x, int y, int exponent) { X = x; Y = y; Exponent = exponent; } /// /// Creates copy of cell. /// public Cell2d(Cell2d cell) { X = cell.X; Y = cell.Y; Exponent = cell.Exponent; } /// /// Cell with min corner at index*2^exponent and size 2^exponent. /// public Cell2d(V2l index, int exponent) : this(index.X, index.Y, exponent) { } /// /// Cell with min corner at index*2^exponent and size 2^exponent. /// public Cell2d(V2i index, int exponent) : this(index.X, index.Y, exponent) { } /// /// Special cell, which is centered at origin, with size 2^exponent. /// public Cell2d(int exponent) { if (exponent == int.MinValue) { X = long.MinValue; Y = long.MinValue; Exponent = exponent; } else { X = long.MaxValue; Y = long.MaxValue; Exponent = exponent; } } /// /// Smallest cell that contains given box. /// public Cell2d(Box2f box) : this(new Box2d(box)) { } /// /// Smallest cell that contains given points. /// public Cell2d(V2f[] ps) : this(new Box2f(ps)) { } /// /// Smallest cell that contains given points. /// public Cell2d(ReadOnlySpan ps) : this(new Box2f(ps)) { } /// /// Smallest cell that contains given points. /// public Cell2d(V2d[] ps) : this(new Box2d(ps)) { } /// /// Smallest cell that contains given points. /// public Cell2d(ReadOnlySpan ps) : this(new Box2d(ps)) { } /// /// Smallest cell that contains given points. /// public Cell2d(IEnumerable ps) : this(new Box2f(ps)) { } /// /// Smallest cell that contains given points. /// public Cell2d(IEnumerable ps) : this(new Box2d(ps)) { } /// /// Smallest cell containing the given point. /// public Cell2d(V2d p) : this(new Box2d(p)) { } /// /// Smallest cell that contains given box, /// where box.Min and box.Max are both interpreted as inclusive /// (whereas a cell's maximum is defined as exclusive). /// public Cell2d(Box2d box) { if (!box.IsValid) throw new InvalidOperationException(); // case 1: contains origin if (box.Min.X < 0.0 && box.Max.X >= 0.0 || box.Min.Y < 0.0 && box.Max.Y >= 0.0) { X = Y = long.MaxValue; Exponent = Math.Max(box.Min.NormMax, box.Max.NormMax).Log2CeilingInt() + 1; } else // case 2: doesn't contain origin { Exponent = (box.Min == box.Max) ? (box.Min.NormMax / (long.MaxValue >> 1)).Log2CeilingInt() : box.Size.NormMax.Log2CeilingInt() ; var s = Math.Pow(2.0, Exponent); var a = (box.Min * (1.0 / s)).Floor(); X = (long)a.X; Y = (long)a.Y; while (box.Max.X >= X * s + s || box.Max.Y >= Y * s + s) { X >>= 1; Y >>= 1; ++Exponent; s *= 2.0; } } } /// /// Common root of a and b. /// public Cell2d(Cell2d a, Cell2d b) : this(GetCommonRoot(a, b)) { } /// /// Common root of cells. /// public Cell2d(params Cell2d[] cells) : this(GetCommonRoot(cells)) { } #endregion /// /// Grid coordinates as a vector. /// [JsonIgnore] public V2l XY => new(X, Y); /// /// True if special cell centered at the origin. /// [JsonIgnore] public bool IsCenteredAtOrigin => X == long.MaxValue && Y == long.MaxValue; /// /// Returns true if this is the special invalid cell. /// [JsonIgnore] public bool IsInvalid => X == long.MinValue && Y == long.MinValue && Exponent == int.MinValue; /// /// Returns true if this is NOT the special invalid cell. /// [JsonIgnore] public bool IsValid => X != long.MinValue || Y != long.MinValue || Exponent != int.MinValue; /// /// Returns true if the cell completely contains the other cell. /// A cell contains itself. /// public bool Contains(Cell2d other) { if (other.Exponent > Exponent) return false; if (other.Exponent == Exponent) return other.X == X && other.Y == Y; // always true from here on: // Exponent > other.Exponent // other.Exponent < Exponent if (IsCenteredAtOrigin) { if (other.IsCenteredAtOrigin) { return true; } else { // bring other into scale of this var d = (Exponent - 1) - other.Exponent; // right-shift with long argument only uses low-order 6 bits // https://docs.microsoft.com/en-us/dotnet/articles/csharp/language-reference/operators/right-shift-operator if (d > 63) d = 63; var x = other.X >> d; var y = other.Y >> d; return x >= -1 && x <= 0 && y >= -1 && y <= 0; } } else { if (other.IsCenteredAtOrigin) { return false; } else { // bring other into scale of this var d = Exponent - other.Exponent; // right-shift with long argument only uses low-order 6 bits // https://docs.microsoft.com/en-us/dotnet/articles/csharp/language-reference/operators/right-shift-operator if (d > 63) d = 63; var x = other.X >> d; var y = other.Y >> d; return x == X && y == Y; } } } /// /// Returns true if two cells intersect each other (or one contains the other). /// Cells DO NOT intersect if only touching from the outside. /// A cell intersects itself. /// public bool Intersects(Cell2d other) { if (X == other.X && Y == other.Y && Exponent == other.Exponent) return true; return BoundingBox.Intersects(other.BoundingBox); } /// /// Gets the 4 subcells. /// Order is (0,0), (1,0), (0,1), (1,1). /// [JsonIgnore] public Cell2d[] Children { get { var x0 = X << 1; var y0 = Y << 1; if (IsCenteredAtOrigin) { x0++; y0++; } var x1 = x0 + 1; var y1 = y0 + 1; var e = Exponent - 1; return [ new(x0, y0, e), new(x1, y0, e), new(x0, y1, e), new(x1, y1, e), ]; } } /// /// Gets parent cell. /// [JsonIgnore] public Cell2d Parent => IsCenteredAtOrigin ? new(Exponent + 1) : new(X >> 1, Y >> 1, Exponent + 1); /// /// True if any corner of this cell is exactly at the origin. /// [JsonIgnore] public bool TouchesOrigin => !IsCenteredAtOrigin && (X == -1 || X == 0) && (Y == -1 || Y == 0); /// /// Cell's bounds as Box2d. /// [JsonIgnore] public Box2d BoundingBox => ComputeBoundingBox(X, Y, Exponent); private static Box2d ComputeBoundingBox(long x, long y, int e) { var d = Math.Pow(2.0, e); var isCenteredAtOrigin = x == long.MaxValue && y == long.MaxValue; var min = isCenteredAtOrigin ? new V2d(-0.5 * d) : new V2d(x * d, y * d); return Box2d.FromMinAndSize(min, new V2d(d, d)); } /// /// Computes cell's center. /// public V2d GetCenter() => BoundingBox.Center; /// /// Quadrant 0-3. /// 0th and 1st bit encodes x-, y-axis, respectively. /// E.g. 0 is quadrant at origin, 3 is quadrant oposite from origin. /// public Cell2d GetQuadrant(int i) { if (i < 0 || i > 3) throw new IndexOutOfRangeException(); if (IsCenteredAtOrigin) { return new( (i & 1) == 0 ? -1 : 0, (i & 2) == 0 ? -1 : 0, Exponent - 1 ); } else { return new( (X << 1) + ((i & 1) == 0 ? 0 : 1), (Y << 1) + ((i & 2) == 0 ? 0 : 1), Exponent - 1 ); } } /// /// Returns the quadrant of this cell, in which the other cell is contained. /// If the other cell is not contained in any quadrant, then no value is returned. /// public int? GetQuadrant(Cell2d other) { // if other cell is bigger or same size, // then it cannot be contained in any quadrant if (other.Exponent >= Exponent) return null; if (IsCenteredAtOrigin) { if (other.IsCenteredAtOrigin) return null; // scale up other to scale of this cell's quadrants // where coord values 0 or 1 mean left or right, // and all other values mean that the other cell is outside other <<= Exponent - other.Exponent - 1; var o = 0; if (other.X == 0) o = 1; else if (other.X != -1) return null; if (other.Y == 0) o |= 2; else if (other.Y != -1) return null; return o; } else { if (other.IsCenteredAtOrigin) return null; // scale up other to scale of this cell's quadrants, // where coord values -1 or 0 mean left or right, // and all other values mean that the other cell is outside other <<= Exponent - other.Exponent - 1; var x = X << 1; var y = Y << 1; var o = 0; if (other.X == x + 1) o = 1; else if (other.X != x) return null; if (other.Y == y + 1) o |= 2; else if (other.Y != y) return null; return o; } } /// /// Get the global quadtrant this cell is located in, or no value if this is a centered cell. /// public int? Quadrant { get { if (IsCenteredAtOrigin) return null; var o = 0; if (X >= 0) o = 1; if (Y >= 0) o |= 2; return o; } } /// /// Smallest cell that contains both input cells. /// public static Cell2d GetCommonRoot(Cell2d a, Cell2d b) { if (a == b) return a; if (a.IsCenteredAtOrigin) { if (b.IsCenteredAtOrigin) { // if both are centered, then the larger cell is the result return a.Exponent > b.Exponent ? a : b; } else { // if A is centered and B is not centered, // then enlarge A until it contains B while (!a.Contains(b)) a = a.Parent; return a; } } else { if (b.IsCenteredAtOrigin) { // if A is not centered and B is centered, // then enlarge B until it contains A while (!b.Contains(a)) b = b.Parent; return b; } else { // if no cell is centered, ... if (a.Quadrant == b.Quadrant) { // and both cells are located in the same global quadrant, // then recursively grow smaller cell (take parent) // until a and b meet at their common root return a.Exponent > b.Exponent ? GetCommonRoot(a, b.Parent) : GetCommonRoot(a.Parent, b); } else { // and each cell is located in a different global quadrant, // then take a centered cell and enlarge it until it contains both A and B var c = new Cell2d(Math.Max(a.Exponent, b.Exponent) + 1); // centered cell needs to be at least twice as large as the bigger one of A and B while (!c.Contains(a)) c = c.Parent; while (!c.Contains(b)) c = c.Parent; return c; } } } } /// /// Smallest cell that contains all input cells. /// public static Cell2d GetCommonRoot(params Cell2d[] cells) { if (cells == null || cells.Length == 0) throw new ArgumentException("No cells."); var r = cells[0]; for (var i = 1; i < cells.Length; i++) r = new(r, cells[i]); return r; } #region operators /// /// Makes cell 2^d times smaller. Minimum corner stays at the same position. /// public static Cell2d operator >>(Cell2d a, int d) { if (d < 1) return a; if (a.IsCenteredAtOrigin) return new(a.Exponent - d); // right-shift with long argument only uses low-order 6 bits // https://docs.microsoft.com/en-us/dotnet/articles/csharp/language-reference/operators/right-shift-operator if (d > 63) d = 63; return new(a.X << d, a.Y << d, a.Exponent - d); } /// /// Makes cell 2^d times larger. Minimum corner moves to the origin of the coarse cell containing it. /// public static Cell2d operator <<(Cell2d a, int d) { if (d < 1) return a; if (a.IsCenteredAtOrigin) return new(a.Exponent + d); // right-shift with long argument only uses low-order 6 bits // https://docs.microsoft.com/en-us/dotnet/articles/csharp/language-reference/operators/right-shift-operator if (d > 63) d = 63; return new(a.X >> d, a.Y >> d, a.Exponent + d); } #endregion #region equality and hashing /// /// public bool Equals(Cell2d other) => this == other; /// /// public static bool operator ==(Cell2d a, Cell2d b) => a.X == b.X && a.Y == b.Y && a.Exponent == b.Exponent; /// /// public static bool operator !=(Cell2d a, Cell2d b) => !(a == b); /// /// public override bool Equals(object obj) => obj is Cell2d other && this == other; /// /// public override int GetHashCode() => HashCode.GetCombined(X, Y, Exponent); #endregion #region binary serialization /// /// public byte[] ToByteArray() { var buffer = new byte[20]; using var ms = new MemoryStream(buffer); using var bw = new BinaryWriter(ms); bw.Write(X); bw.Write(Y); bw.Write(Exponent); return buffer; } /// /// public static Cell2d Parse(byte[] buffer) { using var ms = new MemoryStream(buffer, 0, 20); using var br = new BinaryReader(ms); var x = br.ReadInt64(); var y = br.ReadInt64(); var e = br.ReadInt32(); return new(x, y, e); } #endregion #region string serialization /// public override string ToString() { if (IsCenteredAtOrigin || IsInvalid) { return $"[{Exponent}]"; } else { return $"[{X}, {Y}, {Exponent}]"; } } public static Cell2d Parse(string s) { #if NETSTANDARD2_0 var xs = s.Substring(1, s.Length - 2).Split(','); #else var xs = s[1..^1].Split(','); #endif return xs.Length switch { 1 => new(exponent: int.Parse(xs[0])), 3 => new(x: long.Parse(xs[0]), y: long.Parse(xs[1]), exponent: int.Parse(xs[2])), _ => throw new FormatException( $"Expected [,,], or [], but found {s}. " + $"Error 47575d6f-072a-4166-ac83-5c4effa33427." ) }; } #endregion } ================================================ FILE: src/Aardvark.Base/Math/RangesBoxes/OrientedBox_auto.cs ================================================ using System.Runtime.Serialization; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region OrientedBox2f [DataContract] public struct OrientedBox2f { [DataMember] public Box2f Box; [DataMember] public Euclidean2f Trafo; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox2f(OrientedBox2d box) { Box = (Box2f)box.Box; Trafo = (Euclidean2f)box.Trafo; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox2f(Box2f box) { Box = box; Trafo = Euclidean2f.Identity; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox2f(Box2f box, Rot2f rot) { Box = box; Trafo = new Euclidean2f(rot, V2f.Zero); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox2f(Box2f box, V2f trans) { Box = box; Trafo = new Euclidean2f(Rot2f.Identity, trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox2f(Box2f box, Rot2f rot, V2f trans) { Box = box; Trafo = new Euclidean2f(rot, trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox2f(Box2f box, Euclidean2f trafo) { Box = box; Trafo = trafo; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator OrientedBox2f(OrientedBox2d b) => new OrientedBox2f(b); #endregion #region Properties public readonly Box2f AxisAlignedBox => Box.Transformed((M33f)Trafo); public readonly V2f[] Corners { get { var m = (M33f)Trafo; return Box.ComputeCorners().Map(p => m.TransformPos(p)); } } public readonly V2f[] CornersCCW { get { var m = (M33f)Trafo; return Box.ComputeCornersCCW().Map(p => m.TransformPos(p)); } } #endregion } #endregion #region OrientedBox3f [DataContract] public struct OrientedBox3f { [DataMember] public Box3f Box; [DataMember] public Euclidean3f Trafo; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox3f(OrientedBox3d box) { Box = (Box3f)box.Box; Trafo = (Euclidean3f)box.Trafo; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox3f(Box3f box) { Box = box; Trafo = Euclidean3f.Identity; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox3f(Box3f box, Rot3f rot) { Box = box; Trafo = new Euclidean3f(rot, V3f.Zero); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox3f(Box3f box, V3f trans) { Box = box; Trafo = new Euclidean3f(Rot3f.Identity, trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox3f(Box3f box, Rot3f rot, V3f trans) { Box = box; Trafo = new Euclidean3f(rot, trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox3f(Box3f box, Euclidean3f trafo) { Box = box; Trafo = trafo; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator OrientedBox3f(OrientedBox3d b) => new OrientedBox3f(b); #endregion #region Properties public readonly Box3f AxisAlignedBox => Box.Transformed((M44f)Trafo); public readonly V3f[] Corners { get { var m = (M44f)Trafo; return Box.ComputeCorners().Map(p => m.TransformPos(p)); } } #endregion } #endregion #region OrientedBox2d [DataContract] public struct OrientedBox2d { [DataMember] public Box2d Box; [DataMember] public Euclidean2d Trafo; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox2d(OrientedBox2f box) { Box = (Box2d)box.Box; Trafo = (Euclidean2d)box.Trafo; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox2d(Box2d box) { Box = box; Trafo = Euclidean2d.Identity; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox2d(Box2d box, Rot2d rot) { Box = box; Trafo = new Euclidean2d(rot, V2d.Zero); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox2d(Box2d box, V2d trans) { Box = box; Trafo = new Euclidean2d(Rot2d.Identity, trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox2d(Box2d box, Rot2d rot, V2d trans) { Box = box; Trafo = new Euclidean2d(rot, trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox2d(Box2d box, Euclidean2d trafo) { Box = box; Trafo = trafo; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator OrientedBox2d(OrientedBox2f b) => new OrientedBox2d(b); #endregion #region Properties public readonly Box2d AxisAlignedBox => Box.Transformed((M33d)Trafo); public readonly V2d[] Corners { get { var m = (M33d)Trafo; return Box.ComputeCorners().Map(p => m.TransformPos(p)); } } public readonly V2d[] CornersCCW { get { var m = (M33d)Trafo; return Box.ComputeCornersCCW().Map(p => m.TransformPos(p)); } } #endregion } #endregion #region OrientedBox3d [DataContract] public struct OrientedBox3d { [DataMember] public Box3d Box; [DataMember] public Euclidean3d Trafo; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox3d(OrientedBox3f box) { Box = (Box3d)box.Box; Trafo = (Euclidean3d)box.Trafo; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox3d(Box3d box) { Box = box; Trafo = Euclidean3d.Identity; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox3d(Box3d box, Rot3d rot) { Box = box; Trafo = new Euclidean3d(rot, V3d.Zero); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox3d(Box3d box, V3d trans) { Box = box; Trafo = new Euclidean3d(Rot3d.Identity, trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox3d(Box3d box, Rot3d rot, V3d trans) { Box = box; Trafo = new Euclidean3d(rot, trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OrientedBox3d(Box3d box, Euclidean3d trafo) { Box = box; Trafo = trafo; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator OrientedBox3d(OrientedBox3f b) => new OrientedBox3d(b); #endregion #region Properties public readonly Box3d AxisAlignedBox => Box.Transformed((M44d)Trafo); public readonly V3d[] Corners { get { var m = (M44d)Trafo; return Box.ComputeCorners().Map(p => m.TransformPos(p)); } } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/RangesBoxes/OrientedBox_template.cs ================================================ using System.Runtime.Serialization; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# foreach (var isDouble in new[] { false, true }) { //# for (int n = 2; n <= 3; n++) { //# var m = n + 1; //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "OrientedBox" + n + tc; //# var type2 = "OrientedBox"+ n + tc2; //# var vnt = "V" + n + tc; //# var boxnt = "Box" + n + tc; //# var rotnt = "Rot" + n + tc; //# var euclideannt = "Euclidean" + n + tc; //# var mmmt = "M" + m + m + tc; #region __type__ [DataContract] public struct __type__ { [DataMember] public __boxnt__ Box; [DataMember] public __euclideannt__ Trafo; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ box) { Box = (__boxnt__)box.Box; Trafo = (__euclideannt__)box.Trafo; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__boxnt__ box) { Box = box; Trafo = __euclideannt__.Identity; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__boxnt__ box, __rotnt__ rot) { Box = box; Trafo = new __euclideannt__(rot, __vnt__.Zero); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__boxnt__ box, __vnt__ trans) { Box = box; Trafo = new __euclideannt__(__rotnt__.Identity, trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__boxnt__ box, __rotnt__ rot, __vnt__ trans) { Box = box; Trafo = new __euclideannt__(rot, trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__boxnt__ box, __euclideannt__ trafo) { Box = box; Trafo = trafo; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type__(__type2__ b) => new __type__(b); #endregion #region Properties public readonly __boxnt__ AxisAlignedBox => Box.Transformed((__mmmt__)Trafo); public readonly __vnt__[] Corners { get { var m = (__mmmt__)Trafo; return Box.ComputeCorners().Map(p => m.TransformPos(p)); } } //# if (n == 2) { public readonly __vnt__[] CornersCCW { get { var m = (__mmmt__)Trafo; return Box.ComputeCornersCCW().Map(p => m.TransformPos(p)); } } //# } #endregion } #endregion //# } } } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Affine_auto.cs ================================================ using System; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTOGENERATED CODE - DO NOT CHANGE! #region Affine2f /// /// Struct to represent an affine transformation in 2-dimensional space. It consists of /// a linear tranformation (invertible 2x2 matrix) and a translational component (2d vector). /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Affine2f : IEquatable, IValidity { [DataMember] public M22f Linear; [DataMember] public V2f Trans; #region Constructors /// /// Constructs a copy of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine2f(Affine2f affine) { Linear = affine.Linear; Trans = affine.Trans; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine2f(Affine2d affine) { Linear = (M22f)affine.Linear; Trans = (V2f)affine.Trans; } /// /// Constructs an affine transformation from a linear map and a translation. /// The matrix must be invertible. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine2f(M22f linear, V2f translation) { Debug.Assert(linear.Invertible); Linear = linear; Trans = translation; } /// /// Constructs an affine transformation from a linear map and a translation. /// The matrix must be invertible. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine2f(M22f linear, float tX, float tY) { Debug.Assert(linear.Invertible); Linear = linear; Trans = new V2f(tX, tY); } /// /// Constructs an affine transformation from a linear map. /// The matrix must be invertible. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine2f(M22f linear) { Debug.Assert(linear.Invertible); Linear = linear; Trans = V2f.Zero; } #endregion #region Constants /// /// Gets the identity transformation. /// public static Affine2f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Affine2f(M22f.Identity); } #endregion #region Properties /// /// Gets if this affine transformation is valid, i.e. if the linear map is invertible. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Linear.Invertible; } /// /// Gets if this affine transformation is invalid, i.e. if the linear map is singular. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !IsValid; } /// /// Gets the inverse of this affine transformation. /// public readonly Affine2f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var rs = new Affine2f(this); rs.Invert(); return rs; } } #endregion #region Arithmetic Operators /// /// Multiplies two affine transformations. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Affine2f a, Affine2f b) { return new Affine2f(a.Linear * b.Linear, a.Linear * b.Trans + a.Trans); } /// /// Transforms a vector by an affine transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator *(Affine2f a, V3f v) { return new V3f( a.Linear.M00 * v.X + a.Linear.M01 * v.Y + a.Trans.X * v.Z, a.Linear.M10 * v.X + a.Linear.M11 * v.Y + a.Trans.Y * v.Z, v.Z); } /// /// Multiplies a (as a 3x3 matrix) and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator *(Affine2f a, M33f m) { return new M33f( a.Linear.M00 * m.M00 + a.Linear.M01 * m.M10 + a.Trans.X * m.M20, a.Linear.M00 * m.M01 + a.Linear.M01 * m.M11 + a.Trans.X * m.M21, a.Linear.M00 * m.M02 + a.Linear.M01 * m.M12 + a.Trans.X * m.M22, a.Linear.M10 * m.M00 + a.Linear.M11 * m.M10 + a.Trans.Y * m.M20, a.Linear.M10 * m.M01 + a.Linear.M11 * m.M11 + a.Trans.Y * m.M21, a.Linear.M10 * m.M02 + a.Linear.M11 * m.M12 + a.Trans.Y * m.M22, m.M20, m.M21, m.M22); } /// /// Multiplies a and a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator *(M33f m, Affine2f a) { return new M33f( m.M00 * a.Linear.M00 + m.M01 * a.Linear.M10, m.M00 * a.Linear.M01 + m.M01 * a.Linear.M11, m.M00 * a.Trans.X + m.M01 * a.Trans.Y + m.M02, m.M10 * a.Linear.M00 + m.M11 * a.Linear.M10, m.M10 * a.Linear.M01 + m.M11 * a.Linear.M11, m.M10 * a.Trans.X + m.M11 * a.Trans.Y + m.M12, m.M20 * a.Linear.M00 + m.M21 * a.Linear.M10, m.M20 * a.Linear.M01 + m.M21 * a.Linear.M11, m.M20 * a.Trans.X + m.M21 * a.Trans.Y + m.M22); } /// /// Multiplies a (as a 2x3 matrix) and a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(Affine2f a, M22f m) => new M23f(a.Linear * m, a.Trans); /// /// Multiplies a and a (as a 2x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(M22f m, Affine2f a) => new M23f(m * a.Linear, m * a.Trans); /// /// Multiplies a (as a 2x3 matrix) and a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(Affine2f a, M23f m) { return new M23f( a.Linear.M00 * m.M00 + a.Linear.M01 * m.M10, a.Linear.M00 * m.M01 + a.Linear.M01 * m.M11, a.Trans.X + a.Linear.M00 * m.M02 + a.Linear.M01 * m.M12, a.Linear.M10 * m.M00 + a.Linear.M11 * m.M10, a.Linear.M10 * m.M01 + a.Linear.M11 * m.M11, a.Trans.Y + a.Linear.M10 * m.M02 + a.Linear.M11 * m.M12); } /// /// Multiplies a and a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(M23f m, Affine2f a) { return new M23f( m.M00 * a.Linear.M00 + m.M01 * a.Linear.M10, m.M00 * a.Linear.M01 + m.M01 * a.Linear.M11, m.M00 * a.Trans.X + m.M01 * a.Trans.Y + m.M02, m.M10 * a.Linear.M00 + m.M11 * a.Linear.M10, m.M10 * a.Linear.M01 + m.M11 * a.Linear.M11, m.M10 * a.Trans.X + m.M11 * a.Trans.Y + m.M12); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Affine2f a, Euclidean2f e) => a * (Affine2f)e; /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Euclidean2f e, Affine2f a) => (Affine2f)e * a; /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Affine2f a, Rot2f r) => new Affine2f(a.Linear * r, a.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Rot2f r, Affine2f a) => new Affine2f(r * a.Linear, r * a.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Affine2f a, Scale2f s) { return new Affine2f(new M22f( a.Linear.M00 * s.X, a.Linear.M01 * s.Y, a.Linear.M10 * s.X, a.Linear.M11 * s.Y), a.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Scale2f s, Affine2f a) { return new Affine2f(new M22f( a.Linear.M00 * s.X, a.Linear.M01 * s.X, a.Linear.M10 * s.Y, a.Linear.M11 * s.Y), a.Trans * s.V); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Affine2f a, Shift2f s) { return new Affine2f(a.Linear, a.Linear * s.V + a.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Shift2f s, Affine2f a) { return new Affine2f(a.Linear, a.Trans + s.V); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Affine2f a, Similarity2f s) => a * (Affine2f)s; /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Similarity2f s, Affine2f a) => (Affine2f)s * a; #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Affine2f a0, Affine2f a1) => (a0.Linear == a1.Linear) && (a0.Trans == a1.Trans); /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Affine2f a0, Affine2f a1) => (a0.Linear != a1.Linear) || (a0.Trans != a1.Trans); #endregion #region Static Creators /// /// Creates an affine transformation from a 2x3 matrix. /// The left 2x2 submatrix of must be invertible. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f FromM23f(M23f matrix, float epsilon = 1e-5f) { var linear = (M22f)matrix; var trans = new V2f(matrix.M02, matrix.M12); if (linear.Determinant.IsTiny(epsilon)) throw new ArgumentException("Matrix must be invertible"); return new Affine2f(linear, trans); } /// /// Creates an affine transformation from a 3x3 matrix. /// The matrix has to be homogeneous and must not contain perspective components and its upper left 2x2 submatrix must be invertible. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f FromM33f(M33f m, float epsilon = 1e-5f) { if (!(m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (m.M22.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); var linear = ((M22f)m) / m.M22; var trans = new V2f(m.M02, m.M12) / m.M22; if (linear.Determinant.IsTiny(epsilon)) throw new ArgumentException("Matrix must be invertible"); return new Affine2f(linear, trans); } /// /// Creates an affine transformation from a . /// The transformation must represent a valid affine transformation (e.g. it does not contain perspective components). /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f FromTrafo2f(Trafo2f trafo, float epsilon = 1e-5f) => FromM33f(trafo.Forward, epsilon); #region Translation /// /// Creates an transformation with the translational component given by 2 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f Translation(float tX, float tY) => new Affine2f(M22f.Identity, tX, tY); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f Translation(V2f vector) => new Affine2f(M22f.Identity, vector); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f Translation(Shift2f shift) => new Affine2f(M22f.Identity, shift.V); #endregion #region Scale /// /// Creates a scaling transformation using a uniform scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f Scale(float scaleFactor) => new Affine2f(M22f.Scale(scaleFactor, scaleFactor)); /// /// Creates a scaling transformation using 2 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f Scale(float sX, float sY) => new Affine2f(M22f.Scale(sX, sY)); /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f Scale(V2f scaleFactors) => new Affine2f(M22f.Scale(scaleFactors)); /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f Scale(Scale2f scale) => new Affine2f(M22f.Scale(scale)); #endregion #region Rotation /// /// Creates a rotation transformation from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f Rotation(Rot2f rot) => new Affine2f(M22f.Rotation(rot)); /// /// Creates a rotation transformation with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f Rotation(float angleInRadians) => new Affine2f(M22f.Rotation(angleInRadians)); /// /// Creates a rotation transformation with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f RotationInDegrees(float angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); #endregion #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M23f(Affine2f a) => new M23f(a.Linear, a.Trans); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M22f(Affine2f a) => a.Linear; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33f(Affine2f a) => new M33f((M23f)a); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo2f(Affine2f a) { Debug.Assert(a.Linear.Invertible); var t = (M33f)a; return new Trafo2f(t, t.Inverse); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine2d(Affine2f a) => new Affine2d((M22d)a.Linear, (V2d)a.Trans); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Linear, Trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Affine2f other) => Linear.Equals(other.Linear) && Trans.Equals(other.Trans); public override readonly bool Equals(object other) => (other is Affine2f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Linear, Trans); } public static Affine2f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Affine2f(M22f.Parse(x[0]), V2f.Parse(x[1])); } #endregion } public static partial class Affine { #region Invert /// /// Returns the inverse of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f Inverse(Affine2f a) => a.Inverse; /// /// Inverts the given affine transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Affine2f a) { Debug.Assert(a.Linear.Invertible); a.Linear.Invert(); a.Trans = -a.Linear * a.Trans; } #endregion #region Transformations /// /// Transforms a by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Transform(this Affine2f a, V3f v) => a * v; /// /// Transforms a position vector (v.Z is presumed 1) by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f TransformPos(this Affine2f a, V2f v) { return new V2f( a.Linear.M00 * v.X + a.Linear.M01 * v.Y + a.Trans.X, a.Linear.M10 * v.X + a.Linear.M11 * v.Y + a.Trans.Y); } /// /// Transforms a direction vector (v.Z is presumed 0) by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f TransformDir(this Affine2f a, V2f v) { return new V2f( a.Linear.M00 * v.X + a.Linear.M01 * v.Y, a.Linear.M10 * v.X + a.Linear.M11 * v.Y); } /// /// Transforms a by the transpose of an (as a 3x3 matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransposedTransform(this Affine2f a, V3f v) { return new V3f( v.X * a.Linear.M00 + v.Y * a.Linear.M10, v.X * a.Linear.M01 + v.Y * a.Linear.M11, v.X * a.Trans.X + v.Y * a.Trans.Y + v.Z); } /// /// Transforms a by the transpose of an (as a 3x3 matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f TransposedTransform(this Affine2f a, V2f v) { return new V2f( v.X * a.Linear.M00 + v.Y * a.Linear.M10, v.X * a.Linear.M01 + v.Y * a.Linear.M11); } /// /// Transforms a position vector (v.Z is presumed 1) by the transpose of an (as a 3x3 matrix). /// Projective transform is performed. Perspective Division is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f TransposedTransformPosProj(this Affine2f a, V2f v) { var s = v.X * a.Trans.X + v.Y * a.Trans.Y + 1; return TransposedTransform(a, v) * (1 / s); } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Affine2f a0, Affine2f a1) { return ApproximateEquals(a0, a1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Affine2f a0, Affine2f a1, float tolerance) { return ApproximateEquals(a0.Linear, a1.Linear, tolerance) && ApproximateEquals(a0.Trans, a1.Trans, tolerance); } #endregion } #endregion #region Affine3f /// /// Struct to represent an affine transformation in 3-dimensional space. It consists of /// a linear tranformation (invertible 3x3 matrix) and a translational component (3d vector). /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Affine3f : IEquatable, IValidity { [DataMember] public M33f Linear; [DataMember] public V3f Trans; #region Constructors /// /// Constructs a copy of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine3f(Affine3f affine) { Linear = affine.Linear; Trans = affine.Trans; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine3f(Affine3d affine) { Linear = (M33f)affine.Linear; Trans = (V3f)affine.Trans; } /// /// Constructs an affine transformation from a linear map and a translation. /// The matrix must be invertible. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine3f(M33f linear, V3f translation) { Debug.Assert(linear.Invertible); Linear = linear; Trans = translation; } /// /// Constructs an affine transformation from a linear map and a translation. /// The matrix must be invertible. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine3f(M33f linear, float tX, float tY, float tZ) { Debug.Assert(linear.Invertible); Linear = linear; Trans = new V3f(tX, tY, tZ); } /// /// Constructs an affine transformation from a linear map. /// The matrix must be invertible. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine3f(M33f linear) { Debug.Assert(linear.Invertible); Linear = linear; Trans = V3f.Zero; } #endregion #region Constants /// /// Gets the identity transformation. /// public static Affine3f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Affine3f(M33f.Identity); } #endregion #region Properties /// /// Gets if this affine transformation is valid, i.e. if the linear map is invertible. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Linear.Invertible; } /// /// Gets if this affine transformation is invalid, i.e. if the linear map is singular. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !IsValid; } /// /// Gets the inverse of this affine transformation. /// public readonly Affine3f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var rs = new Affine3f(this); rs.Invert(); return rs; } } #endregion #region Arithmetic Operators /// /// Multiplies two affine transformations. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Affine3f a, Affine3f b) { return new Affine3f(a.Linear * b.Linear, a.Linear * b.Trans + a.Trans); } /// /// Transforms a vector by an affine transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator *(Affine3f a, V4f v) { return new V4f( a.Linear.M00 * v.X + a.Linear.M01 * v.Y + a.Linear.M02 * v.Z + a.Trans.X * v.W, a.Linear.M10 * v.X + a.Linear.M11 * v.Y + a.Linear.M12 * v.Z + a.Trans.Y * v.W, a.Linear.M20 * v.X + a.Linear.M21 * v.Y + a.Linear.M22 * v.Z + a.Trans.Z * v.W, v.W); } /// /// Multiplies a (as a 4x4 matrix) and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator *(Affine3f a, M44f m) { return new M44f( a.Linear.M00 * m.M00 + a.Linear.M01 * m.M10 + a.Linear.M02 * m.M20 + a.Trans.X * m.M30, a.Linear.M00 * m.M01 + a.Linear.M01 * m.M11 + a.Linear.M02 * m.M21 + a.Trans.X * m.M31, a.Linear.M00 * m.M02 + a.Linear.M01 * m.M12 + a.Linear.M02 * m.M22 + a.Trans.X * m.M32, a.Linear.M00 * m.M03 + a.Linear.M01 * m.M13 + a.Linear.M02 * m.M23 + a.Trans.X * m.M33, a.Linear.M10 * m.M00 + a.Linear.M11 * m.M10 + a.Linear.M12 * m.M20 + a.Trans.Y * m.M30, a.Linear.M10 * m.M01 + a.Linear.M11 * m.M11 + a.Linear.M12 * m.M21 + a.Trans.Y * m.M31, a.Linear.M10 * m.M02 + a.Linear.M11 * m.M12 + a.Linear.M12 * m.M22 + a.Trans.Y * m.M32, a.Linear.M10 * m.M03 + a.Linear.M11 * m.M13 + a.Linear.M12 * m.M23 + a.Trans.Y * m.M33, a.Linear.M20 * m.M00 + a.Linear.M21 * m.M10 + a.Linear.M22 * m.M20 + a.Trans.Z * m.M30, a.Linear.M20 * m.M01 + a.Linear.M21 * m.M11 + a.Linear.M22 * m.M21 + a.Trans.Z * m.M31, a.Linear.M20 * m.M02 + a.Linear.M21 * m.M12 + a.Linear.M22 * m.M22 + a.Trans.Z * m.M32, a.Linear.M20 * m.M03 + a.Linear.M21 * m.M13 + a.Linear.M22 * m.M23 + a.Trans.Z * m.M33, m.M30, m.M31, m.M32, m.M33); } /// /// Multiplies a and a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator *(M44f m, Affine3f a) { return new M44f( m.M00 * a.Linear.M00 + m.M01 * a.Linear.M10 + m.M02 * a.Linear.M20, m.M00 * a.Linear.M01 + m.M01 * a.Linear.M11 + m.M02 * a.Linear.M21, m.M00 * a.Linear.M02 + m.M01 * a.Linear.M12 + m.M02 * a.Linear.M22, m.M00 * a.Trans.X + m.M01 * a.Trans.Y + m.M02 * a.Trans.Z + m.M03, m.M10 * a.Linear.M00 + m.M11 * a.Linear.M10 + m.M12 * a.Linear.M20, m.M10 * a.Linear.M01 + m.M11 * a.Linear.M11 + m.M12 * a.Linear.M21, m.M10 * a.Linear.M02 + m.M11 * a.Linear.M12 + m.M12 * a.Linear.M22, m.M10 * a.Trans.X + m.M11 * a.Trans.Y + m.M12 * a.Trans.Z + m.M13, m.M20 * a.Linear.M00 + m.M21 * a.Linear.M10 + m.M22 * a.Linear.M20, m.M20 * a.Linear.M01 + m.M21 * a.Linear.M11 + m.M22 * a.Linear.M21, m.M20 * a.Linear.M02 + m.M21 * a.Linear.M12 + m.M22 * a.Linear.M22, m.M20 * a.Trans.X + m.M21 * a.Trans.Y + m.M22 * a.Trans.Z + m.M23, m.M30 * a.Linear.M00 + m.M31 * a.Linear.M10 + m.M32 * a.Linear.M20, m.M30 * a.Linear.M01 + m.M31 * a.Linear.M11 + m.M32 * a.Linear.M21, m.M30 * a.Linear.M02 + m.M31 * a.Linear.M12 + m.M32 * a.Linear.M22, m.M30 * a.Trans.X + m.M31 * a.Trans.Y + m.M32 * a.Trans.Z + m.M33); } /// /// Multiplies a (as a 3x4 matrix) and a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(Affine3f a, M33f m) => new M34f(a.Linear * m, a.Trans); /// /// Multiplies a and a (as a 3x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(M33f m, Affine3f a) => new M34f(m * a.Linear, m * a.Trans); /// /// Multiplies a (as a 3x4 matrix) and a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(Affine3f a, M34f m) { return new M34f( a.Linear.M00 * m.M00 + a.Linear.M01 * m.M10 + a.Linear.M02 * m.M20, a.Linear.M00 * m.M01 + a.Linear.M01 * m.M11 + a.Linear.M02 * m.M21, a.Linear.M00 * m.M02 + a.Linear.M01 * m.M12 + a.Linear.M02 * m.M22, a.Trans.X + a.Linear.M00 * m.M03 + a.Linear.M01 * m.M13 + a.Linear.M02 * m.M23, a.Linear.M10 * m.M00 + a.Linear.M11 * m.M10 + a.Linear.M12 * m.M20, a.Linear.M10 * m.M01 + a.Linear.M11 * m.M11 + a.Linear.M12 * m.M21, a.Linear.M10 * m.M02 + a.Linear.M11 * m.M12 + a.Linear.M12 * m.M22, a.Trans.Y + a.Linear.M10 * m.M03 + a.Linear.M11 * m.M13 + a.Linear.M12 * m.M23, a.Linear.M20 * m.M00 + a.Linear.M21 * m.M10 + a.Linear.M22 * m.M20, a.Linear.M20 * m.M01 + a.Linear.M21 * m.M11 + a.Linear.M22 * m.M21, a.Linear.M20 * m.M02 + a.Linear.M21 * m.M12 + a.Linear.M22 * m.M22, a.Trans.Z + a.Linear.M20 * m.M03 + a.Linear.M21 * m.M13 + a.Linear.M22 * m.M23); } /// /// Multiplies a and a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(M34f m, Affine3f a) { return new M34f( m.M00 * a.Linear.M00 + m.M01 * a.Linear.M10 + m.M02 * a.Linear.M20, m.M00 * a.Linear.M01 + m.M01 * a.Linear.M11 + m.M02 * a.Linear.M21, m.M00 * a.Linear.M02 + m.M01 * a.Linear.M12 + m.M02 * a.Linear.M22, m.M00 * a.Trans.X + m.M01 * a.Trans.Y + m.M02 * a.Trans.Z + m.M03, m.M10 * a.Linear.M00 + m.M11 * a.Linear.M10 + m.M12 * a.Linear.M20, m.M10 * a.Linear.M01 + m.M11 * a.Linear.M11 + m.M12 * a.Linear.M21, m.M10 * a.Linear.M02 + m.M11 * a.Linear.M12 + m.M12 * a.Linear.M22, m.M10 * a.Trans.X + m.M11 * a.Trans.Y + m.M12 * a.Trans.Z + m.M13, m.M20 * a.Linear.M00 + m.M21 * a.Linear.M10 + m.M22 * a.Linear.M20, m.M20 * a.Linear.M01 + m.M21 * a.Linear.M11 + m.M22 * a.Linear.M21, m.M20 * a.Linear.M02 + m.M21 * a.Linear.M12 + m.M22 * a.Linear.M22, m.M20 * a.Trans.X + m.M21 * a.Trans.Y + m.M22 * a.Trans.Z + m.M23); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Affine3f a, Euclidean3f e) => a * (Affine3f)e; /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Euclidean3f e, Affine3f a) => (Affine3f)e * a; /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Affine3f a, Rot3f r) => new Affine3f(a.Linear * r, a.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Rot3f r, Affine3f a) => new Affine3f(r * a.Linear, r * a.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Affine3f a, Scale3f s) { return new Affine3f(new M33f( a.Linear.M00 * s.X, a.Linear.M01 * s.Y, a.Linear.M02 * s.Z, a.Linear.M10 * s.X, a.Linear.M11 * s.Y, a.Linear.M12 * s.Z, a.Linear.M20 * s.X, a.Linear.M21 * s.Y, a.Linear.M22 * s.Z), a.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Scale3f s, Affine3f a) { return new Affine3f(new M33f( a.Linear.M00 * s.X, a.Linear.M01 * s.X, a.Linear.M02 * s.X, a.Linear.M10 * s.Y, a.Linear.M11 * s.Y, a.Linear.M12 * s.Y, a.Linear.M20 * s.Z, a.Linear.M21 * s.Z, a.Linear.M22 * s.Z), a.Trans * s.V); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Affine3f a, Shift3f s) { return new Affine3f(a.Linear, a.Linear * s.V + a.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Shift3f s, Affine3f a) { return new Affine3f(a.Linear, a.Trans + s.V); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Affine3f a, Similarity3f s) => a * (Affine3f)s; /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Similarity3f s, Affine3f a) => (Affine3f)s * a; #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Affine3f a0, Affine3f a1) => (a0.Linear == a1.Linear) && (a0.Trans == a1.Trans); /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Affine3f a0, Affine3f a1) => (a0.Linear != a1.Linear) || (a0.Trans != a1.Trans); #endregion #region Static Creators /// /// Creates an affine transformation from a 3x4 matrix. /// The left 3x3 submatrix of must be invertible. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f FromM34f(M34f matrix, float epsilon = 1e-5f) { var linear = (M33f)matrix; var trans = new V3f(matrix.M03, matrix.M13, matrix.M23); if (linear.Determinant.IsTiny(epsilon)) throw new ArgumentException("Matrix must be invertible"); return new Affine3f(linear, trans); } /// /// Creates an affine transformation from a 4x4 matrix. /// The matrix has to be homogeneous and must not contain perspective components and its upper left 3x3 submatrix must be invertible. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f FromM44f(M44f m, float epsilon = 1e-5f) { if (!(m.M30.IsTiny(epsilon) && m.M31.IsTiny(epsilon) && m.M32.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (m.M33.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); var linear = ((M33f)m) / m.M33; var trans = new V3f(m.M03, m.M13, m.M23) / m.M33; if (linear.Determinant.IsTiny(epsilon)) throw new ArgumentException("Matrix must be invertible"); return new Affine3f(linear, trans); } /// /// Creates an affine transformation from a . /// The transformation must represent a valid affine transformation (e.g. it does not contain perspective components). /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f FromTrafo3f(Trafo3f trafo, float epsilon = 1e-5f) => FromM44f(trafo.Forward, epsilon); #region Translation /// /// Creates an transformation with the translational component given by 3 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f Translation(float tX, float tY, float tZ) => new Affine3f(M33f.Identity, tX, tY, tZ); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f Translation(V3f vector) => new Affine3f(M33f.Identity, vector); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f Translation(Shift3f shift) => new Affine3f(M33f.Identity, shift.V); #endregion #region Scale /// /// Creates a scaling transformation using a uniform scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f Scale(float scaleFactor) => new Affine3f(M33f.Scale(scaleFactor, scaleFactor, scaleFactor)); /// /// Creates a scaling transformation using 3 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f Scale(float sX, float sY, float sZ) => new Affine3f(M33f.Scale(sX, sY, sZ)); /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f Scale(V3f scaleFactors) => new Affine3f(M33f.Scale(scaleFactors)); /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f Scale(Scale3f scale) => new Affine3f(M33f.Scale(scale)); #endregion #region Rotation /// /// Creates a rotation transformation from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f Rotation(Rot3f rot) => new Affine3f(M33f.Rotation(rot)); /// /// Creates a rotation transformation from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f Rotation(V3f normalizedAxis, float angleRadians) => new Affine3f(M33f.Rotation(normalizedAxis, angleRadians)); /// /// Creates a rotation transformation from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f RotationInDegrees(V3f normalizedAxis, float angleDegrees) => Rotation(normalizedAxis, angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f RotationEuler(float rollInRadians, float pitchInRadians, float yawInRadians) => new Affine3f(M33f.RotationEuler(rollInRadians, pitchInRadians, yawInRadians)); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f RotationEulerInDegrees(float rollInDegrees, float pitchInDegrees, float yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f RotationEuler(V3f rollPitchYawInRadians) => RotationEuler(rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f RotationEulerInDegrees(V3f rollPitchYawInDegrees) => RotationEulerInDegrees( rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a rotation transformation which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f RotateInto(V3f from, V3f into) => new Affine3f(M33f.RotateInto(from, into)); /// /// Creates a rotation transformation by radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f RotationX(float angleRadians) => new Affine3f(M33f.RotationX(angleRadians)); /// /// Creates a rotation transformation for degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f RotationXInDegrees(float angleDegrees) => RotationX(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f RotationY(float angleRadians) => new Affine3f(M33f.RotationY(angleRadians)); /// /// Creates a rotation transformation for degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f RotationYInDegrees(float angleDegrees) => RotationY(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f RotationZ(float angleRadians) => new Affine3f(M33f.RotationZ(angleRadians)); /// /// Creates a rotation transformation for degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f RotationZInDegrees(float angleDegrees) => RotationZ(angleDegrees.RadiansFromDegrees()); #endregion #region Shear /// /// Creates a shear transformation along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f ShearXY(float factorX, float factorY) => new Affine3f(M33f.ShearXY(factorX, factorY)); /// /// Creates a shear transformation along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f ShearXZ(float factorX, float factorZ) => new Affine3f(M33f.ShearXZ(factorX, factorZ)); /// /// Creates a shear transformation along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f ShearYZ(float factorY, float factorZ) => new Affine3f(M33f.ShearYZ(factorY, factorZ)); #endregion #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34f(Affine3f a) => new M34f(a.Linear, a.Trans); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33f(Affine3f a) => a.Linear; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44f(Affine3f a) => new M44f((M34f)a); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo3f(Affine3f a) { Debug.Assert(a.Linear.Invertible); var t = (M44f)a; return new Trafo3f(t, t.Inverse); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine3d(Affine3f a) => new Affine3d((M33d)a.Linear, (V3d)a.Trans); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Linear, Trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Affine3f other) => Linear.Equals(other.Linear) && Trans.Equals(other.Trans); public override readonly bool Equals(object other) => (other is Affine3f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Linear, Trans); } public static Affine3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Affine3f(M33f.Parse(x[0]), V3f.Parse(x[1])); } #endregion } public static partial class Affine { #region Invert /// /// Returns the inverse of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f Inverse(Affine3f a) => a.Inverse; /// /// Inverts the given affine transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Affine3f a) { Debug.Assert(a.Linear.Invertible); a.Linear.Invert(); a.Trans = -a.Linear * a.Trans; } #endregion #region Transformations /// /// Transforms a by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Transform(this Affine3f a, V4f v) => a * v; /// /// Transforms a position vector (v.W is presumed 1) by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransformPos(this Affine3f a, V3f v) { return new V3f( a.Linear.M00 * v.X + a.Linear.M01 * v.Y + a.Linear.M02 * v.Z + a.Trans.X, a.Linear.M10 * v.X + a.Linear.M11 * v.Y + a.Linear.M12 * v.Z + a.Trans.Y, a.Linear.M20 * v.X + a.Linear.M21 * v.Y + a.Linear.M22 * v.Z + a.Trans.Z); } /// /// Transforms a direction vector (v.W is presumed 0) by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransformDir(this Affine3f a, V3f v) { return new V3f( a.Linear.M00 * v.X + a.Linear.M01 * v.Y + a.Linear.M02 * v.Z, a.Linear.M10 * v.X + a.Linear.M11 * v.Y + a.Linear.M12 * v.Z, a.Linear.M20 * v.X + a.Linear.M21 * v.Y + a.Linear.M22 * v.Z); } /// /// Transforms a by the transpose of an (as a 4x4 matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f TransposedTransform(this Affine3f a, V4f v) { return new V4f( v.X * a.Linear.M00 + v.Y * a.Linear.M10 + v.Z * a.Linear.M20, v.X * a.Linear.M01 + v.Y * a.Linear.M11 + v.Z * a.Linear.M21, v.X * a.Linear.M02 + v.Y * a.Linear.M12 + v.Z * a.Linear.M22, v.X * a.Trans.X + v.Y * a.Trans.Y + v.Z * a.Trans.Z + v.W); } /// /// Transforms a by the transpose of an (as a 4x4 matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransposedTransform(this Affine3f a, V3f v) { return new V3f( v.X * a.Linear.M00 + v.Y * a.Linear.M10 + v.Z * a.Linear.M20, v.X * a.Linear.M01 + v.Y * a.Linear.M11 + v.Z * a.Linear.M21, v.X * a.Linear.M02 + v.Y * a.Linear.M12 + v.Z * a.Linear.M22); } /// /// Transforms a position vector (v.W is presumed 1) by the transpose of an (as a 4x4 matrix). /// Projective transform is performed. Perspective Division is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransposedTransformPosProj(this Affine3f a, V3f v) { var s = v.X * a.Trans.X + v.Y * a.Trans.Y + v.Z * a.Trans.Z + 1; return TransposedTransform(a, v) * (1 / s); } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Affine3f a0, Affine3f a1) { return ApproximateEquals(a0, a1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Affine3f a0, Affine3f a1, float tolerance) { return ApproximateEquals(a0.Linear, a1.Linear, tolerance) && ApproximateEquals(a0.Trans, a1.Trans, tolerance); } #endregion } #endregion #region Affine2d /// /// Struct to represent an affine transformation in 2-dimensional space. It consists of /// a linear tranformation (invertible 2x2 matrix) and a translational component (2d vector). /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Affine2d : IEquatable, IValidity { [DataMember] public M22d Linear; [DataMember] public V2d Trans; #region Constructors /// /// Constructs a copy of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine2d(Affine2d affine) { Linear = affine.Linear; Trans = affine.Trans; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine2d(Affine2f affine) { Linear = (M22d)affine.Linear; Trans = (V2d)affine.Trans; } /// /// Constructs an affine transformation from a linear map and a translation. /// The matrix must be invertible. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine2d(M22d linear, V2d translation) { Debug.Assert(linear.Invertible); Linear = linear; Trans = translation; } /// /// Constructs an affine transformation from a linear map and a translation. /// The matrix must be invertible. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine2d(M22d linear, double tX, double tY) { Debug.Assert(linear.Invertible); Linear = linear; Trans = new V2d(tX, tY); } /// /// Constructs an affine transformation from a linear map. /// The matrix must be invertible. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine2d(M22d linear) { Debug.Assert(linear.Invertible); Linear = linear; Trans = V2d.Zero; } #endregion #region Constants /// /// Gets the identity transformation. /// public static Affine2d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Affine2d(M22d.Identity); } #endregion #region Properties /// /// Gets if this affine transformation is valid, i.e. if the linear map is invertible. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Linear.Invertible; } /// /// Gets if this affine transformation is invalid, i.e. if the linear map is singular. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !IsValid; } /// /// Gets the inverse of this affine transformation. /// public readonly Affine2d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var rs = new Affine2d(this); rs.Invert(); return rs; } } #endregion #region Arithmetic Operators /// /// Multiplies two affine transformations. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Affine2d a, Affine2d b) { return new Affine2d(a.Linear * b.Linear, a.Linear * b.Trans + a.Trans); } /// /// Transforms a vector by an affine transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator *(Affine2d a, V3d v) { return new V3d( a.Linear.M00 * v.X + a.Linear.M01 * v.Y + a.Trans.X * v.Z, a.Linear.M10 * v.X + a.Linear.M11 * v.Y + a.Trans.Y * v.Z, v.Z); } /// /// Multiplies a (as a 3x3 matrix) and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator *(Affine2d a, M33d m) { return new M33d( a.Linear.M00 * m.M00 + a.Linear.M01 * m.M10 + a.Trans.X * m.M20, a.Linear.M00 * m.M01 + a.Linear.M01 * m.M11 + a.Trans.X * m.M21, a.Linear.M00 * m.M02 + a.Linear.M01 * m.M12 + a.Trans.X * m.M22, a.Linear.M10 * m.M00 + a.Linear.M11 * m.M10 + a.Trans.Y * m.M20, a.Linear.M10 * m.M01 + a.Linear.M11 * m.M11 + a.Trans.Y * m.M21, a.Linear.M10 * m.M02 + a.Linear.M11 * m.M12 + a.Trans.Y * m.M22, m.M20, m.M21, m.M22); } /// /// Multiplies a and a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator *(M33d m, Affine2d a) { return new M33d( m.M00 * a.Linear.M00 + m.M01 * a.Linear.M10, m.M00 * a.Linear.M01 + m.M01 * a.Linear.M11, m.M00 * a.Trans.X + m.M01 * a.Trans.Y + m.M02, m.M10 * a.Linear.M00 + m.M11 * a.Linear.M10, m.M10 * a.Linear.M01 + m.M11 * a.Linear.M11, m.M10 * a.Trans.X + m.M11 * a.Trans.Y + m.M12, m.M20 * a.Linear.M00 + m.M21 * a.Linear.M10, m.M20 * a.Linear.M01 + m.M21 * a.Linear.M11, m.M20 * a.Trans.X + m.M21 * a.Trans.Y + m.M22); } /// /// Multiplies a (as a 2x3 matrix) and a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(Affine2d a, M22d m) => new M23d(a.Linear * m, a.Trans); /// /// Multiplies a and a (as a 2x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(M22d m, Affine2d a) => new M23d(m * a.Linear, m * a.Trans); /// /// Multiplies a (as a 2x3 matrix) and a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(Affine2d a, M23d m) { return new M23d( a.Linear.M00 * m.M00 + a.Linear.M01 * m.M10, a.Linear.M00 * m.M01 + a.Linear.M01 * m.M11, a.Trans.X + a.Linear.M00 * m.M02 + a.Linear.M01 * m.M12, a.Linear.M10 * m.M00 + a.Linear.M11 * m.M10, a.Linear.M10 * m.M01 + a.Linear.M11 * m.M11, a.Trans.Y + a.Linear.M10 * m.M02 + a.Linear.M11 * m.M12); } /// /// Multiplies a and a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(M23d m, Affine2d a) { return new M23d( m.M00 * a.Linear.M00 + m.M01 * a.Linear.M10, m.M00 * a.Linear.M01 + m.M01 * a.Linear.M11, m.M00 * a.Trans.X + m.M01 * a.Trans.Y + m.M02, m.M10 * a.Linear.M00 + m.M11 * a.Linear.M10, m.M10 * a.Linear.M01 + m.M11 * a.Linear.M11, m.M10 * a.Trans.X + m.M11 * a.Trans.Y + m.M12); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Affine2d a, Euclidean2d e) => a * (Affine2d)e; /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Euclidean2d e, Affine2d a) => (Affine2d)e * a; /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Affine2d a, Rot2d r) => new Affine2d(a.Linear * r, a.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Rot2d r, Affine2d a) => new Affine2d(r * a.Linear, r * a.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Affine2d a, Scale2d s) { return new Affine2d(new M22d( a.Linear.M00 * s.X, a.Linear.M01 * s.Y, a.Linear.M10 * s.X, a.Linear.M11 * s.Y), a.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Scale2d s, Affine2d a) { return new Affine2d(new M22d( a.Linear.M00 * s.X, a.Linear.M01 * s.X, a.Linear.M10 * s.Y, a.Linear.M11 * s.Y), a.Trans * s.V); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Affine2d a, Shift2d s) { return new Affine2d(a.Linear, a.Linear * s.V + a.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Shift2d s, Affine2d a) { return new Affine2d(a.Linear, a.Trans + s.V); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Affine2d a, Similarity2d s) => a * (Affine2d)s; /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Similarity2d s, Affine2d a) => (Affine2d)s * a; #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Affine2d a0, Affine2d a1) => (a0.Linear == a1.Linear) && (a0.Trans == a1.Trans); /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Affine2d a0, Affine2d a1) => (a0.Linear != a1.Linear) || (a0.Trans != a1.Trans); #endregion #region Static Creators /// /// Creates an affine transformation from a 2x3 matrix. /// The left 2x2 submatrix of must be invertible. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d FromM23d(M23d matrix, double epsilon = 1e-12) { var linear = (M22d)matrix; var trans = new V2d(matrix.M02, matrix.M12); if (linear.Determinant.IsTiny(epsilon)) throw new ArgumentException("Matrix must be invertible"); return new Affine2d(linear, trans); } /// /// Creates an affine transformation from a 3x3 matrix. /// The matrix has to be homogeneous and must not contain perspective components and its upper left 2x2 submatrix must be invertible. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d FromM33d(M33d m, double epsilon = 1e-12) { if (!(m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (m.M22.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); var linear = ((M22d)m) / m.M22; var trans = new V2d(m.M02, m.M12) / m.M22; if (linear.Determinant.IsTiny(epsilon)) throw new ArgumentException("Matrix must be invertible"); return new Affine2d(linear, trans); } /// /// Creates an affine transformation from a . /// The transformation must represent a valid affine transformation (e.g. it does not contain perspective components). /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d FromTrafo2d(Trafo2d trafo, double epsilon = 1e-12) => FromM33d(trafo.Forward, epsilon); #region Translation /// /// Creates an transformation with the translational component given by 2 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d Translation(double tX, double tY) => new Affine2d(M22d.Identity, tX, tY); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d Translation(V2d vector) => new Affine2d(M22d.Identity, vector); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d Translation(Shift2d shift) => new Affine2d(M22d.Identity, shift.V); #endregion #region Scale /// /// Creates a scaling transformation using a uniform scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d Scale(double scaleFactor) => new Affine2d(M22d.Scale(scaleFactor, scaleFactor)); /// /// Creates a scaling transformation using 2 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d Scale(double sX, double sY) => new Affine2d(M22d.Scale(sX, sY)); /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d Scale(V2d scaleFactors) => new Affine2d(M22d.Scale(scaleFactors)); /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d Scale(Scale2d scale) => new Affine2d(M22d.Scale(scale)); #endregion #region Rotation /// /// Creates a rotation transformation from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d Rotation(Rot2d rot) => new Affine2d(M22d.Rotation(rot)); /// /// Creates a rotation transformation with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d Rotation(double angleInRadians) => new Affine2d(M22d.Rotation(angleInRadians)); /// /// Creates a rotation transformation with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d RotationInDegrees(double angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); #endregion #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M23d(Affine2d a) => new M23d(a.Linear, a.Trans); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M22d(Affine2d a) => a.Linear; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33d(Affine2d a) => new M33d((M23d)a); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo2d(Affine2d a) { Debug.Assert(a.Linear.Invertible); var t = (M33d)a; return new Trafo2d(t, t.Inverse); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine2f(Affine2d a) => new Affine2f((M22f)a.Linear, (V2f)a.Trans); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Linear, Trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Affine2d other) => Linear.Equals(other.Linear) && Trans.Equals(other.Trans); public override readonly bool Equals(object other) => (other is Affine2d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Linear, Trans); } public static Affine2d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Affine2d(M22d.Parse(x[0]), V2d.Parse(x[1])); } #endregion } public static partial class Affine { #region Invert /// /// Returns the inverse of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d Inverse(Affine2d a) => a.Inverse; /// /// Inverts the given affine transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Affine2d a) { Debug.Assert(a.Linear.Invertible); a.Linear.Invert(); a.Trans = -a.Linear * a.Trans; } #endregion #region Transformations /// /// Transforms a by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Transform(this Affine2d a, V3d v) => a * v; /// /// Transforms a position vector (v.Z is presumed 1) by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d TransformPos(this Affine2d a, V2d v) { return new V2d( a.Linear.M00 * v.X + a.Linear.M01 * v.Y + a.Trans.X, a.Linear.M10 * v.X + a.Linear.M11 * v.Y + a.Trans.Y); } /// /// Transforms a direction vector (v.Z is presumed 0) by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d TransformDir(this Affine2d a, V2d v) { return new V2d( a.Linear.M00 * v.X + a.Linear.M01 * v.Y, a.Linear.M10 * v.X + a.Linear.M11 * v.Y); } /// /// Transforms a by the transpose of an (as a 3x3 matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransposedTransform(this Affine2d a, V3d v) { return new V3d( v.X * a.Linear.M00 + v.Y * a.Linear.M10, v.X * a.Linear.M01 + v.Y * a.Linear.M11, v.X * a.Trans.X + v.Y * a.Trans.Y + v.Z); } /// /// Transforms a by the transpose of an (as a 3x3 matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d TransposedTransform(this Affine2d a, V2d v) { return new V2d( v.X * a.Linear.M00 + v.Y * a.Linear.M10, v.X * a.Linear.M01 + v.Y * a.Linear.M11); } /// /// Transforms a position vector (v.Z is presumed 1) by the transpose of an (as a 3x3 matrix). /// Projective transform is performed. Perspective Division is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d TransposedTransformPosProj(this Affine2d a, V2d v) { var s = v.X * a.Trans.X + v.Y * a.Trans.Y + 1; return TransposedTransform(a, v) * (1 / s); } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Affine2d a0, Affine2d a1) { return ApproximateEquals(a0, a1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Affine2d a0, Affine2d a1, double tolerance) { return ApproximateEquals(a0.Linear, a1.Linear, tolerance) && ApproximateEquals(a0.Trans, a1.Trans, tolerance); } #endregion } #endregion #region Affine3d /// /// Struct to represent an affine transformation in 3-dimensional space. It consists of /// a linear tranformation (invertible 3x3 matrix) and a translational component (3d vector). /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Affine3d : IEquatable, IValidity { [DataMember] public M33d Linear; [DataMember] public V3d Trans; #region Constructors /// /// Constructs a copy of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine3d(Affine3d affine) { Linear = affine.Linear; Trans = affine.Trans; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine3d(Affine3f affine) { Linear = (M33d)affine.Linear; Trans = (V3d)affine.Trans; } /// /// Constructs an affine transformation from a linear map and a translation. /// The matrix must be invertible. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine3d(M33d linear, V3d translation) { Debug.Assert(linear.Invertible); Linear = linear; Trans = translation; } /// /// Constructs an affine transformation from a linear map and a translation. /// The matrix must be invertible. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine3d(M33d linear, double tX, double tY, double tZ) { Debug.Assert(linear.Invertible); Linear = linear; Trans = new V3d(tX, tY, tZ); } /// /// Constructs an affine transformation from a linear map. /// The matrix must be invertible. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Affine3d(M33d linear) { Debug.Assert(linear.Invertible); Linear = linear; Trans = V3d.Zero; } #endregion #region Constants /// /// Gets the identity transformation. /// public static Affine3d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Affine3d(M33d.Identity); } #endregion #region Properties /// /// Gets if this affine transformation is valid, i.e. if the linear map is invertible. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Linear.Invertible; } /// /// Gets if this affine transformation is invalid, i.e. if the linear map is singular. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !IsValid; } /// /// Gets the inverse of this affine transformation. /// public readonly Affine3d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var rs = new Affine3d(this); rs.Invert(); return rs; } } #endregion #region Arithmetic Operators /// /// Multiplies two affine transformations. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Affine3d a, Affine3d b) { return new Affine3d(a.Linear * b.Linear, a.Linear * b.Trans + a.Trans); } /// /// Transforms a vector by an affine transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator *(Affine3d a, V4d v) { return new V4d( a.Linear.M00 * v.X + a.Linear.M01 * v.Y + a.Linear.M02 * v.Z + a.Trans.X * v.W, a.Linear.M10 * v.X + a.Linear.M11 * v.Y + a.Linear.M12 * v.Z + a.Trans.Y * v.W, a.Linear.M20 * v.X + a.Linear.M21 * v.Y + a.Linear.M22 * v.Z + a.Trans.Z * v.W, v.W); } /// /// Multiplies a (as a 4x4 matrix) and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator *(Affine3d a, M44d m) { return new M44d( a.Linear.M00 * m.M00 + a.Linear.M01 * m.M10 + a.Linear.M02 * m.M20 + a.Trans.X * m.M30, a.Linear.M00 * m.M01 + a.Linear.M01 * m.M11 + a.Linear.M02 * m.M21 + a.Trans.X * m.M31, a.Linear.M00 * m.M02 + a.Linear.M01 * m.M12 + a.Linear.M02 * m.M22 + a.Trans.X * m.M32, a.Linear.M00 * m.M03 + a.Linear.M01 * m.M13 + a.Linear.M02 * m.M23 + a.Trans.X * m.M33, a.Linear.M10 * m.M00 + a.Linear.M11 * m.M10 + a.Linear.M12 * m.M20 + a.Trans.Y * m.M30, a.Linear.M10 * m.M01 + a.Linear.M11 * m.M11 + a.Linear.M12 * m.M21 + a.Trans.Y * m.M31, a.Linear.M10 * m.M02 + a.Linear.M11 * m.M12 + a.Linear.M12 * m.M22 + a.Trans.Y * m.M32, a.Linear.M10 * m.M03 + a.Linear.M11 * m.M13 + a.Linear.M12 * m.M23 + a.Trans.Y * m.M33, a.Linear.M20 * m.M00 + a.Linear.M21 * m.M10 + a.Linear.M22 * m.M20 + a.Trans.Z * m.M30, a.Linear.M20 * m.M01 + a.Linear.M21 * m.M11 + a.Linear.M22 * m.M21 + a.Trans.Z * m.M31, a.Linear.M20 * m.M02 + a.Linear.M21 * m.M12 + a.Linear.M22 * m.M22 + a.Trans.Z * m.M32, a.Linear.M20 * m.M03 + a.Linear.M21 * m.M13 + a.Linear.M22 * m.M23 + a.Trans.Z * m.M33, m.M30, m.M31, m.M32, m.M33); } /// /// Multiplies a and a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator *(M44d m, Affine3d a) { return new M44d( m.M00 * a.Linear.M00 + m.M01 * a.Linear.M10 + m.M02 * a.Linear.M20, m.M00 * a.Linear.M01 + m.M01 * a.Linear.M11 + m.M02 * a.Linear.M21, m.M00 * a.Linear.M02 + m.M01 * a.Linear.M12 + m.M02 * a.Linear.M22, m.M00 * a.Trans.X + m.M01 * a.Trans.Y + m.M02 * a.Trans.Z + m.M03, m.M10 * a.Linear.M00 + m.M11 * a.Linear.M10 + m.M12 * a.Linear.M20, m.M10 * a.Linear.M01 + m.M11 * a.Linear.M11 + m.M12 * a.Linear.M21, m.M10 * a.Linear.M02 + m.M11 * a.Linear.M12 + m.M12 * a.Linear.M22, m.M10 * a.Trans.X + m.M11 * a.Trans.Y + m.M12 * a.Trans.Z + m.M13, m.M20 * a.Linear.M00 + m.M21 * a.Linear.M10 + m.M22 * a.Linear.M20, m.M20 * a.Linear.M01 + m.M21 * a.Linear.M11 + m.M22 * a.Linear.M21, m.M20 * a.Linear.M02 + m.M21 * a.Linear.M12 + m.M22 * a.Linear.M22, m.M20 * a.Trans.X + m.M21 * a.Trans.Y + m.M22 * a.Trans.Z + m.M23, m.M30 * a.Linear.M00 + m.M31 * a.Linear.M10 + m.M32 * a.Linear.M20, m.M30 * a.Linear.M01 + m.M31 * a.Linear.M11 + m.M32 * a.Linear.M21, m.M30 * a.Linear.M02 + m.M31 * a.Linear.M12 + m.M32 * a.Linear.M22, m.M30 * a.Trans.X + m.M31 * a.Trans.Y + m.M32 * a.Trans.Z + m.M33); } /// /// Multiplies a (as a 3x4 matrix) and a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(Affine3d a, M33d m) => new M34d(a.Linear * m, a.Trans); /// /// Multiplies a and a (as a 3x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(M33d m, Affine3d a) => new M34d(m * a.Linear, m * a.Trans); /// /// Multiplies a (as a 3x4 matrix) and a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(Affine3d a, M34d m) { return new M34d( a.Linear.M00 * m.M00 + a.Linear.M01 * m.M10 + a.Linear.M02 * m.M20, a.Linear.M00 * m.M01 + a.Linear.M01 * m.M11 + a.Linear.M02 * m.M21, a.Linear.M00 * m.M02 + a.Linear.M01 * m.M12 + a.Linear.M02 * m.M22, a.Trans.X + a.Linear.M00 * m.M03 + a.Linear.M01 * m.M13 + a.Linear.M02 * m.M23, a.Linear.M10 * m.M00 + a.Linear.M11 * m.M10 + a.Linear.M12 * m.M20, a.Linear.M10 * m.M01 + a.Linear.M11 * m.M11 + a.Linear.M12 * m.M21, a.Linear.M10 * m.M02 + a.Linear.M11 * m.M12 + a.Linear.M12 * m.M22, a.Trans.Y + a.Linear.M10 * m.M03 + a.Linear.M11 * m.M13 + a.Linear.M12 * m.M23, a.Linear.M20 * m.M00 + a.Linear.M21 * m.M10 + a.Linear.M22 * m.M20, a.Linear.M20 * m.M01 + a.Linear.M21 * m.M11 + a.Linear.M22 * m.M21, a.Linear.M20 * m.M02 + a.Linear.M21 * m.M12 + a.Linear.M22 * m.M22, a.Trans.Z + a.Linear.M20 * m.M03 + a.Linear.M21 * m.M13 + a.Linear.M22 * m.M23); } /// /// Multiplies a and a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(M34d m, Affine3d a) { return new M34d( m.M00 * a.Linear.M00 + m.M01 * a.Linear.M10 + m.M02 * a.Linear.M20, m.M00 * a.Linear.M01 + m.M01 * a.Linear.M11 + m.M02 * a.Linear.M21, m.M00 * a.Linear.M02 + m.M01 * a.Linear.M12 + m.M02 * a.Linear.M22, m.M00 * a.Trans.X + m.M01 * a.Trans.Y + m.M02 * a.Trans.Z + m.M03, m.M10 * a.Linear.M00 + m.M11 * a.Linear.M10 + m.M12 * a.Linear.M20, m.M10 * a.Linear.M01 + m.M11 * a.Linear.M11 + m.M12 * a.Linear.M21, m.M10 * a.Linear.M02 + m.M11 * a.Linear.M12 + m.M12 * a.Linear.M22, m.M10 * a.Trans.X + m.M11 * a.Trans.Y + m.M12 * a.Trans.Z + m.M13, m.M20 * a.Linear.M00 + m.M21 * a.Linear.M10 + m.M22 * a.Linear.M20, m.M20 * a.Linear.M01 + m.M21 * a.Linear.M11 + m.M22 * a.Linear.M21, m.M20 * a.Linear.M02 + m.M21 * a.Linear.M12 + m.M22 * a.Linear.M22, m.M20 * a.Trans.X + m.M21 * a.Trans.Y + m.M22 * a.Trans.Z + m.M23); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Affine3d a, Euclidean3d e) => a * (Affine3d)e; /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Euclidean3d e, Affine3d a) => (Affine3d)e * a; /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Affine3d a, Rot3d r) => new Affine3d(a.Linear * r, a.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Rot3d r, Affine3d a) => new Affine3d(r * a.Linear, r * a.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Affine3d a, Scale3d s) { return new Affine3d(new M33d( a.Linear.M00 * s.X, a.Linear.M01 * s.Y, a.Linear.M02 * s.Z, a.Linear.M10 * s.X, a.Linear.M11 * s.Y, a.Linear.M12 * s.Z, a.Linear.M20 * s.X, a.Linear.M21 * s.Y, a.Linear.M22 * s.Z), a.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Scale3d s, Affine3d a) { return new Affine3d(new M33d( a.Linear.M00 * s.X, a.Linear.M01 * s.X, a.Linear.M02 * s.X, a.Linear.M10 * s.Y, a.Linear.M11 * s.Y, a.Linear.M12 * s.Y, a.Linear.M20 * s.Z, a.Linear.M21 * s.Z, a.Linear.M22 * s.Z), a.Trans * s.V); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Affine3d a, Shift3d s) { return new Affine3d(a.Linear, a.Linear * s.V + a.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Shift3d s, Affine3d a) { return new Affine3d(a.Linear, a.Trans + s.V); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Affine3d a, Similarity3d s) => a * (Affine3d)s; /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Similarity3d s, Affine3d a) => (Affine3d)s * a; #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Affine3d a0, Affine3d a1) => (a0.Linear == a1.Linear) && (a0.Trans == a1.Trans); /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Affine3d a0, Affine3d a1) => (a0.Linear != a1.Linear) || (a0.Trans != a1.Trans); #endregion #region Static Creators /// /// Creates an affine transformation from a 3x4 matrix. /// The left 3x3 submatrix of must be invertible. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d FromM34d(M34d matrix, double epsilon = 1e-12) { var linear = (M33d)matrix; var trans = new V3d(matrix.M03, matrix.M13, matrix.M23); if (linear.Determinant.IsTiny(epsilon)) throw new ArgumentException("Matrix must be invertible"); return new Affine3d(linear, trans); } /// /// Creates an affine transformation from a 4x4 matrix. /// The matrix has to be homogeneous and must not contain perspective components and its upper left 3x3 submatrix must be invertible. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d FromM44d(M44d m, double epsilon = 1e-12) { if (!(m.M30.IsTiny(epsilon) && m.M31.IsTiny(epsilon) && m.M32.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (m.M33.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); var linear = ((M33d)m) / m.M33; var trans = new V3d(m.M03, m.M13, m.M23) / m.M33; if (linear.Determinant.IsTiny(epsilon)) throw new ArgumentException("Matrix must be invertible"); return new Affine3d(linear, trans); } /// /// Creates an affine transformation from a . /// The transformation must represent a valid affine transformation (e.g. it does not contain perspective components). /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d FromTrafo3d(Trafo3d trafo, double epsilon = 1e-12) => FromM44d(trafo.Forward, epsilon); #region Translation /// /// Creates an transformation with the translational component given by 3 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d Translation(double tX, double tY, double tZ) => new Affine3d(M33d.Identity, tX, tY, tZ); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d Translation(V3d vector) => new Affine3d(M33d.Identity, vector); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d Translation(Shift3d shift) => new Affine3d(M33d.Identity, shift.V); #endregion #region Scale /// /// Creates a scaling transformation using a uniform scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d Scale(double scaleFactor) => new Affine3d(M33d.Scale(scaleFactor, scaleFactor, scaleFactor)); /// /// Creates a scaling transformation using 3 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d Scale(double sX, double sY, double sZ) => new Affine3d(M33d.Scale(sX, sY, sZ)); /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d Scale(V3d scaleFactors) => new Affine3d(M33d.Scale(scaleFactors)); /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d Scale(Scale3d scale) => new Affine3d(M33d.Scale(scale)); #endregion #region Rotation /// /// Creates a rotation transformation from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d Rotation(Rot3d rot) => new Affine3d(M33d.Rotation(rot)); /// /// Creates a rotation transformation from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d Rotation(V3d normalizedAxis, double angleRadians) => new Affine3d(M33d.Rotation(normalizedAxis, angleRadians)); /// /// Creates a rotation transformation from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d RotationInDegrees(V3d normalizedAxis, double angleDegrees) => Rotation(normalizedAxis, angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d RotationEuler(double rollInRadians, double pitchInRadians, double yawInRadians) => new Affine3d(M33d.RotationEuler(rollInRadians, pitchInRadians, yawInRadians)); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d RotationEulerInDegrees(double rollInDegrees, double pitchInDegrees, double yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d RotationEuler(V3d rollPitchYawInRadians) => RotationEuler(rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d RotationEulerInDegrees(V3d rollPitchYawInDegrees) => RotationEulerInDegrees( rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a rotation transformation which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d RotateInto(V3d from, V3d into) => new Affine3d(M33d.RotateInto(from, into)); /// /// Creates a rotation transformation by radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d RotationX(double angleRadians) => new Affine3d(M33d.RotationX(angleRadians)); /// /// Creates a rotation transformation for degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d RotationXInDegrees(double angleDegrees) => RotationX(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d RotationY(double angleRadians) => new Affine3d(M33d.RotationY(angleRadians)); /// /// Creates a rotation transformation for degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d RotationYInDegrees(double angleDegrees) => RotationY(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d RotationZ(double angleRadians) => new Affine3d(M33d.RotationZ(angleRadians)); /// /// Creates a rotation transformation for degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d RotationZInDegrees(double angleDegrees) => RotationZ(angleDegrees.RadiansFromDegrees()); #endregion #region Shear /// /// Creates a shear transformation along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d ShearXY(double factorX, double factorY) => new Affine3d(M33d.ShearXY(factorX, factorY)); /// /// Creates a shear transformation along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d ShearXZ(double factorX, double factorZ) => new Affine3d(M33d.ShearXZ(factorX, factorZ)); /// /// Creates a shear transformation along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d ShearYZ(double factorY, double factorZ) => new Affine3d(M33d.ShearYZ(factorY, factorZ)); #endregion #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34d(Affine3d a) => new M34d(a.Linear, a.Trans); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33d(Affine3d a) => a.Linear; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44d(Affine3d a) => new M44d((M34d)a); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo3d(Affine3d a) { Debug.Assert(a.Linear.Invertible); var t = (M44d)a; return new Trafo3d(t, t.Inverse); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine3f(Affine3d a) => new Affine3f((M33f)a.Linear, (V3f)a.Trans); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Linear, Trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Affine3d other) => Linear.Equals(other.Linear) && Trans.Equals(other.Trans); public override readonly bool Equals(object other) => (other is Affine3d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Linear, Trans); } public static Affine3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Affine3d(M33d.Parse(x[0]), V3d.Parse(x[1])); } #endregion } public static partial class Affine { #region Invert /// /// Returns the inverse of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d Inverse(Affine3d a) => a.Inverse; /// /// Inverts the given affine transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Affine3d a) { Debug.Assert(a.Linear.Invertible); a.Linear.Invert(); a.Trans = -a.Linear * a.Trans; } #endregion #region Transformations /// /// Transforms a by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Transform(this Affine3d a, V4d v) => a * v; /// /// Transforms a position vector (v.W is presumed 1) by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransformPos(this Affine3d a, V3d v) { return new V3d( a.Linear.M00 * v.X + a.Linear.M01 * v.Y + a.Linear.M02 * v.Z + a.Trans.X, a.Linear.M10 * v.X + a.Linear.M11 * v.Y + a.Linear.M12 * v.Z + a.Trans.Y, a.Linear.M20 * v.X + a.Linear.M21 * v.Y + a.Linear.M22 * v.Z + a.Trans.Z); } /// /// Transforms a direction vector (v.W is presumed 0) by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransformDir(this Affine3d a, V3d v) { return new V3d( a.Linear.M00 * v.X + a.Linear.M01 * v.Y + a.Linear.M02 * v.Z, a.Linear.M10 * v.X + a.Linear.M11 * v.Y + a.Linear.M12 * v.Z, a.Linear.M20 * v.X + a.Linear.M21 * v.Y + a.Linear.M22 * v.Z); } /// /// Transforms a by the transpose of an (as a 4x4 matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d TransposedTransform(this Affine3d a, V4d v) { return new V4d( v.X * a.Linear.M00 + v.Y * a.Linear.M10 + v.Z * a.Linear.M20, v.X * a.Linear.M01 + v.Y * a.Linear.M11 + v.Z * a.Linear.M21, v.X * a.Linear.M02 + v.Y * a.Linear.M12 + v.Z * a.Linear.M22, v.X * a.Trans.X + v.Y * a.Trans.Y + v.Z * a.Trans.Z + v.W); } /// /// Transforms a by the transpose of an (as a 4x4 matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransposedTransform(this Affine3d a, V3d v) { return new V3d( v.X * a.Linear.M00 + v.Y * a.Linear.M10 + v.Z * a.Linear.M20, v.X * a.Linear.M01 + v.Y * a.Linear.M11 + v.Z * a.Linear.M21, v.X * a.Linear.M02 + v.Y * a.Linear.M12 + v.Z * a.Linear.M22); } /// /// Transforms a position vector (v.W is presumed 1) by the transpose of an (as a 4x4 matrix). /// Projective transform is performed. Perspective Division is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransposedTransformPosProj(this Affine3d a, V3d v) { var s = v.X * a.Trans.X + v.Y * a.Trans.Y + v.Z * a.Trans.Z + 1; return TransposedTransform(a, v) * (1 / s); } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Affine3d a0, Affine3d a1) { return ApproximateEquals(a0, a1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Affine3d a0, Affine3d a1, double tolerance) { return ApproximateEquals(a0.Linear, a1.Linear, tolerance) && ApproximateEquals(a0.Trans, a1.Trans, tolerance); } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Affine_template.cs ================================================ using System; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTOGENERATED CODE - DO NOT CHANGE! //# Action comma = () => Out(", "); //# Action commaln = () => Out("," + Environment.NewLine); //# Action add = () => Out(" + "); //# Action and = () => Out(" && "); //# var fields = new[] {"X", "Y", "Z", "W"}; //# foreach (var isDouble in new[] { false, true }) { //# for (int n = 2; n <= 3; n++) { //# var ftype = isDouble ? "double" : "float"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var m = n + 1; //# var type = "Affine" + n + tc; //# var type2 = "Affine" + n + tc2; //# var trafont = "Trafo" + n + tc; //# var euclideannt = "Euclidean" + n + tc; //# var rotnt = "Rot" + n + tc; //# var scalent = "Scale" + n + tc; //# var shiftnt = "Shift" + n + tc; //# var similaritynt = "Similarity" + n + tc; //# var mnnt = "M" + n + n + tc; //# var mnnt2 = "M" + n + n + tc2; //# var mnmt = "M" + n + m + tc; //# var mmmt = "M" + m + m + tc; //# var vnt = "V" + n + tc; //# var vnt2 = "V" + n + tc2; //# var vmt = "V" + m + tc; //# var nfields = fields.Take(n).ToArray(); //# var mfields = fields.Take(m).ToArray(); //# var fn = fields[n]; //# var eps = isDouble ? "1e-12" : "1e-5f"; #region __type__ /// /// Struct to represent an affine transformation in __n__-dimensional space. It consists of /// a linear tranformation (invertible __n__x__n__ matrix) and a translational component (__n__d vector). /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__>, IValidity { [DataMember] public __mnnt__ Linear; [DataMember] public __vnt__ Trans; #region Constructors /// /// Constructs a copy of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ affine) { Linear = affine.Linear; Trans = affine.Trans; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ affine) { Linear = (__mnnt__)affine.Linear; Trans = (__vnt__)affine.Trans; } /// /// Constructs an affine transformation from a linear map and a translation. /// The matrix must be invertible. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__mnnt__ linear, __vnt__ translation) { Debug.Assert(linear.Invertible); Linear = linear; Trans = translation; } /// /// Constructs an affine transformation from a linear map and a translation. /// The matrix must be invertible. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__mnnt__ linear, /*# nfields.ForEach(f => { */__ftype__ t__f__/*# }, comma); */) { Debug.Assert(linear.Invertible); Linear = linear; Trans = new __vnt__(/*# nfields.ForEach(f => { */t__f__/*# }, comma); */); } /// /// Constructs an affine transformation from a linear map. /// The matrix must be invertible. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__mnnt__ linear) { Debug.Assert(linear.Invertible); Linear = linear; Trans = __vnt__.Zero; } #endregion #region Constants /// /// Gets the identity transformation. /// public static __type__ Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(__mnnt__.Identity); } #endregion #region Properties /// /// Gets if this affine transformation is valid, i.e. if the linear map is invertible. /// public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Linear.Invertible; } /// /// Gets if this affine transformation is invalid, i.e. if the linear map is singular. /// public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !IsValid; } /// /// Gets the inverse of this affine transformation. /// public readonly __type__ Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var rs = new __type__(this); rs.Invert(); return rs; } } #endregion #region Arithmetic Operators /// /// Multiplies two affine transformations. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ a, __type__ b) { return new __type__(a.Linear * b.Linear, a.Linear * b.Trans + a.Trans); } /// /// Transforms a vector by an affine transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vmt__ operator *(__type__ a, __vmt__ v) { return new __vmt__(/*# nfields.ForEach((fi, i) => { */ /*# mfields.ForEach((fj, j) => { var aij = (j < n) ? "a.Linear.M" + i + j : "a.Trans." + fi; */__aij__ * v.__fj__/*# }, add); }, comma);*/, v.__fn__); } /// /// Multiplies a (as a __m__x__m__ matrix) and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mmmt__ operator *(__type__ a, __mmmt__ m) { return new __mmmt__(/*# nfields.ForEach((fi, i) => { mfields.ForEach((fj, j) => { */ /*# mfields.ForEach((fk, k) => { var aik = (k < n) ? "a.Linear.M" + i + k : "a.Trans." + fi; */__aik__ * m.M__k____j__/*# }, add); }, comma); }, commaln);*/, /*# mfields.ForEach((f, i) => { */m.M__n____i__/*# }, comma);*/); } /// /// Multiplies a and a (as a __m__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mmmt__ operator *(__mmmt__ m, __type__ a) { return new __mmmt__(/*# mfields.ForEach((fi, i) => { nfields.ForEach((fj, j) => { */ /*# nfields.ForEach((fk, k) => { */m.M__i____k__ * a.Linear.M__k____j__/*# }, add); }, comma);*/, /*# nfields.ForEach((fk, k) => { */m.M__i____k__ * a.Trans.__fk__/*# }, add);*/ + m.M__i____n__/*# }, commaln);*/); } /// /// Multiplies a (as a __n__x__m__ matrix) and a (as a __m__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mnmt__ operator *(__type__ a, __mnnt__ m) => new __mnmt__(a.Linear * m, a.Trans); /// /// Multiplies a and a (as a __n__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mnmt__ operator *(__mnnt__ m, __type__ a) => new __mnmt__(m * a.Linear, m * a.Trans); /// /// Multiplies a (as a __n__x__m__ matrix) and a (as a __m__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mnmt__ operator *(__type__ a, __mnmt__ m) { return new __mnmt__(/*# nfields.ForEach((fi, i) => { nfields.ForEach((fj, j) => { */ /*# n.ForEach(k => { */a.Linear.M__i____k__ * m.M__k____j__/*# }, add); }, comma);*/, a.Trans.__fi__ + /*# n.ForEach(k => {*/a.Linear.M__i____k__ * m.M__k____n__/*# }, add); }, commaln);*/); } /// /// Multiplies a and a (as a __m__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mnmt__ operator *(__mnmt__ m, __type__ a) { return new __mnmt__(/*# nfields.ForEach((fi, i) => { nfields.ForEach((fj, j) => { */ /*# nfields.ForEach((fk, k) => { */m.M__i____k__ * a.Linear.M__k____j__/*# }, add); }, comma);*/, /*# nfields.ForEach((fk, k) => { */m.M__i____k__ * a.Trans.__fk__/*# }, add);*/ + m.M__i____n__/*# }, commaln);*/); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ a, __euclideannt__ e) => a * (__type__)e; /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__euclideannt__ e, __type__ a) => (__type__)e * a; /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ a, __rotnt__ r) => new __type__(a.Linear * r, a.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__rotnt__ r, __type__ a) => new __type__(r * a.Linear, r * a.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ a, __scalent__ s) { return new __type__(new __mnnt__(/*# nfields.ForEach((fi, i) => { */ /*# nfields.ForEach((fj, j) => { */a.Linear.M__i____j__ * s.__fj__/*# }, comma); }, comma);*/), a.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__scalent__ s, __type__ a) { return new __type__(new __mnnt__(/*# nfields.ForEach((fi, i) => { */ /*# nfields.ForEach((fj, j) => { */a.Linear.M__i____j__ * s.__fi__/*# }, comma); }, comma);*/), a.Trans * s.V); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ a, __shiftnt__ s) { return new __type__(a.Linear, a.Linear * s.V + a.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__shiftnt__ s, __type__ a) { return new __type__(a.Linear, a.Trans + s.V); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ a, __similaritynt__ s) => a * (__type__)s; /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__similaritynt__ s, __type__ a) => (__type__)s * a; #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ a0, __type__ a1) => (a0.Linear == a1.Linear) && (a0.Trans == a1.Trans); /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ a0, __type__ a1) => (a0.Linear != a1.Linear) || (a0.Trans != a1.Trans); #endregion #region Static Creators /// /// Creates an affine transformation from a __n__x__m__ matrix. /// The left __n__x__n__ submatrix of must be invertible. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__mnmt__(__mnmt__ matrix, __ftype__ epsilon = __eps__) { var linear = (__mnnt__)matrix; var trans = new __vnt__(/*# n.ForEach(i => { */matrix.M__i____n__/*# }, comma); */); if (linear.Determinant.IsTiny(epsilon)) throw new ArgumentException("Matrix must be invertible"); return new __type__(linear, trans); } /// /// Creates an affine transformation from a __m__x__m__ matrix. /// The matrix has to be homogeneous and must not contain perspective components and its upper left __n__x__n__ submatrix must be invertible. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__mmmt__(__mmmt__ m, __ftype__ epsilon = __eps__) { if (!(/*#n.ForEach(j => {*/m.M__n____j__.IsTiny(epsilon)/*# }, and);*/)) throw new ArgumentException("Matrix contains perspective components."); if (m.M__n____n__.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); var linear = ((__mnnt__)m) / m.M__n____n__; var trans = new __vnt__(/*# n.ForEach(i => { */m.M__i____n__/*# }, comma); */) / m.M__n____n__; if (linear.Determinant.IsTiny(epsilon)) throw new ArgumentException("Matrix must be invertible"); return new __type__(linear, trans); } /// /// Creates an affine transformation from a . /// The transformation must represent a valid affine transformation (e.g. it does not contain perspective components). /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__trafont__(__trafont__ trafo, __ftype__ epsilon = __eps__) => From__mmmt__(trafo.Forward, epsilon); #region Translation /// /// Creates an transformation with the translational component given by __n__ scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Translation(/*# nfields.ForEach(f => { */__ftype__ t__f__/*# }, comma); */) => new __type__(__mnnt__.Identity, /*# nfields.ForEach(f => { */t__f__/*# }, comma); */); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Translation(__vnt__ vector) => new __type__(__mnnt__.Identity, vector); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Translation(__shiftnt__ shift) => new __type__(__mnnt__.Identity, shift.V); #endregion #region Scale /// /// Creates a scaling transformation using a uniform scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Scale(__ftype__ scaleFactor) => new __type__(__mnnt__.Scale(/*# nfields.ForEach(f => { */scaleFactor/*# }, comma); */)); /// /// Creates a scaling transformation using __n__ scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Scale(/*# nfields.ForEach(f => { */__ftype__ s__f__/*# }, comma); */) => new __type__(__mnnt__.Scale(/*# nfields.ForEach(f => { */s__f__/*# }, comma); */)); /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Scale(__vnt__ scaleFactors) => new __type__(__mnnt__.Scale(scaleFactors)); /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Scale(__scalent__ scale) => new __type__(__mnnt__.Scale(scale)); #endregion #region Rotation /// /// Creates a rotation transformation from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Rotation(__rotnt__ rot) => new __type__(__mnnt__.Rotation(rot)); //# if (n == 2) { /// /// Creates a rotation transformation with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Rotation(__ftype__ angleInRadians) => new __type__(__mnnt__.Rotation(angleInRadians)); /// /// Creates a rotation transformation with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationInDegrees(__ftype__ angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); //# } else if (n == 3) { /// /// Creates a rotation transformation from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Rotation(__vnt__ normalizedAxis, __ftype__ angleRadians) => new __type__(__mnnt__.Rotation(normalizedAxis, angleRadians)); /// /// Creates a rotation transformation from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationInDegrees(__vnt__ normalizedAxis, __ftype__ angleDegrees) => Rotation(normalizedAxis, angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEuler(__ftype__ rollInRadians, __ftype__ pitchInRadians, __ftype__ yawInRadians) => new __type__(__mnnt__.RotationEuler(rollInRadians, pitchInRadians, yawInRadians)); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEulerInDegrees(__ftype__ rollInDegrees, __ftype__ pitchInDegrees, __ftype__ yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEuler(__vnt__ rollPitchYawInRadians) => RotationEuler(rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEulerInDegrees(__vnt__ rollPitchYawInDegrees) => RotationEulerInDegrees( rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a rotation transformation which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotateInto(__vnt__ from, __vnt__ into) => new __type__(__mnnt__.RotateInto(from, into)); /// /// Creates a rotation transformation by radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationX(__ftype__ angleRadians) => new __type__(__mnnt__.RotationX(angleRadians)); /// /// Creates a rotation transformation for degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationXInDegrees(__ftype__ angleDegrees) => RotationX(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationY(__ftype__ angleRadians) => new __type__(__mnnt__.RotationY(angleRadians)); /// /// Creates a rotation transformation for degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationYInDegrees(__ftype__ angleDegrees) => RotationY(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationZ(__ftype__ angleRadians) => new __type__(__mnnt__.RotationZ(angleRadians)); /// /// Creates a rotation transformation for degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationZInDegrees(__ftype__ angleDegrees) => RotationZ(angleDegrees.RadiansFromDegrees()); //# } #endregion //# if (n == 3) { #region Shear /// /// Creates a shear transformation along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ ShearXY(__ftype__ factorX, __ftype__ factorY) => new __type__(__mnnt__.ShearXY(factorX, factorY)); /// /// Creates a shear transformation along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ ShearXZ(__ftype__ factorX, __ftype__ factorZ) => new __type__(__mnnt__.ShearXZ(factorX, factorZ)); /// /// Creates a shear transformation along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ ShearYZ(__ftype__ factorY, __ftype__ factorZ) => new __type__(__mnnt__.ShearYZ(factorY, factorZ)); #endregion //# } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __mnmt__(__type__ a) => new __mnmt__(a.Linear, a.Trans); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __mnnt__(__type__ a) => a.Linear; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __mmmt__(__type__ a) => new __mmmt__((__mnmt__)a); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __trafont__(__type__ a) { Debug.Assert(a.Linear.Invertible); var t = (__mmmt__)a; return new __trafont__(t, t.Inverse); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type2__(__type__ a) => new __type2__((__mnnt2__)a.Linear, (__vnt2__)a.Trans); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Linear, Trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => Linear.Equals(other.Linear) && Trans.Equals(other.Trans); public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Linear, Trans); } public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__(__mnnt__.Parse(x[0]), __vnt__.Parse(x[1])); } #endregion } public static partial class Affine { #region Invert /// /// Returns the inverse of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Inverse(__type__ a) => a.Inverse; /// /// Inverts the given affine transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref __type__ a) { Debug.Assert(a.Linear.Invertible); a.Linear.Invert(); a.Trans = -a.Linear * a.Trans; } #endregion #region Transformations /// /// Transforms a by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vmt__ Transform(this __type__ a, __vmt__ v) => a * v; /// /// Transforms a position vector (v.__fn__ is presumed 1) by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ TransformPos(this __type__ a, __vnt__ v) { return new __vnt__(/*# nfields.ForEach((fi, i) => { */ /*# nfields.ForEach((fj, j) => { */a.Linear.M__i____j__ * v.__fj__/*# }, add); */ + a.Trans.__fi__/*# }, comma);*/); } /// /// Transforms a direction vector (v.__fn__ is presumed 0) by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ TransformDir(this __type__ a, __vnt__ v) { return new __vnt__(/*# nfields.ForEach((fi, i) => { */ /*# nfields.ForEach((fj, j) => { */a.Linear.M__i____j__ * v.__fj__/*# }, add); }, comma);*/); } /// /// Transforms a by the transpose of an (as a __m__x__m__ matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vmt__ TransposedTransform(this __type__ a, __vmt__ v) { return new __vmt__(/*# nfields.ForEach((fi, i) => { */ /*# nfields.ForEach((fj, j) => { */v.__fj__ * a.Linear.M__j____i__/*# }, add); }, comma);*/, /*# nfields.ForEach((f, i) => { */v.__f__ * a.Trans.__f__/*# }, add);*/ + v.__fn__); } /// /// Transforms a by the transpose of an (as a __m__x__m__ matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ TransposedTransform(this __type__ a, __vnt__ v) { return new __vnt__(/*# nfields.ForEach((fi, i) => { */ /*# nfields.ForEach((fj, j) => { */v.__fj__ * a.Linear.M__j____i__/*# }, add); }, comma);*/); } /// /// Transforms a position vector (v.__fn__ is presumed 1) by the transpose of an (as a __m__x__m__ matrix). /// Projective transform is performed. Perspective Division is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ TransposedTransformPosProj(this __type__ a, __vnt__ v) { var s = /*# nfields.ForEach(f => {*/v.__f__ * a.Trans.__f__/*# }, add);*/ + 1; return TransposedTransform(a, v) * (1 / s); } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a0, __type__ a1) { return ApproximateEquals(a0, a1, Constant<__ftype__>.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a0, __type__ a1, __ftype__ tolerance) { return ApproximateEquals(a0.Linear, a1.Linear, tolerance) && ApproximateEquals(a0.Trans, a1.Trans, tolerance); } #endregion } #endregion //# } //# } } ================================================ FILE: src/Aardvark.Base/Math/Trafos/CoordTransforms.cs ================================================ using static System.Math; namespace Aardvark.Base { /// /// Various coordinate transformations. /// /// Abbreviations: /// ll = lower left, lr = lower right, ul = upper left, ur = upper right /// /// 2D: /// Normalized Image Pos: /// Our coord-exchange format; Independent of reolution. /// (0,0)=ul edge of sensor = ul edge of ul pixel, (1,1) = lr edge of sensor = lr edge of lr pixel. /// /// Pixel Center: /// (0,0)=center of ul pixel, (w-1, h-1)=center of lr pixel. /// /// Pixel Edge: /// (0,0)=ul edge of ul pixel, (w-1, h-1)= lr edge of lr pixel. /// public static class CoordTransforms { public static readonly V2d V2dHalf = new V2d(0.5, 0.5); /// /// Convert from pixel-center position to normalized image position [0,1][0,1]. /// (The inverse of toPixelCenter.) /// /// The pixel location defined in pixel space: (0,0)=center of upper left pixel, (w-1,h-1)=center of lower right pixel. /// The size of the image (as V2d to safe lots of conversions). /// A normalized image position in [0,1][0,1]. public static V2d PixelCenterToNormalizedImgPos(V2d pos, V2d imgSizeInPixel) => (pos + V2dHalf) / imgSizeInPixel; public static V2d PixelCenterToNormalizedImgPos(V2i pos, V2d imgSizeInPixel) => PixelCenterToNormalizedImgPos((V2d)pos, imgSizeInPixel); public static V2d PixelCenterToNormalizedImgPos(int x, int y, V2d imgSizeInPixel) => PixelCenterToNormalizedImgPos(new V2d(x, y), imgSizeInPixel); /// /// Returns a Matrix to /// convert from pixel-center position to normalized image position [0,1][0,1]. /// (The inverse of toPixelCenter.) /// public static M33d PixelCenterToNormalizedImgMat(V2d imgSizeInPixel) => M33d.Scale(V2d.II / imgSizeInPixel) * M33d.Translation(V2dHalf); /// /// Convert from normalized image position [0,1][0,1] to pixel-center position /// (The inverse of toNormalizedImgPos.) /// /// The pixel location defined in pixel space: (0,0)=center of upper left pixel, (w-1,h-1)=center of lower right pixel. /// The size of the image (as V2d to safe lots of conversions). /// A image position in [-0.5,imgSizeInPixel.X-0.5][-0.5,imgSizeInPixel.Y-0.5]. public static V2d NormalizedImagePosToPixelCenter(V2d pos, V2i imgSizeInPixel) => new V2d(pos.X * imgSizeInPixel.X, pos.Y * imgSizeInPixel.Y) - V2dHalf; /// /// Convert from normalized image position [0,1][0,1] to pixel-center position /// (The inverse of toNormalizedImgPos.) /// /// The pixel location defined in pixel space: (0,0)=center of upper left pixel, (w-1,h-1)=center of lower right pixel. /// The size of the image (as V2d to safe lots of conversions). /// A image position in [-0.5,imgSizeInPixel.X-0.5][-0.5,imgSizeInPixel.Y-0.5]. public static V2d NormalizedImagePosToPixelCenter(V2d pos, V2l imgSizeInPixel) => new V2d(pos.X * imgSizeInPixel.X, pos.Y * imgSizeInPixel.Y) - V2dHalf; /// /// Convert from normalized image position [0,1][0,1] to already rounded pixel-center position. /// /// The pixel location defined in pixel space: (0,0)=center of upper left pixel, (w-1,h-1)=center of lower right pixel. /// The size of the image (as V2d to safe lots of conversions). /// A normalized image position in [0, imgSizeInPixel.X-1][0, imgSizeInPixel.Y-1]. public static V2i NormalizedImagePosToPixelCenterRound(V2d pos, V2i imgSizeInPixel) => (V2i)NormalizedImagePosToPixelCenter(pos, imgSizeInPixel).Copy(v => Round(v)); /// /// Convert from normalized image position [0,1][0,1] to already rounded pixel-center position. /// /// The pixel location defined in pixel space: (0,0)=center of upper left pixel, (w-1,h-1)=center of lower right pixel. /// The size of the image (as V2d to safe lots of conversions). /// A normalized image position in [0, imgSizeInPixel.X-1][0, imgSizeInPixel.Y-1]. public static V2l NormalizedImagePosToPixelCenterRound(V2d pos, V2l imgSizeInPixel) => (V2l)NormalizedImagePosToPixelCenter(pos, imgSizeInPixel).Copy(v => Round(v)); /// /// Returns a Matrix to /// convert from normalized image position [0,1][0,1] to pixel-center position /// (The inverse of toNormalizedImgPos.) /// public static M33d NormalizedImagePosToPixelCenterMat(V2d imgSizeInPixel) => M33d.Translation(-V2dHalf) * M33d.Scale(imgSizeInPixel); //[ISSUE 20090819 andi] add docu ///////////////////////// public static V2d PixelEdgeToNormalizedImgPos(V2d pos, V2d imgSizeInPixel) => pos / (imgSizeInPixel-1); public static V2d PixelEdgeToNormalizedImgPos(V2i pos, V2d imgSizeInPixel) => PixelEdgeToNormalizedImgPos((V2d)pos, imgSizeInPixel); public static M33d PixelEdgeToNormalizedImgMat(V2d imgSizeInPixel) => M33d.Scale(V2d.II / (imgSizeInPixel-1)); public static V2d NormalizedImagePosToPixelEdge(V2d pos, V2d imgSizeInPixel) => pos * (imgSizeInPixel-1); public static V2i NormalizedImagePosToPixelEdgeRound(V2d pos, V2d imgSizeInPixel) => (V2i)NormalizedImagePosToPixelEdge(pos, imgSizeInPixel).Copy(v => Round(v)); public static M33d NormalizedImagePosToPixelEdgeMat(V2d imgSizeInPixel) => M33d.Scale(imgSizeInPixel-1); } } ================================================ FILE: src/Aardvark.Base/Math/Trafos/CoordinateSystem.cs ================================================ using System; namespace Aardvark.Base { public static class CoordinateSystem { [Flags] public enum Axis { X = 1, Y = 2, Z = 4 } public enum Handedness { Left, Right } public struct Info { public double UnitScale; public Handedness Handedness; public Axis UpVector; public Info(double s, Handedness h, Axis u) { UnitScale = s; Handedness = h; UpVector = u; } public static readonly Info Vrml = new Info(1, Handedness.Right, Axis.Y); public static readonly Info Aardvark = new Info(1, Handedness.Right, Axis.Z); public readonly bool IsAardvark => Equals(Aardvark); public override readonly int GetHashCode() => HashCode.GetCombined(UnitScale, Handedness, UpVector); public override readonly bool Equals(object other) => (other is Info o) ? UnitScale.Equals(o.UnitScale) && (Handedness == o.Handedness) && (UpVector == o.UpVector) : false; public static bool operator ==(Info a, Info b) => a.UnitScale == b.UnitScale && a.Handedness == b.Handedness && a.UpVector == b.UpVector; public static bool operator !=(Info a, Info b) => a.UnitScale != b.UnitScale || a.Handedness != b.Handedness || a.UpVector != b.UpVector; } /// /// Creates a transformation from the specified coordinate system /// to the aardvark coordinate system (Meters, Right-Handed, Z-Up). /// public static Trafo3d ToAardvark(double scale, Handedness hand, Axis up) { var t = scale != 1 ? Trafo3d.Scale(scale) : Trafo3d.Identity; if (hand != Handedness.Right) t *= SwapHand; if (up != Axis.Z) t *= FromToRH(up, Axis.Z); return t; } /// /// Creates a transformation from the specified coordinate system /// to the aardvark coordinate system (Meters, Right-Handed, Z-Up). /// public static Trafo3d ToAardvark(this Info from) => ToAardvark(from.UnitScale, from.Handedness, from.UpVector); /// /// Creates a transformation from the specified coordinate system /// to the aardvark coordinate system (Meters, Right-Handed, Z-Up). /// public static Trafo3d ToAardvark(Handedness hand, Axis up) => ToAardvark(1, hand, up); /// /// Creates a transformation from the specified coordinate system /// to the aardvark coordinate system (Meters, Right-Handed, Z-Up). /// public static Trafo3d ToAardvark(Axis up) => ToAardvark(1, Handedness.Right, up); /// /// Creates a transformation from the specified coordinate system /// to the aardvark coordinate system (Meters, Right-Handed, Z-Up). /// public static Trafo3d ToAardvark(Handedness hand) => ToAardvark(1, hand, Axis.Z); /// /// Gets the cooresponding vector for a given axis /// public static V3d GetAxisVector(this Axis ax) => ax == Axis.X ? V3d.XAxis : (ax == Axis.Y ? V3d.YAxis : V3d.ZAxis); /// /// Builds transformation from one coordinate system to another. /// public static Trafo3d FromTo(Info from, Info to) { var t = Trafo3d.Identity; if (from.UnitScale != to.UnitScale) t = Trafo3d.Scale(to.UnitScale / from.UnitScale); if (from.Handedness != to.Handedness) t *= SwapHand; if (from.UpVector != to.UpVector) t *= FromToRH(from.UpVector, to.UpVector); return t; } static Trafo3d FromTo(Axis from, Axis to, int s) { if (from == to) return Trafo3d.Identity; var axis = (from == Axis.X || to == Axis.X) ? (from == Axis.Y || to == Axis.Y) ? Axis.Z : Axis.Y : Axis.X; var rotation = axis == Axis.X ? new M44d(1, 0, 0, 0, 0, 0,-s, 0, 0, s, 0, 0, 0, 0, 0, 1) : axis == Axis.Y ? new M44d(0, 0, s, 0, 0, 1, 0, 0, -s, 0, 0, 0, 0, 0, 0, 1) : new M44d(0,-s, 0, 0, s, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); return new Trafo3d(rotation, rotation.Transposed); } public static Trafo3d FromToRH(Axis from, Axis to) { var s = Fun.Sign(((int)to) - ((int)from)); // +/- sin(90°) return FromTo(from, to, s); } public static Trafo3d FromToLH(Axis from, Axis to) { var s = ((int)to) > ((int)from) ? -1 : 1; // +/- sin(90°) return FromTo(from, to, s); } static M44d s_swapHand = new M44d( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,-1, 0, 0, 0, 0, 1); public static readonly Trafo3d SwapHand = new Trafo3d(s_swapHand, s_swapHand); } public static class CoordinateSystemMatrixExtensions { /// /// Returns the handedness of the given transformation matrix that is assumed to be row-major. /// A right-handed coodinate system is given when /// (X cross Y) dot Z is positive, /// otherwise left-handed. /// public static CoordinateSystem.Handedness Handedness(this M44d mat) { var x = mat.R0.XYZ; var y = mat.R1.XYZ; var z = mat.R2.XYZ; return x.Cross(y).Dot(z) > 0 ? CoordinateSystem.Handedness.Right : CoordinateSystem.Handedness.Left; } } } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Euclidean_auto.cs ================================================ using System; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; namespace Aardvark.Base { #region Euclidean2f /// /// Represents a Rigid Transformation (or Rigid Body Transformation) in 2D that is composed of a /// 2D rotation Rot and a subsequent translation by a 2D vector Trans. /// This is also called an Euclidean Transformation and is a length preserving Transformation. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Euclidean2f : IEquatable { [DataMember] public Rot2f Rot; [DataMember] public V2f Trans; #region Constructors /// /// Constructs a copy of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean2f(Euclidean2f e) { Rot = e.Rot; Trans = e.Trans; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean2f(Euclidean2d e) { Rot = (Rot2f)e.Rot; Trans = (V2f)e.Trans; } /// /// Creates a rigid transformation from a rotation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean2f(Rot2f rot) { Rot = rot; Trans = V2f.Zero; } /// /// Creates a rigid transformation from a translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean2f(V2f trans) { Rot = Rot2f.Identity; Trans = trans; } /// /// Creates a rigid transformation from a translation by (, ). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean2f(float tX, float tY) { Rot = Rot2f.Identity; Trans = new V2f(tX, tY); } /// /// Creates a rigid transformation from a rotation and a (subsequent) translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean2f(Rot2f rot, V2f trans) { Rot = rot; Trans = trans; } /// /// Creates a rigid transformation from a rotation and a (subsequent) translation by (, ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean2f(Rot2f rot, float tX, float tY) { Rot = rot; Trans = new V2f(tX, tY); } #endregion #region Constants /// /// Gets the identity transformation. /// public static Euclidean2f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Euclidean2f(Rot2f.Identity, V2f.Zero); } #endregion #region Properties /// /// Gets the (multiplicative) inverse of this Euclidean transformation. /// [Rot^T,-Rot^T Trans] /// public readonly Euclidean2f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var newR = Rot.Inverse; return new Euclidean2f(newR, -newR.Transform(Trans)); } } #endregion #region Arithmetic Operators /// /// Multiplies two Euclidean transformations. /// This concatenates the two rigid transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f operator *(Euclidean2f a, Euclidean2f b) { //a.Rot * b.Rot, a.Trans + a.Rot * b.Trans return new Euclidean2f(a.Rot * b.Rot, a.Trans + a.Rot.Transform(b.Trans)); } /// /// Transforms a vector by a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator *(Euclidean2f e, V3f v) { var rot = (M22f)e.Rot; return new V3f( rot.M00 * v.X + rot.M01 * v.Y + e.Trans.X * v.Z, rot.M10 * v.X + rot.M11 * v.Y + e.Trans.Y * v.Z, v.Z); } /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator *(Euclidean2f e, M33f m) { var t = (M23f)e; return new M33f( t.M00 * m.M00 + t.M01 * m.M10 + t.M02 * m.M20, t.M00 * m.M01 + t.M01 * m.M11 + t.M02 * m.M21, t.M00 * m.M02 + t.M01 * m.M12 + t.M02 * m.M22, t.M10 * m.M00 + t.M11 * m.M10 + t.M12 * m.M20, t.M10 * m.M01 + t.M11 * m.M11 + t.M12 * m.M21, t.M10 * m.M02 + t.M11 * m.M12 + t.M12 * m.M22, m.M20, m.M21, m.M22); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator *(M33f m, Euclidean2f e) { var t = (M23f)e; return new M33f( m.M00 * t.M00 + m.M01 * t.M10, m.M00 * t.M01 + m.M01 * t.M11, m.M00 * t.M02 + m.M01 * t.M12 + m.M02, m.M10 * t.M00 + m.M11 * t.M10, m.M10 * t.M01 + m.M11 * t.M11, m.M10 * t.M02 + m.M11 * t.M12 + m.M12, m.M20 * t.M00 + m.M21 * t.M10, m.M20 * t.M01 + m.M21 * t.M11, m.M20 * t.M02 + m.M21 * t.M12 + m.M22); } /// /// Multiplies a transformation (as a 2x3 matrix) with a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(Euclidean2f e, M23f m) { var t = (M23f)e; return new M23f( t.M00 * m.M00 + t.M01 * m.M10, t.M00 * m.M01 + t.M01 * m.M11, t.M00 * m.M02 + t.M01 * m.M12 + t.M02, t.M10 * m.M00 + t.M11 * m.M10, t.M10 * m.M01 + t.M11 * m.M11, t.M10 * m.M02 + t.M11 * m.M12 + t.M12); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(M23f m, Euclidean2f e) { var t = (M23f)e; return new M23f( m.M00 * t.M00 + m.M01 * t.M10, m.M00 * t.M01 + m.M01 * t.M11, m.M00 * t.M02 + m.M01 * t.M12 + m.M02, m.M10 * t.M00 + m.M11 * t.M10, m.M10 * t.M01 + m.M11 * t.M11, m.M10 * t.M02 + m.M11 * t.M12 + m.M12); } /// /// Multiplies a (as a 2x3 matrix) and a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(Euclidean2f a, M22f m) => new M23f(a.Rot * m, a.Trans); /// /// Multiplies a and a (as a 2x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(M22f m, Euclidean2f a) => new M23f(m * a.Rot, m * a.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f operator *(Euclidean2f e, Rot2f r) => new Euclidean2f(e.Rot * r, e.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f operator *(Rot2f r, Euclidean2f e) => new Euclidean2f(r * e.Rot, r * e.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f operator *(Euclidean2f e, Shift2f s) { return new Euclidean2f(e.Rot, e.Rot * s.V + e.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f operator *(Shift2f s, Euclidean2f e) { return new Euclidean2f(e.Rot, e.Trans + s.V); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Euclidean2f r, Scale2f s) { var t = (M22f)r.Rot; return new Affine2f(new M22f( t.M00 * s.X, t.M01 * s.Y, t.M10 * s.X, t.M11 * s.Y), r.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Scale2f s, Euclidean2f r) { var t = (M22f)r.Rot; return new Affine2f(new M22f( t.M00 * s.X, t.M01 * s.X, t.M10 * s.Y, t.M11 * s.Y), r.Trans * s.V); } #endregion #region Comparison Operators public static bool operator ==(Euclidean2f r0, Euclidean2f r1) { return r0.Rot == r1.Rot && r0.Trans == r1.Trans; } public static bool operator !=(Euclidean2f r0, Euclidean2f r1) { return !(r0 == r1); } #endregion #region Static Creators /// /// Creates a transformation from a rotation matrix and a (subsequent) translation . /// The matrix must be a valid rotation matrix. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f FromM22fAndV2f(M22f rot, V2f trans) => new Euclidean2f(Rot2f.FromM22f(rot), trans); /// /// Creates a transformation from a matrix. /// The matrix has to be homogeneous and must not contain perspective components and its upper left 2x2 submatrix must be a valid rotation matrix. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f FromM33f(M33f m, float epsilon = 1e-5f) { if (!(m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (m.M22.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return FromM22fAndV2f(((M22f)m) / m.M22, m.C2.XY / m.M22); } /// /// Creates a transformation from a matrix. /// The left 2x2 submatrix of must be a valid rotation matrix. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f FromM23f(M23f m, float epsilon = 1e-5f) { return FromM22fAndV2f(((M22f)m), m.C2.XY); } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f FromSimilarity2f(Similarity2f similarity, float epsilon = 1e-5f) { if (!similarity.Scale.ApproximateEquals(1, epsilon)) throw new ArgumentException("Similarity transformation contains scaling component"); return similarity.Euclidean; } /// /// Creates a transformation from an . /// The transformation must only consist of a rotation and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f FromAffine2f(Affine2f affine, float epsilon = 1e-5f) => FromM33f((M33f)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a rotation and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f FromTrafo2f(Trafo2f trafo, float epsilon = 1e-5f) => FromM33f(trafo.Forward, epsilon); #region Translation /// /// Creates a transformation with the translational component given by 2 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f Translation(float tX, float tY) => new Euclidean2f(tX, tY); /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f Translation(V2f vector) => new Euclidean2f(vector); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f Translation(Shift2f shift) => new Euclidean2f(shift.V); #endregion #region Rotation /// /// Creates a rotation transformation from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f Rotation(Rot2f rot) => new Euclidean2f(rot); /// /// Creates a rotation transformation with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f Rotation(float angleInRadians) => new Euclidean2f(new Rot2f(angleInRadians)); /// /// Creates a rotation transformation with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f RotationInDegrees(float angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); #endregion #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M23f(Euclidean2f e) => new M23f((M22f)e.Rot, e.Trans); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M22f(Euclidean2f e) => (M22f)e.Rot; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33f(Euclidean2f e) { M33f rv = (M33f)e.Rot; rv.C2 = e.Trans.XYI; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Similarity2f(Euclidean2f e) => new Similarity2f(1, e); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine2f(Euclidean2f e) => new Affine2f((M22f)e.Rot, e.Trans); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo2f(Euclidean2f e) => new Trafo2f((M33f)e, (M33f)e.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Euclidean2d(Euclidean2f e) => new Euclidean2d((Rot2d)e.Rot, (V2d)e.Trans); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Rot, Trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Euclidean2f other) => Rot.Equals(other.Rot) && Trans.Equals(other.Trans); public override readonly bool Equals(object other) => (other is Euclidean2f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Rot, Trans); } public static Euclidean2f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Euclidean2f(Rot2f.Parse(x[0]), V2f.Parse(x[1])); } #endregion } public static partial class Euclidean { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f Inverse(Euclidean2f r) => r.Inverse; /// /// Inverts this rigid transformation (multiplicative inverse). /// this = [Rot^T,-Rot^T Trans] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Euclidean2f r) { r.Rot.Invert(); r.Trans = -r.Rot.Transform(r.Trans); } #endregion #region Transform /// /// Transforms a by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Transform(this Euclidean2f a, V3f v) => a * v; /// /// Transforms direction vector v (v.Z is presumed 0.0) by rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f TransformDir(this Euclidean2f r, V2f v) { return r.Rot.Transform(v); } /// /// Transforms point p (p.Z is presumed 1.0) by rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f TransformPos(this Euclidean2f r, V2f p) { return r.Rot.Transform(p) + r.Trans; } /// /// Transforms direction vector v (v.Z is presumed 0.0) by the inverse of the rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f InvTransformDir(this Euclidean2f r, V2f v) { return r.Rot.InvTransform(v); } /// /// Transforms point p (p.Z is presumed 1.0) by the inverse of the rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f InvTransformPos(this Euclidean2f r, V2f p) { return r.Rot.InvTransform(p - r.Trans); } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Euclidean2f r0, Euclidean2f r1) { return ApproximateEquals(r0, r1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Euclidean2f r0, Euclidean2f r1, float tol) { return ApproximateEquals(r0.Trans, r1.Trans, tol) && r0.Rot.ApproximateEquals(r1.Rot, tol); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Euclidean2f r0, Euclidean2f r1, float angleTol, float posTol) { return ApproximateEquals(r0.Trans, r1.Trans, posTol) && r0.Rot.ApproximateEquals(r1.Rot, angleTol); } #endregion } #endregion #region Euclidean3f /// /// Represents a Rigid Transformation (or Rigid Body Transformation) in 3D that is composed of a /// 3D rotation Rot and a subsequent translation by a 3D vector Trans. /// This is also called an Euclidean Transformation and is a length preserving Transformation. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Euclidean3f : IEquatable { [DataMember] public Rot3f Rot; [DataMember] public V3f Trans; #region Constructors /// /// Constructs a copy of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean3f(Euclidean3f e) { Rot = e.Rot; Trans = e.Trans; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean3f(Euclidean3d e) { Rot = (Rot3f)e.Rot; Trans = (V3f)e.Trans; } /// /// Creates a rigid transformation from a rotation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean3f(Rot3f rot) { Rot = rot; Trans = V3f.Zero; } /// /// Creates a rigid transformation from a translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean3f(V3f trans) { Rot = Rot3f.Identity; Trans = trans; } /// /// Creates a rigid transformation from a translation by (, , ). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean3f(float tX, float tY, float tZ) { Rot = Rot3f.Identity; Trans = new V3f(tX, tY, tZ); } /// /// Creates a rigid transformation from a rotation and a (subsequent) translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean3f(Rot3f rot, V3f trans) { Rot = rot; Trans = trans; } /// /// Creates a rigid transformation from a rotation and a (subsequent) translation by (, , ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean3f(Rot3f rot, float tX, float tY, float tZ) { Rot = rot; Trans = new V3f(tX, tY, tZ); } #endregion #region Constants /// /// Gets the identity transformation. /// public static Euclidean3f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Euclidean3f(Rot3f.Identity, V3f.Zero); } #endregion #region Properties /// /// Returns a new version of this Euclidean transformation with a normalized rotation quaternion. /// public readonly Euclidean3f Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Euclidean3f(Rot.Normalized, Trans); } /// /// Gets the (multiplicative) inverse of this Euclidean transformation. /// [Rot^T,-Rot^T Trans] /// public readonly Euclidean3f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var newR = Rot.Inverse; return new Euclidean3f(newR, -newR.Transform(Trans)); } } #endregion #region Arithmetic Operators /// /// Multiplies two Euclidean transformations. /// This concatenates the two rigid transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f operator *(Euclidean3f a, Euclidean3f b) { //a.Rot * b.Rot, a.Trans + a.Rot * b.Trans return new Euclidean3f(a.Rot * b.Rot, a.Trans + a.Rot.Transform(b.Trans)); } /// /// Transforms a vector by a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator *(Euclidean3f e, V4f v) { var rot = (M33f)e.Rot; return new V4f( rot.M00 * v.X + rot.M01 * v.Y + rot.M02 * v.Z + e.Trans.X * v.W, rot.M10 * v.X + rot.M11 * v.Y + rot.M12 * v.Z + e.Trans.Y * v.W, rot.M20 * v.X + rot.M21 * v.Y + rot.M22 * v.Z + e.Trans.Z * v.W, v.W); } /// /// Multiplies a transformation (as a 4x4 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator *(Euclidean3f e, M44f m) { var t = (M34f)e; return new M44f( t.M00 * m.M00 + t.M01 * m.M10 + t.M02 * m.M20 + t.M03 * m.M30, t.M00 * m.M01 + t.M01 * m.M11 + t.M02 * m.M21 + t.M03 * m.M31, t.M00 * m.M02 + t.M01 * m.M12 + t.M02 * m.M22 + t.M03 * m.M32, t.M00 * m.M03 + t.M01 * m.M13 + t.M02 * m.M23 + t.M03 * m.M33, t.M10 * m.M00 + t.M11 * m.M10 + t.M12 * m.M20 + t.M13 * m.M30, t.M10 * m.M01 + t.M11 * m.M11 + t.M12 * m.M21 + t.M13 * m.M31, t.M10 * m.M02 + t.M11 * m.M12 + t.M12 * m.M22 + t.M13 * m.M32, t.M10 * m.M03 + t.M11 * m.M13 + t.M12 * m.M23 + t.M13 * m.M33, t.M20 * m.M00 + t.M21 * m.M10 + t.M22 * m.M20 + t.M23 * m.M30, t.M20 * m.M01 + t.M21 * m.M11 + t.M22 * m.M21 + t.M23 * m.M31, t.M20 * m.M02 + t.M21 * m.M12 + t.M22 * m.M22 + t.M23 * m.M32, t.M20 * m.M03 + t.M21 * m.M13 + t.M22 * m.M23 + t.M23 * m.M33, m.M30, m.M31, m.M32, m.M33); } /// /// Multiplies a with a transformation (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator *(M44f m, Euclidean3f e) { var t = (M34f)e; return new M44f( m.M00 * t.M00 + m.M01 * t.M10 + m.M02 * t.M20, m.M00 * t.M01 + m.M01 * t.M11 + m.M02 * t.M21, m.M00 * t.M02 + m.M01 * t.M12 + m.M02 * t.M22, m.M00 * t.M03 + m.M01 * t.M13 + m.M02 * t.M23 + m.M03, m.M10 * t.M00 + m.M11 * t.M10 + m.M12 * t.M20, m.M10 * t.M01 + m.M11 * t.M11 + m.M12 * t.M21, m.M10 * t.M02 + m.M11 * t.M12 + m.M12 * t.M22, m.M10 * t.M03 + m.M11 * t.M13 + m.M12 * t.M23 + m.M13, m.M20 * t.M00 + m.M21 * t.M10 + m.M22 * t.M20, m.M20 * t.M01 + m.M21 * t.M11 + m.M22 * t.M21, m.M20 * t.M02 + m.M21 * t.M12 + m.M22 * t.M22, m.M20 * t.M03 + m.M21 * t.M13 + m.M22 * t.M23 + m.M23, m.M30 * t.M00 + m.M31 * t.M10 + m.M32 * t.M20, m.M30 * t.M01 + m.M31 * t.M11 + m.M32 * t.M21, m.M30 * t.M02 + m.M31 * t.M12 + m.M32 * t.M22, m.M30 * t.M03 + m.M31 * t.M13 + m.M32 * t.M23 + m.M33); } /// /// Multiplies a transformation (as a 3x4 matrix) with a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(Euclidean3f e, M34f m) { var t = (M34f)e; return new M34f( t.M00 * m.M00 + t.M01 * m.M10 + t.M02 * m.M20, t.M00 * m.M01 + t.M01 * m.M11 + t.M02 * m.M21, t.M00 * m.M02 + t.M01 * m.M12 + t.M02 * m.M22, t.M00 * m.M03 + t.M01 * m.M13 + t.M02 * m.M23 + t.M03, t.M10 * m.M00 + t.M11 * m.M10 + t.M12 * m.M20, t.M10 * m.M01 + t.M11 * m.M11 + t.M12 * m.M21, t.M10 * m.M02 + t.M11 * m.M12 + t.M12 * m.M22, t.M10 * m.M03 + t.M11 * m.M13 + t.M12 * m.M23 + t.M13, t.M20 * m.M00 + t.M21 * m.M10 + t.M22 * m.M20, t.M20 * m.M01 + t.M21 * m.M11 + t.M22 * m.M21, t.M20 * m.M02 + t.M21 * m.M12 + t.M22 * m.M22, t.M20 * m.M03 + t.M21 * m.M13 + t.M22 * m.M23 + t.M23); } /// /// Multiplies a with a transformation (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(M34f m, Euclidean3f e) { var t = (M34f)e; return new M34f( m.M00 * t.M00 + m.M01 * t.M10 + m.M02 * t.M20, m.M00 * t.M01 + m.M01 * t.M11 + m.M02 * t.M21, m.M00 * t.M02 + m.M01 * t.M12 + m.M02 * t.M22, m.M00 * t.M03 + m.M01 * t.M13 + m.M02 * t.M23 + m.M03, m.M10 * t.M00 + m.M11 * t.M10 + m.M12 * t.M20, m.M10 * t.M01 + m.M11 * t.M11 + m.M12 * t.M21, m.M10 * t.M02 + m.M11 * t.M12 + m.M12 * t.M22, m.M10 * t.M03 + m.M11 * t.M13 + m.M12 * t.M23 + m.M13, m.M20 * t.M00 + m.M21 * t.M10 + m.M22 * t.M20, m.M20 * t.M01 + m.M21 * t.M11 + m.M22 * t.M21, m.M20 * t.M02 + m.M21 * t.M12 + m.M22 * t.M22, m.M20 * t.M03 + m.M21 * t.M13 + m.M22 * t.M23 + m.M23); } /// /// Multiplies a (as a 3x4 matrix) and a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(Euclidean3f a, M33f m) => new M34f(a.Rot * m, a.Trans); /// /// Multiplies a and a (as a 3x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(M33f m, Euclidean3f a) => new M34f(m * a.Rot, m * a.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f operator *(Euclidean3f e, Rot3f r) => new Euclidean3f(e.Rot * r, e.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f operator *(Rot3f r, Euclidean3f e) => new Euclidean3f(r * e.Rot, r * e.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f operator *(Euclidean3f e, Shift3f s) { return new Euclidean3f(e.Rot, e.Rot * s.V + e.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f operator *(Shift3f s, Euclidean3f e) { return new Euclidean3f(e.Rot, e.Trans + s.V); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Euclidean3f r, Scale3f s) { var t = (M33f)r.Rot; return new Affine3f(new M33f( t.M00 * s.X, t.M01 * s.Y, t.M02 * s.Z, t.M10 * s.X, t.M11 * s.Y, t.M12 * s.Z, t.M20 * s.X, t.M21 * s.Y, t.M22 * s.Z), r.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Scale3f s, Euclidean3f r) { var t = (M33f)r.Rot; return new Affine3f(new M33f( t.M00 * s.X, t.M01 * s.X, t.M02 * s.X, t.M10 * s.Y, t.M11 * s.Y, t.M12 * s.Y, t.M20 * s.Z, t.M21 * s.Z, t.M22 * s.Z), r.Trans * s.V); } #endregion #region Comparison Operators public static bool operator ==(Euclidean3f r0, Euclidean3f r1) { return r0.Rot == r1.Rot && r0.Trans == r1.Trans; } public static bool operator !=(Euclidean3f r0, Euclidean3f r1) { return !(r0 == r1); } #endregion #region Static Creators /// /// Creates a transformation from a rotation matrix and a (subsequent) translation . /// The matrix must be a valid rotation matrix. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f FromM33fAndV3f(M33f rot, V3f trans, float epsilon = 1e-5f) => new Euclidean3f(Rot3f.FromM33f(rot, epsilon), trans); /// /// Creates a transformation from a matrix. /// The matrix has to be homogeneous and must not contain perspective components and its upper left 3x3 submatrix must be a valid rotation matrix. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f FromM44f(M44f m, float epsilon = 1e-5f) { if (!(m.M30.IsTiny(epsilon) && m.M31.IsTiny(epsilon) && m.M32.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (m.M33.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return FromM33fAndV3f(((M33f)m) / m.M33, m.C3.XYZ / m.M33, epsilon); } /// /// Creates a transformation from a matrix. /// The left 3x3 submatrix of must be a valid rotation matrix. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f FromM34f(M34f m, float epsilon = 1e-5f) { return FromM33fAndV3f(((M33f)m), m.C3.XYZ, epsilon); } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f FromSimilarity3f(Similarity3f similarity, float epsilon = 1e-5f) { if (!similarity.Scale.ApproximateEquals(1, epsilon)) throw new ArgumentException("Similarity transformation contains scaling component"); return similarity.Euclidean; } /// /// Creates a transformation from an . /// The transformation must only consist of a rotation and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f FromAffine3f(Affine3f affine, float epsilon = 1e-5f) => FromM44f((M44f)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a rotation and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f FromTrafo3f(Trafo3f trafo, float epsilon = 1e-5f) => FromM44f(trafo.Forward, epsilon); #region Translation /// /// Creates a transformation with the translational component given by 3 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f Translation(float tX, float tY, float tZ) => new Euclidean3f(tX, tY, tZ); /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f Translation(V3f vector) => new Euclidean3f(vector); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f Translation(Shift3f shift) => new Euclidean3f(shift.V); #endregion #region Rotation /// /// Creates a rotation transformation from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f Rotation(Rot3f rot) => new Euclidean3f(rot); /// /// Creates a rotation transformation from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f Rotation(V3f normalizedAxis, float angleRadians) => new Euclidean3f(Rot3f.Rotation(normalizedAxis, angleRadians)); /// /// Creates a rotation transformation from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f RotationInDegrees(V3f normalizedAxis, float angleDegrees) => Rotation(normalizedAxis, angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f RotationEuler(float rollInRadians, float pitchInRadians, float yawInRadians) => new Euclidean3f(Rot3f.RotationEuler(rollInRadians, pitchInRadians, yawInRadians)); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f RotationEulerInDegrees(float rollInDegrees, float pitchInDegrees, float yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f RotationEuler(V3f rollPitchYawInRadians) => RotationEuler(rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f RotationEulerInDegrees(V3f rollPitchYawInDegrees) => RotationEulerInDegrees( rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a rotation transformation which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f RotateInto(V3f from, V3f into) => new Euclidean3f(Rot3f.RotateInto(from, into)); /// /// Creates a rotation transformation by radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f RotationX(float angleRadians) => new Euclidean3f(Rot3f.RotationX(angleRadians)); /// /// Creates a rotation transformation for degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f RotationXInDegrees(float angleDegrees) => RotationX(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f RotationY(float angleRadians) => new Euclidean3f(Rot3f.RotationY(angleRadians)); /// /// Creates a rotation transformation for degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f RotationYInDegrees(float angleDegrees) => RotationY(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f RotationZ(float angleRadians) => new Euclidean3f(Rot3f.RotationZ(angleRadians)); /// /// Creates a rotation transformation for degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f RotationZInDegrees(float angleDegrees) => RotationZ(angleDegrees.RadiansFromDegrees()); #endregion #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34f(Euclidean3f e) => new M34f((M33f)e.Rot, e.Trans); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33f(Euclidean3f e) => (M33f)e.Rot; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44f(Euclidean3f e) { M44f rv = (M44f)e.Rot; rv.C3 = e.Trans.XYZI; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Similarity3f(Euclidean3f e) => new Similarity3f(1, e); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine3f(Euclidean3f e) => new Affine3f((M33f)e.Rot, e.Trans); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo3f(Euclidean3f e) => new Trafo3f((M44f)e, (M44f)e.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Euclidean3d(Euclidean3f e) => new Euclidean3d((Rot3d)e.Rot, (V3d)e.Trans); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Rot, Trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Euclidean3f other) => Rot.Equals(other.Rot) && Trans.Equals(other.Trans); public override readonly bool Equals(object other) => (other is Euclidean3f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Rot, Trans); } public static Euclidean3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Euclidean3f(Rot3f.Parse(x[0]), V3f.Parse(x[1])); } #endregion } public static partial class Euclidean { #region Normalize /// /// Returns a copy of a with its rotation quaternion normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f Normalized(Euclidean3f r) => r.Normalized; /// /// Normalizes the rotation quaternion of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref Euclidean3f r) { r.Rot.Normalize(); } #endregion #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f Inverse(Euclidean3f r) => r.Inverse; /// /// Inverts this rigid transformation (multiplicative inverse). /// this = [Rot^T,-Rot^T Trans] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Euclidean3f r) { r.Rot.Invert(); r.Trans = -r.Rot.Transform(r.Trans); } #endregion #region Transform /// /// Transforms a by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Transform(this Euclidean3f a, V4f v) => a * v; /// /// Transforms direction vector v (v.W is presumed 0.0) by rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransformDir(this Euclidean3f r, V3f v) { return r.Rot.Transform(v); } /// /// Transforms point p (p.W is presumed 1.0) by rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransformPos(this Euclidean3f r, V3f p) { return r.Rot.Transform(p) + r.Trans; } /// /// Transforms direction vector v (v.W is presumed 0.0) by the inverse of the rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvTransformDir(this Euclidean3f r, V3f v) { return r.Rot.InvTransform(v); } /// /// Transforms point p (p.W is presumed 1.0) by the inverse of the rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvTransformPos(this Euclidean3f r, V3f p) { return r.Rot.InvTransform(p - r.Trans); } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Euclidean3f r0, Euclidean3f r1) { return ApproximateEquals(r0, r1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Euclidean3f r0, Euclidean3f r1, float tol) { return ApproximateEquals(r0.Trans, r1.Trans, tol) && r0.Rot.ApproximateEquals(r1.Rot, tol); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Euclidean3f r0, Euclidean3f r1, float angleTol, float posTol) { return ApproximateEquals(r0.Trans, r1.Trans, posTol) && r0.Rot.ApproximateEquals(r1.Rot, angleTol); } #endregion } #endregion #region Euclidean2d /// /// Represents a Rigid Transformation (or Rigid Body Transformation) in 2D that is composed of a /// 2D rotation Rot and a subsequent translation by a 2D vector Trans. /// This is also called an Euclidean Transformation and is a length preserving Transformation. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Euclidean2d : IEquatable { [DataMember] public Rot2d Rot; [DataMember] public V2d Trans; #region Constructors /// /// Constructs a copy of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean2d(Euclidean2d e) { Rot = e.Rot; Trans = e.Trans; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean2d(Euclidean2f e) { Rot = (Rot2d)e.Rot; Trans = (V2d)e.Trans; } /// /// Creates a rigid transformation from a rotation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean2d(Rot2d rot) { Rot = rot; Trans = V2d.Zero; } /// /// Creates a rigid transformation from a translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean2d(V2d trans) { Rot = Rot2d.Identity; Trans = trans; } /// /// Creates a rigid transformation from a translation by (, ). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean2d(double tX, double tY) { Rot = Rot2d.Identity; Trans = new V2d(tX, tY); } /// /// Creates a rigid transformation from a rotation and a (subsequent) translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean2d(Rot2d rot, V2d trans) { Rot = rot; Trans = trans; } /// /// Creates a rigid transformation from a rotation and a (subsequent) translation by (, ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean2d(Rot2d rot, double tX, double tY) { Rot = rot; Trans = new V2d(tX, tY); } #endregion #region Constants /// /// Gets the identity transformation. /// public static Euclidean2d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Euclidean2d(Rot2d.Identity, V2d.Zero); } #endregion #region Properties /// /// Gets the (multiplicative) inverse of this Euclidean transformation. /// [Rot^T,-Rot^T Trans] /// public readonly Euclidean2d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var newR = Rot.Inverse; return new Euclidean2d(newR, -newR.Transform(Trans)); } } #endregion #region Arithmetic Operators /// /// Multiplies two Euclidean transformations. /// This concatenates the two rigid transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d operator *(Euclidean2d a, Euclidean2d b) { //a.Rot * b.Rot, a.Trans + a.Rot * b.Trans return new Euclidean2d(a.Rot * b.Rot, a.Trans + a.Rot.Transform(b.Trans)); } /// /// Transforms a vector by a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator *(Euclidean2d e, V3d v) { var rot = (M22d)e.Rot; return new V3d( rot.M00 * v.X + rot.M01 * v.Y + e.Trans.X * v.Z, rot.M10 * v.X + rot.M11 * v.Y + e.Trans.Y * v.Z, v.Z); } /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator *(Euclidean2d e, M33d m) { var t = (M23d)e; return new M33d( t.M00 * m.M00 + t.M01 * m.M10 + t.M02 * m.M20, t.M00 * m.M01 + t.M01 * m.M11 + t.M02 * m.M21, t.M00 * m.M02 + t.M01 * m.M12 + t.M02 * m.M22, t.M10 * m.M00 + t.M11 * m.M10 + t.M12 * m.M20, t.M10 * m.M01 + t.M11 * m.M11 + t.M12 * m.M21, t.M10 * m.M02 + t.M11 * m.M12 + t.M12 * m.M22, m.M20, m.M21, m.M22); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator *(M33d m, Euclidean2d e) { var t = (M23d)e; return new M33d( m.M00 * t.M00 + m.M01 * t.M10, m.M00 * t.M01 + m.M01 * t.M11, m.M00 * t.M02 + m.M01 * t.M12 + m.M02, m.M10 * t.M00 + m.M11 * t.M10, m.M10 * t.M01 + m.M11 * t.M11, m.M10 * t.M02 + m.M11 * t.M12 + m.M12, m.M20 * t.M00 + m.M21 * t.M10, m.M20 * t.M01 + m.M21 * t.M11, m.M20 * t.M02 + m.M21 * t.M12 + m.M22); } /// /// Multiplies a transformation (as a 2x3 matrix) with a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(Euclidean2d e, M23d m) { var t = (M23d)e; return new M23d( t.M00 * m.M00 + t.M01 * m.M10, t.M00 * m.M01 + t.M01 * m.M11, t.M00 * m.M02 + t.M01 * m.M12 + t.M02, t.M10 * m.M00 + t.M11 * m.M10, t.M10 * m.M01 + t.M11 * m.M11, t.M10 * m.M02 + t.M11 * m.M12 + t.M12); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(M23d m, Euclidean2d e) { var t = (M23d)e; return new M23d( m.M00 * t.M00 + m.M01 * t.M10, m.M00 * t.M01 + m.M01 * t.M11, m.M00 * t.M02 + m.M01 * t.M12 + m.M02, m.M10 * t.M00 + m.M11 * t.M10, m.M10 * t.M01 + m.M11 * t.M11, m.M10 * t.M02 + m.M11 * t.M12 + m.M12); } /// /// Multiplies a (as a 2x3 matrix) and a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(Euclidean2d a, M22d m) => new M23d(a.Rot * m, a.Trans); /// /// Multiplies a and a (as a 2x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(M22d m, Euclidean2d a) => new M23d(m * a.Rot, m * a.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d operator *(Euclidean2d e, Rot2d r) => new Euclidean2d(e.Rot * r, e.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d operator *(Rot2d r, Euclidean2d e) => new Euclidean2d(r * e.Rot, r * e.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d operator *(Euclidean2d e, Shift2d s) { return new Euclidean2d(e.Rot, e.Rot * s.V + e.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d operator *(Shift2d s, Euclidean2d e) { return new Euclidean2d(e.Rot, e.Trans + s.V); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Euclidean2d r, Scale2d s) { var t = (M22d)r.Rot; return new Affine2d(new M22d( t.M00 * s.X, t.M01 * s.Y, t.M10 * s.X, t.M11 * s.Y), r.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Scale2d s, Euclidean2d r) { var t = (M22d)r.Rot; return new Affine2d(new M22d( t.M00 * s.X, t.M01 * s.X, t.M10 * s.Y, t.M11 * s.Y), r.Trans * s.V); } #endregion #region Comparison Operators public static bool operator ==(Euclidean2d r0, Euclidean2d r1) { return r0.Rot == r1.Rot && r0.Trans == r1.Trans; } public static bool operator !=(Euclidean2d r0, Euclidean2d r1) { return !(r0 == r1); } #endregion #region Static Creators /// /// Creates a transformation from a rotation matrix and a (subsequent) translation . /// The matrix must be a valid rotation matrix. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d FromM22dAndV2d(M22d rot, V2d trans) => new Euclidean2d(Rot2d.FromM22d(rot), trans); /// /// Creates a transformation from a matrix. /// The matrix has to be homogeneous and must not contain perspective components and its upper left 2x2 submatrix must be a valid rotation matrix. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d FromM33d(M33d m, double epsilon = 1e-12) { if (!(m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (m.M22.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return FromM22dAndV2d(((M22d)m) / m.M22, m.C2.XY / m.M22); } /// /// Creates a transformation from a matrix. /// The left 2x2 submatrix of must be a valid rotation matrix. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d FromM23d(M23d m, double epsilon = 1e-12) { return FromM22dAndV2d(((M22d)m), m.C2.XY); } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d FromSimilarity2d(Similarity2d similarity, double epsilon = 1e-12) { if (!similarity.Scale.ApproximateEquals(1, epsilon)) throw new ArgumentException("Similarity transformation contains scaling component"); return similarity.Euclidean; } /// /// Creates a transformation from an . /// The transformation must only consist of a rotation and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d FromAffine2d(Affine2d affine, double epsilon = 1e-12) => FromM33d((M33d)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a rotation and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d FromTrafo2d(Trafo2d trafo, double epsilon = 1e-12) => FromM33d(trafo.Forward, epsilon); #region Translation /// /// Creates a transformation with the translational component given by 2 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d Translation(double tX, double tY) => new Euclidean2d(tX, tY); /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d Translation(V2d vector) => new Euclidean2d(vector); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d Translation(Shift2d shift) => new Euclidean2d(shift.V); #endregion #region Rotation /// /// Creates a rotation transformation from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d Rotation(Rot2d rot) => new Euclidean2d(rot); /// /// Creates a rotation transformation with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d Rotation(double angleInRadians) => new Euclidean2d(new Rot2d(angleInRadians)); /// /// Creates a rotation transformation with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d RotationInDegrees(double angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); #endregion #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M23d(Euclidean2d e) => new M23d((M22d)e.Rot, e.Trans); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M22d(Euclidean2d e) => (M22d)e.Rot; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33d(Euclidean2d e) { M33d rv = (M33d)e.Rot; rv.C2 = e.Trans.XYI; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Similarity2d(Euclidean2d e) => new Similarity2d(1, e); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine2d(Euclidean2d e) => new Affine2d((M22d)e.Rot, e.Trans); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo2d(Euclidean2d e) => new Trafo2d((M33d)e, (M33d)e.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Euclidean2f(Euclidean2d e) => new Euclidean2f((Rot2f)e.Rot, (V2f)e.Trans); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Rot, Trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Euclidean2d other) => Rot.Equals(other.Rot) && Trans.Equals(other.Trans); public override readonly bool Equals(object other) => (other is Euclidean2d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Rot, Trans); } public static Euclidean2d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Euclidean2d(Rot2d.Parse(x[0]), V2d.Parse(x[1])); } #endregion } public static partial class Euclidean { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d Inverse(Euclidean2d r) => r.Inverse; /// /// Inverts this rigid transformation (multiplicative inverse). /// this = [Rot^T,-Rot^T Trans] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Euclidean2d r) { r.Rot.Invert(); r.Trans = -r.Rot.Transform(r.Trans); } #endregion #region Transform /// /// Transforms a by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Transform(this Euclidean2d a, V3d v) => a * v; /// /// Transforms direction vector v (v.Z is presumed 0.0) by rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d TransformDir(this Euclidean2d r, V2d v) { return r.Rot.Transform(v); } /// /// Transforms point p (p.Z is presumed 1.0) by rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d TransformPos(this Euclidean2d r, V2d p) { return r.Rot.Transform(p) + r.Trans; } /// /// Transforms direction vector v (v.Z is presumed 0.0) by the inverse of the rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d InvTransformDir(this Euclidean2d r, V2d v) { return r.Rot.InvTransform(v); } /// /// Transforms point p (p.Z is presumed 1.0) by the inverse of the rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d InvTransformPos(this Euclidean2d r, V2d p) { return r.Rot.InvTransform(p - r.Trans); } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Euclidean2d r0, Euclidean2d r1) { return ApproximateEquals(r0, r1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Euclidean2d r0, Euclidean2d r1, double tol) { return ApproximateEquals(r0.Trans, r1.Trans, tol) && r0.Rot.ApproximateEquals(r1.Rot, tol); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Euclidean2d r0, Euclidean2d r1, double angleTol, double posTol) { return ApproximateEquals(r0.Trans, r1.Trans, posTol) && r0.Rot.ApproximateEquals(r1.Rot, angleTol); } #endregion } #endregion #region Euclidean3d /// /// Represents a Rigid Transformation (or Rigid Body Transformation) in 3D that is composed of a /// 3D rotation Rot and a subsequent translation by a 3D vector Trans. /// This is also called an Euclidean Transformation and is a length preserving Transformation. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Euclidean3d : IEquatable { [DataMember] public Rot3d Rot; [DataMember] public V3d Trans; #region Constructors /// /// Constructs a copy of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean3d(Euclidean3d e) { Rot = e.Rot; Trans = e.Trans; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean3d(Euclidean3f e) { Rot = (Rot3d)e.Rot; Trans = (V3d)e.Trans; } /// /// Creates a rigid transformation from a rotation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean3d(Rot3d rot) { Rot = rot; Trans = V3d.Zero; } /// /// Creates a rigid transformation from a translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean3d(V3d trans) { Rot = Rot3d.Identity; Trans = trans; } /// /// Creates a rigid transformation from a translation by (, , ). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean3d(double tX, double tY, double tZ) { Rot = Rot3d.Identity; Trans = new V3d(tX, tY, tZ); } /// /// Creates a rigid transformation from a rotation and a (subsequent) translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean3d(Rot3d rot, V3d trans) { Rot = rot; Trans = trans; } /// /// Creates a rigid transformation from a rotation and a (subsequent) translation by (, , ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Euclidean3d(Rot3d rot, double tX, double tY, double tZ) { Rot = rot; Trans = new V3d(tX, tY, tZ); } #endregion #region Constants /// /// Gets the identity transformation. /// public static Euclidean3d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Euclidean3d(Rot3d.Identity, V3d.Zero); } #endregion #region Properties /// /// Returns a new version of this Euclidean transformation with a normalized rotation quaternion. /// public readonly Euclidean3d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Euclidean3d(Rot.Normalized, Trans); } /// /// Gets the (multiplicative) inverse of this Euclidean transformation. /// [Rot^T,-Rot^T Trans] /// public readonly Euclidean3d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var newR = Rot.Inverse; return new Euclidean3d(newR, -newR.Transform(Trans)); } } #endregion #region Arithmetic Operators /// /// Multiplies two Euclidean transformations. /// This concatenates the two rigid transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d operator *(Euclidean3d a, Euclidean3d b) { //a.Rot * b.Rot, a.Trans + a.Rot * b.Trans return new Euclidean3d(a.Rot * b.Rot, a.Trans + a.Rot.Transform(b.Trans)); } /// /// Transforms a vector by a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator *(Euclidean3d e, V4d v) { var rot = (M33d)e.Rot; return new V4d( rot.M00 * v.X + rot.M01 * v.Y + rot.M02 * v.Z + e.Trans.X * v.W, rot.M10 * v.X + rot.M11 * v.Y + rot.M12 * v.Z + e.Trans.Y * v.W, rot.M20 * v.X + rot.M21 * v.Y + rot.M22 * v.Z + e.Trans.Z * v.W, v.W); } /// /// Multiplies a transformation (as a 4x4 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator *(Euclidean3d e, M44d m) { var t = (M34d)e; return new M44d( t.M00 * m.M00 + t.M01 * m.M10 + t.M02 * m.M20 + t.M03 * m.M30, t.M00 * m.M01 + t.M01 * m.M11 + t.M02 * m.M21 + t.M03 * m.M31, t.M00 * m.M02 + t.M01 * m.M12 + t.M02 * m.M22 + t.M03 * m.M32, t.M00 * m.M03 + t.M01 * m.M13 + t.M02 * m.M23 + t.M03 * m.M33, t.M10 * m.M00 + t.M11 * m.M10 + t.M12 * m.M20 + t.M13 * m.M30, t.M10 * m.M01 + t.M11 * m.M11 + t.M12 * m.M21 + t.M13 * m.M31, t.M10 * m.M02 + t.M11 * m.M12 + t.M12 * m.M22 + t.M13 * m.M32, t.M10 * m.M03 + t.M11 * m.M13 + t.M12 * m.M23 + t.M13 * m.M33, t.M20 * m.M00 + t.M21 * m.M10 + t.M22 * m.M20 + t.M23 * m.M30, t.M20 * m.M01 + t.M21 * m.M11 + t.M22 * m.M21 + t.M23 * m.M31, t.M20 * m.M02 + t.M21 * m.M12 + t.M22 * m.M22 + t.M23 * m.M32, t.M20 * m.M03 + t.M21 * m.M13 + t.M22 * m.M23 + t.M23 * m.M33, m.M30, m.M31, m.M32, m.M33); } /// /// Multiplies a with a transformation (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator *(M44d m, Euclidean3d e) { var t = (M34d)e; return new M44d( m.M00 * t.M00 + m.M01 * t.M10 + m.M02 * t.M20, m.M00 * t.M01 + m.M01 * t.M11 + m.M02 * t.M21, m.M00 * t.M02 + m.M01 * t.M12 + m.M02 * t.M22, m.M00 * t.M03 + m.M01 * t.M13 + m.M02 * t.M23 + m.M03, m.M10 * t.M00 + m.M11 * t.M10 + m.M12 * t.M20, m.M10 * t.M01 + m.M11 * t.M11 + m.M12 * t.M21, m.M10 * t.M02 + m.M11 * t.M12 + m.M12 * t.M22, m.M10 * t.M03 + m.M11 * t.M13 + m.M12 * t.M23 + m.M13, m.M20 * t.M00 + m.M21 * t.M10 + m.M22 * t.M20, m.M20 * t.M01 + m.M21 * t.M11 + m.M22 * t.M21, m.M20 * t.M02 + m.M21 * t.M12 + m.M22 * t.M22, m.M20 * t.M03 + m.M21 * t.M13 + m.M22 * t.M23 + m.M23, m.M30 * t.M00 + m.M31 * t.M10 + m.M32 * t.M20, m.M30 * t.M01 + m.M31 * t.M11 + m.M32 * t.M21, m.M30 * t.M02 + m.M31 * t.M12 + m.M32 * t.M22, m.M30 * t.M03 + m.M31 * t.M13 + m.M32 * t.M23 + m.M33); } /// /// Multiplies a transformation (as a 3x4 matrix) with a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(Euclidean3d e, M34d m) { var t = (M34d)e; return new M34d( t.M00 * m.M00 + t.M01 * m.M10 + t.M02 * m.M20, t.M00 * m.M01 + t.M01 * m.M11 + t.M02 * m.M21, t.M00 * m.M02 + t.M01 * m.M12 + t.M02 * m.M22, t.M00 * m.M03 + t.M01 * m.M13 + t.M02 * m.M23 + t.M03, t.M10 * m.M00 + t.M11 * m.M10 + t.M12 * m.M20, t.M10 * m.M01 + t.M11 * m.M11 + t.M12 * m.M21, t.M10 * m.M02 + t.M11 * m.M12 + t.M12 * m.M22, t.M10 * m.M03 + t.M11 * m.M13 + t.M12 * m.M23 + t.M13, t.M20 * m.M00 + t.M21 * m.M10 + t.M22 * m.M20, t.M20 * m.M01 + t.M21 * m.M11 + t.M22 * m.M21, t.M20 * m.M02 + t.M21 * m.M12 + t.M22 * m.M22, t.M20 * m.M03 + t.M21 * m.M13 + t.M22 * m.M23 + t.M23); } /// /// Multiplies a with a transformation (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(M34d m, Euclidean3d e) { var t = (M34d)e; return new M34d( m.M00 * t.M00 + m.M01 * t.M10 + m.M02 * t.M20, m.M00 * t.M01 + m.M01 * t.M11 + m.M02 * t.M21, m.M00 * t.M02 + m.M01 * t.M12 + m.M02 * t.M22, m.M00 * t.M03 + m.M01 * t.M13 + m.M02 * t.M23 + m.M03, m.M10 * t.M00 + m.M11 * t.M10 + m.M12 * t.M20, m.M10 * t.M01 + m.M11 * t.M11 + m.M12 * t.M21, m.M10 * t.M02 + m.M11 * t.M12 + m.M12 * t.M22, m.M10 * t.M03 + m.M11 * t.M13 + m.M12 * t.M23 + m.M13, m.M20 * t.M00 + m.M21 * t.M10 + m.M22 * t.M20, m.M20 * t.M01 + m.M21 * t.M11 + m.M22 * t.M21, m.M20 * t.M02 + m.M21 * t.M12 + m.M22 * t.M22, m.M20 * t.M03 + m.M21 * t.M13 + m.M22 * t.M23 + m.M23); } /// /// Multiplies a (as a 3x4 matrix) and a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(Euclidean3d a, M33d m) => new M34d(a.Rot * m, a.Trans); /// /// Multiplies a and a (as a 3x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(M33d m, Euclidean3d a) => new M34d(m * a.Rot, m * a.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d operator *(Euclidean3d e, Rot3d r) => new Euclidean3d(e.Rot * r, e.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d operator *(Rot3d r, Euclidean3d e) => new Euclidean3d(r * e.Rot, r * e.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d operator *(Euclidean3d e, Shift3d s) { return new Euclidean3d(e.Rot, e.Rot * s.V + e.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d operator *(Shift3d s, Euclidean3d e) { return new Euclidean3d(e.Rot, e.Trans + s.V); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Euclidean3d r, Scale3d s) { var t = (M33d)r.Rot; return new Affine3d(new M33d( t.M00 * s.X, t.M01 * s.Y, t.M02 * s.Z, t.M10 * s.X, t.M11 * s.Y, t.M12 * s.Z, t.M20 * s.X, t.M21 * s.Y, t.M22 * s.Z), r.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Scale3d s, Euclidean3d r) { var t = (M33d)r.Rot; return new Affine3d(new M33d( t.M00 * s.X, t.M01 * s.X, t.M02 * s.X, t.M10 * s.Y, t.M11 * s.Y, t.M12 * s.Y, t.M20 * s.Z, t.M21 * s.Z, t.M22 * s.Z), r.Trans * s.V); } #endregion #region Comparison Operators public static bool operator ==(Euclidean3d r0, Euclidean3d r1) { return r0.Rot == r1.Rot && r0.Trans == r1.Trans; } public static bool operator !=(Euclidean3d r0, Euclidean3d r1) { return !(r0 == r1); } #endregion #region Static Creators /// /// Creates a transformation from a rotation matrix and a (subsequent) translation . /// The matrix must be a valid rotation matrix. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d FromM33dAndV3d(M33d rot, V3d trans, double epsilon = 1e-12) => new Euclidean3d(Rot3d.FromM33d(rot, epsilon), trans); /// /// Creates a transformation from a matrix. /// The matrix has to be homogeneous and must not contain perspective components and its upper left 3x3 submatrix must be a valid rotation matrix. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d FromM44d(M44d m, double epsilon = 1e-12) { if (!(m.M30.IsTiny(epsilon) && m.M31.IsTiny(epsilon) && m.M32.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (m.M33.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return FromM33dAndV3d(((M33d)m) / m.M33, m.C3.XYZ / m.M33, epsilon); } /// /// Creates a transformation from a matrix. /// The left 3x3 submatrix of must be a valid rotation matrix. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d FromM34d(M34d m, double epsilon = 1e-12) { return FromM33dAndV3d(((M33d)m), m.C3.XYZ, epsilon); } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d FromSimilarity3d(Similarity3d similarity, double epsilon = 1e-12) { if (!similarity.Scale.ApproximateEquals(1, epsilon)) throw new ArgumentException("Similarity transformation contains scaling component"); return similarity.Euclidean; } /// /// Creates a transformation from an . /// The transformation must only consist of a rotation and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d FromAffine3d(Affine3d affine, double epsilon = 1e-12) => FromM44d((M44d)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a rotation and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d FromTrafo3d(Trafo3d trafo, double epsilon = 1e-12) => FromM44d(trafo.Forward, epsilon); #region Translation /// /// Creates a transformation with the translational component given by 3 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d Translation(double tX, double tY, double tZ) => new Euclidean3d(tX, tY, tZ); /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d Translation(V3d vector) => new Euclidean3d(vector); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d Translation(Shift3d shift) => new Euclidean3d(shift.V); #endregion #region Rotation /// /// Creates a rotation transformation from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d Rotation(Rot3d rot) => new Euclidean3d(rot); /// /// Creates a rotation transformation from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d Rotation(V3d normalizedAxis, double angleRadians) => new Euclidean3d(Rot3d.Rotation(normalizedAxis, angleRadians)); /// /// Creates a rotation transformation from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d RotationInDegrees(V3d normalizedAxis, double angleDegrees) => Rotation(normalizedAxis, angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d RotationEuler(double rollInRadians, double pitchInRadians, double yawInRadians) => new Euclidean3d(Rot3d.RotationEuler(rollInRadians, pitchInRadians, yawInRadians)); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d RotationEulerInDegrees(double rollInDegrees, double pitchInDegrees, double yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d RotationEuler(V3d rollPitchYawInRadians) => RotationEuler(rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d RotationEulerInDegrees(V3d rollPitchYawInDegrees) => RotationEulerInDegrees( rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a rotation transformation which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d RotateInto(V3d from, V3d into) => new Euclidean3d(Rot3d.RotateInto(from, into)); /// /// Creates a rotation transformation by radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d RotationX(double angleRadians) => new Euclidean3d(Rot3d.RotationX(angleRadians)); /// /// Creates a rotation transformation for degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d RotationXInDegrees(double angleDegrees) => RotationX(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d RotationY(double angleRadians) => new Euclidean3d(Rot3d.RotationY(angleRadians)); /// /// Creates a rotation transformation for degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d RotationYInDegrees(double angleDegrees) => RotationY(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d RotationZ(double angleRadians) => new Euclidean3d(Rot3d.RotationZ(angleRadians)); /// /// Creates a rotation transformation for degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d RotationZInDegrees(double angleDegrees) => RotationZ(angleDegrees.RadiansFromDegrees()); #endregion #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34d(Euclidean3d e) => new M34d((M33d)e.Rot, e.Trans); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33d(Euclidean3d e) => (M33d)e.Rot; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44d(Euclidean3d e) { M44d rv = (M44d)e.Rot; rv.C3 = e.Trans.XYZI; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Similarity3d(Euclidean3d e) => new Similarity3d(1, e); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine3d(Euclidean3d e) => new Affine3d((M33d)e.Rot, e.Trans); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo3d(Euclidean3d e) => new Trafo3d((M44d)e, (M44d)e.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Euclidean3f(Euclidean3d e) => new Euclidean3f((Rot3f)e.Rot, (V3f)e.Trans); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Rot, Trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Euclidean3d other) => Rot.Equals(other.Rot) && Trans.Equals(other.Trans); public override readonly bool Equals(object other) => (other is Euclidean3d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Rot, Trans); } public static Euclidean3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Euclidean3d(Rot3d.Parse(x[0]), V3d.Parse(x[1])); } #endregion } public static partial class Euclidean { #region Normalize /// /// Returns a copy of a with its rotation quaternion normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d Normalized(Euclidean3d r) => r.Normalized; /// /// Normalizes the rotation quaternion of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref Euclidean3d r) { r.Rot.Normalize(); } #endregion #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d Inverse(Euclidean3d r) => r.Inverse; /// /// Inverts this rigid transformation (multiplicative inverse). /// this = [Rot^T,-Rot^T Trans] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Euclidean3d r) { r.Rot.Invert(); r.Trans = -r.Rot.Transform(r.Trans); } #endregion #region Transform /// /// Transforms a by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Transform(this Euclidean3d a, V4d v) => a * v; /// /// Transforms direction vector v (v.W is presumed 0.0) by rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransformDir(this Euclidean3d r, V3d v) { return r.Rot.Transform(v); } /// /// Transforms point p (p.W is presumed 1.0) by rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransformPos(this Euclidean3d r, V3d p) { return r.Rot.Transform(p) + r.Trans; } /// /// Transforms direction vector v (v.W is presumed 0.0) by the inverse of the rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvTransformDir(this Euclidean3d r, V3d v) { return r.Rot.InvTransform(v); } /// /// Transforms point p (p.W is presumed 1.0) by the inverse of the rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvTransformPos(this Euclidean3d r, V3d p) { return r.Rot.InvTransform(p - r.Trans); } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Euclidean3d r0, Euclidean3d r1) { return ApproximateEquals(r0, r1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Euclidean3d r0, Euclidean3d r1, double tol) { return ApproximateEquals(r0.Trans, r1.Trans, tol) && r0.Rot.ApproximateEquals(r1.Rot, tol); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Euclidean3d r0, Euclidean3d r1, double angleTol, double posTol) { return ApproximateEquals(r0.Trans, r1.Trans, posTol) && r0.Rot.ApproximateEquals(r1.Rot, angleTol); } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Euclidean_template.cs ================================================ using System; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; namespace Aardvark.Base { //# Action comma = () => Out(", "); //# Action commaln = () => Out("," + Environment.NewLine); //# Action add = () => Out(" + "); //# Action and = () => Out(" && "); //# Action or = () => Out(" || "); //# Action andLit = () => Out(" and "); //# var fields = new[] {"X", "Y", "Z", "W"}; //# foreach (var isDouble in new[] { false, true }) { //# for (int n = 2; n <= 3; n++) { //# var m = n + 1; //# var ftype = isDouble ? "double" : "float"; //# var xyz = "XYZW".Substring(0, n); //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Euclidean" + n + tc; //# var type2 = "Euclidean" + n + tc2; //# var vnt = "V" + n + tc; //# var vnt2 = "V" + n + tc2; //# var vmt = "V" + m + tc; //# var mnnt = "M" + n + n + tc; //# var mmmt = "M" + m + m + tc; //# var mnmt = "M" + n + m + tc; //# var rotnt = "Rot" + n + tc; //# var rotnt2 = "Rot" + n + tc2; //# var trafont = "Trafo" + n + tc; //# var affinent = "Affine" + n + tc; //# var scalent = "Scale" + n + tc; //# var shiftnt = "Shift" + n + tc; //# var similaritynt = "Similarity" + n + tc; //# var nfields = fields.Take(n).ToArray(); //# var mfields = fields.Take(m).ToArray(); //# var fn = fields[n]; //# var eps = isDouble ? "1e-12" : "1e-5f"; #region __type__ /// /// Represents a Rigid Transformation (or Rigid Body Transformation) in __n__D that is composed of a /// __n__D rotation Rot and a subsequent translation by a __n__D vector Trans. /// This is also called an Euclidean Transformation and is a length preserving Transformation. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__> { [DataMember] public __rotnt__ Rot; [DataMember] public __vnt__ Trans; #region Constructors /// /// Constructs a copy of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ e) { Rot = e.Rot; Trans = e.Trans; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ e) { Rot = (__rotnt__)e.Rot; Trans = (__vnt__)e.Trans; } /// /// Creates a rigid transformation from a rotation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__rotnt__ rot) { Rot = rot; Trans = __vnt__.Zero; } /// /// Creates a rigid transformation from a translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__vnt__ trans) { Rot = __rotnt__.Identity; Trans = trans; } /// /// Creates a rigid transformation from a translation by (/*# nfields.ForEach(f => { *//*# }, comma);*/). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(/*# nfields.ForEach(f => { */__ftype__ t__f__/*# }, comma);*/) { Rot = __rotnt__.Identity; Trans = new __vnt__(/*# nfields.ForEach(f => { */t__f__/*# }, comma);*/); } /// /// Creates a rigid transformation from a rotation and a (subsequent) translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__rotnt__ rot, __vnt__ trans) { Rot = rot; Trans = trans; } /// /// Creates a rigid transformation from a rotation and a (subsequent) translation by (/*# nfields.ForEach(f => { *//*# }, comma);*/) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__rotnt__ rot, /*# nfields.ForEach(f => { */__ftype__ t__f__/*# }, comma);*/) { Rot = rot; Trans = new __vnt__(/*# nfields.ForEach(f => { */t__f__/*# }, comma);*/); } #endregion #region Constants /// /// Gets the identity transformation. /// public static __type__ Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(__rotnt__.Identity, __vnt__.Zero); } #endregion #region Properties //# if (n > 2) { /// /// Returns a new version of this Euclidean transformation with a normalized rotation quaternion. /// public readonly __type__ Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(Rot.Normalized, Trans); } //# } /// /// Gets the (multiplicative) inverse of this Euclidean transformation. /// [Rot^T,-Rot^T Trans] /// public readonly __type__ Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var newR = Rot.Inverse; return new __type__(newR, -newR.Transform(Trans)); } } #endregion #region Arithmetic Operators /// /// Multiplies two Euclidean transformations. /// This concatenates the two rigid transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ a, __type__ b) { //a.Rot * b.Rot, a.Trans + a.Rot * b.Trans return new __type__(a.Rot * b.Rot, a.Trans + a.Rot.Transform(b.Trans)); } /// /// Transforms a vector by a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vmt__ operator *(__type__ e, __vmt__ v) { var rot = (__mnnt__)e.Rot; return new __vmt__(/*# nfields.ForEach((fi, i) => { */ /*# mfields.ForEach((fj, j) => { var aij = (j < n) ? "rot.M" + i + j : "e.Trans." + fi; */__aij__ * v.__fj__/*# }, add); }, comma);*/, v.__fn__); } /// /// Multiplies a transformation (as a __m__x__m__ matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mmmt__ operator *(__type__ e, __mmmt__ m) { var t = (__mnmt__)e; return new __mmmt__(/*# n.ForEach(i => { m.ForEach(j => { */ /*# m.ForEach(k => { */t.M__i____k__ * m.M__k____j__/*# }, add); }, comma); }, commaln);*/, /*# m.ForEach(i => { */m.M__n____i__/*# }, comma);*/); } /// /// Multiplies a with a transformation (as a __m__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mmmt__ operator *(__mmmt__ m, __type__ e) { var t = (__mnmt__)e; return new __mmmt__(/*# m.ForEach(i => { m.ForEach(j => { */ /*# n.ForEach(k => { */m.M__i____k__ * t.M__k____j__/*# }, add); if (j == n) {*/ + m.M__i____n__/*# } }, comma); }, commaln);*/); } /// /// Multiplies a transformation (as a __n__x__m__ matrix) with a (as a __m__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mnmt__ operator *(__type__ e, __mnmt__ m) { var t = (__mnmt__)e; return new __mnmt__(/*# n.ForEach(i => { m.ForEach(j => { */ /*# n.ForEach(k => { */t.M__i____k__ * m.M__k____j__/*# }, add); if (j == n) {*/ + t.M__i____n__/*# } }, comma); }, commaln);*/); } /// /// Multiplies a with a transformation (as a __m__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mnmt__ operator *(__mnmt__ m, __type__ e) { var t = (__mnmt__)e; return new __mnmt__(/*# n.ForEach(i => { m.ForEach(j => { */ /*# n.ForEach(k => { */m.M__i____k__ * t.M__k____j__/*# }, add); if (j == n) {*/ + m.M__i____n__/*# } }, comma); }, commaln);*/); } /// /// Multiplies a (as a __n__x__m__ matrix) and a (as a __m__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mnmt__ operator *(__type__ a, __mnnt__ m) => new __mnmt__(a.Rot * m, a.Trans); /// /// Multiplies a and a (as a __n__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mnmt__ operator *(__mnnt__ m, __type__ a) => new __mnmt__(m * a.Rot, m * a.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ e, __rotnt__ r) => new __type__(e.Rot * r, e.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__rotnt__ r, __type__ e) => new __type__(r * e.Rot, r * e.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ e, __shiftnt__ s) { return new __type__(e.Rot, e.Rot * s.V + e.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__shiftnt__ s, __type__ e) { return new __type__(e.Rot, e.Trans + s.V); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __affinent__ operator *(__type__ r, __scalent__ s) { var t = (__mnnt__)r.Rot; return new __affinent__(new __mnnt__(/*# nfields.ForEach((fi, i) => { */ /*# nfields.ForEach((fj, j) => { */t.M__i____j__ * s.__fj__/*# }, comma); }, comma);*/), r.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __affinent__ operator *(__scalent__ s, __type__ r) { var t = (__mnnt__)r.Rot; return new __affinent__(new __mnnt__(/*# nfields.ForEach((fi, i) => { */ /*# nfields.ForEach((fj, j) => { */t.M__i____j__ * s.__fi__/*# }, comma); }, comma);*/), r.Trans * s.V); } #endregion #region Comparison Operators public static bool operator ==(__type__ r0, __type__ r1) { return r0.Rot == r1.Rot && r0.Trans == r1.Trans; } public static bool operator !=(__type__ r0, __type__ r1) { return !(r0 == r1); } #endregion #region Static Creators /// /// Creates a transformation from a rotation matrix and a (subsequent) translation . /// The matrix must be a valid rotation matrix. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] //# if (n == 2) { public static __type__ From__mnnt__And__vnt__(__mnnt__ rot, __vnt__ trans) => new __type__(__rotnt__.From__mnnt__(rot), trans); //# } else { public static __type__ From__mnnt__And__vnt__(__mnnt__ rot, __vnt__ trans, __ftype__ epsilon = __eps__) => new __type__(__rotnt__.From__mnnt__(rot, epsilon), trans); //# } /// /// Creates a transformation from a matrix. /// The matrix has to be homogeneous and must not contain perspective components and its upper left __n__x__n__ submatrix must be a valid rotation matrix. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__mmmt__(__mmmt__ m, __ftype__ epsilon = __eps__) { if (!(/*#n.ForEach(j => {*/m.M__n____j__.IsTiny(epsilon)/*# }, and);*/)) throw new ArgumentException("Matrix contains perspective components."); if (m.M__n____n__.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return From__mnnt__And__vnt__(((__mnnt__)m) / m.M__n____n__, m.C__n__.__xyz__ / m.M__n____n__/*# if (n > 2) {*/, epsilon/*# }*/); } /// /// Creates a transformation from a matrix. /// The left __n__x__n__ submatrix of must be a valid rotation matrix. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__mnmt__(__mnmt__ m, __ftype__ epsilon = __eps__) { return From__mnnt__And__vnt__(((__mnnt__)m), m.C__n__.__xyz__/*# if (n > 2) {*/, epsilon/*# }*/); } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__similaritynt__(__similaritynt__ similarity, __ftype__ epsilon = __eps__) { if (!similarity.Scale.ApproximateEquals(1, epsilon)) throw new ArgumentException("Similarity transformation contains scaling component"); return similarity.Euclidean; } /// /// Creates a transformation from an . /// The transformation must only consist of a rotation and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__affinent__(__affinent__ affine, __ftype__ epsilon = __eps__) => From__mmmt__((__mmmt__)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a rotation and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__trafont__(__trafont__ trafo, __ftype__ epsilon = __eps__) => From__mmmt__(trafo.Forward, epsilon); #region Translation /// /// Creates a transformation with the translational component given by __n__ scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Translation(/*# nfields.ForEach(f => { */__ftype__ t__f__/*# }, comma); */) => new __type__(/*# nfields.ForEach(f => { */t__f__/*# }, comma); */); /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Translation(__vnt__ vector) => new __type__(vector); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Translation(__shiftnt__ shift) => new __type__(shift.V); #endregion #region Rotation /// /// Creates a rotation transformation from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Rotation(__rotnt__ rot) => new __type__(rot); //# if (n == 2) { /// /// Creates a rotation transformation with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Rotation(__ftype__ angleInRadians) => new __type__(new __rotnt__(angleInRadians)); /// /// Creates a rotation transformation with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationInDegrees(__ftype__ angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); //# } else if (n == 3) { /// /// Creates a rotation transformation from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Rotation(__vnt__ normalizedAxis, __ftype__ angleRadians) => new __type__(__rotnt__.Rotation(normalizedAxis, angleRadians)); /// /// Creates a rotation transformation from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationInDegrees(__vnt__ normalizedAxis, __ftype__ angleDegrees) => Rotation(normalizedAxis, angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEuler(__ftype__ rollInRadians, __ftype__ pitchInRadians, __ftype__ yawInRadians) => new __type__(__rotnt__.RotationEuler(rollInRadians, pitchInRadians, yawInRadians)); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEulerInDegrees(__ftype__ rollInDegrees, __ftype__ pitchInDegrees, __ftype__ yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEuler(__vnt__ rollPitchYawInRadians) => RotationEuler(rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEulerInDegrees(__vnt__ rollPitchYawInDegrees) => RotationEulerInDegrees( rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a rotation transformation which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotateInto(__vnt__ from, __vnt__ into) => new __type__(__rotnt__.RotateInto(from, into)); /// /// Creates a rotation transformation by radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationX(__ftype__ angleRadians) => new __type__(__rotnt__.RotationX(angleRadians)); /// /// Creates a rotation transformation for degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationXInDegrees(__ftype__ angleDegrees) => RotationX(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationY(__ftype__ angleRadians) => new __type__(__rotnt__.RotationY(angleRadians)); /// /// Creates a rotation transformation for degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationYInDegrees(__ftype__ angleDegrees) => RotationY(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationZ(__ftype__ angleRadians) => new __type__(__rotnt__.RotationZ(angleRadians)); /// /// Creates a rotation transformation for degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationZInDegrees(__ftype__ angleDegrees) => RotationZ(angleDegrees.RadiansFromDegrees()); //# } #endregion #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __mnmt__(__type__ e) => new __mnmt__((__mnnt__)e.Rot, e.Trans); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __mnnt__(__type__ e) => (__mnnt__)e.Rot; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __mmmt__(__type__ e) { __mmmt__ rv = (__mmmt__)e.Rot; rv.C__n__ = e.Trans.__xyz__I; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __similaritynt__(__type__ e) => new __similaritynt__(1, e); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __affinent__(__type__ e) => new __affinent__((__mnnt__)e.Rot, e.Trans); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __trafont__(__type__ e) => new __trafont__((__mmmt__)e, (__mmmt__)e.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type2__(__type__ e) => new __type2__((__rotnt2__)e.Rot, (__vnt2__)e.Trans); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Rot, Trans); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => Rot.Equals(other.Rot) && Trans.Equals(other.Trans); public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Rot, Trans); } public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__(__rotnt__.Parse(x[0]), __vnt__.Parse(x[1])); } #endregion } public static partial class Euclidean { //# if (n > 2) { #region Normalize /// /// Returns a copy of a with its rotation quaternion normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Normalized(__type__ r) => r.Normalized; /// /// Normalizes the rotation quaternion of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref __type__ r) { r.Rot.Normalize(); } #endregion //# } #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Inverse(__type__ r) => r.Inverse; /// /// Inverts this rigid transformation (multiplicative inverse). /// this = [Rot^T,-Rot^T Trans] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref __type__ r) { r.Rot.Invert(); r.Trans = -r.Rot.Transform(r.Trans); } #endregion #region Transform /// /// Transforms a by an . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vmt__ Transform(this __type__ a, __vmt__ v) => a * v; /// /// Transforms direction vector v (v.__fn__ is presumed 0.0) by rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ TransformDir(this __type__ r, __vnt__ v) { return r.Rot.Transform(v); } /// /// Transforms point p (p.__fn__ is presumed 1.0) by rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ TransformPos(this __type__ r, __vnt__ p) { return r.Rot.Transform(p) + r.Trans; } /// /// Transforms direction vector v (v.__fn__ is presumed 0.0) by the inverse of the rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ InvTransformDir(this __type__ r, __vnt__ v) { return r.Rot.InvTransform(v); } /// /// Transforms point p (p.__fn__ is presumed 1.0) by the inverse of the rigid transformation r. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ InvTransformPos(this __type__ r, __vnt__ p) { return r.Rot.InvTransform(p - r.Trans); } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ r0, __type__ r1) { return ApproximateEquals(r0, r1, Constant<__ftype__>.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ r0, __type__ r1, __ftype__ tol) { return ApproximateEquals(r0.Trans, r1.Trans, tol) && r0.Rot.ApproximateEquals(r1.Rot, tol); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ r0, __type__ r1, __ftype__ angleTol, __ftype__ posTol) { return ApproximateEquals(r0.Trans, r1.Trans, posTol) && r0.Rot.ApproximateEquals(r1.Rot, angleTol); } #endregion } #endregion //# } } } ================================================ FILE: src/Aardvark.Base/Math/Trafos/M33_auto.cs ================================================ using System; using System.Text; using System.Runtime.CompilerServices; namespace Aardvark.Base { public partial struct M33f { #region Coordinate-System Transforms /// /// Creates an orthonormal basis from the given normal as z-axis. /// The resulting matrix transforms from the local to the global coordinate system. /// The normal is expected to be normalized. /// /// The implementation is based on: /// Building an Orthonormal Basis, Revisited, by Duff et al. 2017 /// public static M33f NormalFrame(V3f n) { var sg = n.Z >= 0 ? 1 : -1; // original uses copysign(1.0, n.Z) -> not the same as sign where 0 -> 0 var a = -1 / (sg + n.Z); var b = n.X * n.Y * a; // column 0: [1 + sg * n.X * n.X * a, sg * b, -sg * n.X] // column 1: [b, sg + n.Y * n.Y * a, -n.Y] // column 2: n return new M33f(1 + sg * n.X * n.X * a, b, n.X, sg * b, sg + n.Y * n.Y * a, n.Y, -sg * n.X, -n.Y, n.Z); } /// /// Computes from a normal the transformation matrix /// from the local coordinate system where the normal is the z-axis to /// the global coordinate system. /// /// The normal vector of the new ground plane. public static M33f NormalFrameLocal2Global(V3f normal) { V3f min; double x = Fun.Abs(normal.X); double y = Fun.Abs(normal.Y); double z = Fun.Abs(normal.Z); if (x < y) { if (x < z) { min = V3f.XAxis; } else { min = V3f.ZAxis; } } else { if (y < z) { min = V3f.YAxis; } else { min = V3f.ZAxis; } } var xVec = Vec.Cross(normal, min); xVec.Normalize(); // this is now guaranteed to be normal to the input normal var yVec = Vec.Cross(normal, xVec); yVec.Normalize(); var zVec = normal; zVec.Normalize(); return new M33f(xVec.X, yVec.X, zVec.X, xVec.Y, yVec.Y, zVec.Y, xVec.Z, yVec.Z, zVec.Z); } #endregion } public partial struct M33d { #region Coordinate-System Transforms /// /// Creates an orthonormal basis from the given normal as z-axis. /// The resulting matrix transforms from the local to the global coordinate system. /// The normal is expected to be normalized. /// /// The implementation is based on: /// Building an Orthonormal Basis, Revisited, by Duff et al. 2017 /// public static M33d NormalFrame(V3d n) { var sg = n.Z >= 0 ? 1 : -1; // original uses copysign(1.0, n.Z) -> not the same as sign where 0 -> 0 var a = -1 / (sg + n.Z); var b = n.X * n.Y * a; // column 0: [1 + sg * n.X * n.X * a, sg * b, -sg * n.X] // column 1: [b, sg + n.Y * n.Y * a, -n.Y] // column 2: n return new M33d(1 + sg * n.X * n.X * a, b, n.X, sg * b, sg + n.Y * n.Y * a, n.Y, -sg * n.X, -n.Y, n.Z); } /// /// Computes from a normal the transformation matrix /// from the local coordinate system where the normal is the z-axis to /// the global coordinate system. /// /// The normal vector of the new ground plane. public static M33d NormalFrameLocal2Global(V3d normal) { V3d min; double x = Fun.Abs(normal.X); double y = Fun.Abs(normal.Y); double z = Fun.Abs(normal.Z); if (x < y) { if (x < z) { min = V3d.XAxis; } else { min = V3d.ZAxis; } } else { if (y < z) { min = V3d.YAxis; } else { min = V3d.ZAxis; } } var xVec = Vec.Cross(normal, min); xVec.Normalize(); // this is now guaranteed to be normal to the input normal var yVec = Vec.Cross(normal, xVec); yVec.Normalize(); var zVec = normal; zVec.Normalize(); return new M33d(xVec.X, yVec.X, zVec.X, xVec.Y, yVec.Y, zVec.Y, xVec.Z, yVec.Z, zVec.Z); } #endregion } } ================================================ FILE: src/Aardvark.Base/Math/Trafos/M33_template.cs ================================================ using System; using System.Text; using System.Runtime.CompilerServices; namespace Aardvark.Base { //# foreach (var isDouble in new[] { false, true }) { //# var ft = isDouble ? "double" : "float"; //# var x2t = isDouble ? "2d" : "2f"; //# var x3t = isDouble ? "3d" : "3f"; //# var x4t = isDouble ? "4d" : "4f"; public partial struct M3__x3t__ { #region Coordinate-System Transforms /// /// Creates an orthonormal basis from the given normal as z-axis. /// The resulting matrix transforms from the local to the global coordinate system. /// The normal is expected to be normalized. /// /// The implementation is based on: /// Building an Orthonormal Basis, Revisited, by Duff et al. 2017 /// public static M3__x3t__ NormalFrame(V__x3t__ n) { var sg = n.Z >= 0 ? 1 : -1; // original uses copysign(1.0, n.Z) -> not the same as sign where 0 -> 0 var a = -1 / (sg + n.Z); var b = n.X * n.Y * a; // column 0: [1 + sg * n.X * n.X * a, sg * b, -sg * n.X] // column 1: [b, sg + n.Y * n.Y * a, -n.Y] // column 2: n return new M3__x3t__(1 + sg * n.X * n.X * a, b, n.X, sg * b, sg + n.Y * n.Y * a, n.Y, -sg * n.X, -n.Y, n.Z); } /// /// Computes from a normal the transformation matrix /// from the local coordinate system where the normal is the z-axis to /// the global coordinate system. /// /// The normal vector of the new ground plane. public static M3__x3t__ NormalFrameLocal2Global(V__x3t__ normal) { V__x3t__ min; double x = Fun.Abs(normal.X); double y = Fun.Abs(normal.Y); double z = Fun.Abs(normal.Z); if (x < y) { if (x < z) { min = V__x3t__.XAxis; } else { min = V__x3t__.ZAxis; } } else { if (y < z) { min = V__x3t__.YAxis; } else { min = V__x3t__.ZAxis; } } var xVec = Vec.Cross(normal, min); xVec.Normalize(); // this is now guaranteed to be normal to the input normal var yVec = Vec.Cross(normal, xVec); yVec.Normalize(); var zVec = normal; zVec.Normalize(); return new M3__x3t__(xVec.X, yVec.X, zVec.X, xVec.Y, yVec.Y, zVec.Y, xVec.Z, yVec.Z, zVec.Z); } #endregion } //# } } ================================================ FILE: src/Aardvark.Base/Math/Trafos/M44_auto.cs ================================================ using System; using System.Text; namespace Aardvark.Base { #region M44f public partial struct M44f { #region Coordinate-System Transforms /// /// Computes from a point (origin) and /// a normal the transformation matrix /// and its inverse. /// /// The point which will become the new origin. /// The normal vector of the new ground plane. /// A The trafo from local to global system. /// A The trafofrom global to local system. public static void NormalFrame(V3f origin, V3f normal, out M44f local2global, out M44f global2local ) { V3f min; float x = Fun.Abs(normal.X); float y = Fun.Abs(normal.Y); float z = Fun.Abs(normal.Z); if (x < y) { if (x < z) { min = V3f.XAxis; } else { min = V3f.ZAxis; } } else { if (y < z) { min = V3f.YAxis; } else { min = V3f.ZAxis; } } V3f xVec = Vec.Cross(normal, min); xVec.Normalize(); // this is now guaranteed to be normal to the input normal V3f yVec = Vec.Cross(normal, xVec); yVec.Normalize(); V3f zVec = normal; zVec.Normalize(); local2global = new M44f(xVec.X, yVec.X, zVec.X, origin.X, xVec.Y, yVec.Y, zVec.Y, origin.Y, xVec.Z, yVec.Z, zVec.Z, origin.Z, 0, 0, 0, 1); M44f mat = new M44f(xVec.X, xVec.Y, xVec.Z, 0, yVec.X, yVec.Y, yVec.Z, 0, zVec.X, zVec.Y, zVec.Z, 0, 0, 0, 0, 1); var shift = M44f.Translation(-origin); global2local = mat * shift; } /// /// Computes a Coordiante Frame Transformation (Basis) from current CS into /// the (X, Y, Z)-System at a given Origin. /// Note: you can use it, to transform from RH to LH and vice-versa, all depending /// how you will specifie your new basis-vectors. /// /// New X Vector /// New Y Vector /// New Z vector /// New Origin. /// /// public static void CoordinateFrameTransform(V3f xVec, V3f yVec, V3f zVec, V3f oVec, out M44f viewTrafo, out M44f viewTrafoInverse) { oVec = -oVec; viewTrafo = new M44f( xVec.X, xVec.Y, xVec.Z, xVec.X * oVec.X + xVec.Y * oVec.Y + xVec.Z * oVec.Z, yVec.X, yVec.Y, yVec.Z, yVec.X * oVec.X + yVec.Y * oVec.Y + yVec.Z * oVec.Z, zVec.X, zVec.Y, zVec.Z, zVec.X * oVec.X + zVec.Y * oVec.Y + zVec.Z * oVec.Z, 0, 0, 0, 1 ); viewTrafoInverse = new M44f( xVec.X, yVec.X, zVec.X, -oVec.X, xVec.Y, yVec.Y, zVec.Y, -oVec.Y, xVec.Z, yVec.Z, zVec.Z, -oVec.Z, 0, 0, 0, 1 ); } /// /// Provides perspective projection matrix in terms of the vertical field of view angle a and the aspect ratio r. /// public static M44f PerspectiveProjectionTransformRH(float a, float r, float n, float f) { //F / r 0 0 0 // 0 F 0 0 // 0 0 A B // 0 0 -1 0 float F = 1 / Fun.Tan(a / 2); float A = f / (n - f); float B = f * n / (n - f); M44f P = new M44f( F / r, 0, 0, 0, 0, F, 0, 0, 0, 0, A, B, 0, 0, -1, 0); return P; } /// /// Provides perspective projection matrix. /// The parameters describe the dimensions of the view volume. /// public static M44f PerspectiveProjectionTransformRH(V2f size, float n, float f) { float w = size.X; float h = size.Y; // Fx 0 0 0 // 0 Fy 0 0 // 0 0 A B // 0 0 -1 0 float Fx = 2 * n / w; float Fy = 2 * n / h; float A = f / (n - f); float B = n * f / (n - f); M44f P = new M44f( Fx, 0, 0, 0, 0, Fy, 0, 0, 0, 0, A, B, 0, 0, -1, 0); return P; } /// /// Builds a customized, right-handed perspective Off-Center projection matrix. /// public static M44f PerspectiveProjectionTransformRH(float l, float r, float t, float b, float n, float f) { // Fx 0 Sx 0 // 0 Fy Sy 0 // 0 0 A B // 0 0 -1 0 float Fx = 2 * n / (r - l); float Fy = 2 * n / (t - b); float Sx = (l + r) / (r - l); float Sy = (t + b) / (t - b); float A = f / (n - f); float B = n * f / (n - f); M44f P = new M44f( Fx, 0, Sx, 0, 0, Fy, Sy, 0, 0, 0, A, B, 0, 0, -1, 0); return P; } #endregion #region Static creators /// /// Returns the matrix that transforms from the coordinate system /// specified by the basis into the world cordinate system. /// public static M44f FromBasis(V3f xAxis, V3f yAxis, V3f zAxis, V3f origin) { return new M44f( xAxis.X, yAxis.X, zAxis.X, origin.X, xAxis.Y, yAxis.Y, zAxis.Y, origin.Y, xAxis.Z, yAxis.Z, zAxis.Z, origin.Z, 0, 0, 0, 1); } /// /// Creates a view tranformation from the given vectors. /// Transformation from world- into view-space. /// /// Origin of the view /// Right vector of the view-plane /// Up vector of the view-plane /// Normal vector of the view-plane. This vector is suppsoed to point in view-direction for a left-handed view transformation and in opposit direction in the right-handed case. /// The view transformation public static M44f ViewTrafo(V3f location, V3f right, V3f up, V3f normal) { return new M44f( right.X, right.Y, right.Z, -location.Dot(right), up.X, up.Y, up.Z, -location.Dot(up), normal.X, normal.Y, normal.Z, -location.Dot(normal), 0, 0, 0, 1 ); } /// /// Creates a inverse view tranformation from the given vectors. /// Transformation from view- into world-space. /// The implementation is the same as FromBasis(right, up, normal, location) /// /// Origin of the view /// Right vector of the view-plane /// Up vector of the view-plane /// Normal vector of the view-plane. This vector is suppsoed to point in view-direction for a left-handed view transformation and in opposit direction in the right-handed case. /// The inverse view transformation public static M44f InvViewTrafo(V3f location, V3f right, V3f up, V3f normal) { return new M44f( right.X, up.X, normal.X, location.X, right.Y, up.Y, normal.Y, location.Y, right.Z, up.Z, normal.Z, location.Z, 0, 0, 0, 1 ); } #endregion } #endregion #region M44d public partial struct M44d { #region Coordinate-System Transforms /// /// Computes from a point (origin) and /// a normal the transformation matrix /// and its inverse. /// /// The point which will become the new origin. /// The normal vector of the new ground plane. /// A The trafo from local to global system. /// A The trafofrom global to local system. public static void NormalFrame(V3d origin, V3d normal, out M44d local2global, out M44d global2local ) { V3d min; double x = Fun.Abs(normal.X); double y = Fun.Abs(normal.Y); double z = Fun.Abs(normal.Z); if (x < y) { if (x < z) { min = V3d.XAxis; } else { min = V3d.ZAxis; } } else { if (y < z) { min = V3d.YAxis; } else { min = V3d.ZAxis; } } V3d xVec = Vec.Cross(normal, min); xVec.Normalize(); // this is now guaranteed to be normal to the input normal V3d yVec = Vec.Cross(normal, xVec); yVec.Normalize(); V3d zVec = normal; zVec.Normalize(); local2global = new M44d(xVec.X, yVec.X, zVec.X, origin.X, xVec.Y, yVec.Y, zVec.Y, origin.Y, xVec.Z, yVec.Z, zVec.Z, origin.Z, 0, 0, 0, 1); M44d mat = new M44d(xVec.X, xVec.Y, xVec.Z, 0, yVec.X, yVec.Y, yVec.Z, 0, zVec.X, zVec.Y, zVec.Z, 0, 0, 0, 0, 1); var shift = M44d.Translation(-origin); global2local = mat * shift; } /// /// Computes a Coordiante Frame Transformation (Basis) from current CS into /// the (X, Y, Z)-System at a given Origin. /// Note: you can use it, to transform from RH to LH and vice-versa, all depending /// how you will specifie your new basis-vectors. /// /// New X Vector /// New Y Vector /// New Z vector /// New Origin. /// /// public static void CoordinateFrameTransform(V3d xVec, V3d yVec, V3d zVec, V3d oVec, out M44d viewTrafo, out M44d viewTrafoInverse) { oVec = -oVec; viewTrafo = new M44d( xVec.X, xVec.Y, xVec.Z, xVec.X * oVec.X + xVec.Y * oVec.Y + xVec.Z * oVec.Z, yVec.X, yVec.Y, yVec.Z, yVec.X * oVec.X + yVec.Y * oVec.Y + yVec.Z * oVec.Z, zVec.X, zVec.Y, zVec.Z, zVec.X * oVec.X + zVec.Y * oVec.Y + zVec.Z * oVec.Z, 0, 0, 0, 1 ); viewTrafoInverse = new M44d( xVec.X, yVec.X, zVec.X, -oVec.X, xVec.Y, yVec.Y, zVec.Y, -oVec.Y, xVec.Z, yVec.Z, zVec.Z, -oVec.Z, 0, 0, 0, 1 ); } /// /// Provides perspective projection matrix in terms of the vertical field of view angle a and the aspect ratio r. /// public static M44d PerspectiveProjectionTransformRH(double a, double r, double n, double f) { //F / r 0 0 0 // 0 F 0 0 // 0 0 A B // 0 0 -1 0 double F = 1 / Fun.Tan(a / 2); double A = f / (n - f); double B = f * n / (n - f); M44d P = new M44d( F / r, 0, 0, 0, 0, F, 0, 0, 0, 0, A, B, 0, 0, -1, 0); return P; } /// /// Provides perspective projection matrix. /// The parameters describe the dimensions of the view volume. /// public static M44d PerspectiveProjectionTransformRH(V2d size, double n, double f) { double w = size.X; double h = size.Y; // Fx 0 0 0 // 0 Fy 0 0 // 0 0 A B // 0 0 -1 0 double Fx = 2 * n / w; double Fy = 2 * n / h; double A = f / (n - f); double B = n * f / (n - f); M44d P = new M44d( Fx, 0, 0, 0, 0, Fy, 0, 0, 0, 0, A, B, 0, 0, -1, 0); return P; } /// /// Builds a customized, right-handed perspective Off-Center projection matrix. /// public static M44d PerspectiveProjectionTransformRH(double l, double r, double t, double b, double n, double f) { // Fx 0 Sx 0 // 0 Fy Sy 0 // 0 0 A B // 0 0 -1 0 double Fx = 2 * n / (r - l); double Fy = 2 * n / (t - b); double Sx = (l + r) / (r - l); double Sy = (t + b) / (t - b); double A = f / (n - f); double B = n * f / (n - f); M44d P = new M44d( Fx, 0, Sx, 0, 0, Fy, Sy, 0, 0, 0, A, B, 0, 0, -1, 0); return P; } #endregion #region Static creators /// /// Returns the matrix that transforms from the coordinate system /// specified by the basis into the world cordinate system. /// public static M44d FromBasis(V3d xAxis, V3d yAxis, V3d zAxis, V3d origin) { return new M44d( xAxis.X, yAxis.X, zAxis.X, origin.X, xAxis.Y, yAxis.Y, zAxis.Y, origin.Y, xAxis.Z, yAxis.Z, zAxis.Z, origin.Z, 0, 0, 0, 1); } /// /// Creates a view tranformation from the given vectors. /// Transformation from world- into view-space. /// /// Origin of the view /// Right vector of the view-plane /// Up vector of the view-plane /// Normal vector of the view-plane. This vector is suppsoed to point in view-direction for a left-handed view transformation and in opposit direction in the right-handed case. /// The view transformation public static M44d ViewTrafo(V3d location, V3d right, V3d up, V3d normal) { return new M44d( right.X, right.Y, right.Z, -location.Dot(right), up.X, up.Y, up.Z, -location.Dot(up), normal.X, normal.Y, normal.Z, -location.Dot(normal), 0, 0, 0, 1 ); } /// /// Creates a inverse view tranformation from the given vectors. /// Transformation from view- into world-space. /// The implementation is the same as FromBasis(right, up, normal, location) /// /// Origin of the view /// Right vector of the view-plane /// Up vector of the view-plane /// Normal vector of the view-plane. This vector is suppsoed to point in view-direction for a left-handed view transformation and in opposit direction in the right-handed case. /// The inverse view transformation public static M44d InvViewTrafo(V3d location, V3d right, V3d up, V3d normal) { return new M44d( right.X, up.X, normal.X, location.X, right.Y, up.Y, normal.Y, location.Y, right.Z, up.Z, normal.Z, location.Z, 0, 0, 0, 1 ); } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Trafos/M44_template.cs ================================================ using System; using System.Text; namespace Aardvark.Base { //# foreach (var isDouble in new[] { false, true }) { //# var ft = isDouble ? "double" : "float"; //# var x2t = isDouble ? "2d" : "2f"; //# var x3t = isDouble ? "3d" : "3f"; //# var x4t = isDouble ? "4d" : "4f"; #region M4__x4t__ public partial struct M4__x4t__ { #region Coordinate-System Transforms /// /// Computes from a point (origin) and /// a normal the transformation matrix /// and its inverse. /// /// The point which will become the new origin. /// The normal vector of the new ground plane. /// A The trafo from local to global system. /// A The trafofrom global to local system. public static void NormalFrame(V__x3t__ origin, V__x3t__ normal, out M4__x4t__ local2global, out M4__x4t__ global2local ) { V__x3t__ min; __ft__ x = Fun.Abs(normal.X); __ft__ y = Fun.Abs(normal.Y); __ft__ z = Fun.Abs(normal.Z); if (x < y) { if (x < z) { min = V__x3t__.XAxis; } else { min = V__x3t__.ZAxis; } } else { if (y < z) { min = V__x3t__.YAxis; } else { min = V__x3t__.ZAxis; } } V__x3t__ xVec = Vec.Cross(normal, min); xVec.Normalize(); // this is now guaranteed to be normal to the input normal V__x3t__ yVec = Vec.Cross(normal, xVec); yVec.Normalize(); V__x3t__ zVec = normal; zVec.Normalize(); local2global = new M4__x4t__(xVec.X, yVec.X, zVec.X, origin.X, xVec.Y, yVec.Y, zVec.Y, origin.Y, xVec.Z, yVec.Z, zVec.Z, origin.Z, 0, 0, 0, 1); M4__x4t__ mat = new M4__x4t__(xVec.X, xVec.Y, xVec.Z, 0, yVec.X, yVec.Y, yVec.Z, 0, zVec.X, zVec.Y, zVec.Z, 0, 0, 0, 0, 1); var shift = M4__x4t__.Translation(-origin); global2local = mat * shift; } /// /// Computes a Coordiante Frame Transformation (Basis) from current CS into /// the (X, Y, Z)-System at a given Origin. /// Note: you can use it, to transform from RH to LH and vice-versa, all depending /// how you will specifie your new basis-vectors. /// /// New X Vector /// New Y Vector /// New Z vector /// New Origin. /// /// public static void CoordinateFrameTransform(V__x3t__ xVec, V__x3t__ yVec, V__x3t__ zVec, V__x3t__ oVec, out M4__x4t__ viewTrafo, out M4__x4t__ viewTrafoInverse) { oVec = -oVec; viewTrafo = new M4__x4t__( xVec.X, xVec.Y, xVec.Z, xVec.X * oVec.X + xVec.Y * oVec.Y + xVec.Z * oVec.Z, yVec.X, yVec.Y, yVec.Z, yVec.X * oVec.X + yVec.Y * oVec.Y + yVec.Z * oVec.Z, zVec.X, zVec.Y, zVec.Z, zVec.X * oVec.X + zVec.Y * oVec.Y + zVec.Z * oVec.Z, 0, 0, 0, 1 ); viewTrafoInverse = new M4__x4t__( xVec.X, yVec.X, zVec.X, -oVec.X, xVec.Y, yVec.Y, zVec.Y, -oVec.Y, xVec.Z, yVec.Z, zVec.Z, -oVec.Z, 0, 0, 0, 1 ); } /// /// Provides perspective projection matrix in terms of the vertical field of view angle a and the aspect ratio r. /// public static M4__x4t__ PerspectiveProjectionTransformRH(__ft__ a, __ft__ r, __ft__ n, __ft__ f) { //F / r 0 0 0 // 0 F 0 0 // 0 0 A B // 0 0 -1 0 __ft__ F = 1 / Fun.Tan(a / 2); __ft__ A = f / (n - f); __ft__ B = f * n / (n - f); M4__x4t__ P = new M4__x4t__( F / r, 0, 0, 0, 0, F, 0, 0, 0, 0, A, B, 0, 0, -1, 0); return P; } /// /// Provides perspective projection matrix. /// The parameters describe the dimensions of the view volume. /// public static M4__x4t__ PerspectiveProjectionTransformRH(V__x2t__ size, __ft__ n, __ft__ f) { __ft__ w = size.X; __ft__ h = size.Y; // Fx 0 0 0 // 0 Fy 0 0 // 0 0 A B // 0 0 -1 0 __ft__ Fx = 2 * n / w; __ft__ Fy = 2 * n / h; __ft__ A = f / (n - f); __ft__ B = n * f / (n - f); M4__x4t__ P = new M4__x4t__( Fx, 0, 0, 0, 0, Fy, 0, 0, 0, 0, A, B, 0, 0, -1, 0); return P; } /// /// Builds a customized, right-handed perspective Off-Center projection matrix. /// public static M4__x4t__ PerspectiveProjectionTransformRH(__ft__ l, __ft__ r, __ft__ t, __ft__ b, __ft__ n, __ft__ f) { // Fx 0 Sx 0 // 0 Fy Sy 0 // 0 0 A B // 0 0 -1 0 __ft__ Fx = 2 * n / (r - l); __ft__ Fy = 2 * n / (t - b); __ft__ Sx = (l + r) / (r - l); __ft__ Sy = (t + b) / (t - b); __ft__ A = f / (n - f); __ft__ B = n * f / (n - f); M4__x4t__ P = new M4__x4t__( Fx, 0, Sx, 0, 0, Fy, Sy, 0, 0, 0, A, B, 0, 0, -1, 0); return P; } #endregion #region Static creators /// /// Returns the matrix that transforms from the coordinate system /// specified by the basis into the world cordinate system. /// public static M4__x4t__ FromBasis(V__x3t__ xAxis, V__x3t__ yAxis, V__x3t__ zAxis, V__x3t__ origin) { return new M4__x4t__( xAxis.X, yAxis.X, zAxis.X, origin.X, xAxis.Y, yAxis.Y, zAxis.Y, origin.Y, xAxis.Z, yAxis.Z, zAxis.Z, origin.Z, 0, 0, 0, 1); } /// /// Creates a view tranformation from the given vectors. /// Transformation from world- into view-space. /// /// Origin of the view /// Right vector of the view-plane /// Up vector of the view-plane /// Normal vector of the view-plane. This vector is suppsoed to point in view-direction for a left-handed view transformation and in opposit direction in the right-handed case. /// The view transformation public static M4__x4t__ ViewTrafo(V__x3t__ location, V__x3t__ right, V__x3t__ up, V__x3t__ normal) { return new M4__x4t__( right.X, right.Y, right.Z, -location.Dot(right), up.X, up.Y, up.Z, -location.Dot(up), normal.X, normal.Y, normal.Z, -location.Dot(normal), 0, 0, 0, 1 ); } /// /// Creates a inverse view tranformation from the given vectors. /// Transformation from view- into world-space. /// The implementation is the same as FromBasis(right, up, normal, location) /// /// Origin of the view /// Right vector of the view-plane /// Up vector of the view-plane /// Normal vector of the view-plane. This vector is suppsoed to point in view-direction for a left-handed view transformation and in opposit direction in the right-handed case. /// The inverse view transformation public static M4__x4t__ InvViewTrafo(V__x3t__ location, V__x3t__ right, V__x3t__ up, V__x3t__ normal) { return new M4__x4t__( right.X, up.X, normal.X, location.X, right.Y, up.Y, normal.Y, location.Y, right.Z, up.Z, normal.Z, location.Z, 0, 0, 0, 1 ); } #endregion } #endregion //# } // isDouble } ================================================ FILE: src/Aardvark.Base/Math/Trafos/MatrixArrayExtensions.cs ================================================ using System; using System.Collections.Generic; namespace Aardvark.Base { public static class MatrixArrayExtensions { #region Transform position arrays and collections public static void TransformPosArray(this M44d mat, V3d[] points) { for (var i = 0; i < points.Length; i++) points[i] = mat.TransformPos(points[i]); } public static V3d[] TransformedPosArray(this M44d mat, ICollection points) { var result = new V3d[points.Count]; var i = 0; foreach (var p in points) result[i++] = mat.TransformPos(p); return result; } public static V3d[] TransformedDirArray(this M44d mat, V3d[] directions) { var result = new V3d[directions.Length]; for (var i = 0; i < directions.Length; i++) result[i] = mat.TransformDir(directions[i]); return result; } #endregion #region Indexed Copy Operations /// /// Copies from the position array indexed by a backward map into /// a target array, starting at the supplied offset, thereby /// transforming all positions using the supplied matrix. /// /// target array public static V3f[] BackwardIndexedTransformPosAndCopyTo( this V3f[] source, V3f[] target, int[] backwardMap, int offset, M44d m44d) { var count = backwardMap.Length; for (var i = 0; i < count; i++) target[i + offset] = (V3f)m44d.TransformPos((V3d)source[backwardMap[i]]); return target; } /// /// Copies from the position array indexed by a backward map into /// a target array, starting at the supplied offset, thereby /// transforming all positions using the supplied matrix. /// /// target array public static V3d[] BackwardIndexedTransformPosAndCopyTo( this V3d[] source, V3d[] target, int[] backwardMap, int offset, M44d m44d) { var count = backwardMap.Length; for (var i = 0; i < count; i++) target[i + offset] = m44d.TransformPos(source[backwardMap[i]]); return target; } public static Array BackwardIndexedTransformPosAndCopyTo( this Array source, Array target, int[] backwardMap, int offset, M44d m44d) { var type = source.GetType(); if (type == typeof(V3f[])) return BackwardIndexedTransformPosAndCopyTo((V3f[])source, (V3f[])target, backwardMap, offset, m44d); if (type == typeof(V3d[])) return BackwardIndexedTransformPosAndCopyTo((V3d[])source, (V3d[])target, backwardMap, offset, m44d); throw new InvalidOperationException(); } /// /// Copies from the direction array indexed by a backward map into /// a target array, starting at the supplied offset, thereby /// transforming all directions using the supplied matrix. /// /// target array public static V3f[] BackwardIndexedTransformDirAndCopyTo( this V3f[] source, V3f[] target, int[] backwardMap, int offset, M44d m44d) { var count = backwardMap.Length; for (var i = 0; i < count; i++) target[i + offset] = (V3f)m44d.TransformDir((V3d)source[backwardMap[i]]); return target; } /// /// Copies from the direction array indexed by a backward map into /// a target array, starting at the supplied offset, thereby /// transforming all directions using the supplied matrix. /// /// target array public static V3d[] BackwardIndexedTransformDirAndCopyTo( this V3d[] source, V3d[] target, int[] backwardMap, int offset, M44d m44d) { var count = backwardMap.Length; for (var i = 0; i < count; i++) target[i + offset] = m44d.TransformDir(source[backwardMap[i]]); return target; } public static Array BackwardIndexedTransformDirAndCopyTo( this Array source, Array target, int[] backwardMap, int offset, M44d m44d) { var type = source.GetType(); if (type == typeof(V3f[])) return BackwardIndexedTransformDirAndCopyTo((V3f[])source, (V3f[])target, backwardMap, offset, m44d); if (type == typeof(V3d[])) return BackwardIndexedTransformDirAndCopyTo((V3d[])source, (V3d[])target, backwardMap, offset, m44d); throw new InvalidOperationException(); } #endregion } } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Matrix_auto.cs ================================================ using System; using System.ComponentModel; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Xml.Serialization; using System.Diagnostics; namespace Aardvark.Base { // AUTOGENERATED CODE - DO NOT CHANGE! #region M22i [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M22i : IEquatable, IValidity, IMatrix { [DataMember] public int M00, M01; [DataMember] public int M10, M11; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(int value) { M00 = value; M01 = 0; M10 = 0; M11 = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i( int m00, int m01, int m10, int m11) { M00 = m00; M01 = m01; M10 = m10; M11 = m11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(int[] a) { M00 = a[0]; M01 = a[1]; M10 = a[2]; M11 = a[3]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(int[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M10 = a[start + 2]; M11 = a[start + 3]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M23i m) { M00 = m.M00; M01 = m.M01; M10 = m.M10; M11 = m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M33i m) { M00 = m.M00; M01 = m.M01; M10 = m.M10; M11 = m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M34i m) { M00 = m.M00; M01 = m.M01; M10 = m.M10; M11 = m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M44i m) { M00 = m.M00; M01 = m.M01; M10 = m.M10; M11 = m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M22l m) { M00 = (int)m.M00; M01 = (int)m.M01; M10 = (int)m.M10; M11 = (int)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M23l m) { M00 = (int)m.M00; M01 = (int)m.M01; M10 = (int)m.M10; M11 = (int)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M33l m) { M00 = (int)m.M00; M01 = (int)m.M01; M10 = (int)m.M10; M11 = (int)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M34l m) { M00 = (int)m.M00; M01 = (int)m.M01; M10 = (int)m.M10; M11 = (int)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M44l m) { M00 = (int)m.M00; M01 = (int)m.M01; M10 = (int)m.M10; M11 = (int)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M22f m) { M00 = (int)m.M00; M01 = (int)m.M01; M10 = (int)m.M10; M11 = (int)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M23f m) { M00 = (int)m.M00; M01 = (int)m.M01; M10 = (int)m.M10; M11 = (int)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M33f m) { M00 = (int)m.M00; M01 = (int)m.M01; M10 = (int)m.M10; M11 = (int)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M34f m) { M00 = (int)m.M00; M01 = (int)m.M01; M10 = (int)m.M10; M11 = (int)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M44f m) { M00 = (int)m.M00; M01 = (int)m.M01; M10 = (int)m.M10; M11 = (int)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M22d m) { M00 = (int)m.M00; M01 = (int)m.M01; M10 = (int)m.M10; M11 = (int)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M23d m) { M00 = (int)m.M00; M01 = (int)m.M01; M10 = (int)m.M10; M11 = (int)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M33d m) { M00 = (int)m.M00; M01 = (int)m.M01; M10 = (int)m.M10; M11 = (int)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M34d m) { M00 = (int)m.M00; M01 = (int)m.M01; M10 = (int)m.M10; M11 = (int)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22i(M44d m) { M00 = (int)m.M00; M01 = (int)m.M01; M10 = (int)m.M10; M11 = (int)m.M11; } #endregion #region Conversions public static explicit operator M22i(M23i m) { return new M22i { M00 = m.M00, M01 = m.M01, M10 = m.M10, M11 = m.M11, }; } public static explicit operator M22i(M33i m) { return new M22i { M00 = m.M00, M01 = m.M01, M10 = m.M10, M11 = m.M11, }; } public static explicit operator M22i(M34i m) { return new M22i { M00 = m.M00, M01 = m.M01, M10 = m.M10, M11 = m.M11, }; } public static explicit operator M22i(M44i m) { return new M22i { M00 = m.M00, M01 = m.M01, M10 = m.M10, M11 = m.M11, }; } public static explicit operator M22i(M22l m) { return new M22i { M00 = (int)m.M00, M01 = (int)m.M01, M10 = (int)m.M10, M11 = (int)m.M11, }; } public static explicit operator M22i(M23l m) { return new M22i { M00 = (int)m.M00, M01 = (int)m.M01, M10 = (int)m.M10, M11 = (int)m.M11, }; } public static explicit operator M22i(M33l m) { return new M22i { M00 = (int)m.M00, M01 = (int)m.M01, M10 = (int)m.M10, M11 = (int)m.M11, }; } public static explicit operator M22i(M34l m) { return new M22i { M00 = (int)m.M00, M01 = (int)m.M01, M10 = (int)m.M10, M11 = (int)m.M11, }; } public static explicit operator M22i(M44l m) { return new M22i { M00 = (int)m.M00, M01 = (int)m.M01, M10 = (int)m.M10, M11 = (int)m.M11, }; } public static explicit operator M22i(M22f m) { return new M22i { M00 = (int)m.M00, M01 = (int)m.M01, M10 = (int)m.M10, M11 = (int)m.M11, }; } public static explicit operator M22i(M23f m) { return new M22i { M00 = (int)m.M00, M01 = (int)m.M01, M10 = (int)m.M10, M11 = (int)m.M11, }; } public static explicit operator M22i(M33f m) { return new M22i { M00 = (int)m.M00, M01 = (int)m.M01, M10 = (int)m.M10, M11 = (int)m.M11, }; } public static explicit operator M22i(M34f m) { return new M22i { M00 = (int)m.M00, M01 = (int)m.M01, M10 = (int)m.M10, M11 = (int)m.M11, }; } public static explicit operator M22i(M44f m) { return new M22i { M00 = (int)m.M00, M01 = (int)m.M01, M10 = (int)m.M10, M11 = (int)m.M11, }; } public static explicit operator M22i(M22d m) { return new M22i { M00 = (int)m.M00, M01 = (int)m.M01, M10 = (int)m.M10, M11 = (int)m.M11, }; } public static explicit operator M22i(M23d m) { return new M22i { M00 = (int)m.M00, M01 = (int)m.M01, M10 = (int)m.M10, M11 = (int)m.M11, }; } public static explicit operator M22i(M33d m) { return new M22i { M00 = (int)m.M00, M01 = (int)m.M01, M10 = (int)m.M10, M11 = (int)m.M11, }; } public static explicit operator M22i(M34d m) { return new M22i { M00 = (int)m.M00, M01 = (int)m.M01, M10 = (int)m.M10, M11 = (int)m.M11, }; } public static explicit operator M22i(M44d m) { return new M22i { M00 = (int)m.M00, M01 = (int)m.M01, M10 = (int)m.M10, M11 = (int)m.M11, }; } public static explicit operator M22i(int[] a) { return new M22i( a[0], a[1], a[2], a[3]); } public static explicit operator M22i(int[,] a) { return new M22i( a[0, 0], a[0, 1], a[1, 0], a[1, 1]); } public static explicit operator int[](M22i m) { return new int[] { m.M00, m.M01, m.M10, m.M11 }; } public static explicit operator int[,](M22i m) { return new int[,] { { m.M00, m.M01 }, { m.M10, m.M11 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M10; array[index + 3] = M11; } public static explicit operator M22i(long[] a) { return new M22i( (int)a[0], (int)a[1], (int)a[2], (int)a[3]); } public static explicit operator M22i(long[,] a) { return new M22i( (int)a[0, 0], (int)a[0, 1], (int)a[1, 0], (int)a[1, 1]); } public static explicit operator long[](M22i m) { return new long[] { (long)m.M00, (long)m.M01, (long)m.M10, (long)m.M11 }; } public static explicit operator long[,](M22i m) { return new long[,] { { (long)m.M00, (long)m.M01 }, { (long)m.M10, (long)m.M11 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = (long)M00; array[index + 1] = (long)M01; array[index + 2] = (long)M10; array[index + 3] = (long)M11; } public static explicit operator M22i(float[] a) { return new M22i( (int)a[0], (int)a[1], (int)a[2], (int)a[3]); } public static explicit operator M22i(float[,] a) { return new M22i( (int)a[0, 0], (int)a[0, 1], (int)a[1, 0], (int)a[1, 1]); } public static explicit operator float[](M22i m) { return new float[] { (float)m.M00, (float)m.M01, (float)m.M10, (float)m.M11 }; } public static explicit operator float[,](M22i m) { return new float[,] { { (float)m.M00, (float)m.M01 }, { (float)m.M10, (float)m.M11 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = (float)M00; array[index + 1] = (float)M01; array[index + 2] = (float)M10; array[index + 3] = (float)M11; } public static explicit operator M22i(double[] a) { return new M22i( (int)a[0], (int)a[1], (int)a[2], (int)a[3]); } public static explicit operator M22i(double[,] a) { return new M22i( (int)a[0, 0], (int)a[0, 1], (int)a[1, 0], (int)a[1, 1]); } public static explicit operator double[](M22i m) { return new double[] { (double)m.M00, (double)m.M01, (double)m.M10, (double)m.M11 }; } public static explicit operator double[,](M22i m) { return new double[,] { { (double)m.M00, (double)m.M01 }, { (double)m.M10, (double)m.M11 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = (double)M00; array[index + 1] = (double)M01; array[index + 2] = (double)M10; array[index + 3] = (double)M11; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22i Copy(Func element_fun) { return new M22i( element_fun(M00), element_fun(M01), element_fun(M10), element_fun(M11)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22i Copy(Func element_index0_index1_fun) { return new M22i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22l Copy(Func element_fun) { return new M22l( element_fun(M00), element_fun(M01), element_fun(M10), element_fun(M11)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22l Copy(Func element_index0_index1_fun) { return new M22l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22f Copy(Func element_fun) { return new M22f( element_fun(M00), element_fun(M01), element_fun(M10), element_fun(M11)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22f Copy(Func element_index0_index1_fun) { return new M22f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22d Copy(Func element_fun) { return new M22d( element_fun(M00), element_fun(M01), element_fun(M10), element_fun(M11)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22d Copy(Func element_index0_index1_fun) { return new M22d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1)); } public readonly int[] ToArray() { var array = new int[4]; array[0] = M00; array[1] = M01; array[2] = M10; array[3] = M11; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i FromCols(V2i col0, V2i col1) { return new M22i( col0.X, col1.X, col0.Y, col1.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i FromRows(V2i row0, V2i row1) { return new M22i( row0.X, row0.Y, row1.X, row1.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i FromDiagonal(int value) { return new M22i( value, 0, 0, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i FromDiagonal(int m00, int m11) { return new M22i( m00, 0, 0, m11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i FromDiagonal(V2i s) { return new M22i( s.X, 0, 0, s.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i FromAntiDiagonal(int value) { return new M22i( 0, value, value, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i FromAntiDiagonal(int m01, int m10) { return new M22i( 0, m01, m10, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i FromAntiDiagonal(V2i s) { return new M22i( 0, s.X, s.Y, 0); } #region Scale /// /// Creates a transformation using 2 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i Scale(int sX, int sY) => FromDiagonal(sX, sY); /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i Scale(V2i s) => FromDiagonal(s); #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i DivideByInt(M22i m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M10; yield return M11; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; } } [XmlIgnore] public V2i R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2i( M00, M01); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; } } [XmlIgnore] public V2i R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2i( M10, M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; } } [XmlIgnore] public V2i C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2i( M00, M10); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; } } [XmlIgnore] public V2i C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2i( M01, M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; } } public readonly V2i Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2i(M00, M11); } public readonly V2i AntiDiagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2i(M01, M10); } /// /// Returns the minimum element of the matrix. /// public readonly int MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M10, M11); } /// /// Returns the maximum element of the matrix. /// public readonly int MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M10, M11); } public unsafe int this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (int* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (int* ptr = &M00) { ptr[index] = value; } } } public unsafe int this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (int* ptr = &M00) { return ptr[row * 2 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (int* ptr = &M00) { ptr[row * 2 + column] = value; } } } #endregion #region Constants public const int RowCount = 2; public const int ColumnCount = 2; public const int ElementCount = 2 * 2; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(2, 2); } public static M22i Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M22i(0); } public static M22i Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M22i(1, 0, 0, 1); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly int Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M10) + Fun.Abs(M11); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly double Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M10 * M10 + M11 * M11); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly int NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly int NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator -(M22i m) { return new M22i( -m.M00, -m.M01, -m.M10, -m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator + (M22i a, M22i b) { return new M22i( a.M00 + b.M00, a.M01 + b.M01, a.M10 + b.M10, a.M11 + b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator + (M22i m, int s) { return new M22i( m.M00 + s, m.M01 + s, m.M10 + s, m.M11 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator + (int s, M22i m) { return new M22i( s + m.M00, s + m.M01, s + m.M10, s + m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator + (M22i a, M22l b) { return new M22l( a.M00 + b.M00, a.M01 + b.M01, a.M10 + b.M10, a.M11 + b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator + (M22i m, long s) { return new M22l( m.M00 + s, m.M01 + s, m.M10 + s, m.M11 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator + (long s, M22i m) { return new M22l( s + m.M00, s + m.M01, s + m.M10, s + m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator + (M22i a, M22f b) { return new M22f( a.M00 + b.M00, a.M01 + b.M01, a.M10 + b.M10, a.M11 + b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator + (M22i m, float s) { return new M22f( m.M00 + s, m.M01 + s, m.M10 + s, m.M11 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator + (float s, M22i m) { return new M22f( s + m.M00, s + m.M01, s + m.M10, s + m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator + (M22i a, M22d b) { return new M22d( a.M00 + b.M00, a.M01 + b.M01, a.M10 + b.M10, a.M11 + b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator + (M22i m, double s) { return new M22d( m.M00 + s, m.M01 + s, m.M10 + s, m.M11 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator + (double s, M22i m) { return new M22d( s + m.M00, s + m.M01, s + m.M10, s + m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator - (M22i a, M22i b) { return new M22i( a.M00 - b.M00, a.M01 - b.M01, a.M10 - b.M10, a.M11 - b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator - (M22i m, int s) { return new M22i( m.M00 - s, m.M01 - s, m.M10 - s, m.M11 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator - (int s, M22i m) { return new M22i( s - m.M00, s - m.M01, s - m.M10, s - m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator - (M22i a, M22l b) { return new M22l( a.M00 - b.M00, a.M01 - b.M01, a.M10 - b.M10, a.M11 - b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator - (M22i m, long s) { return new M22l( m.M00 - s, m.M01 - s, m.M10 - s, m.M11 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator - (long s, M22i m) { return new M22l( s - m.M00, s - m.M01, s - m.M10, s - m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator - (M22i a, M22f b) { return new M22f( a.M00 - b.M00, a.M01 - b.M01, a.M10 - b.M10, a.M11 - b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator - (M22i m, float s) { return new M22f( m.M00 - s, m.M01 - s, m.M10 - s, m.M11 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator - (float s, M22i m) { return new M22f( s - m.M00, s - m.M01, s - m.M10, s - m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator - (M22i a, M22d b) { return new M22d( a.M00 - b.M00, a.M01 - b.M01, a.M10 - b.M10, a.M11 - b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator - (M22i m, double s) { return new M22d( m.M00 - s, m.M01 - s, m.M10 - s, m.M11 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator - (double s, M22i m) { return new M22d( s - m.M00, s - m.M01, s - m.M10, s - m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator % (M22i a, M22i b) { return new M22i( a.M00 % b.M00, a.M01 % b.M01, a.M10 % b.M10, a.M11 % b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator % (M22i m, int s) { return new M22i( m.M00 % s, m.M01 % s, m.M10 % s, m.M11 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator % (int s, M22i m) { return new M22i( s % m.M00, s % m.M01, s % m.M10, s % m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator % (M22i a, M22l b) { return new M22l( a.M00 % b.M00, a.M01 % b.M01, a.M10 % b.M10, a.M11 % b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator % (M22i m, long s) { return new M22l( m.M00 % s, m.M01 % s, m.M10 % s, m.M11 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator % (long s, M22i m) { return new M22l( s % m.M00, s % m.M01, s % m.M10, s % m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator % (M22i a, M22f b) { return new M22f( a.M00 % b.M00, a.M01 % b.M01, a.M10 % b.M10, a.M11 % b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator % (M22i m, float s) { return new M22f( m.M00 % s, m.M01 % s, m.M10 % s, m.M11 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator % (float s, M22i m) { return new M22f( s % m.M00, s % m.M01, s % m.M10, s % m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator % (M22i a, M22d b) { return new M22d( a.M00 % b.M00, a.M01 % b.M01, a.M10 % b.M10, a.M11 % b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator % (M22i m, double s) { return new M22d( m.M00 % s, m.M01 % s, m.M10 % s, m.M11 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator % (double s, M22i m) { return new M22d( s % m.M00, s % m.M01, s % m.M10, s % m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator / (M22i a, M22i b) { return new M22i( a.M00 / b.M00, a.M01 / b.M01, a.M10 / b.M10, a.M11 / b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator / (M22i m, int s) { return new M22i( m.M00 / s, m.M01 / s, m.M10 / s, m.M11 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator / (int s, M22i m) { return new M22i( s / m.M00, s / m.M01, s / m.M10, s / m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator / (M22i a, M22l b) { return new M22l( a.M00 / b.M00, a.M01 / b.M01, a.M10 / b.M10, a.M11 / b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator / (M22i m, long s) { return new M22l( m.M00 / s, m.M01 / s, m.M10 / s, m.M11 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator / (long s, M22i m) { return new M22l( s / m.M00, s / m.M01, s / m.M10, s / m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator / (M22i a, M22f b) { return new M22f( a.M00 / b.M00, a.M01 / b.M01, a.M10 / b.M10, a.M11 / b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator / (M22i m, float s) { return new M22f( m.M00 / s, m.M01 / s, m.M10 / s, m.M11 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator / (float s, M22i m) { return new M22f( s / m.M00, s / m.M01, s / m.M10, s / m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator / (M22i a, M22d b) { return new M22d( a.M00 / b.M00, a.M01 / b.M01, a.M10 / b.M10, a.M11 / b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator / (M22i m, double s) { return new M22d( m.M00 / s, m.M01 / s, m.M10 / s, m.M11 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator / (double s, M22i m) { return new M22d( s / m.M00, s / m.M01, s / m.M10, s / m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator * (M22i m, int s) { return new M22i( m.M00 * s, m.M01 * s, m.M10 * s, m.M11 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator * (int s, M22i m) { return new M22i( s * m.M00, s * m.M01, s * m.M10, s * m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator * (M22i m, long s) { return new M22l( m.M00 * s, m.M01 * s, m.M10 * s, m.M11 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator * (long s, M22i m) { return new M22l( s * m.M00, s * m.M01, s * m.M10, s * m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator * (M22i m, float s) { return new M22f( m.M00 * s, m.M01 * s, m.M10 * s, m.M11 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator * (float s, M22i m) { return new M22f( s * m.M00, s * m.M01, s * m.M10, s * m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator * (M22i m, double s) { return new M22d( m.M00 * s, m.M01 * s, m.M10 * s, m.M11 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator * (double s, M22i m) { return new M22d( s * m.M00, s * m.M01, s * m.M10, s * m.M11); } #endregion #region Bitwise Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator ~(M22i m) { return new M22i( ~m.M00, ~m.M01, ~m.M10, ~m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator <<(M22i a, int s) { return new M22i( a.M00 << s, a.M01 << s, a.M10 << s, a.M11 << s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator >>(M22i a, int s) { return new M22i( a.M00 >> s, a.M01 >> s, a.M10 >> s, a.M11 >> s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator &(M22i a, M22i b) { return new M22i( a.M00 & b.M00, a.M01 & b.M01, a.M10 & b.M10, a.M11 & b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator &(M22i a, int s) { return new M22i( a.M00 & s, a.M01 & s, a.M10 & s, a.M11 & s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator &(int s, M22i a) { return new M22i( s & a.M00, s & a.M01, s & a.M10, s & a.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator |(M22i a, M22i b) { return new M22i( a.M00 | b.M00, a.M01 | b.M01, a.M10 | b.M10, a.M11 | b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator |(M22i a, int s) { return new M22i( a.M00 | s, a.M01 | s, a.M10 | s, a.M11 | s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator |(int s, M22i a) { return new M22i( s | a.M00, s | a.M01, s | a.M10, s | a.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator ^(M22i a, M22i b) { return new M22i( a.M00 ^ b.M00, a.M01 ^ b.M01, a.M10 ^ b.M10, a.M11 ^ b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator ^(M22i a, int s) { return new M22i( a.M00 ^ s, a.M01 ^ s, a.M10 ^ s, a.M11 ^ s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i operator ^(int s, M22i a) { return new M22i( s ^ a.M00, s ^ a.M01, s ^ a.M10, s ^ a.M11); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M22i matrix with a V2i column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator *(M22i m, V2i v) { return new V2i( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y); } /// /// Multiplies a V2i row vector with a M22i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator *(V2i v, M22i m) { return new V2i( v.X * m.M00 + v.Y * m.M10, v.X * m.M01 + v.Y * m.M11); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M22i a, M22i b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M10 == b.M10 && a.M11 == b.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M22i a, int s) { return a.M00 == s && a.M01 == s && a.M10 == s && a.M11 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(int s, M22i a) { return s == a.M00 && s == a.M01 && s == a.M10 && s == a.M11 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M22i a, M22i b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M22i m, int s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(int s, M22i m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01), HashCode.GetCombined(M10, M11)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M22i other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M10.Equals(other.M10) && M11.Equals(other.M11); } public override readonly bool Equals(object other) => (other is M22i o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M22i Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M22i.FromRows( V2i.Parse(x[0]), V2i.Parse(x[1]) ); } #endregion #region Matrix Operations /// /// Returns adjoint of this matrix. /// public readonly M22i Adjoint { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new M22i(M11, -M10, -M01, M00); } } /// /// Returns the trace of this matrix. /// The trace is defined as the sum of the diagonal elements, /// and is only defined for square matrices. /// public readonly int Trace { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return M00 + M11 ; } } /// /// Gets the determinant of this matrix. /// The determinant is only defined for square matrices. /// public readonly int Determinant { get { return M00 * M11 - M10 * M01; } } /// /// Returns whether this matrix is invertible. /// A matrix is invertible if its determinant is not zero. /// public readonly bool Invertible { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant != 0; } } /// /// Returns whether this matrix is singular. /// A matrix is singular if its determinant is zero. /// public readonly bool Singular { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant == 0; } } /// /// Gets transpose of this matrix. /// public readonly M22i Transposed { get { return new M22i { M00 = M00, M01 = M10, M10 = M01, M11 = M11 }; } } #endregion #region Matrix Multiplication public static M22i operator *(M22i a, M22i b) { return new M22i( a.M00 * b.M00 + a.M01 * b.M10, a.M00 * b.M01 + a.M01 * b.M11, a.M10 * b.M00 + a.M11 * b.M10, a.M10 * b.M01 + a.M11 * b.M11 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return (double)this[(int)y, (int)x]; } set { this[(int)y, (int)x] = (int)value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return (double)this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = (int)value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (int)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (int)value; } #endregion } public class M22iEqualityComparer : IEqualityComparer { public static readonly M22iEqualityComparer Default = new M22iEqualityComparer(); #region IEqualityComparer Members public bool Equals(M22i v0, M22i v1) { return v0 == v1; } public int GetHashCode(M22i v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this M22i m) => (m.C0.Length + m.C1.Length) / 2; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetScaleVector(this M22i m) => new V2d(m.C0.Length, m.C1.Length); #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Norm1(M22i m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(M22i m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NormMax(M22i m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NormMin(M22i m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this M22i m, double p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static int Distance1(this M22i a, M22i b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static double Distance2(this M22i a, M22i b) { return Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11)); } /// /// Returns the p-distance between two matrices. /// public static double Distance(this M22i a, M22i b, double p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static int DistanceMax(this M22i a, M22i b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static int DistanceMin(this M22i a, M22i b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Transform(this M22i m, V2i v) => m * v; /// /// Transforms vector v by matrix m. /// v.Z is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Transform(this M22i m, V3i v) { return new V3i( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y, v.Z); } /// /// Transforms vector v by matrix m. /// v.Z and v.W are not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Transform(this M22i m, V4i v) { return new V4i( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y, v.Z, v.W); } /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i TransposedTransform(this M22i m, V2i v) => v * m; /// /// Transforms vector v by the transpose of matrix m. /// v.Z is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i TransposedTransform(this M22i m, V3i v) { return new V3i( v.X * m.M00 + v.Y * m.M10, v.X * m.M01 + v.Y * m.M11, v.Z); } /// /// Transforms vector v by the transpose of matrix m. /// v.Z and v.W are not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i TransposedTransform(this M22i m, V4i v) { return new V4i( v.X * m.M00 + v.Y * m.M10, v.X * m.M01 + v.Y * m.M11, v.Z, v.W); } #endregion #region Operations /// /// Returns the given to a deleting the /// specified row and column. /// public static int Minor(this M22i m, int row, int column) { return m[1 - row, 1 - column]; } /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V2i Row(this M22i m, int index) { int* ptr = &m.M00; return new V2i(ptr[index * 2], ptr[index * 2 + 1]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V2i Column(this M22i m, int index) { int* ptr = &m.M00; return new V2i(ptr[index], ptr[index + 2]); } /// /// Returns the determinant of the given matrix. /// The determinant is only defined for square matrices. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Determinant(M22i m) => m.Determinant; /// /// Returns the transpose of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i Transposed(M22i m) => m.Transposed; /// /// Transposes the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transpose(this ref M22i m) { Fun.Swap(ref m.M10, ref m.M01); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M22i a, M22i b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M10 < b.M10 && a.M11 < b.M11; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M22i m, int s) { return m.M00 < s && m.M01 < s && m.M10 < s && m.M11 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(int s, M22i m) { return s < m.M00 && s < m.M01 && s < m.M10 && s < m.M11; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M22i a, M22i b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M10 < b.M10 || a.M11 < b.M11; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M22i m, int s) { return m.M00 < s || m.M01 < s || m.M10 < s || m.M11 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(int s, M22i m) { return s < m.M00 || s < m.M01 || s < m.M10 || s < m.M11; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M22i a, M22i b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M10 > b.M10 && a.M11 > b.M11; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M22i m, int s) { return m.M00 > s && m.M01 > s && m.M10 > s && m.M11 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(int s, M22i m) { return s > m.M00 && s > m.M01 && s > m.M10 && s > m.M11; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M22i a, M22i b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M10 > b.M10 || a.M11 > b.M11; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M22i m, int s) { return m.M00 > s || m.M01 > s || m.M10 > s || m.M11 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(int s, M22i m) { return s > m.M00 || s > m.M01 || s > m.M10 || s > m.M11; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M22i a, M22i b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M10 <= b.M10 && a.M11 <= b.M11; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M22i m, int s) { return m.M00 <= s && m.M01 <= s && m.M10 <= s && m.M11 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(int s, M22i m) { return s <= m.M00 && s <= m.M01 && s <= m.M10 && s <= m.M11; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M22i a, M22i b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M10 <= b.M10 || a.M11 <= b.M11; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M22i m, int s) { return m.M00 <= s || m.M01 <= s || m.M10 <= s || m.M11 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(int s, M22i m) { return s <= m.M00 || s <= m.M01 || s <= m.M10 || s <= m.M11; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M22i a, M22i b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M10 >= b.M10 && a.M11 >= b.M11; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M22i m, int s) { return m.M00 >= s && m.M01 >= s && m.M10 >= s && m.M11 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(int s, M22i m) { return s >= m.M00 && s >= m.M01 && s >= m.M10 && s >= m.M11; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M22i a, M22i b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M10 >= b.M10 || a.M11 >= b.M11; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M22i m, int s) { return m.M00 >= s || m.M01 >= s || m.M10 >= s || m.M11 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(int s, M22i m) { return s >= m.M00 || s >= m.M01 || s >= m.M10 || s >= m.M11; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M22i a, M22i b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M10 == b.M10 && a.M11 == b.M11; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M22i m, int s) { return m.M00 == s && m.M01 == s && m.M10 == s && m.M11 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(int s, M22i m) { return s == m.M00 && s == m.M01 && s == m.M10 && s == m.M11; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M22i a, M22i b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M10 == b.M10 || a.M11 == b.M11; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M22i m, int s) { return m.M00 == s || m.M01 == s || m.M10 == s || m.M11 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(int s, M22i m) { return s == m.M00 || s == m.M01 || s == m.M10 || s == m.M11; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M22i a, M22i b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M10 != b.M10 && a.M11 != b.M11; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M22i m, int s) { return m.M00 != s && m.M01 != s && m.M10 != s && m.M11 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(int s, M22i m) { return s != m.M00 && s != m.M01 && s != m.M10 && s != m.M11; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M22i a, M22i b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M10 != b.M10 || a.M11 != b.M11; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M22i m, int s) { return m.M00 != s || m.M01 != s || m.M10 != s || m.M11 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(int s, M22i m) { return s != m.M00 || s != m.M01 || s != m.M10 || s != m.M11; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M22i m0, M22i m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MinElement(M22i m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MaxElement(M22i m) => m.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M22i m, int epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M22i m, int epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon); #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M22i a, M22i b, int epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M22i m, int epsilon) => Mat.AllTiny(m, epsilon); #endregion } public static class IRandomUniformM22iExtensions { #region IRandomUniform extensions for M22i /// /// Uses UniformInt() to generate the elements of an M22i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i UniformM22i(this IRandomUniform rnd) { return new M22i( rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt()); } /// /// Uses UniformIntNonZero() to generate the elements of an M22i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i UniformM22iNonZero(this IRandomUniform rnd) { return new M22i( rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero()); } /// /// Uses UniformInt(int) to generate the elements of an M22i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i UniformM22i(this IRandomUniform rnd, int size) { return new M22i( rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size)); } /// /// Uses UniformInt(int) to generate the elements of an M22i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i UniformM22i(this IRandomUniform rnd, M22i size) { return new M22i( rnd.UniformInt(size.M00), rnd.UniformInt(size.M01), rnd.UniformInt(size.M10), rnd.UniformInt(size.M11)); } #endregion } #endregion #region M22l [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M22l : IEquatable, IValidity, IMatrix { [DataMember] public long M00, M01; [DataMember] public long M10, M11; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(long value) { M00 = value; M01 = 0; M10 = 0; M11 = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l( long m00, long m01, long m10, long m11) { M00 = m00; M01 = m01; M10 = m10; M11 = m11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(long[] a) { M00 = a[0]; M01 = a[1]; M10 = a[2]; M11 = a[3]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(long[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M10 = a[start + 2]; M11 = a[start + 3]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M22i m) { M00 = (long)m.M00; M01 = (long)m.M01; M10 = (long)m.M10; M11 = (long)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M23i m) { M00 = (long)m.M00; M01 = (long)m.M01; M10 = (long)m.M10; M11 = (long)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M33i m) { M00 = (long)m.M00; M01 = (long)m.M01; M10 = (long)m.M10; M11 = (long)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M34i m) { M00 = (long)m.M00; M01 = (long)m.M01; M10 = (long)m.M10; M11 = (long)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M44i m) { M00 = (long)m.M00; M01 = (long)m.M01; M10 = (long)m.M10; M11 = (long)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M23l m) { M00 = m.M00; M01 = m.M01; M10 = m.M10; M11 = m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M33l m) { M00 = m.M00; M01 = m.M01; M10 = m.M10; M11 = m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M34l m) { M00 = m.M00; M01 = m.M01; M10 = m.M10; M11 = m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M44l m) { M00 = m.M00; M01 = m.M01; M10 = m.M10; M11 = m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M22f m) { M00 = (long)m.M00; M01 = (long)m.M01; M10 = (long)m.M10; M11 = (long)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M23f m) { M00 = (long)m.M00; M01 = (long)m.M01; M10 = (long)m.M10; M11 = (long)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M33f m) { M00 = (long)m.M00; M01 = (long)m.M01; M10 = (long)m.M10; M11 = (long)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M34f m) { M00 = (long)m.M00; M01 = (long)m.M01; M10 = (long)m.M10; M11 = (long)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M44f m) { M00 = (long)m.M00; M01 = (long)m.M01; M10 = (long)m.M10; M11 = (long)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M22d m) { M00 = (long)m.M00; M01 = (long)m.M01; M10 = (long)m.M10; M11 = (long)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M23d m) { M00 = (long)m.M00; M01 = (long)m.M01; M10 = (long)m.M10; M11 = (long)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M33d m) { M00 = (long)m.M00; M01 = (long)m.M01; M10 = (long)m.M10; M11 = (long)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M34d m) { M00 = (long)m.M00; M01 = (long)m.M01; M10 = (long)m.M10; M11 = (long)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22l(M44d m) { M00 = (long)m.M00; M01 = (long)m.M01; M10 = (long)m.M10; M11 = (long)m.M11; } #endregion #region Conversions public static explicit operator M22l(M22i m) { return new M22l { M00 = (long)m.M00, M01 = (long)m.M01, M10 = (long)m.M10, M11 = (long)m.M11, }; } public static explicit operator M22l(M23i m) { return new M22l { M00 = (long)m.M00, M01 = (long)m.M01, M10 = (long)m.M10, M11 = (long)m.M11, }; } public static explicit operator M22l(M33i m) { return new M22l { M00 = (long)m.M00, M01 = (long)m.M01, M10 = (long)m.M10, M11 = (long)m.M11, }; } public static explicit operator M22l(M34i m) { return new M22l { M00 = (long)m.M00, M01 = (long)m.M01, M10 = (long)m.M10, M11 = (long)m.M11, }; } public static explicit operator M22l(M44i m) { return new M22l { M00 = (long)m.M00, M01 = (long)m.M01, M10 = (long)m.M10, M11 = (long)m.M11, }; } public static explicit operator M22l(M23l m) { return new M22l { M00 = m.M00, M01 = m.M01, M10 = m.M10, M11 = m.M11, }; } public static explicit operator M22l(M33l m) { return new M22l { M00 = m.M00, M01 = m.M01, M10 = m.M10, M11 = m.M11, }; } public static explicit operator M22l(M34l m) { return new M22l { M00 = m.M00, M01 = m.M01, M10 = m.M10, M11 = m.M11, }; } public static explicit operator M22l(M44l m) { return new M22l { M00 = m.M00, M01 = m.M01, M10 = m.M10, M11 = m.M11, }; } public static explicit operator M22l(M22f m) { return new M22l { M00 = (long)m.M00, M01 = (long)m.M01, M10 = (long)m.M10, M11 = (long)m.M11, }; } public static explicit operator M22l(M23f m) { return new M22l { M00 = (long)m.M00, M01 = (long)m.M01, M10 = (long)m.M10, M11 = (long)m.M11, }; } public static explicit operator M22l(M33f m) { return new M22l { M00 = (long)m.M00, M01 = (long)m.M01, M10 = (long)m.M10, M11 = (long)m.M11, }; } public static explicit operator M22l(M34f m) { return new M22l { M00 = (long)m.M00, M01 = (long)m.M01, M10 = (long)m.M10, M11 = (long)m.M11, }; } public static explicit operator M22l(M44f m) { return new M22l { M00 = (long)m.M00, M01 = (long)m.M01, M10 = (long)m.M10, M11 = (long)m.M11, }; } public static explicit operator M22l(M22d m) { return new M22l { M00 = (long)m.M00, M01 = (long)m.M01, M10 = (long)m.M10, M11 = (long)m.M11, }; } public static explicit operator M22l(M23d m) { return new M22l { M00 = (long)m.M00, M01 = (long)m.M01, M10 = (long)m.M10, M11 = (long)m.M11, }; } public static explicit operator M22l(M33d m) { return new M22l { M00 = (long)m.M00, M01 = (long)m.M01, M10 = (long)m.M10, M11 = (long)m.M11, }; } public static explicit operator M22l(M34d m) { return new M22l { M00 = (long)m.M00, M01 = (long)m.M01, M10 = (long)m.M10, M11 = (long)m.M11, }; } public static explicit operator M22l(M44d m) { return new M22l { M00 = (long)m.M00, M01 = (long)m.M01, M10 = (long)m.M10, M11 = (long)m.M11, }; } public static explicit operator M22l(int[] a) { return new M22l( (long)a[0], (long)a[1], (long)a[2], (long)a[3]); } public static explicit operator M22l(int[,] a) { return new M22l( (long)a[0, 0], (long)a[0, 1], (long)a[1, 0], (long)a[1, 1]); } public static explicit operator int[](M22l m) { return new int[] { (int)m.M00, (int)m.M01, (int)m.M10, (int)m.M11 }; } public static explicit operator int[,](M22l m) { return new int[,] { { (int)m.M00, (int)m.M01 }, { (int)m.M10, (int)m.M11 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = (int)M00; array[index + 1] = (int)M01; array[index + 2] = (int)M10; array[index + 3] = (int)M11; } public static explicit operator M22l(long[] a) { return new M22l( a[0], a[1], a[2], a[3]); } public static explicit operator M22l(long[,] a) { return new M22l( a[0, 0], a[0, 1], a[1, 0], a[1, 1]); } public static explicit operator long[](M22l m) { return new long[] { m.M00, m.M01, m.M10, m.M11 }; } public static explicit operator long[,](M22l m) { return new long[,] { { m.M00, m.M01 }, { m.M10, m.M11 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M10; array[index + 3] = M11; } public static explicit operator M22l(float[] a) { return new M22l( (long)a[0], (long)a[1], (long)a[2], (long)a[3]); } public static explicit operator M22l(float[,] a) { return new M22l( (long)a[0, 0], (long)a[0, 1], (long)a[1, 0], (long)a[1, 1]); } public static explicit operator float[](M22l m) { return new float[] { (float)m.M00, (float)m.M01, (float)m.M10, (float)m.M11 }; } public static explicit operator float[,](M22l m) { return new float[,] { { (float)m.M00, (float)m.M01 }, { (float)m.M10, (float)m.M11 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = (float)M00; array[index + 1] = (float)M01; array[index + 2] = (float)M10; array[index + 3] = (float)M11; } public static explicit operator M22l(double[] a) { return new M22l( (long)a[0], (long)a[1], (long)a[2], (long)a[3]); } public static explicit operator M22l(double[,] a) { return new M22l( (long)a[0, 0], (long)a[0, 1], (long)a[1, 0], (long)a[1, 1]); } public static explicit operator double[](M22l m) { return new double[] { (double)m.M00, (double)m.M01, (double)m.M10, (double)m.M11 }; } public static explicit operator double[,](M22l m) { return new double[,] { { (double)m.M00, (double)m.M01 }, { (double)m.M10, (double)m.M11 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = (double)M00; array[index + 1] = (double)M01; array[index + 2] = (double)M10; array[index + 3] = (double)M11; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22i Copy(Func element_fun) { return new M22i( element_fun(M00), element_fun(M01), element_fun(M10), element_fun(M11)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22i Copy(Func element_index0_index1_fun) { return new M22i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22l Copy(Func element_fun) { return new M22l( element_fun(M00), element_fun(M01), element_fun(M10), element_fun(M11)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22l Copy(Func element_index0_index1_fun) { return new M22l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22f Copy(Func element_fun) { return new M22f( element_fun(M00), element_fun(M01), element_fun(M10), element_fun(M11)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22f Copy(Func element_index0_index1_fun) { return new M22f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22d Copy(Func element_fun) { return new M22d( element_fun(M00), element_fun(M01), element_fun(M10), element_fun(M11)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22d Copy(Func element_index0_index1_fun) { return new M22d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1)); } public readonly long[] ToArray() { var array = new long[4]; array[0] = M00; array[1] = M01; array[2] = M10; array[3] = M11; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l FromCols(V2l col0, V2l col1) { return new M22l( col0.X, col1.X, col0.Y, col1.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l FromRows(V2l row0, V2l row1) { return new M22l( row0.X, row0.Y, row1.X, row1.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l FromDiagonal(long value) { return new M22l( value, 0, 0, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l FromDiagonal(long m00, long m11) { return new M22l( m00, 0, 0, m11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l FromDiagonal(V2l s) { return new M22l( s.X, 0, 0, s.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l FromAntiDiagonal(long value) { return new M22l( 0, value, value, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l FromAntiDiagonal(long m01, long m10) { return new M22l( 0, m01, m10, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l FromAntiDiagonal(V2l s) { return new M22l( 0, s.X, s.Y, 0); } #region Scale /// /// Creates a transformation using 2 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l Scale(long sX, long sY) => FromDiagonal(sX, sY); /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l Scale(V2l s) => FromDiagonal(s); #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l DivideByInt(M22l m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M10; yield return M11; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; } } [XmlIgnore] public V2l R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2l( M00, M01); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; } } [XmlIgnore] public V2l R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2l( M10, M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; } } [XmlIgnore] public V2l C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2l( M00, M10); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; } } [XmlIgnore] public V2l C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2l( M01, M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; } } public readonly V2l Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(M00, M11); } public readonly V2l AntiDiagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(M01, M10); } /// /// Returns the minimum element of the matrix. /// public readonly long MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M10, M11); } /// /// Returns the maximum element of the matrix. /// public readonly long MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M10, M11); } public unsafe long this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (long* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (long* ptr = &M00) { ptr[index] = value; } } } public unsafe long this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (long* ptr = &M00) { return ptr[row * 2 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (long* ptr = &M00) { ptr[row * 2 + column] = value; } } } #endregion #region Constants public const int RowCount = 2; public const int ColumnCount = 2; public const int ElementCount = 2 * 2; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(2, 2); } public static M22l Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M22l(0); } public static M22l Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M22l(1, 0, 0, 1); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly long Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M10) + Fun.Abs(M11); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly double Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M10 * M10 + M11 * M11); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly long NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly long NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator -(M22l m) { return new M22l( -m.M00, -m.M01, -m.M10, -m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator + (M22l a, M22l b) { return new M22l( a.M00 + b.M00, a.M01 + b.M01, a.M10 + b.M10, a.M11 + b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator + (M22l m, long s) { return new M22l( m.M00 + s, m.M01 + s, m.M10 + s, m.M11 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator + (long s, M22l m) { return new M22l( s + m.M00, s + m.M01, s + m.M10, s + m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator + (M22l a, M22f b) { return new M22f( a.M00 + b.M00, a.M01 + b.M01, a.M10 + b.M10, a.M11 + b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator + (M22l m, float s) { return new M22f( m.M00 + s, m.M01 + s, m.M10 + s, m.M11 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator + (float s, M22l m) { return new M22f( s + m.M00, s + m.M01, s + m.M10, s + m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator + (M22l a, M22d b) { return new M22d( a.M00 + b.M00, a.M01 + b.M01, a.M10 + b.M10, a.M11 + b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator + (M22l m, double s) { return new M22d( m.M00 + s, m.M01 + s, m.M10 + s, m.M11 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator + (double s, M22l m) { return new M22d( s + m.M00, s + m.M01, s + m.M10, s + m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator - (M22l a, M22l b) { return new M22l( a.M00 - b.M00, a.M01 - b.M01, a.M10 - b.M10, a.M11 - b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator - (M22l m, long s) { return new M22l( m.M00 - s, m.M01 - s, m.M10 - s, m.M11 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator - (long s, M22l m) { return new M22l( s - m.M00, s - m.M01, s - m.M10, s - m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator - (M22l a, M22f b) { return new M22f( a.M00 - b.M00, a.M01 - b.M01, a.M10 - b.M10, a.M11 - b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator - (M22l m, float s) { return new M22f( m.M00 - s, m.M01 - s, m.M10 - s, m.M11 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator - (float s, M22l m) { return new M22f( s - m.M00, s - m.M01, s - m.M10, s - m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator - (M22l a, M22d b) { return new M22d( a.M00 - b.M00, a.M01 - b.M01, a.M10 - b.M10, a.M11 - b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator - (M22l m, double s) { return new M22d( m.M00 - s, m.M01 - s, m.M10 - s, m.M11 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator - (double s, M22l m) { return new M22d( s - m.M00, s - m.M01, s - m.M10, s - m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator % (M22l a, M22l b) { return new M22l( a.M00 % b.M00, a.M01 % b.M01, a.M10 % b.M10, a.M11 % b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator % (M22l m, long s) { return new M22l( m.M00 % s, m.M01 % s, m.M10 % s, m.M11 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator % (long s, M22l m) { return new M22l( s % m.M00, s % m.M01, s % m.M10, s % m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator % (M22l a, M22f b) { return new M22f( a.M00 % b.M00, a.M01 % b.M01, a.M10 % b.M10, a.M11 % b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator % (M22l m, float s) { return new M22f( m.M00 % s, m.M01 % s, m.M10 % s, m.M11 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator % (float s, M22l m) { return new M22f( s % m.M00, s % m.M01, s % m.M10, s % m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator % (M22l a, M22d b) { return new M22d( a.M00 % b.M00, a.M01 % b.M01, a.M10 % b.M10, a.M11 % b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator % (M22l m, double s) { return new M22d( m.M00 % s, m.M01 % s, m.M10 % s, m.M11 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator % (double s, M22l m) { return new M22d( s % m.M00, s % m.M01, s % m.M10, s % m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator / (M22l a, M22l b) { return new M22l( a.M00 / b.M00, a.M01 / b.M01, a.M10 / b.M10, a.M11 / b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator / (M22l m, long s) { return new M22l( m.M00 / s, m.M01 / s, m.M10 / s, m.M11 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator / (long s, M22l m) { return new M22l( s / m.M00, s / m.M01, s / m.M10, s / m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator / (M22l a, M22f b) { return new M22f( a.M00 / b.M00, a.M01 / b.M01, a.M10 / b.M10, a.M11 / b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator / (M22l m, float s) { return new M22f( m.M00 / s, m.M01 / s, m.M10 / s, m.M11 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator / (float s, M22l m) { return new M22f( s / m.M00, s / m.M01, s / m.M10, s / m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator / (M22l a, M22d b) { return new M22d( a.M00 / b.M00, a.M01 / b.M01, a.M10 / b.M10, a.M11 / b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator / (M22l m, double s) { return new M22d( m.M00 / s, m.M01 / s, m.M10 / s, m.M11 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator / (double s, M22l m) { return new M22d( s / m.M00, s / m.M01, s / m.M10, s / m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator * (M22l m, long s) { return new M22l( m.M00 * s, m.M01 * s, m.M10 * s, m.M11 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator * (long s, M22l m) { return new M22l( s * m.M00, s * m.M01, s * m.M10, s * m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator * (M22l m, float s) { return new M22f( m.M00 * s, m.M01 * s, m.M10 * s, m.M11 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator * (float s, M22l m) { return new M22f( s * m.M00, s * m.M01, s * m.M10, s * m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator * (M22l m, double s) { return new M22d( m.M00 * s, m.M01 * s, m.M10 * s, m.M11 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator * (double s, M22l m) { return new M22d( s * m.M00, s * m.M01, s * m.M10, s * m.M11); } #endregion #region Bitwise Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator ~(M22l m) { return new M22l( ~m.M00, ~m.M01, ~m.M10, ~m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator <<(M22l a, int s) { return new M22l( a.M00 << s, a.M01 << s, a.M10 << s, a.M11 << s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator >>(M22l a, int s) { return new M22l( a.M00 >> s, a.M01 >> s, a.M10 >> s, a.M11 >> s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator &(M22l a, M22l b) { return new M22l( a.M00 & b.M00, a.M01 & b.M01, a.M10 & b.M10, a.M11 & b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator &(M22l a, long s) { return new M22l( a.M00 & s, a.M01 & s, a.M10 & s, a.M11 & s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator &(long s, M22l a) { return new M22l( s & a.M00, s & a.M01, s & a.M10, s & a.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator |(M22l a, M22l b) { return new M22l( a.M00 | b.M00, a.M01 | b.M01, a.M10 | b.M10, a.M11 | b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator |(M22l a, long s) { return new M22l( a.M00 | s, a.M01 | s, a.M10 | s, a.M11 | s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator |(long s, M22l a) { return new M22l( s | a.M00, s | a.M01, s | a.M10, s | a.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator ^(M22l a, M22l b) { return new M22l( a.M00 ^ b.M00, a.M01 ^ b.M01, a.M10 ^ b.M10, a.M11 ^ b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator ^(M22l a, long s) { return new M22l( a.M00 ^ s, a.M01 ^ s, a.M10 ^ s, a.M11 ^ s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l operator ^(long s, M22l a) { return new M22l( s ^ a.M00, s ^ a.M01, s ^ a.M10, s ^ a.M11); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M22l matrix with a V2l column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator *(M22l m, V2l v) { return new V2l( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y); } /// /// Multiplies a V2l row vector with a M22l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator *(V2l v, M22l m) { return new V2l( v.X * m.M00 + v.Y * m.M10, v.X * m.M01 + v.Y * m.M11); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M22l a, M22l b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M10 == b.M10 && a.M11 == b.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M22l a, long s) { return a.M00 == s && a.M01 == s && a.M10 == s && a.M11 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(long s, M22l a) { return s == a.M00 && s == a.M01 && s == a.M10 && s == a.M11 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M22l a, M22l b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M22l m, long s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(long s, M22l m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01), HashCode.GetCombined(M10, M11)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M22l other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M10.Equals(other.M10) && M11.Equals(other.M11); } public override readonly bool Equals(object other) => (other is M22l o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M22l Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M22l.FromRows( V2l.Parse(x[0]), V2l.Parse(x[1]) ); } #endregion #region Matrix Operations /// /// Returns adjoint of this matrix. /// public readonly M22l Adjoint { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new M22l(M11, -M10, -M01, M00); } } /// /// Returns the trace of this matrix. /// The trace is defined as the sum of the diagonal elements, /// and is only defined for square matrices. /// public readonly long Trace { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return M00 + M11 ; } } /// /// Gets the determinant of this matrix. /// The determinant is only defined for square matrices. /// public readonly long Determinant { get { return M00 * M11 - M10 * M01; } } /// /// Returns whether this matrix is invertible. /// A matrix is invertible if its determinant is not zero. /// public readonly bool Invertible { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant != 0; } } /// /// Returns whether this matrix is singular. /// A matrix is singular if its determinant is zero. /// public readonly bool Singular { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant == 0; } } /// /// Gets transpose of this matrix. /// public readonly M22l Transposed { get { return new M22l { M00 = M00, M01 = M10, M10 = M01, M11 = M11 }; } } #endregion #region Matrix Multiplication public static M22l operator *(M22l a, M22l b) { return new M22l( a.M00 * b.M00 + a.M01 * b.M10, a.M00 * b.M01 + a.M01 * b.M11, a.M10 * b.M00 + a.M11 * b.M10, a.M10 * b.M01 + a.M11 * b.M11 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return (double)this[(int)y, (int)x]; } set { this[(int)y, (int)x] = (long)value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return (double)this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = (long)value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (long)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (long)value; } #endregion } public class M22lEqualityComparer : IEqualityComparer { public static readonly M22lEqualityComparer Default = new M22lEqualityComparer(); #region IEqualityComparer Members public bool Equals(M22l v0, M22l v1) { return v0 == v1; } public int GetHashCode(M22l v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this M22l m) => (m.C0.Length + m.C1.Length) / 2; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetScaleVector(this M22l m) => new V2d(m.C0.Length, m.C1.Length); #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Norm1(M22l m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(M22l m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NormMax(M22l m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NormMin(M22l m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this M22l m, double p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static long Distance1(this M22l a, M22l b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static double Distance2(this M22l a, M22l b) { return Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11)); } /// /// Returns the p-distance between two matrices. /// public static double Distance(this M22l a, M22l b, double p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static long DistanceMax(this M22l a, M22l b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static long DistanceMin(this M22l a, M22l b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Transform(this M22l m, V2l v) => m * v; /// /// Transforms vector v by matrix m. /// v.Z is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Transform(this M22l m, V3l v) { return new V3l( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y, v.Z); } /// /// Transforms vector v by matrix m. /// v.Z and v.W are not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Transform(this M22l m, V4l v) { return new V4l( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y, v.Z, v.W); } /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l TransposedTransform(this M22l m, V2l v) => v * m; /// /// Transforms vector v by the transpose of matrix m. /// v.Z is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l TransposedTransform(this M22l m, V3l v) { return new V3l( v.X * m.M00 + v.Y * m.M10, v.X * m.M01 + v.Y * m.M11, v.Z); } /// /// Transforms vector v by the transpose of matrix m. /// v.Z and v.W are not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l TransposedTransform(this M22l m, V4l v) { return new V4l( v.X * m.M00 + v.Y * m.M10, v.X * m.M01 + v.Y * m.M11, v.Z, v.W); } #endregion #region Operations /// /// Returns the given to a deleting the /// specified row and column. /// public static long Minor(this M22l m, int row, int column) { return m[1 - row, 1 - column]; } /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V2l Row(this M22l m, int index) { long* ptr = &m.M00; return new V2l(ptr[index * 2], ptr[index * 2 + 1]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V2l Column(this M22l m, int index) { long* ptr = &m.M00; return new V2l(ptr[index], ptr[index + 2]); } /// /// Returns the determinant of the given matrix. /// The determinant is only defined for square matrices. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Determinant(M22l m) => m.Determinant; /// /// Returns the transpose of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l Transposed(M22l m) => m.Transposed; /// /// Transposes the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transpose(this ref M22l m) { Fun.Swap(ref m.M10, ref m.M01); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M22l a, M22l b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M10 < b.M10 && a.M11 < b.M11; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M22l m, long s) { return m.M00 < s && m.M01 < s && m.M10 < s && m.M11 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(long s, M22l m) { return s < m.M00 && s < m.M01 && s < m.M10 && s < m.M11; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M22l a, M22l b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M10 < b.M10 || a.M11 < b.M11; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M22l m, long s) { return m.M00 < s || m.M01 < s || m.M10 < s || m.M11 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(long s, M22l m) { return s < m.M00 || s < m.M01 || s < m.M10 || s < m.M11; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M22l a, M22l b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M10 > b.M10 && a.M11 > b.M11; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M22l m, long s) { return m.M00 > s && m.M01 > s && m.M10 > s && m.M11 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(long s, M22l m) { return s > m.M00 && s > m.M01 && s > m.M10 && s > m.M11; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M22l a, M22l b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M10 > b.M10 || a.M11 > b.M11; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M22l m, long s) { return m.M00 > s || m.M01 > s || m.M10 > s || m.M11 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(long s, M22l m) { return s > m.M00 || s > m.M01 || s > m.M10 || s > m.M11; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M22l a, M22l b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M10 <= b.M10 && a.M11 <= b.M11; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M22l m, long s) { return m.M00 <= s && m.M01 <= s && m.M10 <= s && m.M11 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(long s, M22l m) { return s <= m.M00 && s <= m.M01 && s <= m.M10 && s <= m.M11; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M22l a, M22l b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M10 <= b.M10 || a.M11 <= b.M11; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M22l m, long s) { return m.M00 <= s || m.M01 <= s || m.M10 <= s || m.M11 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(long s, M22l m) { return s <= m.M00 || s <= m.M01 || s <= m.M10 || s <= m.M11; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M22l a, M22l b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M10 >= b.M10 && a.M11 >= b.M11; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M22l m, long s) { return m.M00 >= s && m.M01 >= s && m.M10 >= s && m.M11 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(long s, M22l m) { return s >= m.M00 && s >= m.M01 && s >= m.M10 && s >= m.M11; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M22l a, M22l b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M10 >= b.M10 || a.M11 >= b.M11; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M22l m, long s) { return m.M00 >= s || m.M01 >= s || m.M10 >= s || m.M11 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(long s, M22l m) { return s >= m.M00 || s >= m.M01 || s >= m.M10 || s >= m.M11; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M22l a, M22l b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M10 == b.M10 && a.M11 == b.M11; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M22l m, long s) { return m.M00 == s && m.M01 == s && m.M10 == s && m.M11 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(long s, M22l m) { return s == m.M00 && s == m.M01 && s == m.M10 && s == m.M11; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M22l a, M22l b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M10 == b.M10 || a.M11 == b.M11; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M22l m, long s) { return m.M00 == s || m.M01 == s || m.M10 == s || m.M11 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(long s, M22l m) { return s == m.M00 || s == m.M01 || s == m.M10 || s == m.M11; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M22l a, M22l b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M10 != b.M10 && a.M11 != b.M11; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M22l m, long s) { return m.M00 != s && m.M01 != s && m.M10 != s && m.M11 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(long s, M22l m) { return s != m.M00 && s != m.M01 && s != m.M10 && s != m.M11; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M22l a, M22l b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M10 != b.M10 || a.M11 != b.M11; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M22l m, long s) { return m.M00 != s || m.M01 != s || m.M10 != s || m.M11 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(long s, M22l m) { return s != m.M00 || s != m.M01 || s != m.M10 || s != m.M11; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M22l m0, M22l m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MinElement(M22l m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MaxElement(M22l m) => m.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M22l m, long epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M22l m, long epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon); #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M22l a, M22l b, long epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M22l m, long epsilon) => Mat.AllTiny(m, epsilon); #endregion } public static class IRandomUniformM22lExtensions { #region IRandomUniform extensions for M22l /// /// Uses UniformLong() to generate the elements of an M22l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l UniformM22l(this IRandomUniform rnd) { return new M22l( rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong()); } /// /// Uses UniformLongNonZero() to generate the elements of an M22l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l UniformM22lNonZero(this IRandomUniform rnd) { return new M22l( rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero()); } /// /// Uses UniformLong(long) to generate the elements of an M22l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l UniformM22l(this IRandomUniform rnd, long size) { return new M22l( rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size)); } /// /// Uses UniformLong(long) to generate the elements of an M22l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l UniformM22l(this IRandomUniform rnd, M22l size) { return new M22l( rnd.UniformLong(size.M00), rnd.UniformLong(size.M01), rnd.UniformLong(size.M10), rnd.UniformLong(size.M11)); } #endregion } #endregion #region M22f [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M22f : IEquatable, IValidity, IMatrix { [DataMember] public float M00, M01; [DataMember] public float M10, M11; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(float value) { M00 = value; M01 = 0; M10 = 0; M11 = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f( float m00, float m01, float m10, float m11) { M00 = m00; M01 = m01; M10 = m10; M11 = m11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(float[] a) { M00 = a[0]; M01 = a[1]; M10 = a[2]; M11 = a[3]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(float[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M10 = a[start + 2]; M11 = a[start + 3]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M22i m) { M00 = (float)m.M00; M01 = (float)m.M01; M10 = (float)m.M10; M11 = (float)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M23i m) { M00 = (float)m.M00; M01 = (float)m.M01; M10 = (float)m.M10; M11 = (float)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M33i m) { M00 = (float)m.M00; M01 = (float)m.M01; M10 = (float)m.M10; M11 = (float)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M34i m) { M00 = (float)m.M00; M01 = (float)m.M01; M10 = (float)m.M10; M11 = (float)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M44i m) { M00 = (float)m.M00; M01 = (float)m.M01; M10 = (float)m.M10; M11 = (float)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M22l m) { M00 = (float)m.M00; M01 = (float)m.M01; M10 = (float)m.M10; M11 = (float)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M23l m) { M00 = (float)m.M00; M01 = (float)m.M01; M10 = (float)m.M10; M11 = (float)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M33l m) { M00 = (float)m.M00; M01 = (float)m.M01; M10 = (float)m.M10; M11 = (float)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M34l m) { M00 = (float)m.M00; M01 = (float)m.M01; M10 = (float)m.M10; M11 = (float)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M44l m) { M00 = (float)m.M00; M01 = (float)m.M01; M10 = (float)m.M10; M11 = (float)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M23f m) { M00 = m.M00; M01 = m.M01; M10 = m.M10; M11 = m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M33f m) { M00 = m.M00; M01 = m.M01; M10 = m.M10; M11 = m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M34f m) { M00 = m.M00; M01 = m.M01; M10 = m.M10; M11 = m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M44f m) { M00 = m.M00; M01 = m.M01; M10 = m.M10; M11 = m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M22d m) { M00 = (float)m.M00; M01 = (float)m.M01; M10 = (float)m.M10; M11 = (float)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M23d m) { M00 = (float)m.M00; M01 = (float)m.M01; M10 = (float)m.M10; M11 = (float)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M33d m) { M00 = (float)m.M00; M01 = (float)m.M01; M10 = (float)m.M10; M11 = (float)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M34d m) { M00 = (float)m.M00; M01 = (float)m.M01; M10 = (float)m.M10; M11 = (float)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22f(M44d m) { M00 = (float)m.M00; M01 = (float)m.M01; M10 = (float)m.M10; M11 = (float)m.M11; } #endregion #region Conversions public static explicit operator M22f(M22i m) { return new M22f { M00 = (float)m.M00, M01 = (float)m.M01, M10 = (float)m.M10, M11 = (float)m.M11, }; } public static explicit operator M22f(M23i m) { return new M22f { M00 = (float)m.M00, M01 = (float)m.M01, M10 = (float)m.M10, M11 = (float)m.M11, }; } public static explicit operator M22f(M33i m) { return new M22f { M00 = (float)m.M00, M01 = (float)m.M01, M10 = (float)m.M10, M11 = (float)m.M11, }; } public static explicit operator M22f(M34i m) { return new M22f { M00 = (float)m.M00, M01 = (float)m.M01, M10 = (float)m.M10, M11 = (float)m.M11, }; } public static explicit operator M22f(M44i m) { return new M22f { M00 = (float)m.M00, M01 = (float)m.M01, M10 = (float)m.M10, M11 = (float)m.M11, }; } public static explicit operator M22f(M22l m) { return new M22f { M00 = (float)m.M00, M01 = (float)m.M01, M10 = (float)m.M10, M11 = (float)m.M11, }; } public static explicit operator M22f(M23l m) { return new M22f { M00 = (float)m.M00, M01 = (float)m.M01, M10 = (float)m.M10, M11 = (float)m.M11, }; } public static explicit operator M22f(M33l m) { return new M22f { M00 = (float)m.M00, M01 = (float)m.M01, M10 = (float)m.M10, M11 = (float)m.M11, }; } public static explicit operator M22f(M34l m) { return new M22f { M00 = (float)m.M00, M01 = (float)m.M01, M10 = (float)m.M10, M11 = (float)m.M11, }; } public static explicit operator M22f(M44l m) { return new M22f { M00 = (float)m.M00, M01 = (float)m.M01, M10 = (float)m.M10, M11 = (float)m.M11, }; } public static explicit operator M22f(M23f m) { return new M22f { M00 = m.M00, M01 = m.M01, M10 = m.M10, M11 = m.M11, }; } public static explicit operator M22f(M33f m) { return new M22f { M00 = m.M00, M01 = m.M01, M10 = m.M10, M11 = m.M11, }; } public static explicit operator M22f(M34f m) { return new M22f { M00 = m.M00, M01 = m.M01, M10 = m.M10, M11 = m.M11, }; } public static explicit operator M22f(M44f m) { return new M22f { M00 = m.M00, M01 = m.M01, M10 = m.M10, M11 = m.M11, }; } public static explicit operator M22f(M22d m) { return new M22f { M00 = (float)m.M00, M01 = (float)m.M01, M10 = (float)m.M10, M11 = (float)m.M11, }; } public static explicit operator M22f(M23d m) { return new M22f { M00 = (float)m.M00, M01 = (float)m.M01, M10 = (float)m.M10, M11 = (float)m.M11, }; } public static explicit operator M22f(M33d m) { return new M22f { M00 = (float)m.M00, M01 = (float)m.M01, M10 = (float)m.M10, M11 = (float)m.M11, }; } public static explicit operator M22f(M34d m) { return new M22f { M00 = (float)m.M00, M01 = (float)m.M01, M10 = (float)m.M10, M11 = (float)m.M11, }; } public static explicit operator M22f(M44d m) { return new M22f { M00 = (float)m.M00, M01 = (float)m.M01, M10 = (float)m.M10, M11 = (float)m.M11, }; } public static explicit operator M22f(int[] a) { return new M22f( (float)a[0], (float)a[1], (float)a[2], (float)a[3]); } public static explicit operator M22f(int[,] a) { return new M22f( (float)a[0, 0], (float)a[0, 1], (float)a[1, 0], (float)a[1, 1]); } public static explicit operator int[](M22f m) { return new int[] { (int)m.M00, (int)m.M01, (int)m.M10, (int)m.M11 }; } public static explicit operator int[,](M22f m) { return new int[,] { { (int)m.M00, (int)m.M01 }, { (int)m.M10, (int)m.M11 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = (int)M00; array[index + 1] = (int)M01; array[index + 2] = (int)M10; array[index + 3] = (int)M11; } public static explicit operator M22f(long[] a) { return new M22f( (float)a[0], (float)a[1], (float)a[2], (float)a[3]); } public static explicit operator M22f(long[,] a) { return new M22f( (float)a[0, 0], (float)a[0, 1], (float)a[1, 0], (float)a[1, 1]); } public static explicit operator long[](M22f m) { return new long[] { (long)m.M00, (long)m.M01, (long)m.M10, (long)m.M11 }; } public static explicit operator long[,](M22f m) { return new long[,] { { (long)m.M00, (long)m.M01 }, { (long)m.M10, (long)m.M11 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = (long)M00; array[index + 1] = (long)M01; array[index + 2] = (long)M10; array[index + 3] = (long)M11; } public static explicit operator M22f(float[] a) { return new M22f( a[0], a[1], a[2], a[3]); } public static explicit operator M22f(float[,] a) { return new M22f( a[0, 0], a[0, 1], a[1, 0], a[1, 1]); } public static explicit operator float[](M22f m) { return new float[] { m.M00, m.M01, m.M10, m.M11 }; } public static explicit operator float[,](M22f m) { return new float[,] { { m.M00, m.M01 }, { m.M10, m.M11 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M10; array[index + 3] = M11; } public static explicit operator M22f(double[] a) { return new M22f( (float)a[0], (float)a[1], (float)a[2], (float)a[3]); } public static explicit operator M22f(double[,] a) { return new M22f( (float)a[0, 0], (float)a[0, 1], (float)a[1, 0], (float)a[1, 1]); } public static explicit operator double[](M22f m) { return new double[] { (double)m.M00, (double)m.M01, (double)m.M10, (double)m.M11 }; } public static explicit operator double[,](M22f m) { return new double[,] { { (double)m.M00, (double)m.M01 }, { (double)m.M10, (double)m.M11 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = (double)M00; array[index + 1] = (double)M01; array[index + 2] = (double)M10; array[index + 3] = (double)M11; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22i Copy(Func element_fun) { return new M22i( element_fun(M00), element_fun(M01), element_fun(M10), element_fun(M11)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22i Copy(Func element_index0_index1_fun) { return new M22i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22l Copy(Func element_fun) { return new M22l( element_fun(M00), element_fun(M01), element_fun(M10), element_fun(M11)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22l Copy(Func element_index0_index1_fun) { return new M22l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22f Copy(Func element_fun) { return new M22f( element_fun(M00), element_fun(M01), element_fun(M10), element_fun(M11)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22f Copy(Func element_index0_index1_fun) { return new M22f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22d Copy(Func element_fun) { return new M22d( element_fun(M00), element_fun(M01), element_fun(M10), element_fun(M11)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22d Copy(Func element_index0_index1_fun) { return new M22d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1)); } public readonly float[] ToArray() { var array = new float[4]; array[0] = M00; array[1] = M01; array[2] = M10; array[3] = M11; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f FromCols(V2f col0, V2f col1) { return new M22f( col0.X, col1.X, col0.Y, col1.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f FromRows(V2f row0, V2f row1) { return new M22f( row0.X, row0.Y, row1.X, row1.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f FromDiagonal(float value) { return new M22f( value, 0, 0, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f FromDiagonal(float m00, float m11) { return new M22f( m00, 0, 0, m11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f FromDiagonal(V2f s) { return new M22f( s.X, 0, 0, s.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f FromAntiDiagonal(float value) { return new M22f( 0, value, value, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f FromAntiDiagonal(float m01, float m10) { return new M22f( 0, m01, m10, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f FromAntiDiagonal(V2f s) { return new M22f( 0, s.X, s.Y, 0); } #region Scale /// /// Creates a transformation using 2 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f Scale(float sX, float sY) => FromDiagonal(sX, sY); /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f Scale(V2f s) => FromDiagonal(s); /// /// Creates a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f Scale(Scale2f s) { return new M22f( s.X, 0, 0, s.Y); } #endregion #region Rotation /// /// Creates a 2D rotation matrix with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f Rotation(float angleInRadians) { var a = Fun.Cos(angleInRadians); var b = Fun.Sin(angleInRadians); return new M22f( a, -b, b, a); } /// /// Creates a 2D rotation matrix with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f RotationInDegrees(float angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); /// /// Creates a 2D rotation matrix from a /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f Rotation(Rot2f r) => (M22f)r; #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f DivideByInt(M22f m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M10; yield return M11; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; } } [XmlIgnore] public V2f R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2f( M00, M01); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; } } [XmlIgnore] public V2f R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2f( M10, M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; } } [XmlIgnore] public V2f C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2f( M00, M10); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; } } [XmlIgnore] public V2f C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2f( M01, M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; } } public readonly V2f Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2f(M00, M11); } public readonly V2f AntiDiagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2f(M01, M10); } /// /// Returns the minimum element of the matrix. /// public readonly float MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M10, M11); } /// /// Returns the maximum element of the matrix. /// public readonly float MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M10, M11); } public unsafe float this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &M00) { ptr[index] = value; } } } public unsafe float this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &M00) { return ptr[row * 2 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &M00) { ptr[row * 2 + column] = value; } } } public readonly bool AnyFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) || Fun.IsFinite(M01) || Fun.IsFinite(M10) || Fun.IsFinite(M11); } } public readonly bool AllFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) && Fun.IsFinite(M01) && Fun.IsFinite(M10) && Fun.IsFinite(M11); } } public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNaN(M00) || float.IsNaN(M01) || float.IsNaN(M10) || float.IsNaN(M11); } } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNaN(M00) && float.IsNaN(M01) && float.IsNaN(M10) && float.IsNaN(M11); } } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsInfinity(M00) || float.IsInfinity(M01) || float.IsInfinity(M10) || float.IsInfinity(M11); } } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsInfinity(M00) && float.IsInfinity(M01) && float.IsInfinity(M10) && float.IsInfinity(M11); } } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsPositiveInfinity(M00) || float.IsPositiveInfinity(M01) || float.IsPositiveInfinity(M10) || float.IsPositiveInfinity(M11); } } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsPositiveInfinity(M00) && float.IsPositiveInfinity(M01) && float.IsPositiveInfinity(M10) && float.IsPositiveInfinity(M11); } } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNegativeInfinity(M00) || float.IsNegativeInfinity(M01) || float.IsNegativeInfinity(M10) || float.IsNegativeInfinity(M11); } } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNegativeInfinity(M00) && float.IsNegativeInfinity(M01) && float.IsNegativeInfinity(M10) && float.IsNegativeInfinity(M11); } } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) || Fun.IsTiny(M01) || Fun.IsTiny(M10) || Fun.IsTiny(M11); } } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) && Fun.IsTiny(M01) && Fun.IsTiny(M10) && Fun.IsTiny(M11); } } /// /// Returns true if the absolute value of each element of the matrix is smaller than Constant<float>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any element of the matrix is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any element of the matrix is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any element of the matrix is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any element of the matrix is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all elements of the matrix are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Constants public const int RowCount = 2; public const int ColumnCount = 2; public const int ElementCount = 2 * 2; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(2, 2); } public static M22f Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M22f(0); } public static M22f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M22f(1, 0, 0, 1); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly float Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M10) + Fun.Abs(M11); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly float Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M10 * M10 + M11 * M11); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly float NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly float NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator -(M22f m) { return new M22f( -m.M00, -m.M01, -m.M10, -m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator + (M22f a, M22f b) { return new M22f( a.M00 + b.M00, a.M01 + b.M01, a.M10 + b.M10, a.M11 + b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator + (M22f m, float s) { return new M22f( m.M00 + s, m.M01 + s, m.M10 + s, m.M11 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator + (float s, M22f m) { return new M22f( s + m.M00, s + m.M01, s + m.M10, s + m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator + (M22f a, M22d b) { return new M22d( a.M00 + b.M00, a.M01 + b.M01, a.M10 + b.M10, a.M11 + b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator + (M22f m, double s) { return new M22d( m.M00 + s, m.M01 + s, m.M10 + s, m.M11 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator + (double s, M22f m) { return new M22d( s + m.M00, s + m.M01, s + m.M10, s + m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator - (M22f a, M22f b) { return new M22f( a.M00 - b.M00, a.M01 - b.M01, a.M10 - b.M10, a.M11 - b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator - (M22f m, float s) { return new M22f( m.M00 - s, m.M01 - s, m.M10 - s, m.M11 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator - (float s, M22f m) { return new M22f( s - m.M00, s - m.M01, s - m.M10, s - m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator - (M22f a, M22d b) { return new M22d( a.M00 - b.M00, a.M01 - b.M01, a.M10 - b.M10, a.M11 - b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator - (M22f m, double s) { return new M22d( m.M00 - s, m.M01 - s, m.M10 - s, m.M11 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator - (double s, M22f m) { return new M22d( s - m.M00, s - m.M01, s - m.M10, s - m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator % (M22f a, M22f b) { return new M22f( a.M00 % b.M00, a.M01 % b.M01, a.M10 % b.M10, a.M11 % b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator % (M22f m, float s) { return new M22f( m.M00 % s, m.M01 % s, m.M10 % s, m.M11 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator % (float s, M22f m) { return new M22f( s % m.M00, s % m.M01, s % m.M10, s % m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator % (M22f a, M22d b) { return new M22d( a.M00 % b.M00, a.M01 % b.M01, a.M10 % b.M10, a.M11 % b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator % (M22f m, double s) { return new M22d( m.M00 % s, m.M01 % s, m.M10 % s, m.M11 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator % (double s, M22f m) { return new M22d( s % m.M00, s % m.M01, s % m.M10, s % m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator / (M22f a, M22f b) { return new M22f( a.M00 / b.M00, a.M01 / b.M01, a.M10 / b.M10, a.M11 / b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator / (M22f m, float s) { return new M22f( m.M00 / s, m.M01 / s, m.M10 / s, m.M11 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator / (float s, M22f m) { return new M22f( s / m.M00, s / m.M01, s / m.M10, s / m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator / (M22f a, M22d b) { return new M22d( a.M00 / b.M00, a.M01 / b.M01, a.M10 / b.M10, a.M11 / b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator / (M22f m, double s) { return new M22d( m.M00 / s, m.M01 / s, m.M10 / s, m.M11 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator / (double s, M22f m) { return new M22d( s / m.M00, s / m.M01, s / m.M10, s / m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator * (M22f m, float s) { return new M22f( m.M00 * s, m.M01 * s, m.M10 * s, m.M11 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator * (float s, M22f m) { return new M22f( s * m.M00, s * m.M01, s * m.M10, s * m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator * (M22f m, double s) { return new M22d( m.M00 * s, m.M01 * s, m.M10 * s, m.M11 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator * (double s, M22f m) { return new M22d( s * m.M00, s * m.M01, s * m.M10, s * m.M11); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M22f matrix with a V2f column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator *(M22f m, V2f v) { return new V2f( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y); } /// /// Multiplies a V2f row vector with a M22f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator *(V2f v, M22f m) { return new V2f( v.X * m.M00 + v.Y * m.M10, v.X * m.M01 + v.Y * m.M11); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M22f a, M22f b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M10 == b.M10 && a.M11 == b.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M22f a, float s) { return a.M00 == s && a.M01 == s && a.M10 == s && a.M11 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(float s, M22f a) { return s == a.M00 && s == a.M01 && s == a.M10 && s == a.M11 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M22f a, M22f b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M22f m, float s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(float s, M22f m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01), HashCode.GetCombined(M10, M11)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M22f other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M10.Equals(other.M10) && M11.Equals(other.M11); } public override readonly bool Equals(object other) => (other is M22f o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M22f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M22f.FromRows( V2f.Parse(x[0]), V2f.Parse(x[1]) ); } #endregion #region Matrix Operations /// /// Returns adjoint of this matrix. /// public readonly M22f Adjoint { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new M22f(M11, -M10, -M01, M00); } } /// /// Returns the trace of this matrix. /// The trace is defined as the sum of the diagonal elements, /// and is only defined for square matrices. /// public readonly float Trace { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return M00 + M11 ; } } /// /// Gets the determinant of this matrix. /// The determinant is only defined for square matrices. /// public readonly float Determinant { get { return M00 * M11 - M10 * M01; } } /// /// Returns whether this matrix is invertible. /// A matrix is invertible if its determinant is not zero. /// public readonly bool Invertible { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant != 0; } } /// /// Returns whether this matrix is singular. /// A matrix is singular if its determinant is zero. /// public readonly bool Singular { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant == 0; } } /// /// Gets transpose of this matrix. /// public readonly M22f Transposed { get { return new M22f { M00 = M00, M01 = M10, M10 = M01, M11 = M11 }; } } private static V2l s_luSize = new V2l(2, 2); private static V2l s_luDelta = new V2l(1, 2); /// /// Inverts the given matrix using lu factorization in place. Returns true /// if the matrix was invertible, otherwise the matrix remains unchanged. /// public bool LuInvert() { M22d dbl = (M22d)this; if(dbl.LuInvert()) { this = (M22f)dbl; return true; } return false; } /// /// Returns the inverse of the matrix using lu factorization. /// If the matrix is not invertible, M22f.Zero is returned. /// public readonly M22f LuInverse() { return (M22f)((M22d)this).LuInverse(); } /// /// Returns the inverse of this matrix. If the matrix is not invertible /// M22f.Zero is returned. /// public readonly M22f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => LuInverse(); } #endregion #region Matrix Multiplication public static M22f operator *(M22f a, M22f b) { return new M22f( a.M00 * b.M00 + a.M01 * b.M10, a.M00 * b.M01 + a.M01 * b.M11, a.M10 * b.M00 + a.M11 * b.M10, a.M10 * b.M01 + a.M11 * b.M11 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return (double)this[(int)y, (int)x]; } set { this[(int)y, (int)x] = (float)value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return (double)this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = (float)value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (float)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (float)value; } #endregion } public class M22fEqualityComparer : IEqualityComparer { public static readonly M22fEqualityComparer Default = new M22fEqualityComparer(); #region IEqualityComparer Members public bool Equals(M22f v0, M22f v1) { return v0 == v1; } public int GetHashCode(M22f v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Computes the (signed) angle in radians of a rotation matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetRotation(this M22f m) => Fun.Atan2(m.M10, m.M00); /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetScale(this M22f m) => (m.C0.Length + m.C1.Length) / 2; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetScaleVector(this M22f m) => new V2f(m.C0.Length, m.C1.Length); #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm1(M22f m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm2(M22f m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormMax(M22f m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormMin(M22f m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm(this M22f m, float p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static float Distance1(this M22f a, M22f b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static float Distance2(this M22f a, M22f b) { return (float)Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11)); } /// /// Returns the p-distance between two matrices. /// public static float Distance(this M22f a, M22f b, float p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static float DistanceMax(this M22f a, M22f b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static float DistanceMin(this M22f a, M22f b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Transform(this M22f m, V2f v) => m * v; /// /// Transforms vector v by matrix m. /// v.Z is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Transform(this M22f m, V3f v) { return new V3f( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y, v.Z); } /// /// Transforms vector v by matrix m. /// v.Z and v.W are not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Transform(this M22f m, V4f v) { return new V4f( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y, v.Z, v.W); } /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f TransposedTransform(this M22f m, V2f v) => v * m; /// /// Transforms vector v by the transpose of matrix m. /// v.Z is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransposedTransform(this M22f m, V3f v) { return new V3f( v.X * m.M00 + v.Y * m.M10, v.X * m.M01 + v.Y * m.M11, v.Z); } /// /// Transforms vector v by the transpose of matrix m. /// v.Z and v.W are not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f TransposedTransform(this M22f m, V4f v) { return new V4f( v.X * m.M00 + v.Y * m.M10, v.X * m.M01 + v.Y * m.M11, v.Z, v.W); } #endregion #region Operations /// /// Returns the given to a deleting the /// specified row and column. /// public static float Minor(this M22f m, int row, int column) { return m[1 - row, 1 - column]; } /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V2f Row(this M22f m, int index) { float* ptr = &m.M00; return new V2f(ptr[index * 2], ptr[index * 2 + 1]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V2f Column(this M22f m, int index) { float* ptr = &m.M00; return new V2f(ptr[index], ptr[index + 2]); } /// /// Returns the determinant of the given matrix. /// The determinant is only defined for square matrices. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Determinant(M22f m) => m.Determinant; /// /// Returns the transpose of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f Transposed(M22f m) => m.Transposed; /// /// Transposes the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transpose(this ref M22f m) { Fun.Swap(ref m.M10, ref m.M01); } /// /// Returns the inverse of the given matrix. If the matrix is not invertible /// M22f.Zero is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f Inverse(M22f m) => m.Inverse; /// /// Inverts the given matrix in place. Returns true if the matrix was invertible, /// otherwise the matrix remains unchanged. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Invert(this ref M22f m) { return m.LuInvert(); } /// /// Returns if the given matrix is the identity matrix I. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIdentity(this M22f m, float epsilon) { return Fun.ApproximateEquals(m, M22f.Identity, epsilon); } /// /// Returns if the given matrix is the identity matrix I. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIdentity(this M22f m) => IsIdentity(m, Constant.PositiveTinyValue); /// /// Returns if the given matrix is orthonormal (i.e. M * M^t == I) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthonormal(this M22f m, float epsilon) { var i = m * m.Transposed; return i.IsIdentity(epsilon); } /// /// Returns if the given matrix is orthonormal (i.e. M * M^t == I) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthonormal(this M22f m) => IsOrthonormal(m, Constant.PositiveTinyValue); /// /// Returns if the given matrix is orthogonal (i.e. all non-diagonal entries of M * M^t == 0) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonal(this M22f m, float epsilon) { var i = m * m.Transposed; for (int j = 0; j < 2; j++) i[j, j] = 1; //inefficient implementation: just leave out the comparisons at the diagonal entries. return i.IsIdentity(epsilon); } /// /// Returns if the given matrix is orthogonal (i.e. all non-diagonal entries of M * M^t == 0) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonal(this M22f m) => IsOrthogonal(m, Constant.PositiveTinyValue); #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M22f a, M22f b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M10 < b.M10 && a.M11 < b.M11; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M22f m, float s) { return m.M00 < s && m.M01 < s && m.M10 < s && m.M11 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(float s, M22f m) { return s < m.M00 && s < m.M01 && s < m.M10 && s < m.M11; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M22f a, M22f b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M10 < b.M10 || a.M11 < b.M11; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M22f m, float s) { return m.M00 < s || m.M01 < s || m.M10 < s || m.M11 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(float s, M22f m) { return s < m.M00 || s < m.M01 || s < m.M10 || s < m.M11; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M22f a, M22f b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M10 > b.M10 && a.M11 > b.M11; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M22f m, float s) { return m.M00 > s && m.M01 > s && m.M10 > s && m.M11 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(float s, M22f m) { return s > m.M00 && s > m.M01 && s > m.M10 && s > m.M11; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M22f a, M22f b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M10 > b.M10 || a.M11 > b.M11; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M22f m, float s) { return m.M00 > s || m.M01 > s || m.M10 > s || m.M11 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(float s, M22f m) { return s > m.M00 || s > m.M01 || s > m.M10 || s > m.M11; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M22f a, M22f b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M10 <= b.M10 && a.M11 <= b.M11; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M22f m, float s) { return m.M00 <= s && m.M01 <= s && m.M10 <= s && m.M11 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(float s, M22f m) { return s <= m.M00 && s <= m.M01 && s <= m.M10 && s <= m.M11; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M22f a, M22f b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M10 <= b.M10 || a.M11 <= b.M11; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M22f m, float s) { return m.M00 <= s || m.M01 <= s || m.M10 <= s || m.M11 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(float s, M22f m) { return s <= m.M00 || s <= m.M01 || s <= m.M10 || s <= m.M11; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M22f a, M22f b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M10 >= b.M10 && a.M11 >= b.M11; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M22f m, float s) { return m.M00 >= s && m.M01 >= s && m.M10 >= s && m.M11 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(float s, M22f m) { return s >= m.M00 && s >= m.M01 && s >= m.M10 && s >= m.M11; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M22f a, M22f b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M10 >= b.M10 || a.M11 >= b.M11; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M22f m, float s) { return m.M00 >= s || m.M01 >= s || m.M10 >= s || m.M11 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(float s, M22f m) { return s >= m.M00 || s >= m.M01 || s >= m.M10 || s >= m.M11; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M22f a, M22f b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M10 == b.M10 && a.M11 == b.M11; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M22f m, float s) { return m.M00 == s && m.M01 == s && m.M10 == s && m.M11 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(float s, M22f m) { return s == m.M00 && s == m.M01 && s == m.M10 && s == m.M11; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M22f a, M22f b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M10 == b.M10 || a.M11 == b.M11; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M22f m, float s) { return m.M00 == s || m.M01 == s || m.M10 == s || m.M11 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(float s, M22f m) { return s == m.M00 || s == m.M01 || s == m.M10 || s == m.M11; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M22f a, M22f b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M10 != b.M10 && a.M11 != b.M11; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M22f m, float s) { return m.M00 != s && m.M01 != s && m.M10 != s && m.M11 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(float s, M22f m) { return s != m.M00 && s != m.M01 && s != m.M10 && s != m.M11; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M22f a, M22f b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M10 != b.M10 || a.M11 != b.M11; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M22f m, float s) { return m.M00 != s || m.M01 != s || m.M10 != s || m.M11 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(float s, M22f m) { return s != m.M00 || s != m.M01 || s != m.M10 || s != m.M11; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M22f m0, M22f m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MinElement(M22f m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MaxElement(M22f m) => m.MaxElement; #endregion #region Orthogonalization /// /// Orthogonalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// public static void Orthogonalize(this ref M22f matrix) { matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; } /// /// Orthogonalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f Orthogonalized(this M22f matrix) { M22f m = matrix; Orthogonalize(ref m); return m; } /// /// Orthonormalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// public static void Orthonormalize(this ref M22f matrix) { matrix.C0 = matrix.C0.Normalized; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 = matrix.C1.Normalized; } /// /// Orthonormalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f Orthonormalized(this M22f matrix) { M22f m = matrix; Orthonormalize(ref m); return m; } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M22f m, float epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M22f m, float epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyFinite(M22f m) => m.AnyFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllFinite(M22f m) => m.AllFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(M22f m) => m.AnyNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(M22f m) => m.AllNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(M22f m) => m.AnyInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(M22f m) => m.AllInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(M22f m) => m.AnyPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(M22f m) => m.AllPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(M22f m) => m.AnyNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(M22f m) => m.AllNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(M22f m) => m.AnyTiny; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(M22f m) => m.AllTiny; #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M22f a, M22f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M22f a, M22f b, float epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M22f m, float epsilon) => Mat.AllTiny(m, epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(M22f m) => m.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any element of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(M22f v) => v.IsNaN; /// /// Returns whether any element of the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(M22f v) => v.IsInfinity; /// /// Returns whether any element of the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(M22f v) => v.IsPositiveInfinity; /// /// Returns whether any element of the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(M22f v) => v.IsNegativeInfinity; /// /// Returns whether all elements of the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(M22f v) => v.IsFinite; #endregion } public static class IRandomUniformM22fExtensions { #region IRandomUniform extensions for M22f /// /// Uses UniformFloat() to generate the elements of an M22f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f UniformM22f(this IRandomUniform rnd) { return new M22f( rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat()); } /// /// Uses UniformFloatClosed() to generate the elements of an M22f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f UniformM22fClosed(this IRandomUniform rnd) { return new M22f( rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed()); } /// /// Uses UniformFloatOpen() to generate the elements of an M22f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f UniformM22fOpen(this IRandomUniform rnd) { return new M22f( rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen()); } #endregion } #endregion #region M22d [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M22d : IEquatable, IValidity, IMatrix { [DataMember] public double M00, M01; [DataMember] public double M10, M11; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(double value) { M00 = value; M01 = 0; M10 = 0; M11 = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d( double m00, double m01, double m10, double m11) { M00 = m00; M01 = m01; M10 = m10; M11 = m11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(double[] a) { M00 = a[0]; M01 = a[1]; M10 = a[2]; M11 = a[3]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(double[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M10 = a[start + 2]; M11 = a[start + 3]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M22i m) { M00 = (double)m.M00; M01 = (double)m.M01; M10 = (double)m.M10; M11 = (double)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M23i m) { M00 = (double)m.M00; M01 = (double)m.M01; M10 = (double)m.M10; M11 = (double)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M33i m) { M00 = (double)m.M00; M01 = (double)m.M01; M10 = (double)m.M10; M11 = (double)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M34i m) { M00 = (double)m.M00; M01 = (double)m.M01; M10 = (double)m.M10; M11 = (double)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M44i m) { M00 = (double)m.M00; M01 = (double)m.M01; M10 = (double)m.M10; M11 = (double)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M22l m) { M00 = (double)m.M00; M01 = (double)m.M01; M10 = (double)m.M10; M11 = (double)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M23l m) { M00 = (double)m.M00; M01 = (double)m.M01; M10 = (double)m.M10; M11 = (double)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M33l m) { M00 = (double)m.M00; M01 = (double)m.M01; M10 = (double)m.M10; M11 = (double)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M34l m) { M00 = (double)m.M00; M01 = (double)m.M01; M10 = (double)m.M10; M11 = (double)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M44l m) { M00 = (double)m.M00; M01 = (double)m.M01; M10 = (double)m.M10; M11 = (double)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M22f m) { M00 = (double)m.M00; M01 = (double)m.M01; M10 = (double)m.M10; M11 = (double)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M23f m) { M00 = (double)m.M00; M01 = (double)m.M01; M10 = (double)m.M10; M11 = (double)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M33f m) { M00 = (double)m.M00; M01 = (double)m.M01; M10 = (double)m.M10; M11 = (double)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M34f m) { M00 = (double)m.M00; M01 = (double)m.M01; M10 = (double)m.M10; M11 = (double)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M44f m) { M00 = (double)m.M00; M01 = (double)m.M01; M10 = (double)m.M10; M11 = (double)m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M23d m) { M00 = m.M00; M01 = m.M01; M10 = m.M10; M11 = m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M33d m) { M00 = m.M00; M01 = m.M01; M10 = m.M10; M11 = m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M34d m) { M00 = m.M00; M01 = m.M01; M10 = m.M10; M11 = m.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M22d(M44d m) { M00 = m.M00; M01 = m.M01; M10 = m.M10; M11 = m.M11; } #endregion #region Conversions public static explicit operator M22d(M22i m) { return new M22d { M00 = (double)m.M00, M01 = (double)m.M01, M10 = (double)m.M10, M11 = (double)m.M11, }; } public static explicit operator M22d(M23i m) { return new M22d { M00 = (double)m.M00, M01 = (double)m.M01, M10 = (double)m.M10, M11 = (double)m.M11, }; } public static explicit operator M22d(M33i m) { return new M22d { M00 = (double)m.M00, M01 = (double)m.M01, M10 = (double)m.M10, M11 = (double)m.M11, }; } public static explicit operator M22d(M34i m) { return new M22d { M00 = (double)m.M00, M01 = (double)m.M01, M10 = (double)m.M10, M11 = (double)m.M11, }; } public static explicit operator M22d(M44i m) { return new M22d { M00 = (double)m.M00, M01 = (double)m.M01, M10 = (double)m.M10, M11 = (double)m.M11, }; } public static explicit operator M22d(M22l m) { return new M22d { M00 = (double)m.M00, M01 = (double)m.M01, M10 = (double)m.M10, M11 = (double)m.M11, }; } public static explicit operator M22d(M23l m) { return new M22d { M00 = (double)m.M00, M01 = (double)m.M01, M10 = (double)m.M10, M11 = (double)m.M11, }; } public static explicit operator M22d(M33l m) { return new M22d { M00 = (double)m.M00, M01 = (double)m.M01, M10 = (double)m.M10, M11 = (double)m.M11, }; } public static explicit operator M22d(M34l m) { return new M22d { M00 = (double)m.M00, M01 = (double)m.M01, M10 = (double)m.M10, M11 = (double)m.M11, }; } public static explicit operator M22d(M44l m) { return new M22d { M00 = (double)m.M00, M01 = (double)m.M01, M10 = (double)m.M10, M11 = (double)m.M11, }; } public static explicit operator M22d(M22f m) { return new M22d { M00 = (double)m.M00, M01 = (double)m.M01, M10 = (double)m.M10, M11 = (double)m.M11, }; } public static explicit operator M22d(M23f m) { return new M22d { M00 = (double)m.M00, M01 = (double)m.M01, M10 = (double)m.M10, M11 = (double)m.M11, }; } public static explicit operator M22d(M33f m) { return new M22d { M00 = (double)m.M00, M01 = (double)m.M01, M10 = (double)m.M10, M11 = (double)m.M11, }; } public static explicit operator M22d(M34f m) { return new M22d { M00 = (double)m.M00, M01 = (double)m.M01, M10 = (double)m.M10, M11 = (double)m.M11, }; } public static explicit operator M22d(M44f m) { return new M22d { M00 = (double)m.M00, M01 = (double)m.M01, M10 = (double)m.M10, M11 = (double)m.M11, }; } public static explicit operator M22d(M23d m) { return new M22d { M00 = m.M00, M01 = m.M01, M10 = m.M10, M11 = m.M11, }; } public static explicit operator M22d(M33d m) { return new M22d { M00 = m.M00, M01 = m.M01, M10 = m.M10, M11 = m.M11, }; } public static explicit operator M22d(M34d m) { return new M22d { M00 = m.M00, M01 = m.M01, M10 = m.M10, M11 = m.M11, }; } public static explicit operator M22d(M44d m) { return new M22d { M00 = m.M00, M01 = m.M01, M10 = m.M10, M11 = m.M11, }; } public static explicit operator M22d(int[] a) { return new M22d( (double)a[0], (double)a[1], (double)a[2], (double)a[3]); } public static explicit operator M22d(int[,] a) { return new M22d( (double)a[0, 0], (double)a[0, 1], (double)a[1, 0], (double)a[1, 1]); } public static explicit operator int[](M22d m) { return new int[] { (int)m.M00, (int)m.M01, (int)m.M10, (int)m.M11 }; } public static explicit operator int[,](M22d m) { return new int[,] { { (int)m.M00, (int)m.M01 }, { (int)m.M10, (int)m.M11 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = (int)M00; array[index + 1] = (int)M01; array[index + 2] = (int)M10; array[index + 3] = (int)M11; } public static explicit operator M22d(long[] a) { return new M22d( (double)a[0], (double)a[1], (double)a[2], (double)a[3]); } public static explicit operator M22d(long[,] a) { return new M22d( (double)a[0, 0], (double)a[0, 1], (double)a[1, 0], (double)a[1, 1]); } public static explicit operator long[](M22d m) { return new long[] { (long)m.M00, (long)m.M01, (long)m.M10, (long)m.M11 }; } public static explicit operator long[,](M22d m) { return new long[,] { { (long)m.M00, (long)m.M01 }, { (long)m.M10, (long)m.M11 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = (long)M00; array[index + 1] = (long)M01; array[index + 2] = (long)M10; array[index + 3] = (long)M11; } public static explicit operator M22d(float[] a) { return new M22d( (double)a[0], (double)a[1], (double)a[2], (double)a[3]); } public static explicit operator M22d(float[,] a) { return new M22d( (double)a[0, 0], (double)a[0, 1], (double)a[1, 0], (double)a[1, 1]); } public static explicit operator float[](M22d m) { return new float[] { (float)m.M00, (float)m.M01, (float)m.M10, (float)m.M11 }; } public static explicit operator float[,](M22d m) { return new float[,] { { (float)m.M00, (float)m.M01 }, { (float)m.M10, (float)m.M11 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = (float)M00; array[index + 1] = (float)M01; array[index + 2] = (float)M10; array[index + 3] = (float)M11; } public static explicit operator M22d(double[] a) { return new M22d( a[0], a[1], a[2], a[3]); } public static explicit operator M22d(double[,] a) { return new M22d( a[0, 0], a[0, 1], a[1, 0], a[1, 1]); } public static explicit operator double[](M22d m) { return new double[] { m.M00, m.M01, m.M10, m.M11 }; } public static explicit operator double[,](M22d m) { return new double[,] { { m.M00, m.M01 }, { m.M10, m.M11 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M10; array[index + 3] = M11; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22i Copy(Func element_fun) { return new M22i( element_fun(M00), element_fun(M01), element_fun(M10), element_fun(M11)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22i Copy(Func element_index0_index1_fun) { return new M22i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22l Copy(Func element_fun) { return new M22l( element_fun(M00), element_fun(M01), element_fun(M10), element_fun(M11)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22l Copy(Func element_index0_index1_fun) { return new M22l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22f Copy(Func element_fun) { return new M22f( element_fun(M00), element_fun(M01), element_fun(M10), element_fun(M11)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22f Copy(Func element_index0_index1_fun) { return new M22f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22d Copy(Func element_fun) { return new M22d( element_fun(M00), element_fun(M01), element_fun(M10), element_fun(M11)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M22d Copy(Func element_index0_index1_fun) { return new M22d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1)); } public readonly double[] ToArray() { var array = new double[4]; array[0] = M00; array[1] = M01; array[2] = M10; array[3] = M11; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d FromCols(V2d col0, V2d col1) { return new M22d( col0.X, col1.X, col0.Y, col1.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d FromRows(V2d row0, V2d row1) { return new M22d( row0.X, row0.Y, row1.X, row1.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d FromDiagonal(double value) { return new M22d( value, 0, 0, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d FromDiagonal(double m00, double m11) { return new M22d( m00, 0, 0, m11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d FromDiagonal(V2d s) { return new M22d( s.X, 0, 0, s.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d FromAntiDiagonal(double value) { return new M22d( 0, value, value, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d FromAntiDiagonal(double m01, double m10) { return new M22d( 0, m01, m10, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d FromAntiDiagonal(V2d s) { return new M22d( 0, s.X, s.Y, 0); } #region Scale /// /// Creates a transformation using 2 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d Scale(double sX, double sY) => FromDiagonal(sX, sY); /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d Scale(V2d s) => FromDiagonal(s); /// /// Creates a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d Scale(Scale2d s) { return new M22d( s.X, 0, 0, s.Y); } #endregion #region Rotation /// /// Creates a 2D rotation matrix with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d Rotation(double angleInRadians) { var a = Fun.Cos(angleInRadians); var b = Fun.Sin(angleInRadians); return new M22d( a, -b, b, a); } /// /// Creates a 2D rotation matrix with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d RotationInDegrees(double angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); /// /// Creates a 2D rotation matrix from a /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d Rotation(Rot2d r) => (M22d)r; #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d DivideByInt(M22d m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M10; yield return M11; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; } } [XmlIgnore] public V2d R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2d( M00, M01); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; } } [XmlIgnore] public V2d R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2d( M10, M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; } } [XmlIgnore] public V2d C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2d( M00, M10); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; } } [XmlIgnore] public V2d C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2d( M01, M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; } } public readonly V2d Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2d(M00, M11); } public readonly V2d AntiDiagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2d(M01, M10); } /// /// Returns the minimum element of the matrix. /// public readonly double MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M10, M11); } /// /// Returns the maximum element of the matrix. /// public readonly double MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M10, M11); } public unsafe double this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &M00) { ptr[index] = value; } } } public unsafe double this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &M00) { return ptr[row * 2 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &M00) { ptr[row * 2 + column] = value; } } } public readonly bool AnyFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) || Fun.IsFinite(M01) || Fun.IsFinite(M10) || Fun.IsFinite(M11); } } public readonly bool AllFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) && Fun.IsFinite(M01) && Fun.IsFinite(M10) && Fun.IsFinite(M11); } } public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNaN(M00) || double.IsNaN(M01) || double.IsNaN(M10) || double.IsNaN(M11); } } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNaN(M00) && double.IsNaN(M01) && double.IsNaN(M10) && double.IsNaN(M11); } } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsInfinity(M00) || double.IsInfinity(M01) || double.IsInfinity(M10) || double.IsInfinity(M11); } } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsInfinity(M00) && double.IsInfinity(M01) && double.IsInfinity(M10) && double.IsInfinity(M11); } } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsPositiveInfinity(M00) || double.IsPositiveInfinity(M01) || double.IsPositiveInfinity(M10) || double.IsPositiveInfinity(M11); } } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsPositiveInfinity(M00) && double.IsPositiveInfinity(M01) && double.IsPositiveInfinity(M10) && double.IsPositiveInfinity(M11); } } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNegativeInfinity(M00) || double.IsNegativeInfinity(M01) || double.IsNegativeInfinity(M10) || double.IsNegativeInfinity(M11); } } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNegativeInfinity(M00) && double.IsNegativeInfinity(M01) && double.IsNegativeInfinity(M10) && double.IsNegativeInfinity(M11); } } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) || Fun.IsTiny(M01) || Fun.IsTiny(M10) || Fun.IsTiny(M11); } } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) && Fun.IsTiny(M01) && Fun.IsTiny(M10) && Fun.IsTiny(M11); } } /// /// Returns true if the absolute value of each element of the matrix is smaller than Constant<double>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any element of the matrix is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any element of the matrix is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any element of the matrix is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any element of the matrix is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all elements of the matrix are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Constants public const int RowCount = 2; public const int ColumnCount = 2; public const int ElementCount = 2 * 2; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(2, 2); } public static M22d Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M22d(0); } public static M22d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M22d(1, 0, 0, 1); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly double Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M10) + Fun.Abs(M11); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly double Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M10 * M10 + M11 * M11); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly double NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly double NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator -(M22d m) { return new M22d( -m.M00, -m.M01, -m.M10, -m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator + (M22d a, M22d b) { return new M22d( a.M00 + b.M00, a.M01 + b.M01, a.M10 + b.M10, a.M11 + b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator + (M22d m, double s) { return new M22d( m.M00 + s, m.M01 + s, m.M10 + s, m.M11 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator + (double s, M22d m) { return new M22d( s + m.M00, s + m.M01, s + m.M10, s + m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator - (M22d a, M22d b) { return new M22d( a.M00 - b.M00, a.M01 - b.M01, a.M10 - b.M10, a.M11 - b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator - (M22d m, double s) { return new M22d( m.M00 - s, m.M01 - s, m.M10 - s, m.M11 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator - (double s, M22d m) { return new M22d( s - m.M00, s - m.M01, s - m.M10, s - m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator % (M22d a, M22d b) { return new M22d( a.M00 % b.M00, a.M01 % b.M01, a.M10 % b.M10, a.M11 % b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator % (M22d m, double s) { return new M22d( m.M00 % s, m.M01 % s, m.M10 % s, m.M11 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator % (double s, M22d m) { return new M22d( s % m.M00, s % m.M01, s % m.M10, s % m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator / (M22d a, M22d b) { return new M22d( a.M00 / b.M00, a.M01 / b.M01, a.M10 / b.M10, a.M11 / b.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator / (M22d m, double s) { return new M22d( m.M00 / s, m.M01 / s, m.M10 / s, m.M11 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator / (double s, M22d m) { return new M22d( s / m.M00, s / m.M01, s / m.M10, s / m.M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator * (M22d m, double s) { return new M22d( m.M00 * s, m.M01 * s, m.M10 * s, m.M11 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator * (double s, M22d m) { return new M22d( s * m.M00, s * m.M01, s * m.M10, s * m.M11); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M22d matrix with a V2d column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator *(M22d m, V2d v) { return new V2d( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y); } /// /// Multiplies a V2d row vector with a M22d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator *(V2d v, M22d m) { return new V2d( v.X * m.M00 + v.Y * m.M10, v.X * m.M01 + v.Y * m.M11); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M22d a, M22d b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M10 == b.M10 && a.M11 == b.M11; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M22d a, double s) { return a.M00 == s && a.M01 == s && a.M10 == s && a.M11 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(double s, M22d a) { return s == a.M00 && s == a.M01 && s == a.M10 && s == a.M11 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M22d a, M22d b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M22d m, double s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(double s, M22d m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01), HashCode.GetCombined(M10, M11)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M22d other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M10.Equals(other.M10) && M11.Equals(other.M11); } public override readonly bool Equals(object other) => (other is M22d o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M22d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M22d.FromRows( V2d.Parse(x[0]), V2d.Parse(x[1]) ); } #endregion #region Matrix Operations /// /// Returns adjoint of this matrix. /// public readonly M22d Adjoint { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new M22d(M11, -M10, -M01, M00); } } /// /// Returns the trace of this matrix. /// The trace is defined as the sum of the diagonal elements, /// and is only defined for square matrices. /// public readonly double Trace { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return M00 + M11 ; } } /// /// Gets the determinant of this matrix. /// The determinant is only defined for square matrices. /// public readonly double Determinant { get { return M00 * M11 - M10 * M01; } } /// /// Returns whether this matrix is invertible. /// A matrix is invertible if its determinant is not zero. /// public readonly bool Invertible { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant != 0; } } /// /// Returns whether this matrix is singular. /// A matrix is singular if its determinant is zero. /// public readonly bool Singular { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant == 0; } } /// /// Gets transpose of this matrix. /// public readonly M22d Transposed { get { return new M22d { M00 = M00, M01 = M10, M10 = M01, M11 = M11 }; } } private static V2l s_luSize = new V2l(2, 2); private static V2l s_luDelta = new V2l(1, 2); /// /// Inverts the given matrix using lu factorization in place. Returns true /// if the matrix was invertible, otherwise the matrix remains unchanged. /// public unsafe bool LuInvert() { fixed (M22d* self = &this) { var lu = this; V2i perm; if (NumericExtensions.LuFactorize((double*)&lu, 0, 1, 2, (int*)&perm, 2)) { NumericExtensions.LuInverse((double*)&lu, 0, 1, 2, (int*)&perm, (double*)self, 0, 1, 2, 2); return true; } return false; } } /// /// Returns the inverse of the matrix using lu factorization. /// If the matrix is not invertible, M22d.Zero is returned. /// public unsafe readonly M22d LuInverse() { var lu = this; M22d res; V2i perm; if (NumericExtensions.LuFactorize((double*)&lu, 0, 1, 2, (int*)&perm, 2)) { NumericExtensions.LuInverse((double*)&lu, 0, 1, 2, (int*)&perm, (double*)&res, 0, 1, 2, 2); return res; } return M22d.Zero; } /// /// Returns the inverse of this matrix. If the matrix is not invertible /// M22d.Zero is returned. /// public readonly M22d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => LuInverse(); } #endregion #region Matrix Multiplication public static M22d operator *(M22d a, M22d b) { return new M22d( a.M00 * b.M00 + a.M01 * b.M10, a.M00 * b.M01 + a.M01 * b.M11, a.M10 * b.M00 + a.M11 * b.M10, a.M10 * b.M01 + a.M11 * b.M11 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return this[(int)y, (int)x]; } set { this[(int)y, (int)x] = value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (double)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (double)value; } #endregion } public class M22dEqualityComparer : IEqualityComparer { public static readonly M22dEqualityComparer Default = new M22dEqualityComparer(); #region IEqualityComparer Members public bool Equals(M22d v0, M22d v1) { return v0 == v1; } public int GetHashCode(M22d v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Computes the (signed) angle in radians of a rotation matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetRotation(this M22d m) => Fun.Atan2(m.M10, m.M00); /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this M22d m) => (m.C0.Length + m.C1.Length) / 2; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetScaleVector(this M22d m) => new V2d(m.C0.Length, m.C1.Length); #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm1(M22d m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(M22d m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormMax(M22d m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormMin(M22d m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this M22d m, double p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static double Distance1(this M22d a, M22d b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static double Distance2(this M22d a, M22d b) { return Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11)); } /// /// Returns the p-distance between two matrices. /// public static double Distance(this M22d a, M22d b, double p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static double DistanceMax(this M22d a, M22d b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static double DistanceMin(this M22d a, M22d b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Transform(this M22d m, V2d v) => m * v; /// /// Transforms vector v by matrix m. /// v.Z is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Transform(this M22d m, V3d v) { return new V3d( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y, v.Z); } /// /// Transforms vector v by matrix m. /// v.Z and v.W are not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Transform(this M22d m, V4d v) { return new V4d( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y, v.Z, v.W); } /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d TransposedTransform(this M22d m, V2d v) => v * m; /// /// Transforms vector v by the transpose of matrix m. /// v.Z is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransposedTransform(this M22d m, V3d v) { return new V3d( v.X * m.M00 + v.Y * m.M10, v.X * m.M01 + v.Y * m.M11, v.Z); } /// /// Transforms vector v by the transpose of matrix m. /// v.Z and v.W are not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d TransposedTransform(this M22d m, V4d v) { return new V4d( v.X * m.M00 + v.Y * m.M10, v.X * m.M01 + v.Y * m.M11, v.Z, v.W); } #endregion #region Operations /// /// Returns the given to a deleting the /// specified row and column. /// public static double Minor(this M22d m, int row, int column) { return m[1 - row, 1 - column]; } /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V2d Row(this M22d m, int index) { double* ptr = &m.M00; return new V2d(ptr[index * 2], ptr[index * 2 + 1]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V2d Column(this M22d m, int index) { double* ptr = &m.M00; return new V2d(ptr[index], ptr[index + 2]); } /// /// Returns the determinant of the given matrix. /// The determinant is only defined for square matrices. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Determinant(M22d m) => m.Determinant; /// /// Returns the transpose of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d Transposed(M22d m) => m.Transposed; /// /// Transposes the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transpose(this ref M22d m) { Fun.Swap(ref m.M10, ref m.M01); } /// /// Returns the inverse of the given matrix. If the matrix is not invertible /// M22d.Zero is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d Inverse(M22d m) => m.Inverse; /// /// Inverts the given matrix in place. Returns true if the matrix was invertible, /// otherwise the matrix remains unchanged. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Invert(this ref M22d m) { return m.LuInvert(); } /// /// Returns if the given matrix is the identity matrix I. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIdentity(this M22d m, double epsilon) { return Fun.ApproximateEquals(m, M22d.Identity, epsilon); } /// /// Returns if the given matrix is the identity matrix I. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIdentity(this M22d m) => IsIdentity(m, Constant.PositiveTinyValue); /// /// Returns if the given matrix is orthonormal (i.e. M * M^t == I) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthonormal(this M22d m, double epsilon) { var i = m * m.Transposed; return i.IsIdentity(epsilon); } /// /// Returns if the given matrix is orthonormal (i.e. M * M^t == I) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthonormal(this M22d m) => IsOrthonormal(m, Constant.PositiveTinyValue); /// /// Returns if the given matrix is orthogonal (i.e. all non-diagonal entries of M * M^t == 0) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonal(this M22d m, double epsilon) { var i = m * m.Transposed; for (int j = 0; j < 2; j++) i[j, j] = 1; //inefficient implementation: just leave out the comparisons at the diagonal entries. return i.IsIdentity(epsilon); } /// /// Returns if the given matrix is orthogonal (i.e. all non-diagonal entries of M * M^t == 0) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonal(this M22d m) => IsOrthogonal(m, Constant.PositiveTinyValue); #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M22d a, M22d b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M10 < b.M10 && a.M11 < b.M11; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M22d m, double s) { return m.M00 < s && m.M01 < s && m.M10 < s && m.M11 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(double s, M22d m) { return s < m.M00 && s < m.M01 && s < m.M10 && s < m.M11; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M22d a, M22d b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M10 < b.M10 || a.M11 < b.M11; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M22d m, double s) { return m.M00 < s || m.M01 < s || m.M10 < s || m.M11 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(double s, M22d m) { return s < m.M00 || s < m.M01 || s < m.M10 || s < m.M11; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M22d a, M22d b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M10 > b.M10 && a.M11 > b.M11; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M22d m, double s) { return m.M00 > s && m.M01 > s && m.M10 > s && m.M11 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(double s, M22d m) { return s > m.M00 && s > m.M01 && s > m.M10 && s > m.M11; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M22d a, M22d b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M10 > b.M10 || a.M11 > b.M11; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M22d m, double s) { return m.M00 > s || m.M01 > s || m.M10 > s || m.M11 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(double s, M22d m) { return s > m.M00 || s > m.M01 || s > m.M10 || s > m.M11; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M22d a, M22d b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M10 <= b.M10 && a.M11 <= b.M11; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M22d m, double s) { return m.M00 <= s && m.M01 <= s && m.M10 <= s && m.M11 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(double s, M22d m) { return s <= m.M00 && s <= m.M01 && s <= m.M10 && s <= m.M11; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M22d a, M22d b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M10 <= b.M10 || a.M11 <= b.M11; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M22d m, double s) { return m.M00 <= s || m.M01 <= s || m.M10 <= s || m.M11 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(double s, M22d m) { return s <= m.M00 || s <= m.M01 || s <= m.M10 || s <= m.M11; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M22d a, M22d b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M10 >= b.M10 && a.M11 >= b.M11; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M22d m, double s) { return m.M00 >= s && m.M01 >= s && m.M10 >= s && m.M11 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(double s, M22d m) { return s >= m.M00 && s >= m.M01 && s >= m.M10 && s >= m.M11; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M22d a, M22d b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M10 >= b.M10 || a.M11 >= b.M11; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M22d m, double s) { return m.M00 >= s || m.M01 >= s || m.M10 >= s || m.M11 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(double s, M22d m) { return s >= m.M00 || s >= m.M01 || s >= m.M10 || s >= m.M11; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M22d a, M22d b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M10 == b.M10 && a.M11 == b.M11; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M22d m, double s) { return m.M00 == s && m.M01 == s && m.M10 == s && m.M11 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(double s, M22d m) { return s == m.M00 && s == m.M01 && s == m.M10 && s == m.M11; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M22d a, M22d b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M10 == b.M10 || a.M11 == b.M11; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M22d m, double s) { return m.M00 == s || m.M01 == s || m.M10 == s || m.M11 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(double s, M22d m) { return s == m.M00 || s == m.M01 || s == m.M10 || s == m.M11; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M22d a, M22d b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M10 != b.M10 && a.M11 != b.M11; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M22d m, double s) { return m.M00 != s && m.M01 != s && m.M10 != s && m.M11 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(double s, M22d m) { return s != m.M00 && s != m.M01 && s != m.M10 && s != m.M11; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M22d a, M22d b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M10 != b.M10 || a.M11 != b.M11; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M22d m, double s) { return m.M00 != s || m.M01 != s || m.M10 != s || m.M11 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(double s, M22d m) { return s != m.M00 || s != m.M01 || s != m.M10 || s != m.M11; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M22d m0, M22d m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MinElement(M22d m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MaxElement(M22d m) => m.MaxElement; #endregion #region Orthogonalization /// /// Orthogonalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// public static void Orthogonalize(this ref M22d matrix) { matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; } /// /// Orthogonalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d Orthogonalized(this M22d matrix) { M22d m = matrix; Orthogonalize(ref m); return m; } /// /// Orthonormalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// public static void Orthonormalize(this ref M22d matrix) { matrix.C0 = matrix.C0.Normalized; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 = matrix.C1.Normalized; } /// /// Orthonormalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d Orthonormalized(this M22d matrix) { M22d m = matrix; Orthonormalize(ref m); return m; } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M22d m, double epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M22d m, double epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyFinite(M22d m) => m.AnyFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllFinite(M22d m) => m.AllFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(M22d m) => m.AnyNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(M22d m) => m.AllNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(M22d m) => m.AnyInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(M22d m) => m.AllInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(M22d m) => m.AnyPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(M22d m) => m.AllPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(M22d m) => m.AnyNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(M22d m) => m.AllNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(M22d m) => m.AnyTiny; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(M22d m) => m.AllTiny; #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M22d a, M22d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M22d a, M22d b, double epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M22d m, double epsilon) => Mat.AllTiny(m, epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(M22d m) => m.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any element of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(M22d v) => v.IsNaN; /// /// Returns whether any element of the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(M22d v) => v.IsInfinity; /// /// Returns whether any element of the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(M22d v) => v.IsPositiveInfinity; /// /// Returns whether any element of the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(M22d v) => v.IsNegativeInfinity; /// /// Returns whether all elements of the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(M22d v) => v.IsFinite; #endregion } public static class IRandomUniformM22dExtensions { #region IRandomUniform extensions for M22d /// /// Uses UniformDouble() to generate the elements of an M22d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d UniformM22d(this IRandomUniform rnd) { return new M22d( rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble()); } /// /// Uses UniformDoubleClosed() to generate the elements of an M22d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d UniformM22dClosed(this IRandomUniform rnd) { return new M22d( rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed()); } /// /// Uses UniformDoubleOpen() to generate the elements of an M22d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d UniformM22dOpen(this IRandomUniform rnd) { return new M22d( rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen()); } /// /// Uses UniformDoubleFull() to generate the elements of an M22d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d UniformM22dFull(this IRandomUniform rnd) { return new M22d( rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull()); } /// /// Uses UniformDoubleFullClosed() to generate the elements of an M22d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d UniformM22dFullClosed(this IRandomUniform rnd) { return new M22d( rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed()); } /// /// Uses UniformDoubleFullOpen() to generate the elements of an M22d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d UniformM22dFullOpen(this IRandomUniform rnd) { return new M22d( rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen()); } #endregion } #endregion #region M23i [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M23i : IEquatable, IValidity, IMatrix { [DataMember] public int M00, M01, M02; [DataMember] public int M10, M11, M12; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(int value) { M00 = value; M01 = 0; M02 = 0; M10 = 0; M11 = value; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i( int m00, int m01, int m02, int m10, int m11, int m12) { M00 = m00; M01 = m01; M02 = m02; M10 = m10; M11 = m11; M12 = m12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(int[] a) { M00 = a[0]; M01 = a[1]; M02 = a[2]; M10 = a[3]; M11 = a[4]; M12 = a[5]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(int[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M02 = a[start + 2]; M10 = a[start + 3]; M11 = a[start + 4]; M12 = a[start + 5]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M22i m, V2i v) { M00 = m.M00; M01 = m.M01; M02 = v.X; M10 = m.M10; M11 = m.M11; M12 = v.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M22i m) { M00 = m.M00; M01 = m.M01; M02 = 0; M10 = m.M10; M11 = m.M11; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M33i m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M34i m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M44i m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M22l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M23l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M33l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M34l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M44l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M22f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M23f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M33f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M34f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M44f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M22d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M23d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M33d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M34d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23i(M44d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; } #endregion #region Conversions public static explicit operator M23i(M22i m) { return new M23i { M00 = m.M00, M01 = m.M01, M02 = 0, M10 = m.M10, M11 = m.M11, M12 = 0, }; } public static explicit operator M23i(M33i m) { return new M23i { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, }; } public static explicit operator M23i(M34i m) { return new M23i { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, }; } public static explicit operator M23i(M44i m) { return new M23i { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, }; } public static explicit operator M23i(M22l m) { return new M23i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = 0, }; } public static explicit operator M23i(M23l m) { return new M23i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, }; } public static explicit operator M23i(M33l m) { return new M23i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, }; } public static explicit operator M23i(M34l m) { return new M23i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, }; } public static explicit operator M23i(M44l m) { return new M23i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, }; } public static explicit operator M23i(M22f m) { return new M23i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = 0, }; } public static explicit operator M23i(M23f m) { return new M23i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, }; } public static explicit operator M23i(M33f m) { return new M23i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, }; } public static explicit operator M23i(M34f m) { return new M23i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, }; } public static explicit operator M23i(M44f m) { return new M23i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, }; } public static explicit operator M23i(M22d m) { return new M23i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = 0, }; } public static explicit operator M23i(M23d m) { return new M23i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, }; } public static explicit operator M23i(M33d m) { return new M23i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, }; } public static explicit operator M23i(M34d m) { return new M23i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, }; } public static explicit operator M23i(M44d m) { return new M23i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, }; } public static explicit operator M23i(int[] a) { return new M23i( a[0], a[1], a[2], a[3], a[4], a[5]); } public static explicit operator M23i(int[,] a) { return new M23i( a[0, 0], a[0, 1], a[0, 2], a[1, 0], a[1, 1], a[1, 2]); } public static explicit operator int[](M23i m) { return new int[] { m.M00, m.M01, m.M02, m.M10, m.M11, m.M12 }; } public static explicit operator int[,](M23i m) { return new int[,] { { m.M00, m.M01, m.M02 }, { m.M10, m.M11, m.M12 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M02; array[index + 3] = M10; array[index + 4] = M11; array[index + 5] = M12; } public static explicit operator M23i(long[] a) { return new M23i( (int)a[0], (int)a[1], (int)a[2], (int)a[3], (int)a[4], (int)a[5]); } public static explicit operator M23i(long[,] a) { return new M23i( (int)a[0, 0], (int)a[0, 1], (int)a[0, 2], (int)a[1, 0], (int)a[1, 1], (int)a[1, 2]); } public static explicit operator long[](M23i m) { return new long[] { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M10, (long)m.M11, (long)m.M12 }; } public static explicit operator long[,](M23i m) { return new long[,] { { (long)m.M00, (long)m.M01, (long)m.M02 }, { (long)m.M10, (long)m.M11, (long)m.M12 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = (long)M00; array[index + 1] = (long)M01; array[index + 2] = (long)M02; array[index + 3] = (long)M10; array[index + 4] = (long)M11; array[index + 5] = (long)M12; } public static explicit operator M23i(float[] a) { return new M23i( (int)a[0], (int)a[1], (int)a[2], (int)a[3], (int)a[4], (int)a[5]); } public static explicit operator M23i(float[,] a) { return new M23i( (int)a[0, 0], (int)a[0, 1], (int)a[0, 2], (int)a[1, 0], (int)a[1, 1], (int)a[1, 2]); } public static explicit operator float[](M23i m) { return new float[] { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M10, (float)m.M11, (float)m.M12 }; } public static explicit operator float[,](M23i m) { return new float[,] { { (float)m.M00, (float)m.M01, (float)m.M02 }, { (float)m.M10, (float)m.M11, (float)m.M12 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = (float)M00; array[index + 1] = (float)M01; array[index + 2] = (float)M02; array[index + 3] = (float)M10; array[index + 4] = (float)M11; array[index + 5] = (float)M12; } public static explicit operator M23i(double[] a) { return new M23i( (int)a[0], (int)a[1], (int)a[2], (int)a[3], (int)a[4], (int)a[5]); } public static explicit operator M23i(double[,] a) { return new M23i( (int)a[0, 0], (int)a[0, 1], (int)a[0, 2], (int)a[1, 0], (int)a[1, 1], (int)a[1, 2]); } public static explicit operator double[](M23i m) { return new double[] { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M10, (double)m.M11, (double)m.M12 }; } public static explicit operator double[,](M23i m) { return new double[,] { { (double)m.M00, (double)m.M01, (double)m.M02 }, { (double)m.M10, (double)m.M11, (double)m.M12 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = (double)M00; array[index + 1] = (double)M01; array[index + 2] = (double)M02; array[index + 3] = (double)M10; array[index + 4] = (double)M11; array[index + 5] = (double)M12; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23i Copy(Func element_fun) { return new M23i( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23i Copy(Func element_index0_index1_fun) { return new M23i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23l Copy(Func element_fun) { return new M23l( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23l Copy(Func element_index0_index1_fun) { return new M23l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23f Copy(Func element_fun) { return new M23f( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23f Copy(Func element_index0_index1_fun) { return new M23f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23d Copy(Func element_fun) { return new M23d( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23d Copy(Func element_index0_index1_fun) { return new M23d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2)); } public readonly int[] ToArray() { var array = new int[6]; array[0] = M00; array[1] = M01; array[2] = M02; array[3] = M10; array[4] = M11; array[5] = M12; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i FromCols(V2i col0, V2i col1, V2i col2) { return new M23i( col0.X, col1.X, col2.X, col0.Y, col1.Y, col2.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i FromRows(V3i row0, V3i row1) { return new M23i( row0.X, row0.Y, row0.Z, row1.X, row1.Y, row1.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i FromDiagonal(int value) { return new M23i( value, 0, 0, 0, value, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i FromDiagonal(int m00, int m11) { return new M23i( m00, 0, 0, 0, m11, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i FromDiagonal(V2i s) { return new M23i( s.X, 0, 0, 0, s.Y, 0); } #region Scale #endregion #region Translation /// /// Creates a transformation with the translational component given by 2 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i Translation(int tX, int tY) { return new M23i( 1, 0, tX, 0, 1, tY); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i Translation(V2i t) { return new M23i( 1, 0, t.X, 0, 1, t.Y); } #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i DivideByInt(M23i m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M02; yield return M10; yield return M11; yield return M12; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; yield return C2; } } [XmlIgnore] public V3i R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3i( M00, M01, M02); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; M02 = value.Z; } } [XmlIgnore] public V3i R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3i( M10, M11, M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; M12 = value.Z; } } [XmlIgnore] public V2i C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2i( M00, M10); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; } } [XmlIgnore] public V2i C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2i( M01, M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; } } [XmlIgnore] public V2i C2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2i( M02, M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M02 = value.X; M12 = value.Y; } } public readonly V2i Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2i(M00, M11); } /// /// Returns the minimum element of the matrix. /// public readonly int MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M02, M10, M11, M12); } /// /// Returns the maximum element of the matrix. /// public readonly int MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M02, M10, M11, M12); } public unsafe int this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (int* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (int* ptr = &M00) { ptr[index] = value; } } } public unsafe int this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (int* ptr = &M00) { return ptr[row * 3 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (int* ptr = &M00) { ptr[row * 3 + column] = value; } } } #endregion #region Constants public const int RowCount = 2; public const int ColumnCount = 3; public const int ElementCount = 2 * 3; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(2, 3); } public static M23i Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M23i(0); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly int Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M02) + Fun.Abs(M10) + Fun.Abs(M11) + Fun.Abs(M12); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly double Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M02 * M02 + M10 * M10 + M11 * M11 + M12 * M12); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly int NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly int NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator -(M23i m) { return new M23i( -m.M00, -m.M01, -m.M02, -m.M10, -m.M11, -m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator + (M23i a, M23i b) { return new M23i( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator + (M23i m, int s) { return new M23i( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator + (int s, M23i m) { return new M23i( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator + (M23i a, M23l b) { return new M23l( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator + (M23i m, long s) { return new M23l( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator + (long s, M23i m) { return new M23l( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator + (M23i a, M23f b) { return new M23f( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator + (M23i m, float s) { return new M23f( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator + (float s, M23i m) { return new M23f( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator + (M23i a, M23d b) { return new M23d( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator + (M23i m, double s) { return new M23d( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator + (double s, M23i m) { return new M23d( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator - (M23i a, M23i b) { return new M23i( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator - (M23i m, int s) { return new M23i( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator - (int s, M23i m) { return new M23i( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator - (M23i a, M23l b) { return new M23l( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator - (M23i m, long s) { return new M23l( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator - (long s, M23i m) { return new M23l( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator - (M23i a, M23f b) { return new M23f( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator - (M23i m, float s) { return new M23f( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator - (float s, M23i m) { return new M23f( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator - (M23i a, M23d b) { return new M23d( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator - (M23i m, double s) { return new M23d( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator - (double s, M23i m) { return new M23d( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator % (M23i a, M23i b) { return new M23i( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator % (M23i m, int s) { return new M23i( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator % (int s, M23i m) { return new M23i( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator % (M23i a, M23l b) { return new M23l( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator % (M23i m, long s) { return new M23l( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator % (long s, M23i m) { return new M23l( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator % (M23i a, M23f b) { return new M23f( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator % (M23i m, float s) { return new M23f( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator % (float s, M23i m) { return new M23f( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator % (M23i a, M23d b) { return new M23d( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator % (M23i m, double s) { return new M23d( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator % (double s, M23i m) { return new M23d( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator / (M23i a, M23i b) { return new M23i( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator / (M23i m, int s) { return new M23i( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator / (int s, M23i m) { return new M23i( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator / (M23i a, M23l b) { return new M23l( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator / (M23i m, long s) { return new M23l( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator / (long s, M23i m) { return new M23l( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator / (M23i a, M23f b) { return new M23f( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator / (M23i m, float s) { return new M23f( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator / (float s, M23i m) { return new M23f( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator / (M23i a, M23d b) { return new M23d( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator / (M23i m, double s) { return new M23d( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator / (double s, M23i m) { return new M23d( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator * (M23i m, int s) { return new M23i( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator * (int s, M23i m) { return new M23i( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator * (M23i m, long s) { return new M23l( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator * (long s, M23i m) { return new M23l( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator * (M23i m, float s) { return new M23f( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator * (float s, M23i m) { return new M23f( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator * (M23i m, double s) { return new M23d( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator * (double s, M23i m) { return new M23d( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12); } #endregion #region Bitwise Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator ~(M23i m) { return new M23i( ~m.M00, ~m.M01, ~m.M02, ~m.M10, ~m.M11, ~m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator <<(M23i a, int s) { return new M23i( a.M00 << s, a.M01 << s, a.M02 << s, a.M10 << s, a.M11 << s, a.M12 << s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator >>(M23i a, int s) { return new M23i( a.M00 >> s, a.M01 >> s, a.M02 >> s, a.M10 >> s, a.M11 >> s, a.M12 >> s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator &(M23i a, M23i b) { return new M23i( a.M00 & b.M00, a.M01 & b.M01, a.M02 & b.M02, a.M10 & b.M10, a.M11 & b.M11, a.M12 & b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator &(M23i a, int s) { return new M23i( a.M00 & s, a.M01 & s, a.M02 & s, a.M10 & s, a.M11 & s, a.M12 & s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator &(int s, M23i a) { return new M23i( s & a.M00, s & a.M01, s & a.M02, s & a.M10, s & a.M11, s & a.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator |(M23i a, M23i b) { return new M23i( a.M00 | b.M00, a.M01 | b.M01, a.M02 | b.M02, a.M10 | b.M10, a.M11 | b.M11, a.M12 | b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator |(M23i a, int s) { return new M23i( a.M00 | s, a.M01 | s, a.M02 | s, a.M10 | s, a.M11 | s, a.M12 | s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator |(int s, M23i a) { return new M23i( s | a.M00, s | a.M01, s | a.M02, s | a.M10, s | a.M11, s | a.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator ^(M23i a, M23i b) { return new M23i( a.M00 ^ b.M00, a.M01 ^ b.M01, a.M02 ^ b.M02, a.M10 ^ b.M10, a.M11 ^ b.M11, a.M12 ^ b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator ^(M23i a, int s) { return new M23i( a.M00 ^ s, a.M01 ^ s, a.M02 ^ s, a.M10 ^ s, a.M11 ^ s, a.M12 ^ s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i operator ^(int s, M23i a) { return new M23i( s ^ a.M00, s ^ a.M01, s ^ a.M02, s ^ a.M10, s ^ a.M11, s ^ a.M12); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M23i matrix with a V3i column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator *(M23i m, V3i v) { return new V2i( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z); } /// /// Multiplies a V2i row vector with a M23i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator *(V2i v, M23i m) { return new V3i( v.X * m.M00 + v.Y * m.M10, v.X * m.M01 + v.Y * m.M11, v.X * m.M02 + v.Y * m.M12); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M23i a, M23i b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M23i a, int s) { return a.M00 == s && a.M01 == s && a.M02 == s && a.M10 == s && a.M11 == s && a.M12 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(int s, M23i a) { return s == a.M00 && s == a.M01 && s == a.M02 && s == a.M10 && s == a.M11 && s == a.M12 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M23i a, M23i b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M23i m, int s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(int s, M23i m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01, M02), HashCode.GetCombined(M10, M11, M12)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M23i other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M02.Equals(other.M02) && M10.Equals(other.M10) && M11.Equals(other.M11) && M12.Equals(other.M12); } public override readonly bool Equals(object other) => (other is M23i o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M23i Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M23i.FromRows( V3i.Parse(x[0]), V3i.Parse(x[1]) ); } #endregion #region Matrix Operations #endregion #region Matrix Multiplication public static M23i operator *(M22i a, M23i b) { return new M23i( a.M00 * b.M00 + a.M01 * b.M10, a.M00 * b.M01 + a.M01 * b.M11, a.M00 * b.M02 + a.M01 * b.M12, a.M10 * b.M00 + a.M11 * b.M10, a.M10 * b.M01 + a.M11 * b.M11, a.M10 * b.M02 + a.M11 * b.M12 ); } public static M23i operator *(M23i a, M33i b) { return new M23i( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return (double)this[(int)y, (int)x]; } set { this[(int)y, (int)x] = (int)value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return (double)this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = (int)value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (int)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (int)value; } #endregion } public class M23iEqualityComparer : IEqualityComparer { public static readonly M23iEqualityComparer Default = new M23iEqualityComparer(); #region IEqualityComparer Members public bool Equals(M23i v0, M23i v1) { return v0 == v1; } public int GetHashCode(M23i v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this M23i m) => (m.C0.Length + m.C1.Length) / 2; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetScaleVector(this M23i m) => new V2d(m.C0.Length, m.C1.Length); #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Norm1(M23i m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(M23i m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NormMax(M23i m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NormMin(M23i m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this M23i m, double p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M02).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) + Fun.Abs(m.M12).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static int Distance1(this M23i a, M23i b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M02 - a.M02) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11) + Fun.Abs(b.M12 - a.M12); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static double Distance2(this M23i a, M23i b) { return Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M02 - a.M02) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11) + Fun.Square(b.M12 - a.M12)); } /// /// Returns the p-distance between two matrices. /// public static double Distance(this M23i a, M23i b, double p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M02 - a.M02).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) + Fun.Abs(b.M12 - a.M12).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static int DistanceMax(this M23i a, M23i b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static int DistanceMin(this M23i a, M23i b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Transform(this M23i m, V3i v) => m * v; /// /// Transforms vector v by matrix m. /// v.W is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Transform(this M23i m, V4i v) { return new V3i( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, v.W); } /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i TransposedTransform(this M23i m, V2i v) => v * m; /// /// Transforms direction vector v (v.Z is presumed 0.0) by matrix m. /// public static V2i TransformDir(this M23i m, V2i v) { return new V2i( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y ); } /// /// Transforms point p (v.Z is presumed 1.0) by matrix m. /// public static V2i TransformPos(this M23i m, V2i p) { return new V2i( m.M00 * p.X + m.M01 * p.Y + m.M02, m.M10 * p.X + m.M11 * p.Y + m.M12 ); } /// /// Multiplies two matrices as 3x3 matrices. /// public static M23i MultiplyAffine(this M23i a, M23i b) { return new M23i( a.M00 * b.M00 + a.M01 * b.M10, a.M00 * b.M01 + a.M01 * b.M11, a.M00 * b.M02 + a.M01 * b.M12 + a.M02, a.M10 * b.M00 + a.M11 * b.M10, a.M10 * b.M01 + a.M11 * b.M11, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 ); } #endregion #region Operations /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V3i Row(this M23i m, int index) { int* ptr = &m.M00; return new V3i(ptr[index * 3], ptr[index * 3 + 1], ptr[index * 3 + 2]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V2i Column(this M23i m, int index) { int* ptr = &m.M00; return new V2i(ptr[index], ptr[index + 3]); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M23i a, M23i b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M02 < b.M02 && a.M10 < b.M10 && a.M11 < b.M11 && a.M12 < b.M12; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M23i m, int s) { return m.M00 < s && m.M01 < s && m.M02 < s && m.M10 < s && m.M11 < s && m.M12 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(int s, M23i m) { return s < m.M00 && s < m.M01 && s < m.M02 && s < m.M10 && s < m.M11 && s < m.M12; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M23i a, M23i b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M02 < b.M02 || a.M10 < b.M10 || a.M11 < b.M11 || a.M12 < b.M12; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M23i m, int s) { return m.M00 < s || m.M01 < s || m.M02 < s || m.M10 < s || m.M11 < s || m.M12 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(int s, M23i m) { return s < m.M00 || s < m.M01 || s < m.M02 || s < m.M10 || s < m.M11 || s < m.M12; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M23i a, M23i b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M02 > b.M02 && a.M10 > b.M10 && a.M11 > b.M11 && a.M12 > b.M12; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M23i m, int s) { return m.M00 > s && m.M01 > s && m.M02 > s && m.M10 > s && m.M11 > s && m.M12 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(int s, M23i m) { return s > m.M00 && s > m.M01 && s > m.M02 && s > m.M10 && s > m.M11 && s > m.M12; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M23i a, M23i b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M02 > b.M02 || a.M10 > b.M10 || a.M11 > b.M11 || a.M12 > b.M12; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M23i m, int s) { return m.M00 > s || m.M01 > s || m.M02 > s || m.M10 > s || m.M11 > s || m.M12 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(int s, M23i m) { return s > m.M00 || s > m.M01 || s > m.M02 || s > m.M10 || s > m.M11 || s > m.M12; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M23i a, M23i b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M02 <= b.M02 && a.M10 <= b.M10 && a.M11 <= b.M11 && a.M12 <= b.M12; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M23i m, int s) { return m.M00 <= s && m.M01 <= s && m.M02 <= s && m.M10 <= s && m.M11 <= s && m.M12 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(int s, M23i m) { return s <= m.M00 && s <= m.M01 && s <= m.M02 && s <= m.M10 && s <= m.M11 && s <= m.M12; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M23i a, M23i b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M02 <= b.M02 || a.M10 <= b.M10 || a.M11 <= b.M11 || a.M12 <= b.M12; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M23i m, int s) { return m.M00 <= s || m.M01 <= s || m.M02 <= s || m.M10 <= s || m.M11 <= s || m.M12 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(int s, M23i m) { return s <= m.M00 || s <= m.M01 || s <= m.M02 || s <= m.M10 || s <= m.M11 || s <= m.M12; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M23i a, M23i b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M02 >= b.M02 && a.M10 >= b.M10 && a.M11 >= b.M11 && a.M12 >= b.M12; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M23i m, int s) { return m.M00 >= s && m.M01 >= s && m.M02 >= s && m.M10 >= s && m.M11 >= s && m.M12 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(int s, M23i m) { return s >= m.M00 && s >= m.M01 && s >= m.M02 && s >= m.M10 && s >= m.M11 && s >= m.M12; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M23i a, M23i b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M02 >= b.M02 || a.M10 >= b.M10 || a.M11 >= b.M11 || a.M12 >= b.M12; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M23i m, int s) { return m.M00 >= s || m.M01 >= s || m.M02 >= s || m.M10 >= s || m.M11 >= s || m.M12 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(int s, M23i m) { return s >= m.M00 || s >= m.M01 || s >= m.M02 || s >= m.M10 || s >= m.M11 || s >= m.M12; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M23i a, M23i b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M23i m, int s) { return m.M00 == s && m.M01 == s && m.M02 == s && m.M10 == s && m.M11 == s && m.M12 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(int s, M23i m) { return s == m.M00 && s == m.M01 && s == m.M02 && s == m.M10 && s == m.M11 && s == m.M12; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M23i a, M23i b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M02 == b.M02 || a.M10 == b.M10 || a.M11 == b.M11 || a.M12 == b.M12; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M23i m, int s) { return m.M00 == s || m.M01 == s || m.M02 == s || m.M10 == s || m.M11 == s || m.M12 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(int s, M23i m) { return s == m.M00 || s == m.M01 || s == m.M02 || s == m.M10 || s == m.M11 || s == m.M12; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M23i a, M23i b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M02 != b.M02 && a.M10 != b.M10 && a.M11 != b.M11 && a.M12 != b.M12; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M23i m, int s) { return m.M00 != s && m.M01 != s && m.M02 != s && m.M10 != s && m.M11 != s && m.M12 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(int s, M23i m) { return s != m.M00 && s != m.M01 && s != m.M02 && s != m.M10 && s != m.M11 && s != m.M12; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M23i a, M23i b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M02 != b.M02 || a.M10 != b.M10 || a.M11 != b.M11 || a.M12 != b.M12; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M23i m, int s) { return m.M00 != s || m.M01 != s || m.M02 != s || m.M10 != s || m.M11 != s || m.M12 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(int s, M23i m) { return s != m.M00 || s != m.M01 || s != m.M02 || s != m.M10 || s != m.M11 || s != m.M12; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M23i m0, M23i m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M02 < m1.M02) return -1; if (m0.M02 > m1.M02) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; if (m0.M12 < m1.M12) return -1; if (m0.M12 > m1.M12) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MinElement(M23i m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MaxElement(M23i m) => m.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M23i m, int epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M02.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon) || m.M12.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M23i m, int epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M02.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon) && m.M12.IsTiny(epsilon); #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M23i a, M23i b, int epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M23i m, int epsilon) => Mat.AllTiny(m, epsilon); #endregion } public static class IRandomUniformM23iExtensions { #region IRandomUniform extensions for M23i /// /// Uses UniformInt() to generate the elements of an M23i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i UniformM23i(this IRandomUniform rnd) { return new M23i( rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt()); } /// /// Uses UniformIntNonZero() to generate the elements of an M23i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i UniformM23iNonZero(this IRandomUniform rnd) { return new M23i( rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero()); } /// /// Uses UniformInt(int) to generate the elements of an M23i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i UniformM23i(this IRandomUniform rnd, int size) { return new M23i( rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size)); } /// /// Uses UniformInt(int) to generate the elements of an M23i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23i UniformM23i(this IRandomUniform rnd, M23i size) { return new M23i( rnd.UniformInt(size.M00), rnd.UniformInt(size.M01), rnd.UniformInt(size.M02), rnd.UniformInt(size.M10), rnd.UniformInt(size.M11), rnd.UniformInt(size.M12)); } #endregion } #endregion #region M23l [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M23l : IEquatable, IValidity, IMatrix { [DataMember] public long M00, M01, M02; [DataMember] public long M10, M11, M12; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(long value) { M00 = value; M01 = 0; M02 = 0; M10 = 0; M11 = value; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l( long m00, long m01, long m02, long m10, long m11, long m12) { M00 = m00; M01 = m01; M02 = m02; M10 = m10; M11 = m11; M12 = m12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(long[] a) { M00 = a[0]; M01 = a[1]; M02 = a[2]; M10 = a[3]; M11 = a[4]; M12 = a[5]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(long[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M02 = a[start + 2]; M10 = a[start + 3]; M11 = a[start + 4]; M12 = a[start + 5]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M22l m, V2l v) { M00 = m.M00; M01 = m.M01; M02 = v.X; M10 = m.M10; M11 = m.M11; M12 = v.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M22i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M23i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M33i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M34i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M44i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M22l m) { M00 = m.M00; M01 = m.M01; M02 = 0; M10 = m.M10; M11 = m.M11; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M33l m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M34l m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M44l m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M22f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M23f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M33f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M34f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M44f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M22d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M23d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M33d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M34d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23l(M44d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; } #endregion #region Conversions public static explicit operator M23l(M22i m) { return new M23l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = 0, }; } public static explicit operator M23l(M23i m) { return new M23l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, }; } public static explicit operator M23l(M33i m) { return new M23l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, }; } public static explicit operator M23l(M34i m) { return new M23l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, }; } public static explicit operator M23l(M44i m) { return new M23l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, }; } public static explicit operator M23l(M22l m) { return new M23l { M00 = m.M00, M01 = m.M01, M02 = 0, M10 = m.M10, M11 = m.M11, M12 = 0, }; } public static explicit operator M23l(M33l m) { return new M23l { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, }; } public static explicit operator M23l(M34l m) { return new M23l { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, }; } public static explicit operator M23l(M44l m) { return new M23l { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, }; } public static explicit operator M23l(M22f m) { return new M23l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = 0, }; } public static explicit operator M23l(M23f m) { return new M23l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, }; } public static explicit operator M23l(M33f m) { return new M23l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, }; } public static explicit operator M23l(M34f m) { return new M23l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, }; } public static explicit operator M23l(M44f m) { return new M23l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, }; } public static explicit operator M23l(M22d m) { return new M23l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = 0, }; } public static explicit operator M23l(M23d m) { return new M23l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, }; } public static explicit operator M23l(M33d m) { return new M23l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, }; } public static explicit operator M23l(M34d m) { return new M23l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, }; } public static explicit operator M23l(M44d m) { return new M23l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, }; } public static explicit operator M23l(int[] a) { return new M23l( (long)a[0], (long)a[1], (long)a[2], (long)a[3], (long)a[4], (long)a[5]); } public static explicit operator M23l(int[,] a) { return new M23l( (long)a[0, 0], (long)a[0, 1], (long)a[0, 2], (long)a[1, 0], (long)a[1, 1], (long)a[1, 2]); } public static explicit operator int[](M23l m) { return new int[] { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M10, (int)m.M11, (int)m.M12 }; } public static explicit operator int[,](M23l m) { return new int[,] { { (int)m.M00, (int)m.M01, (int)m.M02 }, { (int)m.M10, (int)m.M11, (int)m.M12 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = (int)M00; array[index + 1] = (int)M01; array[index + 2] = (int)M02; array[index + 3] = (int)M10; array[index + 4] = (int)M11; array[index + 5] = (int)M12; } public static explicit operator M23l(long[] a) { return new M23l( a[0], a[1], a[2], a[3], a[4], a[5]); } public static explicit operator M23l(long[,] a) { return new M23l( a[0, 0], a[0, 1], a[0, 2], a[1, 0], a[1, 1], a[1, 2]); } public static explicit operator long[](M23l m) { return new long[] { m.M00, m.M01, m.M02, m.M10, m.M11, m.M12 }; } public static explicit operator long[,](M23l m) { return new long[,] { { m.M00, m.M01, m.M02 }, { m.M10, m.M11, m.M12 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M02; array[index + 3] = M10; array[index + 4] = M11; array[index + 5] = M12; } public static explicit operator M23l(float[] a) { return new M23l( (long)a[0], (long)a[1], (long)a[2], (long)a[3], (long)a[4], (long)a[5]); } public static explicit operator M23l(float[,] a) { return new M23l( (long)a[0, 0], (long)a[0, 1], (long)a[0, 2], (long)a[1, 0], (long)a[1, 1], (long)a[1, 2]); } public static explicit operator float[](M23l m) { return new float[] { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M10, (float)m.M11, (float)m.M12 }; } public static explicit operator float[,](M23l m) { return new float[,] { { (float)m.M00, (float)m.M01, (float)m.M02 }, { (float)m.M10, (float)m.M11, (float)m.M12 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = (float)M00; array[index + 1] = (float)M01; array[index + 2] = (float)M02; array[index + 3] = (float)M10; array[index + 4] = (float)M11; array[index + 5] = (float)M12; } public static explicit operator M23l(double[] a) { return new M23l( (long)a[0], (long)a[1], (long)a[2], (long)a[3], (long)a[4], (long)a[5]); } public static explicit operator M23l(double[,] a) { return new M23l( (long)a[0, 0], (long)a[0, 1], (long)a[0, 2], (long)a[1, 0], (long)a[1, 1], (long)a[1, 2]); } public static explicit operator double[](M23l m) { return new double[] { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M10, (double)m.M11, (double)m.M12 }; } public static explicit operator double[,](M23l m) { return new double[,] { { (double)m.M00, (double)m.M01, (double)m.M02 }, { (double)m.M10, (double)m.M11, (double)m.M12 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = (double)M00; array[index + 1] = (double)M01; array[index + 2] = (double)M02; array[index + 3] = (double)M10; array[index + 4] = (double)M11; array[index + 5] = (double)M12; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23i Copy(Func element_fun) { return new M23i( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23i Copy(Func element_index0_index1_fun) { return new M23i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23l Copy(Func element_fun) { return new M23l( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23l Copy(Func element_index0_index1_fun) { return new M23l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23f Copy(Func element_fun) { return new M23f( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23f Copy(Func element_index0_index1_fun) { return new M23f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23d Copy(Func element_fun) { return new M23d( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23d Copy(Func element_index0_index1_fun) { return new M23d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2)); } public readonly long[] ToArray() { var array = new long[6]; array[0] = M00; array[1] = M01; array[2] = M02; array[3] = M10; array[4] = M11; array[5] = M12; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l FromCols(V2l col0, V2l col1, V2l col2) { return new M23l( col0.X, col1.X, col2.X, col0.Y, col1.Y, col2.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l FromRows(V3l row0, V3l row1) { return new M23l( row0.X, row0.Y, row0.Z, row1.X, row1.Y, row1.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l FromDiagonal(long value) { return new M23l( value, 0, 0, 0, value, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l FromDiagonal(long m00, long m11) { return new M23l( m00, 0, 0, 0, m11, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l FromDiagonal(V2l s) { return new M23l( s.X, 0, 0, 0, s.Y, 0); } #region Scale #endregion #region Translation /// /// Creates a transformation with the translational component given by 2 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l Translation(long tX, long tY) { return new M23l( 1, 0, tX, 0, 1, tY); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l Translation(V2l t) { return new M23l( 1, 0, t.X, 0, 1, t.Y); } #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l DivideByInt(M23l m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M02; yield return M10; yield return M11; yield return M12; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; yield return C2; } } [XmlIgnore] public V3l R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3l( M00, M01, M02); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; M02 = value.Z; } } [XmlIgnore] public V3l R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3l( M10, M11, M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; M12 = value.Z; } } [XmlIgnore] public V2l C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2l( M00, M10); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; } } [XmlIgnore] public V2l C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2l( M01, M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; } } [XmlIgnore] public V2l C2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2l( M02, M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M02 = value.X; M12 = value.Y; } } public readonly V2l Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(M00, M11); } /// /// Returns the minimum element of the matrix. /// public readonly long MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M02, M10, M11, M12); } /// /// Returns the maximum element of the matrix. /// public readonly long MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M02, M10, M11, M12); } public unsafe long this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (long* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (long* ptr = &M00) { ptr[index] = value; } } } public unsafe long this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (long* ptr = &M00) { return ptr[row * 3 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (long* ptr = &M00) { ptr[row * 3 + column] = value; } } } #endregion #region Constants public const int RowCount = 2; public const int ColumnCount = 3; public const int ElementCount = 2 * 3; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(2, 3); } public static M23l Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M23l(0); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly long Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M02) + Fun.Abs(M10) + Fun.Abs(M11) + Fun.Abs(M12); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly double Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M02 * M02 + M10 * M10 + M11 * M11 + M12 * M12); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly long NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly long NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator -(M23l m) { return new M23l( -m.M00, -m.M01, -m.M02, -m.M10, -m.M11, -m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator + (M23l a, M23l b) { return new M23l( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator + (M23l m, long s) { return new M23l( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator + (long s, M23l m) { return new M23l( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator + (M23l a, M23f b) { return new M23f( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator + (M23l m, float s) { return new M23f( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator + (float s, M23l m) { return new M23f( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator + (M23l a, M23d b) { return new M23d( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator + (M23l m, double s) { return new M23d( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator + (double s, M23l m) { return new M23d( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator - (M23l a, M23l b) { return new M23l( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator - (M23l m, long s) { return new M23l( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator - (long s, M23l m) { return new M23l( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator - (M23l a, M23f b) { return new M23f( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator - (M23l m, float s) { return new M23f( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator - (float s, M23l m) { return new M23f( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator - (M23l a, M23d b) { return new M23d( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator - (M23l m, double s) { return new M23d( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator - (double s, M23l m) { return new M23d( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator % (M23l a, M23l b) { return new M23l( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator % (M23l m, long s) { return new M23l( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator % (long s, M23l m) { return new M23l( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator % (M23l a, M23f b) { return new M23f( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator % (M23l m, float s) { return new M23f( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator % (float s, M23l m) { return new M23f( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator % (M23l a, M23d b) { return new M23d( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator % (M23l m, double s) { return new M23d( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator % (double s, M23l m) { return new M23d( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator / (M23l a, M23l b) { return new M23l( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator / (M23l m, long s) { return new M23l( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator / (long s, M23l m) { return new M23l( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator / (M23l a, M23f b) { return new M23f( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator / (M23l m, float s) { return new M23f( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator / (float s, M23l m) { return new M23f( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator / (M23l a, M23d b) { return new M23d( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator / (M23l m, double s) { return new M23d( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator / (double s, M23l m) { return new M23d( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator * (M23l m, long s) { return new M23l( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator * (long s, M23l m) { return new M23l( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator * (M23l m, float s) { return new M23f( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator * (float s, M23l m) { return new M23f( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator * (M23l m, double s) { return new M23d( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator * (double s, M23l m) { return new M23d( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12); } #endregion #region Bitwise Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator ~(M23l m) { return new M23l( ~m.M00, ~m.M01, ~m.M02, ~m.M10, ~m.M11, ~m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator <<(M23l a, int s) { return new M23l( a.M00 << s, a.M01 << s, a.M02 << s, a.M10 << s, a.M11 << s, a.M12 << s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator >>(M23l a, int s) { return new M23l( a.M00 >> s, a.M01 >> s, a.M02 >> s, a.M10 >> s, a.M11 >> s, a.M12 >> s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator &(M23l a, M23l b) { return new M23l( a.M00 & b.M00, a.M01 & b.M01, a.M02 & b.M02, a.M10 & b.M10, a.M11 & b.M11, a.M12 & b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator &(M23l a, long s) { return new M23l( a.M00 & s, a.M01 & s, a.M02 & s, a.M10 & s, a.M11 & s, a.M12 & s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator &(long s, M23l a) { return new M23l( s & a.M00, s & a.M01, s & a.M02, s & a.M10, s & a.M11, s & a.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator |(M23l a, M23l b) { return new M23l( a.M00 | b.M00, a.M01 | b.M01, a.M02 | b.M02, a.M10 | b.M10, a.M11 | b.M11, a.M12 | b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator |(M23l a, long s) { return new M23l( a.M00 | s, a.M01 | s, a.M02 | s, a.M10 | s, a.M11 | s, a.M12 | s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator |(long s, M23l a) { return new M23l( s | a.M00, s | a.M01, s | a.M02, s | a.M10, s | a.M11, s | a.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator ^(M23l a, M23l b) { return new M23l( a.M00 ^ b.M00, a.M01 ^ b.M01, a.M02 ^ b.M02, a.M10 ^ b.M10, a.M11 ^ b.M11, a.M12 ^ b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator ^(M23l a, long s) { return new M23l( a.M00 ^ s, a.M01 ^ s, a.M02 ^ s, a.M10 ^ s, a.M11 ^ s, a.M12 ^ s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l operator ^(long s, M23l a) { return new M23l( s ^ a.M00, s ^ a.M01, s ^ a.M02, s ^ a.M10, s ^ a.M11, s ^ a.M12); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M23l matrix with a V3l column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator *(M23l m, V3l v) { return new V2l( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z); } /// /// Multiplies a V2l row vector with a M23l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator *(V2l v, M23l m) { return new V3l( v.X * m.M00 + v.Y * m.M10, v.X * m.M01 + v.Y * m.M11, v.X * m.M02 + v.Y * m.M12); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M23l a, M23l b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M23l a, long s) { return a.M00 == s && a.M01 == s && a.M02 == s && a.M10 == s && a.M11 == s && a.M12 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(long s, M23l a) { return s == a.M00 && s == a.M01 && s == a.M02 && s == a.M10 && s == a.M11 && s == a.M12 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M23l a, M23l b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M23l m, long s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(long s, M23l m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01, M02), HashCode.GetCombined(M10, M11, M12)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M23l other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M02.Equals(other.M02) && M10.Equals(other.M10) && M11.Equals(other.M11) && M12.Equals(other.M12); } public override readonly bool Equals(object other) => (other is M23l o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M23l Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M23l.FromRows( V3l.Parse(x[0]), V3l.Parse(x[1]) ); } #endregion #region Matrix Operations #endregion #region Matrix Multiplication public static M23l operator *(M22l a, M23l b) { return new M23l( a.M00 * b.M00 + a.M01 * b.M10, a.M00 * b.M01 + a.M01 * b.M11, a.M00 * b.M02 + a.M01 * b.M12, a.M10 * b.M00 + a.M11 * b.M10, a.M10 * b.M01 + a.M11 * b.M11, a.M10 * b.M02 + a.M11 * b.M12 ); } public static M23l operator *(M23l a, M33l b) { return new M23l( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return (double)this[(int)y, (int)x]; } set { this[(int)y, (int)x] = (long)value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return (double)this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = (long)value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (long)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (long)value; } #endregion } public class M23lEqualityComparer : IEqualityComparer { public static readonly M23lEqualityComparer Default = new M23lEqualityComparer(); #region IEqualityComparer Members public bool Equals(M23l v0, M23l v1) { return v0 == v1; } public int GetHashCode(M23l v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this M23l m) => (m.C0.Length + m.C1.Length) / 2; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetScaleVector(this M23l m) => new V2d(m.C0.Length, m.C1.Length); #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Norm1(M23l m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(M23l m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NormMax(M23l m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NormMin(M23l m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this M23l m, double p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M02).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) + Fun.Abs(m.M12).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static long Distance1(this M23l a, M23l b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M02 - a.M02) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11) + Fun.Abs(b.M12 - a.M12); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static double Distance2(this M23l a, M23l b) { return Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M02 - a.M02) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11) + Fun.Square(b.M12 - a.M12)); } /// /// Returns the p-distance between two matrices. /// public static double Distance(this M23l a, M23l b, double p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M02 - a.M02).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) + Fun.Abs(b.M12 - a.M12).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static long DistanceMax(this M23l a, M23l b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static long DistanceMin(this M23l a, M23l b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Transform(this M23l m, V3l v) => m * v; /// /// Transforms vector v by matrix m. /// v.W is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Transform(this M23l m, V4l v) { return new V3l( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, v.W); } /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l TransposedTransform(this M23l m, V2l v) => v * m; /// /// Transforms direction vector v (v.Z is presumed 0.0) by matrix m. /// public static V2l TransformDir(this M23l m, V2l v) { return new V2l( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y ); } /// /// Transforms point p (v.Z is presumed 1.0) by matrix m. /// public static V2l TransformPos(this M23l m, V2l p) { return new V2l( m.M00 * p.X + m.M01 * p.Y + m.M02, m.M10 * p.X + m.M11 * p.Y + m.M12 ); } /// /// Multiplies two matrices as 3x3 matrices. /// public static M23l MultiplyAffine(this M23l a, M23l b) { return new M23l( a.M00 * b.M00 + a.M01 * b.M10, a.M00 * b.M01 + a.M01 * b.M11, a.M00 * b.M02 + a.M01 * b.M12 + a.M02, a.M10 * b.M00 + a.M11 * b.M10, a.M10 * b.M01 + a.M11 * b.M11, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 ); } #endregion #region Operations /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V3l Row(this M23l m, int index) { long* ptr = &m.M00; return new V3l(ptr[index * 3], ptr[index * 3 + 1], ptr[index * 3 + 2]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V2l Column(this M23l m, int index) { long* ptr = &m.M00; return new V2l(ptr[index], ptr[index + 3]); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M23l a, M23l b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M02 < b.M02 && a.M10 < b.M10 && a.M11 < b.M11 && a.M12 < b.M12; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M23l m, long s) { return m.M00 < s && m.M01 < s && m.M02 < s && m.M10 < s && m.M11 < s && m.M12 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(long s, M23l m) { return s < m.M00 && s < m.M01 && s < m.M02 && s < m.M10 && s < m.M11 && s < m.M12; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M23l a, M23l b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M02 < b.M02 || a.M10 < b.M10 || a.M11 < b.M11 || a.M12 < b.M12; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M23l m, long s) { return m.M00 < s || m.M01 < s || m.M02 < s || m.M10 < s || m.M11 < s || m.M12 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(long s, M23l m) { return s < m.M00 || s < m.M01 || s < m.M02 || s < m.M10 || s < m.M11 || s < m.M12; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M23l a, M23l b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M02 > b.M02 && a.M10 > b.M10 && a.M11 > b.M11 && a.M12 > b.M12; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M23l m, long s) { return m.M00 > s && m.M01 > s && m.M02 > s && m.M10 > s && m.M11 > s && m.M12 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(long s, M23l m) { return s > m.M00 && s > m.M01 && s > m.M02 && s > m.M10 && s > m.M11 && s > m.M12; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M23l a, M23l b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M02 > b.M02 || a.M10 > b.M10 || a.M11 > b.M11 || a.M12 > b.M12; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M23l m, long s) { return m.M00 > s || m.M01 > s || m.M02 > s || m.M10 > s || m.M11 > s || m.M12 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(long s, M23l m) { return s > m.M00 || s > m.M01 || s > m.M02 || s > m.M10 || s > m.M11 || s > m.M12; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M23l a, M23l b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M02 <= b.M02 && a.M10 <= b.M10 && a.M11 <= b.M11 && a.M12 <= b.M12; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M23l m, long s) { return m.M00 <= s && m.M01 <= s && m.M02 <= s && m.M10 <= s && m.M11 <= s && m.M12 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(long s, M23l m) { return s <= m.M00 && s <= m.M01 && s <= m.M02 && s <= m.M10 && s <= m.M11 && s <= m.M12; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M23l a, M23l b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M02 <= b.M02 || a.M10 <= b.M10 || a.M11 <= b.M11 || a.M12 <= b.M12; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M23l m, long s) { return m.M00 <= s || m.M01 <= s || m.M02 <= s || m.M10 <= s || m.M11 <= s || m.M12 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(long s, M23l m) { return s <= m.M00 || s <= m.M01 || s <= m.M02 || s <= m.M10 || s <= m.M11 || s <= m.M12; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M23l a, M23l b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M02 >= b.M02 && a.M10 >= b.M10 && a.M11 >= b.M11 && a.M12 >= b.M12; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M23l m, long s) { return m.M00 >= s && m.M01 >= s && m.M02 >= s && m.M10 >= s && m.M11 >= s && m.M12 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(long s, M23l m) { return s >= m.M00 && s >= m.M01 && s >= m.M02 && s >= m.M10 && s >= m.M11 && s >= m.M12; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M23l a, M23l b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M02 >= b.M02 || a.M10 >= b.M10 || a.M11 >= b.M11 || a.M12 >= b.M12; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M23l m, long s) { return m.M00 >= s || m.M01 >= s || m.M02 >= s || m.M10 >= s || m.M11 >= s || m.M12 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(long s, M23l m) { return s >= m.M00 || s >= m.M01 || s >= m.M02 || s >= m.M10 || s >= m.M11 || s >= m.M12; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M23l a, M23l b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M23l m, long s) { return m.M00 == s && m.M01 == s && m.M02 == s && m.M10 == s && m.M11 == s && m.M12 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(long s, M23l m) { return s == m.M00 && s == m.M01 && s == m.M02 && s == m.M10 && s == m.M11 && s == m.M12; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M23l a, M23l b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M02 == b.M02 || a.M10 == b.M10 || a.M11 == b.M11 || a.M12 == b.M12; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M23l m, long s) { return m.M00 == s || m.M01 == s || m.M02 == s || m.M10 == s || m.M11 == s || m.M12 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(long s, M23l m) { return s == m.M00 || s == m.M01 || s == m.M02 || s == m.M10 || s == m.M11 || s == m.M12; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M23l a, M23l b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M02 != b.M02 && a.M10 != b.M10 && a.M11 != b.M11 && a.M12 != b.M12; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M23l m, long s) { return m.M00 != s && m.M01 != s && m.M02 != s && m.M10 != s && m.M11 != s && m.M12 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(long s, M23l m) { return s != m.M00 && s != m.M01 && s != m.M02 && s != m.M10 && s != m.M11 && s != m.M12; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M23l a, M23l b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M02 != b.M02 || a.M10 != b.M10 || a.M11 != b.M11 || a.M12 != b.M12; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M23l m, long s) { return m.M00 != s || m.M01 != s || m.M02 != s || m.M10 != s || m.M11 != s || m.M12 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(long s, M23l m) { return s != m.M00 || s != m.M01 || s != m.M02 || s != m.M10 || s != m.M11 || s != m.M12; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M23l m0, M23l m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M02 < m1.M02) return -1; if (m0.M02 > m1.M02) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; if (m0.M12 < m1.M12) return -1; if (m0.M12 > m1.M12) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MinElement(M23l m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MaxElement(M23l m) => m.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M23l m, long epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M02.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon) || m.M12.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M23l m, long epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M02.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon) && m.M12.IsTiny(epsilon); #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M23l a, M23l b, long epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M23l m, long epsilon) => Mat.AllTiny(m, epsilon); #endregion } public static class IRandomUniformM23lExtensions { #region IRandomUniform extensions for M23l /// /// Uses UniformLong() to generate the elements of an M23l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l UniformM23l(this IRandomUniform rnd) { return new M23l( rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong()); } /// /// Uses UniformLongNonZero() to generate the elements of an M23l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l UniformM23lNonZero(this IRandomUniform rnd) { return new M23l( rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero()); } /// /// Uses UniformLong(long) to generate the elements of an M23l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l UniformM23l(this IRandomUniform rnd, long size) { return new M23l( rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size)); } /// /// Uses UniformLong(long) to generate the elements of an M23l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23l UniformM23l(this IRandomUniform rnd, M23l size) { return new M23l( rnd.UniformLong(size.M00), rnd.UniformLong(size.M01), rnd.UniformLong(size.M02), rnd.UniformLong(size.M10), rnd.UniformLong(size.M11), rnd.UniformLong(size.M12)); } #endregion } #endregion #region M23f [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M23f : IEquatable, IValidity, IMatrix { [DataMember] public float M00, M01, M02; [DataMember] public float M10, M11, M12; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(float value) { M00 = value; M01 = 0; M02 = 0; M10 = 0; M11 = value; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f( float m00, float m01, float m02, float m10, float m11, float m12) { M00 = m00; M01 = m01; M02 = m02; M10 = m10; M11 = m11; M12 = m12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(float[] a) { M00 = a[0]; M01 = a[1]; M02 = a[2]; M10 = a[3]; M11 = a[4]; M12 = a[5]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(float[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M02 = a[start + 2]; M10 = a[start + 3]; M11 = a[start + 4]; M12 = a[start + 5]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M22f m, V2f v) { M00 = m.M00; M01 = m.M01; M02 = v.X; M10 = m.M10; M11 = m.M11; M12 = v.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M22i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M23i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M33i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M34i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M44i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M22l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M23l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M33l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M34l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M44l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M22f m) { M00 = m.M00; M01 = m.M01; M02 = 0; M10 = m.M10; M11 = m.M11; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M33f m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M34f m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M44f m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M22d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M23d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M33d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M34d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23f(M44d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; } #endregion #region Conversions public static explicit operator M23f(M22i m) { return new M23f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = 0, }; } public static explicit operator M23f(M23i m) { return new M23f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, }; } public static explicit operator M23f(M33i m) { return new M23f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, }; } public static explicit operator M23f(M34i m) { return new M23f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, }; } public static explicit operator M23f(M44i m) { return new M23f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, }; } public static explicit operator M23f(M22l m) { return new M23f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = 0, }; } public static explicit operator M23f(M23l m) { return new M23f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, }; } public static explicit operator M23f(M33l m) { return new M23f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, }; } public static explicit operator M23f(M34l m) { return new M23f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, }; } public static explicit operator M23f(M44l m) { return new M23f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, }; } public static explicit operator M23f(M22f m) { return new M23f { M00 = m.M00, M01 = m.M01, M02 = 0, M10 = m.M10, M11 = m.M11, M12 = 0, }; } public static explicit operator M23f(M33f m) { return new M23f { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, }; } public static explicit operator M23f(M34f m) { return new M23f { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, }; } public static explicit operator M23f(M44f m) { return new M23f { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, }; } public static explicit operator M23f(M22d m) { return new M23f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = 0, }; } public static explicit operator M23f(M23d m) { return new M23f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, }; } public static explicit operator M23f(M33d m) { return new M23f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, }; } public static explicit operator M23f(M34d m) { return new M23f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, }; } public static explicit operator M23f(M44d m) { return new M23f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, }; } public static explicit operator M23f(int[] a) { return new M23f( (float)a[0], (float)a[1], (float)a[2], (float)a[3], (float)a[4], (float)a[5]); } public static explicit operator M23f(int[,] a) { return new M23f( (float)a[0, 0], (float)a[0, 1], (float)a[0, 2], (float)a[1, 0], (float)a[1, 1], (float)a[1, 2]); } public static explicit operator int[](M23f m) { return new int[] { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M10, (int)m.M11, (int)m.M12 }; } public static explicit operator int[,](M23f m) { return new int[,] { { (int)m.M00, (int)m.M01, (int)m.M02 }, { (int)m.M10, (int)m.M11, (int)m.M12 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = (int)M00; array[index + 1] = (int)M01; array[index + 2] = (int)M02; array[index + 3] = (int)M10; array[index + 4] = (int)M11; array[index + 5] = (int)M12; } public static explicit operator M23f(long[] a) { return new M23f( (float)a[0], (float)a[1], (float)a[2], (float)a[3], (float)a[4], (float)a[5]); } public static explicit operator M23f(long[,] a) { return new M23f( (float)a[0, 0], (float)a[0, 1], (float)a[0, 2], (float)a[1, 0], (float)a[1, 1], (float)a[1, 2]); } public static explicit operator long[](M23f m) { return new long[] { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M10, (long)m.M11, (long)m.M12 }; } public static explicit operator long[,](M23f m) { return new long[,] { { (long)m.M00, (long)m.M01, (long)m.M02 }, { (long)m.M10, (long)m.M11, (long)m.M12 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = (long)M00; array[index + 1] = (long)M01; array[index + 2] = (long)M02; array[index + 3] = (long)M10; array[index + 4] = (long)M11; array[index + 5] = (long)M12; } public static explicit operator M23f(float[] a) { return new M23f( a[0], a[1], a[2], a[3], a[4], a[5]); } public static explicit operator M23f(float[,] a) { return new M23f( a[0, 0], a[0, 1], a[0, 2], a[1, 0], a[1, 1], a[1, 2]); } public static explicit operator float[](M23f m) { return new float[] { m.M00, m.M01, m.M02, m.M10, m.M11, m.M12 }; } public static explicit operator float[,](M23f m) { return new float[,] { { m.M00, m.M01, m.M02 }, { m.M10, m.M11, m.M12 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M02; array[index + 3] = M10; array[index + 4] = M11; array[index + 5] = M12; } public static explicit operator M23f(double[] a) { return new M23f( (float)a[0], (float)a[1], (float)a[2], (float)a[3], (float)a[4], (float)a[5]); } public static explicit operator M23f(double[,] a) { return new M23f( (float)a[0, 0], (float)a[0, 1], (float)a[0, 2], (float)a[1, 0], (float)a[1, 1], (float)a[1, 2]); } public static explicit operator double[](M23f m) { return new double[] { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M10, (double)m.M11, (double)m.M12 }; } public static explicit operator double[,](M23f m) { return new double[,] { { (double)m.M00, (double)m.M01, (double)m.M02 }, { (double)m.M10, (double)m.M11, (double)m.M12 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = (double)M00; array[index + 1] = (double)M01; array[index + 2] = (double)M02; array[index + 3] = (double)M10; array[index + 4] = (double)M11; array[index + 5] = (double)M12; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23i Copy(Func element_fun) { return new M23i( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23i Copy(Func element_index0_index1_fun) { return new M23i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23l Copy(Func element_fun) { return new M23l( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23l Copy(Func element_index0_index1_fun) { return new M23l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23f Copy(Func element_fun) { return new M23f( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23f Copy(Func element_index0_index1_fun) { return new M23f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23d Copy(Func element_fun) { return new M23d( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23d Copy(Func element_index0_index1_fun) { return new M23d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2)); } public readonly float[] ToArray() { var array = new float[6]; array[0] = M00; array[1] = M01; array[2] = M02; array[3] = M10; array[4] = M11; array[5] = M12; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f FromCols(V2f col0, V2f col1, V2f col2) { return new M23f( col0.X, col1.X, col2.X, col0.Y, col1.Y, col2.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f FromRows(V3f row0, V3f row1) { return new M23f( row0.X, row0.Y, row0.Z, row1.X, row1.Y, row1.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f FromDiagonal(float value) { return new M23f( value, 0, 0, 0, value, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f FromDiagonal(float m00, float m11) { return new M23f( m00, 0, 0, 0, m11, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f FromDiagonal(V2f s) { return new M23f( s.X, 0, 0, 0, s.Y, 0); } #region Scale #endregion #region Translation /// /// Creates a transformation with the translational component given by 2 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f Translation(float tX, float tY) { return new M23f( 1, 0, tX, 0, 1, tY); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f Translation(V2f t) { return new M23f( 1, 0, t.X, 0, 1, t.Y); } /// /// Creates a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f Translation(Shift2f s) { return new M23f( 1, 0, s.X, 0, 1, s.Y); } #endregion #region Rotation /// /// Creates a 2D rotation matrix with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f Rotation(float angleInRadians) { var a = Fun.Cos(angleInRadians); var b = Fun.Sin(angleInRadians); return new M23f( a, -b, 0, b, a, 0); } /// /// Creates a 2D rotation matrix with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f RotationInDegrees(float angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); /// /// Creates a 2D rotation matrix from a /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f Rotation(Rot2f r) => (M23f)r; #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f DivideByInt(M23f m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M02; yield return M10; yield return M11; yield return M12; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; yield return C2; } } [XmlIgnore] public V3f R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3f( M00, M01, M02); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; M02 = value.Z; } } [XmlIgnore] public V3f R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3f( M10, M11, M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; M12 = value.Z; } } [XmlIgnore] public V2f C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2f( M00, M10); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; } } [XmlIgnore] public V2f C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2f( M01, M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; } } [XmlIgnore] public V2f C2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2f( M02, M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M02 = value.X; M12 = value.Y; } } public readonly V2f Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2f(M00, M11); } /// /// Returns the minimum element of the matrix. /// public readonly float MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M02, M10, M11, M12); } /// /// Returns the maximum element of the matrix. /// public readonly float MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M02, M10, M11, M12); } public unsafe float this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &M00) { ptr[index] = value; } } } public unsafe float this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &M00) { return ptr[row * 3 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &M00) { ptr[row * 3 + column] = value; } } } public readonly bool AnyFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) || Fun.IsFinite(M01) || Fun.IsFinite(M02) || Fun.IsFinite(M10) || Fun.IsFinite(M11) || Fun.IsFinite(M12); } } public readonly bool AllFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) && Fun.IsFinite(M01) && Fun.IsFinite(M02) && Fun.IsFinite(M10) && Fun.IsFinite(M11) && Fun.IsFinite(M12); } } public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNaN(M00) || float.IsNaN(M01) || float.IsNaN(M02) || float.IsNaN(M10) || float.IsNaN(M11) || float.IsNaN(M12); } } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNaN(M00) && float.IsNaN(M01) && float.IsNaN(M02) && float.IsNaN(M10) && float.IsNaN(M11) && float.IsNaN(M12); } } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsInfinity(M00) || float.IsInfinity(M01) || float.IsInfinity(M02) || float.IsInfinity(M10) || float.IsInfinity(M11) || float.IsInfinity(M12); } } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsInfinity(M00) && float.IsInfinity(M01) && float.IsInfinity(M02) && float.IsInfinity(M10) && float.IsInfinity(M11) && float.IsInfinity(M12); } } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsPositiveInfinity(M00) || float.IsPositiveInfinity(M01) || float.IsPositiveInfinity(M02) || float.IsPositiveInfinity(M10) || float.IsPositiveInfinity(M11) || float.IsPositiveInfinity(M12); } } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsPositiveInfinity(M00) && float.IsPositiveInfinity(M01) && float.IsPositiveInfinity(M02) && float.IsPositiveInfinity(M10) && float.IsPositiveInfinity(M11) && float.IsPositiveInfinity(M12); } } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNegativeInfinity(M00) || float.IsNegativeInfinity(M01) || float.IsNegativeInfinity(M02) || float.IsNegativeInfinity(M10) || float.IsNegativeInfinity(M11) || float.IsNegativeInfinity(M12); } } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNegativeInfinity(M00) && float.IsNegativeInfinity(M01) && float.IsNegativeInfinity(M02) && float.IsNegativeInfinity(M10) && float.IsNegativeInfinity(M11) && float.IsNegativeInfinity(M12); } } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) || Fun.IsTiny(M01) || Fun.IsTiny(M02) || Fun.IsTiny(M10) || Fun.IsTiny(M11) || Fun.IsTiny(M12); } } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) && Fun.IsTiny(M01) && Fun.IsTiny(M02) && Fun.IsTiny(M10) && Fun.IsTiny(M11) && Fun.IsTiny(M12); } } /// /// Returns true if the absolute value of each element of the matrix is smaller than Constant<float>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any element of the matrix is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any element of the matrix is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any element of the matrix is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any element of the matrix is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all elements of the matrix are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Constants public const int RowCount = 2; public const int ColumnCount = 3; public const int ElementCount = 2 * 3; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(2, 3); } public static M23f Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M23f(0); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly float Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M02) + Fun.Abs(M10) + Fun.Abs(M11) + Fun.Abs(M12); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly float Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M02 * M02 + M10 * M10 + M11 * M11 + M12 * M12); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly float NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly float NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator -(M23f m) { return new M23f( -m.M00, -m.M01, -m.M02, -m.M10, -m.M11, -m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator + (M23f a, M23f b) { return new M23f( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator + (M23f m, float s) { return new M23f( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator + (float s, M23f m) { return new M23f( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator + (M23f a, M23d b) { return new M23d( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator + (M23f m, double s) { return new M23d( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator + (double s, M23f m) { return new M23d( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator - (M23f a, M23f b) { return new M23f( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator - (M23f m, float s) { return new M23f( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator - (float s, M23f m) { return new M23f( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator - (M23f a, M23d b) { return new M23d( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator - (M23f m, double s) { return new M23d( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator - (double s, M23f m) { return new M23d( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator % (M23f a, M23f b) { return new M23f( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator % (M23f m, float s) { return new M23f( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator % (float s, M23f m) { return new M23f( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator % (M23f a, M23d b) { return new M23d( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator % (M23f m, double s) { return new M23d( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator % (double s, M23f m) { return new M23d( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator / (M23f a, M23f b) { return new M23f( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator / (M23f m, float s) { return new M23f( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator / (float s, M23f m) { return new M23f( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator / (M23f a, M23d b) { return new M23d( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator / (M23f m, double s) { return new M23d( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator / (double s, M23f m) { return new M23d( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator * (M23f m, float s) { return new M23f( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator * (float s, M23f m) { return new M23f( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator * (M23f m, double s) { return new M23d( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator * (double s, M23f m) { return new M23d( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M23f matrix with a V3f column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator *(M23f m, V3f v) { return new V2f( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z); } /// /// Multiplies a V2f row vector with a M23f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator *(V2f v, M23f m) { return new V3f( v.X * m.M00 + v.Y * m.M10, v.X * m.M01 + v.Y * m.M11, v.X * m.M02 + v.Y * m.M12); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M23f a, M23f b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M23f a, float s) { return a.M00 == s && a.M01 == s && a.M02 == s && a.M10 == s && a.M11 == s && a.M12 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(float s, M23f a) { return s == a.M00 && s == a.M01 && s == a.M02 && s == a.M10 && s == a.M11 && s == a.M12 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M23f a, M23f b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M23f m, float s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(float s, M23f m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01, M02), HashCode.GetCombined(M10, M11, M12)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M23f other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M02.Equals(other.M02) && M10.Equals(other.M10) && M11.Equals(other.M11) && M12.Equals(other.M12); } public override readonly bool Equals(object other) => (other is M23f o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M23f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M23f.FromRows( V3f.Parse(x[0]), V3f.Parse(x[1]) ); } #endregion #region Matrix Operations #endregion #region Matrix Multiplication public static M23f operator *(M22f a, M23f b) { return new M23f( a.M00 * b.M00 + a.M01 * b.M10, a.M00 * b.M01 + a.M01 * b.M11, a.M00 * b.M02 + a.M01 * b.M12, a.M10 * b.M00 + a.M11 * b.M10, a.M10 * b.M01 + a.M11 * b.M11, a.M10 * b.M02 + a.M11 * b.M12 ); } public static M23f operator *(M23f a, M33f b) { return new M23f( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return (double)this[(int)y, (int)x]; } set { this[(int)y, (int)x] = (float)value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return (double)this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = (float)value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (float)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (float)value; } #endregion } public class M23fEqualityComparer : IEqualityComparer { public static readonly M23fEqualityComparer Default = new M23fEqualityComparer(); #region IEqualityComparer Members public bool Equals(M23f v0, M23f v1) { return v0 == v1; } public int GetHashCode(M23f v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Computes the (signed) angle in radians of a rotation matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetRotation(this M23f m) => Fun.Atan2(m.M10, m.M00); /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetScale(this M23f m) => (m.C0.Length + m.C1.Length) / 2; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetScaleVector(this M23f m) => new V2f(m.C0.Length, m.C1.Length); #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm1(M23f m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm2(M23f m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormMax(M23f m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormMin(M23f m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm(this M23f m, float p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M02).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) + Fun.Abs(m.M12).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static float Distance1(this M23f a, M23f b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M02 - a.M02) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11) + Fun.Abs(b.M12 - a.M12); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static float Distance2(this M23f a, M23f b) { return (float)Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M02 - a.M02) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11) + Fun.Square(b.M12 - a.M12)); } /// /// Returns the p-distance between two matrices. /// public static float Distance(this M23f a, M23f b, float p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M02 - a.M02).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) + Fun.Abs(b.M12 - a.M12).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static float DistanceMax(this M23f a, M23f b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static float DistanceMin(this M23f a, M23f b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Transform(this M23f m, V3f v) => m * v; /// /// Transforms vector v by matrix m. /// v.W is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Transform(this M23f m, V4f v) { return new V3f( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, v.W); } /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransposedTransform(this M23f m, V2f v) => v * m; /// /// Transforms direction vector v (v.Z is presumed 0.0) by matrix m. /// public static V2f TransformDir(this M23f m, V2f v) { return new V2f( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y ); } /// /// Transforms point p (v.Z is presumed 1.0) by matrix m. /// public static V2f TransformPos(this M23f m, V2f p) { return new V2f( m.M00 * p.X + m.M01 * p.Y + m.M02, m.M10 * p.X + m.M11 * p.Y + m.M12 ); } /// /// Multiplies two matrices as 3x3 matrices. /// public static M23f MultiplyAffine(this M23f a, M23f b) { return new M23f( a.M00 * b.M00 + a.M01 * b.M10, a.M00 * b.M01 + a.M01 * b.M11, a.M00 * b.M02 + a.M01 * b.M12 + a.M02, a.M10 * b.M00 + a.M11 * b.M10, a.M10 * b.M01 + a.M11 * b.M11, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 ); } #endregion #region Operations /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V3f Row(this M23f m, int index) { float* ptr = &m.M00; return new V3f(ptr[index * 3], ptr[index * 3 + 1], ptr[index * 3 + 2]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V2f Column(this M23f m, int index) { float* ptr = &m.M00; return new V2f(ptr[index], ptr[index + 3]); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M23f a, M23f b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M02 < b.M02 && a.M10 < b.M10 && a.M11 < b.M11 && a.M12 < b.M12; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M23f m, float s) { return m.M00 < s && m.M01 < s && m.M02 < s && m.M10 < s && m.M11 < s && m.M12 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(float s, M23f m) { return s < m.M00 && s < m.M01 && s < m.M02 && s < m.M10 && s < m.M11 && s < m.M12; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M23f a, M23f b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M02 < b.M02 || a.M10 < b.M10 || a.M11 < b.M11 || a.M12 < b.M12; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M23f m, float s) { return m.M00 < s || m.M01 < s || m.M02 < s || m.M10 < s || m.M11 < s || m.M12 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(float s, M23f m) { return s < m.M00 || s < m.M01 || s < m.M02 || s < m.M10 || s < m.M11 || s < m.M12; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M23f a, M23f b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M02 > b.M02 && a.M10 > b.M10 && a.M11 > b.M11 && a.M12 > b.M12; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M23f m, float s) { return m.M00 > s && m.M01 > s && m.M02 > s && m.M10 > s && m.M11 > s && m.M12 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(float s, M23f m) { return s > m.M00 && s > m.M01 && s > m.M02 && s > m.M10 && s > m.M11 && s > m.M12; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M23f a, M23f b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M02 > b.M02 || a.M10 > b.M10 || a.M11 > b.M11 || a.M12 > b.M12; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M23f m, float s) { return m.M00 > s || m.M01 > s || m.M02 > s || m.M10 > s || m.M11 > s || m.M12 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(float s, M23f m) { return s > m.M00 || s > m.M01 || s > m.M02 || s > m.M10 || s > m.M11 || s > m.M12; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M23f a, M23f b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M02 <= b.M02 && a.M10 <= b.M10 && a.M11 <= b.M11 && a.M12 <= b.M12; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M23f m, float s) { return m.M00 <= s && m.M01 <= s && m.M02 <= s && m.M10 <= s && m.M11 <= s && m.M12 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(float s, M23f m) { return s <= m.M00 && s <= m.M01 && s <= m.M02 && s <= m.M10 && s <= m.M11 && s <= m.M12; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M23f a, M23f b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M02 <= b.M02 || a.M10 <= b.M10 || a.M11 <= b.M11 || a.M12 <= b.M12; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M23f m, float s) { return m.M00 <= s || m.M01 <= s || m.M02 <= s || m.M10 <= s || m.M11 <= s || m.M12 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(float s, M23f m) { return s <= m.M00 || s <= m.M01 || s <= m.M02 || s <= m.M10 || s <= m.M11 || s <= m.M12; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M23f a, M23f b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M02 >= b.M02 && a.M10 >= b.M10 && a.M11 >= b.M11 && a.M12 >= b.M12; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M23f m, float s) { return m.M00 >= s && m.M01 >= s && m.M02 >= s && m.M10 >= s && m.M11 >= s && m.M12 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(float s, M23f m) { return s >= m.M00 && s >= m.M01 && s >= m.M02 && s >= m.M10 && s >= m.M11 && s >= m.M12; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M23f a, M23f b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M02 >= b.M02 || a.M10 >= b.M10 || a.M11 >= b.M11 || a.M12 >= b.M12; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M23f m, float s) { return m.M00 >= s || m.M01 >= s || m.M02 >= s || m.M10 >= s || m.M11 >= s || m.M12 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(float s, M23f m) { return s >= m.M00 || s >= m.M01 || s >= m.M02 || s >= m.M10 || s >= m.M11 || s >= m.M12; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M23f a, M23f b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M23f m, float s) { return m.M00 == s && m.M01 == s && m.M02 == s && m.M10 == s && m.M11 == s && m.M12 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(float s, M23f m) { return s == m.M00 && s == m.M01 && s == m.M02 && s == m.M10 && s == m.M11 && s == m.M12; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M23f a, M23f b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M02 == b.M02 || a.M10 == b.M10 || a.M11 == b.M11 || a.M12 == b.M12; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M23f m, float s) { return m.M00 == s || m.M01 == s || m.M02 == s || m.M10 == s || m.M11 == s || m.M12 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(float s, M23f m) { return s == m.M00 || s == m.M01 || s == m.M02 || s == m.M10 || s == m.M11 || s == m.M12; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M23f a, M23f b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M02 != b.M02 && a.M10 != b.M10 && a.M11 != b.M11 && a.M12 != b.M12; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M23f m, float s) { return m.M00 != s && m.M01 != s && m.M02 != s && m.M10 != s && m.M11 != s && m.M12 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(float s, M23f m) { return s != m.M00 && s != m.M01 && s != m.M02 && s != m.M10 && s != m.M11 && s != m.M12; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M23f a, M23f b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M02 != b.M02 || a.M10 != b.M10 || a.M11 != b.M11 || a.M12 != b.M12; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M23f m, float s) { return m.M00 != s || m.M01 != s || m.M02 != s || m.M10 != s || m.M11 != s || m.M12 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(float s, M23f m) { return s != m.M00 || s != m.M01 || s != m.M02 || s != m.M10 || s != m.M11 || s != m.M12; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M23f m0, M23f m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M02 < m1.M02) return -1; if (m0.M02 > m1.M02) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; if (m0.M12 < m1.M12) return -1; if (m0.M12 > m1.M12) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MinElement(M23f m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MaxElement(M23f m) => m.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M23f m, float epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M02.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon) || m.M12.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M23f m, float epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M02.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon) && m.M12.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyFinite(M23f m) => m.AnyFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllFinite(M23f m) => m.AllFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(M23f m) => m.AnyNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(M23f m) => m.AllNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(M23f m) => m.AnyInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(M23f m) => m.AllInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(M23f m) => m.AnyPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(M23f m) => m.AllPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(M23f m) => m.AnyNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(M23f m) => m.AllNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(M23f m) => m.AnyTiny; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(M23f m) => m.AllTiny; #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M23f a, M23f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M23f a, M23f b, float epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M23f m, float epsilon) => Mat.AllTiny(m, epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(M23f m) => m.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any element of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(M23f v) => v.IsNaN; /// /// Returns whether any element of the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(M23f v) => v.IsInfinity; /// /// Returns whether any element of the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(M23f v) => v.IsPositiveInfinity; /// /// Returns whether any element of the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(M23f v) => v.IsNegativeInfinity; /// /// Returns whether all elements of the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(M23f v) => v.IsFinite; #endregion } public static class IRandomUniformM23fExtensions { #region IRandomUniform extensions for M23f /// /// Uses UniformFloat() to generate the elements of an M23f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f UniformM23f(this IRandomUniform rnd) { return new M23f( rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat()); } /// /// Uses UniformFloatClosed() to generate the elements of an M23f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f UniformM23fClosed(this IRandomUniform rnd) { return new M23f( rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed()); } /// /// Uses UniformFloatOpen() to generate the elements of an M23f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f UniformM23fOpen(this IRandomUniform rnd) { return new M23f( rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen()); } #endregion } #endregion #region M23d [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M23d : IEquatable, IValidity, IMatrix { [DataMember] public double M00, M01, M02; [DataMember] public double M10, M11, M12; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(double value) { M00 = value; M01 = 0; M02 = 0; M10 = 0; M11 = value; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d( double m00, double m01, double m02, double m10, double m11, double m12) { M00 = m00; M01 = m01; M02 = m02; M10 = m10; M11 = m11; M12 = m12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(double[] a) { M00 = a[0]; M01 = a[1]; M02 = a[2]; M10 = a[3]; M11 = a[4]; M12 = a[5]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(double[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M02 = a[start + 2]; M10 = a[start + 3]; M11 = a[start + 4]; M12 = a[start + 5]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M22d m, V2d v) { M00 = m.M00; M01 = m.M01; M02 = v.X; M10 = m.M10; M11 = m.M11; M12 = v.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M22i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M23i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M33i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M34i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M44i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M22l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M23l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M33l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M34l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M44l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M22f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M23f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M33f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M34f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M44f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M22d m) { M00 = m.M00; M01 = m.M01; M02 = 0; M10 = m.M10; M11 = m.M11; M12 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M33d m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M34d m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M23d(M44d m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; } #endregion #region Conversions public static explicit operator M23d(M22i m) { return new M23d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = 0, }; } public static explicit operator M23d(M23i m) { return new M23d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, }; } public static explicit operator M23d(M33i m) { return new M23d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, }; } public static explicit operator M23d(M34i m) { return new M23d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, }; } public static explicit operator M23d(M44i m) { return new M23d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, }; } public static explicit operator M23d(M22l m) { return new M23d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = 0, }; } public static explicit operator M23d(M23l m) { return new M23d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, }; } public static explicit operator M23d(M33l m) { return new M23d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, }; } public static explicit operator M23d(M34l m) { return new M23d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, }; } public static explicit operator M23d(M44l m) { return new M23d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, }; } public static explicit operator M23d(M22f m) { return new M23d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = 0, }; } public static explicit operator M23d(M23f m) { return new M23d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, }; } public static explicit operator M23d(M33f m) { return new M23d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, }; } public static explicit operator M23d(M34f m) { return new M23d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, }; } public static explicit operator M23d(M44f m) { return new M23d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, }; } public static explicit operator M23d(M22d m) { return new M23d { M00 = m.M00, M01 = m.M01, M02 = 0, M10 = m.M10, M11 = m.M11, M12 = 0, }; } public static explicit operator M23d(M33d m) { return new M23d { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, }; } public static explicit operator M23d(M34d m) { return new M23d { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, }; } public static explicit operator M23d(M44d m) { return new M23d { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, }; } public static explicit operator M23d(int[] a) { return new M23d( (double)a[0], (double)a[1], (double)a[2], (double)a[3], (double)a[4], (double)a[5]); } public static explicit operator M23d(int[,] a) { return new M23d( (double)a[0, 0], (double)a[0, 1], (double)a[0, 2], (double)a[1, 0], (double)a[1, 1], (double)a[1, 2]); } public static explicit operator int[](M23d m) { return new int[] { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M10, (int)m.M11, (int)m.M12 }; } public static explicit operator int[,](M23d m) { return new int[,] { { (int)m.M00, (int)m.M01, (int)m.M02 }, { (int)m.M10, (int)m.M11, (int)m.M12 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = (int)M00; array[index + 1] = (int)M01; array[index + 2] = (int)M02; array[index + 3] = (int)M10; array[index + 4] = (int)M11; array[index + 5] = (int)M12; } public static explicit operator M23d(long[] a) { return new M23d( (double)a[0], (double)a[1], (double)a[2], (double)a[3], (double)a[4], (double)a[5]); } public static explicit operator M23d(long[,] a) { return new M23d( (double)a[0, 0], (double)a[0, 1], (double)a[0, 2], (double)a[1, 0], (double)a[1, 1], (double)a[1, 2]); } public static explicit operator long[](M23d m) { return new long[] { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M10, (long)m.M11, (long)m.M12 }; } public static explicit operator long[,](M23d m) { return new long[,] { { (long)m.M00, (long)m.M01, (long)m.M02 }, { (long)m.M10, (long)m.M11, (long)m.M12 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = (long)M00; array[index + 1] = (long)M01; array[index + 2] = (long)M02; array[index + 3] = (long)M10; array[index + 4] = (long)M11; array[index + 5] = (long)M12; } public static explicit operator M23d(float[] a) { return new M23d( (double)a[0], (double)a[1], (double)a[2], (double)a[3], (double)a[4], (double)a[5]); } public static explicit operator M23d(float[,] a) { return new M23d( (double)a[0, 0], (double)a[0, 1], (double)a[0, 2], (double)a[1, 0], (double)a[1, 1], (double)a[1, 2]); } public static explicit operator float[](M23d m) { return new float[] { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M10, (float)m.M11, (float)m.M12 }; } public static explicit operator float[,](M23d m) { return new float[,] { { (float)m.M00, (float)m.M01, (float)m.M02 }, { (float)m.M10, (float)m.M11, (float)m.M12 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = (float)M00; array[index + 1] = (float)M01; array[index + 2] = (float)M02; array[index + 3] = (float)M10; array[index + 4] = (float)M11; array[index + 5] = (float)M12; } public static explicit operator M23d(double[] a) { return new M23d( a[0], a[1], a[2], a[3], a[4], a[5]); } public static explicit operator M23d(double[,] a) { return new M23d( a[0, 0], a[0, 1], a[0, 2], a[1, 0], a[1, 1], a[1, 2]); } public static explicit operator double[](M23d m) { return new double[] { m.M00, m.M01, m.M02, m.M10, m.M11, m.M12 }; } public static explicit operator double[,](M23d m) { return new double[,] { { m.M00, m.M01, m.M02 }, { m.M10, m.M11, m.M12 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M02; array[index + 3] = M10; array[index + 4] = M11; array[index + 5] = M12; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23i Copy(Func element_fun) { return new M23i( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23i Copy(Func element_index0_index1_fun) { return new M23i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23l Copy(Func element_fun) { return new M23l( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23l Copy(Func element_index0_index1_fun) { return new M23l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23f Copy(Func element_fun) { return new M23f( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23f Copy(Func element_index0_index1_fun) { return new M23f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23d Copy(Func element_fun) { return new M23d( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M23d Copy(Func element_index0_index1_fun) { return new M23d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2)); } public readonly double[] ToArray() { var array = new double[6]; array[0] = M00; array[1] = M01; array[2] = M02; array[3] = M10; array[4] = M11; array[5] = M12; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d FromCols(V2d col0, V2d col1, V2d col2) { return new M23d( col0.X, col1.X, col2.X, col0.Y, col1.Y, col2.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d FromRows(V3d row0, V3d row1) { return new M23d( row0.X, row0.Y, row0.Z, row1.X, row1.Y, row1.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d FromDiagonal(double value) { return new M23d( value, 0, 0, 0, value, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d FromDiagonal(double m00, double m11) { return new M23d( m00, 0, 0, 0, m11, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d FromDiagonal(V2d s) { return new M23d( s.X, 0, 0, 0, s.Y, 0); } #region Scale #endregion #region Translation /// /// Creates a transformation with the translational component given by 2 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d Translation(double tX, double tY) { return new M23d( 1, 0, tX, 0, 1, tY); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d Translation(V2d t) { return new M23d( 1, 0, t.X, 0, 1, t.Y); } /// /// Creates a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d Translation(Shift2d s) { return new M23d( 1, 0, s.X, 0, 1, s.Y); } #endregion #region Rotation /// /// Creates a 2D rotation matrix with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d Rotation(double angleInRadians) { var a = Fun.Cos(angleInRadians); var b = Fun.Sin(angleInRadians); return new M23d( a, -b, 0, b, a, 0); } /// /// Creates a 2D rotation matrix with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d RotationInDegrees(double angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); /// /// Creates a 2D rotation matrix from a /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d Rotation(Rot2d r) => (M23d)r; #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d DivideByInt(M23d m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M02; yield return M10; yield return M11; yield return M12; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; yield return C2; } } [XmlIgnore] public V3d R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3d( M00, M01, M02); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; M02 = value.Z; } } [XmlIgnore] public V3d R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3d( M10, M11, M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; M12 = value.Z; } } [XmlIgnore] public V2d C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2d( M00, M10); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; } } [XmlIgnore] public V2d C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2d( M01, M11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; } } [XmlIgnore] public V2d C2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V2d( M02, M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M02 = value.X; M12 = value.Y; } } public readonly V2d Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2d(M00, M11); } /// /// Returns the minimum element of the matrix. /// public readonly double MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M02, M10, M11, M12); } /// /// Returns the maximum element of the matrix. /// public readonly double MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M02, M10, M11, M12); } public unsafe double this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &M00) { ptr[index] = value; } } } public unsafe double this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &M00) { return ptr[row * 3 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &M00) { ptr[row * 3 + column] = value; } } } public readonly bool AnyFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) || Fun.IsFinite(M01) || Fun.IsFinite(M02) || Fun.IsFinite(M10) || Fun.IsFinite(M11) || Fun.IsFinite(M12); } } public readonly bool AllFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) && Fun.IsFinite(M01) && Fun.IsFinite(M02) && Fun.IsFinite(M10) && Fun.IsFinite(M11) && Fun.IsFinite(M12); } } public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNaN(M00) || double.IsNaN(M01) || double.IsNaN(M02) || double.IsNaN(M10) || double.IsNaN(M11) || double.IsNaN(M12); } } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNaN(M00) && double.IsNaN(M01) && double.IsNaN(M02) && double.IsNaN(M10) && double.IsNaN(M11) && double.IsNaN(M12); } } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsInfinity(M00) || double.IsInfinity(M01) || double.IsInfinity(M02) || double.IsInfinity(M10) || double.IsInfinity(M11) || double.IsInfinity(M12); } } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsInfinity(M00) && double.IsInfinity(M01) && double.IsInfinity(M02) && double.IsInfinity(M10) && double.IsInfinity(M11) && double.IsInfinity(M12); } } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsPositiveInfinity(M00) || double.IsPositiveInfinity(M01) || double.IsPositiveInfinity(M02) || double.IsPositiveInfinity(M10) || double.IsPositiveInfinity(M11) || double.IsPositiveInfinity(M12); } } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsPositiveInfinity(M00) && double.IsPositiveInfinity(M01) && double.IsPositiveInfinity(M02) && double.IsPositiveInfinity(M10) && double.IsPositiveInfinity(M11) && double.IsPositiveInfinity(M12); } } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNegativeInfinity(M00) || double.IsNegativeInfinity(M01) || double.IsNegativeInfinity(M02) || double.IsNegativeInfinity(M10) || double.IsNegativeInfinity(M11) || double.IsNegativeInfinity(M12); } } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNegativeInfinity(M00) && double.IsNegativeInfinity(M01) && double.IsNegativeInfinity(M02) && double.IsNegativeInfinity(M10) && double.IsNegativeInfinity(M11) && double.IsNegativeInfinity(M12); } } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) || Fun.IsTiny(M01) || Fun.IsTiny(M02) || Fun.IsTiny(M10) || Fun.IsTiny(M11) || Fun.IsTiny(M12); } } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) && Fun.IsTiny(M01) && Fun.IsTiny(M02) && Fun.IsTiny(M10) && Fun.IsTiny(M11) && Fun.IsTiny(M12); } } /// /// Returns true if the absolute value of each element of the matrix is smaller than Constant<double>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any element of the matrix is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any element of the matrix is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any element of the matrix is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any element of the matrix is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all elements of the matrix are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Constants public const int RowCount = 2; public const int ColumnCount = 3; public const int ElementCount = 2 * 3; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(2, 3); } public static M23d Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M23d(0); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly double Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M02) + Fun.Abs(M10) + Fun.Abs(M11) + Fun.Abs(M12); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly double Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M02 * M02 + M10 * M10 + M11 * M11 + M12 * M12); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly double NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly double NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator -(M23d m) { return new M23d( -m.M00, -m.M01, -m.M02, -m.M10, -m.M11, -m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator + (M23d a, M23d b) { return new M23d( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator + (M23d m, double s) { return new M23d( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator + (double s, M23d m) { return new M23d( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator - (M23d a, M23d b) { return new M23d( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator - (M23d m, double s) { return new M23d( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator - (double s, M23d m) { return new M23d( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator % (M23d a, M23d b) { return new M23d( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator % (M23d m, double s) { return new M23d( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator % (double s, M23d m) { return new M23d( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator / (M23d a, M23d b) { return new M23d( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator / (M23d m, double s) { return new M23d( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator / (double s, M23d m) { return new M23d( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator * (M23d m, double s) { return new M23d( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator * (double s, M23d m) { return new M23d( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M23d matrix with a V3d column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator *(M23d m, V3d v) { return new V2d( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z); } /// /// Multiplies a V2d row vector with a M23d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator *(V2d v, M23d m) { return new V3d( v.X * m.M00 + v.Y * m.M10, v.X * m.M01 + v.Y * m.M11, v.X * m.M02 + v.Y * m.M12); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M23d a, M23d b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M23d a, double s) { return a.M00 == s && a.M01 == s && a.M02 == s && a.M10 == s && a.M11 == s && a.M12 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(double s, M23d a) { return s == a.M00 && s == a.M01 && s == a.M02 && s == a.M10 && s == a.M11 && s == a.M12 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M23d a, M23d b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M23d m, double s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(double s, M23d m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01, M02), HashCode.GetCombined(M10, M11, M12)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M23d other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M02.Equals(other.M02) && M10.Equals(other.M10) && M11.Equals(other.M11) && M12.Equals(other.M12); } public override readonly bool Equals(object other) => (other is M23d o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M23d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M23d.FromRows( V3d.Parse(x[0]), V3d.Parse(x[1]) ); } #endregion #region Matrix Operations #endregion #region Matrix Multiplication public static M23d operator *(M22d a, M23d b) { return new M23d( a.M00 * b.M00 + a.M01 * b.M10, a.M00 * b.M01 + a.M01 * b.M11, a.M00 * b.M02 + a.M01 * b.M12, a.M10 * b.M00 + a.M11 * b.M10, a.M10 * b.M01 + a.M11 * b.M11, a.M10 * b.M02 + a.M11 * b.M12 ); } public static M23d operator *(M23d a, M33d b) { return new M23d( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return this[(int)y, (int)x]; } set { this[(int)y, (int)x] = value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (double)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (double)value; } #endregion } public class M23dEqualityComparer : IEqualityComparer { public static readonly M23dEqualityComparer Default = new M23dEqualityComparer(); #region IEqualityComparer Members public bool Equals(M23d v0, M23d v1) { return v0 == v1; } public int GetHashCode(M23d v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Computes the (signed) angle in radians of a rotation matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetRotation(this M23d m) => Fun.Atan2(m.M10, m.M00); /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this M23d m) => (m.C0.Length + m.C1.Length) / 2; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetScaleVector(this M23d m) => new V2d(m.C0.Length, m.C1.Length); #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm1(M23d m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(M23d m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormMax(M23d m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormMin(M23d m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this M23d m, double p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M02).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) + Fun.Abs(m.M12).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static double Distance1(this M23d a, M23d b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M02 - a.M02) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11) + Fun.Abs(b.M12 - a.M12); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static double Distance2(this M23d a, M23d b) { return Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M02 - a.M02) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11) + Fun.Square(b.M12 - a.M12)); } /// /// Returns the p-distance between two matrices. /// public static double Distance(this M23d a, M23d b, double p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M02 - a.M02).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) + Fun.Abs(b.M12 - a.M12).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static double DistanceMax(this M23d a, M23d b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static double DistanceMin(this M23d a, M23d b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Transform(this M23d m, V3d v) => m * v; /// /// Transforms vector v by matrix m. /// v.W is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Transform(this M23d m, V4d v) { return new V3d( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, v.W); } /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransposedTransform(this M23d m, V2d v) => v * m; /// /// Transforms direction vector v (v.Z is presumed 0.0) by matrix m. /// public static V2d TransformDir(this M23d m, V2d v) { return new V2d( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y ); } /// /// Transforms point p (v.Z is presumed 1.0) by matrix m. /// public static V2d TransformPos(this M23d m, V2d p) { return new V2d( m.M00 * p.X + m.M01 * p.Y + m.M02, m.M10 * p.X + m.M11 * p.Y + m.M12 ); } /// /// Multiplies two matrices as 3x3 matrices. /// public static M23d MultiplyAffine(this M23d a, M23d b) { return new M23d( a.M00 * b.M00 + a.M01 * b.M10, a.M00 * b.M01 + a.M01 * b.M11, a.M00 * b.M02 + a.M01 * b.M12 + a.M02, a.M10 * b.M00 + a.M11 * b.M10, a.M10 * b.M01 + a.M11 * b.M11, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 ); } #endregion #region Operations /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V3d Row(this M23d m, int index) { double* ptr = &m.M00; return new V3d(ptr[index * 3], ptr[index * 3 + 1], ptr[index * 3 + 2]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V2d Column(this M23d m, int index) { double* ptr = &m.M00; return new V2d(ptr[index], ptr[index + 3]); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M23d a, M23d b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M02 < b.M02 && a.M10 < b.M10 && a.M11 < b.M11 && a.M12 < b.M12; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M23d m, double s) { return m.M00 < s && m.M01 < s && m.M02 < s && m.M10 < s && m.M11 < s && m.M12 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(double s, M23d m) { return s < m.M00 && s < m.M01 && s < m.M02 && s < m.M10 && s < m.M11 && s < m.M12; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M23d a, M23d b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M02 < b.M02 || a.M10 < b.M10 || a.M11 < b.M11 || a.M12 < b.M12; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M23d m, double s) { return m.M00 < s || m.M01 < s || m.M02 < s || m.M10 < s || m.M11 < s || m.M12 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(double s, M23d m) { return s < m.M00 || s < m.M01 || s < m.M02 || s < m.M10 || s < m.M11 || s < m.M12; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M23d a, M23d b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M02 > b.M02 && a.M10 > b.M10 && a.M11 > b.M11 && a.M12 > b.M12; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M23d m, double s) { return m.M00 > s && m.M01 > s && m.M02 > s && m.M10 > s && m.M11 > s && m.M12 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(double s, M23d m) { return s > m.M00 && s > m.M01 && s > m.M02 && s > m.M10 && s > m.M11 && s > m.M12; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M23d a, M23d b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M02 > b.M02 || a.M10 > b.M10 || a.M11 > b.M11 || a.M12 > b.M12; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M23d m, double s) { return m.M00 > s || m.M01 > s || m.M02 > s || m.M10 > s || m.M11 > s || m.M12 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(double s, M23d m) { return s > m.M00 || s > m.M01 || s > m.M02 || s > m.M10 || s > m.M11 || s > m.M12; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M23d a, M23d b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M02 <= b.M02 && a.M10 <= b.M10 && a.M11 <= b.M11 && a.M12 <= b.M12; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M23d m, double s) { return m.M00 <= s && m.M01 <= s && m.M02 <= s && m.M10 <= s && m.M11 <= s && m.M12 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(double s, M23d m) { return s <= m.M00 && s <= m.M01 && s <= m.M02 && s <= m.M10 && s <= m.M11 && s <= m.M12; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M23d a, M23d b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M02 <= b.M02 || a.M10 <= b.M10 || a.M11 <= b.M11 || a.M12 <= b.M12; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M23d m, double s) { return m.M00 <= s || m.M01 <= s || m.M02 <= s || m.M10 <= s || m.M11 <= s || m.M12 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(double s, M23d m) { return s <= m.M00 || s <= m.M01 || s <= m.M02 || s <= m.M10 || s <= m.M11 || s <= m.M12; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M23d a, M23d b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M02 >= b.M02 && a.M10 >= b.M10 && a.M11 >= b.M11 && a.M12 >= b.M12; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M23d m, double s) { return m.M00 >= s && m.M01 >= s && m.M02 >= s && m.M10 >= s && m.M11 >= s && m.M12 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(double s, M23d m) { return s >= m.M00 && s >= m.M01 && s >= m.M02 && s >= m.M10 && s >= m.M11 && s >= m.M12; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M23d a, M23d b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M02 >= b.M02 || a.M10 >= b.M10 || a.M11 >= b.M11 || a.M12 >= b.M12; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M23d m, double s) { return m.M00 >= s || m.M01 >= s || m.M02 >= s || m.M10 >= s || m.M11 >= s || m.M12 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(double s, M23d m) { return s >= m.M00 || s >= m.M01 || s >= m.M02 || s >= m.M10 || s >= m.M11 || s >= m.M12; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M23d a, M23d b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M23d m, double s) { return m.M00 == s && m.M01 == s && m.M02 == s && m.M10 == s && m.M11 == s && m.M12 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(double s, M23d m) { return s == m.M00 && s == m.M01 && s == m.M02 && s == m.M10 && s == m.M11 && s == m.M12; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M23d a, M23d b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M02 == b.M02 || a.M10 == b.M10 || a.M11 == b.M11 || a.M12 == b.M12; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M23d m, double s) { return m.M00 == s || m.M01 == s || m.M02 == s || m.M10 == s || m.M11 == s || m.M12 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(double s, M23d m) { return s == m.M00 || s == m.M01 || s == m.M02 || s == m.M10 || s == m.M11 || s == m.M12; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M23d a, M23d b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M02 != b.M02 && a.M10 != b.M10 && a.M11 != b.M11 && a.M12 != b.M12; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M23d m, double s) { return m.M00 != s && m.M01 != s && m.M02 != s && m.M10 != s && m.M11 != s && m.M12 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(double s, M23d m) { return s != m.M00 && s != m.M01 && s != m.M02 && s != m.M10 && s != m.M11 && s != m.M12; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M23d a, M23d b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M02 != b.M02 || a.M10 != b.M10 || a.M11 != b.M11 || a.M12 != b.M12; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M23d m, double s) { return m.M00 != s || m.M01 != s || m.M02 != s || m.M10 != s || m.M11 != s || m.M12 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(double s, M23d m) { return s != m.M00 || s != m.M01 || s != m.M02 || s != m.M10 || s != m.M11 || s != m.M12; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M23d m0, M23d m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M02 < m1.M02) return -1; if (m0.M02 > m1.M02) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; if (m0.M12 < m1.M12) return -1; if (m0.M12 > m1.M12) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MinElement(M23d m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MaxElement(M23d m) => m.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M23d m, double epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M02.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon) || m.M12.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M23d m, double epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M02.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon) && m.M12.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyFinite(M23d m) => m.AnyFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllFinite(M23d m) => m.AllFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(M23d m) => m.AnyNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(M23d m) => m.AllNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(M23d m) => m.AnyInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(M23d m) => m.AllInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(M23d m) => m.AnyPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(M23d m) => m.AllPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(M23d m) => m.AnyNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(M23d m) => m.AllNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(M23d m) => m.AnyTiny; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(M23d m) => m.AllTiny; #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M23d a, M23d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M23d a, M23d b, double epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M23d m, double epsilon) => Mat.AllTiny(m, epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(M23d m) => m.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any element of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(M23d v) => v.IsNaN; /// /// Returns whether any element of the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(M23d v) => v.IsInfinity; /// /// Returns whether any element of the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(M23d v) => v.IsPositiveInfinity; /// /// Returns whether any element of the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(M23d v) => v.IsNegativeInfinity; /// /// Returns whether all elements of the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(M23d v) => v.IsFinite; #endregion } public static class IRandomUniformM23dExtensions { #region IRandomUniform extensions for M23d /// /// Uses UniformDouble() to generate the elements of an M23d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d UniformM23d(this IRandomUniform rnd) { return new M23d( rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble()); } /// /// Uses UniformDoubleClosed() to generate the elements of an M23d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d UniformM23dClosed(this IRandomUniform rnd) { return new M23d( rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed()); } /// /// Uses UniformDoubleOpen() to generate the elements of an M23d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d UniformM23dOpen(this IRandomUniform rnd) { return new M23d( rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen()); } /// /// Uses UniformDoubleFull() to generate the elements of an M23d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d UniformM23dFull(this IRandomUniform rnd) { return new M23d( rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull()); } /// /// Uses UniformDoubleFullClosed() to generate the elements of an M23d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d UniformM23dFullClosed(this IRandomUniform rnd) { return new M23d( rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed()); } /// /// Uses UniformDoubleFullOpen() to generate the elements of an M23d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d UniformM23dFullOpen(this IRandomUniform rnd) { return new M23d( rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen()); } #endregion } #endregion #region M33i [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M33i : IEquatable, IValidity, IMatrix { [DataMember] public int M00, M01, M02; [DataMember] public int M10, M11, M12; [DataMember] public int M20, M21, M22; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(int value) { M00 = value; M01 = 0; M02 = 0; M10 = 0; M11 = value; M12 = 0; M20 = 0; M21 = 0; M22 = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i( int m00, int m01, int m02, int m10, int m11, int m12, int m20, int m21, int m22) { M00 = m00; M01 = m01; M02 = m02; M10 = m10; M11 = m11; M12 = m12; M20 = m20; M21 = m21; M22 = m22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(int[] a) { M00 = a[0]; M01 = a[1]; M02 = a[2]; M10 = a[3]; M11 = a[4]; M12 = a[5]; M20 = a[6]; M21 = a[7]; M22 = a[8]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(int[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M02 = a[start + 2]; M10 = a[start + 3]; M11 = a[start + 4]; M12 = a[start + 5]; M20 = a[start + 6]; M21 = a[start + 7]; M22 = a[start + 8]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M22i m) { M00 = m.M00; M01 = m.M01; M02 = 0; M10 = m.M10; M11 = m.M11; M12 = 0; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M23i m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M34i m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; M20 = m.M20; M21 = m.M21; M22 = m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M44i m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; M20 = m.M20; M21 = m.M21; M22 = m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M22l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = 0; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M23l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M33l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M34l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M44l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M22f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = 0; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M23f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M33f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M34f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M44f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M22d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = 0; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M23d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M33d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M34d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33i(M44d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; } #endregion #region Conversions public static explicit operator M33i(M22i m) { return new M33i { M00 = m.M00, M01 = m.M01, M02 = 0, M10 = m.M10, M11 = m.M11, M12 = 0, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33i(M23i m) { return new M33i { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33i(M34i m) { return new M33i { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, M20 = m.M20, M21 = m.M21, M22 = m.M22, }; } public static explicit operator M33i(M44i m) { return new M33i { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, M20 = m.M20, M21 = m.M21, M22 = m.M22, }; } public static explicit operator M33i(M22l m) { return new M33i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = 0, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33i(M23l m) { return new M33i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33i(M33l m) { return new M33i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, }; } public static explicit operator M33i(M34l m) { return new M33i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, }; } public static explicit operator M33i(M44l m) { return new M33i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, }; } public static explicit operator M33i(M22f m) { return new M33i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = 0, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33i(M23f m) { return new M33i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33i(M33f m) { return new M33i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, }; } public static explicit operator M33i(M34f m) { return new M33i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, }; } public static explicit operator M33i(M44f m) { return new M33i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, }; } public static explicit operator M33i(M22d m) { return new M33i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = 0, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33i(M23d m) { return new M33i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33i(M33d m) { return new M33i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, }; } public static explicit operator M33i(M34d m) { return new M33i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, }; } public static explicit operator M33i(M44d m) { return new M33i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, }; } public static explicit operator M33i(int[] a) { return new M33i( a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); } public static explicit operator M33i(int[,] a) { return new M33i( a[0, 0], a[0, 1], a[0, 2], a[1, 0], a[1, 1], a[1, 2], a[2, 0], a[2, 1], a[2, 2]); } public static explicit operator int[](M33i m) { return new int[] { m.M00, m.M01, m.M02, m.M10, m.M11, m.M12, m.M20, m.M21, m.M22 }; } public static explicit operator int[,](M33i m) { return new int[,] { { m.M00, m.M01, m.M02 }, { m.M10, m.M11, m.M12 }, { m.M20, m.M21, m.M22 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M02; array[index + 3] = M10; array[index + 4] = M11; array[index + 5] = M12; array[index + 6] = M20; array[index + 7] = M21; array[index + 8] = M22; } public static explicit operator M33i(long[] a) { return new M33i( (int)a[0], (int)a[1], (int)a[2], (int)a[3], (int)a[4], (int)a[5], (int)a[6], (int)a[7], (int)a[8]); } public static explicit operator M33i(long[,] a) { return new M33i( (int)a[0, 0], (int)a[0, 1], (int)a[0, 2], (int)a[1, 0], (int)a[1, 1], (int)a[1, 2], (int)a[2, 0], (int)a[2, 1], (int)a[2, 2]); } public static explicit operator long[](M33i m) { return new long[] { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M10, (long)m.M11, (long)m.M12, (long)m.M20, (long)m.M21, (long)m.M22 }; } public static explicit operator long[,](M33i m) { return new long[,] { { (long)m.M00, (long)m.M01, (long)m.M02 }, { (long)m.M10, (long)m.M11, (long)m.M12 }, { (long)m.M20, (long)m.M21, (long)m.M22 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = (long)M00; array[index + 1] = (long)M01; array[index + 2] = (long)M02; array[index + 3] = (long)M10; array[index + 4] = (long)M11; array[index + 5] = (long)M12; array[index + 6] = (long)M20; array[index + 7] = (long)M21; array[index + 8] = (long)M22; } public static explicit operator M33i(float[] a) { return new M33i( (int)a[0], (int)a[1], (int)a[2], (int)a[3], (int)a[4], (int)a[5], (int)a[6], (int)a[7], (int)a[8]); } public static explicit operator M33i(float[,] a) { return new M33i( (int)a[0, 0], (int)a[0, 1], (int)a[0, 2], (int)a[1, 0], (int)a[1, 1], (int)a[1, 2], (int)a[2, 0], (int)a[2, 1], (int)a[2, 2]); } public static explicit operator float[](M33i m) { return new float[] { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M10, (float)m.M11, (float)m.M12, (float)m.M20, (float)m.M21, (float)m.M22 }; } public static explicit operator float[,](M33i m) { return new float[,] { { (float)m.M00, (float)m.M01, (float)m.M02 }, { (float)m.M10, (float)m.M11, (float)m.M12 }, { (float)m.M20, (float)m.M21, (float)m.M22 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = (float)M00; array[index + 1] = (float)M01; array[index + 2] = (float)M02; array[index + 3] = (float)M10; array[index + 4] = (float)M11; array[index + 5] = (float)M12; array[index + 6] = (float)M20; array[index + 7] = (float)M21; array[index + 8] = (float)M22; } public static explicit operator M33i(double[] a) { return new M33i( (int)a[0], (int)a[1], (int)a[2], (int)a[3], (int)a[4], (int)a[5], (int)a[6], (int)a[7], (int)a[8]); } public static explicit operator M33i(double[,] a) { return new M33i( (int)a[0, 0], (int)a[0, 1], (int)a[0, 2], (int)a[1, 0], (int)a[1, 1], (int)a[1, 2], (int)a[2, 0], (int)a[2, 1], (int)a[2, 2]); } public static explicit operator double[](M33i m) { return new double[] { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M10, (double)m.M11, (double)m.M12, (double)m.M20, (double)m.M21, (double)m.M22 }; } public static explicit operator double[,](M33i m) { return new double[,] { { (double)m.M00, (double)m.M01, (double)m.M02 }, { (double)m.M10, (double)m.M11, (double)m.M12 }, { (double)m.M20, (double)m.M21, (double)m.M22 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = (double)M00; array[index + 1] = (double)M01; array[index + 2] = (double)M02; array[index + 3] = (double)M10; array[index + 4] = (double)M11; array[index + 5] = (double)M12; array[index + 6] = (double)M20; array[index + 7] = (double)M21; array[index + 8] = (double)M22; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33i Copy(Func element_fun) { return new M33i( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M20), element_fun(M21), element_fun(M22)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33i Copy(Func element_index0_index1_fun) { return new M33i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33l Copy(Func element_fun) { return new M33l( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M20), element_fun(M21), element_fun(M22)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33l Copy(Func element_index0_index1_fun) { return new M33l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33f Copy(Func element_fun) { return new M33f( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M20), element_fun(M21), element_fun(M22)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33f Copy(Func element_index0_index1_fun) { return new M33f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33d Copy(Func element_fun) { return new M33d( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M20), element_fun(M21), element_fun(M22)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33d Copy(Func element_index0_index1_fun) { return new M33d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2)); } /// /// Returns a copy of the upper left sub matrix. /// public readonly M22i UpperLeftM22() { return (M22i)this; } public readonly int[] ToArray() { var array = new int[9]; array[0] = M00; array[1] = M01; array[2] = M02; array[3] = M10; array[4] = M11; array[5] = M12; array[6] = M20; array[7] = M21; array[8] = M22; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i FromCols(V3i col0, V3i col1, V3i col2) { return new M33i( col0.X, col1.X, col2.X, col0.Y, col1.Y, col2.Y, col0.Z, col1.Z, col2.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i FromRows(V3i row0, V3i row1, V3i row2) { return new M33i( row0.X, row0.Y, row0.Z, row1.X, row1.Y, row1.Z, row2.X, row2.Y, row2.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i FromDiagonal(int value) { return new M33i( value, 0, 0, 0, value, 0, 0, 0, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i FromDiagonal(int m00, int m11, int m22) { return new M33i( m00, 0, 0, 0, m11, 0, 0, 0, m22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i FromDiagonal(V3i s) { return new M33i( s.X, 0, 0, 0, s.Y, 0, 0, 0, s.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i FromAntiDiagonal(int value) { return new M33i( 0, 0, value, 0, value, 0, value, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i FromAntiDiagonal(int m02, int m11, int m20) { return new M33i( 0, 0, m02, 0, m11, 0, m20, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i FromAntiDiagonal(V3i s) { return new M33i( 0, 0, s.X, 0, s.Y, 0, s.Z, 0, 0); } #region Scale /// /// Creates a transformation using 3 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i Scale(int sX, int sY, int sZ) => FromDiagonal(sX, sY, sZ); /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i Scale(V3i s) => FromDiagonal(s); /// /// Creates a homogenous transformation using a uniform scale. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i Scale(int s) { return new M33i( s, 0, 0, 0, s, 0, 0, 0, 1); } /// /// Creates a transformation using 2 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i Scale(int sX, int sY) { return new M33i( sX, 0, 0, 0, sY, 0, 0, 0, 1); } /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i Scale(V2i s) { return new M33i( s.X, 0, 0, 0, s.Y, 0, 0, 0, 1); } #endregion #region Translation /// /// Creates a transformation with the translational component given by 2 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i Translation(int tX, int tY) { return new M33i( 1, 0, tX, 0, 1, tY, 0, 0, 1); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i Translation(V2i t) { return new M33i( 1, 0, t.X, 0, 1, t.Y, 0, 0, 1); } #endregion #region Shearing /// /// Creates a shear transformation matrix along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i ShearXY(int factorX, int factorY) { return new M33i( 1, 0, factorX, 0, 1, factorY, 0, 0, 1); } /// /// Creates a shear transformation matrix along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i ShearXZ(int factorX, int factorZ) { return new M33i( 1, factorX, 0, 0, 1, 0, 0, factorZ, 1); } /// /// Creates a shear transformation matrix along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i ShearYZ(int factorY, int factorZ) { return new M33i( 1, 0, 0, factorY, 1, 0, factorZ, 0, 1); } #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i DivideByInt(M33i m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M02; yield return M10; yield return M11; yield return M12; yield return M20; yield return M21; yield return M22; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; yield return R2; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; yield return C2; } } [XmlIgnore] public V3i R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3i( M00, M01, M02); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; M02 = value.Z; } } [XmlIgnore] public V3i R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3i( M10, M11, M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; M12 = value.Z; } } [XmlIgnore] public V3i R2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3i( M20, M21, M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M20 = value.X; M21 = value.Y; M22 = value.Z; } } [XmlIgnore] public V3i C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3i( M00, M10, M20); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; M20 = value.Z; } } [XmlIgnore] public V3i C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3i( M01, M11, M21); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; M21 = value.Z; } } [XmlIgnore] public V3i C2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3i( M02, M12, M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M02 = value.X; M12 = value.Y; M22 = value.Z; } } public readonly V3i Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V3i(M00, M11, M22); } public readonly V3i AntiDiagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V3i(M02, M11, M20); } /// /// Returns the minimum element of the matrix. /// public readonly int MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M02, M10, M11, M12, M20, M21, M22); } /// /// Returns the maximum element of the matrix. /// public readonly int MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M02, M10, M11, M12, M20, M21, M22); } public unsafe int this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (int* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (int* ptr = &M00) { ptr[index] = value; } } } public unsafe int this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (int* ptr = &M00) { return ptr[row * 3 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (int* ptr = &M00) { ptr[row * 3 + column] = value; } } } #endregion #region Constants public const int RowCount = 3; public const int ColumnCount = 3; public const int ElementCount = 3 * 3; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(3, 3); } public static M33i Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M33i(0); } public static M33i Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M33i(1, 0, 0, 0, 1, 0, 0, 0, 1); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly int Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M02) + Fun.Abs(M10) + Fun.Abs(M11) + Fun.Abs(M12) + Fun.Abs(M20) + Fun.Abs(M21) + Fun.Abs(M22); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly double Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M02 * M02 + M10 * M10 + M11 * M11 + M12 * M12 + M20 * M20 + M21 * M21 + M22 * M22); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly int NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12)), Fun.Max( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly int NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12)), Fun.Min( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator -(M33i m) { return new M33i( -m.M00, -m.M01, -m.M02, -m.M10, -m.M11, -m.M12, -m.M20, -m.M21, -m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator + (M33i a, M33i b) { return new M33i( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator + (M33i m, int s) { return new M33i( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M20 + s, m.M21 + s, m.M22 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator + (int s, M33i m) { return new M33i( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12, s + m.M20, s + m.M21, s + m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator + (M33i a, M33l b) { return new M33l( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator + (M33i m, long s) { return new M33l( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M20 + s, m.M21 + s, m.M22 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator + (long s, M33i m) { return new M33l( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12, s + m.M20, s + m.M21, s + m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator + (M33i a, M33f b) { return new M33f( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator + (M33i m, float s) { return new M33f( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M20 + s, m.M21 + s, m.M22 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator + (float s, M33i m) { return new M33f( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12, s + m.M20, s + m.M21, s + m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator + (M33i a, M33d b) { return new M33d( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator + (M33i m, double s) { return new M33d( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M20 + s, m.M21 + s, m.M22 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator + (double s, M33i m) { return new M33d( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12, s + m.M20, s + m.M21, s + m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator - (M33i a, M33i b) { return new M33i( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator - (M33i m, int s) { return new M33i( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M20 - s, m.M21 - s, m.M22 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator - (int s, M33i m) { return new M33i( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12, s - m.M20, s - m.M21, s - m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator - (M33i a, M33l b) { return new M33l( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator - (M33i m, long s) { return new M33l( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M20 - s, m.M21 - s, m.M22 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator - (long s, M33i m) { return new M33l( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12, s - m.M20, s - m.M21, s - m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator - (M33i a, M33f b) { return new M33f( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator - (M33i m, float s) { return new M33f( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M20 - s, m.M21 - s, m.M22 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator - (float s, M33i m) { return new M33f( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12, s - m.M20, s - m.M21, s - m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator - (M33i a, M33d b) { return new M33d( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator - (M33i m, double s) { return new M33d( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M20 - s, m.M21 - s, m.M22 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator - (double s, M33i m) { return new M33d( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12, s - m.M20, s - m.M21, s - m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator % (M33i a, M33i b) { return new M33i( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator % (M33i m, int s) { return new M33i( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M20 % s, m.M21 % s, m.M22 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator % (int s, M33i m) { return new M33i( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12, s % m.M20, s % m.M21, s % m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator % (M33i a, M33l b) { return new M33l( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator % (M33i m, long s) { return new M33l( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M20 % s, m.M21 % s, m.M22 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator % (long s, M33i m) { return new M33l( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12, s % m.M20, s % m.M21, s % m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator % (M33i a, M33f b) { return new M33f( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator % (M33i m, float s) { return new M33f( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M20 % s, m.M21 % s, m.M22 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator % (float s, M33i m) { return new M33f( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12, s % m.M20, s % m.M21, s % m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator % (M33i a, M33d b) { return new M33d( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator % (M33i m, double s) { return new M33d( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M20 % s, m.M21 % s, m.M22 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator % (double s, M33i m) { return new M33d( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12, s % m.M20, s % m.M21, s % m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator / (M33i a, M33i b) { return new M33i( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator / (M33i m, int s) { return new M33i( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M20 / s, m.M21 / s, m.M22 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator / (int s, M33i m) { return new M33i( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12, s / m.M20, s / m.M21, s / m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator / (M33i a, M33l b) { return new M33l( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator / (M33i m, long s) { return new M33l( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M20 / s, m.M21 / s, m.M22 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator / (long s, M33i m) { return new M33l( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12, s / m.M20, s / m.M21, s / m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator / (M33i a, M33f b) { return new M33f( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator / (M33i m, float s) { return new M33f( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M20 / s, m.M21 / s, m.M22 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator / (float s, M33i m) { return new M33f( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12, s / m.M20, s / m.M21, s / m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator / (M33i a, M33d b) { return new M33d( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator / (M33i m, double s) { return new M33d( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M20 / s, m.M21 / s, m.M22 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator / (double s, M33i m) { return new M33d( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12, s / m.M20, s / m.M21, s / m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator * (M33i m, int s) { return new M33i( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M20 * s, m.M21 * s, m.M22 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator * (int s, M33i m) { return new M33i( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12, s * m.M20, s * m.M21, s * m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator * (M33i m, long s) { return new M33l( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M20 * s, m.M21 * s, m.M22 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator * (long s, M33i m) { return new M33l( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12, s * m.M20, s * m.M21, s * m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator * (M33i m, float s) { return new M33f( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M20 * s, m.M21 * s, m.M22 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator * (float s, M33i m) { return new M33f( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12, s * m.M20, s * m.M21, s * m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator * (M33i m, double s) { return new M33d( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M20 * s, m.M21 * s, m.M22 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator * (double s, M33i m) { return new M33d( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12, s * m.M20, s * m.M21, s * m.M22); } #endregion #region Bitwise Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator ~(M33i m) { return new M33i( ~m.M00, ~m.M01, ~m.M02, ~m.M10, ~m.M11, ~m.M12, ~m.M20, ~m.M21, ~m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator <<(M33i a, int s) { return new M33i( a.M00 << s, a.M01 << s, a.M02 << s, a.M10 << s, a.M11 << s, a.M12 << s, a.M20 << s, a.M21 << s, a.M22 << s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator >>(M33i a, int s) { return new M33i( a.M00 >> s, a.M01 >> s, a.M02 >> s, a.M10 >> s, a.M11 >> s, a.M12 >> s, a.M20 >> s, a.M21 >> s, a.M22 >> s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator &(M33i a, M33i b) { return new M33i( a.M00 & b.M00, a.M01 & b.M01, a.M02 & b.M02, a.M10 & b.M10, a.M11 & b.M11, a.M12 & b.M12, a.M20 & b.M20, a.M21 & b.M21, a.M22 & b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator &(M33i a, int s) { return new M33i( a.M00 & s, a.M01 & s, a.M02 & s, a.M10 & s, a.M11 & s, a.M12 & s, a.M20 & s, a.M21 & s, a.M22 & s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator &(int s, M33i a) { return new M33i( s & a.M00, s & a.M01, s & a.M02, s & a.M10, s & a.M11, s & a.M12, s & a.M20, s & a.M21, s & a.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator |(M33i a, M33i b) { return new M33i( a.M00 | b.M00, a.M01 | b.M01, a.M02 | b.M02, a.M10 | b.M10, a.M11 | b.M11, a.M12 | b.M12, a.M20 | b.M20, a.M21 | b.M21, a.M22 | b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator |(M33i a, int s) { return new M33i( a.M00 | s, a.M01 | s, a.M02 | s, a.M10 | s, a.M11 | s, a.M12 | s, a.M20 | s, a.M21 | s, a.M22 | s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator |(int s, M33i a) { return new M33i( s | a.M00, s | a.M01, s | a.M02, s | a.M10, s | a.M11, s | a.M12, s | a.M20, s | a.M21, s | a.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator ^(M33i a, M33i b) { return new M33i( a.M00 ^ b.M00, a.M01 ^ b.M01, a.M02 ^ b.M02, a.M10 ^ b.M10, a.M11 ^ b.M11, a.M12 ^ b.M12, a.M20 ^ b.M20, a.M21 ^ b.M21, a.M22 ^ b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator ^(M33i a, int s) { return new M33i( a.M00 ^ s, a.M01 ^ s, a.M02 ^ s, a.M10 ^ s, a.M11 ^ s, a.M12 ^ s, a.M20 ^ s, a.M21 ^ s, a.M22 ^ s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i operator ^(int s, M33i a) { return new M33i( s ^ a.M00, s ^ a.M01, s ^ a.M02, s ^ a.M10, s ^ a.M11, s ^ a.M12, s ^ a.M20, s ^ a.M21, s ^ a.M22); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M33i matrix with a V3i column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator *(M33i m, V3i v) { return new V3i( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z); } /// /// Multiplies a V3i row vector with a M33i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator *(V3i v, M33i m) { return new V3i( v.X * m.M00 + v.Y * m.M10 + v.Z * m.M20, v.X * m.M01 + v.Y * m.M11 + v.Z * m.M21, v.X * m.M02 + v.Y * m.M12 + v.Z * m.M22); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M33i a, M33i b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M33i a, int s) { return a.M00 == s && a.M01 == s && a.M02 == s && a.M10 == s && a.M11 == s && a.M12 == s && a.M20 == s && a.M21 == s && a.M22 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(int s, M33i a) { return s == a.M00 && s == a.M01 && s == a.M02 && s == a.M10 && s == a.M11 && s == a.M12 && s == a.M20 && s == a.M21 && s == a.M22 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M33i a, M33i b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M33i m, int s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(int s, M33i m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01, M02), HashCode.GetCombined(M10, M11, M12), HashCode.GetCombined(M20, M21, M22)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M33i other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M02.Equals(other.M02) && M10.Equals(other.M10) && M11.Equals(other.M11) && M12.Equals(other.M12) && M20.Equals(other.M20) && M21.Equals(other.M21) && M22.Equals(other.M22); } public override readonly bool Equals(object other) => (other is M33i o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + betweenM + R2.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M33i Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M33i.FromRows( V3i.Parse(x[0]), V3i.Parse(x[1]), V3i.Parse(x[2]) ); } #endregion #region Matrix Operations /// /// Returns adjoint of this matrix. /// public readonly M33i Adjoint { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { M33i result = new M33i(); for (int row = 0; row < 3; row++) { for (int col = 0; col < 3; col++) { if (((col + row) % 2) == 0) result[col, row] = this.Minor(row, col).Determinant; else result[col, row] = -this.Minor(row, col).Determinant; } } return result; } } /// /// Returns the trace of this matrix. /// The trace is defined as the sum of the diagonal elements, /// and is only defined for square matrices. /// public readonly int Trace { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return M00 + M11 + M22 ; } } /// /// Gets the determinant of this matrix. /// The determinant is only defined for square matrices. /// public readonly int Determinant { get { if (M10 == 0 && M20 == 0 && M21 == 0) { return M00 * M11 * M22; } return M00 * M11 * M22 - M00 * M12 * M21 + M01 * M12 * M20 - M01 * M10 * M22 + M02 * M10 * M21 - M02 * M11 * M20; } } /// /// Returns whether this matrix is invertible. /// A matrix is invertible if its determinant is not zero. /// public readonly bool Invertible { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant != 0; } } /// /// Returns whether this matrix is singular. /// A matrix is singular if its determinant is zero. /// public readonly bool Singular { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant == 0; } } /// /// Gets transpose of this matrix. /// public readonly M33i Transposed { get { return new M33i { M00 = M00, M01 = M10, M02 = M20, M10 = M01, M11 = M11, M12 = M21, M20 = M02, M21 = M12, M22 = M22 }; } } #endregion #region Matrix Multiplication public static M33i operator *(M33i a, M33i b) { return new M33i( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return (double)this[(int)y, (int)x]; } set { this[(int)y, (int)x] = (int)value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return (double)this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = (int)value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (int)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (int)value; } #endregion } public class M33iEqualityComparer : IEqualityComparer { public static readonly M33iEqualityComparer Default = new M33iEqualityComparer(); #region IEqualityComparer Members public bool Equals(M33i v0, M33i v1) { return v0 == v1; } public int GetHashCode(M33i v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this M33i m) => (m.C0.Length + m.C1.Length + m.C2.Length) / 3; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetScaleVector(this M33i m) => new V3d(m.C0.Length, m.C1.Length, m.C2.Length); /// /// Approximates the uniform scale value of the given transformation matrix (average length of 2D basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale2(this M33i m) => (m.C0.XY.Length + m.C1.XY.Length) / 2; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the 2D basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetScaleVector2(this M33i m) => new V2d(m.C0.XY.Length, m.C1.XY.Length); #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Norm1(M33i m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(M33i m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NormMax(M33i m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NormMin(M33i m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this M33i m, double p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M02).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) + Fun.Abs(m.M12).Pow(p) + Fun.Abs(m.M20).Pow(p) + Fun.Abs(m.M21).Pow(p) + Fun.Abs(m.M22).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static int Distance1(this M33i a, M33i b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M02 - a.M02) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11) + Fun.Abs(b.M12 - a.M12) + Fun.Abs(b.M20 - a.M20) + Fun.Abs(b.M21 - a.M21) + Fun.Abs(b.M22 - a.M22); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static double Distance2(this M33i a, M33i b) { return Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M02 - a.M02) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11) + Fun.Square(b.M12 - a.M12) + Fun.Square(b.M20 - a.M20) + Fun.Square(b.M21 - a.M21) + Fun.Square(b.M22 - a.M22)); } /// /// Returns the p-distance between two matrices. /// public static double Distance(this M33i a, M33i b, double p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M02 - a.M02).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) + Fun.Abs(b.M12 - a.M12).Pow(p) + Fun.Abs(b.M20 - a.M20).Pow(p) + Fun.Abs(b.M21 - a.M21).Pow(p) + Fun.Abs(b.M22 - a.M22).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static int DistanceMax(this M33i a, M33i b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12)), Fun.Max( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static int DistanceMin(this M33i a, M33i b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12)), Fun.Min( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Transform(this M33i m, V3i v) => m * v; /// /// Transforms vector v by matrix m. /// v.W is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Transform(this M33i m, V4i v) { return new V4i( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z, v.W); } /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i TransposedTransform(this M33i m, V3i v) => v * m; /// /// Transforms vector v by the transpose of matrix m. /// v.W is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i TransposedTransform(this M33i m, V4i v) { return new V4i( v.X * m.M00 + v.Y * m.M10 + v.Z * m.M20, v.X * m.M01 + v.Y * m.M11 + v.Z * m.M21, v.X * m.M02 + v.Y * m.M12 + v.Z * m.M22, v.W); } /// /// Transforms direction vector v (v.Z is presumed 0.0) by matrix m. /// public static V2i TransformDir(this M33i m, V2i v) { return new V2i( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y ); } /// /// Transforms point p (v.Z is presumed 1.0) by matrix m. /// No projective transform is performed. /// public static V2i TransformPos(this M33i m, V2i p) { return new V2i( m.M00 * p.X + m.M01 * p.Y + m.M02, m.M10 * p.X + m.M11 * p.Y + m.M12 ); } /// /// Transforms point p (p.Z is presumed 1.0) by matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static V2i TransformPosProj(this M33i m, V2i p) { int s = m.M20 * p.X + m.M21 * p.Y + m.M22; return TransformPos(m, p) * (1 / s); } /// /// Transforms point p (p.Z is presumed 1.0) by matrix m. /// Projective transform is performed. /// public static V3i TransformPosProjFull(this M33i m, V2i p) { return new V3i( m.M00 * p.X + m.M01 * p.Y + m.M02, m.M10 * p.X + m.M11 * p.Y + m.M12, m.M20 * p.X + m.M21 * p.Y + m.M22 ); } /// /// Transforms direction vector v (v.Z is presumed 0.0) by transposed version of matrix m. /// public static V2i TransposedTransformDir(this M33i m, V2i v) { return new V2i( m.M00 * v.X + m.M10 * v.Y, m.M01 * v.X + m.M11 * v.Y ); } /// /// Transforms point p (v.Z is presumed 1.0) by transposed version of matrix m. /// No projective transform is performed. /// public static V2i TransposedTransformPos(this M33i m, V2i p) { return new V2i( m.M00 * p.X + m.M10 * p.Y + m.M20, m.M01 * p.X + m.M11 * p.Y + m.M21 ); } /// /// Transforms point p (v.Z is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static V2i TransposedTransformPosProj(this M33i m, V2i p) { var s = m.M02 * p.X + m.M12 * p.Y + m.M22; return TransposedTransformPos(m, p) * (1 / s); } [Obsolete("Use TransposedTransformPosProj instead.")] public static V2i TransposedTransformProj(this M33i m, V2i p) => m.TransposedTransformPosProj(p); /// /// Transforms point p (v.Z is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. /// public static V3i TransposedTransformPosProjFull(this M33i m, V2i p) { return new V3i( m.M00 * p.X + m.M10 * p.Y + m.M20, m.M01 * p.X + m.M11 * p.Y + m.M21, m.M02 * p.X + m.M12 * p.Y + m.M22 ); } [Obsolete("Use TransposedTransformPosProjFull instead.")] public static V3i TransposedTransformProjFull(this M33i m, V2i p) => m.TransposedTransformPosProjFull(p); #endregion #region Operations /// /// Returns the given to a deleting the /// specified row and column. /// public static M22i Minor(this M33i m, int row, int column) { M22i rs = new M22i(); for (int k = 0; k < 4; k++) { var i = k / 2; var j = k % 2; var ii = (i < row) ? i : i + 1; var jj = (j < column) ? j : j + 1; rs[k] = m[ii * 3 + jj]; } return rs; } /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V3i Row(this M33i m, int index) { int* ptr = &m.M00; return new V3i(ptr[index * 3], ptr[index * 3 + 1], ptr[index * 3 + 2]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V3i Column(this M33i m, int index) { int* ptr = &m.M00; return new V3i(ptr[index], ptr[index + 3], ptr[index + 6]); } /// /// Returns the determinant of the given matrix. /// The determinant is only defined for square matrices. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Determinant(M33i m) => m.Determinant; /// /// Returns the transpose of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i Transposed(M33i m) => m.Transposed; /// /// Transposes the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transpose(this ref M33i m) { Fun.Swap(ref m.M10, ref m.M01); Fun.Swap(ref m.M20, ref m.M02); Fun.Swap(ref m.M21, ref m.M12); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M33i a, M33i b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M02 < b.M02 && a.M10 < b.M10 && a.M11 < b.M11 && a.M12 < b.M12 && a.M20 < b.M20 && a.M21 < b.M21 && a.M22 < b.M22; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M33i m, int s) { return m.M00 < s && m.M01 < s && m.M02 < s && m.M10 < s && m.M11 < s && m.M12 < s && m.M20 < s && m.M21 < s && m.M22 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(int s, M33i m) { return s < m.M00 && s < m.M01 && s < m.M02 && s < m.M10 && s < m.M11 && s < m.M12 && s < m.M20 && s < m.M21 && s < m.M22; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M33i a, M33i b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M02 < b.M02 || a.M10 < b.M10 || a.M11 < b.M11 || a.M12 < b.M12 || a.M20 < b.M20 || a.M21 < b.M21 || a.M22 < b.M22; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M33i m, int s) { return m.M00 < s || m.M01 < s || m.M02 < s || m.M10 < s || m.M11 < s || m.M12 < s || m.M20 < s || m.M21 < s || m.M22 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(int s, M33i m) { return s < m.M00 || s < m.M01 || s < m.M02 || s < m.M10 || s < m.M11 || s < m.M12 || s < m.M20 || s < m.M21 || s < m.M22; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M33i a, M33i b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M02 > b.M02 && a.M10 > b.M10 && a.M11 > b.M11 && a.M12 > b.M12 && a.M20 > b.M20 && a.M21 > b.M21 && a.M22 > b.M22; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M33i m, int s) { return m.M00 > s && m.M01 > s && m.M02 > s && m.M10 > s && m.M11 > s && m.M12 > s && m.M20 > s && m.M21 > s && m.M22 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(int s, M33i m) { return s > m.M00 && s > m.M01 && s > m.M02 && s > m.M10 && s > m.M11 && s > m.M12 && s > m.M20 && s > m.M21 && s > m.M22; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M33i a, M33i b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M02 > b.M02 || a.M10 > b.M10 || a.M11 > b.M11 || a.M12 > b.M12 || a.M20 > b.M20 || a.M21 > b.M21 || a.M22 > b.M22; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M33i m, int s) { return m.M00 > s || m.M01 > s || m.M02 > s || m.M10 > s || m.M11 > s || m.M12 > s || m.M20 > s || m.M21 > s || m.M22 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(int s, M33i m) { return s > m.M00 || s > m.M01 || s > m.M02 || s > m.M10 || s > m.M11 || s > m.M12 || s > m.M20 || s > m.M21 || s > m.M22; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M33i a, M33i b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M02 <= b.M02 && a.M10 <= b.M10 && a.M11 <= b.M11 && a.M12 <= b.M12 && a.M20 <= b.M20 && a.M21 <= b.M21 && a.M22 <= b.M22; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M33i m, int s) { return m.M00 <= s && m.M01 <= s && m.M02 <= s && m.M10 <= s && m.M11 <= s && m.M12 <= s && m.M20 <= s && m.M21 <= s && m.M22 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(int s, M33i m) { return s <= m.M00 && s <= m.M01 && s <= m.M02 && s <= m.M10 && s <= m.M11 && s <= m.M12 && s <= m.M20 && s <= m.M21 && s <= m.M22; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M33i a, M33i b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M02 <= b.M02 || a.M10 <= b.M10 || a.M11 <= b.M11 || a.M12 <= b.M12 || a.M20 <= b.M20 || a.M21 <= b.M21 || a.M22 <= b.M22; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M33i m, int s) { return m.M00 <= s || m.M01 <= s || m.M02 <= s || m.M10 <= s || m.M11 <= s || m.M12 <= s || m.M20 <= s || m.M21 <= s || m.M22 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(int s, M33i m) { return s <= m.M00 || s <= m.M01 || s <= m.M02 || s <= m.M10 || s <= m.M11 || s <= m.M12 || s <= m.M20 || s <= m.M21 || s <= m.M22; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M33i a, M33i b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M02 >= b.M02 && a.M10 >= b.M10 && a.M11 >= b.M11 && a.M12 >= b.M12 && a.M20 >= b.M20 && a.M21 >= b.M21 && a.M22 >= b.M22; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M33i m, int s) { return m.M00 >= s && m.M01 >= s && m.M02 >= s && m.M10 >= s && m.M11 >= s && m.M12 >= s && m.M20 >= s && m.M21 >= s && m.M22 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(int s, M33i m) { return s >= m.M00 && s >= m.M01 && s >= m.M02 && s >= m.M10 && s >= m.M11 && s >= m.M12 && s >= m.M20 && s >= m.M21 && s >= m.M22; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M33i a, M33i b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M02 >= b.M02 || a.M10 >= b.M10 || a.M11 >= b.M11 || a.M12 >= b.M12 || a.M20 >= b.M20 || a.M21 >= b.M21 || a.M22 >= b.M22; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M33i m, int s) { return m.M00 >= s || m.M01 >= s || m.M02 >= s || m.M10 >= s || m.M11 >= s || m.M12 >= s || m.M20 >= s || m.M21 >= s || m.M22 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(int s, M33i m) { return s >= m.M00 || s >= m.M01 || s >= m.M02 || s >= m.M10 || s >= m.M11 || s >= m.M12 || s >= m.M20 || s >= m.M21 || s >= m.M22; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M33i a, M33i b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M33i m, int s) { return m.M00 == s && m.M01 == s && m.M02 == s && m.M10 == s && m.M11 == s && m.M12 == s && m.M20 == s && m.M21 == s && m.M22 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(int s, M33i m) { return s == m.M00 && s == m.M01 && s == m.M02 && s == m.M10 && s == m.M11 && s == m.M12 && s == m.M20 && s == m.M21 && s == m.M22; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M33i a, M33i b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M02 == b.M02 || a.M10 == b.M10 || a.M11 == b.M11 || a.M12 == b.M12 || a.M20 == b.M20 || a.M21 == b.M21 || a.M22 == b.M22; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M33i m, int s) { return m.M00 == s || m.M01 == s || m.M02 == s || m.M10 == s || m.M11 == s || m.M12 == s || m.M20 == s || m.M21 == s || m.M22 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(int s, M33i m) { return s == m.M00 || s == m.M01 || s == m.M02 || s == m.M10 || s == m.M11 || s == m.M12 || s == m.M20 || s == m.M21 || s == m.M22; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M33i a, M33i b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M02 != b.M02 && a.M10 != b.M10 && a.M11 != b.M11 && a.M12 != b.M12 && a.M20 != b.M20 && a.M21 != b.M21 && a.M22 != b.M22; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M33i m, int s) { return m.M00 != s && m.M01 != s && m.M02 != s && m.M10 != s && m.M11 != s && m.M12 != s && m.M20 != s && m.M21 != s && m.M22 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(int s, M33i m) { return s != m.M00 && s != m.M01 && s != m.M02 && s != m.M10 && s != m.M11 && s != m.M12 && s != m.M20 && s != m.M21 && s != m.M22; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M33i a, M33i b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M02 != b.M02 || a.M10 != b.M10 || a.M11 != b.M11 || a.M12 != b.M12 || a.M20 != b.M20 || a.M21 != b.M21 || a.M22 != b.M22; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M33i m, int s) { return m.M00 != s || m.M01 != s || m.M02 != s || m.M10 != s || m.M11 != s || m.M12 != s || m.M20 != s || m.M21 != s || m.M22 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(int s, M33i m) { return s != m.M00 || s != m.M01 || s != m.M02 || s != m.M10 || s != m.M11 || s != m.M12 || s != m.M20 || s != m.M21 || s != m.M22; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M33i m0, M33i m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M02 < m1.M02) return -1; if (m0.M02 > m1.M02) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; if (m0.M12 < m1.M12) return -1; if (m0.M12 > m1.M12) return +1; if (m0.M20 < m1.M20) return -1; if (m0.M20 > m1.M20) return +1; if (m0.M21 < m1.M21) return -1; if (m0.M21 > m1.M21) return +1; if (m0.M22 < m1.M22) return -1; if (m0.M22 > m1.M22) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MinElement(M33i m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MaxElement(M33i m) => m.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M33i m, int epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M02.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon) || m.M12.IsTiny(epsilon) || m.M20.IsTiny(epsilon) || m.M21.IsTiny(epsilon) || m.M22.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M33i m, int epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M02.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon) && m.M12.IsTiny(epsilon) && m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon) && m.M22.IsTiny(epsilon); #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M33i a, M33i b, int epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M33i m, int epsilon) => Mat.AllTiny(m, epsilon); #endregion } public static class IRandomUniformM33iExtensions { #region IRandomUniform extensions for M33i /// /// Uses UniformInt() to generate the elements of an M33i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i UniformM33i(this IRandomUniform rnd) { return new M33i( rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt()); } /// /// Uses UniformIntNonZero() to generate the elements of an M33i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i UniformM33iNonZero(this IRandomUniform rnd) { return new M33i( rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero()); } /// /// Uses UniformInt(int) to generate the elements of an M33i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i UniformM33i(this IRandomUniform rnd, int size) { return new M33i( rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size)); } /// /// Uses UniformInt(int) to generate the elements of an M33i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i UniformM33i(this IRandomUniform rnd, M33i size) { return new M33i( rnd.UniformInt(size.M00), rnd.UniformInt(size.M01), rnd.UniformInt(size.M02), rnd.UniformInt(size.M10), rnd.UniformInt(size.M11), rnd.UniformInt(size.M12), rnd.UniformInt(size.M20), rnd.UniformInt(size.M21), rnd.UniformInt(size.M22)); } #endregion } #endregion #region M33l [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M33l : IEquatable, IValidity, IMatrix { [DataMember] public long M00, M01, M02; [DataMember] public long M10, M11, M12; [DataMember] public long M20, M21, M22; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(long value) { M00 = value; M01 = 0; M02 = 0; M10 = 0; M11 = value; M12 = 0; M20 = 0; M21 = 0; M22 = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l( long m00, long m01, long m02, long m10, long m11, long m12, long m20, long m21, long m22) { M00 = m00; M01 = m01; M02 = m02; M10 = m10; M11 = m11; M12 = m12; M20 = m20; M21 = m21; M22 = m22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(long[] a) { M00 = a[0]; M01 = a[1]; M02 = a[2]; M10 = a[3]; M11 = a[4]; M12 = a[5]; M20 = a[6]; M21 = a[7]; M22 = a[8]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(long[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M02 = a[start + 2]; M10 = a[start + 3]; M11 = a[start + 4]; M12 = a[start + 5]; M20 = a[start + 6]; M21 = a[start + 7]; M22 = a[start + 8]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M22i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = 0; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M23i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M33i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M34i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M44i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M22l m) { M00 = m.M00; M01 = m.M01; M02 = 0; M10 = m.M10; M11 = m.M11; M12 = 0; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M23l m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M34l m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; M20 = m.M20; M21 = m.M21; M22 = m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M44l m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; M20 = m.M20; M21 = m.M21; M22 = m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M22f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = 0; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M23f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M33f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M34f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M44f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M22d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = 0; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M23d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M33d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M34d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33l(M44d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; } #endregion #region Conversions public static explicit operator M33l(M22i m) { return new M33l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = 0, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33l(M23i m) { return new M33l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33l(M33i m) { return new M33l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, }; } public static explicit operator M33l(M34i m) { return new M33l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, }; } public static explicit operator M33l(M44i m) { return new M33l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, }; } public static explicit operator M33l(M22l m) { return new M33l { M00 = m.M00, M01 = m.M01, M02 = 0, M10 = m.M10, M11 = m.M11, M12 = 0, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33l(M23l m) { return new M33l { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33l(M34l m) { return new M33l { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, M20 = m.M20, M21 = m.M21, M22 = m.M22, }; } public static explicit operator M33l(M44l m) { return new M33l { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, M20 = m.M20, M21 = m.M21, M22 = m.M22, }; } public static explicit operator M33l(M22f m) { return new M33l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = 0, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33l(M23f m) { return new M33l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33l(M33f m) { return new M33l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, }; } public static explicit operator M33l(M34f m) { return new M33l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, }; } public static explicit operator M33l(M44f m) { return new M33l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, }; } public static explicit operator M33l(M22d m) { return new M33l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = 0, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33l(M23d m) { return new M33l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33l(M33d m) { return new M33l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, }; } public static explicit operator M33l(M34d m) { return new M33l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, }; } public static explicit operator M33l(M44d m) { return new M33l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, }; } public static explicit operator M33l(int[] a) { return new M33l( (long)a[0], (long)a[1], (long)a[2], (long)a[3], (long)a[4], (long)a[5], (long)a[6], (long)a[7], (long)a[8]); } public static explicit operator M33l(int[,] a) { return new M33l( (long)a[0, 0], (long)a[0, 1], (long)a[0, 2], (long)a[1, 0], (long)a[1, 1], (long)a[1, 2], (long)a[2, 0], (long)a[2, 1], (long)a[2, 2]); } public static explicit operator int[](M33l m) { return new int[] { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M10, (int)m.M11, (int)m.M12, (int)m.M20, (int)m.M21, (int)m.M22 }; } public static explicit operator int[,](M33l m) { return new int[,] { { (int)m.M00, (int)m.M01, (int)m.M02 }, { (int)m.M10, (int)m.M11, (int)m.M12 }, { (int)m.M20, (int)m.M21, (int)m.M22 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = (int)M00; array[index + 1] = (int)M01; array[index + 2] = (int)M02; array[index + 3] = (int)M10; array[index + 4] = (int)M11; array[index + 5] = (int)M12; array[index + 6] = (int)M20; array[index + 7] = (int)M21; array[index + 8] = (int)M22; } public static explicit operator M33l(long[] a) { return new M33l( a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); } public static explicit operator M33l(long[,] a) { return new M33l( a[0, 0], a[0, 1], a[0, 2], a[1, 0], a[1, 1], a[1, 2], a[2, 0], a[2, 1], a[2, 2]); } public static explicit operator long[](M33l m) { return new long[] { m.M00, m.M01, m.M02, m.M10, m.M11, m.M12, m.M20, m.M21, m.M22 }; } public static explicit operator long[,](M33l m) { return new long[,] { { m.M00, m.M01, m.M02 }, { m.M10, m.M11, m.M12 }, { m.M20, m.M21, m.M22 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M02; array[index + 3] = M10; array[index + 4] = M11; array[index + 5] = M12; array[index + 6] = M20; array[index + 7] = M21; array[index + 8] = M22; } public static explicit operator M33l(float[] a) { return new M33l( (long)a[0], (long)a[1], (long)a[2], (long)a[3], (long)a[4], (long)a[5], (long)a[6], (long)a[7], (long)a[8]); } public static explicit operator M33l(float[,] a) { return new M33l( (long)a[0, 0], (long)a[0, 1], (long)a[0, 2], (long)a[1, 0], (long)a[1, 1], (long)a[1, 2], (long)a[2, 0], (long)a[2, 1], (long)a[2, 2]); } public static explicit operator float[](M33l m) { return new float[] { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M10, (float)m.M11, (float)m.M12, (float)m.M20, (float)m.M21, (float)m.M22 }; } public static explicit operator float[,](M33l m) { return new float[,] { { (float)m.M00, (float)m.M01, (float)m.M02 }, { (float)m.M10, (float)m.M11, (float)m.M12 }, { (float)m.M20, (float)m.M21, (float)m.M22 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = (float)M00; array[index + 1] = (float)M01; array[index + 2] = (float)M02; array[index + 3] = (float)M10; array[index + 4] = (float)M11; array[index + 5] = (float)M12; array[index + 6] = (float)M20; array[index + 7] = (float)M21; array[index + 8] = (float)M22; } public static explicit operator M33l(double[] a) { return new M33l( (long)a[0], (long)a[1], (long)a[2], (long)a[3], (long)a[4], (long)a[5], (long)a[6], (long)a[7], (long)a[8]); } public static explicit operator M33l(double[,] a) { return new M33l( (long)a[0, 0], (long)a[0, 1], (long)a[0, 2], (long)a[1, 0], (long)a[1, 1], (long)a[1, 2], (long)a[2, 0], (long)a[2, 1], (long)a[2, 2]); } public static explicit operator double[](M33l m) { return new double[] { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M10, (double)m.M11, (double)m.M12, (double)m.M20, (double)m.M21, (double)m.M22 }; } public static explicit operator double[,](M33l m) { return new double[,] { { (double)m.M00, (double)m.M01, (double)m.M02 }, { (double)m.M10, (double)m.M11, (double)m.M12 }, { (double)m.M20, (double)m.M21, (double)m.M22 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = (double)M00; array[index + 1] = (double)M01; array[index + 2] = (double)M02; array[index + 3] = (double)M10; array[index + 4] = (double)M11; array[index + 5] = (double)M12; array[index + 6] = (double)M20; array[index + 7] = (double)M21; array[index + 8] = (double)M22; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33i Copy(Func element_fun) { return new M33i( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M20), element_fun(M21), element_fun(M22)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33i Copy(Func element_index0_index1_fun) { return new M33i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33l Copy(Func element_fun) { return new M33l( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M20), element_fun(M21), element_fun(M22)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33l Copy(Func element_index0_index1_fun) { return new M33l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33f Copy(Func element_fun) { return new M33f( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M20), element_fun(M21), element_fun(M22)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33f Copy(Func element_index0_index1_fun) { return new M33f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33d Copy(Func element_fun) { return new M33d( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M20), element_fun(M21), element_fun(M22)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33d Copy(Func element_index0_index1_fun) { return new M33d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2)); } /// /// Returns a copy of the upper left sub matrix. /// public readonly M22l UpperLeftM22() { return (M22l)this; } public readonly long[] ToArray() { var array = new long[9]; array[0] = M00; array[1] = M01; array[2] = M02; array[3] = M10; array[4] = M11; array[5] = M12; array[6] = M20; array[7] = M21; array[8] = M22; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l FromCols(V3l col0, V3l col1, V3l col2) { return new M33l( col0.X, col1.X, col2.X, col0.Y, col1.Y, col2.Y, col0.Z, col1.Z, col2.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l FromRows(V3l row0, V3l row1, V3l row2) { return new M33l( row0.X, row0.Y, row0.Z, row1.X, row1.Y, row1.Z, row2.X, row2.Y, row2.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l FromDiagonal(long value) { return new M33l( value, 0, 0, 0, value, 0, 0, 0, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l FromDiagonal(long m00, long m11, long m22) { return new M33l( m00, 0, 0, 0, m11, 0, 0, 0, m22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l FromDiagonal(V3l s) { return new M33l( s.X, 0, 0, 0, s.Y, 0, 0, 0, s.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l FromAntiDiagonal(long value) { return new M33l( 0, 0, value, 0, value, 0, value, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l FromAntiDiagonal(long m02, long m11, long m20) { return new M33l( 0, 0, m02, 0, m11, 0, m20, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l FromAntiDiagonal(V3l s) { return new M33l( 0, 0, s.X, 0, s.Y, 0, s.Z, 0, 0); } #region Scale /// /// Creates a transformation using 3 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l Scale(long sX, long sY, long sZ) => FromDiagonal(sX, sY, sZ); /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l Scale(V3l s) => FromDiagonal(s); /// /// Creates a homogenous transformation using a uniform scale. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l Scale(long s) { return new M33l( s, 0, 0, 0, s, 0, 0, 0, 1); } /// /// Creates a transformation using 2 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l Scale(long sX, long sY) { return new M33l( sX, 0, 0, 0, sY, 0, 0, 0, 1); } /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l Scale(V2l s) { return new M33l( s.X, 0, 0, 0, s.Y, 0, 0, 0, 1); } #endregion #region Translation /// /// Creates a transformation with the translational component given by 2 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l Translation(long tX, long tY) { return new M33l( 1, 0, tX, 0, 1, tY, 0, 0, 1); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l Translation(V2l t) { return new M33l( 1, 0, t.X, 0, 1, t.Y, 0, 0, 1); } #endregion #region Shearing /// /// Creates a shear transformation matrix along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l ShearXY(long factorX, long factorY) { return new M33l( 1, 0, factorX, 0, 1, factorY, 0, 0, 1); } /// /// Creates a shear transformation matrix along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l ShearXZ(long factorX, long factorZ) { return new M33l( 1, factorX, 0, 0, 1, 0, 0, factorZ, 1); } /// /// Creates a shear transformation matrix along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l ShearYZ(long factorY, long factorZ) { return new M33l( 1, 0, 0, factorY, 1, 0, factorZ, 0, 1); } #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l DivideByInt(M33l m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M02; yield return M10; yield return M11; yield return M12; yield return M20; yield return M21; yield return M22; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; yield return R2; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; yield return C2; } } [XmlIgnore] public V3l R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3l( M00, M01, M02); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; M02 = value.Z; } } [XmlIgnore] public V3l R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3l( M10, M11, M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; M12 = value.Z; } } [XmlIgnore] public V3l R2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3l( M20, M21, M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M20 = value.X; M21 = value.Y; M22 = value.Z; } } [XmlIgnore] public V3l C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3l( M00, M10, M20); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; M20 = value.Z; } } [XmlIgnore] public V3l C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3l( M01, M11, M21); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; M21 = value.Z; } } [XmlIgnore] public V3l C2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3l( M02, M12, M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M02 = value.X; M12 = value.Y; M22 = value.Z; } } public readonly V3l Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V3l(M00, M11, M22); } public readonly V3l AntiDiagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V3l(M02, M11, M20); } /// /// Returns the minimum element of the matrix. /// public readonly long MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M02, M10, M11, M12, M20, M21, M22); } /// /// Returns the maximum element of the matrix. /// public readonly long MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M02, M10, M11, M12, M20, M21, M22); } public unsafe long this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (long* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (long* ptr = &M00) { ptr[index] = value; } } } public unsafe long this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (long* ptr = &M00) { return ptr[row * 3 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (long* ptr = &M00) { ptr[row * 3 + column] = value; } } } #endregion #region Constants public const int RowCount = 3; public const int ColumnCount = 3; public const int ElementCount = 3 * 3; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(3, 3); } public static M33l Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M33l(0); } public static M33l Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M33l(1, 0, 0, 0, 1, 0, 0, 0, 1); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly long Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M02) + Fun.Abs(M10) + Fun.Abs(M11) + Fun.Abs(M12) + Fun.Abs(M20) + Fun.Abs(M21) + Fun.Abs(M22); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly double Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M02 * M02 + M10 * M10 + M11 * M11 + M12 * M12 + M20 * M20 + M21 * M21 + M22 * M22); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly long NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12)), Fun.Max( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly long NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12)), Fun.Min( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator -(M33l m) { return new M33l( -m.M00, -m.M01, -m.M02, -m.M10, -m.M11, -m.M12, -m.M20, -m.M21, -m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator + (M33l a, M33l b) { return new M33l( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator + (M33l m, long s) { return new M33l( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M20 + s, m.M21 + s, m.M22 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator + (long s, M33l m) { return new M33l( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12, s + m.M20, s + m.M21, s + m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator + (M33l a, M33f b) { return new M33f( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator + (M33l m, float s) { return new M33f( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M20 + s, m.M21 + s, m.M22 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator + (float s, M33l m) { return new M33f( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12, s + m.M20, s + m.M21, s + m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator + (M33l a, M33d b) { return new M33d( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator + (M33l m, double s) { return new M33d( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M20 + s, m.M21 + s, m.M22 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator + (double s, M33l m) { return new M33d( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12, s + m.M20, s + m.M21, s + m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator - (M33l a, M33l b) { return new M33l( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator - (M33l m, long s) { return new M33l( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M20 - s, m.M21 - s, m.M22 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator - (long s, M33l m) { return new M33l( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12, s - m.M20, s - m.M21, s - m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator - (M33l a, M33f b) { return new M33f( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator - (M33l m, float s) { return new M33f( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M20 - s, m.M21 - s, m.M22 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator - (float s, M33l m) { return new M33f( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12, s - m.M20, s - m.M21, s - m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator - (M33l a, M33d b) { return new M33d( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator - (M33l m, double s) { return new M33d( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M20 - s, m.M21 - s, m.M22 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator - (double s, M33l m) { return new M33d( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12, s - m.M20, s - m.M21, s - m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator % (M33l a, M33l b) { return new M33l( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator % (M33l m, long s) { return new M33l( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M20 % s, m.M21 % s, m.M22 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator % (long s, M33l m) { return new M33l( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12, s % m.M20, s % m.M21, s % m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator % (M33l a, M33f b) { return new M33f( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator % (M33l m, float s) { return new M33f( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M20 % s, m.M21 % s, m.M22 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator % (float s, M33l m) { return new M33f( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12, s % m.M20, s % m.M21, s % m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator % (M33l a, M33d b) { return new M33d( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator % (M33l m, double s) { return new M33d( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M20 % s, m.M21 % s, m.M22 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator % (double s, M33l m) { return new M33d( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12, s % m.M20, s % m.M21, s % m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator / (M33l a, M33l b) { return new M33l( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator / (M33l m, long s) { return new M33l( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M20 / s, m.M21 / s, m.M22 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator / (long s, M33l m) { return new M33l( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12, s / m.M20, s / m.M21, s / m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator / (M33l a, M33f b) { return new M33f( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator / (M33l m, float s) { return new M33f( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M20 / s, m.M21 / s, m.M22 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator / (float s, M33l m) { return new M33f( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12, s / m.M20, s / m.M21, s / m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator / (M33l a, M33d b) { return new M33d( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator / (M33l m, double s) { return new M33d( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M20 / s, m.M21 / s, m.M22 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator / (double s, M33l m) { return new M33d( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12, s / m.M20, s / m.M21, s / m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator * (M33l m, long s) { return new M33l( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M20 * s, m.M21 * s, m.M22 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator * (long s, M33l m) { return new M33l( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12, s * m.M20, s * m.M21, s * m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator * (M33l m, float s) { return new M33f( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M20 * s, m.M21 * s, m.M22 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator * (float s, M33l m) { return new M33f( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12, s * m.M20, s * m.M21, s * m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator * (M33l m, double s) { return new M33d( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M20 * s, m.M21 * s, m.M22 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator * (double s, M33l m) { return new M33d( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12, s * m.M20, s * m.M21, s * m.M22); } #endregion #region Bitwise Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator ~(M33l m) { return new M33l( ~m.M00, ~m.M01, ~m.M02, ~m.M10, ~m.M11, ~m.M12, ~m.M20, ~m.M21, ~m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator <<(M33l a, int s) { return new M33l( a.M00 << s, a.M01 << s, a.M02 << s, a.M10 << s, a.M11 << s, a.M12 << s, a.M20 << s, a.M21 << s, a.M22 << s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator >>(M33l a, int s) { return new M33l( a.M00 >> s, a.M01 >> s, a.M02 >> s, a.M10 >> s, a.M11 >> s, a.M12 >> s, a.M20 >> s, a.M21 >> s, a.M22 >> s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator &(M33l a, M33l b) { return new M33l( a.M00 & b.M00, a.M01 & b.M01, a.M02 & b.M02, a.M10 & b.M10, a.M11 & b.M11, a.M12 & b.M12, a.M20 & b.M20, a.M21 & b.M21, a.M22 & b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator &(M33l a, long s) { return new M33l( a.M00 & s, a.M01 & s, a.M02 & s, a.M10 & s, a.M11 & s, a.M12 & s, a.M20 & s, a.M21 & s, a.M22 & s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator &(long s, M33l a) { return new M33l( s & a.M00, s & a.M01, s & a.M02, s & a.M10, s & a.M11, s & a.M12, s & a.M20, s & a.M21, s & a.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator |(M33l a, M33l b) { return new M33l( a.M00 | b.M00, a.M01 | b.M01, a.M02 | b.M02, a.M10 | b.M10, a.M11 | b.M11, a.M12 | b.M12, a.M20 | b.M20, a.M21 | b.M21, a.M22 | b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator |(M33l a, long s) { return new M33l( a.M00 | s, a.M01 | s, a.M02 | s, a.M10 | s, a.M11 | s, a.M12 | s, a.M20 | s, a.M21 | s, a.M22 | s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator |(long s, M33l a) { return new M33l( s | a.M00, s | a.M01, s | a.M02, s | a.M10, s | a.M11, s | a.M12, s | a.M20, s | a.M21, s | a.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator ^(M33l a, M33l b) { return new M33l( a.M00 ^ b.M00, a.M01 ^ b.M01, a.M02 ^ b.M02, a.M10 ^ b.M10, a.M11 ^ b.M11, a.M12 ^ b.M12, a.M20 ^ b.M20, a.M21 ^ b.M21, a.M22 ^ b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator ^(M33l a, long s) { return new M33l( a.M00 ^ s, a.M01 ^ s, a.M02 ^ s, a.M10 ^ s, a.M11 ^ s, a.M12 ^ s, a.M20 ^ s, a.M21 ^ s, a.M22 ^ s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l operator ^(long s, M33l a) { return new M33l( s ^ a.M00, s ^ a.M01, s ^ a.M02, s ^ a.M10, s ^ a.M11, s ^ a.M12, s ^ a.M20, s ^ a.M21, s ^ a.M22); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M33l matrix with a V3l column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator *(M33l m, V3l v) { return new V3l( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z); } /// /// Multiplies a V3l row vector with a M33l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator *(V3l v, M33l m) { return new V3l( v.X * m.M00 + v.Y * m.M10 + v.Z * m.M20, v.X * m.M01 + v.Y * m.M11 + v.Z * m.M21, v.X * m.M02 + v.Y * m.M12 + v.Z * m.M22); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M33l a, M33l b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M33l a, long s) { return a.M00 == s && a.M01 == s && a.M02 == s && a.M10 == s && a.M11 == s && a.M12 == s && a.M20 == s && a.M21 == s && a.M22 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(long s, M33l a) { return s == a.M00 && s == a.M01 && s == a.M02 && s == a.M10 && s == a.M11 && s == a.M12 && s == a.M20 && s == a.M21 && s == a.M22 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M33l a, M33l b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M33l m, long s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(long s, M33l m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01, M02), HashCode.GetCombined(M10, M11, M12), HashCode.GetCombined(M20, M21, M22)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M33l other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M02.Equals(other.M02) && M10.Equals(other.M10) && M11.Equals(other.M11) && M12.Equals(other.M12) && M20.Equals(other.M20) && M21.Equals(other.M21) && M22.Equals(other.M22); } public override readonly bool Equals(object other) => (other is M33l o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + betweenM + R2.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M33l Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M33l.FromRows( V3l.Parse(x[0]), V3l.Parse(x[1]), V3l.Parse(x[2]) ); } #endregion #region Matrix Operations /// /// Returns adjoint of this matrix. /// public readonly M33l Adjoint { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { M33l result = new M33l(); for (int row = 0; row < 3; row++) { for (int col = 0; col < 3; col++) { if (((col + row) % 2) == 0) result[col, row] = this.Minor(row, col).Determinant; else result[col, row] = -this.Minor(row, col).Determinant; } } return result; } } /// /// Returns the trace of this matrix. /// The trace is defined as the sum of the diagonal elements, /// and is only defined for square matrices. /// public readonly long Trace { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return M00 + M11 + M22 ; } } /// /// Gets the determinant of this matrix. /// The determinant is only defined for square matrices. /// public readonly long Determinant { get { if (M10 == 0 && M20 == 0 && M21 == 0) { return M00 * M11 * M22; } return M00 * M11 * M22 - M00 * M12 * M21 + M01 * M12 * M20 - M01 * M10 * M22 + M02 * M10 * M21 - M02 * M11 * M20; } } /// /// Returns whether this matrix is invertible. /// A matrix is invertible if its determinant is not zero. /// public readonly bool Invertible { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant != 0; } } /// /// Returns whether this matrix is singular. /// A matrix is singular if its determinant is zero. /// public readonly bool Singular { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant == 0; } } /// /// Gets transpose of this matrix. /// public readonly M33l Transposed { get { return new M33l { M00 = M00, M01 = M10, M02 = M20, M10 = M01, M11 = M11, M12 = M21, M20 = M02, M21 = M12, M22 = M22 }; } } #endregion #region Matrix Multiplication public static M33l operator *(M33l a, M33l b) { return new M33l( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return (double)this[(int)y, (int)x]; } set { this[(int)y, (int)x] = (long)value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return (double)this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = (long)value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (long)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (long)value; } #endregion } public class M33lEqualityComparer : IEqualityComparer { public static readonly M33lEqualityComparer Default = new M33lEqualityComparer(); #region IEqualityComparer Members public bool Equals(M33l v0, M33l v1) { return v0 == v1; } public int GetHashCode(M33l v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this M33l m) => (m.C0.Length + m.C1.Length + m.C2.Length) / 3; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetScaleVector(this M33l m) => new V3d(m.C0.Length, m.C1.Length, m.C2.Length); /// /// Approximates the uniform scale value of the given transformation matrix (average length of 2D basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale2(this M33l m) => (m.C0.XY.Length + m.C1.XY.Length) / 2; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the 2D basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetScaleVector2(this M33l m) => new V2d(m.C0.XY.Length, m.C1.XY.Length); #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Norm1(M33l m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(M33l m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NormMax(M33l m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NormMin(M33l m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this M33l m, double p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M02).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) + Fun.Abs(m.M12).Pow(p) + Fun.Abs(m.M20).Pow(p) + Fun.Abs(m.M21).Pow(p) + Fun.Abs(m.M22).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static long Distance1(this M33l a, M33l b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M02 - a.M02) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11) + Fun.Abs(b.M12 - a.M12) + Fun.Abs(b.M20 - a.M20) + Fun.Abs(b.M21 - a.M21) + Fun.Abs(b.M22 - a.M22); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static double Distance2(this M33l a, M33l b) { return Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M02 - a.M02) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11) + Fun.Square(b.M12 - a.M12) + Fun.Square(b.M20 - a.M20) + Fun.Square(b.M21 - a.M21) + Fun.Square(b.M22 - a.M22)); } /// /// Returns the p-distance between two matrices. /// public static double Distance(this M33l a, M33l b, double p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M02 - a.M02).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) + Fun.Abs(b.M12 - a.M12).Pow(p) + Fun.Abs(b.M20 - a.M20).Pow(p) + Fun.Abs(b.M21 - a.M21).Pow(p) + Fun.Abs(b.M22 - a.M22).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static long DistanceMax(this M33l a, M33l b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12)), Fun.Max( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static long DistanceMin(this M33l a, M33l b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12)), Fun.Min( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Transform(this M33l m, V3l v) => m * v; /// /// Transforms vector v by matrix m. /// v.W is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Transform(this M33l m, V4l v) { return new V4l( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z, v.W); } /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l TransposedTransform(this M33l m, V3l v) => v * m; /// /// Transforms vector v by the transpose of matrix m. /// v.W is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l TransposedTransform(this M33l m, V4l v) { return new V4l( v.X * m.M00 + v.Y * m.M10 + v.Z * m.M20, v.X * m.M01 + v.Y * m.M11 + v.Z * m.M21, v.X * m.M02 + v.Y * m.M12 + v.Z * m.M22, v.W); } /// /// Transforms direction vector v (v.Z is presumed 0.0) by matrix m. /// public static V2l TransformDir(this M33l m, V2l v) { return new V2l( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y ); } /// /// Transforms point p (v.Z is presumed 1.0) by matrix m. /// No projective transform is performed. /// public static V2l TransformPos(this M33l m, V2l p) { return new V2l( m.M00 * p.X + m.M01 * p.Y + m.M02, m.M10 * p.X + m.M11 * p.Y + m.M12 ); } /// /// Transforms point p (p.Z is presumed 1.0) by matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static V2l TransformPosProj(this M33l m, V2l p) { long s = m.M20 * p.X + m.M21 * p.Y + m.M22; return TransformPos(m, p) * (1 / s); } /// /// Transforms point p (p.Z is presumed 1.0) by matrix m. /// Projective transform is performed. /// public static V3l TransformPosProjFull(this M33l m, V2l p) { return new V3l( m.M00 * p.X + m.M01 * p.Y + m.M02, m.M10 * p.X + m.M11 * p.Y + m.M12, m.M20 * p.X + m.M21 * p.Y + m.M22 ); } /// /// Transforms direction vector v (v.Z is presumed 0.0) by transposed version of matrix m. /// public static V2l TransposedTransformDir(this M33l m, V2l v) { return new V2l( m.M00 * v.X + m.M10 * v.Y, m.M01 * v.X + m.M11 * v.Y ); } /// /// Transforms point p (v.Z is presumed 1.0) by transposed version of matrix m. /// No projective transform is performed. /// public static V2l TransposedTransformPos(this M33l m, V2l p) { return new V2l( m.M00 * p.X + m.M10 * p.Y + m.M20, m.M01 * p.X + m.M11 * p.Y + m.M21 ); } /// /// Transforms point p (v.Z is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static V2l TransposedTransformPosProj(this M33l m, V2l p) { var s = m.M02 * p.X + m.M12 * p.Y + m.M22; return TransposedTransformPos(m, p) * (1 / s); } [Obsolete("Use TransposedTransformPosProj instead.")] public static V2l TransposedTransformProj(this M33l m, V2l p) => m.TransposedTransformPosProj(p); /// /// Transforms point p (v.Z is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. /// public static V3l TransposedTransformPosProjFull(this M33l m, V2l p) { return new V3l( m.M00 * p.X + m.M10 * p.Y + m.M20, m.M01 * p.X + m.M11 * p.Y + m.M21, m.M02 * p.X + m.M12 * p.Y + m.M22 ); } [Obsolete("Use TransposedTransformPosProjFull instead.")] public static V3l TransposedTransformProjFull(this M33l m, V2l p) => m.TransposedTransformPosProjFull(p); #endregion #region Operations /// /// Returns the given to a deleting the /// specified row and column. /// public static M22l Minor(this M33l m, int row, int column) { M22l rs = new M22l(); for (int k = 0; k < 4; k++) { var i = k / 2; var j = k % 2; var ii = (i < row) ? i : i + 1; var jj = (j < column) ? j : j + 1; rs[k] = m[ii * 3 + jj]; } return rs; } /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V3l Row(this M33l m, int index) { long* ptr = &m.M00; return new V3l(ptr[index * 3], ptr[index * 3 + 1], ptr[index * 3 + 2]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V3l Column(this M33l m, int index) { long* ptr = &m.M00; return new V3l(ptr[index], ptr[index + 3], ptr[index + 6]); } /// /// Returns the determinant of the given matrix. /// The determinant is only defined for square matrices. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Determinant(M33l m) => m.Determinant; /// /// Returns the transpose of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l Transposed(M33l m) => m.Transposed; /// /// Transposes the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transpose(this ref M33l m) { Fun.Swap(ref m.M10, ref m.M01); Fun.Swap(ref m.M20, ref m.M02); Fun.Swap(ref m.M21, ref m.M12); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M33l a, M33l b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M02 < b.M02 && a.M10 < b.M10 && a.M11 < b.M11 && a.M12 < b.M12 && a.M20 < b.M20 && a.M21 < b.M21 && a.M22 < b.M22; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M33l m, long s) { return m.M00 < s && m.M01 < s && m.M02 < s && m.M10 < s && m.M11 < s && m.M12 < s && m.M20 < s && m.M21 < s && m.M22 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(long s, M33l m) { return s < m.M00 && s < m.M01 && s < m.M02 && s < m.M10 && s < m.M11 && s < m.M12 && s < m.M20 && s < m.M21 && s < m.M22; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M33l a, M33l b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M02 < b.M02 || a.M10 < b.M10 || a.M11 < b.M11 || a.M12 < b.M12 || a.M20 < b.M20 || a.M21 < b.M21 || a.M22 < b.M22; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M33l m, long s) { return m.M00 < s || m.M01 < s || m.M02 < s || m.M10 < s || m.M11 < s || m.M12 < s || m.M20 < s || m.M21 < s || m.M22 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(long s, M33l m) { return s < m.M00 || s < m.M01 || s < m.M02 || s < m.M10 || s < m.M11 || s < m.M12 || s < m.M20 || s < m.M21 || s < m.M22; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M33l a, M33l b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M02 > b.M02 && a.M10 > b.M10 && a.M11 > b.M11 && a.M12 > b.M12 && a.M20 > b.M20 && a.M21 > b.M21 && a.M22 > b.M22; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M33l m, long s) { return m.M00 > s && m.M01 > s && m.M02 > s && m.M10 > s && m.M11 > s && m.M12 > s && m.M20 > s && m.M21 > s && m.M22 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(long s, M33l m) { return s > m.M00 && s > m.M01 && s > m.M02 && s > m.M10 && s > m.M11 && s > m.M12 && s > m.M20 && s > m.M21 && s > m.M22; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M33l a, M33l b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M02 > b.M02 || a.M10 > b.M10 || a.M11 > b.M11 || a.M12 > b.M12 || a.M20 > b.M20 || a.M21 > b.M21 || a.M22 > b.M22; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M33l m, long s) { return m.M00 > s || m.M01 > s || m.M02 > s || m.M10 > s || m.M11 > s || m.M12 > s || m.M20 > s || m.M21 > s || m.M22 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(long s, M33l m) { return s > m.M00 || s > m.M01 || s > m.M02 || s > m.M10 || s > m.M11 || s > m.M12 || s > m.M20 || s > m.M21 || s > m.M22; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M33l a, M33l b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M02 <= b.M02 && a.M10 <= b.M10 && a.M11 <= b.M11 && a.M12 <= b.M12 && a.M20 <= b.M20 && a.M21 <= b.M21 && a.M22 <= b.M22; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M33l m, long s) { return m.M00 <= s && m.M01 <= s && m.M02 <= s && m.M10 <= s && m.M11 <= s && m.M12 <= s && m.M20 <= s && m.M21 <= s && m.M22 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(long s, M33l m) { return s <= m.M00 && s <= m.M01 && s <= m.M02 && s <= m.M10 && s <= m.M11 && s <= m.M12 && s <= m.M20 && s <= m.M21 && s <= m.M22; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M33l a, M33l b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M02 <= b.M02 || a.M10 <= b.M10 || a.M11 <= b.M11 || a.M12 <= b.M12 || a.M20 <= b.M20 || a.M21 <= b.M21 || a.M22 <= b.M22; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M33l m, long s) { return m.M00 <= s || m.M01 <= s || m.M02 <= s || m.M10 <= s || m.M11 <= s || m.M12 <= s || m.M20 <= s || m.M21 <= s || m.M22 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(long s, M33l m) { return s <= m.M00 || s <= m.M01 || s <= m.M02 || s <= m.M10 || s <= m.M11 || s <= m.M12 || s <= m.M20 || s <= m.M21 || s <= m.M22; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M33l a, M33l b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M02 >= b.M02 && a.M10 >= b.M10 && a.M11 >= b.M11 && a.M12 >= b.M12 && a.M20 >= b.M20 && a.M21 >= b.M21 && a.M22 >= b.M22; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M33l m, long s) { return m.M00 >= s && m.M01 >= s && m.M02 >= s && m.M10 >= s && m.M11 >= s && m.M12 >= s && m.M20 >= s && m.M21 >= s && m.M22 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(long s, M33l m) { return s >= m.M00 && s >= m.M01 && s >= m.M02 && s >= m.M10 && s >= m.M11 && s >= m.M12 && s >= m.M20 && s >= m.M21 && s >= m.M22; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M33l a, M33l b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M02 >= b.M02 || a.M10 >= b.M10 || a.M11 >= b.M11 || a.M12 >= b.M12 || a.M20 >= b.M20 || a.M21 >= b.M21 || a.M22 >= b.M22; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M33l m, long s) { return m.M00 >= s || m.M01 >= s || m.M02 >= s || m.M10 >= s || m.M11 >= s || m.M12 >= s || m.M20 >= s || m.M21 >= s || m.M22 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(long s, M33l m) { return s >= m.M00 || s >= m.M01 || s >= m.M02 || s >= m.M10 || s >= m.M11 || s >= m.M12 || s >= m.M20 || s >= m.M21 || s >= m.M22; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M33l a, M33l b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M33l m, long s) { return m.M00 == s && m.M01 == s && m.M02 == s && m.M10 == s && m.M11 == s && m.M12 == s && m.M20 == s && m.M21 == s && m.M22 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(long s, M33l m) { return s == m.M00 && s == m.M01 && s == m.M02 && s == m.M10 && s == m.M11 && s == m.M12 && s == m.M20 && s == m.M21 && s == m.M22; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M33l a, M33l b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M02 == b.M02 || a.M10 == b.M10 || a.M11 == b.M11 || a.M12 == b.M12 || a.M20 == b.M20 || a.M21 == b.M21 || a.M22 == b.M22; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M33l m, long s) { return m.M00 == s || m.M01 == s || m.M02 == s || m.M10 == s || m.M11 == s || m.M12 == s || m.M20 == s || m.M21 == s || m.M22 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(long s, M33l m) { return s == m.M00 || s == m.M01 || s == m.M02 || s == m.M10 || s == m.M11 || s == m.M12 || s == m.M20 || s == m.M21 || s == m.M22; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M33l a, M33l b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M02 != b.M02 && a.M10 != b.M10 && a.M11 != b.M11 && a.M12 != b.M12 && a.M20 != b.M20 && a.M21 != b.M21 && a.M22 != b.M22; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M33l m, long s) { return m.M00 != s && m.M01 != s && m.M02 != s && m.M10 != s && m.M11 != s && m.M12 != s && m.M20 != s && m.M21 != s && m.M22 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(long s, M33l m) { return s != m.M00 && s != m.M01 && s != m.M02 && s != m.M10 && s != m.M11 && s != m.M12 && s != m.M20 && s != m.M21 && s != m.M22; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M33l a, M33l b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M02 != b.M02 || a.M10 != b.M10 || a.M11 != b.M11 || a.M12 != b.M12 || a.M20 != b.M20 || a.M21 != b.M21 || a.M22 != b.M22; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M33l m, long s) { return m.M00 != s || m.M01 != s || m.M02 != s || m.M10 != s || m.M11 != s || m.M12 != s || m.M20 != s || m.M21 != s || m.M22 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(long s, M33l m) { return s != m.M00 || s != m.M01 || s != m.M02 || s != m.M10 || s != m.M11 || s != m.M12 || s != m.M20 || s != m.M21 || s != m.M22; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M33l m0, M33l m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M02 < m1.M02) return -1; if (m0.M02 > m1.M02) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; if (m0.M12 < m1.M12) return -1; if (m0.M12 > m1.M12) return +1; if (m0.M20 < m1.M20) return -1; if (m0.M20 > m1.M20) return +1; if (m0.M21 < m1.M21) return -1; if (m0.M21 > m1.M21) return +1; if (m0.M22 < m1.M22) return -1; if (m0.M22 > m1.M22) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MinElement(M33l m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MaxElement(M33l m) => m.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M33l m, long epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M02.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon) || m.M12.IsTiny(epsilon) || m.M20.IsTiny(epsilon) || m.M21.IsTiny(epsilon) || m.M22.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M33l m, long epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M02.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon) && m.M12.IsTiny(epsilon) && m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon) && m.M22.IsTiny(epsilon); #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M33l a, M33l b, long epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M33l m, long epsilon) => Mat.AllTiny(m, epsilon); #endregion } public static class IRandomUniformM33lExtensions { #region IRandomUniform extensions for M33l /// /// Uses UniformLong() to generate the elements of an M33l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l UniformM33l(this IRandomUniform rnd) { return new M33l( rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong()); } /// /// Uses UniformLongNonZero() to generate the elements of an M33l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l UniformM33lNonZero(this IRandomUniform rnd) { return new M33l( rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero()); } /// /// Uses UniformLong(long) to generate the elements of an M33l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l UniformM33l(this IRandomUniform rnd, long size) { return new M33l( rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size)); } /// /// Uses UniformLong(long) to generate the elements of an M33l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l UniformM33l(this IRandomUniform rnd, M33l size) { return new M33l( rnd.UniformLong(size.M00), rnd.UniformLong(size.M01), rnd.UniformLong(size.M02), rnd.UniformLong(size.M10), rnd.UniformLong(size.M11), rnd.UniformLong(size.M12), rnd.UniformLong(size.M20), rnd.UniformLong(size.M21), rnd.UniformLong(size.M22)); } #endregion } #endregion #region M33f [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M33f : IEquatable, IValidity, IMatrix { [DataMember] public float M00, M01, M02; [DataMember] public float M10, M11, M12; [DataMember] public float M20, M21, M22; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(float value) { M00 = value; M01 = 0; M02 = 0; M10 = 0; M11 = value; M12 = 0; M20 = 0; M21 = 0; M22 = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f( float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22) { M00 = m00; M01 = m01; M02 = m02; M10 = m10; M11 = m11; M12 = m12; M20 = m20; M21 = m21; M22 = m22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(float[] a) { M00 = a[0]; M01 = a[1]; M02 = a[2]; M10 = a[3]; M11 = a[4]; M12 = a[5]; M20 = a[6]; M21 = a[7]; M22 = a[8]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(float[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M02 = a[start + 2]; M10 = a[start + 3]; M11 = a[start + 4]; M12 = a[start + 5]; M20 = a[start + 6]; M21 = a[start + 7]; M22 = a[start + 8]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M22i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = 0; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M23i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M33i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M34i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M44i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M22l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = 0; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M23l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M33l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M34l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M44l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M22f m) { M00 = m.M00; M01 = m.M01; M02 = 0; M10 = m.M10; M11 = m.M11; M12 = 0; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M23f m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M34f m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; M20 = m.M20; M21 = m.M21; M22 = m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M44f m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; M20 = m.M20; M21 = m.M21; M22 = m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M22d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = 0; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M23d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M33d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M34d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33f(M44d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; } #endregion #region Conversions public static explicit operator M33f(M22i m) { return new M33f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = 0, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33f(M23i m) { return new M33f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33f(M33i m) { return new M33f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, }; } public static explicit operator M33f(M34i m) { return new M33f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, }; } public static explicit operator M33f(M44i m) { return new M33f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, }; } public static explicit operator M33f(M22l m) { return new M33f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = 0, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33f(M23l m) { return new M33f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33f(M33l m) { return new M33f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, }; } public static explicit operator M33f(M34l m) { return new M33f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, }; } public static explicit operator M33f(M44l m) { return new M33f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, }; } public static explicit operator M33f(M22f m) { return new M33f { M00 = m.M00, M01 = m.M01, M02 = 0, M10 = m.M10, M11 = m.M11, M12 = 0, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33f(M23f m) { return new M33f { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33f(M34f m) { return new M33f { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, M20 = m.M20, M21 = m.M21, M22 = m.M22, }; } public static explicit operator M33f(M44f m) { return new M33f { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, M20 = m.M20, M21 = m.M21, M22 = m.M22, }; } public static explicit operator M33f(M22d m) { return new M33f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = 0, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33f(M23d m) { return new M33f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33f(M33d m) { return new M33f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, }; } public static explicit operator M33f(M34d m) { return new M33f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, }; } public static explicit operator M33f(M44d m) { return new M33f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, }; } public static explicit operator M33f(int[] a) { return new M33f( (float)a[0], (float)a[1], (float)a[2], (float)a[3], (float)a[4], (float)a[5], (float)a[6], (float)a[7], (float)a[8]); } public static explicit operator M33f(int[,] a) { return new M33f( (float)a[0, 0], (float)a[0, 1], (float)a[0, 2], (float)a[1, 0], (float)a[1, 1], (float)a[1, 2], (float)a[2, 0], (float)a[2, 1], (float)a[2, 2]); } public static explicit operator int[](M33f m) { return new int[] { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M10, (int)m.M11, (int)m.M12, (int)m.M20, (int)m.M21, (int)m.M22 }; } public static explicit operator int[,](M33f m) { return new int[,] { { (int)m.M00, (int)m.M01, (int)m.M02 }, { (int)m.M10, (int)m.M11, (int)m.M12 }, { (int)m.M20, (int)m.M21, (int)m.M22 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = (int)M00; array[index + 1] = (int)M01; array[index + 2] = (int)M02; array[index + 3] = (int)M10; array[index + 4] = (int)M11; array[index + 5] = (int)M12; array[index + 6] = (int)M20; array[index + 7] = (int)M21; array[index + 8] = (int)M22; } public static explicit operator M33f(long[] a) { return new M33f( (float)a[0], (float)a[1], (float)a[2], (float)a[3], (float)a[4], (float)a[5], (float)a[6], (float)a[7], (float)a[8]); } public static explicit operator M33f(long[,] a) { return new M33f( (float)a[0, 0], (float)a[0, 1], (float)a[0, 2], (float)a[1, 0], (float)a[1, 1], (float)a[1, 2], (float)a[2, 0], (float)a[2, 1], (float)a[2, 2]); } public static explicit operator long[](M33f m) { return new long[] { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M10, (long)m.M11, (long)m.M12, (long)m.M20, (long)m.M21, (long)m.M22 }; } public static explicit operator long[,](M33f m) { return new long[,] { { (long)m.M00, (long)m.M01, (long)m.M02 }, { (long)m.M10, (long)m.M11, (long)m.M12 }, { (long)m.M20, (long)m.M21, (long)m.M22 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = (long)M00; array[index + 1] = (long)M01; array[index + 2] = (long)M02; array[index + 3] = (long)M10; array[index + 4] = (long)M11; array[index + 5] = (long)M12; array[index + 6] = (long)M20; array[index + 7] = (long)M21; array[index + 8] = (long)M22; } public static explicit operator M33f(float[] a) { return new M33f( a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); } public static explicit operator M33f(float[,] a) { return new M33f( a[0, 0], a[0, 1], a[0, 2], a[1, 0], a[1, 1], a[1, 2], a[2, 0], a[2, 1], a[2, 2]); } public static explicit operator float[](M33f m) { return new float[] { m.M00, m.M01, m.M02, m.M10, m.M11, m.M12, m.M20, m.M21, m.M22 }; } public static explicit operator float[,](M33f m) { return new float[,] { { m.M00, m.M01, m.M02 }, { m.M10, m.M11, m.M12 }, { m.M20, m.M21, m.M22 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M02; array[index + 3] = M10; array[index + 4] = M11; array[index + 5] = M12; array[index + 6] = M20; array[index + 7] = M21; array[index + 8] = M22; } public static explicit operator M33f(double[] a) { return new M33f( (float)a[0], (float)a[1], (float)a[2], (float)a[3], (float)a[4], (float)a[5], (float)a[6], (float)a[7], (float)a[8]); } public static explicit operator M33f(double[,] a) { return new M33f( (float)a[0, 0], (float)a[0, 1], (float)a[0, 2], (float)a[1, 0], (float)a[1, 1], (float)a[1, 2], (float)a[2, 0], (float)a[2, 1], (float)a[2, 2]); } public static explicit operator double[](M33f m) { return new double[] { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M10, (double)m.M11, (double)m.M12, (double)m.M20, (double)m.M21, (double)m.M22 }; } public static explicit operator double[,](M33f m) { return new double[,] { { (double)m.M00, (double)m.M01, (double)m.M02 }, { (double)m.M10, (double)m.M11, (double)m.M12 }, { (double)m.M20, (double)m.M21, (double)m.M22 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = (double)M00; array[index + 1] = (double)M01; array[index + 2] = (double)M02; array[index + 3] = (double)M10; array[index + 4] = (double)M11; array[index + 5] = (double)M12; array[index + 6] = (double)M20; array[index + 7] = (double)M21; array[index + 8] = (double)M22; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33i Copy(Func element_fun) { return new M33i( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M20), element_fun(M21), element_fun(M22)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33i Copy(Func element_index0_index1_fun) { return new M33i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33l Copy(Func element_fun) { return new M33l( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M20), element_fun(M21), element_fun(M22)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33l Copy(Func element_index0_index1_fun) { return new M33l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33f Copy(Func element_fun) { return new M33f( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M20), element_fun(M21), element_fun(M22)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33f Copy(Func element_index0_index1_fun) { return new M33f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33d Copy(Func element_fun) { return new M33d( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M20), element_fun(M21), element_fun(M22)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33d Copy(Func element_index0_index1_fun) { return new M33d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2)); } /// /// Returns a copy of the upper left sub matrix. /// public readonly M22f UpperLeftM22() { return (M22f)this; } public readonly float[] ToArray() { var array = new float[9]; array[0] = M00; array[1] = M01; array[2] = M02; array[3] = M10; array[4] = M11; array[5] = M12; array[6] = M20; array[7] = M21; array[8] = M22; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f FromCols(V3f col0, V3f col1, V3f col2) { return new M33f( col0.X, col1.X, col2.X, col0.Y, col1.Y, col2.Y, col0.Z, col1.Z, col2.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f FromRows(V3f row0, V3f row1, V3f row2) { return new M33f( row0.X, row0.Y, row0.Z, row1.X, row1.Y, row1.Z, row2.X, row2.Y, row2.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f FromDiagonal(float value) { return new M33f( value, 0, 0, 0, value, 0, 0, 0, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f FromDiagonal(float m00, float m11, float m22) { return new M33f( m00, 0, 0, 0, m11, 0, 0, 0, m22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f FromDiagonal(V3f s) { return new M33f( s.X, 0, 0, 0, s.Y, 0, 0, 0, s.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f FromAntiDiagonal(float value) { return new M33f( 0, 0, value, 0, value, 0, value, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f FromAntiDiagonal(float m02, float m11, float m20) { return new M33f( 0, 0, m02, 0, m11, 0, m20, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f FromAntiDiagonal(V3f s) { return new M33f( 0, 0, s.X, 0, s.Y, 0, s.Z, 0, 0); } #region Scale /// /// Creates a transformation using 3 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Scale(float sX, float sY, float sZ) => FromDiagonal(sX, sY, sZ); /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Scale(V3f s) => FromDiagonal(s); /// /// Creates a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Scale(Scale3f s) { return new M33f( s.X, 0, 0, 0, s.Y, 0, 0, 0, s.Z); } /// /// Creates a homogenous transformation using a uniform scale. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Scale(float s) { return new M33f( s, 0, 0, 0, s, 0, 0, 0, 1); } /// /// Creates a transformation using 2 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Scale(float sX, float sY) { return new M33f( sX, 0, 0, 0, sY, 0, 0, 0, 1); } /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Scale(V2f s) { return new M33f( s.X, 0, 0, 0, s.Y, 0, 0, 0, 1); } /// /// Creates a scaling transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Scale(Scale2f s) { return new M33f( s.X, 0, 0, 0, s.Y, 0, 0, 0, 1); } #endregion #region Translation /// /// Creates a transformation with the translational component given by 2 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Translation(float tX, float tY) { return new M33f( 1, 0, tX, 0, 1, tY, 0, 0, 1); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Translation(V2f t) { return new M33f( 1, 0, t.X, 0, 1, t.Y, 0, 0, 1); } /// /// Creates a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Translation(Shift2f s) { return new M33f( 1, 0, s.X, 0, 1, s.Y, 0, 0, 1); } #endregion #region Rotation /// /// Creates a 2D rotation matrix with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Rotation(float angleInRadians) { var a = Fun.Cos(angleInRadians); var b = Fun.Sin(angleInRadians); return new M33f( a, -b, 0, b, a, 0, 0, 0, 1); } /// /// Creates a 2D rotation matrix with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f RotationInDegrees(float angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix from a /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Rotation(Rot3f r) => (M33f)r; /// /// Creates a 2D rotation matrix from a /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Rotation(Rot2f r) => (M33f)r; /// /// Creates a 3D rotation matrix from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Rotation(V3f normalizedAxis, float angleInRadians) { Debug.Assert(normalizedAxis.LengthSquared.ApproximateEquals(1, 1e-5f)); return (M33f)(Rot3f.Rotation(normalizedAxis, angleInRadians)); } /// /// Creates a 3D rotation matrix from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f RotationInDegrees(V3f normalizedAxis, float angleInDegrees) => Rotation(normalizedAxis, angleInDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f RotationEuler(float rollInRadians, float pitchInRadians, float yawInRadians) { return (M33f)(Rot3f.RotationEuler(rollInRadians, pitchInRadians, yawInRadians)); } /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f RotationEulerInDegrees(float rollInDegrees, float pitchInDegrees, float yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f RotationEuler(V3f rollPitchYawInRadians) => RotationEuler( rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f RotationEulerInDegrees(V3f rollPitchYawInDegrees) => RotationEulerInDegrees( rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a 3D rotation matrix which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f RotateInto(V3f from, V3f into) { Debug.Assert(from.LengthSquared.ApproximateEquals(1, 1e-5f)); Debug.Assert(into.LengthSquared.ApproximateEquals(1, 1e-5f)); return (M33f)(Rot3f.RotateInto(from, into)); } /// /// Creates a 3D rotation matrix for radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f RotationX(float angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M33f( 1, 0, 0, 0, a, -b, 0, b, a); } /// /// Creates a 3D rotation matrix for degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f RotationXInDegrees(float angleDegrees) => RotationX(angleDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix for radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f RotationY(float angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M33f( a, 0, b, 0, 1, 0, -b, 0, a); } /// /// Creates a 3D rotation matrix for degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f RotationYInDegrees(float angleDegrees) => RotationY(angleDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix for radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f RotationZ(float angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M33f( a, -b, 0, b, a, 0, 0, 0, 1); } /// /// Creates a 3D rotation matrix for degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f RotationZInDegrees(float angleDegrees) => RotationZ(angleDegrees.RadiansFromDegrees()); #endregion #region Shearing /// /// Creates a shear transformation matrix along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f ShearXY(float factorX, float factorY) { return new M33f( 1, 0, factorX, 0, 1, factorY, 0, 0, 1); } /// /// Creates a shear transformation matrix along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f ShearXZ(float factorX, float factorZ) { return new M33f( 1, factorX, 0, 0, 1, 0, 0, factorZ, 1); } /// /// Creates a shear transformation matrix along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f ShearYZ(float factorY, float factorZ) { return new M33f( 1, 0, 0, factorY, 1, 0, factorZ, 0, 1); } #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f DivideByInt(M33f m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M02; yield return M10; yield return M11; yield return M12; yield return M20; yield return M21; yield return M22; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; yield return R2; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; yield return C2; } } [XmlIgnore] public V3f R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3f( M00, M01, M02); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; M02 = value.Z; } } [XmlIgnore] public V3f R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3f( M10, M11, M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; M12 = value.Z; } } [XmlIgnore] public V3f R2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3f( M20, M21, M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M20 = value.X; M21 = value.Y; M22 = value.Z; } } [XmlIgnore] public V3f C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3f( M00, M10, M20); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; M20 = value.Z; } } [XmlIgnore] public V3f C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3f( M01, M11, M21); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; M21 = value.Z; } } [XmlIgnore] public V3f C2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3f( M02, M12, M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M02 = value.X; M12 = value.Y; M22 = value.Z; } } public readonly V3f Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V3f(M00, M11, M22); } public readonly V3f AntiDiagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V3f(M02, M11, M20); } /// /// Returns the minimum element of the matrix. /// public readonly float MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M02, M10, M11, M12, M20, M21, M22); } /// /// Returns the maximum element of the matrix. /// public readonly float MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M02, M10, M11, M12, M20, M21, M22); } public unsafe float this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &M00) { ptr[index] = value; } } } public unsafe float this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &M00) { return ptr[row * 3 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &M00) { ptr[row * 3 + column] = value; } } } public readonly bool AnyFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) || Fun.IsFinite(M01) || Fun.IsFinite(M02) || Fun.IsFinite(M10) || Fun.IsFinite(M11) || Fun.IsFinite(M12) || Fun.IsFinite(M20) || Fun.IsFinite(M21) || Fun.IsFinite(M22); } } public readonly bool AllFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) && Fun.IsFinite(M01) && Fun.IsFinite(M02) && Fun.IsFinite(M10) && Fun.IsFinite(M11) && Fun.IsFinite(M12) && Fun.IsFinite(M20) && Fun.IsFinite(M21) && Fun.IsFinite(M22); } } public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNaN(M00) || float.IsNaN(M01) || float.IsNaN(M02) || float.IsNaN(M10) || float.IsNaN(M11) || float.IsNaN(M12) || float.IsNaN(M20) || float.IsNaN(M21) || float.IsNaN(M22); } } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNaN(M00) && float.IsNaN(M01) && float.IsNaN(M02) && float.IsNaN(M10) && float.IsNaN(M11) && float.IsNaN(M12) && float.IsNaN(M20) && float.IsNaN(M21) && float.IsNaN(M22); } } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsInfinity(M00) || float.IsInfinity(M01) || float.IsInfinity(M02) || float.IsInfinity(M10) || float.IsInfinity(M11) || float.IsInfinity(M12) || float.IsInfinity(M20) || float.IsInfinity(M21) || float.IsInfinity(M22); } } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsInfinity(M00) && float.IsInfinity(M01) && float.IsInfinity(M02) && float.IsInfinity(M10) && float.IsInfinity(M11) && float.IsInfinity(M12) && float.IsInfinity(M20) && float.IsInfinity(M21) && float.IsInfinity(M22); } } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsPositiveInfinity(M00) || float.IsPositiveInfinity(M01) || float.IsPositiveInfinity(M02) || float.IsPositiveInfinity(M10) || float.IsPositiveInfinity(M11) || float.IsPositiveInfinity(M12) || float.IsPositiveInfinity(M20) || float.IsPositiveInfinity(M21) || float.IsPositiveInfinity(M22); } } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsPositiveInfinity(M00) && float.IsPositiveInfinity(M01) && float.IsPositiveInfinity(M02) && float.IsPositiveInfinity(M10) && float.IsPositiveInfinity(M11) && float.IsPositiveInfinity(M12) && float.IsPositiveInfinity(M20) && float.IsPositiveInfinity(M21) && float.IsPositiveInfinity(M22); } } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNegativeInfinity(M00) || float.IsNegativeInfinity(M01) || float.IsNegativeInfinity(M02) || float.IsNegativeInfinity(M10) || float.IsNegativeInfinity(M11) || float.IsNegativeInfinity(M12) || float.IsNegativeInfinity(M20) || float.IsNegativeInfinity(M21) || float.IsNegativeInfinity(M22); } } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNegativeInfinity(M00) && float.IsNegativeInfinity(M01) && float.IsNegativeInfinity(M02) && float.IsNegativeInfinity(M10) && float.IsNegativeInfinity(M11) && float.IsNegativeInfinity(M12) && float.IsNegativeInfinity(M20) && float.IsNegativeInfinity(M21) && float.IsNegativeInfinity(M22); } } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) || Fun.IsTiny(M01) || Fun.IsTiny(M02) || Fun.IsTiny(M10) || Fun.IsTiny(M11) || Fun.IsTiny(M12) || Fun.IsTiny(M20) || Fun.IsTiny(M21) || Fun.IsTiny(M22); } } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) && Fun.IsTiny(M01) && Fun.IsTiny(M02) && Fun.IsTiny(M10) && Fun.IsTiny(M11) && Fun.IsTiny(M12) && Fun.IsTiny(M20) && Fun.IsTiny(M21) && Fun.IsTiny(M22); } } /// /// Returns true if the absolute value of each element of the matrix is smaller than Constant<float>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any element of the matrix is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any element of the matrix is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any element of the matrix is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any element of the matrix is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all elements of the matrix are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Constants public const int RowCount = 3; public const int ColumnCount = 3; public const int ElementCount = 3 * 3; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(3, 3); } public static M33f Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M33f(0); } public static M33f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M33f(1, 0, 0, 0, 1, 0, 0, 0, 1); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly float Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M02) + Fun.Abs(M10) + Fun.Abs(M11) + Fun.Abs(M12) + Fun.Abs(M20) + Fun.Abs(M21) + Fun.Abs(M22); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly float Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M02 * M02 + M10 * M10 + M11 * M11 + M12 * M12 + M20 * M20 + M21 * M21 + M22 * M22); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly float NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12)), Fun.Max( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly float NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12)), Fun.Min( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator -(M33f m) { return new M33f( -m.M00, -m.M01, -m.M02, -m.M10, -m.M11, -m.M12, -m.M20, -m.M21, -m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator + (M33f a, M33f b) { return new M33f( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator + (M33f m, float s) { return new M33f( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M20 + s, m.M21 + s, m.M22 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator + (float s, M33f m) { return new M33f( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12, s + m.M20, s + m.M21, s + m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator + (M33f a, M33d b) { return new M33d( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator + (M33f m, double s) { return new M33d( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M20 + s, m.M21 + s, m.M22 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator + (double s, M33f m) { return new M33d( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12, s + m.M20, s + m.M21, s + m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator - (M33f a, M33f b) { return new M33f( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator - (M33f m, float s) { return new M33f( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M20 - s, m.M21 - s, m.M22 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator - (float s, M33f m) { return new M33f( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12, s - m.M20, s - m.M21, s - m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator - (M33f a, M33d b) { return new M33d( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator - (M33f m, double s) { return new M33d( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M20 - s, m.M21 - s, m.M22 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator - (double s, M33f m) { return new M33d( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12, s - m.M20, s - m.M21, s - m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator % (M33f a, M33f b) { return new M33f( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator % (M33f m, float s) { return new M33f( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M20 % s, m.M21 % s, m.M22 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator % (float s, M33f m) { return new M33f( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12, s % m.M20, s % m.M21, s % m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator % (M33f a, M33d b) { return new M33d( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator % (M33f m, double s) { return new M33d( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M20 % s, m.M21 % s, m.M22 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator % (double s, M33f m) { return new M33d( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12, s % m.M20, s % m.M21, s % m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator / (M33f a, M33f b) { return new M33f( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator / (M33f m, float s) { return new M33f( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M20 / s, m.M21 / s, m.M22 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator / (float s, M33f m) { return new M33f( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12, s / m.M20, s / m.M21, s / m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator / (M33f a, M33d b) { return new M33d( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator / (M33f m, double s) { return new M33d( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M20 / s, m.M21 / s, m.M22 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator / (double s, M33f m) { return new M33d( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12, s / m.M20, s / m.M21, s / m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator * (M33f m, float s) { return new M33f( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M20 * s, m.M21 * s, m.M22 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator * (float s, M33f m) { return new M33f( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12, s * m.M20, s * m.M21, s * m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator * (M33f m, double s) { return new M33d( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M20 * s, m.M21 * s, m.M22 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator * (double s, M33f m) { return new M33d( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12, s * m.M20, s * m.M21, s * m.M22); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M33f matrix with a V3f column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator *(M33f m, V3f v) { return new V3f( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z); } /// /// Multiplies a V3f row vector with a M33f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator *(V3f v, M33f m) { return new V3f( v.X * m.M00 + v.Y * m.M10 + v.Z * m.M20, v.X * m.M01 + v.Y * m.M11 + v.Z * m.M21, v.X * m.M02 + v.Y * m.M12 + v.Z * m.M22); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M33f a, M33f b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M33f a, float s) { return a.M00 == s && a.M01 == s && a.M02 == s && a.M10 == s && a.M11 == s && a.M12 == s && a.M20 == s && a.M21 == s && a.M22 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(float s, M33f a) { return s == a.M00 && s == a.M01 && s == a.M02 && s == a.M10 && s == a.M11 && s == a.M12 && s == a.M20 && s == a.M21 && s == a.M22 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M33f a, M33f b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M33f m, float s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(float s, M33f m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01, M02), HashCode.GetCombined(M10, M11, M12), HashCode.GetCombined(M20, M21, M22)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M33f other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M02.Equals(other.M02) && M10.Equals(other.M10) && M11.Equals(other.M11) && M12.Equals(other.M12) && M20.Equals(other.M20) && M21.Equals(other.M21) && M22.Equals(other.M22); } public override readonly bool Equals(object other) => (other is M33f o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + betweenM + R2.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M33f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M33f.FromRows( V3f.Parse(x[0]), V3f.Parse(x[1]), V3f.Parse(x[2]) ); } #endregion #region Matrix Operations /// /// Returns adjoint of this matrix. /// public readonly M33f Adjoint { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { M33f result = new M33f(); for (int row = 0; row < 3; row++) { for (int col = 0; col < 3; col++) { if (((col + row) % 2) == 0) result[col, row] = this.Minor(row, col).Determinant; else result[col, row] = -this.Minor(row, col).Determinant; } } return result; } } /// /// Returns the trace of this matrix. /// The trace is defined as the sum of the diagonal elements, /// and is only defined for square matrices. /// public readonly float Trace { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return M00 + M11 + M22 ; } } /// /// Gets the determinant of this matrix. /// The determinant is only defined for square matrices. /// public readonly float Determinant { get { if (M10 == 0 && M20 == 0 && M21 == 0) { return M00 * M11 * M22; } return M00 * M11 * M22 - M00 * M12 * M21 + M01 * M12 * M20 - M01 * M10 * M22 + M02 * M10 * M21 - M02 * M11 * M20; } } /// /// Returns whether this matrix is invertible. /// A matrix is invertible if its determinant is not zero. /// public readonly bool Invertible { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant != 0; } } /// /// Returns whether this matrix is singular. /// A matrix is singular if its determinant is zero. /// public readonly bool Singular { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant == 0; } } /// /// Gets transpose of this matrix. /// public readonly M33f Transposed { get { return new M33f { M00 = M00, M01 = M10, M02 = M20, M10 = M01, M11 = M11, M12 = M21, M20 = M02, M21 = M12, M22 = M22 }; } } private static V2l s_luSize = new V2l(3, 3); private static V2l s_luDelta = new V2l(1, 3); /// /// Inverts the given matrix using lu factorization in place. Returns true /// if the matrix was invertible, otherwise the matrix remains unchanged. /// public bool LuInvert() { M33d dbl = (M33d)this; if(dbl.LuInvert()) { this = (M33f)dbl; return true; } return false; } /// /// Returns the inverse of the matrix using lu factorization. /// If the matrix is not invertible, M33f.Zero is returned. /// public readonly M33f LuInverse() { return (M33f)((M33d)this).LuInverse(); } /// /// Returns the inverse of this matrix. If the matrix is not invertible /// M33f.Zero is returned. /// public readonly M33f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => LuInverse(); } #endregion #region Matrix Multiplication public static M33f operator *(M33f a, M33f b) { return new M33f( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return (double)this[(int)y, (int)x]; } set { this[(int)y, (int)x] = (float)value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return (double)this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = (float)value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (float)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (float)value; } #endregion } public class M33fEqualityComparer : IEqualityComparer { public static readonly M33fEqualityComparer Default = new M33fEqualityComparer(); #region IEqualityComparer Members public bool Equals(M33f v0, M33f v1) { return v0 == v1; } public int GetHashCode(M33f v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetScale(this M33f m) => (m.C0.Length + m.C1.Length + m.C2.Length) / 3; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetScaleVector(this M33f m) => new V3f(m.C0.Length, m.C1.Length, m.C2.Length); /// /// Approximates the uniform scale value of the given transformation matrix (average length of 2D basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetScale2(this M33f m) => (m.C0.XY.Length + m.C1.XY.Length) / 2; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the 2D basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetScaleVector2(this M33f m) => new V2f(m.C0.XY.Length, m.C1.XY.Length); #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm1(M33f m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm2(M33f m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormMax(M33f m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormMin(M33f m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm(this M33f m, float p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M02).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) + Fun.Abs(m.M12).Pow(p) + Fun.Abs(m.M20).Pow(p) + Fun.Abs(m.M21).Pow(p) + Fun.Abs(m.M22).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static float Distance1(this M33f a, M33f b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M02 - a.M02) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11) + Fun.Abs(b.M12 - a.M12) + Fun.Abs(b.M20 - a.M20) + Fun.Abs(b.M21 - a.M21) + Fun.Abs(b.M22 - a.M22); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static float Distance2(this M33f a, M33f b) { return (float)Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M02 - a.M02) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11) + Fun.Square(b.M12 - a.M12) + Fun.Square(b.M20 - a.M20) + Fun.Square(b.M21 - a.M21) + Fun.Square(b.M22 - a.M22)); } /// /// Returns the p-distance between two matrices. /// public static float Distance(this M33f a, M33f b, float p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M02 - a.M02).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) + Fun.Abs(b.M12 - a.M12).Pow(p) + Fun.Abs(b.M20 - a.M20).Pow(p) + Fun.Abs(b.M21 - a.M21).Pow(p) + Fun.Abs(b.M22 - a.M22).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static float DistanceMax(this M33f a, M33f b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12)), Fun.Max( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static float DistanceMin(this M33f a, M33f b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12)), Fun.Min( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Transform(this M33f m, V3f v) => m * v; /// /// Transforms vector v by matrix m. /// v.W is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Transform(this M33f m, V4f v) { return new V4f( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z, v.W); } /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransposedTransform(this M33f m, V3f v) => v * m; /// /// Transforms vector v by the transpose of matrix m. /// v.W is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f TransposedTransform(this M33f m, V4f v) { return new V4f( v.X * m.M00 + v.Y * m.M10 + v.Z * m.M20, v.X * m.M01 + v.Y * m.M11 + v.Z * m.M21, v.X * m.M02 + v.Y * m.M12 + v.Z * m.M22, v.W); } /// /// Transforms direction vector v (v.Z is presumed 0.0) by matrix m. /// public static V2f TransformDir(this M33f m, V2f v) { return new V2f( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y ); } /// /// Transforms point p (v.Z is presumed 1.0) by matrix m. /// No projective transform is performed. /// public static V2f TransformPos(this M33f m, V2f p) { return new V2f( m.M00 * p.X + m.M01 * p.Y + m.M02, m.M10 * p.X + m.M11 * p.Y + m.M12 ); } /// /// Transforms point p (p.Z is presumed 1.0) by matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static V2f TransformPosProj(this M33f m, V2f p) { float s = m.M20 * p.X + m.M21 * p.Y + m.M22; return TransformPos(m, p) * (1 / s); } /// /// Transforms point p (p.Z is presumed 1.0) by matrix m. /// Projective transform is performed. /// public static V3f TransformPosProjFull(this M33f m, V2f p) { return new V3f( m.M00 * p.X + m.M01 * p.Y + m.M02, m.M10 * p.X + m.M11 * p.Y + m.M12, m.M20 * p.X + m.M21 * p.Y + m.M22 ); } /// /// Transforms direction vector v (v.Z is presumed 0.0) by transposed version of matrix m. /// public static V2f TransposedTransformDir(this M33f m, V2f v) { return new V2f( m.M00 * v.X + m.M10 * v.Y, m.M01 * v.X + m.M11 * v.Y ); } /// /// Transforms point p (v.Z is presumed 1.0) by transposed version of matrix m. /// No projective transform is performed. /// public static V2f TransposedTransformPos(this M33f m, V2f p) { return new V2f( m.M00 * p.X + m.M10 * p.Y + m.M20, m.M01 * p.X + m.M11 * p.Y + m.M21 ); } /// /// Transforms point p (v.Z is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static V2f TransposedTransformPosProj(this M33f m, V2f p) { var s = m.M02 * p.X + m.M12 * p.Y + m.M22; return TransposedTransformPos(m, p) * (1 / s); } [Obsolete("Use TransposedTransformPosProj instead.")] public static V2f TransposedTransformProj(this M33f m, V2f p) => m.TransposedTransformPosProj(p); /// /// Transforms point p (v.Z is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. /// public static V3f TransposedTransformPosProjFull(this M33f m, V2f p) { return new V3f( m.M00 * p.X + m.M10 * p.Y + m.M20, m.M01 * p.X + m.M11 * p.Y + m.M21, m.M02 * p.X + m.M12 * p.Y + m.M22 ); } [Obsolete("Use TransposedTransformPosProjFull instead.")] public static V3f TransposedTransformProjFull(this M33f m, V2f p) => m.TransposedTransformPosProjFull(p); #endregion #region Operations /// /// Returns the given to a deleting the /// specified row and column. /// public static M22f Minor(this M33f m, int row, int column) { M22f rs = new M22f(); for (int k = 0; k < 4; k++) { var i = k / 2; var j = k % 2; var ii = (i < row) ? i : i + 1; var jj = (j < column) ? j : j + 1; rs[k] = m[ii * 3 + jj]; } return rs; } /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V3f Row(this M33f m, int index) { float* ptr = &m.M00; return new V3f(ptr[index * 3], ptr[index * 3 + 1], ptr[index * 3 + 2]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V3f Column(this M33f m, int index) { float* ptr = &m.M00; return new V3f(ptr[index], ptr[index + 3], ptr[index + 6]); } /// /// Returns the determinant of the given matrix. /// The determinant is only defined for square matrices. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Determinant(M33f m) => m.Determinant; /// /// Returns the transpose of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Transposed(M33f m) => m.Transposed; /// /// Transposes the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transpose(this ref M33f m) { Fun.Swap(ref m.M10, ref m.M01); Fun.Swap(ref m.M20, ref m.M02); Fun.Swap(ref m.M21, ref m.M12); } /// /// Returns the inverse of the given matrix. If the matrix is not invertible /// M33f.Zero is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Inverse(M33f m) => m.Inverse; /// /// Inverts the given matrix in place. Returns true if the matrix was invertible, /// otherwise the matrix remains unchanged. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Invert(this ref M33f m) { return m.LuInvert(); } /// /// Returns if the given matrix is the identity matrix I. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIdentity(this M33f m, float epsilon) { return Fun.ApproximateEquals(m, M33f.Identity, epsilon); } /// /// Returns if the given matrix is the identity matrix I. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIdentity(this M33f m) => IsIdentity(m, Constant.PositiveTinyValue); /// /// Returns if the given matrix is orthonormal (i.e. M * M^t == I) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthonormal(this M33f m, float epsilon) { var i = m * m.Transposed; return i.IsIdentity(epsilon); } /// /// Returns if the given matrix is orthonormal (i.e. M * M^t == I) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthonormal(this M33f m) => IsOrthonormal(m, Constant.PositiveTinyValue); /// /// Returns if the given matrix is orthogonal (i.e. all non-diagonal entries of M * M^t == 0) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonal(this M33f m, float epsilon) { var i = m * m.Transposed; for (int j = 0; j < 3; j++) i[j, j] = 1; //inefficient implementation: just leave out the comparisons at the diagonal entries. return i.IsIdentity(epsilon); } /// /// Returns if the given matrix is orthogonal (i.e. all non-diagonal entries of M * M^t == 0) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonal(this M33f m) => IsOrthogonal(m, Constant.PositiveTinyValue); #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M33f a, M33f b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M02 < b.M02 && a.M10 < b.M10 && a.M11 < b.M11 && a.M12 < b.M12 && a.M20 < b.M20 && a.M21 < b.M21 && a.M22 < b.M22; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M33f m, float s) { return m.M00 < s && m.M01 < s && m.M02 < s && m.M10 < s && m.M11 < s && m.M12 < s && m.M20 < s && m.M21 < s && m.M22 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(float s, M33f m) { return s < m.M00 && s < m.M01 && s < m.M02 && s < m.M10 && s < m.M11 && s < m.M12 && s < m.M20 && s < m.M21 && s < m.M22; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M33f a, M33f b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M02 < b.M02 || a.M10 < b.M10 || a.M11 < b.M11 || a.M12 < b.M12 || a.M20 < b.M20 || a.M21 < b.M21 || a.M22 < b.M22; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M33f m, float s) { return m.M00 < s || m.M01 < s || m.M02 < s || m.M10 < s || m.M11 < s || m.M12 < s || m.M20 < s || m.M21 < s || m.M22 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(float s, M33f m) { return s < m.M00 || s < m.M01 || s < m.M02 || s < m.M10 || s < m.M11 || s < m.M12 || s < m.M20 || s < m.M21 || s < m.M22; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M33f a, M33f b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M02 > b.M02 && a.M10 > b.M10 && a.M11 > b.M11 && a.M12 > b.M12 && a.M20 > b.M20 && a.M21 > b.M21 && a.M22 > b.M22; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M33f m, float s) { return m.M00 > s && m.M01 > s && m.M02 > s && m.M10 > s && m.M11 > s && m.M12 > s && m.M20 > s && m.M21 > s && m.M22 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(float s, M33f m) { return s > m.M00 && s > m.M01 && s > m.M02 && s > m.M10 && s > m.M11 && s > m.M12 && s > m.M20 && s > m.M21 && s > m.M22; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M33f a, M33f b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M02 > b.M02 || a.M10 > b.M10 || a.M11 > b.M11 || a.M12 > b.M12 || a.M20 > b.M20 || a.M21 > b.M21 || a.M22 > b.M22; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M33f m, float s) { return m.M00 > s || m.M01 > s || m.M02 > s || m.M10 > s || m.M11 > s || m.M12 > s || m.M20 > s || m.M21 > s || m.M22 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(float s, M33f m) { return s > m.M00 || s > m.M01 || s > m.M02 || s > m.M10 || s > m.M11 || s > m.M12 || s > m.M20 || s > m.M21 || s > m.M22; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M33f a, M33f b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M02 <= b.M02 && a.M10 <= b.M10 && a.M11 <= b.M11 && a.M12 <= b.M12 && a.M20 <= b.M20 && a.M21 <= b.M21 && a.M22 <= b.M22; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M33f m, float s) { return m.M00 <= s && m.M01 <= s && m.M02 <= s && m.M10 <= s && m.M11 <= s && m.M12 <= s && m.M20 <= s && m.M21 <= s && m.M22 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(float s, M33f m) { return s <= m.M00 && s <= m.M01 && s <= m.M02 && s <= m.M10 && s <= m.M11 && s <= m.M12 && s <= m.M20 && s <= m.M21 && s <= m.M22; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M33f a, M33f b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M02 <= b.M02 || a.M10 <= b.M10 || a.M11 <= b.M11 || a.M12 <= b.M12 || a.M20 <= b.M20 || a.M21 <= b.M21 || a.M22 <= b.M22; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M33f m, float s) { return m.M00 <= s || m.M01 <= s || m.M02 <= s || m.M10 <= s || m.M11 <= s || m.M12 <= s || m.M20 <= s || m.M21 <= s || m.M22 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(float s, M33f m) { return s <= m.M00 || s <= m.M01 || s <= m.M02 || s <= m.M10 || s <= m.M11 || s <= m.M12 || s <= m.M20 || s <= m.M21 || s <= m.M22; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M33f a, M33f b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M02 >= b.M02 && a.M10 >= b.M10 && a.M11 >= b.M11 && a.M12 >= b.M12 && a.M20 >= b.M20 && a.M21 >= b.M21 && a.M22 >= b.M22; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M33f m, float s) { return m.M00 >= s && m.M01 >= s && m.M02 >= s && m.M10 >= s && m.M11 >= s && m.M12 >= s && m.M20 >= s && m.M21 >= s && m.M22 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(float s, M33f m) { return s >= m.M00 && s >= m.M01 && s >= m.M02 && s >= m.M10 && s >= m.M11 && s >= m.M12 && s >= m.M20 && s >= m.M21 && s >= m.M22; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M33f a, M33f b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M02 >= b.M02 || a.M10 >= b.M10 || a.M11 >= b.M11 || a.M12 >= b.M12 || a.M20 >= b.M20 || a.M21 >= b.M21 || a.M22 >= b.M22; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M33f m, float s) { return m.M00 >= s || m.M01 >= s || m.M02 >= s || m.M10 >= s || m.M11 >= s || m.M12 >= s || m.M20 >= s || m.M21 >= s || m.M22 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(float s, M33f m) { return s >= m.M00 || s >= m.M01 || s >= m.M02 || s >= m.M10 || s >= m.M11 || s >= m.M12 || s >= m.M20 || s >= m.M21 || s >= m.M22; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M33f a, M33f b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M33f m, float s) { return m.M00 == s && m.M01 == s && m.M02 == s && m.M10 == s && m.M11 == s && m.M12 == s && m.M20 == s && m.M21 == s && m.M22 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(float s, M33f m) { return s == m.M00 && s == m.M01 && s == m.M02 && s == m.M10 && s == m.M11 && s == m.M12 && s == m.M20 && s == m.M21 && s == m.M22; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M33f a, M33f b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M02 == b.M02 || a.M10 == b.M10 || a.M11 == b.M11 || a.M12 == b.M12 || a.M20 == b.M20 || a.M21 == b.M21 || a.M22 == b.M22; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M33f m, float s) { return m.M00 == s || m.M01 == s || m.M02 == s || m.M10 == s || m.M11 == s || m.M12 == s || m.M20 == s || m.M21 == s || m.M22 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(float s, M33f m) { return s == m.M00 || s == m.M01 || s == m.M02 || s == m.M10 || s == m.M11 || s == m.M12 || s == m.M20 || s == m.M21 || s == m.M22; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M33f a, M33f b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M02 != b.M02 && a.M10 != b.M10 && a.M11 != b.M11 && a.M12 != b.M12 && a.M20 != b.M20 && a.M21 != b.M21 && a.M22 != b.M22; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M33f m, float s) { return m.M00 != s && m.M01 != s && m.M02 != s && m.M10 != s && m.M11 != s && m.M12 != s && m.M20 != s && m.M21 != s && m.M22 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(float s, M33f m) { return s != m.M00 && s != m.M01 && s != m.M02 && s != m.M10 && s != m.M11 && s != m.M12 && s != m.M20 && s != m.M21 && s != m.M22; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M33f a, M33f b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M02 != b.M02 || a.M10 != b.M10 || a.M11 != b.M11 || a.M12 != b.M12 || a.M20 != b.M20 || a.M21 != b.M21 || a.M22 != b.M22; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M33f m, float s) { return m.M00 != s || m.M01 != s || m.M02 != s || m.M10 != s || m.M11 != s || m.M12 != s || m.M20 != s || m.M21 != s || m.M22 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(float s, M33f m) { return s != m.M00 || s != m.M01 || s != m.M02 || s != m.M10 || s != m.M11 || s != m.M12 || s != m.M20 || s != m.M21 || s != m.M22; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M33f m0, M33f m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M02 < m1.M02) return -1; if (m0.M02 > m1.M02) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; if (m0.M12 < m1.M12) return -1; if (m0.M12 > m1.M12) return +1; if (m0.M20 < m1.M20) return -1; if (m0.M20 > m1.M20) return +1; if (m0.M21 < m1.M21) return -1; if (m0.M21 > m1.M21) return +1; if (m0.M22 < m1.M22) return -1; if (m0.M22 > m1.M22) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MinElement(M33f m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MaxElement(M33f m) => m.MaxElement; #endregion #region Orthogonalization /// /// Orthogonalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// public static void Orthogonalize(this ref M33f matrix) { matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C0, matrix.C2) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C1, matrix.C2) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C2 -= (Vec.Dot(matrix.C0, matrix.C2) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C1, matrix.C2) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; } /// /// Orthogonalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Orthogonalized(this M33f matrix) { M33f m = matrix; Orthogonalize(ref m); return m; } /// /// Orthonormalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// public static void Orthonormalize(this ref M33f matrix) { matrix.C0 = matrix.C0.Normalized; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 = matrix.C1.Normalized; matrix.C2 -= (Vec.Dot(matrix.C0, matrix.C2) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C1, matrix.C2) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C2 -= (Vec.Dot(matrix.C0, matrix.C2) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C1, matrix.C2) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C2 = matrix.C2.Normalized; } /// /// Orthonormalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Orthonormalized(this M33f matrix) { M33f m = matrix; Orthonormalize(ref m); return m; } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M33f m, float epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M02.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon) || m.M12.IsTiny(epsilon) || m.M20.IsTiny(epsilon) || m.M21.IsTiny(epsilon) || m.M22.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M33f m, float epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M02.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon) && m.M12.IsTiny(epsilon) && m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon) && m.M22.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyFinite(M33f m) => m.AnyFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllFinite(M33f m) => m.AllFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(M33f m) => m.AnyNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(M33f m) => m.AllNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(M33f m) => m.AnyInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(M33f m) => m.AllInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(M33f m) => m.AnyPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(M33f m) => m.AllPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(M33f m) => m.AnyNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(M33f m) => m.AllNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(M33f m) => m.AnyTiny; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(M33f m) => m.AllTiny; #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M33f a, M33f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M33f a, M33f b, float epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M33f m, float epsilon) => Mat.AllTiny(m, epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(M33f m) => m.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any element of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(M33f v) => v.IsNaN; /// /// Returns whether any element of the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(M33f v) => v.IsInfinity; /// /// Returns whether any element of the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(M33f v) => v.IsPositiveInfinity; /// /// Returns whether any element of the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(M33f v) => v.IsNegativeInfinity; /// /// Returns whether all elements of the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(M33f v) => v.IsFinite; #endregion } public static class IRandomUniformM33fExtensions { #region IRandomUniform extensions for M33f /// /// Uses UniformFloat() to generate the elements of an M33f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f UniformM33f(this IRandomUniform rnd) { return new M33f( rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat()); } /// /// Uses UniformFloatClosed() to generate the elements of an M33f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f UniformM33fClosed(this IRandomUniform rnd) { return new M33f( rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed()); } /// /// Uses UniformFloatOpen() to generate the elements of an M33f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f UniformM33fOpen(this IRandomUniform rnd) { return new M33f( rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen()); } #endregion } #endregion #region M33d [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M33d : IEquatable, IValidity, IMatrix { [DataMember] public double M00, M01, M02; [DataMember] public double M10, M11, M12; [DataMember] public double M20, M21, M22; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(double value) { M00 = value; M01 = 0; M02 = 0; M10 = 0; M11 = value; M12 = 0; M20 = 0; M21 = 0; M22 = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d( double m00, double m01, double m02, double m10, double m11, double m12, double m20, double m21, double m22) { M00 = m00; M01 = m01; M02 = m02; M10 = m10; M11 = m11; M12 = m12; M20 = m20; M21 = m21; M22 = m22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(double[] a) { M00 = a[0]; M01 = a[1]; M02 = a[2]; M10 = a[3]; M11 = a[4]; M12 = a[5]; M20 = a[6]; M21 = a[7]; M22 = a[8]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(double[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M02 = a[start + 2]; M10 = a[start + 3]; M11 = a[start + 4]; M12 = a[start + 5]; M20 = a[start + 6]; M21 = a[start + 7]; M22 = a[start + 8]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M22i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = 0; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M23i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M33i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M34i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M44i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M22l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = 0; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M23l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M33l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M34l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M44l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M22f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = 0; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M23f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M33f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M34f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M44f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M22d m) { M00 = m.M00; M01 = m.M01; M02 = 0; M10 = m.M10; M11 = m.M11; M12 = 0; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M23d m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; M20 = 0; M21 = 0; M22 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M34d m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; M20 = m.M20; M21 = m.M21; M22 = m.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M33d(M44d m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M10 = m.M10; M11 = m.M11; M12 = m.M12; M20 = m.M20; M21 = m.M21; M22 = m.M22; } #endregion #region Conversions public static explicit operator M33d(M22i m) { return new M33d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = 0, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33d(M23i m) { return new M33d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33d(M33i m) { return new M33d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, }; } public static explicit operator M33d(M34i m) { return new M33d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, }; } public static explicit operator M33d(M44i m) { return new M33d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, }; } public static explicit operator M33d(M22l m) { return new M33d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = 0, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33d(M23l m) { return new M33d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33d(M33l m) { return new M33d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, }; } public static explicit operator M33d(M34l m) { return new M33d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, }; } public static explicit operator M33d(M44l m) { return new M33d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, }; } public static explicit operator M33d(M22f m) { return new M33d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = 0, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33d(M23f m) { return new M33d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33d(M33f m) { return new M33d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, }; } public static explicit operator M33d(M34f m) { return new M33d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, }; } public static explicit operator M33d(M44f m) { return new M33d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, }; } public static explicit operator M33d(M22d m) { return new M33d { M00 = m.M00, M01 = m.M01, M02 = 0, M10 = m.M10, M11 = m.M11, M12 = 0, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33d(M23d m) { return new M33d { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, M20 = 0, M21 = 0, M22 = 1, }; } public static explicit operator M33d(M34d m) { return new M33d { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, M20 = m.M20, M21 = m.M21, M22 = m.M22, }; } public static explicit operator M33d(M44d m) { return new M33d { M00 = m.M00, M01 = m.M01, M02 = m.M02, M10 = m.M10, M11 = m.M11, M12 = m.M12, M20 = m.M20, M21 = m.M21, M22 = m.M22, }; } public static explicit operator M33d(int[] a) { return new M33d( (double)a[0], (double)a[1], (double)a[2], (double)a[3], (double)a[4], (double)a[5], (double)a[6], (double)a[7], (double)a[8]); } public static explicit operator M33d(int[,] a) { return new M33d( (double)a[0, 0], (double)a[0, 1], (double)a[0, 2], (double)a[1, 0], (double)a[1, 1], (double)a[1, 2], (double)a[2, 0], (double)a[2, 1], (double)a[2, 2]); } public static explicit operator int[](M33d m) { return new int[] { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M10, (int)m.M11, (int)m.M12, (int)m.M20, (int)m.M21, (int)m.M22 }; } public static explicit operator int[,](M33d m) { return new int[,] { { (int)m.M00, (int)m.M01, (int)m.M02 }, { (int)m.M10, (int)m.M11, (int)m.M12 }, { (int)m.M20, (int)m.M21, (int)m.M22 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = (int)M00; array[index + 1] = (int)M01; array[index + 2] = (int)M02; array[index + 3] = (int)M10; array[index + 4] = (int)M11; array[index + 5] = (int)M12; array[index + 6] = (int)M20; array[index + 7] = (int)M21; array[index + 8] = (int)M22; } public static explicit operator M33d(long[] a) { return new M33d( (double)a[0], (double)a[1], (double)a[2], (double)a[3], (double)a[4], (double)a[5], (double)a[6], (double)a[7], (double)a[8]); } public static explicit operator M33d(long[,] a) { return new M33d( (double)a[0, 0], (double)a[0, 1], (double)a[0, 2], (double)a[1, 0], (double)a[1, 1], (double)a[1, 2], (double)a[2, 0], (double)a[2, 1], (double)a[2, 2]); } public static explicit operator long[](M33d m) { return new long[] { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M10, (long)m.M11, (long)m.M12, (long)m.M20, (long)m.M21, (long)m.M22 }; } public static explicit operator long[,](M33d m) { return new long[,] { { (long)m.M00, (long)m.M01, (long)m.M02 }, { (long)m.M10, (long)m.M11, (long)m.M12 }, { (long)m.M20, (long)m.M21, (long)m.M22 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = (long)M00; array[index + 1] = (long)M01; array[index + 2] = (long)M02; array[index + 3] = (long)M10; array[index + 4] = (long)M11; array[index + 5] = (long)M12; array[index + 6] = (long)M20; array[index + 7] = (long)M21; array[index + 8] = (long)M22; } public static explicit operator M33d(float[] a) { return new M33d( (double)a[0], (double)a[1], (double)a[2], (double)a[3], (double)a[4], (double)a[5], (double)a[6], (double)a[7], (double)a[8]); } public static explicit operator M33d(float[,] a) { return new M33d( (double)a[0, 0], (double)a[0, 1], (double)a[0, 2], (double)a[1, 0], (double)a[1, 1], (double)a[1, 2], (double)a[2, 0], (double)a[2, 1], (double)a[2, 2]); } public static explicit operator float[](M33d m) { return new float[] { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M10, (float)m.M11, (float)m.M12, (float)m.M20, (float)m.M21, (float)m.M22 }; } public static explicit operator float[,](M33d m) { return new float[,] { { (float)m.M00, (float)m.M01, (float)m.M02 }, { (float)m.M10, (float)m.M11, (float)m.M12 }, { (float)m.M20, (float)m.M21, (float)m.M22 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = (float)M00; array[index + 1] = (float)M01; array[index + 2] = (float)M02; array[index + 3] = (float)M10; array[index + 4] = (float)M11; array[index + 5] = (float)M12; array[index + 6] = (float)M20; array[index + 7] = (float)M21; array[index + 8] = (float)M22; } public static explicit operator M33d(double[] a) { return new M33d( a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); } public static explicit operator M33d(double[,] a) { return new M33d( a[0, 0], a[0, 1], a[0, 2], a[1, 0], a[1, 1], a[1, 2], a[2, 0], a[2, 1], a[2, 2]); } public static explicit operator double[](M33d m) { return new double[] { m.M00, m.M01, m.M02, m.M10, m.M11, m.M12, m.M20, m.M21, m.M22 }; } public static explicit operator double[,](M33d m) { return new double[,] { { m.M00, m.M01, m.M02 }, { m.M10, m.M11, m.M12 }, { m.M20, m.M21, m.M22 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M02; array[index + 3] = M10; array[index + 4] = M11; array[index + 5] = M12; array[index + 6] = M20; array[index + 7] = M21; array[index + 8] = M22; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33i Copy(Func element_fun) { return new M33i( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M20), element_fun(M21), element_fun(M22)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33i Copy(Func element_index0_index1_fun) { return new M33i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33l Copy(Func element_fun) { return new M33l( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M20), element_fun(M21), element_fun(M22)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33l Copy(Func element_index0_index1_fun) { return new M33l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33f Copy(Func element_fun) { return new M33f( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M20), element_fun(M21), element_fun(M22)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33f Copy(Func element_index0_index1_fun) { return new M33f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33d Copy(Func element_fun) { return new M33d( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M20), element_fun(M21), element_fun(M22)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M33d Copy(Func element_index0_index1_fun) { return new M33d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2)); } /// /// Returns a copy of the upper left sub matrix. /// public readonly M22d UpperLeftM22() { return (M22d)this; } public readonly double[] ToArray() { var array = new double[9]; array[0] = M00; array[1] = M01; array[2] = M02; array[3] = M10; array[4] = M11; array[5] = M12; array[6] = M20; array[7] = M21; array[8] = M22; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d FromCols(V3d col0, V3d col1, V3d col2) { return new M33d( col0.X, col1.X, col2.X, col0.Y, col1.Y, col2.Y, col0.Z, col1.Z, col2.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d FromRows(V3d row0, V3d row1, V3d row2) { return new M33d( row0.X, row0.Y, row0.Z, row1.X, row1.Y, row1.Z, row2.X, row2.Y, row2.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d FromDiagonal(double value) { return new M33d( value, 0, 0, 0, value, 0, 0, 0, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d FromDiagonal(double m00, double m11, double m22) { return new M33d( m00, 0, 0, 0, m11, 0, 0, 0, m22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d FromDiagonal(V3d s) { return new M33d( s.X, 0, 0, 0, s.Y, 0, 0, 0, s.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d FromAntiDiagonal(double value) { return new M33d( 0, 0, value, 0, value, 0, value, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d FromAntiDiagonal(double m02, double m11, double m20) { return new M33d( 0, 0, m02, 0, m11, 0, m20, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d FromAntiDiagonal(V3d s) { return new M33d( 0, 0, s.X, 0, s.Y, 0, s.Z, 0, 0); } #region Scale /// /// Creates a transformation using 3 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Scale(double sX, double sY, double sZ) => FromDiagonal(sX, sY, sZ); /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Scale(V3d s) => FromDiagonal(s); /// /// Creates a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Scale(Scale3d s) { return new M33d( s.X, 0, 0, 0, s.Y, 0, 0, 0, s.Z); } /// /// Creates a homogenous transformation using a uniform scale. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Scale(double s) { return new M33d( s, 0, 0, 0, s, 0, 0, 0, 1); } /// /// Creates a transformation using 2 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Scale(double sX, double sY) { return new M33d( sX, 0, 0, 0, sY, 0, 0, 0, 1); } /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Scale(V2d s) { return new M33d( s.X, 0, 0, 0, s.Y, 0, 0, 0, 1); } /// /// Creates a scaling transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Scale(Scale2d s) { return new M33d( s.X, 0, 0, 0, s.Y, 0, 0, 0, 1); } #endregion #region Translation /// /// Creates a transformation with the translational component given by 2 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Translation(double tX, double tY) { return new M33d( 1, 0, tX, 0, 1, tY, 0, 0, 1); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Translation(V2d t) { return new M33d( 1, 0, t.X, 0, 1, t.Y, 0, 0, 1); } /// /// Creates a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Translation(Shift2d s) { return new M33d( 1, 0, s.X, 0, 1, s.Y, 0, 0, 1); } #endregion #region Rotation /// /// Creates a 2D rotation matrix with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Rotation(double angleInRadians) { var a = Fun.Cos(angleInRadians); var b = Fun.Sin(angleInRadians); return new M33d( a, -b, 0, b, a, 0, 0, 0, 1); } /// /// Creates a 2D rotation matrix with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d RotationInDegrees(double angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix from a /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Rotation(Rot3d r) => (M33d)r; /// /// Creates a 2D rotation matrix from a /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Rotation(Rot2d r) => (M33d)r; /// /// Creates a 3D rotation matrix from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Rotation(V3d normalizedAxis, double angleInRadians) { Debug.Assert(normalizedAxis.LengthSquared.ApproximateEquals(1, 1e-10)); return (M33d)(Rot3d.Rotation(normalizedAxis, angleInRadians)); } /// /// Creates a 3D rotation matrix from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d RotationInDegrees(V3d normalizedAxis, double angleInDegrees) => Rotation(normalizedAxis, angleInDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d RotationEuler(double rollInRadians, double pitchInRadians, double yawInRadians) { return (M33d)(Rot3d.RotationEuler(rollInRadians, pitchInRadians, yawInRadians)); } /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d RotationEulerInDegrees(double rollInDegrees, double pitchInDegrees, double yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d RotationEuler(V3d rollPitchYawInRadians) => RotationEuler( rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d RotationEulerInDegrees(V3d rollPitchYawInDegrees) => RotationEulerInDegrees( rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a 3D rotation matrix which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d RotateInto(V3d from, V3d into) { Debug.Assert(from.LengthSquared.ApproximateEquals(1, 1e-10)); Debug.Assert(into.LengthSquared.ApproximateEquals(1, 1e-10)); return (M33d)(Rot3d.RotateInto(from, into)); } /// /// Creates a 3D rotation matrix for radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d RotationX(double angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M33d( 1, 0, 0, 0, a, -b, 0, b, a); } /// /// Creates a 3D rotation matrix for degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d RotationXInDegrees(double angleDegrees) => RotationX(angleDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix for radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d RotationY(double angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M33d( a, 0, b, 0, 1, 0, -b, 0, a); } /// /// Creates a 3D rotation matrix for degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d RotationYInDegrees(double angleDegrees) => RotationY(angleDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix for radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d RotationZ(double angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M33d( a, -b, 0, b, a, 0, 0, 0, 1); } /// /// Creates a 3D rotation matrix for degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d RotationZInDegrees(double angleDegrees) => RotationZ(angleDegrees.RadiansFromDegrees()); #endregion #region Shearing /// /// Creates a shear transformation matrix along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d ShearXY(double factorX, double factorY) { return new M33d( 1, 0, factorX, 0, 1, factorY, 0, 0, 1); } /// /// Creates a shear transformation matrix along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d ShearXZ(double factorX, double factorZ) { return new M33d( 1, factorX, 0, 0, 1, 0, 0, factorZ, 1); } /// /// Creates a shear transformation matrix along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d ShearYZ(double factorY, double factorZ) { return new M33d( 1, 0, 0, factorY, 1, 0, factorZ, 0, 1); } #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d DivideByInt(M33d m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M02; yield return M10; yield return M11; yield return M12; yield return M20; yield return M21; yield return M22; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; yield return R2; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; yield return C2; } } [XmlIgnore] public V3d R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3d( M00, M01, M02); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; M02 = value.Z; } } [XmlIgnore] public V3d R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3d( M10, M11, M12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; M12 = value.Z; } } [XmlIgnore] public V3d R2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3d( M20, M21, M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M20 = value.X; M21 = value.Y; M22 = value.Z; } } [XmlIgnore] public V3d C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3d( M00, M10, M20); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; M20 = value.Z; } } [XmlIgnore] public V3d C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3d( M01, M11, M21); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; M21 = value.Z; } } [XmlIgnore] public V3d C2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3d( M02, M12, M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M02 = value.X; M12 = value.Y; M22 = value.Z; } } public readonly V3d Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V3d(M00, M11, M22); } public readonly V3d AntiDiagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V3d(M02, M11, M20); } /// /// Returns the minimum element of the matrix. /// public readonly double MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M02, M10, M11, M12, M20, M21, M22); } /// /// Returns the maximum element of the matrix. /// public readonly double MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M02, M10, M11, M12, M20, M21, M22); } public unsafe double this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &M00) { ptr[index] = value; } } } public unsafe double this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &M00) { return ptr[row * 3 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &M00) { ptr[row * 3 + column] = value; } } } public readonly bool AnyFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) || Fun.IsFinite(M01) || Fun.IsFinite(M02) || Fun.IsFinite(M10) || Fun.IsFinite(M11) || Fun.IsFinite(M12) || Fun.IsFinite(M20) || Fun.IsFinite(M21) || Fun.IsFinite(M22); } } public readonly bool AllFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) && Fun.IsFinite(M01) && Fun.IsFinite(M02) && Fun.IsFinite(M10) && Fun.IsFinite(M11) && Fun.IsFinite(M12) && Fun.IsFinite(M20) && Fun.IsFinite(M21) && Fun.IsFinite(M22); } } public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNaN(M00) || double.IsNaN(M01) || double.IsNaN(M02) || double.IsNaN(M10) || double.IsNaN(M11) || double.IsNaN(M12) || double.IsNaN(M20) || double.IsNaN(M21) || double.IsNaN(M22); } } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNaN(M00) && double.IsNaN(M01) && double.IsNaN(M02) && double.IsNaN(M10) && double.IsNaN(M11) && double.IsNaN(M12) && double.IsNaN(M20) && double.IsNaN(M21) && double.IsNaN(M22); } } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsInfinity(M00) || double.IsInfinity(M01) || double.IsInfinity(M02) || double.IsInfinity(M10) || double.IsInfinity(M11) || double.IsInfinity(M12) || double.IsInfinity(M20) || double.IsInfinity(M21) || double.IsInfinity(M22); } } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsInfinity(M00) && double.IsInfinity(M01) && double.IsInfinity(M02) && double.IsInfinity(M10) && double.IsInfinity(M11) && double.IsInfinity(M12) && double.IsInfinity(M20) && double.IsInfinity(M21) && double.IsInfinity(M22); } } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsPositiveInfinity(M00) || double.IsPositiveInfinity(M01) || double.IsPositiveInfinity(M02) || double.IsPositiveInfinity(M10) || double.IsPositiveInfinity(M11) || double.IsPositiveInfinity(M12) || double.IsPositiveInfinity(M20) || double.IsPositiveInfinity(M21) || double.IsPositiveInfinity(M22); } } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsPositiveInfinity(M00) && double.IsPositiveInfinity(M01) && double.IsPositiveInfinity(M02) && double.IsPositiveInfinity(M10) && double.IsPositiveInfinity(M11) && double.IsPositiveInfinity(M12) && double.IsPositiveInfinity(M20) && double.IsPositiveInfinity(M21) && double.IsPositiveInfinity(M22); } } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNegativeInfinity(M00) || double.IsNegativeInfinity(M01) || double.IsNegativeInfinity(M02) || double.IsNegativeInfinity(M10) || double.IsNegativeInfinity(M11) || double.IsNegativeInfinity(M12) || double.IsNegativeInfinity(M20) || double.IsNegativeInfinity(M21) || double.IsNegativeInfinity(M22); } } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNegativeInfinity(M00) && double.IsNegativeInfinity(M01) && double.IsNegativeInfinity(M02) && double.IsNegativeInfinity(M10) && double.IsNegativeInfinity(M11) && double.IsNegativeInfinity(M12) && double.IsNegativeInfinity(M20) && double.IsNegativeInfinity(M21) && double.IsNegativeInfinity(M22); } } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) || Fun.IsTiny(M01) || Fun.IsTiny(M02) || Fun.IsTiny(M10) || Fun.IsTiny(M11) || Fun.IsTiny(M12) || Fun.IsTiny(M20) || Fun.IsTiny(M21) || Fun.IsTiny(M22); } } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) && Fun.IsTiny(M01) && Fun.IsTiny(M02) && Fun.IsTiny(M10) && Fun.IsTiny(M11) && Fun.IsTiny(M12) && Fun.IsTiny(M20) && Fun.IsTiny(M21) && Fun.IsTiny(M22); } } /// /// Returns true if the absolute value of each element of the matrix is smaller than Constant<double>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any element of the matrix is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any element of the matrix is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any element of the matrix is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any element of the matrix is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all elements of the matrix are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Constants public const int RowCount = 3; public const int ColumnCount = 3; public const int ElementCount = 3 * 3; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(3, 3); } public static M33d Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M33d(0); } public static M33d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M33d(1, 0, 0, 0, 1, 0, 0, 0, 1); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly double Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M02) + Fun.Abs(M10) + Fun.Abs(M11) + Fun.Abs(M12) + Fun.Abs(M20) + Fun.Abs(M21) + Fun.Abs(M22); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly double Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M02 * M02 + M10 * M10 + M11 * M11 + M12 * M12 + M20 * M20 + M21 * M21 + M22 * M22); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly double NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12)), Fun.Max( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly double NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12)), Fun.Min( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator -(M33d m) { return new M33d( -m.M00, -m.M01, -m.M02, -m.M10, -m.M11, -m.M12, -m.M20, -m.M21, -m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator + (M33d a, M33d b) { return new M33d( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator + (M33d m, double s) { return new M33d( m.M00 + s, m.M01 + s, m.M02 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M20 + s, m.M21 + s, m.M22 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator + (double s, M33d m) { return new M33d( s + m.M00, s + m.M01, s + m.M02, s + m.M10, s + m.M11, s + m.M12, s + m.M20, s + m.M21, s + m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator - (M33d a, M33d b) { return new M33d( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator - (M33d m, double s) { return new M33d( m.M00 - s, m.M01 - s, m.M02 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M20 - s, m.M21 - s, m.M22 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator - (double s, M33d m) { return new M33d( s - m.M00, s - m.M01, s - m.M02, s - m.M10, s - m.M11, s - m.M12, s - m.M20, s - m.M21, s - m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator % (M33d a, M33d b) { return new M33d( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator % (M33d m, double s) { return new M33d( m.M00 % s, m.M01 % s, m.M02 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M20 % s, m.M21 % s, m.M22 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator % (double s, M33d m) { return new M33d( s % m.M00, s % m.M01, s % m.M02, s % m.M10, s % m.M11, s % m.M12, s % m.M20, s % m.M21, s % m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator / (M33d a, M33d b) { return new M33d( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator / (M33d m, double s) { return new M33d( m.M00 / s, m.M01 / s, m.M02 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M20 / s, m.M21 / s, m.M22 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator / (double s, M33d m) { return new M33d( s / m.M00, s / m.M01, s / m.M02, s / m.M10, s / m.M11, s / m.M12, s / m.M20, s / m.M21, s / m.M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator * (M33d m, double s) { return new M33d( m.M00 * s, m.M01 * s, m.M02 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M20 * s, m.M21 * s, m.M22 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator * (double s, M33d m) { return new M33d( s * m.M00, s * m.M01, s * m.M02, s * m.M10, s * m.M11, s * m.M12, s * m.M20, s * m.M21, s * m.M22); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M33d matrix with a V3d column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator *(M33d m, V3d v) { return new V3d( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z); } /// /// Multiplies a V3d row vector with a M33d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator *(V3d v, M33d m) { return new V3d( v.X * m.M00 + v.Y * m.M10 + v.Z * m.M20, v.X * m.M01 + v.Y * m.M11 + v.Z * m.M21, v.X * m.M02 + v.Y * m.M12 + v.Z * m.M22); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M33d a, M33d b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M33d a, double s) { return a.M00 == s && a.M01 == s && a.M02 == s && a.M10 == s && a.M11 == s && a.M12 == s && a.M20 == s && a.M21 == s && a.M22 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(double s, M33d a) { return s == a.M00 && s == a.M01 && s == a.M02 && s == a.M10 && s == a.M11 && s == a.M12 && s == a.M20 && s == a.M21 && s == a.M22 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M33d a, M33d b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M33d m, double s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(double s, M33d m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01, M02), HashCode.GetCombined(M10, M11, M12), HashCode.GetCombined(M20, M21, M22)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M33d other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M02.Equals(other.M02) && M10.Equals(other.M10) && M11.Equals(other.M11) && M12.Equals(other.M12) && M20.Equals(other.M20) && M21.Equals(other.M21) && M22.Equals(other.M22); } public override readonly bool Equals(object other) => (other is M33d o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + betweenM + R2.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M33d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M33d.FromRows( V3d.Parse(x[0]), V3d.Parse(x[1]), V3d.Parse(x[2]) ); } #endregion #region Matrix Operations /// /// Returns adjoint of this matrix. /// public readonly M33d Adjoint { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { M33d result = new M33d(); for (int row = 0; row < 3; row++) { for (int col = 0; col < 3; col++) { if (((col + row) % 2) == 0) result[col, row] = this.Minor(row, col).Determinant; else result[col, row] = -this.Minor(row, col).Determinant; } } return result; } } /// /// Returns the trace of this matrix. /// The trace is defined as the sum of the diagonal elements, /// and is only defined for square matrices. /// public readonly double Trace { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return M00 + M11 + M22 ; } } /// /// Gets the determinant of this matrix. /// The determinant is only defined for square matrices. /// public readonly double Determinant { get { if (M10 == 0 && M20 == 0 && M21 == 0) { return M00 * M11 * M22; } return M00 * M11 * M22 - M00 * M12 * M21 + M01 * M12 * M20 - M01 * M10 * M22 + M02 * M10 * M21 - M02 * M11 * M20; } } /// /// Returns whether this matrix is invertible. /// A matrix is invertible if its determinant is not zero. /// public readonly bool Invertible { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant != 0; } } /// /// Returns whether this matrix is singular. /// A matrix is singular if its determinant is zero. /// public readonly bool Singular { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant == 0; } } /// /// Gets transpose of this matrix. /// public readonly M33d Transposed { get { return new M33d { M00 = M00, M01 = M10, M02 = M20, M10 = M01, M11 = M11, M12 = M21, M20 = M02, M21 = M12, M22 = M22 }; } } private static V2l s_luSize = new V2l(3, 3); private static V2l s_luDelta = new V2l(1, 3); /// /// Inverts the given matrix using lu factorization in place. Returns true /// if the matrix was invertible, otherwise the matrix remains unchanged. /// public unsafe bool LuInvert() { fixed (M33d* self = &this) { var lu = this; V3i perm; if (NumericExtensions.LuFactorize((double*)&lu, 0, 1, 3, (int*)&perm, 3)) { NumericExtensions.LuInverse((double*)&lu, 0, 1, 3, (int*)&perm, (double*)self, 0, 1, 3, 3); return true; } return false; } } /// /// Returns the inverse of the matrix using lu factorization. /// If the matrix is not invertible, M33d.Zero is returned. /// public unsafe readonly M33d LuInverse() { var lu = this; M33d res; V3i perm; if (NumericExtensions.LuFactorize((double*)&lu, 0, 1, 3, (int*)&perm, 3)) { NumericExtensions.LuInverse((double*)&lu, 0, 1, 3, (int*)&perm, (double*)&res, 0, 1, 3, 3); return res; } return M33d.Zero; } /// /// Returns the inverse of this matrix. If the matrix is not invertible /// M33d.Zero is returned. /// public readonly M33d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => LuInverse(); } #endregion #region Matrix Multiplication public static M33d operator *(M33d a, M33d b) { return new M33d( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return this[(int)y, (int)x]; } set { this[(int)y, (int)x] = value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (double)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (double)value; } #endregion } public class M33dEqualityComparer : IEqualityComparer { public static readonly M33dEqualityComparer Default = new M33dEqualityComparer(); #region IEqualityComparer Members public bool Equals(M33d v0, M33d v1) { return v0 == v1; } public int GetHashCode(M33d v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this M33d m) => (m.C0.Length + m.C1.Length + m.C2.Length) / 3; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetScaleVector(this M33d m) => new V3d(m.C0.Length, m.C1.Length, m.C2.Length); /// /// Approximates the uniform scale value of the given transformation matrix (average length of 2D basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale2(this M33d m) => (m.C0.XY.Length + m.C1.XY.Length) / 2; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the 2D basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetScaleVector2(this M33d m) => new V2d(m.C0.XY.Length, m.C1.XY.Length); #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm1(M33d m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(M33d m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormMax(M33d m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormMin(M33d m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this M33d m, double p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M02).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) + Fun.Abs(m.M12).Pow(p) + Fun.Abs(m.M20).Pow(p) + Fun.Abs(m.M21).Pow(p) + Fun.Abs(m.M22).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static double Distance1(this M33d a, M33d b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M02 - a.M02) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11) + Fun.Abs(b.M12 - a.M12) + Fun.Abs(b.M20 - a.M20) + Fun.Abs(b.M21 - a.M21) + Fun.Abs(b.M22 - a.M22); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static double Distance2(this M33d a, M33d b) { return Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M02 - a.M02) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11) + Fun.Square(b.M12 - a.M12) + Fun.Square(b.M20 - a.M20) + Fun.Square(b.M21 - a.M21) + Fun.Square(b.M22 - a.M22)); } /// /// Returns the p-distance between two matrices. /// public static double Distance(this M33d a, M33d b, double p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M02 - a.M02).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) + Fun.Abs(b.M12 - a.M12).Pow(p) + Fun.Abs(b.M20 - a.M20).Pow(p) + Fun.Abs(b.M21 - a.M21).Pow(p) + Fun.Abs(b.M22 - a.M22).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static double DistanceMax(this M33d a, M33d b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12)), Fun.Max( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static double DistanceMin(this M33d a, M33d b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12)), Fun.Min( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Transform(this M33d m, V3d v) => m * v; /// /// Transforms vector v by matrix m. /// v.W is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Transform(this M33d m, V4d v) { return new V4d( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z, v.W); } /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransposedTransform(this M33d m, V3d v) => v * m; /// /// Transforms vector v by the transpose of matrix m. /// v.W is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d TransposedTransform(this M33d m, V4d v) { return new V4d( v.X * m.M00 + v.Y * m.M10 + v.Z * m.M20, v.X * m.M01 + v.Y * m.M11 + v.Z * m.M21, v.X * m.M02 + v.Y * m.M12 + v.Z * m.M22, v.W); } /// /// Transforms direction vector v (v.Z is presumed 0.0) by matrix m. /// public static V2d TransformDir(this M33d m, V2d v) { return new V2d( m.M00 * v.X + m.M01 * v.Y, m.M10 * v.X + m.M11 * v.Y ); } /// /// Transforms point p (v.Z is presumed 1.0) by matrix m. /// No projective transform is performed. /// public static V2d TransformPos(this M33d m, V2d p) { return new V2d( m.M00 * p.X + m.M01 * p.Y + m.M02, m.M10 * p.X + m.M11 * p.Y + m.M12 ); } /// /// Transforms point p (p.Z is presumed 1.0) by matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static V2d TransformPosProj(this M33d m, V2d p) { double s = m.M20 * p.X + m.M21 * p.Y + m.M22; return TransformPos(m, p) * (1 / s); } /// /// Transforms point p (p.Z is presumed 1.0) by matrix m. /// Projective transform is performed. /// public static V3d TransformPosProjFull(this M33d m, V2d p) { return new V3d( m.M00 * p.X + m.M01 * p.Y + m.M02, m.M10 * p.X + m.M11 * p.Y + m.M12, m.M20 * p.X + m.M21 * p.Y + m.M22 ); } /// /// Transforms direction vector v (v.Z is presumed 0.0) by transposed version of matrix m. /// public static V2d TransposedTransformDir(this M33d m, V2d v) { return new V2d( m.M00 * v.X + m.M10 * v.Y, m.M01 * v.X + m.M11 * v.Y ); } /// /// Transforms point p (v.Z is presumed 1.0) by transposed version of matrix m. /// No projective transform is performed. /// public static V2d TransposedTransformPos(this M33d m, V2d p) { return new V2d( m.M00 * p.X + m.M10 * p.Y + m.M20, m.M01 * p.X + m.M11 * p.Y + m.M21 ); } /// /// Transforms point p (v.Z is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static V2d TransposedTransformPosProj(this M33d m, V2d p) { var s = m.M02 * p.X + m.M12 * p.Y + m.M22; return TransposedTransformPos(m, p) * (1 / s); } [Obsolete("Use TransposedTransformPosProj instead.")] public static V2d TransposedTransformProj(this M33d m, V2d p) => m.TransposedTransformPosProj(p); /// /// Transforms point p (v.Z is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. /// public static V3d TransposedTransformPosProjFull(this M33d m, V2d p) { return new V3d( m.M00 * p.X + m.M10 * p.Y + m.M20, m.M01 * p.X + m.M11 * p.Y + m.M21, m.M02 * p.X + m.M12 * p.Y + m.M22 ); } [Obsolete("Use TransposedTransformPosProjFull instead.")] public static V3d TransposedTransformProjFull(this M33d m, V2d p) => m.TransposedTransformPosProjFull(p); #endregion #region Operations /// /// Returns the given to a deleting the /// specified row and column. /// public static M22d Minor(this M33d m, int row, int column) { M22d rs = new M22d(); for (int k = 0; k < 4; k++) { var i = k / 2; var j = k % 2; var ii = (i < row) ? i : i + 1; var jj = (j < column) ? j : j + 1; rs[k] = m[ii * 3 + jj]; } return rs; } /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V3d Row(this M33d m, int index) { double* ptr = &m.M00; return new V3d(ptr[index * 3], ptr[index * 3 + 1], ptr[index * 3 + 2]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V3d Column(this M33d m, int index) { double* ptr = &m.M00; return new V3d(ptr[index], ptr[index + 3], ptr[index + 6]); } /// /// Returns the determinant of the given matrix. /// The determinant is only defined for square matrices. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Determinant(M33d m) => m.Determinant; /// /// Returns the transpose of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Transposed(M33d m) => m.Transposed; /// /// Transposes the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transpose(this ref M33d m) { Fun.Swap(ref m.M10, ref m.M01); Fun.Swap(ref m.M20, ref m.M02); Fun.Swap(ref m.M21, ref m.M12); } /// /// Returns the inverse of the given matrix. If the matrix is not invertible /// M33d.Zero is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Inverse(M33d m) => m.Inverse; /// /// Inverts the given matrix in place. Returns true if the matrix was invertible, /// otherwise the matrix remains unchanged. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Invert(this ref M33d m) { return m.LuInvert(); } /// /// Returns if the given matrix is the identity matrix I. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIdentity(this M33d m, double epsilon) { return Fun.ApproximateEquals(m, M33d.Identity, epsilon); } /// /// Returns if the given matrix is the identity matrix I. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIdentity(this M33d m) => IsIdentity(m, Constant.PositiveTinyValue); /// /// Returns if the given matrix is orthonormal (i.e. M * M^t == I) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthonormal(this M33d m, double epsilon) { var i = m * m.Transposed; return i.IsIdentity(epsilon); } /// /// Returns if the given matrix is orthonormal (i.e. M * M^t == I) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthonormal(this M33d m) => IsOrthonormal(m, Constant.PositiveTinyValue); /// /// Returns if the given matrix is orthogonal (i.e. all non-diagonal entries of M * M^t == 0) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonal(this M33d m, double epsilon) { var i = m * m.Transposed; for (int j = 0; j < 3; j++) i[j, j] = 1; //inefficient implementation: just leave out the comparisons at the diagonal entries. return i.IsIdentity(epsilon); } /// /// Returns if the given matrix is orthogonal (i.e. all non-diagonal entries of M * M^t == 0) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonal(this M33d m) => IsOrthogonal(m, Constant.PositiveTinyValue); #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M33d a, M33d b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M02 < b.M02 && a.M10 < b.M10 && a.M11 < b.M11 && a.M12 < b.M12 && a.M20 < b.M20 && a.M21 < b.M21 && a.M22 < b.M22; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M33d m, double s) { return m.M00 < s && m.M01 < s && m.M02 < s && m.M10 < s && m.M11 < s && m.M12 < s && m.M20 < s && m.M21 < s && m.M22 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(double s, M33d m) { return s < m.M00 && s < m.M01 && s < m.M02 && s < m.M10 && s < m.M11 && s < m.M12 && s < m.M20 && s < m.M21 && s < m.M22; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M33d a, M33d b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M02 < b.M02 || a.M10 < b.M10 || a.M11 < b.M11 || a.M12 < b.M12 || a.M20 < b.M20 || a.M21 < b.M21 || a.M22 < b.M22; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M33d m, double s) { return m.M00 < s || m.M01 < s || m.M02 < s || m.M10 < s || m.M11 < s || m.M12 < s || m.M20 < s || m.M21 < s || m.M22 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(double s, M33d m) { return s < m.M00 || s < m.M01 || s < m.M02 || s < m.M10 || s < m.M11 || s < m.M12 || s < m.M20 || s < m.M21 || s < m.M22; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M33d a, M33d b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M02 > b.M02 && a.M10 > b.M10 && a.M11 > b.M11 && a.M12 > b.M12 && a.M20 > b.M20 && a.M21 > b.M21 && a.M22 > b.M22; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M33d m, double s) { return m.M00 > s && m.M01 > s && m.M02 > s && m.M10 > s && m.M11 > s && m.M12 > s && m.M20 > s && m.M21 > s && m.M22 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(double s, M33d m) { return s > m.M00 && s > m.M01 && s > m.M02 && s > m.M10 && s > m.M11 && s > m.M12 && s > m.M20 && s > m.M21 && s > m.M22; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M33d a, M33d b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M02 > b.M02 || a.M10 > b.M10 || a.M11 > b.M11 || a.M12 > b.M12 || a.M20 > b.M20 || a.M21 > b.M21 || a.M22 > b.M22; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M33d m, double s) { return m.M00 > s || m.M01 > s || m.M02 > s || m.M10 > s || m.M11 > s || m.M12 > s || m.M20 > s || m.M21 > s || m.M22 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(double s, M33d m) { return s > m.M00 || s > m.M01 || s > m.M02 || s > m.M10 || s > m.M11 || s > m.M12 || s > m.M20 || s > m.M21 || s > m.M22; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M33d a, M33d b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M02 <= b.M02 && a.M10 <= b.M10 && a.M11 <= b.M11 && a.M12 <= b.M12 && a.M20 <= b.M20 && a.M21 <= b.M21 && a.M22 <= b.M22; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M33d m, double s) { return m.M00 <= s && m.M01 <= s && m.M02 <= s && m.M10 <= s && m.M11 <= s && m.M12 <= s && m.M20 <= s && m.M21 <= s && m.M22 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(double s, M33d m) { return s <= m.M00 && s <= m.M01 && s <= m.M02 && s <= m.M10 && s <= m.M11 && s <= m.M12 && s <= m.M20 && s <= m.M21 && s <= m.M22; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M33d a, M33d b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M02 <= b.M02 || a.M10 <= b.M10 || a.M11 <= b.M11 || a.M12 <= b.M12 || a.M20 <= b.M20 || a.M21 <= b.M21 || a.M22 <= b.M22; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M33d m, double s) { return m.M00 <= s || m.M01 <= s || m.M02 <= s || m.M10 <= s || m.M11 <= s || m.M12 <= s || m.M20 <= s || m.M21 <= s || m.M22 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(double s, M33d m) { return s <= m.M00 || s <= m.M01 || s <= m.M02 || s <= m.M10 || s <= m.M11 || s <= m.M12 || s <= m.M20 || s <= m.M21 || s <= m.M22; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M33d a, M33d b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M02 >= b.M02 && a.M10 >= b.M10 && a.M11 >= b.M11 && a.M12 >= b.M12 && a.M20 >= b.M20 && a.M21 >= b.M21 && a.M22 >= b.M22; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M33d m, double s) { return m.M00 >= s && m.M01 >= s && m.M02 >= s && m.M10 >= s && m.M11 >= s && m.M12 >= s && m.M20 >= s && m.M21 >= s && m.M22 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(double s, M33d m) { return s >= m.M00 && s >= m.M01 && s >= m.M02 && s >= m.M10 && s >= m.M11 && s >= m.M12 && s >= m.M20 && s >= m.M21 && s >= m.M22; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M33d a, M33d b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M02 >= b.M02 || a.M10 >= b.M10 || a.M11 >= b.M11 || a.M12 >= b.M12 || a.M20 >= b.M20 || a.M21 >= b.M21 || a.M22 >= b.M22; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M33d m, double s) { return m.M00 >= s || m.M01 >= s || m.M02 >= s || m.M10 >= s || m.M11 >= s || m.M12 >= s || m.M20 >= s || m.M21 >= s || m.M22 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(double s, M33d m) { return s >= m.M00 || s >= m.M01 || s >= m.M02 || s >= m.M10 || s >= m.M11 || s >= m.M12 || s >= m.M20 || s >= m.M21 || s >= m.M22; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M33d a, M33d b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M33d m, double s) { return m.M00 == s && m.M01 == s && m.M02 == s && m.M10 == s && m.M11 == s && m.M12 == s && m.M20 == s && m.M21 == s && m.M22 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(double s, M33d m) { return s == m.M00 && s == m.M01 && s == m.M02 && s == m.M10 && s == m.M11 && s == m.M12 && s == m.M20 && s == m.M21 && s == m.M22; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M33d a, M33d b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M02 == b.M02 || a.M10 == b.M10 || a.M11 == b.M11 || a.M12 == b.M12 || a.M20 == b.M20 || a.M21 == b.M21 || a.M22 == b.M22; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M33d m, double s) { return m.M00 == s || m.M01 == s || m.M02 == s || m.M10 == s || m.M11 == s || m.M12 == s || m.M20 == s || m.M21 == s || m.M22 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(double s, M33d m) { return s == m.M00 || s == m.M01 || s == m.M02 || s == m.M10 || s == m.M11 || s == m.M12 || s == m.M20 || s == m.M21 || s == m.M22; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M33d a, M33d b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M02 != b.M02 && a.M10 != b.M10 && a.M11 != b.M11 && a.M12 != b.M12 && a.M20 != b.M20 && a.M21 != b.M21 && a.M22 != b.M22; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M33d m, double s) { return m.M00 != s && m.M01 != s && m.M02 != s && m.M10 != s && m.M11 != s && m.M12 != s && m.M20 != s && m.M21 != s && m.M22 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(double s, M33d m) { return s != m.M00 && s != m.M01 && s != m.M02 && s != m.M10 && s != m.M11 && s != m.M12 && s != m.M20 && s != m.M21 && s != m.M22; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M33d a, M33d b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M02 != b.M02 || a.M10 != b.M10 || a.M11 != b.M11 || a.M12 != b.M12 || a.M20 != b.M20 || a.M21 != b.M21 || a.M22 != b.M22; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M33d m, double s) { return m.M00 != s || m.M01 != s || m.M02 != s || m.M10 != s || m.M11 != s || m.M12 != s || m.M20 != s || m.M21 != s || m.M22 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(double s, M33d m) { return s != m.M00 || s != m.M01 || s != m.M02 || s != m.M10 || s != m.M11 || s != m.M12 || s != m.M20 || s != m.M21 || s != m.M22; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M33d m0, M33d m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M02 < m1.M02) return -1; if (m0.M02 > m1.M02) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; if (m0.M12 < m1.M12) return -1; if (m0.M12 > m1.M12) return +1; if (m0.M20 < m1.M20) return -1; if (m0.M20 > m1.M20) return +1; if (m0.M21 < m1.M21) return -1; if (m0.M21 > m1.M21) return +1; if (m0.M22 < m1.M22) return -1; if (m0.M22 > m1.M22) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MinElement(M33d m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MaxElement(M33d m) => m.MaxElement; #endregion #region Orthogonalization /// /// Orthogonalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// public static void Orthogonalize(this ref M33d matrix) { matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C0, matrix.C2) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C1, matrix.C2) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C2 -= (Vec.Dot(matrix.C0, matrix.C2) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C1, matrix.C2) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; } /// /// Orthogonalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Orthogonalized(this M33d matrix) { M33d m = matrix; Orthogonalize(ref m); return m; } /// /// Orthonormalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// public static void Orthonormalize(this ref M33d matrix) { matrix.C0 = matrix.C0.Normalized; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 = matrix.C1.Normalized; matrix.C2 -= (Vec.Dot(matrix.C0, matrix.C2) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C1, matrix.C2) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C2 -= (Vec.Dot(matrix.C0, matrix.C2) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C1, matrix.C2) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C2 = matrix.C2.Normalized; } /// /// Orthonormalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Orthonormalized(this M33d matrix) { M33d m = matrix; Orthonormalize(ref m); return m; } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M33d m, double epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M02.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon) || m.M12.IsTiny(epsilon) || m.M20.IsTiny(epsilon) || m.M21.IsTiny(epsilon) || m.M22.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M33d m, double epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M02.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon) && m.M12.IsTiny(epsilon) && m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon) && m.M22.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyFinite(M33d m) => m.AnyFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllFinite(M33d m) => m.AllFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(M33d m) => m.AnyNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(M33d m) => m.AllNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(M33d m) => m.AnyInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(M33d m) => m.AllInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(M33d m) => m.AnyPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(M33d m) => m.AllPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(M33d m) => m.AnyNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(M33d m) => m.AllNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(M33d m) => m.AnyTiny; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(M33d m) => m.AllTiny; #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M33d a, M33d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M33d a, M33d b, double epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M33d m, double epsilon) => Mat.AllTiny(m, epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(M33d m) => m.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any element of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(M33d v) => v.IsNaN; /// /// Returns whether any element of the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(M33d v) => v.IsInfinity; /// /// Returns whether any element of the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(M33d v) => v.IsPositiveInfinity; /// /// Returns whether any element of the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(M33d v) => v.IsNegativeInfinity; /// /// Returns whether all elements of the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(M33d v) => v.IsFinite; #endregion } public static class IRandomUniformM33dExtensions { #region IRandomUniform extensions for M33d /// /// Uses UniformDouble() to generate the elements of an M33d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d UniformM33d(this IRandomUniform rnd) { return new M33d( rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble()); } /// /// Uses UniformDoubleClosed() to generate the elements of an M33d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d UniformM33dClosed(this IRandomUniform rnd) { return new M33d( rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed()); } /// /// Uses UniformDoubleOpen() to generate the elements of an M33d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d UniformM33dOpen(this IRandomUniform rnd) { return new M33d( rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen()); } /// /// Uses UniformDoubleFull() to generate the elements of an M33d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d UniformM33dFull(this IRandomUniform rnd) { return new M33d( rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull()); } /// /// Uses UniformDoubleFullClosed() to generate the elements of an M33d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d UniformM33dFullClosed(this IRandomUniform rnd) { return new M33d( rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed()); } /// /// Uses UniformDoubleFullOpen() to generate the elements of an M33d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d UniformM33dFullOpen(this IRandomUniform rnd) { return new M33d( rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen()); } #endregion } #endregion #region M34i [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M34i : IEquatable, IValidity, IMatrix { [DataMember] public int M00, M01, M02, M03; [DataMember] public int M10, M11, M12, M13; [DataMember] public int M20, M21, M22, M23; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(int value) { M00 = value; M01 = 0; M02 = 0; M03 = 0; M10 = 0; M11 = value; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = value; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i( int m00, int m01, int m02, int m03, int m10, int m11, int m12, int m13, int m20, int m21, int m22, int m23) { M00 = m00; M01 = m01; M02 = m02; M03 = m03; M10 = m10; M11 = m11; M12 = m12; M13 = m13; M20 = m20; M21 = m21; M22 = m22; M23 = m23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(int[] a) { M00 = a[0]; M01 = a[1]; M02 = a[2]; M03 = a[3]; M10 = a[4]; M11 = a[5]; M12 = a[6]; M13 = a[7]; M20 = a[8]; M21 = a[9]; M22 = a[10]; M23 = a[11]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(int[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M02 = a[start + 2]; M03 = a[start + 3]; M10 = a[start + 4]; M11 = a[start + 5]; M12 = a[start + 6]; M13 = a[start + 7]; M20 = a[start + 8]; M21 = a[start + 9]; M22 = a[start + 10]; M23 = a[start + 11]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M33i m, V3i v) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = v.X; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = v.Y; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = v.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M22i m) { M00 = m.M00; M01 = m.M01; M02 = 0; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M23i m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M33i m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = 0; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M44i m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = m.M03; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = m.M13; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M22l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = 0; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M23l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M33l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = 0; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M34l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = (int)m.M03; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = (int)m.M13; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = (int)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M44l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = (int)m.M03; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = (int)m.M13; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = (int)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M22f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = 0; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M23f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M33f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = 0; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M34f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = (int)m.M03; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = (int)m.M13; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = (int)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M44f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = (int)m.M03; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = (int)m.M13; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = (int)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M22d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = 0; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M23d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M33d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = 0; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M34d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = (int)m.M03; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = (int)m.M13; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = (int)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34i(M44d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = (int)m.M03; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = (int)m.M13; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = (int)m.M23; } #endregion #region Conversions public static explicit operator M34i(M22i m) { return new M34i { M00 = m.M00, M01 = m.M01, M02 = 0, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34i(M23i m) { return new M34i { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34i(M33i m) { return new M34i { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = 0, M20 = m.M20, M21 = m.M21, M22 = m.M22, M23 = 0, }; } public static explicit operator M34i(M44i m) { return new M34i { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = m.M03, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = m.M13, M20 = m.M20, M21 = m.M21, M22 = m.M22, M23 = m.M23, }; } public static explicit operator M34i(M22l m) { return new M34i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = 0, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34i(M23l m) { return new M34i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34i(M33l m) { return new M34i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = 0, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = 0, }; } public static explicit operator M34i(M34l m) { return new M34i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = (int)m.M03, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = (int)m.M13, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = (int)m.M23, }; } public static explicit operator M34i(M44l m) { return new M34i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = (int)m.M03, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = (int)m.M13, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = (int)m.M23, }; } public static explicit operator M34i(M22f m) { return new M34i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = 0, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34i(M23f m) { return new M34i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34i(M33f m) { return new M34i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = 0, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = 0, }; } public static explicit operator M34i(M34f m) { return new M34i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = (int)m.M03, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = (int)m.M13, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = (int)m.M23, }; } public static explicit operator M34i(M44f m) { return new M34i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = (int)m.M03, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = (int)m.M13, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = (int)m.M23, }; } public static explicit operator M34i(M22d m) { return new M34i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = 0, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34i(M23d m) { return new M34i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34i(M33d m) { return new M34i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = 0, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = 0, }; } public static explicit operator M34i(M34d m) { return new M34i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = (int)m.M03, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = (int)m.M13, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = (int)m.M23, }; } public static explicit operator M34i(M44d m) { return new M34i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = (int)m.M03, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = (int)m.M13, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = (int)m.M23, }; } public static explicit operator M34i(int[] a) { return new M34i( a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11]); } public static explicit operator M34i(int[,] a) { return new M34i( a[0, 0], a[0, 1], a[0, 2], a[0, 3], a[1, 0], a[1, 1], a[1, 2], a[1, 3], a[2, 0], a[2, 1], a[2, 2], a[2, 3]); } public static explicit operator int[](M34i m) { return new int[] { m.M00, m.M01, m.M02, m.M03, m.M10, m.M11, m.M12, m.M13, m.M20, m.M21, m.M22, m.M23 }; } public static explicit operator int[,](M34i m) { return new int[,] { { m.M00, m.M01, m.M02, m.M03 }, { m.M10, m.M11, m.M12, m.M13 }, { m.M20, m.M21, m.M22, m.M23 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M02; array[index + 3] = M03; array[index + 4] = M10; array[index + 5] = M11; array[index + 6] = M12; array[index + 7] = M13; array[index + 8] = M20; array[index + 9] = M21; array[index + 10] = M22; array[index + 11] = M23; } public static explicit operator M34i(long[] a) { return new M34i( (int)a[0], (int)a[1], (int)a[2], (int)a[3], (int)a[4], (int)a[5], (int)a[6], (int)a[7], (int)a[8], (int)a[9], (int)a[10], (int)a[11]); } public static explicit operator M34i(long[,] a) { return new M34i( (int)a[0, 0], (int)a[0, 1], (int)a[0, 2], (int)a[0, 3], (int)a[1, 0], (int)a[1, 1], (int)a[1, 2], (int)a[1, 3], (int)a[2, 0], (int)a[2, 1], (int)a[2, 2], (int)a[2, 3]); } public static explicit operator long[](M34i m) { return new long[] { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M03, (long)m.M10, (long)m.M11, (long)m.M12, (long)m.M13, (long)m.M20, (long)m.M21, (long)m.M22, (long)m.M23 }; } public static explicit operator long[,](M34i m) { return new long[,] { { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M03 }, { (long)m.M10, (long)m.M11, (long)m.M12, (long)m.M13 }, { (long)m.M20, (long)m.M21, (long)m.M22, (long)m.M23 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = (long)M00; array[index + 1] = (long)M01; array[index + 2] = (long)M02; array[index + 3] = (long)M03; array[index + 4] = (long)M10; array[index + 5] = (long)M11; array[index + 6] = (long)M12; array[index + 7] = (long)M13; array[index + 8] = (long)M20; array[index + 9] = (long)M21; array[index + 10] = (long)M22; array[index + 11] = (long)M23; } public static explicit operator M34i(float[] a) { return new M34i( (int)a[0], (int)a[1], (int)a[2], (int)a[3], (int)a[4], (int)a[5], (int)a[6], (int)a[7], (int)a[8], (int)a[9], (int)a[10], (int)a[11]); } public static explicit operator M34i(float[,] a) { return new M34i( (int)a[0, 0], (int)a[0, 1], (int)a[0, 2], (int)a[0, 3], (int)a[1, 0], (int)a[1, 1], (int)a[1, 2], (int)a[1, 3], (int)a[2, 0], (int)a[2, 1], (int)a[2, 2], (int)a[2, 3]); } public static explicit operator float[](M34i m) { return new float[] { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M03, (float)m.M10, (float)m.M11, (float)m.M12, (float)m.M13, (float)m.M20, (float)m.M21, (float)m.M22, (float)m.M23 }; } public static explicit operator float[,](M34i m) { return new float[,] { { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M03 }, { (float)m.M10, (float)m.M11, (float)m.M12, (float)m.M13 }, { (float)m.M20, (float)m.M21, (float)m.M22, (float)m.M23 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = (float)M00; array[index + 1] = (float)M01; array[index + 2] = (float)M02; array[index + 3] = (float)M03; array[index + 4] = (float)M10; array[index + 5] = (float)M11; array[index + 6] = (float)M12; array[index + 7] = (float)M13; array[index + 8] = (float)M20; array[index + 9] = (float)M21; array[index + 10] = (float)M22; array[index + 11] = (float)M23; } public static explicit operator M34i(double[] a) { return new M34i( (int)a[0], (int)a[1], (int)a[2], (int)a[3], (int)a[4], (int)a[5], (int)a[6], (int)a[7], (int)a[8], (int)a[9], (int)a[10], (int)a[11]); } public static explicit operator M34i(double[,] a) { return new M34i( (int)a[0, 0], (int)a[0, 1], (int)a[0, 2], (int)a[0, 3], (int)a[1, 0], (int)a[1, 1], (int)a[1, 2], (int)a[1, 3], (int)a[2, 0], (int)a[2, 1], (int)a[2, 2], (int)a[2, 3]); } public static explicit operator double[](M34i m) { return new double[] { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M03, (double)m.M10, (double)m.M11, (double)m.M12, (double)m.M13, (double)m.M20, (double)m.M21, (double)m.M22, (double)m.M23 }; } public static explicit operator double[,](M34i m) { return new double[,] { { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M03 }, { (double)m.M10, (double)m.M11, (double)m.M12, (double)m.M13 }, { (double)m.M20, (double)m.M21, (double)m.M22, (double)m.M23 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = (double)M00; array[index + 1] = (double)M01; array[index + 2] = (double)M02; array[index + 3] = (double)M03; array[index + 4] = (double)M10; array[index + 5] = (double)M11; array[index + 6] = (double)M12; array[index + 7] = (double)M13; array[index + 8] = (double)M20; array[index + 9] = (double)M21; array[index + 10] = (double)M22; array[index + 11] = (double)M23; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34i Copy(Func element_fun) { return new M34i( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34i Copy(Func element_index0_index1_fun) { return new M34i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34l Copy(Func element_fun) { return new M34l( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34l Copy(Func element_index0_index1_fun) { return new M34l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34f Copy(Func element_fun) { return new M34f( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34f Copy(Func element_index0_index1_fun) { return new M34f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34d Copy(Func element_fun) { return new M34d( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34d Copy(Func element_index0_index1_fun) { return new M34d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3)); } public readonly int[] ToArray() { var array = new int[12]; array[0] = M00; array[1] = M01; array[2] = M02; array[3] = M03; array[4] = M10; array[5] = M11; array[6] = M12; array[7] = M13; array[8] = M20; array[9] = M21; array[10] = M22; array[11] = M23; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i FromCols(V3i col0, V3i col1, V3i col2, V3i col3) { return new M34i( col0.X, col1.X, col2.X, col3.X, col0.Y, col1.Y, col2.Y, col3.Y, col0.Z, col1.Z, col2.Z, col3.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i FromRows(V4i row0, V4i row1, V4i row2) { return new M34i( row0.X, row0.Y, row0.Z, row0.W, row1.X, row1.Y, row1.Z, row1.W, row2.X, row2.Y, row2.Z, row2.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i FromDiagonal(int value) { return new M34i( value, 0, 0, 0, 0, value, 0, 0, 0, 0, value, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i FromDiagonal(int m00, int m11, int m22) { return new M34i( m00, 0, 0, 0, 0, m11, 0, 0, 0, 0, m22, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i FromDiagonal(V3i s) { return new M34i( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0); } #region Scale /// /// Creates a homogenous transformation using a uniform scale. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i Scale(int s) { return new M34i( s, 0, 0, 0, 0, s, 0, 0, 0, 0, s, 0); } /// /// Creates a transformation using 3 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i Scale(int sX, int sY, int sZ) { return new M34i( sX, 0, 0, 0, 0, sY, 0, 0, 0, 0, sZ, 0); } /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i Scale(V3i s) { return new M34i( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0); } #endregion #region Translation /// /// Creates a transformation with the translational component given by 3 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i Translation(int tX, int tY, int tZ) { return new M34i( 1, 0, 0, tX, 0, 1, 0, tY, 0, 0, 1, tZ); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i Translation(V3i t) { return new M34i( 1, 0, 0, t.X, 0, 1, 0, t.Y, 0, 0, 1, t.Z); } #endregion #region Shearing /// /// Creates a shear transformation matrix along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i ShearXY(int factorX, int factorY) { return new M34i( 1, 0, factorX, 0, 0, 1, factorY, 0, 0, 0, 1, 0); } /// /// Creates a shear transformation matrix along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i ShearXZ(int factorX, int factorZ) { return new M34i( 1, factorX, 0, 0, 0, 1, 0, 0, 0, factorZ, 1, 0); } /// /// Creates a shear transformation matrix along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i ShearYZ(int factorY, int factorZ) { return new M34i( 1, 0, 0, 0, factorY, 1, 0, 0, factorZ, 0, 1, 0); } #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i DivideByInt(M34i m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M02; yield return M03; yield return M10; yield return M11; yield return M12; yield return M13; yield return M20; yield return M21; yield return M22; yield return M23; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; yield return R2; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; yield return C2; yield return C3; } } [XmlIgnore] public V4i R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4i( M00, M01, M02, M03); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; M02 = value.Z; M03 = value.W; } } [XmlIgnore] public V4i R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4i( M10, M11, M12, M13); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; M12 = value.Z; M13 = value.W; } } [XmlIgnore] public V4i R2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4i( M20, M21, M22, M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M20 = value.X; M21 = value.Y; M22 = value.Z; M23 = value.W; } } [XmlIgnore] public V3i C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3i( M00, M10, M20); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; M20 = value.Z; } } [XmlIgnore] public V3i C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3i( M01, M11, M21); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; M21 = value.Z; } } [XmlIgnore] public V3i C2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3i( M02, M12, M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M02 = value.X; M12 = value.Y; M22 = value.Z; } } [XmlIgnore] public V3i C3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3i( M03, M13, M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M03 = value.X; M13 = value.Y; M23 = value.Z; } } public readonly V3i Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V3i(M00, M11, M22); } /// /// Returns the minimum element of the matrix. /// public readonly int MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23); } /// /// Returns the maximum element of the matrix. /// public readonly int MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23); } public unsafe int this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (int* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (int* ptr = &M00) { ptr[index] = value; } } } public unsafe int this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (int* ptr = &M00) { return ptr[row * 4 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (int* ptr = &M00) { ptr[row * 4 + column] = value; } } } #endregion #region Constants public const int RowCount = 3; public const int ColumnCount = 4; public const int ElementCount = 3 * 4; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(3, 4); } public static M34i Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M34i(0); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly int Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M02) + Fun.Abs(M03) + Fun.Abs(M10) + Fun.Abs(M11) + Fun.Abs(M12) + Fun.Abs(M13) + Fun.Abs(M20) + Fun.Abs(M21) + Fun.Abs(M22) + Fun.Abs(M23); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly double Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M02 * M02 + M03 * M03 + M10 * M10 + M11 * M11 + M12 * M12 + M13 * M13 + M20 * M20 + M21 * M21 + M22 * M22 + M23 * M23); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly int NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02), Fun.Abs(M03)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12), Fun.Abs(M13)), Fun.Max( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22), Fun.Abs(M23))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly int NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02), Fun.Abs(M03)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12), Fun.Abs(M13)), Fun.Min( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22), Fun.Abs(M23))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator -(M34i m) { return new M34i( -m.M00, -m.M01, -m.M02, -m.M03, -m.M10, -m.M11, -m.M12, -m.M13, -m.M20, -m.M21, -m.M22, -m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator + (M34i a, M34i b) { return new M34i( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator + (M34i m, int s) { return new M34i( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator + (int s, M34i m) { return new M34i( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator + (M34i a, M34l b) { return new M34l( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator + (M34i m, long s) { return new M34l( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator + (long s, M34i m) { return new M34l( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator + (M34i a, M34f b) { return new M34f( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator + (M34i m, float s) { return new M34f( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator + (float s, M34i m) { return new M34f( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator + (M34i a, M34d b) { return new M34d( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator + (M34i m, double s) { return new M34d( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator + (double s, M34i m) { return new M34d( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator - (M34i a, M34i b) { return new M34i( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator - (M34i m, int s) { return new M34i( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator - (int s, M34i m) { return new M34i( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator - (M34i a, M34l b) { return new M34l( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator - (M34i m, long s) { return new M34l( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator - (long s, M34i m) { return new M34l( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator - (M34i a, M34f b) { return new M34f( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator - (M34i m, float s) { return new M34f( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator - (float s, M34i m) { return new M34f( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator - (M34i a, M34d b) { return new M34d( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator - (M34i m, double s) { return new M34d( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator - (double s, M34i m) { return new M34d( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator % (M34i a, M34i b) { return new M34i( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator % (M34i m, int s) { return new M34i( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator % (int s, M34i m) { return new M34i( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator % (M34i a, M34l b) { return new M34l( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator % (M34i m, long s) { return new M34l( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator % (long s, M34i m) { return new M34l( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator % (M34i a, M34f b) { return new M34f( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator % (M34i m, float s) { return new M34f( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator % (float s, M34i m) { return new M34f( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator % (M34i a, M34d b) { return new M34d( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator % (M34i m, double s) { return new M34d( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator % (double s, M34i m) { return new M34d( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator / (M34i a, M34i b) { return new M34i( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator / (M34i m, int s) { return new M34i( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator / (int s, M34i m) { return new M34i( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator / (M34i a, M34l b) { return new M34l( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator / (M34i m, long s) { return new M34l( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator / (long s, M34i m) { return new M34l( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator / (M34i a, M34f b) { return new M34f( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator / (M34i m, float s) { return new M34f( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator / (float s, M34i m) { return new M34f( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator / (M34i a, M34d b) { return new M34d( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator / (M34i m, double s) { return new M34d( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator / (double s, M34i m) { return new M34d( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator * (M34i m, int s) { return new M34i( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator * (int s, M34i m) { return new M34i( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator * (M34i m, long s) { return new M34l( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator * (long s, M34i m) { return new M34l( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator * (M34i m, float s) { return new M34f( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator * (float s, M34i m) { return new M34f( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator * (M34i m, double s) { return new M34d( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator * (double s, M34i m) { return new M34d( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23); } #endregion #region Bitwise Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator ~(M34i m) { return new M34i( ~m.M00, ~m.M01, ~m.M02, ~m.M03, ~m.M10, ~m.M11, ~m.M12, ~m.M13, ~m.M20, ~m.M21, ~m.M22, ~m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator <<(M34i a, int s) { return new M34i( a.M00 << s, a.M01 << s, a.M02 << s, a.M03 << s, a.M10 << s, a.M11 << s, a.M12 << s, a.M13 << s, a.M20 << s, a.M21 << s, a.M22 << s, a.M23 << s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator >>(M34i a, int s) { return new M34i( a.M00 >> s, a.M01 >> s, a.M02 >> s, a.M03 >> s, a.M10 >> s, a.M11 >> s, a.M12 >> s, a.M13 >> s, a.M20 >> s, a.M21 >> s, a.M22 >> s, a.M23 >> s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator &(M34i a, M34i b) { return new M34i( a.M00 & b.M00, a.M01 & b.M01, a.M02 & b.M02, a.M03 & b.M03, a.M10 & b.M10, a.M11 & b.M11, a.M12 & b.M12, a.M13 & b.M13, a.M20 & b.M20, a.M21 & b.M21, a.M22 & b.M22, a.M23 & b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator &(M34i a, int s) { return new M34i( a.M00 & s, a.M01 & s, a.M02 & s, a.M03 & s, a.M10 & s, a.M11 & s, a.M12 & s, a.M13 & s, a.M20 & s, a.M21 & s, a.M22 & s, a.M23 & s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator &(int s, M34i a) { return new M34i( s & a.M00, s & a.M01, s & a.M02, s & a.M03, s & a.M10, s & a.M11, s & a.M12, s & a.M13, s & a.M20, s & a.M21, s & a.M22, s & a.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator |(M34i a, M34i b) { return new M34i( a.M00 | b.M00, a.M01 | b.M01, a.M02 | b.M02, a.M03 | b.M03, a.M10 | b.M10, a.M11 | b.M11, a.M12 | b.M12, a.M13 | b.M13, a.M20 | b.M20, a.M21 | b.M21, a.M22 | b.M22, a.M23 | b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator |(M34i a, int s) { return new M34i( a.M00 | s, a.M01 | s, a.M02 | s, a.M03 | s, a.M10 | s, a.M11 | s, a.M12 | s, a.M13 | s, a.M20 | s, a.M21 | s, a.M22 | s, a.M23 | s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator |(int s, M34i a) { return new M34i( s | a.M00, s | a.M01, s | a.M02, s | a.M03, s | a.M10, s | a.M11, s | a.M12, s | a.M13, s | a.M20, s | a.M21, s | a.M22, s | a.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator ^(M34i a, M34i b) { return new M34i( a.M00 ^ b.M00, a.M01 ^ b.M01, a.M02 ^ b.M02, a.M03 ^ b.M03, a.M10 ^ b.M10, a.M11 ^ b.M11, a.M12 ^ b.M12, a.M13 ^ b.M13, a.M20 ^ b.M20, a.M21 ^ b.M21, a.M22 ^ b.M22, a.M23 ^ b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator ^(M34i a, int s) { return new M34i( a.M00 ^ s, a.M01 ^ s, a.M02 ^ s, a.M03 ^ s, a.M10 ^ s, a.M11 ^ s, a.M12 ^ s, a.M13 ^ s, a.M20 ^ s, a.M21 ^ s, a.M22 ^ s, a.M23 ^ s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i operator ^(int s, M34i a) { return new M34i( s ^ a.M00, s ^ a.M01, s ^ a.M02, s ^ a.M03, s ^ a.M10, s ^ a.M11, s ^ a.M12, s ^ a.M13, s ^ a.M20, s ^ a.M21, s ^ a.M22, s ^ a.M23); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M34i matrix with a V4i column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator *(M34i m, V4i v) { return new V3i( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z + m.M03 * v.W, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z + m.M13 * v.W, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z + m.M23 * v.W); } /// /// Multiplies a V3i row vector with a M34i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator *(V3i v, M34i m) { return new V4i( v.X * m.M00 + v.Y * m.M10 + v.Z * m.M20, v.X * m.M01 + v.Y * m.M11 + v.Z * m.M21, v.X * m.M02 + v.Y * m.M12 + v.Z * m.M22, v.X * m.M03 + v.Y * m.M13 + v.Z * m.M23); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M34i a, M34i b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M03 == b.M03 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M13 == b.M13 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22 && a.M23 == b.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M34i a, int s) { return a.M00 == s && a.M01 == s && a.M02 == s && a.M03 == s && a.M10 == s && a.M11 == s && a.M12 == s && a.M13 == s && a.M20 == s && a.M21 == s && a.M22 == s && a.M23 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(int s, M34i a) { return s == a.M00 && s == a.M01 && s == a.M02 && s == a.M03 && s == a.M10 && s == a.M11 && s == a.M12 && s == a.M13 && s == a.M20 && s == a.M21 && s == a.M22 && s == a.M23 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M34i a, M34i b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M34i m, int s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(int s, M34i m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01, M02, M03), HashCode.GetCombined(M10, M11, M12, M13), HashCode.GetCombined(M20, M21, M22, M23)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M34i other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M02.Equals(other.M02) && M03.Equals(other.M03) && M10.Equals(other.M10) && M11.Equals(other.M11) && M12.Equals(other.M12) && M13.Equals(other.M13) && M20.Equals(other.M20) && M21.Equals(other.M21) && M22.Equals(other.M22) && M23.Equals(other.M23); } public override readonly bool Equals(object other) => (other is M34i o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + betweenM + R2.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M34i Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M34i.FromRows( V4i.Parse(x[0]), V4i.Parse(x[1]), V4i.Parse(x[2]) ); } #endregion #region Matrix Operations #endregion #region Matrix Multiplication public static M34i operator *(M33i a, M34i b) { return new M34i( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22, a.M00 * b.M03 + a.M01 * b.M13 + a.M02 * b.M23, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22, a.M10 * b.M03 + a.M11 * b.M13 + a.M12 * b.M23, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22, a.M20 * b.M03 + a.M21 * b.M13 + a.M22 * b.M23 ); } public static M34i operator *(M34i a, M44i b) { return new M34i( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20 + a.M03 * b.M30, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21 + a.M03 * b.M31, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22 + a.M03 * b.M32, a.M00 * b.M03 + a.M01 * b.M13 + a.M02 * b.M23 + a.M03 * b.M33, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20 + a.M13 * b.M30, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21 + a.M13 * b.M31, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22 + a.M13 * b.M32, a.M10 * b.M03 + a.M11 * b.M13 + a.M12 * b.M23 + a.M13 * b.M33, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20 + a.M23 * b.M30, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21 + a.M23 * b.M31, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22 + a.M23 * b.M32, a.M20 * b.M03 + a.M21 * b.M13 + a.M22 * b.M23 + a.M23 * b.M33 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return (double)this[(int)y, (int)x]; } set { this[(int)y, (int)x] = (int)value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return (double)this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = (int)value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (int)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (int)value; } #endregion } public class M34iEqualityComparer : IEqualityComparer { public static readonly M34iEqualityComparer Default = new M34iEqualityComparer(); #region IEqualityComparer Members public bool Equals(M34i v0, M34i v1) { return v0 == v1; } public int GetHashCode(M34i v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this M34i m) => (m.C0.Length + m.C1.Length + m.C2.Length) / 3; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetScaleVector(this M34i m) => new V3d(m.C0.Length, m.C1.Length, m.C2.Length); #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Norm1(M34i m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(M34i m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NormMax(M34i m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NormMin(M34i m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this M34i m, double p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M02).Pow(p) + Fun.Abs(m.M03).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) + Fun.Abs(m.M12).Pow(p) + Fun.Abs(m.M13).Pow(p) + Fun.Abs(m.M20).Pow(p) + Fun.Abs(m.M21).Pow(p) + Fun.Abs(m.M22).Pow(p) + Fun.Abs(m.M23).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static int Distance1(this M34i a, M34i b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M02 - a.M02) + Fun.Abs(b.M03 - a.M03) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11) + Fun.Abs(b.M12 - a.M12) + Fun.Abs(b.M13 - a.M13) + Fun.Abs(b.M20 - a.M20) + Fun.Abs(b.M21 - a.M21) + Fun.Abs(b.M22 - a.M22) + Fun.Abs(b.M23 - a.M23); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static double Distance2(this M34i a, M34i b) { return Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M02 - a.M02) + Fun.Square(b.M03 - a.M03) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11) + Fun.Square(b.M12 - a.M12) + Fun.Square(b.M13 - a.M13) + Fun.Square(b.M20 - a.M20) + Fun.Square(b.M21 - a.M21) + Fun.Square(b.M22 - a.M22) + Fun.Square(b.M23 - a.M23)); } /// /// Returns the p-distance between two matrices. /// public static double Distance(this M34i a, M34i b, double p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M02 - a.M02).Pow(p) + Fun.Abs(b.M03 - a.M03).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) + Fun.Abs(b.M12 - a.M12).Pow(p) + Fun.Abs(b.M13 - a.M13).Pow(p) + Fun.Abs(b.M20 - a.M20).Pow(p) + Fun.Abs(b.M21 - a.M21).Pow(p) + Fun.Abs(b.M22 - a.M22).Pow(p) + Fun.Abs(b.M23 - a.M23).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static int DistanceMax(this M34i a, M34i b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02), Fun.Abs(b.M03 - a.M03)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12), Fun.Abs(b.M13 - a.M13)), Fun.Max( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22), Fun.Abs(b.M23 - a.M23))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static int DistanceMin(this M34i a, M34i b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02), Fun.Abs(b.M03 - a.M03)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12), Fun.Abs(b.M13 - a.M13)), Fun.Min( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22), Fun.Abs(b.M23 - a.M23))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Transform(this M34i m, V4i v) => m * v; /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i TransposedTransform(this M34i m, V3i v) => v * m; /// /// Transforms direction vector v (v.W is presumed 0.0) by matrix m. /// public static V3i TransformDir(this M34i m, V3i v) { return new V3i( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z ); } /// /// Transforms point p (v.W is presumed 1.0) by matrix m. /// public static V3i TransformPos(this M34i m, V3i p) { return new V3i( m.M00 * p.X + m.M01 * p.Y + m.M02 * p.Z + m.M03, m.M10 * p.X + m.M11 * p.Y + m.M12 * p.Z + m.M13, m.M20 * p.X + m.M21 * p.Y + m.M22 * p.Z + m.M23 ); } /// /// Multiplies two matrices as 4x4 matrices. /// public static M34i MultiplyAffine(this M34i a, M34i b) { return new M34i( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22, a.M00 * b.M03 + a.M01 * b.M13 + a.M02 * b.M23 + a.M03, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22, a.M10 * b.M03 + a.M11 * b.M13 + a.M12 * b.M23 + a.M13, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22, a.M20 * b.M03 + a.M21 * b.M13 + a.M22 * b.M23 + a.M23 ); } #endregion #region Operations /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V4i Row(this M34i m, int index) { int* ptr = &m.M00; return new V4i(ptr[index * 4], ptr[index * 4 + 1], ptr[index * 4 + 2], ptr[index * 4 + 3]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V3i Column(this M34i m, int index) { int* ptr = &m.M00; return new V3i(ptr[index], ptr[index + 4], ptr[index + 8]); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M34i a, M34i b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M02 < b.M02 && a.M03 < b.M03 && a.M10 < b.M10 && a.M11 < b.M11 && a.M12 < b.M12 && a.M13 < b.M13 && a.M20 < b.M20 && a.M21 < b.M21 && a.M22 < b.M22 && a.M23 < b.M23; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M34i m, int s) { return m.M00 < s && m.M01 < s && m.M02 < s && m.M03 < s && m.M10 < s && m.M11 < s && m.M12 < s && m.M13 < s && m.M20 < s && m.M21 < s && m.M22 < s && m.M23 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(int s, M34i m) { return s < m.M00 && s < m.M01 && s < m.M02 && s < m.M03 && s < m.M10 && s < m.M11 && s < m.M12 && s < m.M13 && s < m.M20 && s < m.M21 && s < m.M22 && s < m.M23; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M34i a, M34i b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M02 < b.M02 || a.M03 < b.M03 || a.M10 < b.M10 || a.M11 < b.M11 || a.M12 < b.M12 || a.M13 < b.M13 || a.M20 < b.M20 || a.M21 < b.M21 || a.M22 < b.M22 || a.M23 < b.M23; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M34i m, int s) { return m.M00 < s || m.M01 < s || m.M02 < s || m.M03 < s || m.M10 < s || m.M11 < s || m.M12 < s || m.M13 < s || m.M20 < s || m.M21 < s || m.M22 < s || m.M23 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(int s, M34i m) { return s < m.M00 || s < m.M01 || s < m.M02 || s < m.M03 || s < m.M10 || s < m.M11 || s < m.M12 || s < m.M13 || s < m.M20 || s < m.M21 || s < m.M22 || s < m.M23; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M34i a, M34i b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M02 > b.M02 && a.M03 > b.M03 && a.M10 > b.M10 && a.M11 > b.M11 && a.M12 > b.M12 && a.M13 > b.M13 && a.M20 > b.M20 && a.M21 > b.M21 && a.M22 > b.M22 && a.M23 > b.M23; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M34i m, int s) { return m.M00 > s && m.M01 > s && m.M02 > s && m.M03 > s && m.M10 > s && m.M11 > s && m.M12 > s && m.M13 > s && m.M20 > s && m.M21 > s && m.M22 > s && m.M23 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(int s, M34i m) { return s > m.M00 && s > m.M01 && s > m.M02 && s > m.M03 && s > m.M10 && s > m.M11 && s > m.M12 && s > m.M13 && s > m.M20 && s > m.M21 && s > m.M22 && s > m.M23; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M34i a, M34i b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M02 > b.M02 || a.M03 > b.M03 || a.M10 > b.M10 || a.M11 > b.M11 || a.M12 > b.M12 || a.M13 > b.M13 || a.M20 > b.M20 || a.M21 > b.M21 || a.M22 > b.M22 || a.M23 > b.M23; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M34i m, int s) { return m.M00 > s || m.M01 > s || m.M02 > s || m.M03 > s || m.M10 > s || m.M11 > s || m.M12 > s || m.M13 > s || m.M20 > s || m.M21 > s || m.M22 > s || m.M23 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(int s, M34i m) { return s > m.M00 || s > m.M01 || s > m.M02 || s > m.M03 || s > m.M10 || s > m.M11 || s > m.M12 || s > m.M13 || s > m.M20 || s > m.M21 || s > m.M22 || s > m.M23; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M34i a, M34i b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M02 <= b.M02 && a.M03 <= b.M03 && a.M10 <= b.M10 && a.M11 <= b.M11 && a.M12 <= b.M12 && a.M13 <= b.M13 && a.M20 <= b.M20 && a.M21 <= b.M21 && a.M22 <= b.M22 && a.M23 <= b.M23; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M34i m, int s) { return m.M00 <= s && m.M01 <= s && m.M02 <= s && m.M03 <= s && m.M10 <= s && m.M11 <= s && m.M12 <= s && m.M13 <= s && m.M20 <= s && m.M21 <= s && m.M22 <= s && m.M23 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(int s, M34i m) { return s <= m.M00 && s <= m.M01 && s <= m.M02 && s <= m.M03 && s <= m.M10 && s <= m.M11 && s <= m.M12 && s <= m.M13 && s <= m.M20 && s <= m.M21 && s <= m.M22 && s <= m.M23; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M34i a, M34i b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M02 <= b.M02 || a.M03 <= b.M03 || a.M10 <= b.M10 || a.M11 <= b.M11 || a.M12 <= b.M12 || a.M13 <= b.M13 || a.M20 <= b.M20 || a.M21 <= b.M21 || a.M22 <= b.M22 || a.M23 <= b.M23; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M34i m, int s) { return m.M00 <= s || m.M01 <= s || m.M02 <= s || m.M03 <= s || m.M10 <= s || m.M11 <= s || m.M12 <= s || m.M13 <= s || m.M20 <= s || m.M21 <= s || m.M22 <= s || m.M23 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(int s, M34i m) { return s <= m.M00 || s <= m.M01 || s <= m.M02 || s <= m.M03 || s <= m.M10 || s <= m.M11 || s <= m.M12 || s <= m.M13 || s <= m.M20 || s <= m.M21 || s <= m.M22 || s <= m.M23; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M34i a, M34i b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M02 >= b.M02 && a.M03 >= b.M03 && a.M10 >= b.M10 && a.M11 >= b.M11 && a.M12 >= b.M12 && a.M13 >= b.M13 && a.M20 >= b.M20 && a.M21 >= b.M21 && a.M22 >= b.M22 && a.M23 >= b.M23; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M34i m, int s) { return m.M00 >= s && m.M01 >= s && m.M02 >= s && m.M03 >= s && m.M10 >= s && m.M11 >= s && m.M12 >= s && m.M13 >= s && m.M20 >= s && m.M21 >= s && m.M22 >= s && m.M23 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(int s, M34i m) { return s >= m.M00 && s >= m.M01 && s >= m.M02 && s >= m.M03 && s >= m.M10 && s >= m.M11 && s >= m.M12 && s >= m.M13 && s >= m.M20 && s >= m.M21 && s >= m.M22 && s >= m.M23; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M34i a, M34i b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M02 >= b.M02 || a.M03 >= b.M03 || a.M10 >= b.M10 || a.M11 >= b.M11 || a.M12 >= b.M12 || a.M13 >= b.M13 || a.M20 >= b.M20 || a.M21 >= b.M21 || a.M22 >= b.M22 || a.M23 >= b.M23; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M34i m, int s) { return m.M00 >= s || m.M01 >= s || m.M02 >= s || m.M03 >= s || m.M10 >= s || m.M11 >= s || m.M12 >= s || m.M13 >= s || m.M20 >= s || m.M21 >= s || m.M22 >= s || m.M23 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(int s, M34i m) { return s >= m.M00 || s >= m.M01 || s >= m.M02 || s >= m.M03 || s >= m.M10 || s >= m.M11 || s >= m.M12 || s >= m.M13 || s >= m.M20 || s >= m.M21 || s >= m.M22 || s >= m.M23; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M34i a, M34i b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M03 == b.M03 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M13 == b.M13 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22 && a.M23 == b.M23; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M34i m, int s) { return m.M00 == s && m.M01 == s && m.M02 == s && m.M03 == s && m.M10 == s && m.M11 == s && m.M12 == s && m.M13 == s && m.M20 == s && m.M21 == s && m.M22 == s && m.M23 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(int s, M34i m) { return s == m.M00 && s == m.M01 && s == m.M02 && s == m.M03 && s == m.M10 && s == m.M11 && s == m.M12 && s == m.M13 && s == m.M20 && s == m.M21 && s == m.M22 && s == m.M23; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M34i a, M34i b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M02 == b.M02 || a.M03 == b.M03 || a.M10 == b.M10 || a.M11 == b.M11 || a.M12 == b.M12 || a.M13 == b.M13 || a.M20 == b.M20 || a.M21 == b.M21 || a.M22 == b.M22 || a.M23 == b.M23; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M34i m, int s) { return m.M00 == s || m.M01 == s || m.M02 == s || m.M03 == s || m.M10 == s || m.M11 == s || m.M12 == s || m.M13 == s || m.M20 == s || m.M21 == s || m.M22 == s || m.M23 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(int s, M34i m) { return s == m.M00 || s == m.M01 || s == m.M02 || s == m.M03 || s == m.M10 || s == m.M11 || s == m.M12 || s == m.M13 || s == m.M20 || s == m.M21 || s == m.M22 || s == m.M23; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M34i a, M34i b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M02 != b.M02 && a.M03 != b.M03 && a.M10 != b.M10 && a.M11 != b.M11 && a.M12 != b.M12 && a.M13 != b.M13 && a.M20 != b.M20 && a.M21 != b.M21 && a.M22 != b.M22 && a.M23 != b.M23; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M34i m, int s) { return m.M00 != s && m.M01 != s && m.M02 != s && m.M03 != s && m.M10 != s && m.M11 != s && m.M12 != s && m.M13 != s && m.M20 != s && m.M21 != s && m.M22 != s && m.M23 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(int s, M34i m) { return s != m.M00 && s != m.M01 && s != m.M02 && s != m.M03 && s != m.M10 && s != m.M11 && s != m.M12 && s != m.M13 && s != m.M20 && s != m.M21 && s != m.M22 && s != m.M23; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M34i a, M34i b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M02 != b.M02 || a.M03 != b.M03 || a.M10 != b.M10 || a.M11 != b.M11 || a.M12 != b.M12 || a.M13 != b.M13 || a.M20 != b.M20 || a.M21 != b.M21 || a.M22 != b.M22 || a.M23 != b.M23; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M34i m, int s) { return m.M00 != s || m.M01 != s || m.M02 != s || m.M03 != s || m.M10 != s || m.M11 != s || m.M12 != s || m.M13 != s || m.M20 != s || m.M21 != s || m.M22 != s || m.M23 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(int s, M34i m) { return s != m.M00 || s != m.M01 || s != m.M02 || s != m.M03 || s != m.M10 || s != m.M11 || s != m.M12 || s != m.M13 || s != m.M20 || s != m.M21 || s != m.M22 || s != m.M23; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M34i m0, M34i m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M02 < m1.M02) return -1; if (m0.M02 > m1.M02) return +1; if (m0.M03 < m1.M03) return -1; if (m0.M03 > m1.M03) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; if (m0.M12 < m1.M12) return -1; if (m0.M12 > m1.M12) return +1; if (m0.M13 < m1.M13) return -1; if (m0.M13 > m1.M13) return +1; if (m0.M20 < m1.M20) return -1; if (m0.M20 > m1.M20) return +1; if (m0.M21 < m1.M21) return -1; if (m0.M21 > m1.M21) return +1; if (m0.M22 < m1.M22) return -1; if (m0.M22 > m1.M22) return +1; if (m0.M23 < m1.M23) return -1; if (m0.M23 > m1.M23) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MinElement(M34i m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MaxElement(M34i m) => m.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M34i m, int epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M02.IsTiny(epsilon) || m.M03.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon) || m.M12.IsTiny(epsilon) || m.M13.IsTiny(epsilon) || m.M20.IsTiny(epsilon) || m.M21.IsTiny(epsilon) || m.M22.IsTiny(epsilon) || m.M23.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M34i m, int epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M02.IsTiny(epsilon) && m.M03.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon) && m.M12.IsTiny(epsilon) && m.M13.IsTiny(epsilon) && m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon) && m.M22.IsTiny(epsilon) && m.M23.IsTiny(epsilon); #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M34i a, M34i b, int epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M34i m, int epsilon) => Mat.AllTiny(m, epsilon); #endregion } public static class IRandomUniformM34iExtensions { #region IRandomUniform extensions for M34i /// /// Uses UniformInt() to generate the elements of an M34i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i UniformM34i(this IRandomUniform rnd) { return new M34i( rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt()); } /// /// Uses UniformIntNonZero() to generate the elements of an M34i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i UniformM34iNonZero(this IRandomUniform rnd) { return new M34i( rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero()); } /// /// Uses UniformInt(int) to generate the elements of an M34i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i UniformM34i(this IRandomUniform rnd, int size) { return new M34i( rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size)); } /// /// Uses UniformInt(int) to generate the elements of an M34i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34i UniformM34i(this IRandomUniform rnd, M34i size) { return new M34i( rnd.UniformInt(size.M00), rnd.UniformInt(size.M01), rnd.UniformInt(size.M02), rnd.UniformInt(size.M03), rnd.UniformInt(size.M10), rnd.UniformInt(size.M11), rnd.UniformInt(size.M12), rnd.UniformInt(size.M13), rnd.UniformInt(size.M20), rnd.UniformInt(size.M21), rnd.UniformInt(size.M22), rnd.UniformInt(size.M23)); } #endregion } #endregion #region M34l [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M34l : IEquatable, IValidity, IMatrix { [DataMember] public long M00, M01, M02, M03; [DataMember] public long M10, M11, M12, M13; [DataMember] public long M20, M21, M22, M23; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(long value) { M00 = value; M01 = 0; M02 = 0; M03 = 0; M10 = 0; M11 = value; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = value; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l( long m00, long m01, long m02, long m03, long m10, long m11, long m12, long m13, long m20, long m21, long m22, long m23) { M00 = m00; M01 = m01; M02 = m02; M03 = m03; M10 = m10; M11 = m11; M12 = m12; M13 = m13; M20 = m20; M21 = m21; M22 = m22; M23 = m23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(long[] a) { M00 = a[0]; M01 = a[1]; M02 = a[2]; M03 = a[3]; M10 = a[4]; M11 = a[5]; M12 = a[6]; M13 = a[7]; M20 = a[8]; M21 = a[9]; M22 = a[10]; M23 = a[11]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(long[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M02 = a[start + 2]; M03 = a[start + 3]; M10 = a[start + 4]; M11 = a[start + 5]; M12 = a[start + 6]; M13 = a[start + 7]; M20 = a[start + 8]; M21 = a[start + 9]; M22 = a[start + 10]; M23 = a[start + 11]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M33l m, V3l v) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = v.X; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = v.Y; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = v.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M22i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = 0; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M23i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M33i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = 0; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M34i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = (long)m.M03; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = (long)m.M13; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = (long)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M44i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = (long)m.M03; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = (long)m.M13; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = (long)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M22l m) { M00 = m.M00; M01 = m.M01; M02 = 0; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M23l m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M33l m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = 0; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M44l m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = m.M03; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = m.M13; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M22f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = 0; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M23f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M33f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = 0; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M34f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = (long)m.M03; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = (long)m.M13; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = (long)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M44f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = (long)m.M03; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = (long)m.M13; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = (long)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M22d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = 0; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M23d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M33d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = 0; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M34d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = (long)m.M03; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = (long)m.M13; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = (long)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34l(M44d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = (long)m.M03; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = (long)m.M13; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = (long)m.M23; } #endregion #region Conversions public static explicit operator M34l(M22i m) { return new M34l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = 0, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34l(M23i m) { return new M34l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34l(M33i m) { return new M34l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = 0, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = 0, }; } public static explicit operator M34l(M34i m) { return new M34l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = (long)m.M03, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = (long)m.M13, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = (long)m.M23, }; } public static explicit operator M34l(M44i m) { return new M34l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = (long)m.M03, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = (long)m.M13, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = (long)m.M23, }; } public static explicit operator M34l(M22l m) { return new M34l { M00 = m.M00, M01 = m.M01, M02 = 0, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34l(M23l m) { return new M34l { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34l(M33l m) { return new M34l { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = 0, M20 = m.M20, M21 = m.M21, M22 = m.M22, M23 = 0, }; } public static explicit operator M34l(M44l m) { return new M34l { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = m.M03, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = m.M13, M20 = m.M20, M21 = m.M21, M22 = m.M22, M23 = m.M23, }; } public static explicit operator M34l(M22f m) { return new M34l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = 0, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34l(M23f m) { return new M34l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34l(M33f m) { return new M34l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = 0, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = 0, }; } public static explicit operator M34l(M34f m) { return new M34l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = (long)m.M03, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = (long)m.M13, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = (long)m.M23, }; } public static explicit operator M34l(M44f m) { return new M34l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = (long)m.M03, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = (long)m.M13, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = (long)m.M23, }; } public static explicit operator M34l(M22d m) { return new M34l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = 0, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34l(M23d m) { return new M34l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34l(M33d m) { return new M34l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = 0, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = 0, }; } public static explicit operator M34l(M34d m) { return new M34l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = (long)m.M03, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = (long)m.M13, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = (long)m.M23, }; } public static explicit operator M34l(M44d m) { return new M34l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = (long)m.M03, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = (long)m.M13, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = (long)m.M23, }; } public static explicit operator M34l(int[] a) { return new M34l( (long)a[0], (long)a[1], (long)a[2], (long)a[3], (long)a[4], (long)a[5], (long)a[6], (long)a[7], (long)a[8], (long)a[9], (long)a[10], (long)a[11]); } public static explicit operator M34l(int[,] a) { return new M34l( (long)a[0, 0], (long)a[0, 1], (long)a[0, 2], (long)a[0, 3], (long)a[1, 0], (long)a[1, 1], (long)a[1, 2], (long)a[1, 3], (long)a[2, 0], (long)a[2, 1], (long)a[2, 2], (long)a[2, 3]); } public static explicit operator int[](M34l m) { return new int[] { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M03, (int)m.M10, (int)m.M11, (int)m.M12, (int)m.M13, (int)m.M20, (int)m.M21, (int)m.M22, (int)m.M23 }; } public static explicit operator int[,](M34l m) { return new int[,] { { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M03 }, { (int)m.M10, (int)m.M11, (int)m.M12, (int)m.M13 }, { (int)m.M20, (int)m.M21, (int)m.M22, (int)m.M23 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = (int)M00; array[index + 1] = (int)M01; array[index + 2] = (int)M02; array[index + 3] = (int)M03; array[index + 4] = (int)M10; array[index + 5] = (int)M11; array[index + 6] = (int)M12; array[index + 7] = (int)M13; array[index + 8] = (int)M20; array[index + 9] = (int)M21; array[index + 10] = (int)M22; array[index + 11] = (int)M23; } public static explicit operator M34l(long[] a) { return new M34l( a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11]); } public static explicit operator M34l(long[,] a) { return new M34l( a[0, 0], a[0, 1], a[0, 2], a[0, 3], a[1, 0], a[1, 1], a[1, 2], a[1, 3], a[2, 0], a[2, 1], a[2, 2], a[2, 3]); } public static explicit operator long[](M34l m) { return new long[] { m.M00, m.M01, m.M02, m.M03, m.M10, m.M11, m.M12, m.M13, m.M20, m.M21, m.M22, m.M23 }; } public static explicit operator long[,](M34l m) { return new long[,] { { m.M00, m.M01, m.M02, m.M03 }, { m.M10, m.M11, m.M12, m.M13 }, { m.M20, m.M21, m.M22, m.M23 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M02; array[index + 3] = M03; array[index + 4] = M10; array[index + 5] = M11; array[index + 6] = M12; array[index + 7] = M13; array[index + 8] = M20; array[index + 9] = M21; array[index + 10] = M22; array[index + 11] = M23; } public static explicit operator M34l(float[] a) { return new M34l( (long)a[0], (long)a[1], (long)a[2], (long)a[3], (long)a[4], (long)a[5], (long)a[6], (long)a[7], (long)a[8], (long)a[9], (long)a[10], (long)a[11]); } public static explicit operator M34l(float[,] a) { return new M34l( (long)a[0, 0], (long)a[0, 1], (long)a[0, 2], (long)a[0, 3], (long)a[1, 0], (long)a[1, 1], (long)a[1, 2], (long)a[1, 3], (long)a[2, 0], (long)a[2, 1], (long)a[2, 2], (long)a[2, 3]); } public static explicit operator float[](M34l m) { return new float[] { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M03, (float)m.M10, (float)m.M11, (float)m.M12, (float)m.M13, (float)m.M20, (float)m.M21, (float)m.M22, (float)m.M23 }; } public static explicit operator float[,](M34l m) { return new float[,] { { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M03 }, { (float)m.M10, (float)m.M11, (float)m.M12, (float)m.M13 }, { (float)m.M20, (float)m.M21, (float)m.M22, (float)m.M23 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = (float)M00; array[index + 1] = (float)M01; array[index + 2] = (float)M02; array[index + 3] = (float)M03; array[index + 4] = (float)M10; array[index + 5] = (float)M11; array[index + 6] = (float)M12; array[index + 7] = (float)M13; array[index + 8] = (float)M20; array[index + 9] = (float)M21; array[index + 10] = (float)M22; array[index + 11] = (float)M23; } public static explicit operator M34l(double[] a) { return new M34l( (long)a[0], (long)a[1], (long)a[2], (long)a[3], (long)a[4], (long)a[5], (long)a[6], (long)a[7], (long)a[8], (long)a[9], (long)a[10], (long)a[11]); } public static explicit operator M34l(double[,] a) { return new M34l( (long)a[0, 0], (long)a[0, 1], (long)a[0, 2], (long)a[0, 3], (long)a[1, 0], (long)a[1, 1], (long)a[1, 2], (long)a[1, 3], (long)a[2, 0], (long)a[2, 1], (long)a[2, 2], (long)a[2, 3]); } public static explicit operator double[](M34l m) { return new double[] { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M03, (double)m.M10, (double)m.M11, (double)m.M12, (double)m.M13, (double)m.M20, (double)m.M21, (double)m.M22, (double)m.M23 }; } public static explicit operator double[,](M34l m) { return new double[,] { { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M03 }, { (double)m.M10, (double)m.M11, (double)m.M12, (double)m.M13 }, { (double)m.M20, (double)m.M21, (double)m.M22, (double)m.M23 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = (double)M00; array[index + 1] = (double)M01; array[index + 2] = (double)M02; array[index + 3] = (double)M03; array[index + 4] = (double)M10; array[index + 5] = (double)M11; array[index + 6] = (double)M12; array[index + 7] = (double)M13; array[index + 8] = (double)M20; array[index + 9] = (double)M21; array[index + 10] = (double)M22; array[index + 11] = (double)M23; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34i Copy(Func element_fun) { return new M34i( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34i Copy(Func element_index0_index1_fun) { return new M34i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34l Copy(Func element_fun) { return new M34l( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34l Copy(Func element_index0_index1_fun) { return new M34l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34f Copy(Func element_fun) { return new M34f( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34f Copy(Func element_index0_index1_fun) { return new M34f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34d Copy(Func element_fun) { return new M34d( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34d Copy(Func element_index0_index1_fun) { return new M34d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3)); } public readonly long[] ToArray() { var array = new long[12]; array[0] = M00; array[1] = M01; array[2] = M02; array[3] = M03; array[4] = M10; array[5] = M11; array[6] = M12; array[7] = M13; array[8] = M20; array[9] = M21; array[10] = M22; array[11] = M23; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l FromCols(V3l col0, V3l col1, V3l col2, V3l col3) { return new M34l( col0.X, col1.X, col2.X, col3.X, col0.Y, col1.Y, col2.Y, col3.Y, col0.Z, col1.Z, col2.Z, col3.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l FromRows(V4l row0, V4l row1, V4l row2) { return new M34l( row0.X, row0.Y, row0.Z, row0.W, row1.X, row1.Y, row1.Z, row1.W, row2.X, row2.Y, row2.Z, row2.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l FromDiagonal(long value) { return new M34l( value, 0, 0, 0, 0, value, 0, 0, 0, 0, value, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l FromDiagonal(long m00, long m11, long m22) { return new M34l( m00, 0, 0, 0, 0, m11, 0, 0, 0, 0, m22, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l FromDiagonal(V3l s) { return new M34l( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0); } #region Scale /// /// Creates a homogenous transformation using a uniform scale. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l Scale(long s) { return new M34l( s, 0, 0, 0, 0, s, 0, 0, 0, 0, s, 0); } /// /// Creates a transformation using 3 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l Scale(long sX, long sY, long sZ) { return new M34l( sX, 0, 0, 0, 0, sY, 0, 0, 0, 0, sZ, 0); } /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l Scale(V3l s) { return new M34l( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0); } #endregion #region Translation /// /// Creates a transformation with the translational component given by 3 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l Translation(long tX, long tY, long tZ) { return new M34l( 1, 0, 0, tX, 0, 1, 0, tY, 0, 0, 1, tZ); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l Translation(V3l t) { return new M34l( 1, 0, 0, t.X, 0, 1, 0, t.Y, 0, 0, 1, t.Z); } #endregion #region Shearing /// /// Creates a shear transformation matrix along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l ShearXY(long factorX, long factorY) { return new M34l( 1, 0, factorX, 0, 0, 1, factorY, 0, 0, 0, 1, 0); } /// /// Creates a shear transformation matrix along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l ShearXZ(long factorX, long factorZ) { return new M34l( 1, factorX, 0, 0, 0, 1, 0, 0, 0, factorZ, 1, 0); } /// /// Creates a shear transformation matrix along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l ShearYZ(long factorY, long factorZ) { return new M34l( 1, 0, 0, 0, factorY, 1, 0, 0, factorZ, 0, 1, 0); } #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l DivideByInt(M34l m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M02; yield return M03; yield return M10; yield return M11; yield return M12; yield return M13; yield return M20; yield return M21; yield return M22; yield return M23; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; yield return R2; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; yield return C2; yield return C3; } } [XmlIgnore] public V4l R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4l( M00, M01, M02, M03); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; M02 = value.Z; M03 = value.W; } } [XmlIgnore] public V4l R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4l( M10, M11, M12, M13); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; M12 = value.Z; M13 = value.W; } } [XmlIgnore] public V4l R2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4l( M20, M21, M22, M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M20 = value.X; M21 = value.Y; M22 = value.Z; M23 = value.W; } } [XmlIgnore] public V3l C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3l( M00, M10, M20); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; M20 = value.Z; } } [XmlIgnore] public V3l C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3l( M01, M11, M21); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; M21 = value.Z; } } [XmlIgnore] public V3l C2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3l( M02, M12, M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M02 = value.X; M12 = value.Y; M22 = value.Z; } } [XmlIgnore] public V3l C3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3l( M03, M13, M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M03 = value.X; M13 = value.Y; M23 = value.Z; } } public readonly V3l Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V3l(M00, M11, M22); } /// /// Returns the minimum element of the matrix. /// public readonly long MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23); } /// /// Returns the maximum element of the matrix. /// public readonly long MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23); } public unsafe long this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (long* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (long* ptr = &M00) { ptr[index] = value; } } } public unsafe long this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (long* ptr = &M00) { return ptr[row * 4 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (long* ptr = &M00) { ptr[row * 4 + column] = value; } } } #endregion #region Constants public const int RowCount = 3; public const int ColumnCount = 4; public const int ElementCount = 3 * 4; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(3, 4); } public static M34l Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M34l(0); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly long Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M02) + Fun.Abs(M03) + Fun.Abs(M10) + Fun.Abs(M11) + Fun.Abs(M12) + Fun.Abs(M13) + Fun.Abs(M20) + Fun.Abs(M21) + Fun.Abs(M22) + Fun.Abs(M23); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly double Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M02 * M02 + M03 * M03 + M10 * M10 + M11 * M11 + M12 * M12 + M13 * M13 + M20 * M20 + M21 * M21 + M22 * M22 + M23 * M23); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly long NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02), Fun.Abs(M03)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12), Fun.Abs(M13)), Fun.Max( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22), Fun.Abs(M23))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly long NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02), Fun.Abs(M03)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12), Fun.Abs(M13)), Fun.Min( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22), Fun.Abs(M23))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator -(M34l m) { return new M34l( -m.M00, -m.M01, -m.M02, -m.M03, -m.M10, -m.M11, -m.M12, -m.M13, -m.M20, -m.M21, -m.M22, -m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator + (M34l a, M34l b) { return new M34l( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator + (M34l m, long s) { return new M34l( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator + (long s, M34l m) { return new M34l( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator + (M34l a, M34f b) { return new M34f( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator + (M34l m, float s) { return new M34f( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator + (float s, M34l m) { return new M34f( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator + (M34l a, M34d b) { return new M34d( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator + (M34l m, double s) { return new M34d( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator + (double s, M34l m) { return new M34d( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator - (M34l a, M34l b) { return new M34l( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator - (M34l m, long s) { return new M34l( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator - (long s, M34l m) { return new M34l( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator - (M34l a, M34f b) { return new M34f( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator - (M34l m, float s) { return new M34f( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator - (float s, M34l m) { return new M34f( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator - (M34l a, M34d b) { return new M34d( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator - (M34l m, double s) { return new M34d( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator - (double s, M34l m) { return new M34d( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator % (M34l a, M34l b) { return new M34l( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator % (M34l m, long s) { return new M34l( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator % (long s, M34l m) { return new M34l( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator % (M34l a, M34f b) { return new M34f( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator % (M34l m, float s) { return new M34f( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator % (float s, M34l m) { return new M34f( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator % (M34l a, M34d b) { return new M34d( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator % (M34l m, double s) { return new M34d( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator % (double s, M34l m) { return new M34d( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator / (M34l a, M34l b) { return new M34l( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator / (M34l m, long s) { return new M34l( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator / (long s, M34l m) { return new M34l( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator / (M34l a, M34f b) { return new M34f( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator / (M34l m, float s) { return new M34f( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator / (float s, M34l m) { return new M34f( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator / (M34l a, M34d b) { return new M34d( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator / (M34l m, double s) { return new M34d( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator / (double s, M34l m) { return new M34d( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator * (M34l m, long s) { return new M34l( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator * (long s, M34l m) { return new M34l( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator * (M34l m, float s) { return new M34f( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator * (float s, M34l m) { return new M34f( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator * (M34l m, double s) { return new M34d( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator * (double s, M34l m) { return new M34d( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23); } #endregion #region Bitwise Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator ~(M34l m) { return new M34l( ~m.M00, ~m.M01, ~m.M02, ~m.M03, ~m.M10, ~m.M11, ~m.M12, ~m.M13, ~m.M20, ~m.M21, ~m.M22, ~m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator <<(M34l a, int s) { return new M34l( a.M00 << s, a.M01 << s, a.M02 << s, a.M03 << s, a.M10 << s, a.M11 << s, a.M12 << s, a.M13 << s, a.M20 << s, a.M21 << s, a.M22 << s, a.M23 << s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator >>(M34l a, int s) { return new M34l( a.M00 >> s, a.M01 >> s, a.M02 >> s, a.M03 >> s, a.M10 >> s, a.M11 >> s, a.M12 >> s, a.M13 >> s, a.M20 >> s, a.M21 >> s, a.M22 >> s, a.M23 >> s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator &(M34l a, M34l b) { return new M34l( a.M00 & b.M00, a.M01 & b.M01, a.M02 & b.M02, a.M03 & b.M03, a.M10 & b.M10, a.M11 & b.M11, a.M12 & b.M12, a.M13 & b.M13, a.M20 & b.M20, a.M21 & b.M21, a.M22 & b.M22, a.M23 & b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator &(M34l a, long s) { return new M34l( a.M00 & s, a.M01 & s, a.M02 & s, a.M03 & s, a.M10 & s, a.M11 & s, a.M12 & s, a.M13 & s, a.M20 & s, a.M21 & s, a.M22 & s, a.M23 & s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator &(long s, M34l a) { return new M34l( s & a.M00, s & a.M01, s & a.M02, s & a.M03, s & a.M10, s & a.M11, s & a.M12, s & a.M13, s & a.M20, s & a.M21, s & a.M22, s & a.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator |(M34l a, M34l b) { return new M34l( a.M00 | b.M00, a.M01 | b.M01, a.M02 | b.M02, a.M03 | b.M03, a.M10 | b.M10, a.M11 | b.M11, a.M12 | b.M12, a.M13 | b.M13, a.M20 | b.M20, a.M21 | b.M21, a.M22 | b.M22, a.M23 | b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator |(M34l a, long s) { return new M34l( a.M00 | s, a.M01 | s, a.M02 | s, a.M03 | s, a.M10 | s, a.M11 | s, a.M12 | s, a.M13 | s, a.M20 | s, a.M21 | s, a.M22 | s, a.M23 | s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator |(long s, M34l a) { return new M34l( s | a.M00, s | a.M01, s | a.M02, s | a.M03, s | a.M10, s | a.M11, s | a.M12, s | a.M13, s | a.M20, s | a.M21, s | a.M22, s | a.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator ^(M34l a, M34l b) { return new M34l( a.M00 ^ b.M00, a.M01 ^ b.M01, a.M02 ^ b.M02, a.M03 ^ b.M03, a.M10 ^ b.M10, a.M11 ^ b.M11, a.M12 ^ b.M12, a.M13 ^ b.M13, a.M20 ^ b.M20, a.M21 ^ b.M21, a.M22 ^ b.M22, a.M23 ^ b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator ^(M34l a, long s) { return new M34l( a.M00 ^ s, a.M01 ^ s, a.M02 ^ s, a.M03 ^ s, a.M10 ^ s, a.M11 ^ s, a.M12 ^ s, a.M13 ^ s, a.M20 ^ s, a.M21 ^ s, a.M22 ^ s, a.M23 ^ s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l operator ^(long s, M34l a) { return new M34l( s ^ a.M00, s ^ a.M01, s ^ a.M02, s ^ a.M03, s ^ a.M10, s ^ a.M11, s ^ a.M12, s ^ a.M13, s ^ a.M20, s ^ a.M21, s ^ a.M22, s ^ a.M23); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M34l matrix with a V4l column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator *(M34l m, V4l v) { return new V3l( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z + m.M03 * v.W, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z + m.M13 * v.W, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z + m.M23 * v.W); } /// /// Multiplies a V3l row vector with a M34l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator *(V3l v, M34l m) { return new V4l( v.X * m.M00 + v.Y * m.M10 + v.Z * m.M20, v.X * m.M01 + v.Y * m.M11 + v.Z * m.M21, v.X * m.M02 + v.Y * m.M12 + v.Z * m.M22, v.X * m.M03 + v.Y * m.M13 + v.Z * m.M23); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M34l a, M34l b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M03 == b.M03 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M13 == b.M13 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22 && a.M23 == b.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M34l a, long s) { return a.M00 == s && a.M01 == s && a.M02 == s && a.M03 == s && a.M10 == s && a.M11 == s && a.M12 == s && a.M13 == s && a.M20 == s && a.M21 == s && a.M22 == s && a.M23 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(long s, M34l a) { return s == a.M00 && s == a.M01 && s == a.M02 && s == a.M03 && s == a.M10 && s == a.M11 && s == a.M12 && s == a.M13 && s == a.M20 && s == a.M21 && s == a.M22 && s == a.M23 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M34l a, M34l b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M34l m, long s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(long s, M34l m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01, M02, M03), HashCode.GetCombined(M10, M11, M12, M13), HashCode.GetCombined(M20, M21, M22, M23)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M34l other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M02.Equals(other.M02) && M03.Equals(other.M03) && M10.Equals(other.M10) && M11.Equals(other.M11) && M12.Equals(other.M12) && M13.Equals(other.M13) && M20.Equals(other.M20) && M21.Equals(other.M21) && M22.Equals(other.M22) && M23.Equals(other.M23); } public override readonly bool Equals(object other) => (other is M34l o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + betweenM + R2.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M34l Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M34l.FromRows( V4l.Parse(x[0]), V4l.Parse(x[1]), V4l.Parse(x[2]) ); } #endregion #region Matrix Operations #endregion #region Matrix Multiplication public static M34l operator *(M33l a, M34l b) { return new M34l( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22, a.M00 * b.M03 + a.M01 * b.M13 + a.M02 * b.M23, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22, a.M10 * b.M03 + a.M11 * b.M13 + a.M12 * b.M23, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22, a.M20 * b.M03 + a.M21 * b.M13 + a.M22 * b.M23 ); } public static M34l operator *(M34l a, M44l b) { return new M34l( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20 + a.M03 * b.M30, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21 + a.M03 * b.M31, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22 + a.M03 * b.M32, a.M00 * b.M03 + a.M01 * b.M13 + a.M02 * b.M23 + a.M03 * b.M33, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20 + a.M13 * b.M30, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21 + a.M13 * b.M31, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22 + a.M13 * b.M32, a.M10 * b.M03 + a.M11 * b.M13 + a.M12 * b.M23 + a.M13 * b.M33, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20 + a.M23 * b.M30, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21 + a.M23 * b.M31, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22 + a.M23 * b.M32, a.M20 * b.M03 + a.M21 * b.M13 + a.M22 * b.M23 + a.M23 * b.M33 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return (double)this[(int)y, (int)x]; } set { this[(int)y, (int)x] = (long)value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return (double)this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = (long)value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (long)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (long)value; } #endregion } public class M34lEqualityComparer : IEqualityComparer { public static readonly M34lEqualityComparer Default = new M34lEqualityComparer(); #region IEqualityComparer Members public bool Equals(M34l v0, M34l v1) { return v0 == v1; } public int GetHashCode(M34l v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this M34l m) => (m.C0.Length + m.C1.Length + m.C2.Length) / 3; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetScaleVector(this M34l m) => new V3d(m.C0.Length, m.C1.Length, m.C2.Length); #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Norm1(M34l m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(M34l m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NormMax(M34l m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NormMin(M34l m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this M34l m, double p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M02).Pow(p) + Fun.Abs(m.M03).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) + Fun.Abs(m.M12).Pow(p) + Fun.Abs(m.M13).Pow(p) + Fun.Abs(m.M20).Pow(p) + Fun.Abs(m.M21).Pow(p) + Fun.Abs(m.M22).Pow(p) + Fun.Abs(m.M23).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static long Distance1(this M34l a, M34l b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M02 - a.M02) + Fun.Abs(b.M03 - a.M03) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11) + Fun.Abs(b.M12 - a.M12) + Fun.Abs(b.M13 - a.M13) + Fun.Abs(b.M20 - a.M20) + Fun.Abs(b.M21 - a.M21) + Fun.Abs(b.M22 - a.M22) + Fun.Abs(b.M23 - a.M23); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static double Distance2(this M34l a, M34l b) { return Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M02 - a.M02) + Fun.Square(b.M03 - a.M03) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11) + Fun.Square(b.M12 - a.M12) + Fun.Square(b.M13 - a.M13) + Fun.Square(b.M20 - a.M20) + Fun.Square(b.M21 - a.M21) + Fun.Square(b.M22 - a.M22) + Fun.Square(b.M23 - a.M23)); } /// /// Returns the p-distance between two matrices. /// public static double Distance(this M34l a, M34l b, double p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M02 - a.M02).Pow(p) + Fun.Abs(b.M03 - a.M03).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) + Fun.Abs(b.M12 - a.M12).Pow(p) + Fun.Abs(b.M13 - a.M13).Pow(p) + Fun.Abs(b.M20 - a.M20).Pow(p) + Fun.Abs(b.M21 - a.M21).Pow(p) + Fun.Abs(b.M22 - a.M22).Pow(p) + Fun.Abs(b.M23 - a.M23).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static long DistanceMax(this M34l a, M34l b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02), Fun.Abs(b.M03 - a.M03)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12), Fun.Abs(b.M13 - a.M13)), Fun.Max( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22), Fun.Abs(b.M23 - a.M23))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static long DistanceMin(this M34l a, M34l b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02), Fun.Abs(b.M03 - a.M03)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12), Fun.Abs(b.M13 - a.M13)), Fun.Min( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22), Fun.Abs(b.M23 - a.M23))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Transform(this M34l m, V4l v) => m * v; /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l TransposedTransform(this M34l m, V3l v) => v * m; /// /// Transforms direction vector v (v.W is presumed 0.0) by matrix m. /// public static V3l TransformDir(this M34l m, V3l v) { return new V3l( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z ); } /// /// Transforms point p (v.W is presumed 1.0) by matrix m. /// public static V3l TransformPos(this M34l m, V3l p) { return new V3l( m.M00 * p.X + m.M01 * p.Y + m.M02 * p.Z + m.M03, m.M10 * p.X + m.M11 * p.Y + m.M12 * p.Z + m.M13, m.M20 * p.X + m.M21 * p.Y + m.M22 * p.Z + m.M23 ); } /// /// Multiplies two matrices as 4x4 matrices. /// public static M34l MultiplyAffine(this M34l a, M34l b) { return new M34l( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22, a.M00 * b.M03 + a.M01 * b.M13 + a.M02 * b.M23 + a.M03, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22, a.M10 * b.M03 + a.M11 * b.M13 + a.M12 * b.M23 + a.M13, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22, a.M20 * b.M03 + a.M21 * b.M13 + a.M22 * b.M23 + a.M23 ); } #endregion #region Operations /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V4l Row(this M34l m, int index) { long* ptr = &m.M00; return new V4l(ptr[index * 4], ptr[index * 4 + 1], ptr[index * 4 + 2], ptr[index * 4 + 3]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V3l Column(this M34l m, int index) { long* ptr = &m.M00; return new V3l(ptr[index], ptr[index + 4], ptr[index + 8]); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M34l a, M34l b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M02 < b.M02 && a.M03 < b.M03 && a.M10 < b.M10 && a.M11 < b.M11 && a.M12 < b.M12 && a.M13 < b.M13 && a.M20 < b.M20 && a.M21 < b.M21 && a.M22 < b.M22 && a.M23 < b.M23; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M34l m, long s) { return m.M00 < s && m.M01 < s && m.M02 < s && m.M03 < s && m.M10 < s && m.M11 < s && m.M12 < s && m.M13 < s && m.M20 < s && m.M21 < s && m.M22 < s && m.M23 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(long s, M34l m) { return s < m.M00 && s < m.M01 && s < m.M02 && s < m.M03 && s < m.M10 && s < m.M11 && s < m.M12 && s < m.M13 && s < m.M20 && s < m.M21 && s < m.M22 && s < m.M23; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M34l a, M34l b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M02 < b.M02 || a.M03 < b.M03 || a.M10 < b.M10 || a.M11 < b.M11 || a.M12 < b.M12 || a.M13 < b.M13 || a.M20 < b.M20 || a.M21 < b.M21 || a.M22 < b.M22 || a.M23 < b.M23; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M34l m, long s) { return m.M00 < s || m.M01 < s || m.M02 < s || m.M03 < s || m.M10 < s || m.M11 < s || m.M12 < s || m.M13 < s || m.M20 < s || m.M21 < s || m.M22 < s || m.M23 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(long s, M34l m) { return s < m.M00 || s < m.M01 || s < m.M02 || s < m.M03 || s < m.M10 || s < m.M11 || s < m.M12 || s < m.M13 || s < m.M20 || s < m.M21 || s < m.M22 || s < m.M23; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M34l a, M34l b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M02 > b.M02 && a.M03 > b.M03 && a.M10 > b.M10 && a.M11 > b.M11 && a.M12 > b.M12 && a.M13 > b.M13 && a.M20 > b.M20 && a.M21 > b.M21 && a.M22 > b.M22 && a.M23 > b.M23; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M34l m, long s) { return m.M00 > s && m.M01 > s && m.M02 > s && m.M03 > s && m.M10 > s && m.M11 > s && m.M12 > s && m.M13 > s && m.M20 > s && m.M21 > s && m.M22 > s && m.M23 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(long s, M34l m) { return s > m.M00 && s > m.M01 && s > m.M02 && s > m.M03 && s > m.M10 && s > m.M11 && s > m.M12 && s > m.M13 && s > m.M20 && s > m.M21 && s > m.M22 && s > m.M23; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M34l a, M34l b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M02 > b.M02 || a.M03 > b.M03 || a.M10 > b.M10 || a.M11 > b.M11 || a.M12 > b.M12 || a.M13 > b.M13 || a.M20 > b.M20 || a.M21 > b.M21 || a.M22 > b.M22 || a.M23 > b.M23; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M34l m, long s) { return m.M00 > s || m.M01 > s || m.M02 > s || m.M03 > s || m.M10 > s || m.M11 > s || m.M12 > s || m.M13 > s || m.M20 > s || m.M21 > s || m.M22 > s || m.M23 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(long s, M34l m) { return s > m.M00 || s > m.M01 || s > m.M02 || s > m.M03 || s > m.M10 || s > m.M11 || s > m.M12 || s > m.M13 || s > m.M20 || s > m.M21 || s > m.M22 || s > m.M23; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M34l a, M34l b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M02 <= b.M02 && a.M03 <= b.M03 && a.M10 <= b.M10 && a.M11 <= b.M11 && a.M12 <= b.M12 && a.M13 <= b.M13 && a.M20 <= b.M20 && a.M21 <= b.M21 && a.M22 <= b.M22 && a.M23 <= b.M23; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M34l m, long s) { return m.M00 <= s && m.M01 <= s && m.M02 <= s && m.M03 <= s && m.M10 <= s && m.M11 <= s && m.M12 <= s && m.M13 <= s && m.M20 <= s && m.M21 <= s && m.M22 <= s && m.M23 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(long s, M34l m) { return s <= m.M00 && s <= m.M01 && s <= m.M02 && s <= m.M03 && s <= m.M10 && s <= m.M11 && s <= m.M12 && s <= m.M13 && s <= m.M20 && s <= m.M21 && s <= m.M22 && s <= m.M23; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M34l a, M34l b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M02 <= b.M02 || a.M03 <= b.M03 || a.M10 <= b.M10 || a.M11 <= b.M11 || a.M12 <= b.M12 || a.M13 <= b.M13 || a.M20 <= b.M20 || a.M21 <= b.M21 || a.M22 <= b.M22 || a.M23 <= b.M23; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M34l m, long s) { return m.M00 <= s || m.M01 <= s || m.M02 <= s || m.M03 <= s || m.M10 <= s || m.M11 <= s || m.M12 <= s || m.M13 <= s || m.M20 <= s || m.M21 <= s || m.M22 <= s || m.M23 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(long s, M34l m) { return s <= m.M00 || s <= m.M01 || s <= m.M02 || s <= m.M03 || s <= m.M10 || s <= m.M11 || s <= m.M12 || s <= m.M13 || s <= m.M20 || s <= m.M21 || s <= m.M22 || s <= m.M23; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M34l a, M34l b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M02 >= b.M02 && a.M03 >= b.M03 && a.M10 >= b.M10 && a.M11 >= b.M11 && a.M12 >= b.M12 && a.M13 >= b.M13 && a.M20 >= b.M20 && a.M21 >= b.M21 && a.M22 >= b.M22 && a.M23 >= b.M23; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M34l m, long s) { return m.M00 >= s && m.M01 >= s && m.M02 >= s && m.M03 >= s && m.M10 >= s && m.M11 >= s && m.M12 >= s && m.M13 >= s && m.M20 >= s && m.M21 >= s && m.M22 >= s && m.M23 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(long s, M34l m) { return s >= m.M00 && s >= m.M01 && s >= m.M02 && s >= m.M03 && s >= m.M10 && s >= m.M11 && s >= m.M12 && s >= m.M13 && s >= m.M20 && s >= m.M21 && s >= m.M22 && s >= m.M23; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M34l a, M34l b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M02 >= b.M02 || a.M03 >= b.M03 || a.M10 >= b.M10 || a.M11 >= b.M11 || a.M12 >= b.M12 || a.M13 >= b.M13 || a.M20 >= b.M20 || a.M21 >= b.M21 || a.M22 >= b.M22 || a.M23 >= b.M23; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M34l m, long s) { return m.M00 >= s || m.M01 >= s || m.M02 >= s || m.M03 >= s || m.M10 >= s || m.M11 >= s || m.M12 >= s || m.M13 >= s || m.M20 >= s || m.M21 >= s || m.M22 >= s || m.M23 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(long s, M34l m) { return s >= m.M00 || s >= m.M01 || s >= m.M02 || s >= m.M03 || s >= m.M10 || s >= m.M11 || s >= m.M12 || s >= m.M13 || s >= m.M20 || s >= m.M21 || s >= m.M22 || s >= m.M23; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M34l a, M34l b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M03 == b.M03 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M13 == b.M13 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22 && a.M23 == b.M23; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M34l m, long s) { return m.M00 == s && m.M01 == s && m.M02 == s && m.M03 == s && m.M10 == s && m.M11 == s && m.M12 == s && m.M13 == s && m.M20 == s && m.M21 == s && m.M22 == s && m.M23 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(long s, M34l m) { return s == m.M00 && s == m.M01 && s == m.M02 && s == m.M03 && s == m.M10 && s == m.M11 && s == m.M12 && s == m.M13 && s == m.M20 && s == m.M21 && s == m.M22 && s == m.M23; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M34l a, M34l b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M02 == b.M02 || a.M03 == b.M03 || a.M10 == b.M10 || a.M11 == b.M11 || a.M12 == b.M12 || a.M13 == b.M13 || a.M20 == b.M20 || a.M21 == b.M21 || a.M22 == b.M22 || a.M23 == b.M23; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M34l m, long s) { return m.M00 == s || m.M01 == s || m.M02 == s || m.M03 == s || m.M10 == s || m.M11 == s || m.M12 == s || m.M13 == s || m.M20 == s || m.M21 == s || m.M22 == s || m.M23 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(long s, M34l m) { return s == m.M00 || s == m.M01 || s == m.M02 || s == m.M03 || s == m.M10 || s == m.M11 || s == m.M12 || s == m.M13 || s == m.M20 || s == m.M21 || s == m.M22 || s == m.M23; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M34l a, M34l b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M02 != b.M02 && a.M03 != b.M03 && a.M10 != b.M10 && a.M11 != b.M11 && a.M12 != b.M12 && a.M13 != b.M13 && a.M20 != b.M20 && a.M21 != b.M21 && a.M22 != b.M22 && a.M23 != b.M23; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M34l m, long s) { return m.M00 != s && m.M01 != s && m.M02 != s && m.M03 != s && m.M10 != s && m.M11 != s && m.M12 != s && m.M13 != s && m.M20 != s && m.M21 != s && m.M22 != s && m.M23 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(long s, M34l m) { return s != m.M00 && s != m.M01 && s != m.M02 && s != m.M03 && s != m.M10 && s != m.M11 && s != m.M12 && s != m.M13 && s != m.M20 && s != m.M21 && s != m.M22 && s != m.M23; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M34l a, M34l b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M02 != b.M02 || a.M03 != b.M03 || a.M10 != b.M10 || a.M11 != b.M11 || a.M12 != b.M12 || a.M13 != b.M13 || a.M20 != b.M20 || a.M21 != b.M21 || a.M22 != b.M22 || a.M23 != b.M23; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M34l m, long s) { return m.M00 != s || m.M01 != s || m.M02 != s || m.M03 != s || m.M10 != s || m.M11 != s || m.M12 != s || m.M13 != s || m.M20 != s || m.M21 != s || m.M22 != s || m.M23 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(long s, M34l m) { return s != m.M00 || s != m.M01 || s != m.M02 || s != m.M03 || s != m.M10 || s != m.M11 || s != m.M12 || s != m.M13 || s != m.M20 || s != m.M21 || s != m.M22 || s != m.M23; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M34l m0, M34l m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M02 < m1.M02) return -1; if (m0.M02 > m1.M02) return +1; if (m0.M03 < m1.M03) return -1; if (m0.M03 > m1.M03) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; if (m0.M12 < m1.M12) return -1; if (m0.M12 > m1.M12) return +1; if (m0.M13 < m1.M13) return -1; if (m0.M13 > m1.M13) return +1; if (m0.M20 < m1.M20) return -1; if (m0.M20 > m1.M20) return +1; if (m0.M21 < m1.M21) return -1; if (m0.M21 > m1.M21) return +1; if (m0.M22 < m1.M22) return -1; if (m0.M22 > m1.M22) return +1; if (m0.M23 < m1.M23) return -1; if (m0.M23 > m1.M23) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MinElement(M34l m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MaxElement(M34l m) => m.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M34l m, long epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M02.IsTiny(epsilon) || m.M03.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon) || m.M12.IsTiny(epsilon) || m.M13.IsTiny(epsilon) || m.M20.IsTiny(epsilon) || m.M21.IsTiny(epsilon) || m.M22.IsTiny(epsilon) || m.M23.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M34l m, long epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M02.IsTiny(epsilon) && m.M03.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon) && m.M12.IsTiny(epsilon) && m.M13.IsTiny(epsilon) && m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon) && m.M22.IsTiny(epsilon) && m.M23.IsTiny(epsilon); #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M34l a, M34l b, long epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M34l m, long epsilon) => Mat.AllTiny(m, epsilon); #endregion } public static class IRandomUniformM34lExtensions { #region IRandomUniform extensions for M34l /// /// Uses UniformLong() to generate the elements of an M34l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l UniformM34l(this IRandomUniform rnd) { return new M34l( rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong()); } /// /// Uses UniformLongNonZero() to generate the elements of an M34l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l UniformM34lNonZero(this IRandomUniform rnd) { return new M34l( rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero()); } /// /// Uses UniformLong(long) to generate the elements of an M34l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l UniformM34l(this IRandomUniform rnd, long size) { return new M34l( rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size)); } /// /// Uses UniformLong(long) to generate the elements of an M34l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34l UniformM34l(this IRandomUniform rnd, M34l size) { return new M34l( rnd.UniformLong(size.M00), rnd.UniformLong(size.M01), rnd.UniformLong(size.M02), rnd.UniformLong(size.M03), rnd.UniformLong(size.M10), rnd.UniformLong(size.M11), rnd.UniformLong(size.M12), rnd.UniformLong(size.M13), rnd.UniformLong(size.M20), rnd.UniformLong(size.M21), rnd.UniformLong(size.M22), rnd.UniformLong(size.M23)); } #endregion } #endregion #region M34f [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M34f : IEquatable, IValidity, IMatrix { [DataMember] public float M00, M01, M02, M03; [DataMember] public float M10, M11, M12, M13; [DataMember] public float M20, M21, M22, M23; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(float value) { M00 = value; M01 = 0; M02 = 0; M03 = 0; M10 = 0; M11 = value; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = value; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f( float m00, float m01, float m02, float m03, float m10, float m11, float m12, float m13, float m20, float m21, float m22, float m23) { M00 = m00; M01 = m01; M02 = m02; M03 = m03; M10 = m10; M11 = m11; M12 = m12; M13 = m13; M20 = m20; M21 = m21; M22 = m22; M23 = m23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(float[] a) { M00 = a[0]; M01 = a[1]; M02 = a[2]; M03 = a[3]; M10 = a[4]; M11 = a[5]; M12 = a[6]; M13 = a[7]; M20 = a[8]; M21 = a[9]; M22 = a[10]; M23 = a[11]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(float[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M02 = a[start + 2]; M03 = a[start + 3]; M10 = a[start + 4]; M11 = a[start + 5]; M12 = a[start + 6]; M13 = a[start + 7]; M20 = a[start + 8]; M21 = a[start + 9]; M22 = a[start + 10]; M23 = a[start + 11]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M33f m, V3f v) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = v.X; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = v.Y; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = v.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M22i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = 0; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M23i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M33i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = 0; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M34i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = (float)m.M03; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = (float)m.M13; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = (float)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M44i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = (float)m.M03; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = (float)m.M13; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = (float)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M22l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = 0; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M23l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M33l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = 0; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M34l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = (float)m.M03; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = (float)m.M13; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = (float)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M44l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = (float)m.M03; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = (float)m.M13; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = (float)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M22f m) { M00 = m.M00; M01 = m.M01; M02 = 0; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M23f m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M33f m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = 0; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M44f m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = m.M03; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = m.M13; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M22d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = 0; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M23d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M33d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = 0; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M34d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = (float)m.M03; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = (float)m.M13; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = (float)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34f(M44d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = (float)m.M03; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = (float)m.M13; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = (float)m.M23; } #endregion #region Conversions public static explicit operator M34f(M22i m) { return new M34f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = 0, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34f(M23i m) { return new M34f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34f(M33i m) { return new M34f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = 0, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = 0, }; } public static explicit operator M34f(M34i m) { return new M34f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = (float)m.M03, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = (float)m.M13, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = (float)m.M23, }; } public static explicit operator M34f(M44i m) { return new M34f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = (float)m.M03, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = (float)m.M13, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = (float)m.M23, }; } public static explicit operator M34f(M22l m) { return new M34f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = 0, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34f(M23l m) { return new M34f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34f(M33l m) { return new M34f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = 0, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = 0, }; } public static explicit operator M34f(M34l m) { return new M34f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = (float)m.M03, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = (float)m.M13, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = (float)m.M23, }; } public static explicit operator M34f(M44l m) { return new M34f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = (float)m.M03, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = (float)m.M13, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = (float)m.M23, }; } public static explicit operator M34f(M22f m) { return new M34f { M00 = m.M00, M01 = m.M01, M02 = 0, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34f(M23f m) { return new M34f { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34f(M33f m) { return new M34f { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = 0, M20 = m.M20, M21 = m.M21, M22 = m.M22, M23 = 0, }; } public static explicit operator M34f(M44f m) { return new M34f { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = m.M03, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = m.M13, M20 = m.M20, M21 = m.M21, M22 = m.M22, M23 = m.M23, }; } public static explicit operator M34f(M22d m) { return new M34f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = 0, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34f(M23d m) { return new M34f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34f(M33d m) { return new M34f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = 0, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = 0, }; } public static explicit operator M34f(M34d m) { return new M34f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = (float)m.M03, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = (float)m.M13, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = (float)m.M23, }; } public static explicit operator M34f(M44d m) { return new M34f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = (float)m.M03, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = (float)m.M13, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = (float)m.M23, }; } public static explicit operator M34f(int[] a) { return new M34f( (float)a[0], (float)a[1], (float)a[2], (float)a[3], (float)a[4], (float)a[5], (float)a[6], (float)a[7], (float)a[8], (float)a[9], (float)a[10], (float)a[11]); } public static explicit operator M34f(int[,] a) { return new M34f( (float)a[0, 0], (float)a[0, 1], (float)a[0, 2], (float)a[0, 3], (float)a[1, 0], (float)a[1, 1], (float)a[1, 2], (float)a[1, 3], (float)a[2, 0], (float)a[2, 1], (float)a[2, 2], (float)a[2, 3]); } public static explicit operator int[](M34f m) { return new int[] { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M03, (int)m.M10, (int)m.M11, (int)m.M12, (int)m.M13, (int)m.M20, (int)m.M21, (int)m.M22, (int)m.M23 }; } public static explicit operator int[,](M34f m) { return new int[,] { { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M03 }, { (int)m.M10, (int)m.M11, (int)m.M12, (int)m.M13 }, { (int)m.M20, (int)m.M21, (int)m.M22, (int)m.M23 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = (int)M00; array[index + 1] = (int)M01; array[index + 2] = (int)M02; array[index + 3] = (int)M03; array[index + 4] = (int)M10; array[index + 5] = (int)M11; array[index + 6] = (int)M12; array[index + 7] = (int)M13; array[index + 8] = (int)M20; array[index + 9] = (int)M21; array[index + 10] = (int)M22; array[index + 11] = (int)M23; } public static explicit operator M34f(long[] a) { return new M34f( (float)a[0], (float)a[1], (float)a[2], (float)a[3], (float)a[4], (float)a[5], (float)a[6], (float)a[7], (float)a[8], (float)a[9], (float)a[10], (float)a[11]); } public static explicit operator M34f(long[,] a) { return new M34f( (float)a[0, 0], (float)a[0, 1], (float)a[0, 2], (float)a[0, 3], (float)a[1, 0], (float)a[1, 1], (float)a[1, 2], (float)a[1, 3], (float)a[2, 0], (float)a[2, 1], (float)a[2, 2], (float)a[2, 3]); } public static explicit operator long[](M34f m) { return new long[] { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M03, (long)m.M10, (long)m.M11, (long)m.M12, (long)m.M13, (long)m.M20, (long)m.M21, (long)m.M22, (long)m.M23 }; } public static explicit operator long[,](M34f m) { return new long[,] { { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M03 }, { (long)m.M10, (long)m.M11, (long)m.M12, (long)m.M13 }, { (long)m.M20, (long)m.M21, (long)m.M22, (long)m.M23 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = (long)M00; array[index + 1] = (long)M01; array[index + 2] = (long)M02; array[index + 3] = (long)M03; array[index + 4] = (long)M10; array[index + 5] = (long)M11; array[index + 6] = (long)M12; array[index + 7] = (long)M13; array[index + 8] = (long)M20; array[index + 9] = (long)M21; array[index + 10] = (long)M22; array[index + 11] = (long)M23; } public static explicit operator M34f(float[] a) { return new M34f( a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11]); } public static explicit operator M34f(float[,] a) { return new M34f( a[0, 0], a[0, 1], a[0, 2], a[0, 3], a[1, 0], a[1, 1], a[1, 2], a[1, 3], a[2, 0], a[2, 1], a[2, 2], a[2, 3]); } public static explicit operator float[](M34f m) { return new float[] { m.M00, m.M01, m.M02, m.M03, m.M10, m.M11, m.M12, m.M13, m.M20, m.M21, m.M22, m.M23 }; } public static explicit operator float[,](M34f m) { return new float[,] { { m.M00, m.M01, m.M02, m.M03 }, { m.M10, m.M11, m.M12, m.M13 }, { m.M20, m.M21, m.M22, m.M23 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M02; array[index + 3] = M03; array[index + 4] = M10; array[index + 5] = M11; array[index + 6] = M12; array[index + 7] = M13; array[index + 8] = M20; array[index + 9] = M21; array[index + 10] = M22; array[index + 11] = M23; } public static explicit operator M34f(double[] a) { return new M34f( (float)a[0], (float)a[1], (float)a[2], (float)a[3], (float)a[4], (float)a[5], (float)a[6], (float)a[7], (float)a[8], (float)a[9], (float)a[10], (float)a[11]); } public static explicit operator M34f(double[,] a) { return new M34f( (float)a[0, 0], (float)a[0, 1], (float)a[0, 2], (float)a[0, 3], (float)a[1, 0], (float)a[1, 1], (float)a[1, 2], (float)a[1, 3], (float)a[2, 0], (float)a[2, 1], (float)a[2, 2], (float)a[2, 3]); } public static explicit operator double[](M34f m) { return new double[] { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M03, (double)m.M10, (double)m.M11, (double)m.M12, (double)m.M13, (double)m.M20, (double)m.M21, (double)m.M22, (double)m.M23 }; } public static explicit operator double[,](M34f m) { return new double[,] { { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M03 }, { (double)m.M10, (double)m.M11, (double)m.M12, (double)m.M13 }, { (double)m.M20, (double)m.M21, (double)m.M22, (double)m.M23 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = (double)M00; array[index + 1] = (double)M01; array[index + 2] = (double)M02; array[index + 3] = (double)M03; array[index + 4] = (double)M10; array[index + 5] = (double)M11; array[index + 6] = (double)M12; array[index + 7] = (double)M13; array[index + 8] = (double)M20; array[index + 9] = (double)M21; array[index + 10] = (double)M22; array[index + 11] = (double)M23; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34i Copy(Func element_fun) { return new M34i( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34i Copy(Func element_index0_index1_fun) { return new M34i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34l Copy(Func element_fun) { return new M34l( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34l Copy(Func element_index0_index1_fun) { return new M34l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34f Copy(Func element_fun) { return new M34f( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34f Copy(Func element_index0_index1_fun) { return new M34f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34d Copy(Func element_fun) { return new M34d( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34d Copy(Func element_index0_index1_fun) { return new M34d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3)); } public readonly float[] ToArray() { var array = new float[12]; array[0] = M00; array[1] = M01; array[2] = M02; array[3] = M03; array[4] = M10; array[5] = M11; array[6] = M12; array[7] = M13; array[8] = M20; array[9] = M21; array[10] = M22; array[11] = M23; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f FromCols(V3f col0, V3f col1, V3f col2, V3f col3) { return new M34f( col0.X, col1.X, col2.X, col3.X, col0.Y, col1.Y, col2.Y, col3.Y, col0.Z, col1.Z, col2.Z, col3.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f FromRows(V4f row0, V4f row1, V4f row2) { return new M34f( row0.X, row0.Y, row0.Z, row0.W, row1.X, row1.Y, row1.Z, row1.W, row2.X, row2.Y, row2.Z, row2.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f FromDiagonal(float value) { return new M34f( value, 0, 0, 0, 0, value, 0, 0, 0, 0, value, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f FromDiagonal(float m00, float m11, float m22) { return new M34f( m00, 0, 0, 0, 0, m11, 0, 0, 0, 0, m22, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f FromDiagonal(V3f s) { return new M34f( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0); } #region Scale /// /// Creates a homogenous transformation using a uniform scale. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f Scale(float s) { return new M34f( s, 0, 0, 0, 0, s, 0, 0, 0, 0, s, 0); } /// /// Creates a transformation using 3 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f Scale(float sX, float sY, float sZ) { return new M34f( sX, 0, 0, 0, 0, sY, 0, 0, 0, 0, sZ, 0); } /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f Scale(V3f s) { return new M34f( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0); } /// /// Creates a scaling transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f Scale(Scale3f s) { return new M34f( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0); } #endregion #region Translation /// /// Creates a transformation with the translational component given by 3 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f Translation(float tX, float tY, float tZ) { return new M34f( 1, 0, 0, tX, 0, 1, 0, tY, 0, 0, 1, tZ); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f Translation(V3f t) { return new M34f( 1, 0, 0, t.X, 0, 1, 0, t.Y, 0, 0, 1, t.Z); } /// /// Creates a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f Translation(Shift3f s) { return new M34f( 1, 0, 0, s.X, 0, 1, 0, s.Y, 0, 0, 1, s.Z); } #endregion #region Rotation /// /// Creates a 3D rotation matrix from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f Rotation(V3f normalizedAxis, float angleInRadians) { Debug.Assert(normalizedAxis.LengthSquared.ApproximateEquals(1, 1e-5f)); return (M34f)(Rot3f.Rotation(normalizedAxis, angleInRadians)); } /// /// Creates a 3D rotation matrix from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f RotationInDegrees(V3f normalizedAxis, float angleInDegrees) => Rotation(normalizedAxis, angleInDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f RotationEuler(float rollInRadians, float pitchInRadians, float yawInRadians) { return (M34f)(Rot3f.RotationEuler(rollInRadians, pitchInRadians, yawInRadians)); } /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f RotationEulerInDegrees(float rollInDegrees, float pitchInDegrees, float yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f RotationEuler(V3f rollPitchYawInRadians) => RotationEuler( rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f RotationEulerInDegrees(V3f rollPitchYawInDegrees) => RotationEulerInDegrees( rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a 3D rotation matrix which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f RotateInto(V3f from, V3f into) { Debug.Assert(from.LengthSquared.ApproximateEquals(1, 1e-5f)); Debug.Assert(into.LengthSquared.ApproximateEquals(1, 1e-5f)); return (M34f)(Rot3f.RotateInto(from, into)); } /// /// Creates a 3D rotation matrix for radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f RotationX(float angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M34f( 1, 0, 0, 0, 0, a, -b, 0, 0, b, a, 0); } /// /// Creates a 3D rotation matrix for degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f RotationXInDegrees(float angleDegrees) => RotationX(angleDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix for radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f RotationY(float angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M34f( a, 0, b, 0, 0, 1, 0, 0, -b, 0, a, 0); } /// /// Creates a 3D rotation matrix for degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f RotationYInDegrees(float angleDegrees) => RotationY(angleDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix for radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f RotationZ(float angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M34f( a, -b, 0, 0, b, a, 0, 0, 0, 0, 1, 0); } /// /// Creates a 3D rotation matrix for degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f RotationZInDegrees(float angleDegrees) => RotationZ(angleDegrees.RadiansFromDegrees()); #endregion #region Shearing /// /// Creates a shear transformation matrix along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f ShearXY(float factorX, float factorY) { return new M34f( 1, 0, factorX, 0, 0, 1, factorY, 0, 0, 0, 1, 0); } /// /// Creates a shear transformation matrix along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f ShearXZ(float factorX, float factorZ) { return new M34f( 1, factorX, 0, 0, 0, 1, 0, 0, 0, factorZ, 1, 0); } /// /// Creates a shear transformation matrix along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f ShearYZ(float factorY, float factorZ) { return new M34f( 1, 0, 0, 0, factorY, 1, 0, 0, factorZ, 0, 1, 0); } #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f DivideByInt(M34f m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M02; yield return M03; yield return M10; yield return M11; yield return M12; yield return M13; yield return M20; yield return M21; yield return M22; yield return M23; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; yield return R2; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; yield return C2; yield return C3; } } [XmlIgnore] public V4f R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4f( M00, M01, M02, M03); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; M02 = value.Z; M03 = value.W; } } [XmlIgnore] public V4f R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4f( M10, M11, M12, M13); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; M12 = value.Z; M13 = value.W; } } [XmlIgnore] public V4f R2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4f( M20, M21, M22, M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M20 = value.X; M21 = value.Y; M22 = value.Z; M23 = value.W; } } [XmlIgnore] public V3f C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3f( M00, M10, M20); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; M20 = value.Z; } } [XmlIgnore] public V3f C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3f( M01, M11, M21); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; M21 = value.Z; } } [XmlIgnore] public V3f C2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3f( M02, M12, M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M02 = value.X; M12 = value.Y; M22 = value.Z; } } [XmlIgnore] public V3f C3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3f( M03, M13, M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M03 = value.X; M13 = value.Y; M23 = value.Z; } } public readonly V3f Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V3f(M00, M11, M22); } /// /// Returns the minimum element of the matrix. /// public readonly float MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23); } /// /// Returns the maximum element of the matrix. /// public readonly float MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23); } public unsafe float this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &M00) { ptr[index] = value; } } } public unsafe float this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &M00) { return ptr[row * 4 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &M00) { ptr[row * 4 + column] = value; } } } public readonly bool AnyFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) || Fun.IsFinite(M01) || Fun.IsFinite(M02) || Fun.IsFinite(M03) || Fun.IsFinite(M10) || Fun.IsFinite(M11) || Fun.IsFinite(M12) || Fun.IsFinite(M13) || Fun.IsFinite(M20) || Fun.IsFinite(M21) || Fun.IsFinite(M22) || Fun.IsFinite(M23); } } public readonly bool AllFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) && Fun.IsFinite(M01) && Fun.IsFinite(M02) && Fun.IsFinite(M03) && Fun.IsFinite(M10) && Fun.IsFinite(M11) && Fun.IsFinite(M12) && Fun.IsFinite(M13) && Fun.IsFinite(M20) && Fun.IsFinite(M21) && Fun.IsFinite(M22) && Fun.IsFinite(M23); } } public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNaN(M00) || float.IsNaN(M01) || float.IsNaN(M02) || float.IsNaN(M03) || float.IsNaN(M10) || float.IsNaN(M11) || float.IsNaN(M12) || float.IsNaN(M13) || float.IsNaN(M20) || float.IsNaN(M21) || float.IsNaN(M22) || float.IsNaN(M23); } } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNaN(M00) && float.IsNaN(M01) && float.IsNaN(M02) && float.IsNaN(M03) && float.IsNaN(M10) && float.IsNaN(M11) && float.IsNaN(M12) && float.IsNaN(M13) && float.IsNaN(M20) && float.IsNaN(M21) && float.IsNaN(M22) && float.IsNaN(M23); } } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsInfinity(M00) || float.IsInfinity(M01) || float.IsInfinity(M02) || float.IsInfinity(M03) || float.IsInfinity(M10) || float.IsInfinity(M11) || float.IsInfinity(M12) || float.IsInfinity(M13) || float.IsInfinity(M20) || float.IsInfinity(M21) || float.IsInfinity(M22) || float.IsInfinity(M23); } } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsInfinity(M00) && float.IsInfinity(M01) && float.IsInfinity(M02) && float.IsInfinity(M03) && float.IsInfinity(M10) && float.IsInfinity(M11) && float.IsInfinity(M12) && float.IsInfinity(M13) && float.IsInfinity(M20) && float.IsInfinity(M21) && float.IsInfinity(M22) && float.IsInfinity(M23); } } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsPositiveInfinity(M00) || float.IsPositiveInfinity(M01) || float.IsPositiveInfinity(M02) || float.IsPositiveInfinity(M03) || float.IsPositiveInfinity(M10) || float.IsPositiveInfinity(M11) || float.IsPositiveInfinity(M12) || float.IsPositiveInfinity(M13) || float.IsPositiveInfinity(M20) || float.IsPositiveInfinity(M21) || float.IsPositiveInfinity(M22) || float.IsPositiveInfinity(M23); } } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsPositiveInfinity(M00) && float.IsPositiveInfinity(M01) && float.IsPositiveInfinity(M02) && float.IsPositiveInfinity(M03) && float.IsPositiveInfinity(M10) && float.IsPositiveInfinity(M11) && float.IsPositiveInfinity(M12) && float.IsPositiveInfinity(M13) && float.IsPositiveInfinity(M20) && float.IsPositiveInfinity(M21) && float.IsPositiveInfinity(M22) && float.IsPositiveInfinity(M23); } } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNegativeInfinity(M00) || float.IsNegativeInfinity(M01) || float.IsNegativeInfinity(M02) || float.IsNegativeInfinity(M03) || float.IsNegativeInfinity(M10) || float.IsNegativeInfinity(M11) || float.IsNegativeInfinity(M12) || float.IsNegativeInfinity(M13) || float.IsNegativeInfinity(M20) || float.IsNegativeInfinity(M21) || float.IsNegativeInfinity(M22) || float.IsNegativeInfinity(M23); } } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNegativeInfinity(M00) && float.IsNegativeInfinity(M01) && float.IsNegativeInfinity(M02) && float.IsNegativeInfinity(M03) && float.IsNegativeInfinity(M10) && float.IsNegativeInfinity(M11) && float.IsNegativeInfinity(M12) && float.IsNegativeInfinity(M13) && float.IsNegativeInfinity(M20) && float.IsNegativeInfinity(M21) && float.IsNegativeInfinity(M22) && float.IsNegativeInfinity(M23); } } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) || Fun.IsTiny(M01) || Fun.IsTiny(M02) || Fun.IsTiny(M03) || Fun.IsTiny(M10) || Fun.IsTiny(M11) || Fun.IsTiny(M12) || Fun.IsTiny(M13) || Fun.IsTiny(M20) || Fun.IsTiny(M21) || Fun.IsTiny(M22) || Fun.IsTiny(M23); } } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) && Fun.IsTiny(M01) && Fun.IsTiny(M02) && Fun.IsTiny(M03) && Fun.IsTiny(M10) && Fun.IsTiny(M11) && Fun.IsTiny(M12) && Fun.IsTiny(M13) && Fun.IsTiny(M20) && Fun.IsTiny(M21) && Fun.IsTiny(M22) && Fun.IsTiny(M23); } } /// /// Returns true if the absolute value of each element of the matrix is smaller than Constant<float>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any element of the matrix is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any element of the matrix is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any element of the matrix is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any element of the matrix is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all elements of the matrix are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Constants public const int RowCount = 3; public const int ColumnCount = 4; public const int ElementCount = 3 * 4; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(3, 4); } public static M34f Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M34f(0); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly float Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M02) + Fun.Abs(M03) + Fun.Abs(M10) + Fun.Abs(M11) + Fun.Abs(M12) + Fun.Abs(M13) + Fun.Abs(M20) + Fun.Abs(M21) + Fun.Abs(M22) + Fun.Abs(M23); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly float Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M02 * M02 + M03 * M03 + M10 * M10 + M11 * M11 + M12 * M12 + M13 * M13 + M20 * M20 + M21 * M21 + M22 * M22 + M23 * M23); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly float NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02), Fun.Abs(M03)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12), Fun.Abs(M13)), Fun.Max( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22), Fun.Abs(M23))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly float NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02), Fun.Abs(M03)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12), Fun.Abs(M13)), Fun.Min( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22), Fun.Abs(M23))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator -(M34f m) { return new M34f( -m.M00, -m.M01, -m.M02, -m.M03, -m.M10, -m.M11, -m.M12, -m.M13, -m.M20, -m.M21, -m.M22, -m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator + (M34f a, M34f b) { return new M34f( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator + (M34f m, float s) { return new M34f( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator + (float s, M34f m) { return new M34f( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator + (M34f a, M34d b) { return new M34d( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator + (M34f m, double s) { return new M34d( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator + (double s, M34f m) { return new M34d( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator - (M34f a, M34f b) { return new M34f( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator - (M34f m, float s) { return new M34f( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator - (float s, M34f m) { return new M34f( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator - (M34f a, M34d b) { return new M34d( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator - (M34f m, double s) { return new M34d( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator - (double s, M34f m) { return new M34d( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator % (M34f a, M34f b) { return new M34f( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator % (M34f m, float s) { return new M34f( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator % (float s, M34f m) { return new M34f( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator % (M34f a, M34d b) { return new M34d( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator % (M34f m, double s) { return new M34d( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator % (double s, M34f m) { return new M34d( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator / (M34f a, M34f b) { return new M34f( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator / (M34f m, float s) { return new M34f( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator / (float s, M34f m) { return new M34f( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator / (M34f a, M34d b) { return new M34d( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator / (M34f m, double s) { return new M34d( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator / (double s, M34f m) { return new M34d( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator * (M34f m, float s) { return new M34f( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator * (float s, M34f m) { return new M34f( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator * (M34f m, double s) { return new M34d( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator * (double s, M34f m) { return new M34d( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M34f matrix with a V4f column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator *(M34f m, V4f v) { return new V3f( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z + m.M03 * v.W, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z + m.M13 * v.W, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z + m.M23 * v.W); } /// /// Multiplies a V3f row vector with a M34f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator *(V3f v, M34f m) { return new V4f( v.X * m.M00 + v.Y * m.M10 + v.Z * m.M20, v.X * m.M01 + v.Y * m.M11 + v.Z * m.M21, v.X * m.M02 + v.Y * m.M12 + v.Z * m.M22, v.X * m.M03 + v.Y * m.M13 + v.Z * m.M23); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M34f a, M34f b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M03 == b.M03 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M13 == b.M13 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22 && a.M23 == b.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M34f a, float s) { return a.M00 == s && a.M01 == s && a.M02 == s && a.M03 == s && a.M10 == s && a.M11 == s && a.M12 == s && a.M13 == s && a.M20 == s && a.M21 == s && a.M22 == s && a.M23 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(float s, M34f a) { return s == a.M00 && s == a.M01 && s == a.M02 && s == a.M03 && s == a.M10 && s == a.M11 && s == a.M12 && s == a.M13 && s == a.M20 && s == a.M21 && s == a.M22 && s == a.M23 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M34f a, M34f b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M34f m, float s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(float s, M34f m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01, M02, M03), HashCode.GetCombined(M10, M11, M12, M13), HashCode.GetCombined(M20, M21, M22, M23)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M34f other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M02.Equals(other.M02) && M03.Equals(other.M03) && M10.Equals(other.M10) && M11.Equals(other.M11) && M12.Equals(other.M12) && M13.Equals(other.M13) && M20.Equals(other.M20) && M21.Equals(other.M21) && M22.Equals(other.M22) && M23.Equals(other.M23); } public override readonly bool Equals(object other) => (other is M34f o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + betweenM + R2.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M34f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M34f.FromRows( V4f.Parse(x[0]), V4f.Parse(x[1]), V4f.Parse(x[2]) ); } #endregion #region Matrix Operations #endregion #region Matrix Multiplication public static M34f operator *(M33f a, M34f b) { return new M34f( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22, a.M00 * b.M03 + a.M01 * b.M13 + a.M02 * b.M23, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22, a.M10 * b.M03 + a.M11 * b.M13 + a.M12 * b.M23, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22, a.M20 * b.M03 + a.M21 * b.M13 + a.M22 * b.M23 ); } public static M34f operator *(M34f a, M44f b) { return new M34f( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20 + a.M03 * b.M30, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21 + a.M03 * b.M31, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22 + a.M03 * b.M32, a.M00 * b.M03 + a.M01 * b.M13 + a.M02 * b.M23 + a.M03 * b.M33, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20 + a.M13 * b.M30, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21 + a.M13 * b.M31, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22 + a.M13 * b.M32, a.M10 * b.M03 + a.M11 * b.M13 + a.M12 * b.M23 + a.M13 * b.M33, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20 + a.M23 * b.M30, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21 + a.M23 * b.M31, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22 + a.M23 * b.M32, a.M20 * b.M03 + a.M21 * b.M13 + a.M22 * b.M23 + a.M23 * b.M33 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return (double)this[(int)y, (int)x]; } set { this[(int)y, (int)x] = (float)value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return (double)this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = (float)value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (float)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (float)value; } #endregion } public class M34fEqualityComparer : IEqualityComparer { public static readonly M34fEqualityComparer Default = new M34fEqualityComparer(); #region IEqualityComparer Members public bool Equals(M34f v0, M34f v1) { return v0 == v1; } public int GetHashCode(M34f v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetScale(this M34f m) => (m.C0.Length + m.C1.Length + m.C2.Length) / 3; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetScaleVector(this M34f m) => new V3f(m.C0.Length, m.C1.Length, m.C2.Length); /// /// Extracts the forward vector from the given view transformation matrix. /// NOTE: A left-handed coordinates system transformation is expected, /// where the view-space z-axis points in forward direction. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetViewDirectionLH(this M34f m) => m.R2.XYZ.Normalized; /// /// Extracts the forward vector from the given view transformation matrix. /// NOTE: A right-handed coordinates system transformation is expected, where /// the view-space z-axis points opposit the forward vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetViewDirectionRH(this M34f m) => -m.R2.XYZ.Normalized; /// /// Extracts the translation component of the given transformation matrix, which when given /// a model transformation represents the model origin in world position. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetModelOrigin(this M34f m) => m.C3; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm1(M34f m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm2(M34f m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormMax(M34f m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormMin(M34f m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm(this M34f m, float p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M02).Pow(p) + Fun.Abs(m.M03).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) + Fun.Abs(m.M12).Pow(p) + Fun.Abs(m.M13).Pow(p) + Fun.Abs(m.M20).Pow(p) + Fun.Abs(m.M21).Pow(p) + Fun.Abs(m.M22).Pow(p) + Fun.Abs(m.M23).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static float Distance1(this M34f a, M34f b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M02 - a.M02) + Fun.Abs(b.M03 - a.M03) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11) + Fun.Abs(b.M12 - a.M12) + Fun.Abs(b.M13 - a.M13) + Fun.Abs(b.M20 - a.M20) + Fun.Abs(b.M21 - a.M21) + Fun.Abs(b.M22 - a.M22) + Fun.Abs(b.M23 - a.M23); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static float Distance2(this M34f a, M34f b) { return (float)Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M02 - a.M02) + Fun.Square(b.M03 - a.M03) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11) + Fun.Square(b.M12 - a.M12) + Fun.Square(b.M13 - a.M13) + Fun.Square(b.M20 - a.M20) + Fun.Square(b.M21 - a.M21) + Fun.Square(b.M22 - a.M22) + Fun.Square(b.M23 - a.M23)); } /// /// Returns the p-distance between two matrices. /// public static float Distance(this M34f a, M34f b, float p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M02 - a.M02).Pow(p) + Fun.Abs(b.M03 - a.M03).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) + Fun.Abs(b.M12 - a.M12).Pow(p) + Fun.Abs(b.M13 - a.M13).Pow(p) + Fun.Abs(b.M20 - a.M20).Pow(p) + Fun.Abs(b.M21 - a.M21).Pow(p) + Fun.Abs(b.M22 - a.M22).Pow(p) + Fun.Abs(b.M23 - a.M23).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static float DistanceMax(this M34f a, M34f b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02), Fun.Abs(b.M03 - a.M03)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12), Fun.Abs(b.M13 - a.M13)), Fun.Max( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22), Fun.Abs(b.M23 - a.M23))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static float DistanceMin(this M34f a, M34f b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02), Fun.Abs(b.M03 - a.M03)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12), Fun.Abs(b.M13 - a.M13)), Fun.Min( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22), Fun.Abs(b.M23 - a.M23))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Transform(this M34f m, V4f v) => m * v; /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f TransposedTransform(this M34f m, V3f v) => v * m; /// /// Transforms direction vector v (v.W is presumed 0.0) by matrix m. /// public static V3f TransformDir(this M34f m, V3f v) { return new V3f( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z ); } /// /// Transforms point p (v.W is presumed 1.0) by matrix m. /// public static V3f TransformPos(this M34f m, V3f p) { return new V3f( m.M00 * p.X + m.M01 * p.Y + m.M02 * p.Z + m.M03, m.M10 * p.X + m.M11 * p.Y + m.M12 * p.Z + m.M13, m.M20 * p.X + m.M21 * p.Y + m.M22 * p.Z + m.M23 ); } /// /// Multiplies two matrices as 4x4 matrices. /// public static M34f MultiplyAffine(this M34f a, M34f b) { return new M34f( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22, a.M00 * b.M03 + a.M01 * b.M13 + a.M02 * b.M23 + a.M03, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22, a.M10 * b.M03 + a.M11 * b.M13 + a.M12 * b.M23 + a.M13, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22, a.M20 * b.M03 + a.M21 * b.M13 + a.M22 * b.M23 + a.M23 ); } #endregion #region Operations /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V4f Row(this M34f m, int index) { float* ptr = &m.M00; return new V4f(ptr[index * 4], ptr[index * 4 + 1], ptr[index * 4 + 2], ptr[index * 4 + 3]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V3f Column(this M34f m, int index) { float* ptr = &m.M00; return new V3f(ptr[index], ptr[index + 4], ptr[index + 8]); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M34f a, M34f b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M02 < b.M02 && a.M03 < b.M03 && a.M10 < b.M10 && a.M11 < b.M11 && a.M12 < b.M12 && a.M13 < b.M13 && a.M20 < b.M20 && a.M21 < b.M21 && a.M22 < b.M22 && a.M23 < b.M23; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M34f m, float s) { return m.M00 < s && m.M01 < s && m.M02 < s && m.M03 < s && m.M10 < s && m.M11 < s && m.M12 < s && m.M13 < s && m.M20 < s && m.M21 < s && m.M22 < s && m.M23 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(float s, M34f m) { return s < m.M00 && s < m.M01 && s < m.M02 && s < m.M03 && s < m.M10 && s < m.M11 && s < m.M12 && s < m.M13 && s < m.M20 && s < m.M21 && s < m.M22 && s < m.M23; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M34f a, M34f b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M02 < b.M02 || a.M03 < b.M03 || a.M10 < b.M10 || a.M11 < b.M11 || a.M12 < b.M12 || a.M13 < b.M13 || a.M20 < b.M20 || a.M21 < b.M21 || a.M22 < b.M22 || a.M23 < b.M23; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M34f m, float s) { return m.M00 < s || m.M01 < s || m.M02 < s || m.M03 < s || m.M10 < s || m.M11 < s || m.M12 < s || m.M13 < s || m.M20 < s || m.M21 < s || m.M22 < s || m.M23 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(float s, M34f m) { return s < m.M00 || s < m.M01 || s < m.M02 || s < m.M03 || s < m.M10 || s < m.M11 || s < m.M12 || s < m.M13 || s < m.M20 || s < m.M21 || s < m.M22 || s < m.M23; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M34f a, M34f b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M02 > b.M02 && a.M03 > b.M03 && a.M10 > b.M10 && a.M11 > b.M11 && a.M12 > b.M12 && a.M13 > b.M13 && a.M20 > b.M20 && a.M21 > b.M21 && a.M22 > b.M22 && a.M23 > b.M23; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M34f m, float s) { return m.M00 > s && m.M01 > s && m.M02 > s && m.M03 > s && m.M10 > s && m.M11 > s && m.M12 > s && m.M13 > s && m.M20 > s && m.M21 > s && m.M22 > s && m.M23 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(float s, M34f m) { return s > m.M00 && s > m.M01 && s > m.M02 && s > m.M03 && s > m.M10 && s > m.M11 && s > m.M12 && s > m.M13 && s > m.M20 && s > m.M21 && s > m.M22 && s > m.M23; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M34f a, M34f b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M02 > b.M02 || a.M03 > b.M03 || a.M10 > b.M10 || a.M11 > b.M11 || a.M12 > b.M12 || a.M13 > b.M13 || a.M20 > b.M20 || a.M21 > b.M21 || a.M22 > b.M22 || a.M23 > b.M23; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M34f m, float s) { return m.M00 > s || m.M01 > s || m.M02 > s || m.M03 > s || m.M10 > s || m.M11 > s || m.M12 > s || m.M13 > s || m.M20 > s || m.M21 > s || m.M22 > s || m.M23 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(float s, M34f m) { return s > m.M00 || s > m.M01 || s > m.M02 || s > m.M03 || s > m.M10 || s > m.M11 || s > m.M12 || s > m.M13 || s > m.M20 || s > m.M21 || s > m.M22 || s > m.M23; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M34f a, M34f b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M02 <= b.M02 && a.M03 <= b.M03 && a.M10 <= b.M10 && a.M11 <= b.M11 && a.M12 <= b.M12 && a.M13 <= b.M13 && a.M20 <= b.M20 && a.M21 <= b.M21 && a.M22 <= b.M22 && a.M23 <= b.M23; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M34f m, float s) { return m.M00 <= s && m.M01 <= s && m.M02 <= s && m.M03 <= s && m.M10 <= s && m.M11 <= s && m.M12 <= s && m.M13 <= s && m.M20 <= s && m.M21 <= s && m.M22 <= s && m.M23 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(float s, M34f m) { return s <= m.M00 && s <= m.M01 && s <= m.M02 && s <= m.M03 && s <= m.M10 && s <= m.M11 && s <= m.M12 && s <= m.M13 && s <= m.M20 && s <= m.M21 && s <= m.M22 && s <= m.M23; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M34f a, M34f b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M02 <= b.M02 || a.M03 <= b.M03 || a.M10 <= b.M10 || a.M11 <= b.M11 || a.M12 <= b.M12 || a.M13 <= b.M13 || a.M20 <= b.M20 || a.M21 <= b.M21 || a.M22 <= b.M22 || a.M23 <= b.M23; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M34f m, float s) { return m.M00 <= s || m.M01 <= s || m.M02 <= s || m.M03 <= s || m.M10 <= s || m.M11 <= s || m.M12 <= s || m.M13 <= s || m.M20 <= s || m.M21 <= s || m.M22 <= s || m.M23 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(float s, M34f m) { return s <= m.M00 || s <= m.M01 || s <= m.M02 || s <= m.M03 || s <= m.M10 || s <= m.M11 || s <= m.M12 || s <= m.M13 || s <= m.M20 || s <= m.M21 || s <= m.M22 || s <= m.M23; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M34f a, M34f b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M02 >= b.M02 && a.M03 >= b.M03 && a.M10 >= b.M10 && a.M11 >= b.M11 && a.M12 >= b.M12 && a.M13 >= b.M13 && a.M20 >= b.M20 && a.M21 >= b.M21 && a.M22 >= b.M22 && a.M23 >= b.M23; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M34f m, float s) { return m.M00 >= s && m.M01 >= s && m.M02 >= s && m.M03 >= s && m.M10 >= s && m.M11 >= s && m.M12 >= s && m.M13 >= s && m.M20 >= s && m.M21 >= s && m.M22 >= s && m.M23 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(float s, M34f m) { return s >= m.M00 && s >= m.M01 && s >= m.M02 && s >= m.M03 && s >= m.M10 && s >= m.M11 && s >= m.M12 && s >= m.M13 && s >= m.M20 && s >= m.M21 && s >= m.M22 && s >= m.M23; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M34f a, M34f b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M02 >= b.M02 || a.M03 >= b.M03 || a.M10 >= b.M10 || a.M11 >= b.M11 || a.M12 >= b.M12 || a.M13 >= b.M13 || a.M20 >= b.M20 || a.M21 >= b.M21 || a.M22 >= b.M22 || a.M23 >= b.M23; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M34f m, float s) { return m.M00 >= s || m.M01 >= s || m.M02 >= s || m.M03 >= s || m.M10 >= s || m.M11 >= s || m.M12 >= s || m.M13 >= s || m.M20 >= s || m.M21 >= s || m.M22 >= s || m.M23 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(float s, M34f m) { return s >= m.M00 || s >= m.M01 || s >= m.M02 || s >= m.M03 || s >= m.M10 || s >= m.M11 || s >= m.M12 || s >= m.M13 || s >= m.M20 || s >= m.M21 || s >= m.M22 || s >= m.M23; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M34f a, M34f b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M03 == b.M03 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M13 == b.M13 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22 && a.M23 == b.M23; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M34f m, float s) { return m.M00 == s && m.M01 == s && m.M02 == s && m.M03 == s && m.M10 == s && m.M11 == s && m.M12 == s && m.M13 == s && m.M20 == s && m.M21 == s && m.M22 == s && m.M23 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(float s, M34f m) { return s == m.M00 && s == m.M01 && s == m.M02 && s == m.M03 && s == m.M10 && s == m.M11 && s == m.M12 && s == m.M13 && s == m.M20 && s == m.M21 && s == m.M22 && s == m.M23; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M34f a, M34f b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M02 == b.M02 || a.M03 == b.M03 || a.M10 == b.M10 || a.M11 == b.M11 || a.M12 == b.M12 || a.M13 == b.M13 || a.M20 == b.M20 || a.M21 == b.M21 || a.M22 == b.M22 || a.M23 == b.M23; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M34f m, float s) { return m.M00 == s || m.M01 == s || m.M02 == s || m.M03 == s || m.M10 == s || m.M11 == s || m.M12 == s || m.M13 == s || m.M20 == s || m.M21 == s || m.M22 == s || m.M23 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(float s, M34f m) { return s == m.M00 || s == m.M01 || s == m.M02 || s == m.M03 || s == m.M10 || s == m.M11 || s == m.M12 || s == m.M13 || s == m.M20 || s == m.M21 || s == m.M22 || s == m.M23; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M34f a, M34f b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M02 != b.M02 && a.M03 != b.M03 && a.M10 != b.M10 && a.M11 != b.M11 && a.M12 != b.M12 && a.M13 != b.M13 && a.M20 != b.M20 && a.M21 != b.M21 && a.M22 != b.M22 && a.M23 != b.M23; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M34f m, float s) { return m.M00 != s && m.M01 != s && m.M02 != s && m.M03 != s && m.M10 != s && m.M11 != s && m.M12 != s && m.M13 != s && m.M20 != s && m.M21 != s && m.M22 != s && m.M23 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(float s, M34f m) { return s != m.M00 && s != m.M01 && s != m.M02 && s != m.M03 && s != m.M10 && s != m.M11 && s != m.M12 && s != m.M13 && s != m.M20 && s != m.M21 && s != m.M22 && s != m.M23; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M34f a, M34f b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M02 != b.M02 || a.M03 != b.M03 || a.M10 != b.M10 || a.M11 != b.M11 || a.M12 != b.M12 || a.M13 != b.M13 || a.M20 != b.M20 || a.M21 != b.M21 || a.M22 != b.M22 || a.M23 != b.M23; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M34f m, float s) { return m.M00 != s || m.M01 != s || m.M02 != s || m.M03 != s || m.M10 != s || m.M11 != s || m.M12 != s || m.M13 != s || m.M20 != s || m.M21 != s || m.M22 != s || m.M23 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(float s, M34f m) { return s != m.M00 || s != m.M01 || s != m.M02 || s != m.M03 || s != m.M10 || s != m.M11 || s != m.M12 || s != m.M13 || s != m.M20 || s != m.M21 || s != m.M22 || s != m.M23; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M34f m0, M34f m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M02 < m1.M02) return -1; if (m0.M02 > m1.M02) return +1; if (m0.M03 < m1.M03) return -1; if (m0.M03 > m1.M03) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; if (m0.M12 < m1.M12) return -1; if (m0.M12 > m1.M12) return +1; if (m0.M13 < m1.M13) return -1; if (m0.M13 > m1.M13) return +1; if (m0.M20 < m1.M20) return -1; if (m0.M20 > m1.M20) return +1; if (m0.M21 < m1.M21) return -1; if (m0.M21 > m1.M21) return +1; if (m0.M22 < m1.M22) return -1; if (m0.M22 > m1.M22) return +1; if (m0.M23 < m1.M23) return -1; if (m0.M23 > m1.M23) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MinElement(M34f m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MaxElement(M34f m) => m.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M34f m, float epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M02.IsTiny(epsilon) || m.M03.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon) || m.M12.IsTiny(epsilon) || m.M13.IsTiny(epsilon) || m.M20.IsTiny(epsilon) || m.M21.IsTiny(epsilon) || m.M22.IsTiny(epsilon) || m.M23.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M34f m, float epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M02.IsTiny(epsilon) && m.M03.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon) && m.M12.IsTiny(epsilon) && m.M13.IsTiny(epsilon) && m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon) && m.M22.IsTiny(epsilon) && m.M23.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyFinite(M34f m) => m.AnyFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllFinite(M34f m) => m.AllFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(M34f m) => m.AnyNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(M34f m) => m.AllNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(M34f m) => m.AnyInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(M34f m) => m.AllInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(M34f m) => m.AnyPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(M34f m) => m.AllPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(M34f m) => m.AnyNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(M34f m) => m.AllNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(M34f m) => m.AnyTiny; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(M34f m) => m.AllTiny; #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M34f a, M34f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M34f a, M34f b, float epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M34f m, float epsilon) => Mat.AllTiny(m, epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(M34f m) => m.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any element of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(M34f v) => v.IsNaN; /// /// Returns whether any element of the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(M34f v) => v.IsInfinity; /// /// Returns whether any element of the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(M34f v) => v.IsPositiveInfinity; /// /// Returns whether any element of the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(M34f v) => v.IsNegativeInfinity; /// /// Returns whether all elements of the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(M34f v) => v.IsFinite; #endregion } public static class IRandomUniformM34fExtensions { #region IRandomUniform extensions for M34f /// /// Uses UniformFloat() to generate the elements of an M34f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f UniformM34f(this IRandomUniform rnd) { return new M34f( rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat()); } /// /// Uses UniformFloatClosed() to generate the elements of an M34f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f UniformM34fClosed(this IRandomUniform rnd) { return new M34f( rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed()); } /// /// Uses UniformFloatOpen() to generate the elements of an M34f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f UniformM34fOpen(this IRandomUniform rnd) { return new M34f( rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen()); } #endregion } #endregion #region M34d [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M34d : IEquatable, IValidity, IMatrix { [DataMember] public double M00, M01, M02, M03; [DataMember] public double M10, M11, M12, M13; [DataMember] public double M20, M21, M22, M23; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(double value) { M00 = value; M01 = 0; M02 = 0; M03 = 0; M10 = 0; M11 = value; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = value; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d( double m00, double m01, double m02, double m03, double m10, double m11, double m12, double m13, double m20, double m21, double m22, double m23) { M00 = m00; M01 = m01; M02 = m02; M03 = m03; M10 = m10; M11 = m11; M12 = m12; M13 = m13; M20 = m20; M21 = m21; M22 = m22; M23 = m23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(double[] a) { M00 = a[0]; M01 = a[1]; M02 = a[2]; M03 = a[3]; M10 = a[4]; M11 = a[5]; M12 = a[6]; M13 = a[7]; M20 = a[8]; M21 = a[9]; M22 = a[10]; M23 = a[11]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(double[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M02 = a[start + 2]; M03 = a[start + 3]; M10 = a[start + 4]; M11 = a[start + 5]; M12 = a[start + 6]; M13 = a[start + 7]; M20 = a[start + 8]; M21 = a[start + 9]; M22 = a[start + 10]; M23 = a[start + 11]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M33d m, V3d v) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = v.X; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = v.Y; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = v.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M22i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = 0; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M23i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M33i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = 0; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M34i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = (double)m.M03; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = (double)m.M13; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = (double)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M44i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = (double)m.M03; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = (double)m.M13; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = (double)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M22l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = 0; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M23l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M33l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = 0; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M34l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = (double)m.M03; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = (double)m.M13; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = (double)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M44l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = (double)m.M03; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = (double)m.M13; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = (double)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M22f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = 0; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M23f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M33f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = 0; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M34f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = (double)m.M03; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = (double)m.M13; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = (double)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M44f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = (double)m.M03; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = (double)m.M13; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = (double)m.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M22d m) { M00 = m.M00; M01 = m.M01; M02 = 0; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M23d m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M33d m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = 0; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M34d(M44d m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = m.M03; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = m.M13; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = m.M23; } #endregion #region Conversions public static explicit operator M34d(M22i m) { return new M34d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = 0, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34d(M23i m) { return new M34d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34d(M33i m) { return new M34d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = 0, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = 0, }; } public static explicit operator M34d(M34i m) { return new M34d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = (double)m.M03, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = (double)m.M13, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = (double)m.M23, }; } public static explicit operator M34d(M44i m) { return new M34d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = (double)m.M03, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = (double)m.M13, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = (double)m.M23, }; } public static explicit operator M34d(M22l m) { return new M34d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = 0, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34d(M23l m) { return new M34d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34d(M33l m) { return new M34d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = 0, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = 0, }; } public static explicit operator M34d(M34l m) { return new M34d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = (double)m.M03, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = (double)m.M13, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = (double)m.M23, }; } public static explicit operator M34d(M44l m) { return new M34d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = (double)m.M03, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = (double)m.M13, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = (double)m.M23, }; } public static explicit operator M34d(M22f m) { return new M34d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = 0, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34d(M23f m) { return new M34d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34d(M33f m) { return new M34d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = 0, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = 0, }; } public static explicit operator M34d(M34f m) { return new M34d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = (double)m.M03, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = (double)m.M13, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = (double)m.M23, }; } public static explicit operator M34d(M44f m) { return new M34d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = (double)m.M03, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = (double)m.M13, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = (double)m.M23, }; } public static explicit operator M34d(M22d m) { return new M34d { M00 = m.M00, M01 = m.M01, M02 = 0, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34d(M23d m) { return new M34d { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, }; } public static explicit operator M34d(M33d m) { return new M34d { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = 0, M20 = m.M20, M21 = m.M21, M22 = m.M22, M23 = 0, }; } public static explicit operator M34d(M44d m) { return new M34d { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = m.M03, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = m.M13, M20 = m.M20, M21 = m.M21, M22 = m.M22, M23 = m.M23, }; } public static explicit operator M34d(int[] a) { return new M34d( (double)a[0], (double)a[1], (double)a[2], (double)a[3], (double)a[4], (double)a[5], (double)a[6], (double)a[7], (double)a[8], (double)a[9], (double)a[10], (double)a[11]); } public static explicit operator M34d(int[,] a) { return new M34d( (double)a[0, 0], (double)a[0, 1], (double)a[0, 2], (double)a[0, 3], (double)a[1, 0], (double)a[1, 1], (double)a[1, 2], (double)a[1, 3], (double)a[2, 0], (double)a[2, 1], (double)a[2, 2], (double)a[2, 3]); } public static explicit operator int[](M34d m) { return new int[] { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M03, (int)m.M10, (int)m.M11, (int)m.M12, (int)m.M13, (int)m.M20, (int)m.M21, (int)m.M22, (int)m.M23 }; } public static explicit operator int[,](M34d m) { return new int[,] { { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M03 }, { (int)m.M10, (int)m.M11, (int)m.M12, (int)m.M13 }, { (int)m.M20, (int)m.M21, (int)m.M22, (int)m.M23 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = (int)M00; array[index + 1] = (int)M01; array[index + 2] = (int)M02; array[index + 3] = (int)M03; array[index + 4] = (int)M10; array[index + 5] = (int)M11; array[index + 6] = (int)M12; array[index + 7] = (int)M13; array[index + 8] = (int)M20; array[index + 9] = (int)M21; array[index + 10] = (int)M22; array[index + 11] = (int)M23; } public static explicit operator M34d(long[] a) { return new M34d( (double)a[0], (double)a[1], (double)a[2], (double)a[3], (double)a[4], (double)a[5], (double)a[6], (double)a[7], (double)a[8], (double)a[9], (double)a[10], (double)a[11]); } public static explicit operator M34d(long[,] a) { return new M34d( (double)a[0, 0], (double)a[0, 1], (double)a[0, 2], (double)a[0, 3], (double)a[1, 0], (double)a[1, 1], (double)a[1, 2], (double)a[1, 3], (double)a[2, 0], (double)a[2, 1], (double)a[2, 2], (double)a[2, 3]); } public static explicit operator long[](M34d m) { return new long[] { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M03, (long)m.M10, (long)m.M11, (long)m.M12, (long)m.M13, (long)m.M20, (long)m.M21, (long)m.M22, (long)m.M23 }; } public static explicit operator long[,](M34d m) { return new long[,] { { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M03 }, { (long)m.M10, (long)m.M11, (long)m.M12, (long)m.M13 }, { (long)m.M20, (long)m.M21, (long)m.M22, (long)m.M23 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = (long)M00; array[index + 1] = (long)M01; array[index + 2] = (long)M02; array[index + 3] = (long)M03; array[index + 4] = (long)M10; array[index + 5] = (long)M11; array[index + 6] = (long)M12; array[index + 7] = (long)M13; array[index + 8] = (long)M20; array[index + 9] = (long)M21; array[index + 10] = (long)M22; array[index + 11] = (long)M23; } public static explicit operator M34d(float[] a) { return new M34d( (double)a[0], (double)a[1], (double)a[2], (double)a[3], (double)a[4], (double)a[5], (double)a[6], (double)a[7], (double)a[8], (double)a[9], (double)a[10], (double)a[11]); } public static explicit operator M34d(float[,] a) { return new M34d( (double)a[0, 0], (double)a[0, 1], (double)a[0, 2], (double)a[0, 3], (double)a[1, 0], (double)a[1, 1], (double)a[1, 2], (double)a[1, 3], (double)a[2, 0], (double)a[2, 1], (double)a[2, 2], (double)a[2, 3]); } public static explicit operator float[](M34d m) { return new float[] { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M03, (float)m.M10, (float)m.M11, (float)m.M12, (float)m.M13, (float)m.M20, (float)m.M21, (float)m.M22, (float)m.M23 }; } public static explicit operator float[,](M34d m) { return new float[,] { { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M03 }, { (float)m.M10, (float)m.M11, (float)m.M12, (float)m.M13 }, { (float)m.M20, (float)m.M21, (float)m.M22, (float)m.M23 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = (float)M00; array[index + 1] = (float)M01; array[index + 2] = (float)M02; array[index + 3] = (float)M03; array[index + 4] = (float)M10; array[index + 5] = (float)M11; array[index + 6] = (float)M12; array[index + 7] = (float)M13; array[index + 8] = (float)M20; array[index + 9] = (float)M21; array[index + 10] = (float)M22; array[index + 11] = (float)M23; } public static explicit operator M34d(double[] a) { return new M34d( a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11]); } public static explicit operator M34d(double[,] a) { return new M34d( a[0, 0], a[0, 1], a[0, 2], a[0, 3], a[1, 0], a[1, 1], a[1, 2], a[1, 3], a[2, 0], a[2, 1], a[2, 2], a[2, 3]); } public static explicit operator double[](M34d m) { return new double[] { m.M00, m.M01, m.M02, m.M03, m.M10, m.M11, m.M12, m.M13, m.M20, m.M21, m.M22, m.M23 }; } public static explicit operator double[,](M34d m) { return new double[,] { { m.M00, m.M01, m.M02, m.M03 }, { m.M10, m.M11, m.M12, m.M13 }, { m.M20, m.M21, m.M22, m.M23 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M02; array[index + 3] = M03; array[index + 4] = M10; array[index + 5] = M11; array[index + 6] = M12; array[index + 7] = M13; array[index + 8] = M20; array[index + 9] = M21; array[index + 10] = M22; array[index + 11] = M23; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34i Copy(Func element_fun) { return new M34i( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34i Copy(Func element_index0_index1_fun) { return new M34i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34l Copy(Func element_fun) { return new M34l( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34l Copy(Func element_index0_index1_fun) { return new M34l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34f Copy(Func element_fun) { return new M34f( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34f Copy(Func element_index0_index1_fun) { return new M34f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34d Copy(Func element_fun) { return new M34d( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M34d Copy(Func element_index0_index1_fun) { return new M34d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3)); } public readonly double[] ToArray() { var array = new double[12]; array[0] = M00; array[1] = M01; array[2] = M02; array[3] = M03; array[4] = M10; array[5] = M11; array[6] = M12; array[7] = M13; array[8] = M20; array[9] = M21; array[10] = M22; array[11] = M23; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d FromCols(V3d col0, V3d col1, V3d col2, V3d col3) { return new M34d( col0.X, col1.X, col2.X, col3.X, col0.Y, col1.Y, col2.Y, col3.Y, col0.Z, col1.Z, col2.Z, col3.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d FromRows(V4d row0, V4d row1, V4d row2) { return new M34d( row0.X, row0.Y, row0.Z, row0.W, row1.X, row1.Y, row1.Z, row1.W, row2.X, row2.Y, row2.Z, row2.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d FromDiagonal(double value) { return new M34d( value, 0, 0, 0, 0, value, 0, 0, 0, 0, value, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d FromDiagonal(double m00, double m11, double m22) { return new M34d( m00, 0, 0, 0, 0, m11, 0, 0, 0, 0, m22, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d FromDiagonal(V3d s) { return new M34d( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0); } #region Scale /// /// Creates a homogenous transformation using a uniform scale. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d Scale(double s) { return new M34d( s, 0, 0, 0, 0, s, 0, 0, 0, 0, s, 0); } /// /// Creates a transformation using 3 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d Scale(double sX, double sY, double sZ) { return new M34d( sX, 0, 0, 0, 0, sY, 0, 0, 0, 0, sZ, 0); } /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d Scale(V3d s) { return new M34d( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0); } /// /// Creates a scaling transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d Scale(Scale3d s) { return new M34d( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0); } #endregion #region Translation /// /// Creates a transformation with the translational component given by 3 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d Translation(double tX, double tY, double tZ) { return new M34d( 1, 0, 0, tX, 0, 1, 0, tY, 0, 0, 1, tZ); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d Translation(V3d t) { return new M34d( 1, 0, 0, t.X, 0, 1, 0, t.Y, 0, 0, 1, t.Z); } /// /// Creates a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d Translation(Shift3d s) { return new M34d( 1, 0, 0, s.X, 0, 1, 0, s.Y, 0, 0, 1, s.Z); } #endregion #region Rotation /// /// Creates a 3D rotation matrix from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d Rotation(V3d normalizedAxis, double angleInRadians) { Debug.Assert(normalizedAxis.LengthSquared.ApproximateEquals(1, 1e-10)); return (M34d)(Rot3d.Rotation(normalizedAxis, angleInRadians)); } /// /// Creates a 3D rotation matrix from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d RotationInDegrees(V3d normalizedAxis, double angleInDegrees) => Rotation(normalizedAxis, angleInDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d RotationEuler(double rollInRadians, double pitchInRadians, double yawInRadians) { return (M34d)(Rot3d.RotationEuler(rollInRadians, pitchInRadians, yawInRadians)); } /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d RotationEulerInDegrees(double rollInDegrees, double pitchInDegrees, double yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d RotationEuler(V3d rollPitchYawInRadians) => RotationEuler( rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d RotationEulerInDegrees(V3d rollPitchYawInDegrees) => RotationEulerInDegrees( rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a 3D rotation matrix which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d RotateInto(V3d from, V3d into) { Debug.Assert(from.LengthSquared.ApproximateEquals(1, 1e-10)); Debug.Assert(into.LengthSquared.ApproximateEquals(1, 1e-10)); return (M34d)(Rot3d.RotateInto(from, into)); } /// /// Creates a 3D rotation matrix for radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d RotationX(double angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M34d( 1, 0, 0, 0, 0, a, -b, 0, 0, b, a, 0); } /// /// Creates a 3D rotation matrix for degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d RotationXInDegrees(double angleDegrees) => RotationX(angleDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix for radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d RotationY(double angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M34d( a, 0, b, 0, 0, 1, 0, 0, -b, 0, a, 0); } /// /// Creates a 3D rotation matrix for degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d RotationYInDegrees(double angleDegrees) => RotationY(angleDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix for radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d RotationZ(double angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M34d( a, -b, 0, 0, b, a, 0, 0, 0, 0, 1, 0); } /// /// Creates a 3D rotation matrix for degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d RotationZInDegrees(double angleDegrees) => RotationZ(angleDegrees.RadiansFromDegrees()); #endregion #region Shearing /// /// Creates a shear transformation matrix along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d ShearXY(double factorX, double factorY) { return new M34d( 1, 0, factorX, 0, 0, 1, factorY, 0, 0, 0, 1, 0); } /// /// Creates a shear transformation matrix along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d ShearXZ(double factorX, double factorZ) { return new M34d( 1, factorX, 0, 0, 0, 1, 0, 0, 0, factorZ, 1, 0); } /// /// Creates a shear transformation matrix along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d ShearYZ(double factorY, double factorZ) { return new M34d( 1, 0, 0, 0, factorY, 1, 0, 0, factorZ, 0, 1, 0); } #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d DivideByInt(M34d m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M02; yield return M03; yield return M10; yield return M11; yield return M12; yield return M13; yield return M20; yield return M21; yield return M22; yield return M23; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; yield return R2; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; yield return C2; yield return C3; } } [XmlIgnore] public V4d R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4d( M00, M01, M02, M03); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; M02 = value.Z; M03 = value.W; } } [XmlIgnore] public V4d R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4d( M10, M11, M12, M13); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; M12 = value.Z; M13 = value.W; } } [XmlIgnore] public V4d R2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4d( M20, M21, M22, M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M20 = value.X; M21 = value.Y; M22 = value.Z; M23 = value.W; } } [XmlIgnore] public V3d C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3d( M00, M10, M20); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; M20 = value.Z; } } [XmlIgnore] public V3d C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3d( M01, M11, M21); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; M21 = value.Z; } } [XmlIgnore] public V3d C2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3d( M02, M12, M22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M02 = value.X; M12 = value.Y; M22 = value.Z; } } [XmlIgnore] public V3d C3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3d( M03, M13, M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M03 = value.X; M13 = value.Y; M23 = value.Z; } } public readonly V3d Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V3d(M00, M11, M22); } /// /// Returns the minimum element of the matrix. /// public readonly double MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23); } /// /// Returns the maximum element of the matrix. /// public readonly double MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23); } public unsafe double this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &M00) { ptr[index] = value; } } } public unsafe double this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &M00) { return ptr[row * 4 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &M00) { ptr[row * 4 + column] = value; } } } public readonly bool AnyFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) || Fun.IsFinite(M01) || Fun.IsFinite(M02) || Fun.IsFinite(M03) || Fun.IsFinite(M10) || Fun.IsFinite(M11) || Fun.IsFinite(M12) || Fun.IsFinite(M13) || Fun.IsFinite(M20) || Fun.IsFinite(M21) || Fun.IsFinite(M22) || Fun.IsFinite(M23); } } public readonly bool AllFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) && Fun.IsFinite(M01) && Fun.IsFinite(M02) && Fun.IsFinite(M03) && Fun.IsFinite(M10) && Fun.IsFinite(M11) && Fun.IsFinite(M12) && Fun.IsFinite(M13) && Fun.IsFinite(M20) && Fun.IsFinite(M21) && Fun.IsFinite(M22) && Fun.IsFinite(M23); } } public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNaN(M00) || double.IsNaN(M01) || double.IsNaN(M02) || double.IsNaN(M03) || double.IsNaN(M10) || double.IsNaN(M11) || double.IsNaN(M12) || double.IsNaN(M13) || double.IsNaN(M20) || double.IsNaN(M21) || double.IsNaN(M22) || double.IsNaN(M23); } } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNaN(M00) && double.IsNaN(M01) && double.IsNaN(M02) && double.IsNaN(M03) && double.IsNaN(M10) && double.IsNaN(M11) && double.IsNaN(M12) && double.IsNaN(M13) && double.IsNaN(M20) && double.IsNaN(M21) && double.IsNaN(M22) && double.IsNaN(M23); } } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsInfinity(M00) || double.IsInfinity(M01) || double.IsInfinity(M02) || double.IsInfinity(M03) || double.IsInfinity(M10) || double.IsInfinity(M11) || double.IsInfinity(M12) || double.IsInfinity(M13) || double.IsInfinity(M20) || double.IsInfinity(M21) || double.IsInfinity(M22) || double.IsInfinity(M23); } } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsInfinity(M00) && double.IsInfinity(M01) && double.IsInfinity(M02) && double.IsInfinity(M03) && double.IsInfinity(M10) && double.IsInfinity(M11) && double.IsInfinity(M12) && double.IsInfinity(M13) && double.IsInfinity(M20) && double.IsInfinity(M21) && double.IsInfinity(M22) && double.IsInfinity(M23); } } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsPositiveInfinity(M00) || double.IsPositiveInfinity(M01) || double.IsPositiveInfinity(M02) || double.IsPositiveInfinity(M03) || double.IsPositiveInfinity(M10) || double.IsPositiveInfinity(M11) || double.IsPositiveInfinity(M12) || double.IsPositiveInfinity(M13) || double.IsPositiveInfinity(M20) || double.IsPositiveInfinity(M21) || double.IsPositiveInfinity(M22) || double.IsPositiveInfinity(M23); } } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsPositiveInfinity(M00) && double.IsPositiveInfinity(M01) && double.IsPositiveInfinity(M02) && double.IsPositiveInfinity(M03) && double.IsPositiveInfinity(M10) && double.IsPositiveInfinity(M11) && double.IsPositiveInfinity(M12) && double.IsPositiveInfinity(M13) && double.IsPositiveInfinity(M20) && double.IsPositiveInfinity(M21) && double.IsPositiveInfinity(M22) && double.IsPositiveInfinity(M23); } } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNegativeInfinity(M00) || double.IsNegativeInfinity(M01) || double.IsNegativeInfinity(M02) || double.IsNegativeInfinity(M03) || double.IsNegativeInfinity(M10) || double.IsNegativeInfinity(M11) || double.IsNegativeInfinity(M12) || double.IsNegativeInfinity(M13) || double.IsNegativeInfinity(M20) || double.IsNegativeInfinity(M21) || double.IsNegativeInfinity(M22) || double.IsNegativeInfinity(M23); } } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNegativeInfinity(M00) && double.IsNegativeInfinity(M01) && double.IsNegativeInfinity(M02) && double.IsNegativeInfinity(M03) && double.IsNegativeInfinity(M10) && double.IsNegativeInfinity(M11) && double.IsNegativeInfinity(M12) && double.IsNegativeInfinity(M13) && double.IsNegativeInfinity(M20) && double.IsNegativeInfinity(M21) && double.IsNegativeInfinity(M22) && double.IsNegativeInfinity(M23); } } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) || Fun.IsTiny(M01) || Fun.IsTiny(M02) || Fun.IsTiny(M03) || Fun.IsTiny(M10) || Fun.IsTiny(M11) || Fun.IsTiny(M12) || Fun.IsTiny(M13) || Fun.IsTiny(M20) || Fun.IsTiny(M21) || Fun.IsTiny(M22) || Fun.IsTiny(M23); } } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) && Fun.IsTiny(M01) && Fun.IsTiny(M02) && Fun.IsTiny(M03) && Fun.IsTiny(M10) && Fun.IsTiny(M11) && Fun.IsTiny(M12) && Fun.IsTiny(M13) && Fun.IsTiny(M20) && Fun.IsTiny(M21) && Fun.IsTiny(M22) && Fun.IsTiny(M23); } } /// /// Returns true if the absolute value of each element of the matrix is smaller than Constant<double>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any element of the matrix is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any element of the matrix is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any element of the matrix is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any element of the matrix is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all elements of the matrix are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Constants public const int RowCount = 3; public const int ColumnCount = 4; public const int ElementCount = 3 * 4; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(3, 4); } public static M34d Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M34d(0); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly double Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M02) + Fun.Abs(M03) + Fun.Abs(M10) + Fun.Abs(M11) + Fun.Abs(M12) + Fun.Abs(M13) + Fun.Abs(M20) + Fun.Abs(M21) + Fun.Abs(M22) + Fun.Abs(M23); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly double Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M02 * M02 + M03 * M03 + M10 * M10 + M11 * M11 + M12 * M12 + M13 * M13 + M20 * M20 + M21 * M21 + M22 * M22 + M23 * M23); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly double NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02), Fun.Abs(M03)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12), Fun.Abs(M13)), Fun.Max( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22), Fun.Abs(M23))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly double NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02), Fun.Abs(M03)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12), Fun.Abs(M13)), Fun.Min( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22), Fun.Abs(M23))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator -(M34d m) { return new M34d( -m.M00, -m.M01, -m.M02, -m.M03, -m.M10, -m.M11, -m.M12, -m.M13, -m.M20, -m.M21, -m.M22, -m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator + (M34d a, M34d b) { return new M34d( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator + (M34d m, double s) { return new M34d( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator + (double s, M34d m) { return new M34d( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator - (M34d a, M34d b) { return new M34d( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator - (M34d m, double s) { return new M34d( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator - (double s, M34d m) { return new M34d( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator % (M34d a, M34d b) { return new M34d( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator % (M34d m, double s) { return new M34d( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator % (double s, M34d m) { return new M34d( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator / (M34d a, M34d b) { return new M34d( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator / (M34d m, double s) { return new M34d( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator / (double s, M34d m) { return new M34d( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator * (M34d m, double s) { return new M34d( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator * (double s, M34d m) { return new M34d( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M34d matrix with a V4d column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator *(M34d m, V4d v) { return new V3d( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z + m.M03 * v.W, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z + m.M13 * v.W, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z + m.M23 * v.W); } /// /// Multiplies a V3d row vector with a M34d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator *(V3d v, M34d m) { return new V4d( v.X * m.M00 + v.Y * m.M10 + v.Z * m.M20, v.X * m.M01 + v.Y * m.M11 + v.Z * m.M21, v.X * m.M02 + v.Y * m.M12 + v.Z * m.M22, v.X * m.M03 + v.Y * m.M13 + v.Z * m.M23); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M34d a, M34d b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M03 == b.M03 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M13 == b.M13 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22 && a.M23 == b.M23; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M34d a, double s) { return a.M00 == s && a.M01 == s && a.M02 == s && a.M03 == s && a.M10 == s && a.M11 == s && a.M12 == s && a.M13 == s && a.M20 == s && a.M21 == s && a.M22 == s && a.M23 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(double s, M34d a) { return s == a.M00 && s == a.M01 && s == a.M02 && s == a.M03 && s == a.M10 && s == a.M11 && s == a.M12 && s == a.M13 && s == a.M20 && s == a.M21 && s == a.M22 && s == a.M23 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M34d a, M34d b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M34d m, double s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(double s, M34d m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01, M02, M03), HashCode.GetCombined(M10, M11, M12, M13), HashCode.GetCombined(M20, M21, M22, M23)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M34d other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M02.Equals(other.M02) && M03.Equals(other.M03) && M10.Equals(other.M10) && M11.Equals(other.M11) && M12.Equals(other.M12) && M13.Equals(other.M13) && M20.Equals(other.M20) && M21.Equals(other.M21) && M22.Equals(other.M22) && M23.Equals(other.M23); } public override readonly bool Equals(object other) => (other is M34d o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + betweenM + R2.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M34d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M34d.FromRows( V4d.Parse(x[0]), V4d.Parse(x[1]), V4d.Parse(x[2]) ); } #endregion #region Matrix Operations #endregion #region Matrix Multiplication public static M34d operator *(M33d a, M34d b) { return new M34d( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22, a.M00 * b.M03 + a.M01 * b.M13 + a.M02 * b.M23, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22, a.M10 * b.M03 + a.M11 * b.M13 + a.M12 * b.M23, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22, a.M20 * b.M03 + a.M21 * b.M13 + a.M22 * b.M23 ); } public static M34d operator *(M34d a, M44d b) { return new M34d( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20 + a.M03 * b.M30, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21 + a.M03 * b.M31, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22 + a.M03 * b.M32, a.M00 * b.M03 + a.M01 * b.M13 + a.M02 * b.M23 + a.M03 * b.M33, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20 + a.M13 * b.M30, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21 + a.M13 * b.M31, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22 + a.M13 * b.M32, a.M10 * b.M03 + a.M11 * b.M13 + a.M12 * b.M23 + a.M13 * b.M33, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20 + a.M23 * b.M30, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21 + a.M23 * b.M31, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22 + a.M23 * b.M32, a.M20 * b.M03 + a.M21 * b.M13 + a.M22 * b.M23 + a.M23 * b.M33 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return this[(int)y, (int)x]; } set { this[(int)y, (int)x] = value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (double)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (double)value; } #endregion } public class M34dEqualityComparer : IEqualityComparer { public static readonly M34dEqualityComparer Default = new M34dEqualityComparer(); #region IEqualityComparer Members public bool Equals(M34d v0, M34d v1) { return v0 == v1; } public int GetHashCode(M34d v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this M34d m) => (m.C0.Length + m.C1.Length + m.C2.Length) / 3; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetScaleVector(this M34d m) => new V3d(m.C0.Length, m.C1.Length, m.C2.Length); /// /// Extracts the forward vector from the given view transformation matrix. /// NOTE: A left-handed coordinates system transformation is expected, /// where the view-space z-axis points in forward direction. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetViewDirectionLH(this M34d m) => m.R2.XYZ.Normalized; /// /// Extracts the forward vector from the given view transformation matrix. /// NOTE: A right-handed coordinates system transformation is expected, where /// the view-space z-axis points opposit the forward vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetViewDirectionRH(this M34d m) => -m.R2.XYZ.Normalized; /// /// Extracts the translation component of the given transformation matrix, which when given /// a model transformation represents the model origin in world position. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetModelOrigin(this M34d m) => m.C3; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm1(M34d m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(M34d m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormMax(M34d m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormMin(M34d m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this M34d m, double p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M02).Pow(p) + Fun.Abs(m.M03).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) + Fun.Abs(m.M12).Pow(p) + Fun.Abs(m.M13).Pow(p) + Fun.Abs(m.M20).Pow(p) + Fun.Abs(m.M21).Pow(p) + Fun.Abs(m.M22).Pow(p) + Fun.Abs(m.M23).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static double Distance1(this M34d a, M34d b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M02 - a.M02) + Fun.Abs(b.M03 - a.M03) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11) + Fun.Abs(b.M12 - a.M12) + Fun.Abs(b.M13 - a.M13) + Fun.Abs(b.M20 - a.M20) + Fun.Abs(b.M21 - a.M21) + Fun.Abs(b.M22 - a.M22) + Fun.Abs(b.M23 - a.M23); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static double Distance2(this M34d a, M34d b) { return Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M02 - a.M02) + Fun.Square(b.M03 - a.M03) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11) + Fun.Square(b.M12 - a.M12) + Fun.Square(b.M13 - a.M13) + Fun.Square(b.M20 - a.M20) + Fun.Square(b.M21 - a.M21) + Fun.Square(b.M22 - a.M22) + Fun.Square(b.M23 - a.M23)); } /// /// Returns the p-distance between two matrices. /// public static double Distance(this M34d a, M34d b, double p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M02 - a.M02).Pow(p) + Fun.Abs(b.M03 - a.M03).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) + Fun.Abs(b.M12 - a.M12).Pow(p) + Fun.Abs(b.M13 - a.M13).Pow(p) + Fun.Abs(b.M20 - a.M20).Pow(p) + Fun.Abs(b.M21 - a.M21).Pow(p) + Fun.Abs(b.M22 - a.M22).Pow(p) + Fun.Abs(b.M23 - a.M23).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static double DistanceMax(this M34d a, M34d b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02), Fun.Abs(b.M03 - a.M03)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12), Fun.Abs(b.M13 - a.M13)), Fun.Max( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22), Fun.Abs(b.M23 - a.M23))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static double DistanceMin(this M34d a, M34d b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02), Fun.Abs(b.M03 - a.M03)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12), Fun.Abs(b.M13 - a.M13)), Fun.Min( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22), Fun.Abs(b.M23 - a.M23))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Transform(this M34d m, V4d v) => m * v; /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d TransposedTransform(this M34d m, V3d v) => v * m; /// /// Transforms direction vector v (v.W is presumed 0.0) by matrix m. /// public static V3d TransformDir(this M34d m, V3d v) { return new V3d( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z ); } /// /// Transforms point p (v.W is presumed 1.0) by matrix m. /// public static V3d TransformPos(this M34d m, V3d p) { return new V3d( m.M00 * p.X + m.M01 * p.Y + m.M02 * p.Z + m.M03, m.M10 * p.X + m.M11 * p.Y + m.M12 * p.Z + m.M13, m.M20 * p.X + m.M21 * p.Y + m.M22 * p.Z + m.M23 ); } /// /// Multiplies two matrices as 4x4 matrices. /// public static M34d MultiplyAffine(this M34d a, M34d b) { return new M34d( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22, a.M00 * b.M03 + a.M01 * b.M13 + a.M02 * b.M23 + a.M03, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22, a.M10 * b.M03 + a.M11 * b.M13 + a.M12 * b.M23 + a.M13, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22, a.M20 * b.M03 + a.M21 * b.M13 + a.M22 * b.M23 + a.M23 ); } #endregion #region Operations /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V4d Row(this M34d m, int index) { double* ptr = &m.M00; return new V4d(ptr[index * 4], ptr[index * 4 + 1], ptr[index * 4 + 2], ptr[index * 4 + 3]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V3d Column(this M34d m, int index) { double* ptr = &m.M00; return new V3d(ptr[index], ptr[index + 4], ptr[index + 8]); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M34d a, M34d b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M02 < b.M02 && a.M03 < b.M03 && a.M10 < b.M10 && a.M11 < b.M11 && a.M12 < b.M12 && a.M13 < b.M13 && a.M20 < b.M20 && a.M21 < b.M21 && a.M22 < b.M22 && a.M23 < b.M23; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M34d m, double s) { return m.M00 < s && m.M01 < s && m.M02 < s && m.M03 < s && m.M10 < s && m.M11 < s && m.M12 < s && m.M13 < s && m.M20 < s && m.M21 < s && m.M22 < s && m.M23 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(double s, M34d m) { return s < m.M00 && s < m.M01 && s < m.M02 && s < m.M03 && s < m.M10 && s < m.M11 && s < m.M12 && s < m.M13 && s < m.M20 && s < m.M21 && s < m.M22 && s < m.M23; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M34d a, M34d b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M02 < b.M02 || a.M03 < b.M03 || a.M10 < b.M10 || a.M11 < b.M11 || a.M12 < b.M12 || a.M13 < b.M13 || a.M20 < b.M20 || a.M21 < b.M21 || a.M22 < b.M22 || a.M23 < b.M23; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M34d m, double s) { return m.M00 < s || m.M01 < s || m.M02 < s || m.M03 < s || m.M10 < s || m.M11 < s || m.M12 < s || m.M13 < s || m.M20 < s || m.M21 < s || m.M22 < s || m.M23 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(double s, M34d m) { return s < m.M00 || s < m.M01 || s < m.M02 || s < m.M03 || s < m.M10 || s < m.M11 || s < m.M12 || s < m.M13 || s < m.M20 || s < m.M21 || s < m.M22 || s < m.M23; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M34d a, M34d b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M02 > b.M02 && a.M03 > b.M03 && a.M10 > b.M10 && a.M11 > b.M11 && a.M12 > b.M12 && a.M13 > b.M13 && a.M20 > b.M20 && a.M21 > b.M21 && a.M22 > b.M22 && a.M23 > b.M23; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M34d m, double s) { return m.M00 > s && m.M01 > s && m.M02 > s && m.M03 > s && m.M10 > s && m.M11 > s && m.M12 > s && m.M13 > s && m.M20 > s && m.M21 > s && m.M22 > s && m.M23 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(double s, M34d m) { return s > m.M00 && s > m.M01 && s > m.M02 && s > m.M03 && s > m.M10 && s > m.M11 && s > m.M12 && s > m.M13 && s > m.M20 && s > m.M21 && s > m.M22 && s > m.M23; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M34d a, M34d b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M02 > b.M02 || a.M03 > b.M03 || a.M10 > b.M10 || a.M11 > b.M11 || a.M12 > b.M12 || a.M13 > b.M13 || a.M20 > b.M20 || a.M21 > b.M21 || a.M22 > b.M22 || a.M23 > b.M23; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M34d m, double s) { return m.M00 > s || m.M01 > s || m.M02 > s || m.M03 > s || m.M10 > s || m.M11 > s || m.M12 > s || m.M13 > s || m.M20 > s || m.M21 > s || m.M22 > s || m.M23 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(double s, M34d m) { return s > m.M00 || s > m.M01 || s > m.M02 || s > m.M03 || s > m.M10 || s > m.M11 || s > m.M12 || s > m.M13 || s > m.M20 || s > m.M21 || s > m.M22 || s > m.M23; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M34d a, M34d b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M02 <= b.M02 && a.M03 <= b.M03 && a.M10 <= b.M10 && a.M11 <= b.M11 && a.M12 <= b.M12 && a.M13 <= b.M13 && a.M20 <= b.M20 && a.M21 <= b.M21 && a.M22 <= b.M22 && a.M23 <= b.M23; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M34d m, double s) { return m.M00 <= s && m.M01 <= s && m.M02 <= s && m.M03 <= s && m.M10 <= s && m.M11 <= s && m.M12 <= s && m.M13 <= s && m.M20 <= s && m.M21 <= s && m.M22 <= s && m.M23 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(double s, M34d m) { return s <= m.M00 && s <= m.M01 && s <= m.M02 && s <= m.M03 && s <= m.M10 && s <= m.M11 && s <= m.M12 && s <= m.M13 && s <= m.M20 && s <= m.M21 && s <= m.M22 && s <= m.M23; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M34d a, M34d b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M02 <= b.M02 || a.M03 <= b.M03 || a.M10 <= b.M10 || a.M11 <= b.M11 || a.M12 <= b.M12 || a.M13 <= b.M13 || a.M20 <= b.M20 || a.M21 <= b.M21 || a.M22 <= b.M22 || a.M23 <= b.M23; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M34d m, double s) { return m.M00 <= s || m.M01 <= s || m.M02 <= s || m.M03 <= s || m.M10 <= s || m.M11 <= s || m.M12 <= s || m.M13 <= s || m.M20 <= s || m.M21 <= s || m.M22 <= s || m.M23 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(double s, M34d m) { return s <= m.M00 || s <= m.M01 || s <= m.M02 || s <= m.M03 || s <= m.M10 || s <= m.M11 || s <= m.M12 || s <= m.M13 || s <= m.M20 || s <= m.M21 || s <= m.M22 || s <= m.M23; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M34d a, M34d b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M02 >= b.M02 && a.M03 >= b.M03 && a.M10 >= b.M10 && a.M11 >= b.M11 && a.M12 >= b.M12 && a.M13 >= b.M13 && a.M20 >= b.M20 && a.M21 >= b.M21 && a.M22 >= b.M22 && a.M23 >= b.M23; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M34d m, double s) { return m.M00 >= s && m.M01 >= s && m.M02 >= s && m.M03 >= s && m.M10 >= s && m.M11 >= s && m.M12 >= s && m.M13 >= s && m.M20 >= s && m.M21 >= s && m.M22 >= s && m.M23 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(double s, M34d m) { return s >= m.M00 && s >= m.M01 && s >= m.M02 && s >= m.M03 && s >= m.M10 && s >= m.M11 && s >= m.M12 && s >= m.M13 && s >= m.M20 && s >= m.M21 && s >= m.M22 && s >= m.M23; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M34d a, M34d b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M02 >= b.M02 || a.M03 >= b.M03 || a.M10 >= b.M10 || a.M11 >= b.M11 || a.M12 >= b.M12 || a.M13 >= b.M13 || a.M20 >= b.M20 || a.M21 >= b.M21 || a.M22 >= b.M22 || a.M23 >= b.M23; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M34d m, double s) { return m.M00 >= s || m.M01 >= s || m.M02 >= s || m.M03 >= s || m.M10 >= s || m.M11 >= s || m.M12 >= s || m.M13 >= s || m.M20 >= s || m.M21 >= s || m.M22 >= s || m.M23 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(double s, M34d m) { return s >= m.M00 || s >= m.M01 || s >= m.M02 || s >= m.M03 || s >= m.M10 || s >= m.M11 || s >= m.M12 || s >= m.M13 || s >= m.M20 || s >= m.M21 || s >= m.M22 || s >= m.M23; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M34d a, M34d b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M03 == b.M03 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M13 == b.M13 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22 && a.M23 == b.M23; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M34d m, double s) { return m.M00 == s && m.M01 == s && m.M02 == s && m.M03 == s && m.M10 == s && m.M11 == s && m.M12 == s && m.M13 == s && m.M20 == s && m.M21 == s && m.M22 == s && m.M23 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(double s, M34d m) { return s == m.M00 && s == m.M01 && s == m.M02 && s == m.M03 && s == m.M10 && s == m.M11 && s == m.M12 && s == m.M13 && s == m.M20 && s == m.M21 && s == m.M22 && s == m.M23; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M34d a, M34d b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M02 == b.M02 || a.M03 == b.M03 || a.M10 == b.M10 || a.M11 == b.M11 || a.M12 == b.M12 || a.M13 == b.M13 || a.M20 == b.M20 || a.M21 == b.M21 || a.M22 == b.M22 || a.M23 == b.M23; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M34d m, double s) { return m.M00 == s || m.M01 == s || m.M02 == s || m.M03 == s || m.M10 == s || m.M11 == s || m.M12 == s || m.M13 == s || m.M20 == s || m.M21 == s || m.M22 == s || m.M23 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(double s, M34d m) { return s == m.M00 || s == m.M01 || s == m.M02 || s == m.M03 || s == m.M10 || s == m.M11 || s == m.M12 || s == m.M13 || s == m.M20 || s == m.M21 || s == m.M22 || s == m.M23; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M34d a, M34d b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M02 != b.M02 && a.M03 != b.M03 && a.M10 != b.M10 && a.M11 != b.M11 && a.M12 != b.M12 && a.M13 != b.M13 && a.M20 != b.M20 && a.M21 != b.M21 && a.M22 != b.M22 && a.M23 != b.M23; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M34d m, double s) { return m.M00 != s && m.M01 != s && m.M02 != s && m.M03 != s && m.M10 != s && m.M11 != s && m.M12 != s && m.M13 != s && m.M20 != s && m.M21 != s && m.M22 != s && m.M23 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(double s, M34d m) { return s != m.M00 && s != m.M01 && s != m.M02 && s != m.M03 && s != m.M10 && s != m.M11 && s != m.M12 && s != m.M13 && s != m.M20 && s != m.M21 && s != m.M22 && s != m.M23; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M34d a, M34d b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M02 != b.M02 || a.M03 != b.M03 || a.M10 != b.M10 || a.M11 != b.M11 || a.M12 != b.M12 || a.M13 != b.M13 || a.M20 != b.M20 || a.M21 != b.M21 || a.M22 != b.M22 || a.M23 != b.M23; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M34d m, double s) { return m.M00 != s || m.M01 != s || m.M02 != s || m.M03 != s || m.M10 != s || m.M11 != s || m.M12 != s || m.M13 != s || m.M20 != s || m.M21 != s || m.M22 != s || m.M23 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(double s, M34d m) { return s != m.M00 || s != m.M01 || s != m.M02 || s != m.M03 || s != m.M10 || s != m.M11 || s != m.M12 || s != m.M13 || s != m.M20 || s != m.M21 || s != m.M22 || s != m.M23; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M34d m0, M34d m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M02 < m1.M02) return -1; if (m0.M02 > m1.M02) return +1; if (m0.M03 < m1.M03) return -1; if (m0.M03 > m1.M03) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; if (m0.M12 < m1.M12) return -1; if (m0.M12 > m1.M12) return +1; if (m0.M13 < m1.M13) return -1; if (m0.M13 > m1.M13) return +1; if (m0.M20 < m1.M20) return -1; if (m0.M20 > m1.M20) return +1; if (m0.M21 < m1.M21) return -1; if (m0.M21 > m1.M21) return +1; if (m0.M22 < m1.M22) return -1; if (m0.M22 > m1.M22) return +1; if (m0.M23 < m1.M23) return -1; if (m0.M23 > m1.M23) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MinElement(M34d m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MaxElement(M34d m) => m.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M34d m, double epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M02.IsTiny(epsilon) || m.M03.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon) || m.M12.IsTiny(epsilon) || m.M13.IsTiny(epsilon) || m.M20.IsTiny(epsilon) || m.M21.IsTiny(epsilon) || m.M22.IsTiny(epsilon) || m.M23.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M34d m, double epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M02.IsTiny(epsilon) && m.M03.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon) && m.M12.IsTiny(epsilon) && m.M13.IsTiny(epsilon) && m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon) && m.M22.IsTiny(epsilon) && m.M23.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyFinite(M34d m) => m.AnyFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllFinite(M34d m) => m.AllFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(M34d m) => m.AnyNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(M34d m) => m.AllNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(M34d m) => m.AnyInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(M34d m) => m.AllInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(M34d m) => m.AnyPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(M34d m) => m.AllPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(M34d m) => m.AnyNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(M34d m) => m.AllNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(M34d m) => m.AnyTiny; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(M34d m) => m.AllTiny; #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M34d a, M34d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M34d a, M34d b, double epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M34d m, double epsilon) => Mat.AllTiny(m, epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(M34d m) => m.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any element of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(M34d v) => v.IsNaN; /// /// Returns whether any element of the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(M34d v) => v.IsInfinity; /// /// Returns whether any element of the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(M34d v) => v.IsPositiveInfinity; /// /// Returns whether any element of the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(M34d v) => v.IsNegativeInfinity; /// /// Returns whether all elements of the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(M34d v) => v.IsFinite; #endregion } public static class IRandomUniformM34dExtensions { #region IRandomUniform extensions for M34d /// /// Uses UniformDouble() to generate the elements of an M34d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d UniformM34d(this IRandomUniform rnd) { return new M34d( rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble()); } /// /// Uses UniformDoubleClosed() to generate the elements of an M34d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d UniformM34dClosed(this IRandomUniform rnd) { return new M34d( rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed()); } /// /// Uses UniformDoubleOpen() to generate the elements of an M34d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d UniformM34dOpen(this IRandomUniform rnd) { return new M34d( rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen()); } /// /// Uses UniformDoubleFull() to generate the elements of an M34d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d UniformM34dFull(this IRandomUniform rnd) { return new M34d( rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull()); } /// /// Uses UniformDoubleFullClosed() to generate the elements of an M34d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d UniformM34dFullClosed(this IRandomUniform rnd) { return new M34d( rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed()); } /// /// Uses UniformDoubleFullOpen() to generate the elements of an M34d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d UniformM34dFullOpen(this IRandomUniform rnd) { return new M34d( rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen()); } #endregion } #endregion #region M44i [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M44i : IEquatable, IValidity, IMatrix { [DataMember] public int M00, M01, M02, M03; [DataMember] public int M10, M11, M12, M13; [DataMember] public int M20, M21, M22, M23; [DataMember] public int M30, M31, M32, M33; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(int value) { M00 = value; M01 = 0; M02 = 0; M03 = 0; M10 = 0; M11 = value; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = value; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i( int m00, int m01, int m02, int m03, int m10, int m11, int m12, int m13, int m20, int m21, int m22, int m23, int m30, int m31, int m32, int m33) { M00 = m00; M01 = m01; M02 = m02; M03 = m03; M10 = m10; M11 = m11; M12 = m12; M13 = m13; M20 = m20; M21 = m21; M22 = m22; M23 = m23; M30 = m30; M31 = m31; M32 = m32; M33 = m33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(int[] a) { M00 = a[0]; M01 = a[1]; M02 = a[2]; M03 = a[3]; M10 = a[4]; M11 = a[5]; M12 = a[6]; M13 = a[7]; M20 = a[8]; M21 = a[9]; M22 = a[10]; M23 = a[11]; M30 = a[12]; M31 = a[13]; M32 = a[14]; M33 = a[15]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(int[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M02 = a[start + 2]; M03 = a[start + 3]; M10 = a[start + 4]; M11 = a[start + 5]; M12 = a[start + 6]; M13 = a[start + 7]; M20 = a[start + 8]; M21 = a[start + 9]; M22 = a[start + 10]; M23 = a[start + 11]; M30 = a[start + 12]; M31 = a[start + 13]; M32 = a[start + 14]; M33 = a[start + 15]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M22i m) { M00 = m.M00; M01 = m.M01; M02 = 0; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M23i m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M33i m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = 0; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M34i m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = m.M03; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = m.M13; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = m.M23; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M22l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = 0; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M23l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M33l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = 0; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M34l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = (int)m.M03; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = (int)m.M13; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = (int)m.M23; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M44l m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = (int)m.M03; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = (int)m.M13; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = (int)m.M23; M30 = (int)m.M30; M31 = (int)m.M31; M32 = (int)m.M32; M33 = (int)m.M33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M22f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = 0; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M23f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M33f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = 0; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M34f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = (int)m.M03; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = (int)m.M13; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = (int)m.M23; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M44f m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = (int)m.M03; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = (int)m.M13; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = (int)m.M23; M30 = (int)m.M30; M31 = (int)m.M31; M32 = (int)m.M32; M33 = (int)m.M33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M22d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = 0; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M23d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M33d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = 0; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = 0; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M34d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = (int)m.M03; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = (int)m.M13; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = (int)m.M23; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44i(M44d m) { M00 = (int)m.M00; M01 = (int)m.M01; M02 = (int)m.M02; M03 = (int)m.M03; M10 = (int)m.M10; M11 = (int)m.M11; M12 = (int)m.M12; M13 = (int)m.M13; M20 = (int)m.M20; M21 = (int)m.M21; M22 = (int)m.M22; M23 = (int)m.M23; M30 = (int)m.M30; M31 = (int)m.M31; M32 = (int)m.M32; M33 = (int)m.M33; } #endregion #region Conversions public static explicit operator M44i(M22i m) { return new M44i { M00 = m.M00, M01 = m.M01, M02 = 0, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44i(M23i m) { return new M44i { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44i(M33i m) { return new M44i { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = 0, M20 = m.M20, M21 = m.M21, M22 = m.M22, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44i(M34i m) { return new M44i { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = m.M03, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = m.M13, M20 = m.M20, M21 = m.M21, M22 = m.M22, M23 = m.M23, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44i(M22l m) { return new M44i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = 0, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44i(M23l m) { return new M44i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44i(M33l m) { return new M44i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = 0, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44i(M34l m) { return new M44i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = (int)m.M03, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = (int)m.M13, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = (int)m.M23, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44i(M44l m) { return new M44i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = (int)m.M03, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = (int)m.M13, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = (int)m.M23, M30 = (int)m.M30, M31 = (int)m.M31, M32 = (int)m.M32, M33 = (int)m.M33, }; } public static explicit operator M44i(M22f m) { return new M44i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = 0, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44i(M23f m) { return new M44i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44i(M33f m) { return new M44i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = 0, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44i(M34f m) { return new M44i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = (int)m.M03, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = (int)m.M13, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = (int)m.M23, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44i(M44f m) { return new M44i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = (int)m.M03, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = (int)m.M13, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = (int)m.M23, M30 = (int)m.M30, M31 = (int)m.M31, M32 = (int)m.M32, M33 = (int)m.M33, }; } public static explicit operator M44i(M22d m) { return new M44i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = 0, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44i(M23d m) { return new M44i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44i(M33d m) { return new M44i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = 0, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = 0, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44i(M34d m) { return new M44i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = (int)m.M03, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = (int)m.M13, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = (int)m.M23, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44i(M44d m) { return new M44i { M00 = (int)m.M00, M01 = (int)m.M01, M02 = (int)m.M02, M03 = (int)m.M03, M10 = (int)m.M10, M11 = (int)m.M11, M12 = (int)m.M12, M13 = (int)m.M13, M20 = (int)m.M20, M21 = (int)m.M21, M22 = (int)m.M22, M23 = (int)m.M23, M30 = (int)m.M30, M31 = (int)m.M31, M32 = (int)m.M32, M33 = (int)m.M33, }; } public static explicit operator M44i(int[] a) { return new M44i( a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); } public static explicit operator M44i(int[,] a) { return new M44i( a[0, 0], a[0, 1], a[0, 2], a[0, 3], a[1, 0], a[1, 1], a[1, 2], a[1, 3], a[2, 0], a[2, 1], a[2, 2], a[2, 3], a[3, 0], a[3, 1], a[3, 2], a[3, 3]); } public static explicit operator int[](M44i m) { return new int[] { m.M00, m.M01, m.M02, m.M03, m.M10, m.M11, m.M12, m.M13, m.M20, m.M21, m.M22, m.M23, m.M30, m.M31, m.M32, m.M33 }; } public static explicit operator int[,](M44i m) { return new int[,] { { m.M00, m.M01, m.M02, m.M03 }, { m.M10, m.M11, m.M12, m.M13 }, { m.M20, m.M21, m.M22, m.M23 }, { m.M30, m.M31, m.M32, m.M33 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M02; array[index + 3] = M03; array[index + 4] = M10; array[index + 5] = M11; array[index + 6] = M12; array[index + 7] = M13; array[index + 8] = M20; array[index + 9] = M21; array[index + 10] = M22; array[index + 11] = M23; array[index + 12] = M30; array[index + 13] = M31; array[index + 14] = M32; array[index + 15] = M33; } public static explicit operator M44i(long[] a) { return new M44i( (int)a[0], (int)a[1], (int)a[2], (int)a[3], (int)a[4], (int)a[5], (int)a[6], (int)a[7], (int)a[8], (int)a[9], (int)a[10], (int)a[11], (int)a[12], (int)a[13], (int)a[14], (int)a[15]); } public static explicit operator M44i(long[,] a) { return new M44i( (int)a[0, 0], (int)a[0, 1], (int)a[0, 2], (int)a[0, 3], (int)a[1, 0], (int)a[1, 1], (int)a[1, 2], (int)a[1, 3], (int)a[2, 0], (int)a[2, 1], (int)a[2, 2], (int)a[2, 3], (int)a[3, 0], (int)a[3, 1], (int)a[3, 2], (int)a[3, 3]); } public static explicit operator long[](M44i m) { return new long[] { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M03, (long)m.M10, (long)m.M11, (long)m.M12, (long)m.M13, (long)m.M20, (long)m.M21, (long)m.M22, (long)m.M23, (long)m.M30, (long)m.M31, (long)m.M32, (long)m.M33 }; } public static explicit operator long[,](M44i m) { return new long[,] { { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M03 }, { (long)m.M10, (long)m.M11, (long)m.M12, (long)m.M13 }, { (long)m.M20, (long)m.M21, (long)m.M22, (long)m.M23 }, { (long)m.M30, (long)m.M31, (long)m.M32, (long)m.M33 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = (long)M00; array[index + 1] = (long)M01; array[index + 2] = (long)M02; array[index + 3] = (long)M03; array[index + 4] = (long)M10; array[index + 5] = (long)M11; array[index + 6] = (long)M12; array[index + 7] = (long)M13; array[index + 8] = (long)M20; array[index + 9] = (long)M21; array[index + 10] = (long)M22; array[index + 11] = (long)M23; array[index + 12] = (long)M30; array[index + 13] = (long)M31; array[index + 14] = (long)M32; array[index + 15] = (long)M33; } public static explicit operator M44i(float[] a) { return new M44i( (int)a[0], (int)a[1], (int)a[2], (int)a[3], (int)a[4], (int)a[5], (int)a[6], (int)a[7], (int)a[8], (int)a[9], (int)a[10], (int)a[11], (int)a[12], (int)a[13], (int)a[14], (int)a[15]); } public static explicit operator M44i(float[,] a) { return new M44i( (int)a[0, 0], (int)a[0, 1], (int)a[0, 2], (int)a[0, 3], (int)a[1, 0], (int)a[1, 1], (int)a[1, 2], (int)a[1, 3], (int)a[2, 0], (int)a[2, 1], (int)a[2, 2], (int)a[2, 3], (int)a[3, 0], (int)a[3, 1], (int)a[3, 2], (int)a[3, 3]); } public static explicit operator float[](M44i m) { return new float[] { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M03, (float)m.M10, (float)m.M11, (float)m.M12, (float)m.M13, (float)m.M20, (float)m.M21, (float)m.M22, (float)m.M23, (float)m.M30, (float)m.M31, (float)m.M32, (float)m.M33 }; } public static explicit operator float[,](M44i m) { return new float[,] { { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M03 }, { (float)m.M10, (float)m.M11, (float)m.M12, (float)m.M13 }, { (float)m.M20, (float)m.M21, (float)m.M22, (float)m.M23 }, { (float)m.M30, (float)m.M31, (float)m.M32, (float)m.M33 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = (float)M00; array[index + 1] = (float)M01; array[index + 2] = (float)M02; array[index + 3] = (float)M03; array[index + 4] = (float)M10; array[index + 5] = (float)M11; array[index + 6] = (float)M12; array[index + 7] = (float)M13; array[index + 8] = (float)M20; array[index + 9] = (float)M21; array[index + 10] = (float)M22; array[index + 11] = (float)M23; array[index + 12] = (float)M30; array[index + 13] = (float)M31; array[index + 14] = (float)M32; array[index + 15] = (float)M33; } public static explicit operator M44i(double[] a) { return new M44i( (int)a[0], (int)a[1], (int)a[2], (int)a[3], (int)a[4], (int)a[5], (int)a[6], (int)a[7], (int)a[8], (int)a[9], (int)a[10], (int)a[11], (int)a[12], (int)a[13], (int)a[14], (int)a[15]); } public static explicit operator M44i(double[,] a) { return new M44i( (int)a[0, 0], (int)a[0, 1], (int)a[0, 2], (int)a[0, 3], (int)a[1, 0], (int)a[1, 1], (int)a[1, 2], (int)a[1, 3], (int)a[2, 0], (int)a[2, 1], (int)a[2, 2], (int)a[2, 3], (int)a[3, 0], (int)a[3, 1], (int)a[3, 2], (int)a[3, 3]); } public static explicit operator double[](M44i m) { return new double[] { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M03, (double)m.M10, (double)m.M11, (double)m.M12, (double)m.M13, (double)m.M20, (double)m.M21, (double)m.M22, (double)m.M23, (double)m.M30, (double)m.M31, (double)m.M32, (double)m.M33 }; } public static explicit operator double[,](M44i m) { return new double[,] { { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M03 }, { (double)m.M10, (double)m.M11, (double)m.M12, (double)m.M13 }, { (double)m.M20, (double)m.M21, (double)m.M22, (double)m.M23 }, { (double)m.M30, (double)m.M31, (double)m.M32, (double)m.M33 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = (double)M00; array[index + 1] = (double)M01; array[index + 2] = (double)M02; array[index + 3] = (double)M03; array[index + 4] = (double)M10; array[index + 5] = (double)M11; array[index + 6] = (double)M12; array[index + 7] = (double)M13; array[index + 8] = (double)M20; array[index + 9] = (double)M21; array[index + 10] = (double)M22; array[index + 11] = (double)M23; array[index + 12] = (double)M30; array[index + 13] = (double)M31; array[index + 14] = (double)M32; array[index + 15] = (double)M33; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44i Copy(Func element_fun) { return new M44i( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23), element_fun(M30), element_fun(M31), element_fun(M32), element_fun(M33)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44i Copy(Func element_index0_index1_fun) { return new M44i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3), element_index0_index1_fun(M30, 3, 0), element_index0_index1_fun(M31, 3, 1), element_index0_index1_fun(M32, 3, 2), element_index0_index1_fun(M33, 3, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44l Copy(Func element_fun) { return new M44l( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23), element_fun(M30), element_fun(M31), element_fun(M32), element_fun(M33)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44l Copy(Func element_index0_index1_fun) { return new M44l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3), element_index0_index1_fun(M30, 3, 0), element_index0_index1_fun(M31, 3, 1), element_index0_index1_fun(M32, 3, 2), element_index0_index1_fun(M33, 3, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44f Copy(Func element_fun) { return new M44f( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23), element_fun(M30), element_fun(M31), element_fun(M32), element_fun(M33)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44f Copy(Func element_index0_index1_fun) { return new M44f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3), element_index0_index1_fun(M30, 3, 0), element_index0_index1_fun(M31, 3, 1), element_index0_index1_fun(M32, 3, 2), element_index0_index1_fun(M33, 3, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44d Copy(Func element_fun) { return new M44d( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23), element_fun(M30), element_fun(M31), element_fun(M32), element_fun(M33)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44d Copy(Func element_index0_index1_fun) { return new M44d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3), element_index0_index1_fun(M30, 3, 0), element_index0_index1_fun(M31, 3, 1), element_index0_index1_fun(M32, 3, 2), element_index0_index1_fun(M33, 3, 3)); } /// /// Returns a copy of the upper left sub matrix. /// public readonly M33i UpperLeftM33() { return (M33i)this; } public readonly int[] ToArray() { var array = new int[16]; array[0] = M00; array[1] = M01; array[2] = M02; array[3] = M03; array[4] = M10; array[5] = M11; array[6] = M12; array[7] = M13; array[8] = M20; array[9] = M21; array[10] = M22; array[11] = M23; array[12] = M30; array[13] = M31; array[14] = M32; array[15] = M33; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i FromCols(V4i col0, V4i col1, V4i col2, V4i col3) { return new M44i( col0.X, col1.X, col2.X, col3.X, col0.Y, col1.Y, col2.Y, col3.Y, col0.Z, col1.Z, col2.Z, col3.Z, col0.W, col1.W, col2.W, col3.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i FromRows(V4i row0, V4i row1, V4i row2, V4i row3) { return new M44i( row0.X, row0.Y, row0.Z, row0.W, row1.X, row1.Y, row1.Z, row1.W, row2.X, row2.Y, row2.Z, row2.W, row3.X, row3.Y, row3.Z, row3.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i FromDiagonal(int value) { return new M44i( value, 0, 0, 0, 0, value, 0, 0, 0, 0, value, 0, 0, 0, 0, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i FromDiagonal(int m00, int m11, int m22, int m33) { return new M44i( m00, 0, 0, 0, 0, m11, 0, 0, 0, 0, m22, 0, 0, 0, 0, m33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i FromDiagonal(V4i s) { return new M44i( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0, 0, 0, 0, s.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i FromAntiDiagonal(int value) { return new M44i( 0, 0, 0, value, 0, 0, value, 0, 0, value, 0, 0, value, 0, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i FromAntiDiagonal(int m03, int m12, int m21, int m30) { return new M44i( 0, 0, 0, m03, 0, 0, m12, 0, 0, m21, 0, 0, m30, 0, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i FromAntiDiagonal(V4i s) { return new M44i( 0, 0, 0, s.X, 0, 0, s.Y, 0, 0, s.Z, 0, 0, s.W, 0, 0, 0); } #region Scale /// /// Creates a transformation using 4 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i Scale(int sX, int sY, int sZ, int sW) => FromDiagonal(sX, sY, sZ, sW); /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i Scale(V4i s) => FromDiagonal(s); /// /// Creates a homogenous transformation using a uniform scale. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i Scale(int s) { return new M44i( s, 0, 0, 0, 0, s, 0, 0, 0, 0, s, 0, 0, 0, 0, 1); } /// /// Creates a transformation using 3 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i Scale(int sX, int sY, int sZ) { return new M44i( sX, 0, 0, 0, 0, sY, 0, 0, 0, 0, sZ, 0, 0, 0, 0, 1); } /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i Scale(V3i s) { return new M44i( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0, 0, 0, 0, 1); } #endregion #region Translation /// /// Creates a transformation with the translational component given by 3 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i Translation(int tX, int tY, int tZ) { return new M44i( 1, 0, 0, tX, 0, 1, 0, tY, 0, 0, 1, tZ, 0, 0, 0, 1); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i Translation(V3i t) { return new M44i( 1, 0, 0, t.X, 0, 1, 0, t.Y, 0, 0, 1, t.Z, 0, 0, 0, 1); } #endregion #region Shearing /// /// Creates a shear transformation matrix along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i ShearXY(int factorX, int factorY) { return new M44i( 1, 0, factorX, 0, 0, 1, factorY, 0, 0, 0, 1, 0, 0, 0, 0, 1); } /// /// Creates a shear transformation matrix along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i ShearXZ(int factorX, int factorZ) { return new M44i( 1, factorX, 0, 0, 0, 1, 0, 0, 0, factorZ, 1, 0, 0, 0, 0, 1); } /// /// Creates a shear transformation matrix along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i ShearYZ(int factorY, int factorZ) { return new M44i( 1, 0, 0, 0, factorY, 1, 0, 0, factorZ, 0, 1, 0, 0, 0, 0, 1); } #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i DivideByInt(M44i m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M02; yield return M03; yield return M10; yield return M11; yield return M12; yield return M13; yield return M20; yield return M21; yield return M22; yield return M23; yield return M30; yield return M31; yield return M32; yield return M33; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; yield return R2; yield return R3; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; yield return C2; yield return C3; } } [XmlIgnore] public V4i R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4i( M00, M01, M02, M03); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; M02 = value.Z; M03 = value.W; } } [XmlIgnore] public V4i R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4i( M10, M11, M12, M13); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; M12 = value.Z; M13 = value.W; } } [XmlIgnore] public V4i R2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4i( M20, M21, M22, M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M20 = value.X; M21 = value.Y; M22 = value.Z; M23 = value.W; } } [XmlIgnore] public V4i R3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4i( M30, M31, M32, M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M30 = value.X; M31 = value.Y; M32 = value.Z; M33 = value.W; } } [XmlIgnore] public V4i C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4i( M00, M10, M20, M30); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; M20 = value.Z; M30 = value.W; } } [XmlIgnore] public V4i C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4i( M01, M11, M21, M31); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; M21 = value.Z; M31 = value.W; } } [XmlIgnore] public V4i C2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4i( M02, M12, M22, M32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M02 = value.X; M12 = value.Y; M22 = value.Z; M32 = value.W; } } [XmlIgnore] public V4i C3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4i( M03, M13, M23, M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M03 = value.X; M13 = value.Y; M23 = value.Z; M33 = value.W; } } public readonly V4i Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V4i(M00, M11, M22, M33); } public readonly V4i AntiDiagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V4i(M03, M12, M21, M30); } /// /// Returns the minimum element of the matrix. /// public readonly int MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23, M30, M31, M32, M33); } /// /// Returns the maximum element of the matrix. /// public readonly int MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23, M30, M31, M32, M33); } public unsafe int this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (int* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (int* ptr = &M00) { ptr[index] = value; } } } public unsafe int this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (int* ptr = &M00) { return ptr[row * 4 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (int* ptr = &M00) { ptr[row * 4 + column] = value; } } } #endregion #region Constants public const int RowCount = 4; public const int ColumnCount = 4; public const int ElementCount = 4 * 4; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(4, 4); } public static M44i Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M44i(0); } public static M44i Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M44i(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly int Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M02) + Fun.Abs(M03) + Fun.Abs(M10) + Fun.Abs(M11) + Fun.Abs(M12) + Fun.Abs(M13) + Fun.Abs(M20) + Fun.Abs(M21) + Fun.Abs(M22) + Fun.Abs(M23) + Fun.Abs(M30) + Fun.Abs(M31) + Fun.Abs(M32) + Fun.Abs(M33); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly double Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M02 * M02 + M03 * M03 + M10 * M10 + M11 * M11 + M12 * M12 + M13 * M13 + M20 * M20 + M21 * M21 + M22 * M22 + M23 * M23 + M30 * M30 + M31 * M31 + M32 * M32 + M33 * M33); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly int NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02), Fun.Abs(M03)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12), Fun.Abs(M13)), Fun.Max( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22), Fun.Abs(M23)), Fun.Max( Fun.Abs(M30), Fun.Abs(M31), Fun.Abs(M32), Fun.Abs(M33))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly int NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02), Fun.Abs(M03)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12), Fun.Abs(M13)), Fun.Min( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22), Fun.Abs(M23)), Fun.Min( Fun.Abs(M30), Fun.Abs(M31), Fun.Abs(M32), Fun.Abs(M33))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator -(M44i m) { return new M44i( -m.M00, -m.M01, -m.M02, -m.M03, -m.M10, -m.M11, -m.M12, -m.M13, -m.M20, -m.M21, -m.M22, -m.M23, -m.M30, -m.M31, -m.M32, -m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator + (M44i a, M44i b) { return new M44i( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23, a.M30 + b.M30, a.M31 + b.M31, a.M32 + b.M32, a.M33 + b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator + (M44i m, int s) { return new M44i( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s, m.M30 + s, m.M31 + s, m.M32 + s, m.M33 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator + (int s, M44i m) { return new M44i( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23, s + m.M30, s + m.M31, s + m.M32, s + m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator + (M44i a, M44l b) { return new M44l( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23, a.M30 + b.M30, a.M31 + b.M31, a.M32 + b.M32, a.M33 + b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator + (M44i m, long s) { return new M44l( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s, m.M30 + s, m.M31 + s, m.M32 + s, m.M33 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator + (long s, M44i m) { return new M44l( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23, s + m.M30, s + m.M31, s + m.M32, s + m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator + (M44i a, M44f b) { return new M44f( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23, a.M30 + b.M30, a.M31 + b.M31, a.M32 + b.M32, a.M33 + b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator + (M44i m, float s) { return new M44f( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s, m.M30 + s, m.M31 + s, m.M32 + s, m.M33 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator + (float s, M44i m) { return new M44f( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23, s + m.M30, s + m.M31, s + m.M32, s + m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator + (M44i a, M44d b) { return new M44d( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23, a.M30 + b.M30, a.M31 + b.M31, a.M32 + b.M32, a.M33 + b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator + (M44i m, double s) { return new M44d( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s, m.M30 + s, m.M31 + s, m.M32 + s, m.M33 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator + (double s, M44i m) { return new M44d( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23, s + m.M30, s + m.M31, s + m.M32, s + m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator - (M44i a, M44i b) { return new M44i( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23, a.M30 - b.M30, a.M31 - b.M31, a.M32 - b.M32, a.M33 - b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator - (M44i m, int s) { return new M44i( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s, m.M30 - s, m.M31 - s, m.M32 - s, m.M33 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator - (int s, M44i m) { return new M44i( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23, s - m.M30, s - m.M31, s - m.M32, s - m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator - (M44i a, M44l b) { return new M44l( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23, a.M30 - b.M30, a.M31 - b.M31, a.M32 - b.M32, a.M33 - b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator - (M44i m, long s) { return new M44l( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s, m.M30 - s, m.M31 - s, m.M32 - s, m.M33 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator - (long s, M44i m) { return new M44l( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23, s - m.M30, s - m.M31, s - m.M32, s - m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator - (M44i a, M44f b) { return new M44f( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23, a.M30 - b.M30, a.M31 - b.M31, a.M32 - b.M32, a.M33 - b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator - (M44i m, float s) { return new M44f( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s, m.M30 - s, m.M31 - s, m.M32 - s, m.M33 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator - (float s, M44i m) { return new M44f( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23, s - m.M30, s - m.M31, s - m.M32, s - m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator - (M44i a, M44d b) { return new M44d( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23, a.M30 - b.M30, a.M31 - b.M31, a.M32 - b.M32, a.M33 - b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator - (M44i m, double s) { return new M44d( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s, m.M30 - s, m.M31 - s, m.M32 - s, m.M33 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator - (double s, M44i m) { return new M44d( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23, s - m.M30, s - m.M31, s - m.M32, s - m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator % (M44i a, M44i b) { return new M44i( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23, a.M30 % b.M30, a.M31 % b.M31, a.M32 % b.M32, a.M33 % b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator % (M44i m, int s) { return new M44i( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s, m.M30 % s, m.M31 % s, m.M32 % s, m.M33 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator % (int s, M44i m) { return new M44i( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23, s % m.M30, s % m.M31, s % m.M32, s % m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator % (M44i a, M44l b) { return new M44l( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23, a.M30 % b.M30, a.M31 % b.M31, a.M32 % b.M32, a.M33 % b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator % (M44i m, long s) { return new M44l( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s, m.M30 % s, m.M31 % s, m.M32 % s, m.M33 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator % (long s, M44i m) { return new M44l( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23, s % m.M30, s % m.M31, s % m.M32, s % m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator % (M44i a, M44f b) { return new M44f( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23, a.M30 % b.M30, a.M31 % b.M31, a.M32 % b.M32, a.M33 % b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator % (M44i m, float s) { return new M44f( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s, m.M30 % s, m.M31 % s, m.M32 % s, m.M33 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator % (float s, M44i m) { return new M44f( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23, s % m.M30, s % m.M31, s % m.M32, s % m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator % (M44i a, M44d b) { return new M44d( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23, a.M30 % b.M30, a.M31 % b.M31, a.M32 % b.M32, a.M33 % b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator % (M44i m, double s) { return new M44d( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s, m.M30 % s, m.M31 % s, m.M32 % s, m.M33 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator % (double s, M44i m) { return new M44d( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23, s % m.M30, s % m.M31, s % m.M32, s % m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator / (M44i a, M44i b) { return new M44i( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23, a.M30 / b.M30, a.M31 / b.M31, a.M32 / b.M32, a.M33 / b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator / (M44i m, int s) { return new M44i( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s, m.M30 / s, m.M31 / s, m.M32 / s, m.M33 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator / (int s, M44i m) { return new M44i( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23, s / m.M30, s / m.M31, s / m.M32, s / m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator / (M44i a, M44l b) { return new M44l( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23, a.M30 / b.M30, a.M31 / b.M31, a.M32 / b.M32, a.M33 / b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator / (M44i m, long s) { return new M44l( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s, m.M30 / s, m.M31 / s, m.M32 / s, m.M33 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator / (long s, M44i m) { return new M44l( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23, s / m.M30, s / m.M31, s / m.M32, s / m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator / (M44i a, M44f b) { return new M44f( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23, a.M30 / b.M30, a.M31 / b.M31, a.M32 / b.M32, a.M33 / b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator / (M44i m, float s) { return new M44f( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s, m.M30 / s, m.M31 / s, m.M32 / s, m.M33 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator / (float s, M44i m) { return new M44f( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23, s / m.M30, s / m.M31, s / m.M32, s / m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator / (M44i a, M44d b) { return new M44d( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23, a.M30 / b.M30, a.M31 / b.M31, a.M32 / b.M32, a.M33 / b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator / (M44i m, double s) { return new M44d( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s, m.M30 / s, m.M31 / s, m.M32 / s, m.M33 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator / (double s, M44i m) { return new M44d( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23, s / m.M30, s / m.M31, s / m.M32, s / m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator * (M44i m, int s) { return new M44i( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s, m.M30 * s, m.M31 * s, m.M32 * s, m.M33 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator * (int s, M44i m) { return new M44i( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23, s * m.M30, s * m.M31, s * m.M32, s * m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator * (M44i m, long s) { return new M44l( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s, m.M30 * s, m.M31 * s, m.M32 * s, m.M33 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator * (long s, M44i m) { return new M44l( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23, s * m.M30, s * m.M31, s * m.M32, s * m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator * (M44i m, float s) { return new M44f( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s, m.M30 * s, m.M31 * s, m.M32 * s, m.M33 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator * (float s, M44i m) { return new M44f( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23, s * m.M30, s * m.M31, s * m.M32, s * m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator * (M44i m, double s) { return new M44d( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s, m.M30 * s, m.M31 * s, m.M32 * s, m.M33 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator * (double s, M44i m) { return new M44d( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23, s * m.M30, s * m.M31, s * m.M32, s * m.M33); } #endregion #region Bitwise Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator ~(M44i m) { return new M44i( ~m.M00, ~m.M01, ~m.M02, ~m.M03, ~m.M10, ~m.M11, ~m.M12, ~m.M13, ~m.M20, ~m.M21, ~m.M22, ~m.M23, ~m.M30, ~m.M31, ~m.M32, ~m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator <<(M44i a, int s) { return new M44i( a.M00 << s, a.M01 << s, a.M02 << s, a.M03 << s, a.M10 << s, a.M11 << s, a.M12 << s, a.M13 << s, a.M20 << s, a.M21 << s, a.M22 << s, a.M23 << s, a.M30 << s, a.M31 << s, a.M32 << s, a.M33 << s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator >>(M44i a, int s) { return new M44i( a.M00 >> s, a.M01 >> s, a.M02 >> s, a.M03 >> s, a.M10 >> s, a.M11 >> s, a.M12 >> s, a.M13 >> s, a.M20 >> s, a.M21 >> s, a.M22 >> s, a.M23 >> s, a.M30 >> s, a.M31 >> s, a.M32 >> s, a.M33 >> s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator &(M44i a, M44i b) { return new M44i( a.M00 & b.M00, a.M01 & b.M01, a.M02 & b.M02, a.M03 & b.M03, a.M10 & b.M10, a.M11 & b.M11, a.M12 & b.M12, a.M13 & b.M13, a.M20 & b.M20, a.M21 & b.M21, a.M22 & b.M22, a.M23 & b.M23, a.M30 & b.M30, a.M31 & b.M31, a.M32 & b.M32, a.M33 & b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator &(M44i a, int s) { return new M44i( a.M00 & s, a.M01 & s, a.M02 & s, a.M03 & s, a.M10 & s, a.M11 & s, a.M12 & s, a.M13 & s, a.M20 & s, a.M21 & s, a.M22 & s, a.M23 & s, a.M30 & s, a.M31 & s, a.M32 & s, a.M33 & s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator &(int s, M44i a) { return new M44i( s & a.M00, s & a.M01, s & a.M02, s & a.M03, s & a.M10, s & a.M11, s & a.M12, s & a.M13, s & a.M20, s & a.M21, s & a.M22, s & a.M23, s & a.M30, s & a.M31, s & a.M32, s & a.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator |(M44i a, M44i b) { return new M44i( a.M00 | b.M00, a.M01 | b.M01, a.M02 | b.M02, a.M03 | b.M03, a.M10 | b.M10, a.M11 | b.M11, a.M12 | b.M12, a.M13 | b.M13, a.M20 | b.M20, a.M21 | b.M21, a.M22 | b.M22, a.M23 | b.M23, a.M30 | b.M30, a.M31 | b.M31, a.M32 | b.M32, a.M33 | b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator |(M44i a, int s) { return new M44i( a.M00 | s, a.M01 | s, a.M02 | s, a.M03 | s, a.M10 | s, a.M11 | s, a.M12 | s, a.M13 | s, a.M20 | s, a.M21 | s, a.M22 | s, a.M23 | s, a.M30 | s, a.M31 | s, a.M32 | s, a.M33 | s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator |(int s, M44i a) { return new M44i( s | a.M00, s | a.M01, s | a.M02, s | a.M03, s | a.M10, s | a.M11, s | a.M12, s | a.M13, s | a.M20, s | a.M21, s | a.M22, s | a.M23, s | a.M30, s | a.M31, s | a.M32, s | a.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator ^(M44i a, M44i b) { return new M44i( a.M00 ^ b.M00, a.M01 ^ b.M01, a.M02 ^ b.M02, a.M03 ^ b.M03, a.M10 ^ b.M10, a.M11 ^ b.M11, a.M12 ^ b.M12, a.M13 ^ b.M13, a.M20 ^ b.M20, a.M21 ^ b.M21, a.M22 ^ b.M22, a.M23 ^ b.M23, a.M30 ^ b.M30, a.M31 ^ b.M31, a.M32 ^ b.M32, a.M33 ^ b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator ^(M44i a, int s) { return new M44i( a.M00 ^ s, a.M01 ^ s, a.M02 ^ s, a.M03 ^ s, a.M10 ^ s, a.M11 ^ s, a.M12 ^ s, a.M13 ^ s, a.M20 ^ s, a.M21 ^ s, a.M22 ^ s, a.M23 ^ s, a.M30 ^ s, a.M31 ^ s, a.M32 ^ s, a.M33 ^ s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i operator ^(int s, M44i a) { return new M44i( s ^ a.M00, s ^ a.M01, s ^ a.M02, s ^ a.M03, s ^ a.M10, s ^ a.M11, s ^ a.M12, s ^ a.M13, s ^ a.M20, s ^ a.M21, s ^ a.M22, s ^ a.M23, s ^ a.M30, s ^ a.M31, s ^ a.M32, s ^ a.M33); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M44i matrix with a V4i column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator *(M44i m, V4i v) { return new V4i( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z + m.M03 * v.W, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z + m.M13 * v.W, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z + m.M23 * v.W, m.M30 * v.X + m.M31 * v.Y + m.M32 * v.Z + m.M33 * v.W); } /// /// Multiplies a V4i row vector with a M44i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator *(V4i v, M44i m) { return new V4i( v.X * m.M00 + v.Y * m.M10 + v.Z * m.M20 + v.W * m.M30, v.X * m.M01 + v.Y * m.M11 + v.Z * m.M21 + v.W * m.M31, v.X * m.M02 + v.Y * m.M12 + v.Z * m.M22 + v.W * m.M32, v.X * m.M03 + v.Y * m.M13 + v.Z * m.M23 + v.W * m.M33); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M44i a, M44i b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M03 == b.M03 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M13 == b.M13 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22 && a.M23 == b.M23 && a.M30 == b.M30 && a.M31 == b.M31 && a.M32 == b.M32 && a.M33 == b.M33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M44i a, int s) { return a.M00 == s && a.M01 == s && a.M02 == s && a.M03 == s && a.M10 == s && a.M11 == s && a.M12 == s && a.M13 == s && a.M20 == s && a.M21 == s && a.M22 == s && a.M23 == s && a.M30 == s && a.M31 == s && a.M32 == s && a.M33 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(int s, M44i a) { return s == a.M00 && s == a.M01 && s == a.M02 && s == a.M03 && s == a.M10 && s == a.M11 && s == a.M12 && s == a.M13 && s == a.M20 && s == a.M21 && s == a.M22 && s == a.M23 && s == a.M30 && s == a.M31 && s == a.M32 && s == a.M33 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M44i a, M44i b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M44i m, int s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(int s, M44i m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01, M02, M03), HashCode.GetCombined(M10, M11, M12, M13), HashCode.GetCombined(M20, M21, M22, M23), HashCode.GetCombined(M30, M31, M32, M33)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M44i other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M02.Equals(other.M02) && M03.Equals(other.M03) && M10.Equals(other.M10) && M11.Equals(other.M11) && M12.Equals(other.M12) && M13.Equals(other.M13) && M20.Equals(other.M20) && M21.Equals(other.M21) && M22.Equals(other.M22) && M23.Equals(other.M23) && M30.Equals(other.M30) && M31.Equals(other.M31) && M32.Equals(other.M32) && M33.Equals(other.M33); } public override readonly bool Equals(object other) => (other is M44i o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + betweenM + R2.ToString(format, fp, beginR, betweenR, endR) + betweenM + R3.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M44i Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M44i.FromRows( V4i.Parse(x[0]), V4i.Parse(x[1]), V4i.Parse(x[2]), V4i.Parse(x[3]) ); } #endregion #region Matrix Operations /// /// Returns adjoint of this matrix. /// public readonly M44i Adjoint { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { M44i result = new M44i(); for (int row = 0; row < 4; row++) { for (int col = 0; col < 4; col++) { if (((col + row) % 2) == 0) result[col, row] = this.Minor(row, col).Determinant; else result[col, row] = -this.Minor(row, col).Determinant; } } return result; } } /// /// Returns the trace of this matrix. /// The trace is defined as the sum of the diagonal elements, /// and is only defined for square matrices. /// public readonly int Trace { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return M00 + M11 + M22 + M33 ; } } /// /// Gets the determinant of this matrix. /// The determinant is only defined for square matrices. /// public readonly int Determinant { get { // using bottom row because elements M30, M31, and M32 // are zero most of the time. int d = 0; if (M30 != 0.0f) d -= M30 * ( M01 * M12 * M23 + M02 * M13 * M21 + M03 * M11 * M22 - M21 * M12 * M03 - M22 * M13 * M01 - M23 * M11 * M02 ); if (M31 != 0.0f) d += M31 * ( M00 * M12 * M23 + M02 * M13 * M20 + M03 * M10 * M22 - M20 * M12 * M03 - M22 * M13 * M00 - M23 * M10 * M02 ); if (M32 != 0.0f) d -= M32 * ( M00 * M11 * M23 + M01 * M13 * M20 + M03 * M10 * M21 - M20 * M11 * M03 - M21 * M13 * M00 - M23 * M10 * M01 ); if (M33 != 0.0f) d += M33 * ( M00 * M11 * M22 + M01 * M12 * M20 + M02 * M10 * M21 - M20 * M11 * M02 - M21 * M12 * M00 - M22 * M10 * M01 ); return d; } } /// /// Returns whether this matrix is invertible. /// A matrix is invertible if its determinant is not zero. /// public readonly bool Invertible { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant != 0; } } /// /// Returns whether this matrix is singular. /// A matrix is singular if its determinant is zero. /// public readonly bool Singular { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant == 0; } } /// /// Gets transpose of this matrix. /// public readonly M44i Transposed { get { return new M44i { M00 = M00, M01 = M10, M02 = M20, M03 = M30, M10 = M01, M11 = M11, M12 = M21, M13 = M31, M20 = M02, M21 = M12, M22 = M22, M23 = M32, M30 = M03, M31 = M13, M32 = M23, M33 = M33 }; } } #endregion #region Matrix Multiplication public static M44i operator *(M44i a, M44i b) { return new M44i( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20 + a.M03 * b.M30, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21 + a.M03 * b.M31, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22 + a.M03 * b.M32, a.M00 * b.M03 + a.M01 * b.M13 + a.M02 * b.M23 + a.M03 * b.M33, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20 + a.M13 * b.M30, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21 + a.M13 * b.M31, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22 + a.M13 * b.M32, a.M10 * b.M03 + a.M11 * b.M13 + a.M12 * b.M23 + a.M13 * b.M33, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20 + a.M23 * b.M30, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21 + a.M23 * b.M31, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22 + a.M23 * b.M32, a.M20 * b.M03 + a.M21 * b.M13 + a.M22 * b.M23 + a.M23 * b.M33, a.M30 * b.M00 + a.M31 * b.M10 + a.M32 * b.M20 + a.M33 * b.M30, a.M30 * b.M01 + a.M31 * b.M11 + a.M32 * b.M21 + a.M33 * b.M31, a.M30 * b.M02 + a.M31 * b.M12 + a.M32 * b.M22 + a.M33 * b.M32, a.M30 * b.M03 + a.M31 * b.M13 + a.M32 * b.M23 + a.M33 * b.M33 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return (double)this[(int)y, (int)x]; } set { this[(int)y, (int)x] = (int)value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return (double)this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = (int)value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (int)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (int)value; } #endregion } public class M44iEqualityComparer : IEqualityComparer { public static readonly M44iEqualityComparer Default = new M44iEqualityComparer(); #region IEqualityComparer Members public bool Equals(M44i v0, M44i v1) { return v0 == v1; } public int GetHashCode(M44i v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this M44i m) => (m.C0.Length + m.C1.Length + m.C2.Length + m.C3.Length) / 4; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d GetScaleVector(this M44i m) => new V4d(m.C0.Length, m.C1.Length, m.C2.Length, m.C3.Length); /// /// Approximates the uniform scale value of the given transformation matrix (average length of 3D basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale3(this M44i m) => (m.C0.XYZ.Length + m.C1.XYZ.Length + m.C2.XYZ.Length) / 3; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the 3D basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetScaleVector3(this M44i m) => new V3d(m.C0.XYZ.Length, m.C1.XYZ.Length, m.C2.XYZ.Length); #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Norm1(M44i m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(M44i m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NormMax(M44i m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NormMin(M44i m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this M44i m, double p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M02).Pow(p) + Fun.Abs(m.M03).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) + Fun.Abs(m.M12).Pow(p) + Fun.Abs(m.M13).Pow(p) + Fun.Abs(m.M20).Pow(p) + Fun.Abs(m.M21).Pow(p) + Fun.Abs(m.M22).Pow(p) + Fun.Abs(m.M23).Pow(p) + Fun.Abs(m.M30).Pow(p) + Fun.Abs(m.M31).Pow(p) + Fun.Abs(m.M32).Pow(p) + Fun.Abs(m.M33).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static int Distance1(this M44i a, M44i b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M02 - a.M02) + Fun.Abs(b.M03 - a.M03) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11) + Fun.Abs(b.M12 - a.M12) + Fun.Abs(b.M13 - a.M13) + Fun.Abs(b.M20 - a.M20) + Fun.Abs(b.M21 - a.M21) + Fun.Abs(b.M22 - a.M22) + Fun.Abs(b.M23 - a.M23) + Fun.Abs(b.M30 - a.M30) + Fun.Abs(b.M31 - a.M31) + Fun.Abs(b.M32 - a.M32) + Fun.Abs(b.M33 - a.M33); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static double Distance2(this M44i a, M44i b) { return Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M02 - a.M02) + Fun.Square(b.M03 - a.M03) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11) + Fun.Square(b.M12 - a.M12) + Fun.Square(b.M13 - a.M13) + Fun.Square(b.M20 - a.M20) + Fun.Square(b.M21 - a.M21) + Fun.Square(b.M22 - a.M22) + Fun.Square(b.M23 - a.M23) + Fun.Square(b.M30 - a.M30) + Fun.Square(b.M31 - a.M31) + Fun.Square(b.M32 - a.M32) + Fun.Square(b.M33 - a.M33)); } /// /// Returns the p-distance between two matrices. /// public static double Distance(this M44i a, M44i b, double p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M02 - a.M02).Pow(p) + Fun.Abs(b.M03 - a.M03).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) + Fun.Abs(b.M12 - a.M12).Pow(p) + Fun.Abs(b.M13 - a.M13).Pow(p) + Fun.Abs(b.M20 - a.M20).Pow(p) + Fun.Abs(b.M21 - a.M21).Pow(p) + Fun.Abs(b.M22 - a.M22).Pow(p) + Fun.Abs(b.M23 - a.M23).Pow(p) + Fun.Abs(b.M30 - a.M30).Pow(p) + Fun.Abs(b.M31 - a.M31).Pow(p) + Fun.Abs(b.M32 - a.M32).Pow(p) + Fun.Abs(b.M33 - a.M33).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static int DistanceMax(this M44i a, M44i b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02), Fun.Abs(b.M03 - a.M03)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12), Fun.Abs(b.M13 - a.M13)), Fun.Max( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22), Fun.Abs(b.M23 - a.M23)), Fun.Max( Fun.Abs(b.M30 - a.M30), Fun.Abs(b.M31 - a.M31), Fun.Abs(b.M32 - a.M32), Fun.Abs(b.M33 - a.M33))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static int DistanceMin(this M44i a, M44i b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02), Fun.Abs(b.M03 - a.M03)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12), Fun.Abs(b.M13 - a.M13)), Fun.Min( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22), Fun.Abs(b.M23 - a.M23)), Fun.Min( Fun.Abs(b.M30 - a.M30), Fun.Abs(b.M31 - a.M31), Fun.Abs(b.M32 - a.M32), Fun.Abs(b.M33 - a.M33))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Transform(this M44i m, V4i v) => m * v; /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i TransposedTransform(this M44i m, V4i v) => v * m; /// /// Transforms direction vector v (v.W is presumed 0.0) by matrix m. /// public static V3i TransformDir(this M44i m, V3i v) { return new V3i( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z ); } /// /// Transforms point p (v.W is presumed 1.0) by matrix m. /// No projective transform is performed. /// public static V3i TransformPos(this M44i m, V3i p) { return new V3i( m.M00 * p.X + m.M01 * p.Y + m.M02 * p.Z + m.M03, m.M10 * p.X + m.M11 * p.Y + m.M12 * p.Z + m.M13, m.M20 * p.X + m.M21 * p.Y + m.M22 * p.Z + m.M23 ); } /// /// Transforms point p (p.W is presumed 1.0) by matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static V3i TransformPosProj(this M44i m, V3i p) { int s = m.M30 * p.X + m.M31 * p.Y + m.M32 * p.Z + m.M33; return TransformPos(m, p) * (1 / s); } /// /// Transforms point p (p.W is presumed 1.0) by matrix m. /// Projective transform is performed. /// public static V4i TransformPosProjFull(this M44i m, V3i p) { return new V4i( m.M00 * p.X + m.M01 * p.Y + m.M02 * p.Z + m.M03, m.M10 * p.X + m.M11 * p.Y + m.M12 * p.Z + m.M13, m.M20 * p.X + m.M21 * p.Y + m.M22 * p.Z + m.M23, m.M30 * p.X + m.M31 * p.Y + m.M32 * p.Z + m.M33 ); } /// /// Transforms direction vector v (v.W is presumed 0.0) by transposed version of matrix m. /// public static V3i TransposedTransformDir(this M44i m, V3i v) { return new V3i( m.M00 * v.X + m.M10 * v.Y + m.M20 * v.Z, m.M01 * v.X + m.M11 * v.Y + m.M21 * v.Z, m.M02 * v.X + m.M12 * v.Y + m.M22 * v.Z ); } /// /// Transforms point p (v.W is presumed 1.0) by transposed version of matrix m. /// No projective transform is performed. /// public static V3i TransposedTransformPos(this M44i m, V3i p) { return new V3i( m.M00 * p.X + m.M10 * p.Y + m.M20 * p.Z + m.M30, m.M01 * p.X + m.M11 * p.Y + m.M21 * p.Z + m.M31, m.M02 * p.X + m.M12 * p.Y + m.M22 * p.Z + m.M32 ); } /// /// Transforms point p (v.W is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static V3i TransposedTransformPosProj(this M44i m, V3i p) { var s = m.M03 * p.X + m.M13 * p.Y + m.M23 * p.Z + m.M33; return TransposedTransformPos(m, p) * (1 / s); } [Obsolete("Use TransposedTransformPosProj instead.")] public static V3i TransposedTransformProj(this M44i m, V3i p) => m.TransposedTransformPosProj(p); /// /// Transforms point p (v.W is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. /// public static V4i TransposedTransformPosProjFull(this M44i m, V3i p) { return new V4i( m.M00 * p.X + m.M10 * p.Y + m.M20 * p.Z + m.M30, m.M01 * p.X + m.M11 * p.Y + m.M21 * p.Z + m.M31, m.M02 * p.X + m.M12 * p.Y + m.M22 * p.Z + m.M32, m.M03 * p.X + m.M13 * p.Y + m.M23 * p.Z + m.M33 ); } [Obsolete("Use TransposedTransformPosProjFull instead.")] public static V4i TransposedTransformProjFull(this M44i m, V3i p) => m.TransposedTransformPosProjFull(p); #endregion #region Operations /// /// Returns the given to a deleting the /// specified row and column. /// public static M33i Minor(this M44i m, int row, int column) { M33i rs = new M33i(); for (int k = 0; k < 9; k++) { var i = k / 3; var j = k % 3; var ii = (i < row) ? i : i + 1; var jj = (j < column) ? j : j + 1; rs[k] = m[ii * 4 + jj]; } return rs; } /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V4i Row(this M44i m, int index) { int* ptr = &m.M00; return new V4i(ptr[index * 4], ptr[index * 4 + 1], ptr[index * 4 + 2], ptr[index * 4 + 3]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V4i Column(this M44i m, int index) { int* ptr = &m.M00; return new V4i(ptr[index], ptr[index + 4], ptr[index + 8], ptr[index + 12]); } /// /// Returns the determinant of the given matrix. /// The determinant is only defined for square matrices. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Determinant(M44i m) => m.Determinant; /// /// Returns the transpose of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i Transposed(M44i m) => m.Transposed; /// /// Transposes the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transpose(this ref M44i m) { Fun.Swap(ref m.M10, ref m.M01); Fun.Swap(ref m.M20, ref m.M02); Fun.Swap(ref m.M21, ref m.M12); Fun.Swap(ref m.M30, ref m.M03); Fun.Swap(ref m.M31, ref m.M13); Fun.Swap(ref m.M32, ref m.M23); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M44i a, M44i b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M02 < b.M02 && a.M03 < b.M03 && a.M10 < b.M10 && a.M11 < b.M11 && a.M12 < b.M12 && a.M13 < b.M13 && a.M20 < b.M20 && a.M21 < b.M21 && a.M22 < b.M22 && a.M23 < b.M23 && a.M30 < b.M30 && a.M31 < b.M31 && a.M32 < b.M32 && a.M33 < b.M33; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M44i m, int s) { return m.M00 < s && m.M01 < s && m.M02 < s && m.M03 < s && m.M10 < s && m.M11 < s && m.M12 < s && m.M13 < s && m.M20 < s && m.M21 < s && m.M22 < s && m.M23 < s && m.M30 < s && m.M31 < s && m.M32 < s && m.M33 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(int s, M44i m) { return s < m.M00 && s < m.M01 && s < m.M02 && s < m.M03 && s < m.M10 && s < m.M11 && s < m.M12 && s < m.M13 && s < m.M20 && s < m.M21 && s < m.M22 && s < m.M23 && s < m.M30 && s < m.M31 && s < m.M32 && s < m.M33; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M44i a, M44i b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M02 < b.M02 || a.M03 < b.M03 || a.M10 < b.M10 || a.M11 < b.M11 || a.M12 < b.M12 || a.M13 < b.M13 || a.M20 < b.M20 || a.M21 < b.M21 || a.M22 < b.M22 || a.M23 < b.M23 || a.M30 < b.M30 || a.M31 < b.M31 || a.M32 < b.M32 || a.M33 < b.M33; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M44i m, int s) { return m.M00 < s || m.M01 < s || m.M02 < s || m.M03 < s || m.M10 < s || m.M11 < s || m.M12 < s || m.M13 < s || m.M20 < s || m.M21 < s || m.M22 < s || m.M23 < s || m.M30 < s || m.M31 < s || m.M32 < s || m.M33 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(int s, M44i m) { return s < m.M00 || s < m.M01 || s < m.M02 || s < m.M03 || s < m.M10 || s < m.M11 || s < m.M12 || s < m.M13 || s < m.M20 || s < m.M21 || s < m.M22 || s < m.M23 || s < m.M30 || s < m.M31 || s < m.M32 || s < m.M33; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M44i a, M44i b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M02 > b.M02 && a.M03 > b.M03 && a.M10 > b.M10 && a.M11 > b.M11 && a.M12 > b.M12 && a.M13 > b.M13 && a.M20 > b.M20 && a.M21 > b.M21 && a.M22 > b.M22 && a.M23 > b.M23 && a.M30 > b.M30 && a.M31 > b.M31 && a.M32 > b.M32 && a.M33 > b.M33; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M44i m, int s) { return m.M00 > s && m.M01 > s && m.M02 > s && m.M03 > s && m.M10 > s && m.M11 > s && m.M12 > s && m.M13 > s && m.M20 > s && m.M21 > s && m.M22 > s && m.M23 > s && m.M30 > s && m.M31 > s && m.M32 > s && m.M33 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(int s, M44i m) { return s > m.M00 && s > m.M01 && s > m.M02 && s > m.M03 && s > m.M10 && s > m.M11 && s > m.M12 && s > m.M13 && s > m.M20 && s > m.M21 && s > m.M22 && s > m.M23 && s > m.M30 && s > m.M31 && s > m.M32 && s > m.M33; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M44i a, M44i b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M02 > b.M02 || a.M03 > b.M03 || a.M10 > b.M10 || a.M11 > b.M11 || a.M12 > b.M12 || a.M13 > b.M13 || a.M20 > b.M20 || a.M21 > b.M21 || a.M22 > b.M22 || a.M23 > b.M23 || a.M30 > b.M30 || a.M31 > b.M31 || a.M32 > b.M32 || a.M33 > b.M33; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M44i m, int s) { return m.M00 > s || m.M01 > s || m.M02 > s || m.M03 > s || m.M10 > s || m.M11 > s || m.M12 > s || m.M13 > s || m.M20 > s || m.M21 > s || m.M22 > s || m.M23 > s || m.M30 > s || m.M31 > s || m.M32 > s || m.M33 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(int s, M44i m) { return s > m.M00 || s > m.M01 || s > m.M02 || s > m.M03 || s > m.M10 || s > m.M11 || s > m.M12 || s > m.M13 || s > m.M20 || s > m.M21 || s > m.M22 || s > m.M23 || s > m.M30 || s > m.M31 || s > m.M32 || s > m.M33; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M44i a, M44i b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M02 <= b.M02 && a.M03 <= b.M03 && a.M10 <= b.M10 && a.M11 <= b.M11 && a.M12 <= b.M12 && a.M13 <= b.M13 && a.M20 <= b.M20 && a.M21 <= b.M21 && a.M22 <= b.M22 && a.M23 <= b.M23 && a.M30 <= b.M30 && a.M31 <= b.M31 && a.M32 <= b.M32 && a.M33 <= b.M33; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M44i m, int s) { return m.M00 <= s && m.M01 <= s && m.M02 <= s && m.M03 <= s && m.M10 <= s && m.M11 <= s && m.M12 <= s && m.M13 <= s && m.M20 <= s && m.M21 <= s && m.M22 <= s && m.M23 <= s && m.M30 <= s && m.M31 <= s && m.M32 <= s && m.M33 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(int s, M44i m) { return s <= m.M00 && s <= m.M01 && s <= m.M02 && s <= m.M03 && s <= m.M10 && s <= m.M11 && s <= m.M12 && s <= m.M13 && s <= m.M20 && s <= m.M21 && s <= m.M22 && s <= m.M23 && s <= m.M30 && s <= m.M31 && s <= m.M32 && s <= m.M33; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M44i a, M44i b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M02 <= b.M02 || a.M03 <= b.M03 || a.M10 <= b.M10 || a.M11 <= b.M11 || a.M12 <= b.M12 || a.M13 <= b.M13 || a.M20 <= b.M20 || a.M21 <= b.M21 || a.M22 <= b.M22 || a.M23 <= b.M23 || a.M30 <= b.M30 || a.M31 <= b.M31 || a.M32 <= b.M32 || a.M33 <= b.M33; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M44i m, int s) { return m.M00 <= s || m.M01 <= s || m.M02 <= s || m.M03 <= s || m.M10 <= s || m.M11 <= s || m.M12 <= s || m.M13 <= s || m.M20 <= s || m.M21 <= s || m.M22 <= s || m.M23 <= s || m.M30 <= s || m.M31 <= s || m.M32 <= s || m.M33 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(int s, M44i m) { return s <= m.M00 || s <= m.M01 || s <= m.M02 || s <= m.M03 || s <= m.M10 || s <= m.M11 || s <= m.M12 || s <= m.M13 || s <= m.M20 || s <= m.M21 || s <= m.M22 || s <= m.M23 || s <= m.M30 || s <= m.M31 || s <= m.M32 || s <= m.M33; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M44i a, M44i b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M02 >= b.M02 && a.M03 >= b.M03 && a.M10 >= b.M10 && a.M11 >= b.M11 && a.M12 >= b.M12 && a.M13 >= b.M13 && a.M20 >= b.M20 && a.M21 >= b.M21 && a.M22 >= b.M22 && a.M23 >= b.M23 && a.M30 >= b.M30 && a.M31 >= b.M31 && a.M32 >= b.M32 && a.M33 >= b.M33; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M44i m, int s) { return m.M00 >= s && m.M01 >= s && m.M02 >= s && m.M03 >= s && m.M10 >= s && m.M11 >= s && m.M12 >= s && m.M13 >= s && m.M20 >= s && m.M21 >= s && m.M22 >= s && m.M23 >= s && m.M30 >= s && m.M31 >= s && m.M32 >= s && m.M33 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(int s, M44i m) { return s >= m.M00 && s >= m.M01 && s >= m.M02 && s >= m.M03 && s >= m.M10 && s >= m.M11 && s >= m.M12 && s >= m.M13 && s >= m.M20 && s >= m.M21 && s >= m.M22 && s >= m.M23 && s >= m.M30 && s >= m.M31 && s >= m.M32 && s >= m.M33; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M44i a, M44i b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M02 >= b.M02 || a.M03 >= b.M03 || a.M10 >= b.M10 || a.M11 >= b.M11 || a.M12 >= b.M12 || a.M13 >= b.M13 || a.M20 >= b.M20 || a.M21 >= b.M21 || a.M22 >= b.M22 || a.M23 >= b.M23 || a.M30 >= b.M30 || a.M31 >= b.M31 || a.M32 >= b.M32 || a.M33 >= b.M33; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M44i m, int s) { return m.M00 >= s || m.M01 >= s || m.M02 >= s || m.M03 >= s || m.M10 >= s || m.M11 >= s || m.M12 >= s || m.M13 >= s || m.M20 >= s || m.M21 >= s || m.M22 >= s || m.M23 >= s || m.M30 >= s || m.M31 >= s || m.M32 >= s || m.M33 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(int s, M44i m) { return s >= m.M00 || s >= m.M01 || s >= m.M02 || s >= m.M03 || s >= m.M10 || s >= m.M11 || s >= m.M12 || s >= m.M13 || s >= m.M20 || s >= m.M21 || s >= m.M22 || s >= m.M23 || s >= m.M30 || s >= m.M31 || s >= m.M32 || s >= m.M33; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M44i a, M44i b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M03 == b.M03 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M13 == b.M13 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22 && a.M23 == b.M23 && a.M30 == b.M30 && a.M31 == b.M31 && a.M32 == b.M32 && a.M33 == b.M33; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M44i m, int s) { return m.M00 == s && m.M01 == s && m.M02 == s && m.M03 == s && m.M10 == s && m.M11 == s && m.M12 == s && m.M13 == s && m.M20 == s && m.M21 == s && m.M22 == s && m.M23 == s && m.M30 == s && m.M31 == s && m.M32 == s && m.M33 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(int s, M44i m) { return s == m.M00 && s == m.M01 && s == m.M02 && s == m.M03 && s == m.M10 && s == m.M11 && s == m.M12 && s == m.M13 && s == m.M20 && s == m.M21 && s == m.M22 && s == m.M23 && s == m.M30 && s == m.M31 && s == m.M32 && s == m.M33; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M44i a, M44i b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M02 == b.M02 || a.M03 == b.M03 || a.M10 == b.M10 || a.M11 == b.M11 || a.M12 == b.M12 || a.M13 == b.M13 || a.M20 == b.M20 || a.M21 == b.M21 || a.M22 == b.M22 || a.M23 == b.M23 || a.M30 == b.M30 || a.M31 == b.M31 || a.M32 == b.M32 || a.M33 == b.M33; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M44i m, int s) { return m.M00 == s || m.M01 == s || m.M02 == s || m.M03 == s || m.M10 == s || m.M11 == s || m.M12 == s || m.M13 == s || m.M20 == s || m.M21 == s || m.M22 == s || m.M23 == s || m.M30 == s || m.M31 == s || m.M32 == s || m.M33 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(int s, M44i m) { return s == m.M00 || s == m.M01 || s == m.M02 || s == m.M03 || s == m.M10 || s == m.M11 || s == m.M12 || s == m.M13 || s == m.M20 || s == m.M21 || s == m.M22 || s == m.M23 || s == m.M30 || s == m.M31 || s == m.M32 || s == m.M33; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M44i a, M44i b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M02 != b.M02 && a.M03 != b.M03 && a.M10 != b.M10 && a.M11 != b.M11 && a.M12 != b.M12 && a.M13 != b.M13 && a.M20 != b.M20 && a.M21 != b.M21 && a.M22 != b.M22 && a.M23 != b.M23 && a.M30 != b.M30 && a.M31 != b.M31 && a.M32 != b.M32 && a.M33 != b.M33; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M44i m, int s) { return m.M00 != s && m.M01 != s && m.M02 != s && m.M03 != s && m.M10 != s && m.M11 != s && m.M12 != s && m.M13 != s && m.M20 != s && m.M21 != s && m.M22 != s && m.M23 != s && m.M30 != s && m.M31 != s && m.M32 != s && m.M33 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(int s, M44i m) { return s != m.M00 && s != m.M01 && s != m.M02 && s != m.M03 && s != m.M10 && s != m.M11 && s != m.M12 && s != m.M13 && s != m.M20 && s != m.M21 && s != m.M22 && s != m.M23 && s != m.M30 && s != m.M31 && s != m.M32 && s != m.M33; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M44i a, M44i b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M02 != b.M02 || a.M03 != b.M03 || a.M10 != b.M10 || a.M11 != b.M11 || a.M12 != b.M12 || a.M13 != b.M13 || a.M20 != b.M20 || a.M21 != b.M21 || a.M22 != b.M22 || a.M23 != b.M23 || a.M30 != b.M30 || a.M31 != b.M31 || a.M32 != b.M32 || a.M33 != b.M33; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M44i m, int s) { return m.M00 != s || m.M01 != s || m.M02 != s || m.M03 != s || m.M10 != s || m.M11 != s || m.M12 != s || m.M13 != s || m.M20 != s || m.M21 != s || m.M22 != s || m.M23 != s || m.M30 != s || m.M31 != s || m.M32 != s || m.M33 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(int s, M44i m) { return s != m.M00 || s != m.M01 || s != m.M02 || s != m.M03 || s != m.M10 || s != m.M11 || s != m.M12 || s != m.M13 || s != m.M20 || s != m.M21 || s != m.M22 || s != m.M23 || s != m.M30 || s != m.M31 || s != m.M32 || s != m.M33; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M44i m0, M44i m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M02 < m1.M02) return -1; if (m0.M02 > m1.M02) return +1; if (m0.M03 < m1.M03) return -1; if (m0.M03 > m1.M03) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; if (m0.M12 < m1.M12) return -1; if (m0.M12 > m1.M12) return +1; if (m0.M13 < m1.M13) return -1; if (m0.M13 > m1.M13) return +1; if (m0.M20 < m1.M20) return -1; if (m0.M20 > m1.M20) return +1; if (m0.M21 < m1.M21) return -1; if (m0.M21 > m1.M21) return +1; if (m0.M22 < m1.M22) return -1; if (m0.M22 > m1.M22) return +1; if (m0.M23 < m1.M23) return -1; if (m0.M23 > m1.M23) return +1; if (m0.M30 < m1.M30) return -1; if (m0.M30 > m1.M30) return +1; if (m0.M31 < m1.M31) return -1; if (m0.M31 > m1.M31) return +1; if (m0.M32 < m1.M32) return -1; if (m0.M32 > m1.M32) return +1; if (m0.M33 < m1.M33) return -1; if (m0.M33 > m1.M33) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MinElement(M44i m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MaxElement(M44i m) => m.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M44i m, int epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M02.IsTiny(epsilon) || m.M03.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon) || m.M12.IsTiny(epsilon) || m.M13.IsTiny(epsilon) || m.M20.IsTiny(epsilon) || m.M21.IsTiny(epsilon) || m.M22.IsTiny(epsilon) || m.M23.IsTiny(epsilon) || m.M30.IsTiny(epsilon) || m.M31.IsTiny(epsilon) || m.M32.IsTiny(epsilon) || m.M33.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M44i m, int epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M02.IsTiny(epsilon) && m.M03.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon) && m.M12.IsTiny(epsilon) && m.M13.IsTiny(epsilon) && m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon) && m.M22.IsTiny(epsilon) && m.M23.IsTiny(epsilon) && m.M30.IsTiny(epsilon) && m.M31.IsTiny(epsilon) && m.M32.IsTiny(epsilon) && m.M33.IsTiny(epsilon); #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M44i a, M44i b, int epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M44i m, int epsilon) => Mat.AllTiny(m, epsilon); #endregion } public static class IRandomUniformM44iExtensions { #region IRandomUniform extensions for M44i /// /// Uses UniformInt() to generate the elements of an M44i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i UniformM44i(this IRandomUniform rnd) { return new M44i( rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt()); } /// /// Uses UniformIntNonZero() to generate the elements of an M44i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i UniformM44iNonZero(this IRandomUniform rnd) { return new M44i( rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero()); } /// /// Uses UniformInt(int) to generate the elements of an M44i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i UniformM44i(this IRandomUniform rnd, int size) { return new M44i( rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size)); } /// /// Uses UniformInt(int) to generate the elements of an M44i matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i UniformM44i(this IRandomUniform rnd, M44i size) { return new M44i( rnd.UniformInt(size.M00), rnd.UniformInt(size.M01), rnd.UniformInt(size.M02), rnd.UniformInt(size.M03), rnd.UniformInt(size.M10), rnd.UniformInt(size.M11), rnd.UniformInt(size.M12), rnd.UniformInt(size.M13), rnd.UniformInt(size.M20), rnd.UniformInt(size.M21), rnd.UniformInt(size.M22), rnd.UniformInt(size.M23), rnd.UniformInt(size.M30), rnd.UniformInt(size.M31), rnd.UniformInt(size.M32), rnd.UniformInt(size.M33)); } #endregion } #endregion #region M44l [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M44l : IEquatable, IValidity, IMatrix { [DataMember] public long M00, M01, M02, M03; [DataMember] public long M10, M11, M12, M13; [DataMember] public long M20, M21, M22, M23; [DataMember] public long M30, M31, M32, M33; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(long value) { M00 = value; M01 = 0; M02 = 0; M03 = 0; M10 = 0; M11 = value; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = value; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l( long m00, long m01, long m02, long m03, long m10, long m11, long m12, long m13, long m20, long m21, long m22, long m23, long m30, long m31, long m32, long m33) { M00 = m00; M01 = m01; M02 = m02; M03 = m03; M10 = m10; M11 = m11; M12 = m12; M13 = m13; M20 = m20; M21 = m21; M22 = m22; M23 = m23; M30 = m30; M31 = m31; M32 = m32; M33 = m33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(long[] a) { M00 = a[0]; M01 = a[1]; M02 = a[2]; M03 = a[3]; M10 = a[4]; M11 = a[5]; M12 = a[6]; M13 = a[7]; M20 = a[8]; M21 = a[9]; M22 = a[10]; M23 = a[11]; M30 = a[12]; M31 = a[13]; M32 = a[14]; M33 = a[15]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(long[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M02 = a[start + 2]; M03 = a[start + 3]; M10 = a[start + 4]; M11 = a[start + 5]; M12 = a[start + 6]; M13 = a[start + 7]; M20 = a[start + 8]; M21 = a[start + 9]; M22 = a[start + 10]; M23 = a[start + 11]; M30 = a[start + 12]; M31 = a[start + 13]; M32 = a[start + 14]; M33 = a[start + 15]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M22i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = 0; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M23i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M33i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = 0; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M34i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = (long)m.M03; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = (long)m.M13; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = (long)m.M23; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M44i m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = (long)m.M03; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = (long)m.M13; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = (long)m.M23; M30 = (long)m.M30; M31 = (long)m.M31; M32 = (long)m.M32; M33 = (long)m.M33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M22l m) { M00 = m.M00; M01 = m.M01; M02 = 0; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M23l m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M33l m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = 0; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M34l m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = m.M03; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = m.M13; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = m.M23; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M22f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = 0; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M23f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M33f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = 0; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M34f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = (long)m.M03; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = (long)m.M13; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = (long)m.M23; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M44f m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = (long)m.M03; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = (long)m.M13; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = (long)m.M23; M30 = (long)m.M30; M31 = (long)m.M31; M32 = (long)m.M32; M33 = (long)m.M33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M22d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = 0; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M23d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M33d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = 0; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = 0; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M34d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = (long)m.M03; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = (long)m.M13; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = (long)m.M23; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44l(M44d m) { M00 = (long)m.M00; M01 = (long)m.M01; M02 = (long)m.M02; M03 = (long)m.M03; M10 = (long)m.M10; M11 = (long)m.M11; M12 = (long)m.M12; M13 = (long)m.M13; M20 = (long)m.M20; M21 = (long)m.M21; M22 = (long)m.M22; M23 = (long)m.M23; M30 = (long)m.M30; M31 = (long)m.M31; M32 = (long)m.M32; M33 = (long)m.M33; } #endregion #region Conversions public static explicit operator M44l(M22i m) { return new M44l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = 0, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44l(M23i m) { return new M44l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44l(M33i m) { return new M44l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = 0, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44l(M34i m) { return new M44l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = (long)m.M03, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = (long)m.M13, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = (long)m.M23, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44l(M44i m) { return new M44l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = (long)m.M03, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = (long)m.M13, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = (long)m.M23, M30 = (long)m.M30, M31 = (long)m.M31, M32 = (long)m.M32, M33 = (long)m.M33, }; } public static explicit operator M44l(M22l m) { return new M44l { M00 = m.M00, M01 = m.M01, M02 = 0, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44l(M23l m) { return new M44l { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44l(M33l m) { return new M44l { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = 0, M20 = m.M20, M21 = m.M21, M22 = m.M22, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44l(M34l m) { return new M44l { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = m.M03, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = m.M13, M20 = m.M20, M21 = m.M21, M22 = m.M22, M23 = m.M23, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44l(M22f m) { return new M44l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = 0, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44l(M23f m) { return new M44l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44l(M33f m) { return new M44l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = 0, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44l(M34f m) { return new M44l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = (long)m.M03, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = (long)m.M13, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = (long)m.M23, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44l(M44f m) { return new M44l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = (long)m.M03, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = (long)m.M13, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = (long)m.M23, M30 = (long)m.M30, M31 = (long)m.M31, M32 = (long)m.M32, M33 = (long)m.M33, }; } public static explicit operator M44l(M22d m) { return new M44l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = 0, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44l(M23d m) { return new M44l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44l(M33d m) { return new M44l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = 0, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = 0, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44l(M34d m) { return new M44l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = (long)m.M03, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = (long)m.M13, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = (long)m.M23, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44l(M44d m) { return new M44l { M00 = (long)m.M00, M01 = (long)m.M01, M02 = (long)m.M02, M03 = (long)m.M03, M10 = (long)m.M10, M11 = (long)m.M11, M12 = (long)m.M12, M13 = (long)m.M13, M20 = (long)m.M20, M21 = (long)m.M21, M22 = (long)m.M22, M23 = (long)m.M23, M30 = (long)m.M30, M31 = (long)m.M31, M32 = (long)m.M32, M33 = (long)m.M33, }; } public static explicit operator M44l(int[] a) { return new M44l( (long)a[0], (long)a[1], (long)a[2], (long)a[3], (long)a[4], (long)a[5], (long)a[6], (long)a[7], (long)a[8], (long)a[9], (long)a[10], (long)a[11], (long)a[12], (long)a[13], (long)a[14], (long)a[15]); } public static explicit operator M44l(int[,] a) { return new M44l( (long)a[0, 0], (long)a[0, 1], (long)a[0, 2], (long)a[0, 3], (long)a[1, 0], (long)a[1, 1], (long)a[1, 2], (long)a[1, 3], (long)a[2, 0], (long)a[2, 1], (long)a[2, 2], (long)a[2, 3], (long)a[3, 0], (long)a[3, 1], (long)a[3, 2], (long)a[3, 3]); } public static explicit operator int[](M44l m) { return new int[] { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M03, (int)m.M10, (int)m.M11, (int)m.M12, (int)m.M13, (int)m.M20, (int)m.M21, (int)m.M22, (int)m.M23, (int)m.M30, (int)m.M31, (int)m.M32, (int)m.M33 }; } public static explicit operator int[,](M44l m) { return new int[,] { { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M03 }, { (int)m.M10, (int)m.M11, (int)m.M12, (int)m.M13 }, { (int)m.M20, (int)m.M21, (int)m.M22, (int)m.M23 }, { (int)m.M30, (int)m.M31, (int)m.M32, (int)m.M33 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = (int)M00; array[index + 1] = (int)M01; array[index + 2] = (int)M02; array[index + 3] = (int)M03; array[index + 4] = (int)M10; array[index + 5] = (int)M11; array[index + 6] = (int)M12; array[index + 7] = (int)M13; array[index + 8] = (int)M20; array[index + 9] = (int)M21; array[index + 10] = (int)M22; array[index + 11] = (int)M23; array[index + 12] = (int)M30; array[index + 13] = (int)M31; array[index + 14] = (int)M32; array[index + 15] = (int)M33; } public static explicit operator M44l(long[] a) { return new M44l( a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); } public static explicit operator M44l(long[,] a) { return new M44l( a[0, 0], a[0, 1], a[0, 2], a[0, 3], a[1, 0], a[1, 1], a[1, 2], a[1, 3], a[2, 0], a[2, 1], a[2, 2], a[2, 3], a[3, 0], a[3, 1], a[3, 2], a[3, 3]); } public static explicit operator long[](M44l m) { return new long[] { m.M00, m.M01, m.M02, m.M03, m.M10, m.M11, m.M12, m.M13, m.M20, m.M21, m.M22, m.M23, m.M30, m.M31, m.M32, m.M33 }; } public static explicit operator long[,](M44l m) { return new long[,] { { m.M00, m.M01, m.M02, m.M03 }, { m.M10, m.M11, m.M12, m.M13 }, { m.M20, m.M21, m.M22, m.M23 }, { m.M30, m.M31, m.M32, m.M33 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M02; array[index + 3] = M03; array[index + 4] = M10; array[index + 5] = M11; array[index + 6] = M12; array[index + 7] = M13; array[index + 8] = M20; array[index + 9] = M21; array[index + 10] = M22; array[index + 11] = M23; array[index + 12] = M30; array[index + 13] = M31; array[index + 14] = M32; array[index + 15] = M33; } public static explicit operator M44l(float[] a) { return new M44l( (long)a[0], (long)a[1], (long)a[2], (long)a[3], (long)a[4], (long)a[5], (long)a[6], (long)a[7], (long)a[8], (long)a[9], (long)a[10], (long)a[11], (long)a[12], (long)a[13], (long)a[14], (long)a[15]); } public static explicit operator M44l(float[,] a) { return new M44l( (long)a[0, 0], (long)a[0, 1], (long)a[0, 2], (long)a[0, 3], (long)a[1, 0], (long)a[1, 1], (long)a[1, 2], (long)a[1, 3], (long)a[2, 0], (long)a[2, 1], (long)a[2, 2], (long)a[2, 3], (long)a[3, 0], (long)a[3, 1], (long)a[3, 2], (long)a[3, 3]); } public static explicit operator float[](M44l m) { return new float[] { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M03, (float)m.M10, (float)m.M11, (float)m.M12, (float)m.M13, (float)m.M20, (float)m.M21, (float)m.M22, (float)m.M23, (float)m.M30, (float)m.M31, (float)m.M32, (float)m.M33 }; } public static explicit operator float[,](M44l m) { return new float[,] { { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M03 }, { (float)m.M10, (float)m.M11, (float)m.M12, (float)m.M13 }, { (float)m.M20, (float)m.M21, (float)m.M22, (float)m.M23 }, { (float)m.M30, (float)m.M31, (float)m.M32, (float)m.M33 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = (float)M00; array[index + 1] = (float)M01; array[index + 2] = (float)M02; array[index + 3] = (float)M03; array[index + 4] = (float)M10; array[index + 5] = (float)M11; array[index + 6] = (float)M12; array[index + 7] = (float)M13; array[index + 8] = (float)M20; array[index + 9] = (float)M21; array[index + 10] = (float)M22; array[index + 11] = (float)M23; array[index + 12] = (float)M30; array[index + 13] = (float)M31; array[index + 14] = (float)M32; array[index + 15] = (float)M33; } public static explicit operator M44l(double[] a) { return new M44l( (long)a[0], (long)a[1], (long)a[2], (long)a[3], (long)a[4], (long)a[5], (long)a[6], (long)a[7], (long)a[8], (long)a[9], (long)a[10], (long)a[11], (long)a[12], (long)a[13], (long)a[14], (long)a[15]); } public static explicit operator M44l(double[,] a) { return new M44l( (long)a[0, 0], (long)a[0, 1], (long)a[0, 2], (long)a[0, 3], (long)a[1, 0], (long)a[1, 1], (long)a[1, 2], (long)a[1, 3], (long)a[2, 0], (long)a[2, 1], (long)a[2, 2], (long)a[2, 3], (long)a[3, 0], (long)a[3, 1], (long)a[3, 2], (long)a[3, 3]); } public static explicit operator double[](M44l m) { return new double[] { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M03, (double)m.M10, (double)m.M11, (double)m.M12, (double)m.M13, (double)m.M20, (double)m.M21, (double)m.M22, (double)m.M23, (double)m.M30, (double)m.M31, (double)m.M32, (double)m.M33 }; } public static explicit operator double[,](M44l m) { return new double[,] { { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M03 }, { (double)m.M10, (double)m.M11, (double)m.M12, (double)m.M13 }, { (double)m.M20, (double)m.M21, (double)m.M22, (double)m.M23 }, { (double)m.M30, (double)m.M31, (double)m.M32, (double)m.M33 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = (double)M00; array[index + 1] = (double)M01; array[index + 2] = (double)M02; array[index + 3] = (double)M03; array[index + 4] = (double)M10; array[index + 5] = (double)M11; array[index + 6] = (double)M12; array[index + 7] = (double)M13; array[index + 8] = (double)M20; array[index + 9] = (double)M21; array[index + 10] = (double)M22; array[index + 11] = (double)M23; array[index + 12] = (double)M30; array[index + 13] = (double)M31; array[index + 14] = (double)M32; array[index + 15] = (double)M33; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44i Copy(Func element_fun) { return new M44i( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23), element_fun(M30), element_fun(M31), element_fun(M32), element_fun(M33)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44i Copy(Func element_index0_index1_fun) { return new M44i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3), element_index0_index1_fun(M30, 3, 0), element_index0_index1_fun(M31, 3, 1), element_index0_index1_fun(M32, 3, 2), element_index0_index1_fun(M33, 3, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44l Copy(Func element_fun) { return new M44l( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23), element_fun(M30), element_fun(M31), element_fun(M32), element_fun(M33)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44l Copy(Func element_index0_index1_fun) { return new M44l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3), element_index0_index1_fun(M30, 3, 0), element_index0_index1_fun(M31, 3, 1), element_index0_index1_fun(M32, 3, 2), element_index0_index1_fun(M33, 3, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44f Copy(Func element_fun) { return new M44f( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23), element_fun(M30), element_fun(M31), element_fun(M32), element_fun(M33)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44f Copy(Func element_index0_index1_fun) { return new M44f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3), element_index0_index1_fun(M30, 3, 0), element_index0_index1_fun(M31, 3, 1), element_index0_index1_fun(M32, 3, 2), element_index0_index1_fun(M33, 3, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44d Copy(Func element_fun) { return new M44d( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23), element_fun(M30), element_fun(M31), element_fun(M32), element_fun(M33)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44d Copy(Func element_index0_index1_fun) { return new M44d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3), element_index0_index1_fun(M30, 3, 0), element_index0_index1_fun(M31, 3, 1), element_index0_index1_fun(M32, 3, 2), element_index0_index1_fun(M33, 3, 3)); } /// /// Returns a copy of the upper left sub matrix. /// public readonly M33l UpperLeftM33() { return (M33l)this; } public readonly long[] ToArray() { var array = new long[16]; array[0] = M00; array[1] = M01; array[2] = M02; array[3] = M03; array[4] = M10; array[5] = M11; array[6] = M12; array[7] = M13; array[8] = M20; array[9] = M21; array[10] = M22; array[11] = M23; array[12] = M30; array[13] = M31; array[14] = M32; array[15] = M33; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l FromCols(V4l col0, V4l col1, V4l col2, V4l col3) { return new M44l( col0.X, col1.X, col2.X, col3.X, col0.Y, col1.Y, col2.Y, col3.Y, col0.Z, col1.Z, col2.Z, col3.Z, col0.W, col1.W, col2.W, col3.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l FromRows(V4l row0, V4l row1, V4l row2, V4l row3) { return new M44l( row0.X, row0.Y, row0.Z, row0.W, row1.X, row1.Y, row1.Z, row1.W, row2.X, row2.Y, row2.Z, row2.W, row3.X, row3.Y, row3.Z, row3.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l FromDiagonal(long value) { return new M44l( value, 0, 0, 0, 0, value, 0, 0, 0, 0, value, 0, 0, 0, 0, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l FromDiagonal(long m00, long m11, long m22, long m33) { return new M44l( m00, 0, 0, 0, 0, m11, 0, 0, 0, 0, m22, 0, 0, 0, 0, m33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l FromDiagonal(V4l s) { return new M44l( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0, 0, 0, 0, s.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l FromAntiDiagonal(long value) { return new M44l( 0, 0, 0, value, 0, 0, value, 0, 0, value, 0, 0, value, 0, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l FromAntiDiagonal(long m03, long m12, long m21, long m30) { return new M44l( 0, 0, 0, m03, 0, 0, m12, 0, 0, m21, 0, 0, m30, 0, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l FromAntiDiagonal(V4l s) { return new M44l( 0, 0, 0, s.X, 0, 0, s.Y, 0, 0, s.Z, 0, 0, s.W, 0, 0, 0); } #region Scale /// /// Creates a transformation using 4 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l Scale(long sX, long sY, long sZ, long sW) => FromDiagonal(sX, sY, sZ, sW); /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l Scale(V4l s) => FromDiagonal(s); /// /// Creates a homogenous transformation using a uniform scale. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l Scale(long s) { return new M44l( s, 0, 0, 0, 0, s, 0, 0, 0, 0, s, 0, 0, 0, 0, 1); } /// /// Creates a transformation using 3 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l Scale(long sX, long sY, long sZ) { return new M44l( sX, 0, 0, 0, 0, sY, 0, 0, 0, 0, sZ, 0, 0, 0, 0, 1); } /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l Scale(V3l s) { return new M44l( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0, 0, 0, 0, 1); } #endregion #region Translation /// /// Creates a transformation with the translational component given by 3 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l Translation(long tX, long tY, long tZ) { return new M44l( 1, 0, 0, tX, 0, 1, 0, tY, 0, 0, 1, tZ, 0, 0, 0, 1); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l Translation(V3l t) { return new M44l( 1, 0, 0, t.X, 0, 1, 0, t.Y, 0, 0, 1, t.Z, 0, 0, 0, 1); } #endregion #region Shearing /// /// Creates a shear transformation matrix along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l ShearXY(long factorX, long factorY) { return new M44l( 1, 0, factorX, 0, 0, 1, factorY, 0, 0, 0, 1, 0, 0, 0, 0, 1); } /// /// Creates a shear transformation matrix along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l ShearXZ(long factorX, long factorZ) { return new M44l( 1, factorX, 0, 0, 0, 1, 0, 0, 0, factorZ, 1, 0, 0, 0, 0, 1); } /// /// Creates a shear transformation matrix along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l ShearYZ(long factorY, long factorZ) { return new M44l( 1, 0, 0, 0, factorY, 1, 0, 0, factorZ, 0, 1, 0, 0, 0, 0, 1); } #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l DivideByInt(M44l m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M02; yield return M03; yield return M10; yield return M11; yield return M12; yield return M13; yield return M20; yield return M21; yield return M22; yield return M23; yield return M30; yield return M31; yield return M32; yield return M33; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; yield return R2; yield return R3; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; yield return C2; yield return C3; } } [XmlIgnore] public V4l R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4l( M00, M01, M02, M03); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; M02 = value.Z; M03 = value.W; } } [XmlIgnore] public V4l R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4l( M10, M11, M12, M13); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; M12 = value.Z; M13 = value.W; } } [XmlIgnore] public V4l R2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4l( M20, M21, M22, M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M20 = value.X; M21 = value.Y; M22 = value.Z; M23 = value.W; } } [XmlIgnore] public V4l R3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4l( M30, M31, M32, M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M30 = value.X; M31 = value.Y; M32 = value.Z; M33 = value.W; } } [XmlIgnore] public V4l C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4l( M00, M10, M20, M30); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; M20 = value.Z; M30 = value.W; } } [XmlIgnore] public V4l C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4l( M01, M11, M21, M31); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; M21 = value.Z; M31 = value.W; } } [XmlIgnore] public V4l C2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4l( M02, M12, M22, M32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M02 = value.X; M12 = value.Y; M22 = value.Z; M32 = value.W; } } [XmlIgnore] public V4l C3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4l( M03, M13, M23, M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M03 = value.X; M13 = value.Y; M23 = value.Z; M33 = value.W; } } public readonly V4l Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V4l(M00, M11, M22, M33); } public readonly V4l AntiDiagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V4l(M03, M12, M21, M30); } /// /// Returns the minimum element of the matrix. /// public readonly long MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23, M30, M31, M32, M33); } /// /// Returns the maximum element of the matrix. /// public readonly long MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23, M30, M31, M32, M33); } public unsafe long this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (long* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (long* ptr = &M00) { ptr[index] = value; } } } public unsafe long this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (long* ptr = &M00) { return ptr[row * 4 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (long* ptr = &M00) { ptr[row * 4 + column] = value; } } } #endregion #region Constants public const int RowCount = 4; public const int ColumnCount = 4; public const int ElementCount = 4 * 4; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(4, 4); } public static M44l Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M44l(0); } public static M44l Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M44l(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly long Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M02) + Fun.Abs(M03) + Fun.Abs(M10) + Fun.Abs(M11) + Fun.Abs(M12) + Fun.Abs(M13) + Fun.Abs(M20) + Fun.Abs(M21) + Fun.Abs(M22) + Fun.Abs(M23) + Fun.Abs(M30) + Fun.Abs(M31) + Fun.Abs(M32) + Fun.Abs(M33); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly double Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M02 * M02 + M03 * M03 + M10 * M10 + M11 * M11 + M12 * M12 + M13 * M13 + M20 * M20 + M21 * M21 + M22 * M22 + M23 * M23 + M30 * M30 + M31 * M31 + M32 * M32 + M33 * M33); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly long NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02), Fun.Abs(M03)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12), Fun.Abs(M13)), Fun.Max( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22), Fun.Abs(M23)), Fun.Max( Fun.Abs(M30), Fun.Abs(M31), Fun.Abs(M32), Fun.Abs(M33))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly long NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02), Fun.Abs(M03)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12), Fun.Abs(M13)), Fun.Min( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22), Fun.Abs(M23)), Fun.Min( Fun.Abs(M30), Fun.Abs(M31), Fun.Abs(M32), Fun.Abs(M33))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator -(M44l m) { return new M44l( -m.M00, -m.M01, -m.M02, -m.M03, -m.M10, -m.M11, -m.M12, -m.M13, -m.M20, -m.M21, -m.M22, -m.M23, -m.M30, -m.M31, -m.M32, -m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator + (M44l a, M44l b) { return new M44l( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23, a.M30 + b.M30, a.M31 + b.M31, a.M32 + b.M32, a.M33 + b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator + (M44l m, long s) { return new M44l( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s, m.M30 + s, m.M31 + s, m.M32 + s, m.M33 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator + (long s, M44l m) { return new M44l( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23, s + m.M30, s + m.M31, s + m.M32, s + m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator + (M44l a, M44f b) { return new M44f( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23, a.M30 + b.M30, a.M31 + b.M31, a.M32 + b.M32, a.M33 + b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator + (M44l m, float s) { return new M44f( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s, m.M30 + s, m.M31 + s, m.M32 + s, m.M33 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator + (float s, M44l m) { return new M44f( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23, s + m.M30, s + m.M31, s + m.M32, s + m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator + (M44l a, M44d b) { return new M44d( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23, a.M30 + b.M30, a.M31 + b.M31, a.M32 + b.M32, a.M33 + b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator + (M44l m, double s) { return new M44d( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s, m.M30 + s, m.M31 + s, m.M32 + s, m.M33 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator + (double s, M44l m) { return new M44d( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23, s + m.M30, s + m.M31, s + m.M32, s + m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator - (M44l a, M44l b) { return new M44l( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23, a.M30 - b.M30, a.M31 - b.M31, a.M32 - b.M32, a.M33 - b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator - (M44l m, long s) { return new M44l( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s, m.M30 - s, m.M31 - s, m.M32 - s, m.M33 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator - (long s, M44l m) { return new M44l( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23, s - m.M30, s - m.M31, s - m.M32, s - m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator - (M44l a, M44f b) { return new M44f( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23, a.M30 - b.M30, a.M31 - b.M31, a.M32 - b.M32, a.M33 - b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator - (M44l m, float s) { return new M44f( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s, m.M30 - s, m.M31 - s, m.M32 - s, m.M33 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator - (float s, M44l m) { return new M44f( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23, s - m.M30, s - m.M31, s - m.M32, s - m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator - (M44l a, M44d b) { return new M44d( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23, a.M30 - b.M30, a.M31 - b.M31, a.M32 - b.M32, a.M33 - b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator - (M44l m, double s) { return new M44d( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s, m.M30 - s, m.M31 - s, m.M32 - s, m.M33 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator - (double s, M44l m) { return new M44d( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23, s - m.M30, s - m.M31, s - m.M32, s - m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator % (M44l a, M44l b) { return new M44l( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23, a.M30 % b.M30, a.M31 % b.M31, a.M32 % b.M32, a.M33 % b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator % (M44l m, long s) { return new M44l( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s, m.M30 % s, m.M31 % s, m.M32 % s, m.M33 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator % (long s, M44l m) { return new M44l( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23, s % m.M30, s % m.M31, s % m.M32, s % m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator % (M44l a, M44f b) { return new M44f( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23, a.M30 % b.M30, a.M31 % b.M31, a.M32 % b.M32, a.M33 % b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator % (M44l m, float s) { return new M44f( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s, m.M30 % s, m.M31 % s, m.M32 % s, m.M33 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator % (float s, M44l m) { return new M44f( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23, s % m.M30, s % m.M31, s % m.M32, s % m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator % (M44l a, M44d b) { return new M44d( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23, a.M30 % b.M30, a.M31 % b.M31, a.M32 % b.M32, a.M33 % b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator % (M44l m, double s) { return new M44d( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s, m.M30 % s, m.M31 % s, m.M32 % s, m.M33 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator % (double s, M44l m) { return new M44d( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23, s % m.M30, s % m.M31, s % m.M32, s % m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator / (M44l a, M44l b) { return new M44l( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23, a.M30 / b.M30, a.M31 / b.M31, a.M32 / b.M32, a.M33 / b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator / (M44l m, long s) { return new M44l( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s, m.M30 / s, m.M31 / s, m.M32 / s, m.M33 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator / (long s, M44l m) { return new M44l( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23, s / m.M30, s / m.M31, s / m.M32, s / m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator / (M44l a, M44f b) { return new M44f( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23, a.M30 / b.M30, a.M31 / b.M31, a.M32 / b.M32, a.M33 / b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator / (M44l m, float s) { return new M44f( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s, m.M30 / s, m.M31 / s, m.M32 / s, m.M33 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator / (float s, M44l m) { return new M44f( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23, s / m.M30, s / m.M31, s / m.M32, s / m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator / (M44l a, M44d b) { return new M44d( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23, a.M30 / b.M30, a.M31 / b.M31, a.M32 / b.M32, a.M33 / b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator / (M44l m, double s) { return new M44d( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s, m.M30 / s, m.M31 / s, m.M32 / s, m.M33 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator / (double s, M44l m) { return new M44d( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23, s / m.M30, s / m.M31, s / m.M32, s / m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator * (M44l m, long s) { return new M44l( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s, m.M30 * s, m.M31 * s, m.M32 * s, m.M33 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator * (long s, M44l m) { return new M44l( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23, s * m.M30, s * m.M31, s * m.M32, s * m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator * (M44l m, float s) { return new M44f( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s, m.M30 * s, m.M31 * s, m.M32 * s, m.M33 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator * (float s, M44l m) { return new M44f( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23, s * m.M30, s * m.M31, s * m.M32, s * m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator * (M44l m, double s) { return new M44d( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s, m.M30 * s, m.M31 * s, m.M32 * s, m.M33 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator * (double s, M44l m) { return new M44d( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23, s * m.M30, s * m.M31, s * m.M32, s * m.M33); } #endregion #region Bitwise Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator ~(M44l m) { return new M44l( ~m.M00, ~m.M01, ~m.M02, ~m.M03, ~m.M10, ~m.M11, ~m.M12, ~m.M13, ~m.M20, ~m.M21, ~m.M22, ~m.M23, ~m.M30, ~m.M31, ~m.M32, ~m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator <<(M44l a, int s) { return new M44l( a.M00 << s, a.M01 << s, a.M02 << s, a.M03 << s, a.M10 << s, a.M11 << s, a.M12 << s, a.M13 << s, a.M20 << s, a.M21 << s, a.M22 << s, a.M23 << s, a.M30 << s, a.M31 << s, a.M32 << s, a.M33 << s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator >>(M44l a, int s) { return new M44l( a.M00 >> s, a.M01 >> s, a.M02 >> s, a.M03 >> s, a.M10 >> s, a.M11 >> s, a.M12 >> s, a.M13 >> s, a.M20 >> s, a.M21 >> s, a.M22 >> s, a.M23 >> s, a.M30 >> s, a.M31 >> s, a.M32 >> s, a.M33 >> s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator &(M44l a, M44l b) { return new M44l( a.M00 & b.M00, a.M01 & b.M01, a.M02 & b.M02, a.M03 & b.M03, a.M10 & b.M10, a.M11 & b.M11, a.M12 & b.M12, a.M13 & b.M13, a.M20 & b.M20, a.M21 & b.M21, a.M22 & b.M22, a.M23 & b.M23, a.M30 & b.M30, a.M31 & b.M31, a.M32 & b.M32, a.M33 & b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator &(M44l a, long s) { return new M44l( a.M00 & s, a.M01 & s, a.M02 & s, a.M03 & s, a.M10 & s, a.M11 & s, a.M12 & s, a.M13 & s, a.M20 & s, a.M21 & s, a.M22 & s, a.M23 & s, a.M30 & s, a.M31 & s, a.M32 & s, a.M33 & s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator &(long s, M44l a) { return new M44l( s & a.M00, s & a.M01, s & a.M02, s & a.M03, s & a.M10, s & a.M11, s & a.M12, s & a.M13, s & a.M20, s & a.M21, s & a.M22, s & a.M23, s & a.M30, s & a.M31, s & a.M32, s & a.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator |(M44l a, M44l b) { return new M44l( a.M00 | b.M00, a.M01 | b.M01, a.M02 | b.M02, a.M03 | b.M03, a.M10 | b.M10, a.M11 | b.M11, a.M12 | b.M12, a.M13 | b.M13, a.M20 | b.M20, a.M21 | b.M21, a.M22 | b.M22, a.M23 | b.M23, a.M30 | b.M30, a.M31 | b.M31, a.M32 | b.M32, a.M33 | b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator |(M44l a, long s) { return new M44l( a.M00 | s, a.M01 | s, a.M02 | s, a.M03 | s, a.M10 | s, a.M11 | s, a.M12 | s, a.M13 | s, a.M20 | s, a.M21 | s, a.M22 | s, a.M23 | s, a.M30 | s, a.M31 | s, a.M32 | s, a.M33 | s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator |(long s, M44l a) { return new M44l( s | a.M00, s | a.M01, s | a.M02, s | a.M03, s | a.M10, s | a.M11, s | a.M12, s | a.M13, s | a.M20, s | a.M21, s | a.M22, s | a.M23, s | a.M30, s | a.M31, s | a.M32, s | a.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator ^(M44l a, M44l b) { return new M44l( a.M00 ^ b.M00, a.M01 ^ b.M01, a.M02 ^ b.M02, a.M03 ^ b.M03, a.M10 ^ b.M10, a.M11 ^ b.M11, a.M12 ^ b.M12, a.M13 ^ b.M13, a.M20 ^ b.M20, a.M21 ^ b.M21, a.M22 ^ b.M22, a.M23 ^ b.M23, a.M30 ^ b.M30, a.M31 ^ b.M31, a.M32 ^ b.M32, a.M33 ^ b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator ^(M44l a, long s) { return new M44l( a.M00 ^ s, a.M01 ^ s, a.M02 ^ s, a.M03 ^ s, a.M10 ^ s, a.M11 ^ s, a.M12 ^ s, a.M13 ^ s, a.M20 ^ s, a.M21 ^ s, a.M22 ^ s, a.M23 ^ s, a.M30 ^ s, a.M31 ^ s, a.M32 ^ s, a.M33 ^ s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l operator ^(long s, M44l a) { return new M44l( s ^ a.M00, s ^ a.M01, s ^ a.M02, s ^ a.M03, s ^ a.M10, s ^ a.M11, s ^ a.M12, s ^ a.M13, s ^ a.M20, s ^ a.M21, s ^ a.M22, s ^ a.M23, s ^ a.M30, s ^ a.M31, s ^ a.M32, s ^ a.M33); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M44l matrix with a V4l column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator *(M44l m, V4l v) { return new V4l( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z + m.M03 * v.W, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z + m.M13 * v.W, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z + m.M23 * v.W, m.M30 * v.X + m.M31 * v.Y + m.M32 * v.Z + m.M33 * v.W); } /// /// Multiplies a V4l row vector with a M44l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator *(V4l v, M44l m) { return new V4l( v.X * m.M00 + v.Y * m.M10 + v.Z * m.M20 + v.W * m.M30, v.X * m.M01 + v.Y * m.M11 + v.Z * m.M21 + v.W * m.M31, v.X * m.M02 + v.Y * m.M12 + v.Z * m.M22 + v.W * m.M32, v.X * m.M03 + v.Y * m.M13 + v.Z * m.M23 + v.W * m.M33); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M44l a, M44l b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M03 == b.M03 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M13 == b.M13 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22 && a.M23 == b.M23 && a.M30 == b.M30 && a.M31 == b.M31 && a.M32 == b.M32 && a.M33 == b.M33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M44l a, long s) { return a.M00 == s && a.M01 == s && a.M02 == s && a.M03 == s && a.M10 == s && a.M11 == s && a.M12 == s && a.M13 == s && a.M20 == s && a.M21 == s && a.M22 == s && a.M23 == s && a.M30 == s && a.M31 == s && a.M32 == s && a.M33 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(long s, M44l a) { return s == a.M00 && s == a.M01 && s == a.M02 && s == a.M03 && s == a.M10 && s == a.M11 && s == a.M12 && s == a.M13 && s == a.M20 && s == a.M21 && s == a.M22 && s == a.M23 && s == a.M30 && s == a.M31 && s == a.M32 && s == a.M33 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M44l a, M44l b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M44l m, long s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(long s, M44l m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01, M02, M03), HashCode.GetCombined(M10, M11, M12, M13), HashCode.GetCombined(M20, M21, M22, M23), HashCode.GetCombined(M30, M31, M32, M33)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M44l other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M02.Equals(other.M02) && M03.Equals(other.M03) && M10.Equals(other.M10) && M11.Equals(other.M11) && M12.Equals(other.M12) && M13.Equals(other.M13) && M20.Equals(other.M20) && M21.Equals(other.M21) && M22.Equals(other.M22) && M23.Equals(other.M23) && M30.Equals(other.M30) && M31.Equals(other.M31) && M32.Equals(other.M32) && M33.Equals(other.M33); } public override readonly bool Equals(object other) => (other is M44l o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + betweenM + R2.ToString(format, fp, beginR, betweenR, endR) + betweenM + R3.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M44l Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M44l.FromRows( V4l.Parse(x[0]), V4l.Parse(x[1]), V4l.Parse(x[2]), V4l.Parse(x[3]) ); } #endregion #region Matrix Operations /// /// Returns adjoint of this matrix. /// public readonly M44l Adjoint { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { M44l result = new M44l(); for (int row = 0; row < 4; row++) { for (int col = 0; col < 4; col++) { if (((col + row) % 2) == 0) result[col, row] = this.Minor(row, col).Determinant; else result[col, row] = -this.Minor(row, col).Determinant; } } return result; } } /// /// Returns the trace of this matrix. /// The trace is defined as the sum of the diagonal elements, /// and is only defined for square matrices. /// public readonly long Trace { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return M00 + M11 + M22 + M33 ; } } /// /// Gets the determinant of this matrix. /// The determinant is only defined for square matrices. /// public readonly long Determinant { get { // using bottom row because elements M30, M31, and M32 // are zero most of the time. long d = 0; if (M30 != 0.0f) d -= M30 * ( M01 * M12 * M23 + M02 * M13 * M21 + M03 * M11 * M22 - M21 * M12 * M03 - M22 * M13 * M01 - M23 * M11 * M02 ); if (M31 != 0.0f) d += M31 * ( M00 * M12 * M23 + M02 * M13 * M20 + M03 * M10 * M22 - M20 * M12 * M03 - M22 * M13 * M00 - M23 * M10 * M02 ); if (M32 != 0.0f) d -= M32 * ( M00 * M11 * M23 + M01 * M13 * M20 + M03 * M10 * M21 - M20 * M11 * M03 - M21 * M13 * M00 - M23 * M10 * M01 ); if (M33 != 0.0f) d += M33 * ( M00 * M11 * M22 + M01 * M12 * M20 + M02 * M10 * M21 - M20 * M11 * M02 - M21 * M12 * M00 - M22 * M10 * M01 ); return d; } } /// /// Returns whether this matrix is invertible. /// A matrix is invertible if its determinant is not zero. /// public readonly bool Invertible { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant != 0; } } /// /// Returns whether this matrix is singular. /// A matrix is singular if its determinant is zero. /// public readonly bool Singular { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant == 0; } } /// /// Gets transpose of this matrix. /// public readonly M44l Transposed { get { return new M44l { M00 = M00, M01 = M10, M02 = M20, M03 = M30, M10 = M01, M11 = M11, M12 = M21, M13 = M31, M20 = M02, M21 = M12, M22 = M22, M23 = M32, M30 = M03, M31 = M13, M32 = M23, M33 = M33 }; } } #endregion #region Matrix Multiplication public static M44l operator *(M44l a, M44l b) { return new M44l( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20 + a.M03 * b.M30, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21 + a.M03 * b.M31, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22 + a.M03 * b.M32, a.M00 * b.M03 + a.M01 * b.M13 + a.M02 * b.M23 + a.M03 * b.M33, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20 + a.M13 * b.M30, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21 + a.M13 * b.M31, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22 + a.M13 * b.M32, a.M10 * b.M03 + a.M11 * b.M13 + a.M12 * b.M23 + a.M13 * b.M33, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20 + a.M23 * b.M30, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21 + a.M23 * b.M31, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22 + a.M23 * b.M32, a.M20 * b.M03 + a.M21 * b.M13 + a.M22 * b.M23 + a.M23 * b.M33, a.M30 * b.M00 + a.M31 * b.M10 + a.M32 * b.M20 + a.M33 * b.M30, a.M30 * b.M01 + a.M31 * b.M11 + a.M32 * b.M21 + a.M33 * b.M31, a.M30 * b.M02 + a.M31 * b.M12 + a.M32 * b.M22 + a.M33 * b.M32, a.M30 * b.M03 + a.M31 * b.M13 + a.M32 * b.M23 + a.M33 * b.M33 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return (double)this[(int)y, (int)x]; } set { this[(int)y, (int)x] = (long)value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return (double)this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = (long)value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (long)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (long)value; } #endregion } public class M44lEqualityComparer : IEqualityComparer { public static readonly M44lEqualityComparer Default = new M44lEqualityComparer(); #region IEqualityComparer Members public bool Equals(M44l v0, M44l v1) { return v0 == v1; } public int GetHashCode(M44l v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this M44l m) => (m.C0.Length + m.C1.Length + m.C2.Length + m.C3.Length) / 4; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d GetScaleVector(this M44l m) => new V4d(m.C0.Length, m.C1.Length, m.C2.Length, m.C3.Length); /// /// Approximates the uniform scale value of the given transformation matrix (average length of 3D basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale3(this M44l m) => (m.C0.XYZ.Length + m.C1.XYZ.Length + m.C2.XYZ.Length) / 3; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the 3D basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetScaleVector3(this M44l m) => new V3d(m.C0.XYZ.Length, m.C1.XYZ.Length, m.C2.XYZ.Length); #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Norm1(M44l m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(M44l m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NormMax(M44l m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NormMin(M44l m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this M44l m, double p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M02).Pow(p) + Fun.Abs(m.M03).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) + Fun.Abs(m.M12).Pow(p) + Fun.Abs(m.M13).Pow(p) + Fun.Abs(m.M20).Pow(p) + Fun.Abs(m.M21).Pow(p) + Fun.Abs(m.M22).Pow(p) + Fun.Abs(m.M23).Pow(p) + Fun.Abs(m.M30).Pow(p) + Fun.Abs(m.M31).Pow(p) + Fun.Abs(m.M32).Pow(p) + Fun.Abs(m.M33).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static long Distance1(this M44l a, M44l b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M02 - a.M02) + Fun.Abs(b.M03 - a.M03) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11) + Fun.Abs(b.M12 - a.M12) + Fun.Abs(b.M13 - a.M13) + Fun.Abs(b.M20 - a.M20) + Fun.Abs(b.M21 - a.M21) + Fun.Abs(b.M22 - a.M22) + Fun.Abs(b.M23 - a.M23) + Fun.Abs(b.M30 - a.M30) + Fun.Abs(b.M31 - a.M31) + Fun.Abs(b.M32 - a.M32) + Fun.Abs(b.M33 - a.M33); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static double Distance2(this M44l a, M44l b) { return Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M02 - a.M02) + Fun.Square(b.M03 - a.M03) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11) + Fun.Square(b.M12 - a.M12) + Fun.Square(b.M13 - a.M13) + Fun.Square(b.M20 - a.M20) + Fun.Square(b.M21 - a.M21) + Fun.Square(b.M22 - a.M22) + Fun.Square(b.M23 - a.M23) + Fun.Square(b.M30 - a.M30) + Fun.Square(b.M31 - a.M31) + Fun.Square(b.M32 - a.M32) + Fun.Square(b.M33 - a.M33)); } /// /// Returns the p-distance between two matrices. /// public static double Distance(this M44l a, M44l b, double p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M02 - a.M02).Pow(p) + Fun.Abs(b.M03 - a.M03).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) + Fun.Abs(b.M12 - a.M12).Pow(p) + Fun.Abs(b.M13 - a.M13).Pow(p) + Fun.Abs(b.M20 - a.M20).Pow(p) + Fun.Abs(b.M21 - a.M21).Pow(p) + Fun.Abs(b.M22 - a.M22).Pow(p) + Fun.Abs(b.M23 - a.M23).Pow(p) + Fun.Abs(b.M30 - a.M30).Pow(p) + Fun.Abs(b.M31 - a.M31).Pow(p) + Fun.Abs(b.M32 - a.M32).Pow(p) + Fun.Abs(b.M33 - a.M33).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static long DistanceMax(this M44l a, M44l b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02), Fun.Abs(b.M03 - a.M03)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12), Fun.Abs(b.M13 - a.M13)), Fun.Max( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22), Fun.Abs(b.M23 - a.M23)), Fun.Max( Fun.Abs(b.M30 - a.M30), Fun.Abs(b.M31 - a.M31), Fun.Abs(b.M32 - a.M32), Fun.Abs(b.M33 - a.M33))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static long DistanceMin(this M44l a, M44l b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02), Fun.Abs(b.M03 - a.M03)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12), Fun.Abs(b.M13 - a.M13)), Fun.Min( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22), Fun.Abs(b.M23 - a.M23)), Fun.Min( Fun.Abs(b.M30 - a.M30), Fun.Abs(b.M31 - a.M31), Fun.Abs(b.M32 - a.M32), Fun.Abs(b.M33 - a.M33))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Transform(this M44l m, V4l v) => m * v; /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l TransposedTransform(this M44l m, V4l v) => v * m; /// /// Transforms direction vector v (v.W is presumed 0.0) by matrix m. /// public static V3l TransformDir(this M44l m, V3l v) { return new V3l( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z ); } /// /// Transforms point p (v.W is presumed 1.0) by matrix m. /// No projective transform is performed. /// public static V3l TransformPos(this M44l m, V3l p) { return new V3l( m.M00 * p.X + m.M01 * p.Y + m.M02 * p.Z + m.M03, m.M10 * p.X + m.M11 * p.Y + m.M12 * p.Z + m.M13, m.M20 * p.X + m.M21 * p.Y + m.M22 * p.Z + m.M23 ); } /// /// Transforms point p (p.W is presumed 1.0) by matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static V3l TransformPosProj(this M44l m, V3l p) { long s = m.M30 * p.X + m.M31 * p.Y + m.M32 * p.Z + m.M33; return TransformPos(m, p) * (1 / s); } /// /// Transforms point p (p.W is presumed 1.0) by matrix m. /// Projective transform is performed. /// public static V4l TransformPosProjFull(this M44l m, V3l p) { return new V4l( m.M00 * p.X + m.M01 * p.Y + m.M02 * p.Z + m.M03, m.M10 * p.X + m.M11 * p.Y + m.M12 * p.Z + m.M13, m.M20 * p.X + m.M21 * p.Y + m.M22 * p.Z + m.M23, m.M30 * p.X + m.M31 * p.Y + m.M32 * p.Z + m.M33 ); } /// /// Transforms direction vector v (v.W is presumed 0.0) by transposed version of matrix m. /// public static V3l TransposedTransformDir(this M44l m, V3l v) { return new V3l( m.M00 * v.X + m.M10 * v.Y + m.M20 * v.Z, m.M01 * v.X + m.M11 * v.Y + m.M21 * v.Z, m.M02 * v.X + m.M12 * v.Y + m.M22 * v.Z ); } /// /// Transforms point p (v.W is presumed 1.0) by transposed version of matrix m. /// No projective transform is performed. /// public static V3l TransposedTransformPos(this M44l m, V3l p) { return new V3l( m.M00 * p.X + m.M10 * p.Y + m.M20 * p.Z + m.M30, m.M01 * p.X + m.M11 * p.Y + m.M21 * p.Z + m.M31, m.M02 * p.X + m.M12 * p.Y + m.M22 * p.Z + m.M32 ); } /// /// Transforms point p (v.W is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static V3l TransposedTransformPosProj(this M44l m, V3l p) { var s = m.M03 * p.X + m.M13 * p.Y + m.M23 * p.Z + m.M33; return TransposedTransformPos(m, p) * (1 / s); } [Obsolete("Use TransposedTransformPosProj instead.")] public static V3l TransposedTransformProj(this M44l m, V3l p) => m.TransposedTransformPosProj(p); /// /// Transforms point p (v.W is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. /// public static V4l TransposedTransformPosProjFull(this M44l m, V3l p) { return new V4l( m.M00 * p.X + m.M10 * p.Y + m.M20 * p.Z + m.M30, m.M01 * p.X + m.M11 * p.Y + m.M21 * p.Z + m.M31, m.M02 * p.X + m.M12 * p.Y + m.M22 * p.Z + m.M32, m.M03 * p.X + m.M13 * p.Y + m.M23 * p.Z + m.M33 ); } [Obsolete("Use TransposedTransformPosProjFull instead.")] public static V4l TransposedTransformProjFull(this M44l m, V3l p) => m.TransposedTransformPosProjFull(p); #endregion #region Operations /// /// Returns the given to a deleting the /// specified row and column. /// public static M33l Minor(this M44l m, int row, int column) { M33l rs = new M33l(); for (int k = 0; k < 9; k++) { var i = k / 3; var j = k % 3; var ii = (i < row) ? i : i + 1; var jj = (j < column) ? j : j + 1; rs[k] = m[ii * 4 + jj]; } return rs; } /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V4l Row(this M44l m, int index) { long* ptr = &m.M00; return new V4l(ptr[index * 4], ptr[index * 4 + 1], ptr[index * 4 + 2], ptr[index * 4 + 3]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V4l Column(this M44l m, int index) { long* ptr = &m.M00; return new V4l(ptr[index], ptr[index + 4], ptr[index + 8], ptr[index + 12]); } /// /// Returns the determinant of the given matrix. /// The determinant is only defined for square matrices. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Determinant(M44l m) => m.Determinant; /// /// Returns the transpose of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l Transposed(M44l m) => m.Transposed; /// /// Transposes the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transpose(this ref M44l m) { Fun.Swap(ref m.M10, ref m.M01); Fun.Swap(ref m.M20, ref m.M02); Fun.Swap(ref m.M21, ref m.M12); Fun.Swap(ref m.M30, ref m.M03); Fun.Swap(ref m.M31, ref m.M13); Fun.Swap(ref m.M32, ref m.M23); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M44l a, M44l b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M02 < b.M02 && a.M03 < b.M03 && a.M10 < b.M10 && a.M11 < b.M11 && a.M12 < b.M12 && a.M13 < b.M13 && a.M20 < b.M20 && a.M21 < b.M21 && a.M22 < b.M22 && a.M23 < b.M23 && a.M30 < b.M30 && a.M31 < b.M31 && a.M32 < b.M32 && a.M33 < b.M33; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M44l m, long s) { return m.M00 < s && m.M01 < s && m.M02 < s && m.M03 < s && m.M10 < s && m.M11 < s && m.M12 < s && m.M13 < s && m.M20 < s && m.M21 < s && m.M22 < s && m.M23 < s && m.M30 < s && m.M31 < s && m.M32 < s && m.M33 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(long s, M44l m) { return s < m.M00 && s < m.M01 && s < m.M02 && s < m.M03 && s < m.M10 && s < m.M11 && s < m.M12 && s < m.M13 && s < m.M20 && s < m.M21 && s < m.M22 && s < m.M23 && s < m.M30 && s < m.M31 && s < m.M32 && s < m.M33; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M44l a, M44l b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M02 < b.M02 || a.M03 < b.M03 || a.M10 < b.M10 || a.M11 < b.M11 || a.M12 < b.M12 || a.M13 < b.M13 || a.M20 < b.M20 || a.M21 < b.M21 || a.M22 < b.M22 || a.M23 < b.M23 || a.M30 < b.M30 || a.M31 < b.M31 || a.M32 < b.M32 || a.M33 < b.M33; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M44l m, long s) { return m.M00 < s || m.M01 < s || m.M02 < s || m.M03 < s || m.M10 < s || m.M11 < s || m.M12 < s || m.M13 < s || m.M20 < s || m.M21 < s || m.M22 < s || m.M23 < s || m.M30 < s || m.M31 < s || m.M32 < s || m.M33 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(long s, M44l m) { return s < m.M00 || s < m.M01 || s < m.M02 || s < m.M03 || s < m.M10 || s < m.M11 || s < m.M12 || s < m.M13 || s < m.M20 || s < m.M21 || s < m.M22 || s < m.M23 || s < m.M30 || s < m.M31 || s < m.M32 || s < m.M33; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M44l a, M44l b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M02 > b.M02 && a.M03 > b.M03 && a.M10 > b.M10 && a.M11 > b.M11 && a.M12 > b.M12 && a.M13 > b.M13 && a.M20 > b.M20 && a.M21 > b.M21 && a.M22 > b.M22 && a.M23 > b.M23 && a.M30 > b.M30 && a.M31 > b.M31 && a.M32 > b.M32 && a.M33 > b.M33; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M44l m, long s) { return m.M00 > s && m.M01 > s && m.M02 > s && m.M03 > s && m.M10 > s && m.M11 > s && m.M12 > s && m.M13 > s && m.M20 > s && m.M21 > s && m.M22 > s && m.M23 > s && m.M30 > s && m.M31 > s && m.M32 > s && m.M33 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(long s, M44l m) { return s > m.M00 && s > m.M01 && s > m.M02 && s > m.M03 && s > m.M10 && s > m.M11 && s > m.M12 && s > m.M13 && s > m.M20 && s > m.M21 && s > m.M22 && s > m.M23 && s > m.M30 && s > m.M31 && s > m.M32 && s > m.M33; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M44l a, M44l b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M02 > b.M02 || a.M03 > b.M03 || a.M10 > b.M10 || a.M11 > b.M11 || a.M12 > b.M12 || a.M13 > b.M13 || a.M20 > b.M20 || a.M21 > b.M21 || a.M22 > b.M22 || a.M23 > b.M23 || a.M30 > b.M30 || a.M31 > b.M31 || a.M32 > b.M32 || a.M33 > b.M33; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M44l m, long s) { return m.M00 > s || m.M01 > s || m.M02 > s || m.M03 > s || m.M10 > s || m.M11 > s || m.M12 > s || m.M13 > s || m.M20 > s || m.M21 > s || m.M22 > s || m.M23 > s || m.M30 > s || m.M31 > s || m.M32 > s || m.M33 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(long s, M44l m) { return s > m.M00 || s > m.M01 || s > m.M02 || s > m.M03 || s > m.M10 || s > m.M11 || s > m.M12 || s > m.M13 || s > m.M20 || s > m.M21 || s > m.M22 || s > m.M23 || s > m.M30 || s > m.M31 || s > m.M32 || s > m.M33; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M44l a, M44l b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M02 <= b.M02 && a.M03 <= b.M03 && a.M10 <= b.M10 && a.M11 <= b.M11 && a.M12 <= b.M12 && a.M13 <= b.M13 && a.M20 <= b.M20 && a.M21 <= b.M21 && a.M22 <= b.M22 && a.M23 <= b.M23 && a.M30 <= b.M30 && a.M31 <= b.M31 && a.M32 <= b.M32 && a.M33 <= b.M33; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M44l m, long s) { return m.M00 <= s && m.M01 <= s && m.M02 <= s && m.M03 <= s && m.M10 <= s && m.M11 <= s && m.M12 <= s && m.M13 <= s && m.M20 <= s && m.M21 <= s && m.M22 <= s && m.M23 <= s && m.M30 <= s && m.M31 <= s && m.M32 <= s && m.M33 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(long s, M44l m) { return s <= m.M00 && s <= m.M01 && s <= m.M02 && s <= m.M03 && s <= m.M10 && s <= m.M11 && s <= m.M12 && s <= m.M13 && s <= m.M20 && s <= m.M21 && s <= m.M22 && s <= m.M23 && s <= m.M30 && s <= m.M31 && s <= m.M32 && s <= m.M33; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M44l a, M44l b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M02 <= b.M02 || a.M03 <= b.M03 || a.M10 <= b.M10 || a.M11 <= b.M11 || a.M12 <= b.M12 || a.M13 <= b.M13 || a.M20 <= b.M20 || a.M21 <= b.M21 || a.M22 <= b.M22 || a.M23 <= b.M23 || a.M30 <= b.M30 || a.M31 <= b.M31 || a.M32 <= b.M32 || a.M33 <= b.M33; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M44l m, long s) { return m.M00 <= s || m.M01 <= s || m.M02 <= s || m.M03 <= s || m.M10 <= s || m.M11 <= s || m.M12 <= s || m.M13 <= s || m.M20 <= s || m.M21 <= s || m.M22 <= s || m.M23 <= s || m.M30 <= s || m.M31 <= s || m.M32 <= s || m.M33 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(long s, M44l m) { return s <= m.M00 || s <= m.M01 || s <= m.M02 || s <= m.M03 || s <= m.M10 || s <= m.M11 || s <= m.M12 || s <= m.M13 || s <= m.M20 || s <= m.M21 || s <= m.M22 || s <= m.M23 || s <= m.M30 || s <= m.M31 || s <= m.M32 || s <= m.M33; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M44l a, M44l b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M02 >= b.M02 && a.M03 >= b.M03 && a.M10 >= b.M10 && a.M11 >= b.M11 && a.M12 >= b.M12 && a.M13 >= b.M13 && a.M20 >= b.M20 && a.M21 >= b.M21 && a.M22 >= b.M22 && a.M23 >= b.M23 && a.M30 >= b.M30 && a.M31 >= b.M31 && a.M32 >= b.M32 && a.M33 >= b.M33; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M44l m, long s) { return m.M00 >= s && m.M01 >= s && m.M02 >= s && m.M03 >= s && m.M10 >= s && m.M11 >= s && m.M12 >= s && m.M13 >= s && m.M20 >= s && m.M21 >= s && m.M22 >= s && m.M23 >= s && m.M30 >= s && m.M31 >= s && m.M32 >= s && m.M33 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(long s, M44l m) { return s >= m.M00 && s >= m.M01 && s >= m.M02 && s >= m.M03 && s >= m.M10 && s >= m.M11 && s >= m.M12 && s >= m.M13 && s >= m.M20 && s >= m.M21 && s >= m.M22 && s >= m.M23 && s >= m.M30 && s >= m.M31 && s >= m.M32 && s >= m.M33; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M44l a, M44l b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M02 >= b.M02 || a.M03 >= b.M03 || a.M10 >= b.M10 || a.M11 >= b.M11 || a.M12 >= b.M12 || a.M13 >= b.M13 || a.M20 >= b.M20 || a.M21 >= b.M21 || a.M22 >= b.M22 || a.M23 >= b.M23 || a.M30 >= b.M30 || a.M31 >= b.M31 || a.M32 >= b.M32 || a.M33 >= b.M33; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M44l m, long s) { return m.M00 >= s || m.M01 >= s || m.M02 >= s || m.M03 >= s || m.M10 >= s || m.M11 >= s || m.M12 >= s || m.M13 >= s || m.M20 >= s || m.M21 >= s || m.M22 >= s || m.M23 >= s || m.M30 >= s || m.M31 >= s || m.M32 >= s || m.M33 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(long s, M44l m) { return s >= m.M00 || s >= m.M01 || s >= m.M02 || s >= m.M03 || s >= m.M10 || s >= m.M11 || s >= m.M12 || s >= m.M13 || s >= m.M20 || s >= m.M21 || s >= m.M22 || s >= m.M23 || s >= m.M30 || s >= m.M31 || s >= m.M32 || s >= m.M33; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M44l a, M44l b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M03 == b.M03 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M13 == b.M13 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22 && a.M23 == b.M23 && a.M30 == b.M30 && a.M31 == b.M31 && a.M32 == b.M32 && a.M33 == b.M33; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M44l m, long s) { return m.M00 == s && m.M01 == s && m.M02 == s && m.M03 == s && m.M10 == s && m.M11 == s && m.M12 == s && m.M13 == s && m.M20 == s && m.M21 == s && m.M22 == s && m.M23 == s && m.M30 == s && m.M31 == s && m.M32 == s && m.M33 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(long s, M44l m) { return s == m.M00 && s == m.M01 && s == m.M02 && s == m.M03 && s == m.M10 && s == m.M11 && s == m.M12 && s == m.M13 && s == m.M20 && s == m.M21 && s == m.M22 && s == m.M23 && s == m.M30 && s == m.M31 && s == m.M32 && s == m.M33; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M44l a, M44l b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M02 == b.M02 || a.M03 == b.M03 || a.M10 == b.M10 || a.M11 == b.M11 || a.M12 == b.M12 || a.M13 == b.M13 || a.M20 == b.M20 || a.M21 == b.M21 || a.M22 == b.M22 || a.M23 == b.M23 || a.M30 == b.M30 || a.M31 == b.M31 || a.M32 == b.M32 || a.M33 == b.M33; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M44l m, long s) { return m.M00 == s || m.M01 == s || m.M02 == s || m.M03 == s || m.M10 == s || m.M11 == s || m.M12 == s || m.M13 == s || m.M20 == s || m.M21 == s || m.M22 == s || m.M23 == s || m.M30 == s || m.M31 == s || m.M32 == s || m.M33 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(long s, M44l m) { return s == m.M00 || s == m.M01 || s == m.M02 || s == m.M03 || s == m.M10 || s == m.M11 || s == m.M12 || s == m.M13 || s == m.M20 || s == m.M21 || s == m.M22 || s == m.M23 || s == m.M30 || s == m.M31 || s == m.M32 || s == m.M33; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M44l a, M44l b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M02 != b.M02 && a.M03 != b.M03 && a.M10 != b.M10 && a.M11 != b.M11 && a.M12 != b.M12 && a.M13 != b.M13 && a.M20 != b.M20 && a.M21 != b.M21 && a.M22 != b.M22 && a.M23 != b.M23 && a.M30 != b.M30 && a.M31 != b.M31 && a.M32 != b.M32 && a.M33 != b.M33; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M44l m, long s) { return m.M00 != s && m.M01 != s && m.M02 != s && m.M03 != s && m.M10 != s && m.M11 != s && m.M12 != s && m.M13 != s && m.M20 != s && m.M21 != s && m.M22 != s && m.M23 != s && m.M30 != s && m.M31 != s && m.M32 != s && m.M33 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(long s, M44l m) { return s != m.M00 && s != m.M01 && s != m.M02 && s != m.M03 && s != m.M10 && s != m.M11 && s != m.M12 && s != m.M13 && s != m.M20 && s != m.M21 && s != m.M22 && s != m.M23 && s != m.M30 && s != m.M31 && s != m.M32 && s != m.M33; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M44l a, M44l b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M02 != b.M02 || a.M03 != b.M03 || a.M10 != b.M10 || a.M11 != b.M11 || a.M12 != b.M12 || a.M13 != b.M13 || a.M20 != b.M20 || a.M21 != b.M21 || a.M22 != b.M22 || a.M23 != b.M23 || a.M30 != b.M30 || a.M31 != b.M31 || a.M32 != b.M32 || a.M33 != b.M33; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M44l m, long s) { return m.M00 != s || m.M01 != s || m.M02 != s || m.M03 != s || m.M10 != s || m.M11 != s || m.M12 != s || m.M13 != s || m.M20 != s || m.M21 != s || m.M22 != s || m.M23 != s || m.M30 != s || m.M31 != s || m.M32 != s || m.M33 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(long s, M44l m) { return s != m.M00 || s != m.M01 || s != m.M02 || s != m.M03 || s != m.M10 || s != m.M11 || s != m.M12 || s != m.M13 || s != m.M20 || s != m.M21 || s != m.M22 || s != m.M23 || s != m.M30 || s != m.M31 || s != m.M32 || s != m.M33; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M44l m0, M44l m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M02 < m1.M02) return -1; if (m0.M02 > m1.M02) return +1; if (m0.M03 < m1.M03) return -1; if (m0.M03 > m1.M03) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; if (m0.M12 < m1.M12) return -1; if (m0.M12 > m1.M12) return +1; if (m0.M13 < m1.M13) return -1; if (m0.M13 > m1.M13) return +1; if (m0.M20 < m1.M20) return -1; if (m0.M20 > m1.M20) return +1; if (m0.M21 < m1.M21) return -1; if (m0.M21 > m1.M21) return +1; if (m0.M22 < m1.M22) return -1; if (m0.M22 > m1.M22) return +1; if (m0.M23 < m1.M23) return -1; if (m0.M23 > m1.M23) return +1; if (m0.M30 < m1.M30) return -1; if (m0.M30 > m1.M30) return +1; if (m0.M31 < m1.M31) return -1; if (m0.M31 > m1.M31) return +1; if (m0.M32 < m1.M32) return -1; if (m0.M32 > m1.M32) return +1; if (m0.M33 < m1.M33) return -1; if (m0.M33 > m1.M33) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MinElement(M44l m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MaxElement(M44l m) => m.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M44l m, long epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M02.IsTiny(epsilon) || m.M03.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon) || m.M12.IsTiny(epsilon) || m.M13.IsTiny(epsilon) || m.M20.IsTiny(epsilon) || m.M21.IsTiny(epsilon) || m.M22.IsTiny(epsilon) || m.M23.IsTiny(epsilon) || m.M30.IsTiny(epsilon) || m.M31.IsTiny(epsilon) || m.M32.IsTiny(epsilon) || m.M33.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M44l m, long epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M02.IsTiny(epsilon) && m.M03.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon) && m.M12.IsTiny(epsilon) && m.M13.IsTiny(epsilon) && m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon) && m.M22.IsTiny(epsilon) && m.M23.IsTiny(epsilon) && m.M30.IsTiny(epsilon) && m.M31.IsTiny(epsilon) && m.M32.IsTiny(epsilon) && m.M33.IsTiny(epsilon); #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M44l a, M44l b, long epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M44l m, long epsilon) => Mat.AllTiny(m, epsilon); #endregion } public static class IRandomUniformM44lExtensions { #region IRandomUniform extensions for M44l /// /// Uses UniformLong() to generate the elements of an M44l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l UniformM44l(this IRandomUniform rnd) { return new M44l( rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong()); } /// /// Uses UniformLongNonZero() to generate the elements of an M44l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l UniformM44lNonZero(this IRandomUniform rnd) { return new M44l( rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero()); } /// /// Uses UniformLong(long) to generate the elements of an M44l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l UniformM44l(this IRandomUniform rnd, long size) { return new M44l( rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size)); } /// /// Uses UniformLong(long) to generate the elements of an M44l matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l UniformM44l(this IRandomUniform rnd, M44l size) { return new M44l( rnd.UniformLong(size.M00), rnd.UniformLong(size.M01), rnd.UniformLong(size.M02), rnd.UniformLong(size.M03), rnd.UniformLong(size.M10), rnd.UniformLong(size.M11), rnd.UniformLong(size.M12), rnd.UniformLong(size.M13), rnd.UniformLong(size.M20), rnd.UniformLong(size.M21), rnd.UniformLong(size.M22), rnd.UniformLong(size.M23), rnd.UniformLong(size.M30), rnd.UniformLong(size.M31), rnd.UniformLong(size.M32), rnd.UniformLong(size.M33)); } #endregion } #endregion #region M44f [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M44f : IEquatable, IValidity, IMatrix { [DataMember] public float M00, M01, M02, M03; [DataMember] public float M10, M11, M12, M13; [DataMember] public float M20, M21, M22, M23; [DataMember] public float M30, M31, M32, M33; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(float value) { M00 = value; M01 = 0; M02 = 0; M03 = 0; M10 = 0; M11 = value; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = value; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f( float m00, float m01, float m02, float m03, float m10, float m11, float m12, float m13, float m20, float m21, float m22, float m23, float m30, float m31, float m32, float m33) { M00 = m00; M01 = m01; M02 = m02; M03 = m03; M10 = m10; M11 = m11; M12 = m12; M13 = m13; M20 = m20; M21 = m21; M22 = m22; M23 = m23; M30 = m30; M31 = m31; M32 = m32; M33 = m33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(float[] a) { M00 = a[0]; M01 = a[1]; M02 = a[2]; M03 = a[3]; M10 = a[4]; M11 = a[5]; M12 = a[6]; M13 = a[7]; M20 = a[8]; M21 = a[9]; M22 = a[10]; M23 = a[11]; M30 = a[12]; M31 = a[13]; M32 = a[14]; M33 = a[15]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(float[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M02 = a[start + 2]; M03 = a[start + 3]; M10 = a[start + 4]; M11 = a[start + 5]; M12 = a[start + 6]; M13 = a[start + 7]; M20 = a[start + 8]; M21 = a[start + 9]; M22 = a[start + 10]; M23 = a[start + 11]; M30 = a[start + 12]; M31 = a[start + 13]; M32 = a[start + 14]; M33 = a[start + 15]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M22i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = 0; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M23i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M33i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = 0; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M34i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = (float)m.M03; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = (float)m.M13; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = (float)m.M23; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M44i m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = (float)m.M03; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = (float)m.M13; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = (float)m.M23; M30 = (float)m.M30; M31 = (float)m.M31; M32 = (float)m.M32; M33 = (float)m.M33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M22l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = 0; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M23l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M33l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = 0; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M34l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = (float)m.M03; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = (float)m.M13; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = (float)m.M23; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M44l m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = (float)m.M03; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = (float)m.M13; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = (float)m.M23; M30 = (float)m.M30; M31 = (float)m.M31; M32 = (float)m.M32; M33 = (float)m.M33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M22f m) { M00 = m.M00; M01 = m.M01; M02 = 0; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M23f m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M33f m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = 0; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M34f m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = m.M03; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = m.M13; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = m.M23; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M22d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = 0; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M23d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M33d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = 0; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = 0; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M34d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = (float)m.M03; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = (float)m.M13; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = (float)m.M23; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44f(M44d m) { M00 = (float)m.M00; M01 = (float)m.M01; M02 = (float)m.M02; M03 = (float)m.M03; M10 = (float)m.M10; M11 = (float)m.M11; M12 = (float)m.M12; M13 = (float)m.M13; M20 = (float)m.M20; M21 = (float)m.M21; M22 = (float)m.M22; M23 = (float)m.M23; M30 = (float)m.M30; M31 = (float)m.M31; M32 = (float)m.M32; M33 = (float)m.M33; } #endregion #region Conversions public static explicit operator M44f(M22i m) { return new M44f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = 0, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44f(M23i m) { return new M44f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44f(M33i m) { return new M44f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = 0, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44f(M34i m) { return new M44f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = (float)m.M03, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = (float)m.M13, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = (float)m.M23, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44f(M44i m) { return new M44f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = (float)m.M03, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = (float)m.M13, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = (float)m.M23, M30 = (float)m.M30, M31 = (float)m.M31, M32 = (float)m.M32, M33 = (float)m.M33, }; } public static explicit operator M44f(M22l m) { return new M44f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = 0, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44f(M23l m) { return new M44f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44f(M33l m) { return new M44f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = 0, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44f(M34l m) { return new M44f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = (float)m.M03, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = (float)m.M13, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = (float)m.M23, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44f(M44l m) { return new M44f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = (float)m.M03, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = (float)m.M13, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = (float)m.M23, M30 = (float)m.M30, M31 = (float)m.M31, M32 = (float)m.M32, M33 = (float)m.M33, }; } public static explicit operator M44f(M22f m) { return new M44f { M00 = m.M00, M01 = m.M01, M02 = 0, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44f(M23f m) { return new M44f { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44f(M33f m) { return new M44f { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = 0, M20 = m.M20, M21 = m.M21, M22 = m.M22, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44f(M34f m) { return new M44f { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = m.M03, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = m.M13, M20 = m.M20, M21 = m.M21, M22 = m.M22, M23 = m.M23, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44f(M22d m) { return new M44f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = 0, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44f(M23d m) { return new M44f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44f(M33d m) { return new M44f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = 0, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = 0, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44f(M34d m) { return new M44f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = (float)m.M03, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = (float)m.M13, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = (float)m.M23, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44f(M44d m) { return new M44f { M00 = (float)m.M00, M01 = (float)m.M01, M02 = (float)m.M02, M03 = (float)m.M03, M10 = (float)m.M10, M11 = (float)m.M11, M12 = (float)m.M12, M13 = (float)m.M13, M20 = (float)m.M20, M21 = (float)m.M21, M22 = (float)m.M22, M23 = (float)m.M23, M30 = (float)m.M30, M31 = (float)m.M31, M32 = (float)m.M32, M33 = (float)m.M33, }; } public static explicit operator M44f(int[] a) { return new M44f( (float)a[0], (float)a[1], (float)a[2], (float)a[3], (float)a[4], (float)a[5], (float)a[6], (float)a[7], (float)a[8], (float)a[9], (float)a[10], (float)a[11], (float)a[12], (float)a[13], (float)a[14], (float)a[15]); } public static explicit operator M44f(int[,] a) { return new M44f( (float)a[0, 0], (float)a[0, 1], (float)a[0, 2], (float)a[0, 3], (float)a[1, 0], (float)a[1, 1], (float)a[1, 2], (float)a[1, 3], (float)a[2, 0], (float)a[2, 1], (float)a[2, 2], (float)a[2, 3], (float)a[3, 0], (float)a[3, 1], (float)a[3, 2], (float)a[3, 3]); } public static explicit operator int[](M44f m) { return new int[] { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M03, (int)m.M10, (int)m.M11, (int)m.M12, (int)m.M13, (int)m.M20, (int)m.M21, (int)m.M22, (int)m.M23, (int)m.M30, (int)m.M31, (int)m.M32, (int)m.M33 }; } public static explicit operator int[,](M44f m) { return new int[,] { { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M03 }, { (int)m.M10, (int)m.M11, (int)m.M12, (int)m.M13 }, { (int)m.M20, (int)m.M21, (int)m.M22, (int)m.M23 }, { (int)m.M30, (int)m.M31, (int)m.M32, (int)m.M33 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = (int)M00; array[index + 1] = (int)M01; array[index + 2] = (int)M02; array[index + 3] = (int)M03; array[index + 4] = (int)M10; array[index + 5] = (int)M11; array[index + 6] = (int)M12; array[index + 7] = (int)M13; array[index + 8] = (int)M20; array[index + 9] = (int)M21; array[index + 10] = (int)M22; array[index + 11] = (int)M23; array[index + 12] = (int)M30; array[index + 13] = (int)M31; array[index + 14] = (int)M32; array[index + 15] = (int)M33; } public static explicit operator M44f(long[] a) { return new M44f( (float)a[0], (float)a[1], (float)a[2], (float)a[3], (float)a[4], (float)a[5], (float)a[6], (float)a[7], (float)a[8], (float)a[9], (float)a[10], (float)a[11], (float)a[12], (float)a[13], (float)a[14], (float)a[15]); } public static explicit operator M44f(long[,] a) { return new M44f( (float)a[0, 0], (float)a[0, 1], (float)a[0, 2], (float)a[0, 3], (float)a[1, 0], (float)a[1, 1], (float)a[1, 2], (float)a[1, 3], (float)a[2, 0], (float)a[2, 1], (float)a[2, 2], (float)a[2, 3], (float)a[3, 0], (float)a[3, 1], (float)a[3, 2], (float)a[3, 3]); } public static explicit operator long[](M44f m) { return new long[] { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M03, (long)m.M10, (long)m.M11, (long)m.M12, (long)m.M13, (long)m.M20, (long)m.M21, (long)m.M22, (long)m.M23, (long)m.M30, (long)m.M31, (long)m.M32, (long)m.M33 }; } public static explicit operator long[,](M44f m) { return new long[,] { { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M03 }, { (long)m.M10, (long)m.M11, (long)m.M12, (long)m.M13 }, { (long)m.M20, (long)m.M21, (long)m.M22, (long)m.M23 }, { (long)m.M30, (long)m.M31, (long)m.M32, (long)m.M33 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = (long)M00; array[index + 1] = (long)M01; array[index + 2] = (long)M02; array[index + 3] = (long)M03; array[index + 4] = (long)M10; array[index + 5] = (long)M11; array[index + 6] = (long)M12; array[index + 7] = (long)M13; array[index + 8] = (long)M20; array[index + 9] = (long)M21; array[index + 10] = (long)M22; array[index + 11] = (long)M23; array[index + 12] = (long)M30; array[index + 13] = (long)M31; array[index + 14] = (long)M32; array[index + 15] = (long)M33; } public static explicit operator M44f(float[] a) { return new M44f( a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); } public static explicit operator M44f(float[,] a) { return new M44f( a[0, 0], a[0, 1], a[0, 2], a[0, 3], a[1, 0], a[1, 1], a[1, 2], a[1, 3], a[2, 0], a[2, 1], a[2, 2], a[2, 3], a[3, 0], a[3, 1], a[3, 2], a[3, 3]); } public static explicit operator float[](M44f m) { return new float[] { m.M00, m.M01, m.M02, m.M03, m.M10, m.M11, m.M12, m.M13, m.M20, m.M21, m.M22, m.M23, m.M30, m.M31, m.M32, m.M33 }; } public static explicit operator float[,](M44f m) { return new float[,] { { m.M00, m.M01, m.M02, m.M03 }, { m.M10, m.M11, m.M12, m.M13 }, { m.M20, m.M21, m.M22, m.M23 }, { m.M30, m.M31, m.M32, m.M33 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M02; array[index + 3] = M03; array[index + 4] = M10; array[index + 5] = M11; array[index + 6] = M12; array[index + 7] = M13; array[index + 8] = M20; array[index + 9] = M21; array[index + 10] = M22; array[index + 11] = M23; array[index + 12] = M30; array[index + 13] = M31; array[index + 14] = M32; array[index + 15] = M33; } public static explicit operator M44f(double[] a) { return new M44f( (float)a[0], (float)a[1], (float)a[2], (float)a[3], (float)a[4], (float)a[5], (float)a[6], (float)a[7], (float)a[8], (float)a[9], (float)a[10], (float)a[11], (float)a[12], (float)a[13], (float)a[14], (float)a[15]); } public static explicit operator M44f(double[,] a) { return new M44f( (float)a[0, 0], (float)a[0, 1], (float)a[0, 2], (float)a[0, 3], (float)a[1, 0], (float)a[1, 1], (float)a[1, 2], (float)a[1, 3], (float)a[2, 0], (float)a[2, 1], (float)a[2, 2], (float)a[2, 3], (float)a[3, 0], (float)a[3, 1], (float)a[3, 2], (float)a[3, 3]); } public static explicit operator double[](M44f m) { return new double[] { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M03, (double)m.M10, (double)m.M11, (double)m.M12, (double)m.M13, (double)m.M20, (double)m.M21, (double)m.M22, (double)m.M23, (double)m.M30, (double)m.M31, (double)m.M32, (double)m.M33 }; } public static explicit operator double[,](M44f m) { return new double[,] { { (double)m.M00, (double)m.M01, (double)m.M02, (double)m.M03 }, { (double)m.M10, (double)m.M11, (double)m.M12, (double)m.M13 }, { (double)m.M20, (double)m.M21, (double)m.M22, (double)m.M23 }, { (double)m.M30, (double)m.M31, (double)m.M32, (double)m.M33 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = (double)M00; array[index + 1] = (double)M01; array[index + 2] = (double)M02; array[index + 3] = (double)M03; array[index + 4] = (double)M10; array[index + 5] = (double)M11; array[index + 6] = (double)M12; array[index + 7] = (double)M13; array[index + 8] = (double)M20; array[index + 9] = (double)M21; array[index + 10] = (double)M22; array[index + 11] = (double)M23; array[index + 12] = (double)M30; array[index + 13] = (double)M31; array[index + 14] = (double)M32; array[index + 15] = (double)M33; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44i Copy(Func element_fun) { return new M44i( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23), element_fun(M30), element_fun(M31), element_fun(M32), element_fun(M33)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44i Copy(Func element_index0_index1_fun) { return new M44i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3), element_index0_index1_fun(M30, 3, 0), element_index0_index1_fun(M31, 3, 1), element_index0_index1_fun(M32, 3, 2), element_index0_index1_fun(M33, 3, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44l Copy(Func element_fun) { return new M44l( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23), element_fun(M30), element_fun(M31), element_fun(M32), element_fun(M33)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44l Copy(Func element_index0_index1_fun) { return new M44l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3), element_index0_index1_fun(M30, 3, 0), element_index0_index1_fun(M31, 3, 1), element_index0_index1_fun(M32, 3, 2), element_index0_index1_fun(M33, 3, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44f Copy(Func element_fun) { return new M44f( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23), element_fun(M30), element_fun(M31), element_fun(M32), element_fun(M33)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44f Copy(Func element_index0_index1_fun) { return new M44f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3), element_index0_index1_fun(M30, 3, 0), element_index0_index1_fun(M31, 3, 1), element_index0_index1_fun(M32, 3, 2), element_index0_index1_fun(M33, 3, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44d Copy(Func element_fun) { return new M44d( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23), element_fun(M30), element_fun(M31), element_fun(M32), element_fun(M33)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44d Copy(Func element_index0_index1_fun) { return new M44d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3), element_index0_index1_fun(M30, 3, 0), element_index0_index1_fun(M31, 3, 1), element_index0_index1_fun(M32, 3, 2), element_index0_index1_fun(M33, 3, 3)); } /// /// Returns a copy of the upper left sub matrix. /// public readonly M33f UpperLeftM33() { return (M33f)this; } public readonly float[] ToArray() { var array = new float[16]; array[0] = M00; array[1] = M01; array[2] = M02; array[3] = M03; array[4] = M10; array[5] = M11; array[6] = M12; array[7] = M13; array[8] = M20; array[9] = M21; array[10] = M22; array[11] = M23; array[12] = M30; array[13] = M31; array[14] = M32; array[15] = M33; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f FromCols(V4f col0, V4f col1, V4f col2, V4f col3) { return new M44f( col0.X, col1.X, col2.X, col3.X, col0.Y, col1.Y, col2.Y, col3.Y, col0.Z, col1.Z, col2.Z, col3.Z, col0.W, col1.W, col2.W, col3.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f FromRows(V4f row0, V4f row1, V4f row2, V4f row3) { return new M44f( row0.X, row0.Y, row0.Z, row0.W, row1.X, row1.Y, row1.Z, row1.W, row2.X, row2.Y, row2.Z, row2.W, row3.X, row3.Y, row3.Z, row3.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f FromDiagonal(float value) { return new M44f( value, 0, 0, 0, 0, value, 0, 0, 0, 0, value, 0, 0, 0, 0, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f FromDiagonal(float m00, float m11, float m22, float m33) { return new M44f( m00, 0, 0, 0, 0, m11, 0, 0, 0, 0, m22, 0, 0, 0, 0, m33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f FromDiagonal(V4f s) { return new M44f( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0, 0, 0, 0, s.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f FromAntiDiagonal(float value) { return new M44f( 0, 0, 0, value, 0, 0, value, 0, 0, value, 0, 0, value, 0, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f FromAntiDiagonal(float m03, float m12, float m21, float m30) { return new M44f( 0, 0, 0, m03, 0, 0, m12, 0, 0, m21, 0, 0, m30, 0, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f FromAntiDiagonal(V4f s) { return new M44f( 0, 0, 0, s.X, 0, 0, s.Y, 0, 0, s.Z, 0, 0, s.W, 0, 0, 0); } #region Scale /// /// Creates a transformation using 4 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Scale(float sX, float sY, float sZ, float sW) => FromDiagonal(sX, sY, sZ, sW); /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Scale(V4f s) => FromDiagonal(s); /// /// Creates a homogenous transformation using a uniform scale. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Scale(float s) { return new M44f( s, 0, 0, 0, 0, s, 0, 0, 0, 0, s, 0, 0, 0, 0, 1); } /// /// Creates a transformation using 3 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Scale(float sX, float sY, float sZ) { return new M44f( sX, 0, 0, 0, 0, sY, 0, 0, 0, 0, sZ, 0, 0, 0, 0, 1); } /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Scale(V3f s) { return new M44f( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0, 0, 0, 0, 1); } /// /// Creates a scaling transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Scale(Scale3f s) { return new M44f( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0, 0, 0, 0, 1); } #endregion #region Translation /// /// Creates a transformation with the translational component given by 3 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Translation(float tX, float tY, float tZ) { return new M44f( 1, 0, 0, tX, 0, 1, 0, tY, 0, 0, 1, tZ, 0, 0, 0, 1); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Translation(V3f t) { return new M44f( 1, 0, 0, t.X, 0, 1, 0, t.Y, 0, 0, 1, t.Z, 0, 0, 0, 1); } /// /// Creates a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Translation(Shift3f s) { return new M44f( 1, 0, 0, s.X, 0, 1, 0, s.Y, 0, 0, 1, s.Z, 0, 0, 0, 1); } #endregion #region Rotation /// /// Creates a 3D rotation matrix from a /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Rotation(Rot3f r) => (M44f)r; /// /// Creates a 3D rotation matrix from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Rotation(V3f normalizedAxis, float angleInRadians) { Debug.Assert(normalizedAxis.LengthSquared.ApproximateEquals(1, 1e-5f)); return (M44f)(Rot3f.Rotation(normalizedAxis, angleInRadians)); } /// /// Creates a 3D rotation matrix from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f RotationInDegrees(V3f normalizedAxis, float angleInDegrees) => Rotation(normalizedAxis, angleInDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f RotationEuler(float rollInRadians, float pitchInRadians, float yawInRadians) { return (M44f)(Rot3f.RotationEuler(rollInRadians, pitchInRadians, yawInRadians)); } /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f RotationEulerInDegrees(float rollInDegrees, float pitchInDegrees, float yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f RotationEuler(V3f rollPitchYawInRadians) => RotationEuler( rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f RotationEulerInDegrees(V3f rollPitchYawInDegrees) => RotationEulerInDegrees( rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a 3D rotation matrix which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f RotateInto(V3f from, V3f into) { Debug.Assert(from.LengthSquared.ApproximateEquals(1, 1e-5f)); Debug.Assert(into.LengthSquared.ApproximateEquals(1, 1e-5f)); return (M44f)(Rot3f.RotateInto(from, into)); } /// /// Creates a 3D rotation matrix for radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f RotationX(float angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M44f( 1, 0, 0, 0, 0, a, -b, 0, 0, b, a, 0, 0, 0, 0, 1); } /// /// Creates a 3D rotation matrix for degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f RotationXInDegrees(float angleDegrees) => RotationX(angleDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix for radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f RotationY(float angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M44f( a, 0, b, 0, 0, 1, 0, 0, -b, 0, a, 0, 0, 0, 0, 1); } /// /// Creates a 3D rotation matrix for degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f RotationYInDegrees(float angleDegrees) => RotationY(angleDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix for radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f RotationZ(float angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M44f( a, -b, 0, 0, b, a, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } /// /// Creates a 3D rotation matrix for degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f RotationZInDegrees(float angleDegrees) => RotationZ(angleDegrees.RadiansFromDegrees()); #endregion #region Shearing /// /// Creates a shear transformation matrix along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f ShearXY(float factorX, float factorY) { return new M44f( 1, 0, factorX, 0, 0, 1, factorY, 0, 0, 0, 1, 0, 0, 0, 0, 1); } /// /// Creates a shear transformation matrix along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f ShearXZ(float factorX, float factorZ) { return new M44f( 1, factorX, 0, 0, 0, 1, 0, 0, 0, factorZ, 1, 0, 0, 0, 0, 1); } /// /// Creates a shear transformation matrix along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f ShearYZ(float factorY, float factorZ) { return new M44f( 1, 0, 0, 0, factorY, 1, 0, 0, factorZ, 0, 1, 0, 0, 0, 0, 1); } #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f DivideByInt(M44f m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M02; yield return M03; yield return M10; yield return M11; yield return M12; yield return M13; yield return M20; yield return M21; yield return M22; yield return M23; yield return M30; yield return M31; yield return M32; yield return M33; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; yield return R2; yield return R3; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; yield return C2; yield return C3; } } [XmlIgnore] public V4f R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4f( M00, M01, M02, M03); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; M02 = value.Z; M03 = value.W; } } [XmlIgnore] public V4f R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4f( M10, M11, M12, M13); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; M12 = value.Z; M13 = value.W; } } [XmlIgnore] public V4f R2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4f( M20, M21, M22, M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M20 = value.X; M21 = value.Y; M22 = value.Z; M23 = value.W; } } [XmlIgnore] public V4f R3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4f( M30, M31, M32, M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M30 = value.X; M31 = value.Y; M32 = value.Z; M33 = value.W; } } [XmlIgnore] public V4f C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4f( M00, M10, M20, M30); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; M20 = value.Z; M30 = value.W; } } [XmlIgnore] public V4f C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4f( M01, M11, M21, M31); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; M21 = value.Z; M31 = value.W; } } [XmlIgnore] public V4f C2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4f( M02, M12, M22, M32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M02 = value.X; M12 = value.Y; M22 = value.Z; M32 = value.W; } } [XmlIgnore] public V4f C3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4f( M03, M13, M23, M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M03 = value.X; M13 = value.Y; M23 = value.Z; M33 = value.W; } } public readonly V4f Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V4f(M00, M11, M22, M33); } public readonly V4f AntiDiagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V4f(M03, M12, M21, M30); } /// /// Returns the minimum element of the matrix. /// public readonly float MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23, M30, M31, M32, M33); } /// /// Returns the maximum element of the matrix. /// public readonly float MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23, M30, M31, M32, M33); } public unsafe float this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &M00) { ptr[index] = value; } } } public unsafe float this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &M00) { return ptr[row * 4 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &M00) { ptr[row * 4 + column] = value; } } } public readonly bool AnyFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) || Fun.IsFinite(M01) || Fun.IsFinite(M02) || Fun.IsFinite(M03) || Fun.IsFinite(M10) || Fun.IsFinite(M11) || Fun.IsFinite(M12) || Fun.IsFinite(M13) || Fun.IsFinite(M20) || Fun.IsFinite(M21) || Fun.IsFinite(M22) || Fun.IsFinite(M23) || Fun.IsFinite(M30) || Fun.IsFinite(M31) || Fun.IsFinite(M32) || Fun.IsFinite(M33); } } public readonly bool AllFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) && Fun.IsFinite(M01) && Fun.IsFinite(M02) && Fun.IsFinite(M03) && Fun.IsFinite(M10) && Fun.IsFinite(M11) && Fun.IsFinite(M12) && Fun.IsFinite(M13) && Fun.IsFinite(M20) && Fun.IsFinite(M21) && Fun.IsFinite(M22) && Fun.IsFinite(M23) && Fun.IsFinite(M30) && Fun.IsFinite(M31) && Fun.IsFinite(M32) && Fun.IsFinite(M33); } } public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNaN(M00) || float.IsNaN(M01) || float.IsNaN(M02) || float.IsNaN(M03) || float.IsNaN(M10) || float.IsNaN(M11) || float.IsNaN(M12) || float.IsNaN(M13) || float.IsNaN(M20) || float.IsNaN(M21) || float.IsNaN(M22) || float.IsNaN(M23) || float.IsNaN(M30) || float.IsNaN(M31) || float.IsNaN(M32) || float.IsNaN(M33); } } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNaN(M00) && float.IsNaN(M01) && float.IsNaN(M02) && float.IsNaN(M03) && float.IsNaN(M10) && float.IsNaN(M11) && float.IsNaN(M12) && float.IsNaN(M13) && float.IsNaN(M20) && float.IsNaN(M21) && float.IsNaN(M22) && float.IsNaN(M23) && float.IsNaN(M30) && float.IsNaN(M31) && float.IsNaN(M32) && float.IsNaN(M33); } } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsInfinity(M00) || float.IsInfinity(M01) || float.IsInfinity(M02) || float.IsInfinity(M03) || float.IsInfinity(M10) || float.IsInfinity(M11) || float.IsInfinity(M12) || float.IsInfinity(M13) || float.IsInfinity(M20) || float.IsInfinity(M21) || float.IsInfinity(M22) || float.IsInfinity(M23) || float.IsInfinity(M30) || float.IsInfinity(M31) || float.IsInfinity(M32) || float.IsInfinity(M33); } } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsInfinity(M00) && float.IsInfinity(M01) && float.IsInfinity(M02) && float.IsInfinity(M03) && float.IsInfinity(M10) && float.IsInfinity(M11) && float.IsInfinity(M12) && float.IsInfinity(M13) && float.IsInfinity(M20) && float.IsInfinity(M21) && float.IsInfinity(M22) && float.IsInfinity(M23) && float.IsInfinity(M30) && float.IsInfinity(M31) && float.IsInfinity(M32) && float.IsInfinity(M33); } } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsPositiveInfinity(M00) || float.IsPositiveInfinity(M01) || float.IsPositiveInfinity(M02) || float.IsPositiveInfinity(M03) || float.IsPositiveInfinity(M10) || float.IsPositiveInfinity(M11) || float.IsPositiveInfinity(M12) || float.IsPositiveInfinity(M13) || float.IsPositiveInfinity(M20) || float.IsPositiveInfinity(M21) || float.IsPositiveInfinity(M22) || float.IsPositiveInfinity(M23) || float.IsPositiveInfinity(M30) || float.IsPositiveInfinity(M31) || float.IsPositiveInfinity(M32) || float.IsPositiveInfinity(M33); } } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsPositiveInfinity(M00) && float.IsPositiveInfinity(M01) && float.IsPositiveInfinity(M02) && float.IsPositiveInfinity(M03) && float.IsPositiveInfinity(M10) && float.IsPositiveInfinity(M11) && float.IsPositiveInfinity(M12) && float.IsPositiveInfinity(M13) && float.IsPositiveInfinity(M20) && float.IsPositiveInfinity(M21) && float.IsPositiveInfinity(M22) && float.IsPositiveInfinity(M23) && float.IsPositiveInfinity(M30) && float.IsPositiveInfinity(M31) && float.IsPositiveInfinity(M32) && float.IsPositiveInfinity(M33); } } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNegativeInfinity(M00) || float.IsNegativeInfinity(M01) || float.IsNegativeInfinity(M02) || float.IsNegativeInfinity(M03) || float.IsNegativeInfinity(M10) || float.IsNegativeInfinity(M11) || float.IsNegativeInfinity(M12) || float.IsNegativeInfinity(M13) || float.IsNegativeInfinity(M20) || float.IsNegativeInfinity(M21) || float.IsNegativeInfinity(M22) || float.IsNegativeInfinity(M23) || float.IsNegativeInfinity(M30) || float.IsNegativeInfinity(M31) || float.IsNegativeInfinity(M32) || float.IsNegativeInfinity(M33); } } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return float.IsNegativeInfinity(M00) && float.IsNegativeInfinity(M01) && float.IsNegativeInfinity(M02) && float.IsNegativeInfinity(M03) && float.IsNegativeInfinity(M10) && float.IsNegativeInfinity(M11) && float.IsNegativeInfinity(M12) && float.IsNegativeInfinity(M13) && float.IsNegativeInfinity(M20) && float.IsNegativeInfinity(M21) && float.IsNegativeInfinity(M22) && float.IsNegativeInfinity(M23) && float.IsNegativeInfinity(M30) && float.IsNegativeInfinity(M31) && float.IsNegativeInfinity(M32) && float.IsNegativeInfinity(M33); } } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) || Fun.IsTiny(M01) || Fun.IsTiny(M02) || Fun.IsTiny(M03) || Fun.IsTiny(M10) || Fun.IsTiny(M11) || Fun.IsTiny(M12) || Fun.IsTiny(M13) || Fun.IsTiny(M20) || Fun.IsTiny(M21) || Fun.IsTiny(M22) || Fun.IsTiny(M23) || Fun.IsTiny(M30) || Fun.IsTiny(M31) || Fun.IsTiny(M32) || Fun.IsTiny(M33); } } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) && Fun.IsTiny(M01) && Fun.IsTiny(M02) && Fun.IsTiny(M03) && Fun.IsTiny(M10) && Fun.IsTiny(M11) && Fun.IsTiny(M12) && Fun.IsTiny(M13) && Fun.IsTiny(M20) && Fun.IsTiny(M21) && Fun.IsTiny(M22) && Fun.IsTiny(M23) && Fun.IsTiny(M30) && Fun.IsTiny(M31) && Fun.IsTiny(M32) && Fun.IsTiny(M33); } } /// /// Returns true if the absolute value of each element of the matrix is smaller than Constant<float>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any element of the matrix is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any element of the matrix is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any element of the matrix is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any element of the matrix is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all elements of the matrix are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Constants public const int RowCount = 4; public const int ColumnCount = 4; public const int ElementCount = 4 * 4; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(4, 4); } public static M44f Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M44f(0); } public static M44f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M44f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly float Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M02) + Fun.Abs(M03) + Fun.Abs(M10) + Fun.Abs(M11) + Fun.Abs(M12) + Fun.Abs(M13) + Fun.Abs(M20) + Fun.Abs(M21) + Fun.Abs(M22) + Fun.Abs(M23) + Fun.Abs(M30) + Fun.Abs(M31) + Fun.Abs(M32) + Fun.Abs(M33); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly float Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M02 * M02 + M03 * M03 + M10 * M10 + M11 * M11 + M12 * M12 + M13 * M13 + M20 * M20 + M21 * M21 + M22 * M22 + M23 * M23 + M30 * M30 + M31 * M31 + M32 * M32 + M33 * M33); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly float NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02), Fun.Abs(M03)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12), Fun.Abs(M13)), Fun.Max( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22), Fun.Abs(M23)), Fun.Max( Fun.Abs(M30), Fun.Abs(M31), Fun.Abs(M32), Fun.Abs(M33))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly float NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02), Fun.Abs(M03)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12), Fun.Abs(M13)), Fun.Min( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22), Fun.Abs(M23)), Fun.Min( Fun.Abs(M30), Fun.Abs(M31), Fun.Abs(M32), Fun.Abs(M33))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator -(M44f m) { return new M44f( -m.M00, -m.M01, -m.M02, -m.M03, -m.M10, -m.M11, -m.M12, -m.M13, -m.M20, -m.M21, -m.M22, -m.M23, -m.M30, -m.M31, -m.M32, -m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator + (M44f a, M44f b) { return new M44f( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23, a.M30 + b.M30, a.M31 + b.M31, a.M32 + b.M32, a.M33 + b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator + (M44f m, float s) { return new M44f( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s, m.M30 + s, m.M31 + s, m.M32 + s, m.M33 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator + (float s, M44f m) { return new M44f( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23, s + m.M30, s + m.M31, s + m.M32, s + m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator + (M44f a, M44d b) { return new M44d( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23, a.M30 + b.M30, a.M31 + b.M31, a.M32 + b.M32, a.M33 + b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator + (M44f m, double s) { return new M44d( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s, m.M30 + s, m.M31 + s, m.M32 + s, m.M33 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator + (double s, M44f m) { return new M44d( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23, s + m.M30, s + m.M31, s + m.M32, s + m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator - (M44f a, M44f b) { return new M44f( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23, a.M30 - b.M30, a.M31 - b.M31, a.M32 - b.M32, a.M33 - b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator - (M44f m, float s) { return new M44f( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s, m.M30 - s, m.M31 - s, m.M32 - s, m.M33 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator - (float s, M44f m) { return new M44f( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23, s - m.M30, s - m.M31, s - m.M32, s - m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator - (M44f a, M44d b) { return new M44d( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23, a.M30 - b.M30, a.M31 - b.M31, a.M32 - b.M32, a.M33 - b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator - (M44f m, double s) { return new M44d( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s, m.M30 - s, m.M31 - s, m.M32 - s, m.M33 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator - (double s, M44f m) { return new M44d( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23, s - m.M30, s - m.M31, s - m.M32, s - m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator % (M44f a, M44f b) { return new M44f( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23, a.M30 % b.M30, a.M31 % b.M31, a.M32 % b.M32, a.M33 % b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator % (M44f m, float s) { return new M44f( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s, m.M30 % s, m.M31 % s, m.M32 % s, m.M33 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator % (float s, M44f m) { return new M44f( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23, s % m.M30, s % m.M31, s % m.M32, s % m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator % (M44f a, M44d b) { return new M44d( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23, a.M30 % b.M30, a.M31 % b.M31, a.M32 % b.M32, a.M33 % b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator % (M44f m, double s) { return new M44d( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s, m.M30 % s, m.M31 % s, m.M32 % s, m.M33 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator % (double s, M44f m) { return new M44d( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23, s % m.M30, s % m.M31, s % m.M32, s % m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator / (M44f a, M44f b) { return new M44f( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23, a.M30 / b.M30, a.M31 / b.M31, a.M32 / b.M32, a.M33 / b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator / (M44f m, float s) { return new M44f( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s, m.M30 / s, m.M31 / s, m.M32 / s, m.M33 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator / (float s, M44f m) { return new M44f( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23, s / m.M30, s / m.M31, s / m.M32, s / m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator / (M44f a, M44d b) { return new M44d( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23, a.M30 / b.M30, a.M31 / b.M31, a.M32 / b.M32, a.M33 / b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator / (M44f m, double s) { return new M44d( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s, m.M30 / s, m.M31 / s, m.M32 / s, m.M33 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator / (double s, M44f m) { return new M44d( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23, s / m.M30, s / m.M31, s / m.M32, s / m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator * (M44f m, float s) { return new M44f( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s, m.M30 * s, m.M31 * s, m.M32 * s, m.M33 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator * (float s, M44f m) { return new M44f( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23, s * m.M30, s * m.M31, s * m.M32, s * m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator * (M44f m, double s) { return new M44d( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s, m.M30 * s, m.M31 * s, m.M32 * s, m.M33 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator * (double s, M44f m) { return new M44d( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23, s * m.M30, s * m.M31, s * m.M32, s * m.M33); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M44f matrix with a V4f column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator *(M44f m, V4f v) { return new V4f( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z + m.M03 * v.W, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z + m.M13 * v.W, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z + m.M23 * v.W, m.M30 * v.X + m.M31 * v.Y + m.M32 * v.Z + m.M33 * v.W); } /// /// Multiplies a V4f row vector with a M44f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator *(V4f v, M44f m) { return new V4f( v.X * m.M00 + v.Y * m.M10 + v.Z * m.M20 + v.W * m.M30, v.X * m.M01 + v.Y * m.M11 + v.Z * m.M21 + v.W * m.M31, v.X * m.M02 + v.Y * m.M12 + v.Z * m.M22 + v.W * m.M32, v.X * m.M03 + v.Y * m.M13 + v.Z * m.M23 + v.W * m.M33); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M44f a, M44f b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M03 == b.M03 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M13 == b.M13 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22 && a.M23 == b.M23 && a.M30 == b.M30 && a.M31 == b.M31 && a.M32 == b.M32 && a.M33 == b.M33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M44f a, float s) { return a.M00 == s && a.M01 == s && a.M02 == s && a.M03 == s && a.M10 == s && a.M11 == s && a.M12 == s && a.M13 == s && a.M20 == s && a.M21 == s && a.M22 == s && a.M23 == s && a.M30 == s && a.M31 == s && a.M32 == s && a.M33 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(float s, M44f a) { return s == a.M00 && s == a.M01 && s == a.M02 && s == a.M03 && s == a.M10 && s == a.M11 && s == a.M12 && s == a.M13 && s == a.M20 && s == a.M21 && s == a.M22 && s == a.M23 && s == a.M30 && s == a.M31 && s == a.M32 && s == a.M33 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M44f a, M44f b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M44f m, float s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(float s, M44f m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01, M02, M03), HashCode.GetCombined(M10, M11, M12, M13), HashCode.GetCombined(M20, M21, M22, M23), HashCode.GetCombined(M30, M31, M32, M33)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M44f other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M02.Equals(other.M02) && M03.Equals(other.M03) && M10.Equals(other.M10) && M11.Equals(other.M11) && M12.Equals(other.M12) && M13.Equals(other.M13) && M20.Equals(other.M20) && M21.Equals(other.M21) && M22.Equals(other.M22) && M23.Equals(other.M23) && M30.Equals(other.M30) && M31.Equals(other.M31) && M32.Equals(other.M32) && M33.Equals(other.M33); } public override readonly bool Equals(object other) => (other is M44f o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + betweenM + R2.ToString(format, fp, beginR, betweenR, endR) + betweenM + R3.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M44f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M44f.FromRows( V4f.Parse(x[0]), V4f.Parse(x[1]), V4f.Parse(x[2]), V4f.Parse(x[3]) ); } #endregion #region Matrix Operations /// /// Returns adjoint of this matrix. /// public readonly M44f Adjoint { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { M44f result = new M44f(); for (int row = 0; row < 4; row++) { for (int col = 0; col < 4; col++) { if (((col + row) % 2) == 0) result[col, row] = this.Minor(row, col).Determinant; else result[col, row] = -this.Minor(row, col).Determinant; } } return result; } } /// /// Returns the trace of this matrix. /// The trace is defined as the sum of the diagonal elements, /// and is only defined for square matrices. /// public readonly float Trace { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return M00 + M11 + M22 + M33 ; } } /// /// Gets the determinant of this matrix. /// The determinant is only defined for square matrices. /// public readonly float Determinant { get { // using bottom row because elements M30, M31, and M32 // are zero most of the time. float d = 0; if (M30 != 0.0f) d -= M30 * ( M01 * M12 * M23 + M02 * M13 * M21 + M03 * M11 * M22 - M21 * M12 * M03 - M22 * M13 * M01 - M23 * M11 * M02 ); if (M31 != 0.0f) d += M31 * ( M00 * M12 * M23 + M02 * M13 * M20 + M03 * M10 * M22 - M20 * M12 * M03 - M22 * M13 * M00 - M23 * M10 * M02 ); if (M32 != 0.0f) d -= M32 * ( M00 * M11 * M23 + M01 * M13 * M20 + M03 * M10 * M21 - M20 * M11 * M03 - M21 * M13 * M00 - M23 * M10 * M01 ); if (M33 != 0.0f) d += M33 * ( M00 * M11 * M22 + M01 * M12 * M20 + M02 * M10 * M21 - M20 * M11 * M02 - M21 * M12 * M00 - M22 * M10 * M01 ); return d; } } /// /// Returns whether this matrix is invertible. /// A matrix is invertible if its determinant is not zero. /// public readonly bool Invertible { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant != 0; } } /// /// Returns whether this matrix is singular. /// A matrix is singular if its determinant is zero. /// public readonly bool Singular { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant == 0; } } /// /// Gets transpose of this matrix. /// public readonly M44f Transposed { get { return new M44f { M00 = M00, M01 = M10, M02 = M20, M03 = M30, M10 = M01, M11 = M11, M12 = M21, M13 = M31, M20 = M02, M21 = M12, M22 = M22, M23 = M32, M30 = M03, M31 = M13, M32 = M23, M33 = M33 }; } } private static V2l s_luSize = new V2l(4, 4); private static V2l s_luDelta = new V2l(1, 4); /// /// Inverts the given matrix using lu factorization in place. Returns true /// if the matrix was invertible, otherwise the matrix remains unchanged. /// public bool LuInvert() { M44d dbl = (M44d)this; if(dbl.LuInvert()) { this = (M44f)dbl; return true; } return false; } /// /// Returns the inverse of the matrix using lu factorization. /// If the matrix is not invertible, M44f.Zero is returned. /// public readonly M44f LuInverse() { return (M44f)((M44d)this).LuInverse(); } /// /// Returns the inverse of this matrix. If the matrix is not invertible /// M44f.Zero is returned. /// public readonly M44f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => LuInverse(); } #endregion #region Matrix Multiplication public static M44f operator *(M44f a, M44f b) { return new M44f( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20 + a.M03 * b.M30, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21 + a.M03 * b.M31, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22 + a.M03 * b.M32, a.M00 * b.M03 + a.M01 * b.M13 + a.M02 * b.M23 + a.M03 * b.M33, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20 + a.M13 * b.M30, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21 + a.M13 * b.M31, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22 + a.M13 * b.M32, a.M10 * b.M03 + a.M11 * b.M13 + a.M12 * b.M23 + a.M13 * b.M33, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20 + a.M23 * b.M30, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21 + a.M23 * b.M31, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22 + a.M23 * b.M32, a.M20 * b.M03 + a.M21 * b.M13 + a.M22 * b.M23 + a.M23 * b.M33, a.M30 * b.M00 + a.M31 * b.M10 + a.M32 * b.M20 + a.M33 * b.M30, a.M30 * b.M01 + a.M31 * b.M11 + a.M32 * b.M21 + a.M33 * b.M31, a.M30 * b.M02 + a.M31 * b.M12 + a.M32 * b.M22 + a.M33 * b.M32, a.M30 * b.M03 + a.M31 * b.M13 + a.M32 * b.M23 + a.M33 * b.M33 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return (double)this[(int)y, (int)x]; } set { this[(int)y, (int)x] = (float)value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return (double)this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = (float)value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (float)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (float)value; } #endregion } public class M44fEqualityComparer : IEqualityComparer { public static readonly M44fEqualityComparer Default = new M44fEqualityComparer(); #region IEqualityComparer Members public bool Equals(M44f v0, M44f v1) { return v0 == v1; } public int GetHashCode(M44f v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetScale(this M44f m) => (m.C0.Length + m.C1.Length + m.C2.Length + m.C3.Length) / 4; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f GetScaleVector(this M44f m) => new V4f(m.C0.Length, m.C1.Length, m.C2.Length, m.C3.Length); /// /// Approximates the uniform scale value of the given transformation matrix (average length of 3D basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetScale3(this M44f m) => (m.C0.XYZ.Length + m.C1.XYZ.Length + m.C2.XYZ.Length) / 3; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the 3D basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetScaleVector3(this M44f m) => new V3f(m.C0.XYZ.Length, m.C1.XYZ.Length, m.C2.XYZ.Length); /// /// Extracts the forward vector from the given view transformation matrix. /// NOTE: A left-handed coordinates system transformation is expected, /// where the view-space z-axis points in forward direction. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetViewDirectionLH(this M44f m) => m.R2.XYZ.Normalized; /// /// Extracts the forward vector from the given view transformation matrix. /// NOTE: A right-handed coordinates system transformation is expected, where /// the view-space z-axis points opposit the forward vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetViewDirectionRH(this M44f m) => -m.R2.XYZ.Normalized; /// /// Extracts the translation component of the given transformation matrix, which when given /// a model transformation represents the model origin in world position. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetModelOrigin(this M44f m) => m.C3.XYZ; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm1(M44f m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm2(M44f m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormMax(M44f m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormMin(M44f m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm(this M44f m, float p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M02).Pow(p) + Fun.Abs(m.M03).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) + Fun.Abs(m.M12).Pow(p) + Fun.Abs(m.M13).Pow(p) + Fun.Abs(m.M20).Pow(p) + Fun.Abs(m.M21).Pow(p) + Fun.Abs(m.M22).Pow(p) + Fun.Abs(m.M23).Pow(p) + Fun.Abs(m.M30).Pow(p) + Fun.Abs(m.M31).Pow(p) + Fun.Abs(m.M32).Pow(p) + Fun.Abs(m.M33).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static float Distance1(this M44f a, M44f b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M02 - a.M02) + Fun.Abs(b.M03 - a.M03) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11) + Fun.Abs(b.M12 - a.M12) + Fun.Abs(b.M13 - a.M13) + Fun.Abs(b.M20 - a.M20) + Fun.Abs(b.M21 - a.M21) + Fun.Abs(b.M22 - a.M22) + Fun.Abs(b.M23 - a.M23) + Fun.Abs(b.M30 - a.M30) + Fun.Abs(b.M31 - a.M31) + Fun.Abs(b.M32 - a.M32) + Fun.Abs(b.M33 - a.M33); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static float Distance2(this M44f a, M44f b) { return (float)Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M02 - a.M02) + Fun.Square(b.M03 - a.M03) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11) + Fun.Square(b.M12 - a.M12) + Fun.Square(b.M13 - a.M13) + Fun.Square(b.M20 - a.M20) + Fun.Square(b.M21 - a.M21) + Fun.Square(b.M22 - a.M22) + Fun.Square(b.M23 - a.M23) + Fun.Square(b.M30 - a.M30) + Fun.Square(b.M31 - a.M31) + Fun.Square(b.M32 - a.M32) + Fun.Square(b.M33 - a.M33)); } /// /// Returns the p-distance between two matrices. /// public static float Distance(this M44f a, M44f b, float p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M02 - a.M02).Pow(p) + Fun.Abs(b.M03 - a.M03).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) + Fun.Abs(b.M12 - a.M12).Pow(p) + Fun.Abs(b.M13 - a.M13).Pow(p) + Fun.Abs(b.M20 - a.M20).Pow(p) + Fun.Abs(b.M21 - a.M21).Pow(p) + Fun.Abs(b.M22 - a.M22).Pow(p) + Fun.Abs(b.M23 - a.M23).Pow(p) + Fun.Abs(b.M30 - a.M30).Pow(p) + Fun.Abs(b.M31 - a.M31).Pow(p) + Fun.Abs(b.M32 - a.M32).Pow(p) + Fun.Abs(b.M33 - a.M33).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static float DistanceMax(this M44f a, M44f b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02), Fun.Abs(b.M03 - a.M03)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12), Fun.Abs(b.M13 - a.M13)), Fun.Max( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22), Fun.Abs(b.M23 - a.M23)), Fun.Max( Fun.Abs(b.M30 - a.M30), Fun.Abs(b.M31 - a.M31), Fun.Abs(b.M32 - a.M32), Fun.Abs(b.M33 - a.M33))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static float DistanceMin(this M44f a, M44f b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02), Fun.Abs(b.M03 - a.M03)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12), Fun.Abs(b.M13 - a.M13)), Fun.Min( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22), Fun.Abs(b.M23 - a.M23)), Fun.Min( Fun.Abs(b.M30 - a.M30), Fun.Abs(b.M31 - a.M31), Fun.Abs(b.M32 - a.M32), Fun.Abs(b.M33 - a.M33))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Transform(this M44f m, V4f v) => m * v; /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f TransposedTransform(this M44f m, V4f v) => v * m; /// /// Transforms direction vector v (v.W is presumed 0.0) by matrix m. /// public static V3f TransformDir(this M44f m, V3f v) { return new V3f( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z ); } /// /// Transforms point p (v.W is presumed 1.0) by matrix m. /// No projective transform is performed. /// public static V3f TransformPos(this M44f m, V3f p) { return new V3f( m.M00 * p.X + m.M01 * p.Y + m.M02 * p.Z + m.M03, m.M10 * p.X + m.M11 * p.Y + m.M12 * p.Z + m.M13, m.M20 * p.X + m.M21 * p.Y + m.M22 * p.Z + m.M23 ); } /// /// Transforms point p (p.W is presumed 1.0) by matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static V3f TransformPosProj(this M44f m, V3f p) { float s = m.M30 * p.X + m.M31 * p.Y + m.M32 * p.Z + m.M33; return TransformPos(m, p) * (1 / s); } /// /// Transforms point p (p.W is presumed 1.0) by matrix m. /// Projective transform is performed. /// public static V4f TransformPosProjFull(this M44f m, V3f p) { return new V4f( m.M00 * p.X + m.M01 * p.Y + m.M02 * p.Z + m.M03, m.M10 * p.X + m.M11 * p.Y + m.M12 * p.Z + m.M13, m.M20 * p.X + m.M21 * p.Y + m.M22 * p.Z + m.M23, m.M30 * p.X + m.M31 * p.Y + m.M32 * p.Z + m.M33 ); } /// /// Transforms direction vector v (v.W is presumed 0.0) by transposed version of matrix m. /// public static V3f TransposedTransformDir(this M44f m, V3f v) { return new V3f( m.M00 * v.X + m.M10 * v.Y + m.M20 * v.Z, m.M01 * v.X + m.M11 * v.Y + m.M21 * v.Z, m.M02 * v.X + m.M12 * v.Y + m.M22 * v.Z ); } /// /// Transforms point p (v.W is presumed 1.0) by transposed version of matrix m. /// No projective transform is performed. /// public static V3f TransposedTransformPos(this M44f m, V3f p) { return new V3f( m.M00 * p.X + m.M10 * p.Y + m.M20 * p.Z + m.M30, m.M01 * p.X + m.M11 * p.Y + m.M21 * p.Z + m.M31, m.M02 * p.X + m.M12 * p.Y + m.M22 * p.Z + m.M32 ); } /// /// Transforms point p (v.W is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static V3f TransposedTransformPosProj(this M44f m, V3f p) { var s = m.M03 * p.X + m.M13 * p.Y + m.M23 * p.Z + m.M33; return TransposedTransformPos(m, p) * (1 / s); } [Obsolete("Use TransposedTransformPosProj instead.")] public static V3f TransposedTransformProj(this M44f m, V3f p) => m.TransposedTransformPosProj(p); /// /// Transforms point p (v.W is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. /// public static V4f TransposedTransformPosProjFull(this M44f m, V3f p) { return new V4f( m.M00 * p.X + m.M10 * p.Y + m.M20 * p.Z + m.M30, m.M01 * p.X + m.M11 * p.Y + m.M21 * p.Z + m.M31, m.M02 * p.X + m.M12 * p.Y + m.M22 * p.Z + m.M32, m.M03 * p.X + m.M13 * p.Y + m.M23 * p.Z + m.M33 ); } [Obsolete("Use TransposedTransformPosProjFull instead.")] public static V4f TransposedTransformProjFull(this M44f m, V3f p) => m.TransposedTransformPosProjFull(p); #endregion #region Operations /// /// Returns the given to a deleting the /// specified row and column. /// public static M33f Minor(this M44f m, int row, int column) { M33f rs = new M33f(); for (int k = 0; k < 9; k++) { var i = k / 3; var j = k % 3; var ii = (i < row) ? i : i + 1; var jj = (j < column) ? j : j + 1; rs[k] = m[ii * 4 + jj]; } return rs; } /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V4f Row(this M44f m, int index) { float* ptr = &m.M00; return new V4f(ptr[index * 4], ptr[index * 4 + 1], ptr[index * 4 + 2], ptr[index * 4 + 3]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V4f Column(this M44f m, int index) { float* ptr = &m.M00; return new V4f(ptr[index], ptr[index + 4], ptr[index + 8], ptr[index + 12]); } /// /// Returns the determinant of the given matrix. /// The determinant is only defined for square matrices. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Determinant(M44f m) => m.Determinant; /// /// Returns the transpose of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Transposed(M44f m) => m.Transposed; /// /// Transposes the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transpose(this ref M44f m) { Fun.Swap(ref m.M10, ref m.M01); Fun.Swap(ref m.M20, ref m.M02); Fun.Swap(ref m.M21, ref m.M12); Fun.Swap(ref m.M30, ref m.M03); Fun.Swap(ref m.M31, ref m.M13); Fun.Swap(ref m.M32, ref m.M23); } /// /// Returns the inverse of the given matrix. If the matrix is not invertible /// M44f.Zero is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Inverse(M44f m) => m.Inverse; /// /// Inverts the given matrix in place. Returns true if the matrix was invertible, /// otherwise the matrix remains unchanged. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Invert(this ref M44f m) { return m.LuInvert(); } /// /// Returns if the given matrix is the identity matrix I. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIdentity(this M44f m, float epsilon) { return Fun.ApproximateEquals(m, M44f.Identity, epsilon); } /// /// Returns if the given matrix is the identity matrix I. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIdentity(this M44f m) => IsIdentity(m, Constant.PositiveTinyValue); /// /// Returns if the given matrix is orthonormal (i.e. M * M^t == I) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthonormal(this M44f m, float epsilon) { var i = m * m.Transposed; return i.IsIdentity(epsilon); } /// /// Returns if the given matrix is orthonormal (i.e. M * M^t == I) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthonormal(this M44f m) => IsOrthonormal(m, Constant.PositiveTinyValue); /// /// Returns if the given matrix is orthogonal (i.e. all non-diagonal entries of M * M^t == 0) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonal(this M44f m, float epsilon) { var i = m * m.Transposed; for (int j = 0; j < 4; j++) i[j, j] = 1; //inefficient implementation: just leave out the comparisons at the diagonal entries. return i.IsIdentity(epsilon); } /// /// Returns if the given matrix is orthogonal (i.e. all non-diagonal entries of M * M^t == 0) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonal(this M44f m) => IsOrthogonal(m, Constant.PositiveTinyValue); #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M44f a, M44f b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M02 < b.M02 && a.M03 < b.M03 && a.M10 < b.M10 && a.M11 < b.M11 && a.M12 < b.M12 && a.M13 < b.M13 && a.M20 < b.M20 && a.M21 < b.M21 && a.M22 < b.M22 && a.M23 < b.M23 && a.M30 < b.M30 && a.M31 < b.M31 && a.M32 < b.M32 && a.M33 < b.M33; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M44f m, float s) { return m.M00 < s && m.M01 < s && m.M02 < s && m.M03 < s && m.M10 < s && m.M11 < s && m.M12 < s && m.M13 < s && m.M20 < s && m.M21 < s && m.M22 < s && m.M23 < s && m.M30 < s && m.M31 < s && m.M32 < s && m.M33 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(float s, M44f m) { return s < m.M00 && s < m.M01 && s < m.M02 && s < m.M03 && s < m.M10 && s < m.M11 && s < m.M12 && s < m.M13 && s < m.M20 && s < m.M21 && s < m.M22 && s < m.M23 && s < m.M30 && s < m.M31 && s < m.M32 && s < m.M33; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M44f a, M44f b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M02 < b.M02 || a.M03 < b.M03 || a.M10 < b.M10 || a.M11 < b.M11 || a.M12 < b.M12 || a.M13 < b.M13 || a.M20 < b.M20 || a.M21 < b.M21 || a.M22 < b.M22 || a.M23 < b.M23 || a.M30 < b.M30 || a.M31 < b.M31 || a.M32 < b.M32 || a.M33 < b.M33; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M44f m, float s) { return m.M00 < s || m.M01 < s || m.M02 < s || m.M03 < s || m.M10 < s || m.M11 < s || m.M12 < s || m.M13 < s || m.M20 < s || m.M21 < s || m.M22 < s || m.M23 < s || m.M30 < s || m.M31 < s || m.M32 < s || m.M33 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(float s, M44f m) { return s < m.M00 || s < m.M01 || s < m.M02 || s < m.M03 || s < m.M10 || s < m.M11 || s < m.M12 || s < m.M13 || s < m.M20 || s < m.M21 || s < m.M22 || s < m.M23 || s < m.M30 || s < m.M31 || s < m.M32 || s < m.M33; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M44f a, M44f b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M02 > b.M02 && a.M03 > b.M03 && a.M10 > b.M10 && a.M11 > b.M11 && a.M12 > b.M12 && a.M13 > b.M13 && a.M20 > b.M20 && a.M21 > b.M21 && a.M22 > b.M22 && a.M23 > b.M23 && a.M30 > b.M30 && a.M31 > b.M31 && a.M32 > b.M32 && a.M33 > b.M33; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M44f m, float s) { return m.M00 > s && m.M01 > s && m.M02 > s && m.M03 > s && m.M10 > s && m.M11 > s && m.M12 > s && m.M13 > s && m.M20 > s && m.M21 > s && m.M22 > s && m.M23 > s && m.M30 > s && m.M31 > s && m.M32 > s && m.M33 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(float s, M44f m) { return s > m.M00 && s > m.M01 && s > m.M02 && s > m.M03 && s > m.M10 && s > m.M11 && s > m.M12 && s > m.M13 && s > m.M20 && s > m.M21 && s > m.M22 && s > m.M23 && s > m.M30 && s > m.M31 && s > m.M32 && s > m.M33; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M44f a, M44f b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M02 > b.M02 || a.M03 > b.M03 || a.M10 > b.M10 || a.M11 > b.M11 || a.M12 > b.M12 || a.M13 > b.M13 || a.M20 > b.M20 || a.M21 > b.M21 || a.M22 > b.M22 || a.M23 > b.M23 || a.M30 > b.M30 || a.M31 > b.M31 || a.M32 > b.M32 || a.M33 > b.M33; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M44f m, float s) { return m.M00 > s || m.M01 > s || m.M02 > s || m.M03 > s || m.M10 > s || m.M11 > s || m.M12 > s || m.M13 > s || m.M20 > s || m.M21 > s || m.M22 > s || m.M23 > s || m.M30 > s || m.M31 > s || m.M32 > s || m.M33 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(float s, M44f m) { return s > m.M00 || s > m.M01 || s > m.M02 || s > m.M03 || s > m.M10 || s > m.M11 || s > m.M12 || s > m.M13 || s > m.M20 || s > m.M21 || s > m.M22 || s > m.M23 || s > m.M30 || s > m.M31 || s > m.M32 || s > m.M33; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M44f a, M44f b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M02 <= b.M02 && a.M03 <= b.M03 && a.M10 <= b.M10 && a.M11 <= b.M11 && a.M12 <= b.M12 && a.M13 <= b.M13 && a.M20 <= b.M20 && a.M21 <= b.M21 && a.M22 <= b.M22 && a.M23 <= b.M23 && a.M30 <= b.M30 && a.M31 <= b.M31 && a.M32 <= b.M32 && a.M33 <= b.M33; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M44f m, float s) { return m.M00 <= s && m.M01 <= s && m.M02 <= s && m.M03 <= s && m.M10 <= s && m.M11 <= s && m.M12 <= s && m.M13 <= s && m.M20 <= s && m.M21 <= s && m.M22 <= s && m.M23 <= s && m.M30 <= s && m.M31 <= s && m.M32 <= s && m.M33 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(float s, M44f m) { return s <= m.M00 && s <= m.M01 && s <= m.M02 && s <= m.M03 && s <= m.M10 && s <= m.M11 && s <= m.M12 && s <= m.M13 && s <= m.M20 && s <= m.M21 && s <= m.M22 && s <= m.M23 && s <= m.M30 && s <= m.M31 && s <= m.M32 && s <= m.M33; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M44f a, M44f b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M02 <= b.M02 || a.M03 <= b.M03 || a.M10 <= b.M10 || a.M11 <= b.M11 || a.M12 <= b.M12 || a.M13 <= b.M13 || a.M20 <= b.M20 || a.M21 <= b.M21 || a.M22 <= b.M22 || a.M23 <= b.M23 || a.M30 <= b.M30 || a.M31 <= b.M31 || a.M32 <= b.M32 || a.M33 <= b.M33; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M44f m, float s) { return m.M00 <= s || m.M01 <= s || m.M02 <= s || m.M03 <= s || m.M10 <= s || m.M11 <= s || m.M12 <= s || m.M13 <= s || m.M20 <= s || m.M21 <= s || m.M22 <= s || m.M23 <= s || m.M30 <= s || m.M31 <= s || m.M32 <= s || m.M33 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(float s, M44f m) { return s <= m.M00 || s <= m.M01 || s <= m.M02 || s <= m.M03 || s <= m.M10 || s <= m.M11 || s <= m.M12 || s <= m.M13 || s <= m.M20 || s <= m.M21 || s <= m.M22 || s <= m.M23 || s <= m.M30 || s <= m.M31 || s <= m.M32 || s <= m.M33; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M44f a, M44f b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M02 >= b.M02 && a.M03 >= b.M03 && a.M10 >= b.M10 && a.M11 >= b.M11 && a.M12 >= b.M12 && a.M13 >= b.M13 && a.M20 >= b.M20 && a.M21 >= b.M21 && a.M22 >= b.M22 && a.M23 >= b.M23 && a.M30 >= b.M30 && a.M31 >= b.M31 && a.M32 >= b.M32 && a.M33 >= b.M33; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M44f m, float s) { return m.M00 >= s && m.M01 >= s && m.M02 >= s && m.M03 >= s && m.M10 >= s && m.M11 >= s && m.M12 >= s && m.M13 >= s && m.M20 >= s && m.M21 >= s && m.M22 >= s && m.M23 >= s && m.M30 >= s && m.M31 >= s && m.M32 >= s && m.M33 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(float s, M44f m) { return s >= m.M00 && s >= m.M01 && s >= m.M02 && s >= m.M03 && s >= m.M10 && s >= m.M11 && s >= m.M12 && s >= m.M13 && s >= m.M20 && s >= m.M21 && s >= m.M22 && s >= m.M23 && s >= m.M30 && s >= m.M31 && s >= m.M32 && s >= m.M33; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M44f a, M44f b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M02 >= b.M02 || a.M03 >= b.M03 || a.M10 >= b.M10 || a.M11 >= b.M11 || a.M12 >= b.M12 || a.M13 >= b.M13 || a.M20 >= b.M20 || a.M21 >= b.M21 || a.M22 >= b.M22 || a.M23 >= b.M23 || a.M30 >= b.M30 || a.M31 >= b.M31 || a.M32 >= b.M32 || a.M33 >= b.M33; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M44f m, float s) { return m.M00 >= s || m.M01 >= s || m.M02 >= s || m.M03 >= s || m.M10 >= s || m.M11 >= s || m.M12 >= s || m.M13 >= s || m.M20 >= s || m.M21 >= s || m.M22 >= s || m.M23 >= s || m.M30 >= s || m.M31 >= s || m.M32 >= s || m.M33 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(float s, M44f m) { return s >= m.M00 || s >= m.M01 || s >= m.M02 || s >= m.M03 || s >= m.M10 || s >= m.M11 || s >= m.M12 || s >= m.M13 || s >= m.M20 || s >= m.M21 || s >= m.M22 || s >= m.M23 || s >= m.M30 || s >= m.M31 || s >= m.M32 || s >= m.M33; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M44f a, M44f b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M03 == b.M03 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M13 == b.M13 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22 && a.M23 == b.M23 && a.M30 == b.M30 && a.M31 == b.M31 && a.M32 == b.M32 && a.M33 == b.M33; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M44f m, float s) { return m.M00 == s && m.M01 == s && m.M02 == s && m.M03 == s && m.M10 == s && m.M11 == s && m.M12 == s && m.M13 == s && m.M20 == s && m.M21 == s && m.M22 == s && m.M23 == s && m.M30 == s && m.M31 == s && m.M32 == s && m.M33 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(float s, M44f m) { return s == m.M00 && s == m.M01 && s == m.M02 && s == m.M03 && s == m.M10 && s == m.M11 && s == m.M12 && s == m.M13 && s == m.M20 && s == m.M21 && s == m.M22 && s == m.M23 && s == m.M30 && s == m.M31 && s == m.M32 && s == m.M33; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M44f a, M44f b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M02 == b.M02 || a.M03 == b.M03 || a.M10 == b.M10 || a.M11 == b.M11 || a.M12 == b.M12 || a.M13 == b.M13 || a.M20 == b.M20 || a.M21 == b.M21 || a.M22 == b.M22 || a.M23 == b.M23 || a.M30 == b.M30 || a.M31 == b.M31 || a.M32 == b.M32 || a.M33 == b.M33; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M44f m, float s) { return m.M00 == s || m.M01 == s || m.M02 == s || m.M03 == s || m.M10 == s || m.M11 == s || m.M12 == s || m.M13 == s || m.M20 == s || m.M21 == s || m.M22 == s || m.M23 == s || m.M30 == s || m.M31 == s || m.M32 == s || m.M33 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(float s, M44f m) { return s == m.M00 || s == m.M01 || s == m.M02 || s == m.M03 || s == m.M10 || s == m.M11 || s == m.M12 || s == m.M13 || s == m.M20 || s == m.M21 || s == m.M22 || s == m.M23 || s == m.M30 || s == m.M31 || s == m.M32 || s == m.M33; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M44f a, M44f b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M02 != b.M02 && a.M03 != b.M03 && a.M10 != b.M10 && a.M11 != b.M11 && a.M12 != b.M12 && a.M13 != b.M13 && a.M20 != b.M20 && a.M21 != b.M21 && a.M22 != b.M22 && a.M23 != b.M23 && a.M30 != b.M30 && a.M31 != b.M31 && a.M32 != b.M32 && a.M33 != b.M33; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M44f m, float s) { return m.M00 != s && m.M01 != s && m.M02 != s && m.M03 != s && m.M10 != s && m.M11 != s && m.M12 != s && m.M13 != s && m.M20 != s && m.M21 != s && m.M22 != s && m.M23 != s && m.M30 != s && m.M31 != s && m.M32 != s && m.M33 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(float s, M44f m) { return s != m.M00 && s != m.M01 && s != m.M02 && s != m.M03 && s != m.M10 && s != m.M11 && s != m.M12 && s != m.M13 && s != m.M20 && s != m.M21 && s != m.M22 && s != m.M23 && s != m.M30 && s != m.M31 && s != m.M32 && s != m.M33; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M44f a, M44f b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M02 != b.M02 || a.M03 != b.M03 || a.M10 != b.M10 || a.M11 != b.M11 || a.M12 != b.M12 || a.M13 != b.M13 || a.M20 != b.M20 || a.M21 != b.M21 || a.M22 != b.M22 || a.M23 != b.M23 || a.M30 != b.M30 || a.M31 != b.M31 || a.M32 != b.M32 || a.M33 != b.M33; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M44f m, float s) { return m.M00 != s || m.M01 != s || m.M02 != s || m.M03 != s || m.M10 != s || m.M11 != s || m.M12 != s || m.M13 != s || m.M20 != s || m.M21 != s || m.M22 != s || m.M23 != s || m.M30 != s || m.M31 != s || m.M32 != s || m.M33 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(float s, M44f m) { return s != m.M00 || s != m.M01 || s != m.M02 || s != m.M03 || s != m.M10 || s != m.M11 || s != m.M12 || s != m.M13 || s != m.M20 || s != m.M21 || s != m.M22 || s != m.M23 || s != m.M30 || s != m.M31 || s != m.M32 || s != m.M33; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M44f m0, M44f m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M02 < m1.M02) return -1; if (m0.M02 > m1.M02) return +1; if (m0.M03 < m1.M03) return -1; if (m0.M03 > m1.M03) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; if (m0.M12 < m1.M12) return -1; if (m0.M12 > m1.M12) return +1; if (m0.M13 < m1.M13) return -1; if (m0.M13 > m1.M13) return +1; if (m0.M20 < m1.M20) return -1; if (m0.M20 > m1.M20) return +1; if (m0.M21 < m1.M21) return -1; if (m0.M21 > m1.M21) return +1; if (m0.M22 < m1.M22) return -1; if (m0.M22 > m1.M22) return +1; if (m0.M23 < m1.M23) return -1; if (m0.M23 > m1.M23) return +1; if (m0.M30 < m1.M30) return -1; if (m0.M30 > m1.M30) return +1; if (m0.M31 < m1.M31) return -1; if (m0.M31 > m1.M31) return +1; if (m0.M32 < m1.M32) return -1; if (m0.M32 > m1.M32) return +1; if (m0.M33 < m1.M33) return -1; if (m0.M33 > m1.M33) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MinElement(M44f m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MaxElement(M44f m) => m.MaxElement; #endregion #region Orthogonalization /// /// Orthogonalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// public static void Orthogonalize(this ref M44f matrix) { matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C0, matrix.C2) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C1, matrix.C2) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C2 -= (Vec.Dot(matrix.C0, matrix.C2) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C1, matrix.C2) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C3 -= (Vec.Dot(matrix.C0, matrix.C3) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C3 -= (Vec.Dot(matrix.C1, matrix.C3) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C3 -= (Vec.Dot(matrix.C2, matrix.C3) / Vec.Dot(matrix.C2, matrix.C2)) * matrix.C2; matrix.C3 -= (Vec.Dot(matrix.C0, matrix.C3) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C3 -= (Vec.Dot(matrix.C1, matrix.C3) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C3 -= (Vec.Dot(matrix.C2, matrix.C3) / Vec.Dot(matrix.C2, matrix.C2)) * matrix.C2; } /// /// Orthogonalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Orthogonalized(this M44f matrix) { M44f m = matrix; Orthogonalize(ref m); return m; } /// /// Orthonormalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// public static void Orthonormalize(this ref M44f matrix) { matrix.C0 = matrix.C0.Normalized; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 = matrix.C1.Normalized; matrix.C2 -= (Vec.Dot(matrix.C0, matrix.C2) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C1, matrix.C2) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C2 -= (Vec.Dot(matrix.C0, matrix.C2) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C1, matrix.C2) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C2 = matrix.C2.Normalized; matrix.C3 -= (Vec.Dot(matrix.C0, matrix.C3) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C3 -= (Vec.Dot(matrix.C1, matrix.C3) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C3 -= (Vec.Dot(matrix.C2, matrix.C3) / Vec.Dot(matrix.C2, matrix.C2)) * matrix.C2; matrix.C3 -= (Vec.Dot(matrix.C0, matrix.C3) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C3 -= (Vec.Dot(matrix.C1, matrix.C3) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C3 -= (Vec.Dot(matrix.C2, matrix.C3) / Vec.Dot(matrix.C2, matrix.C2)) * matrix.C2; matrix.C3 = matrix.C3.Normalized; } /// /// Orthonormalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Orthonormalized(this M44f matrix) { M44f m = matrix; Orthonormalize(ref m); return m; } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M44f m, float epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M02.IsTiny(epsilon) || m.M03.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon) || m.M12.IsTiny(epsilon) || m.M13.IsTiny(epsilon) || m.M20.IsTiny(epsilon) || m.M21.IsTiny(epsilon) || m.M22.IsTiny(epsilon) || m.M23.IsTiny(epsilon) || m.M30.IsTiny(epsilon) || m.M31.IsTiny(epsilon) || m.M32.IsTiny(epsilon) || m.M33.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M44f m, float epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M02.IsTiny(epsilon) && m.M03.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon) && m.M12.IsTiny(epsilon) && m.M13.IsTiny(epsilon) && m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon) && m.M22.IsTiny(epsilon) && m.M23.IsTiny(epsilon) && m.M30.IsTiny(epsilon) && m.M31.IsTiny(epsilon) && m.M32.IsTiny(epsilon) && m.M33.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyFinite(M44f m) => m.AnyFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllFinite(M44f m) => m.AllFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(M44f m) => m.AnyNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(M44f m) => m.AllNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(M44f m) => m.AnyInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(M44f m) => m.AllInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(M44f m) => m.AnyPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(M44f m) => m.AllPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(M44f m) => m.AnyNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(M44f m) => m.AllNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(M44f m) => m.AnyTiny; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(M44f m) => m.AllTiny; #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M44f a, M44f b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M44f a, M44f b, float epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M44f m, float epsilon) => Mat.AllTiny(m, epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than Constant<float>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(M44f m) => m.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any element of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(M44f v) => v.IsNaN; /// /// Returns whether any element of the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(M44f v) => v.IsInfinity; /// /// Returns whether any element of the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(M44f v) => v.IsPositiveInfinity; /// /// Returns whether any element of the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(M44f v) => v.IsNegativeInfinity; /// /// Returns whether all elements of the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(M44f v) => v.IsFinite; #endregion } public static class IRandomUniformM44fExtensions { #region IRandomUniform extensions for M44f /// /// Uses UniformFloat() to generate the elements of an M44f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f UniformM44f(this IRandomUniform rnd) { return new M44f( rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat()); } /// /// Uses UniformFloatClosed() to generate the elements of an M44f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f UniformM44fClosed(this IRandomUniform rnd) { return new M44f( rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed()); } /// /// Uses UniformFloatOpen() to generate the elements of an M44f matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f UniformM44fOpen(this IRandomUniform rnd) { return new M44f( rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen()); } #endregion } #endregion #region M44d [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct M44d : IEquatable, IValidity, IMatrix { [DataMember] public double M00, M01, M02, M03; [DataMember] public double M10, M11, M12, M13; [DataMember] public double M20, M21, M22, M23; [DataMember] public double M30, M31, M32, M33; #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(double value) { M00 = value; M01 = 0; M02 = 0; M03 = 0; M10 = 0; M11 = value; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = value; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d( double m00, double m01, double m02, double m03, double m10, double m11, double m12, double m13, double m20, double m21, double m22, double m23, double m30, double m31, double m32, double m33) { M00 = m00; M01 = m01; M02 = m02; M03 = m03; M10 = m10; M11 = m11; M12 = m12; M13 = m13; M20 = m20; M21 = m21; M22 = m22; M23 = m23; M30 = m30; M31 = m31; M32 = m32; M33 = m33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(double[] a) { M00 = a[0]; M01 = a[1]; M02 = a[2]; M03 = a[3]; M10 = a[4]; M11 = a[5]; M12 = a[6]; M13 = a[7]; M20 = a[8]; M21 = a[9]; M22 = a[10]; M23 = a[11]; M30 = a[12]; M31 = a[13]; M32 = a[14]; M33 = a[15]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(double[] a, int start) { M00 = a[start + 0]; M01 = a[start + 1]; M02 = a[start + 2]; M03 = a[start + 3]; M10 = a[start + 4]; M11 = a[start + 5]; M12 = a[start + 6]; M13 = a[start + 7]; M20 = a[start + 8]; M21 = a[start + 9]; M22 = a[start + 10]; M23 = a[start + 11]; M30 = a[start + 12]; M31 = a[start + 13]; M32 = a[start + 14]; M33 = a[start + 15]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M22i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = 0; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M23i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M33i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = 0; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M34i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = (double)m.M03; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = (double)m.M13; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = (double)m.M23; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M44i m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = (double)m.M03; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = (double)m.M13; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = (double)m.M23; M30 = (double)m.M30; M31 = (double)m.M31; M32 = (double)m.M32; M33 = (double)m.M33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M22l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = 0; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M23l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M33l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = 0; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M34l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = (double)m.M03; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = (double)m.M13; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = (double)m.M23; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M44l m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = (double)m.M03; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = (double)m.M13; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = (double)m.M23; M30 = (double)m.M30; M31 = (double)m.M31; M32 = (double)m.M32; M33 = (double)m.M33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M22f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = 0; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M23f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M33f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = 0; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = 0; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M34f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = (double)m.M03; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = (double)m.M13; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = (double)m.M23; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M44f m) { M00 = (double)m.M00; M01 = (double)m.M01; M02 = (double)m.M02; M03 = (double)m.M03; M10 = (double)m.M10; M11 = (double)m.M11; M12 = (double)m.M12; M13 = (double)m.M13; M20 = (double)m.M20; M21 = (double)m.M21; M22 = (double)m.M22; M23 = (double)m.M23; M30 = (double)m.M30; M31 = (double)m.M31; M32 = (double)m.M32; M33 = (double)m.M33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M22d m) { M00 = m.M00; M01 = m.M01; M02 = 0; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = 0; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M23d m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = 0; M20 = 0; M21 = 0; M22 = 1; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M33d m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = 0; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = 0; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = 0; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public M44d(M34d m) { M00 = m.M00; M01 = m.M01; M02 = m.M02; M03 = m.M03; M10 = m.M10; M11 = m.M11; M12 = m.M12; M13 = m.M13; M20 = m.M20; M21 = m.M21; M22 = m.M22; M23 = m.M23; M30 = 0; M31 = 0; M32 = 0; M33 = 1; } #endregion #region Conversions public static explicit operator M44d(M22i m) { return new M44d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = 0, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44d(M23i m) { return new M44d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44d(M33i m) { return new M44d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = 0, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44d(M34i m) { return new M44d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = (double)m.M03, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = (double)m.M13, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = (double)m.M23, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44d(M44i m) { return new M44d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = (double)m.M03, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = (double)m.M13, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = (double)m.M23, M30 = (double)m.M30, M31 = (double)m.M31, M32 = (double)m.M32, M33 = (double)m.M33, }; } public static explicit operator M44d(M22l m) { return new M44d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = 0, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44d(M23l m) { return new M44d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44d(M33l m) { return new M44d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = 0, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44d(M34l m) { return new M44d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = (double)m.M03, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = (double)m.M13, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = (double)m.M23, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44d(M44l m) { return new M44d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = (double)m.M03, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = (double)m.M13, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = (double)m.M23, M30 = (double)m.M30, M31 = (double)m.M31, M32 = (double)m.M32, M33 = (double)m.M33, }; } public static explicit operator M44d(M22f m) { return new M44d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = 0, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44d(M23f m) { return new M44d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44d(M33f m) { return new M44d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = 0, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = 0, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44d(M34f m) { return new M44d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = (double)m.M03, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = (double)m.M13, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = (double)m.M23, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44d(M44f m) { return new M44d { M00 = (double)m.M00, M01 = (double)m.M01, M02 = (double)m.M02, M03 = (double)m.M03, M10 = (double)m.M10, M11 = (double)m.M11, M12 = (double)m.M12, M13 = (double)m.M13, M20 = (double)m.M20, M21 = (double)m.M21, M22 = (double)m.M22, M23 = (double)m.M23, M30 = (double)m.M30, M31 = (double)m.M31, M32 = (double)m.M32, M33 = (double)m.M33, }; } public static explicit operator M44d(M22d m) { return new M44d { M00 = m.M00, M01 = m.M01, M02 = 0, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = 0, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44d(M23d m) { return new M44d { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = 0, M20 = 0, M21 = 0, M22 = 1, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44d(M33d m) { return new M44d { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = 0, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = 0, M20 = m.M20, M21 = m.M21, M22 = m.M22, M23 = 0, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44d(M34d m) { return new M44d { M00 = m.M00, M01 = m.M01, M02 = m.M02, M03 = m.M03, M10 = m.M10, M11 = m.M11, M12 = m.M12, M13 = m.M13, M20 = m.M20, M21 = m.M21, M22 = m.M22, M23 = m.M23, M30 = 0, M31 = 0, M32 = 0, M33 = 1, }; } public static explicit operator M44d(int[] a) { return new M44d( (double)a[0], (double)a[1], (double)a[2], (double)a[3], (double)a[4], (double)a[5], (double)a[6], (double)a[7], (double)a[8], (double)a[9], (double)a[10], (double)a[11], (double)a[12], (double)a[13], (double)a[14], (double)a[15]); } public static explicit operator M44d(int[,] a) { return new M44d( (double)a[0, 0], (double)a[0, 1], (double)a[0, 2], (double)a[0, 3], (double)a[1, 0], (double)a[1, 1], (double)a[1, 2], (double)a[1, 3], (double)a[2, 0], (double)a[2, 1], (double)a[2, 2], (double)a[2, 3], (double)a[3, 0], (double)a[3, 1], (double)a[3, 2], (double)a[3, 3]); } public static explicit operator int[](M44d m) { return new int[] { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M03, (int)m.M10, (int)m.M11, (int)m.M12, (int)m.M13, (int)m.M20, (int)m.M21, (int)m.M22, (int)m.M23, (int)m.M30, (int)m.M31, (int)m.M32, (int)m.M33 }; } public static explicit operator int[,](M44d m) { return new int[,] { { (int)m.M00, (int)m.M01, (int)m.M02, (int)m.M03 }, { (int)m.M10, (int)m.M11, (int)m.M12, (int)m.M13 }, { (int)m.M20, (int)m.M21, (int)m.M22, (int)m.M23 }, { (int)m.M30, (int)m.M31, (int)m.M32, (int)m.M33 } }; } public readonly void CopyTo(int[] array, long index) { array[index + 0] = (int)M00; array[index + 1] = (int)M01; array[index + 2] = (int)M02; array[index + 3] = (int)M03; array[index + 4] = (int)M10; array[index + 5] = (int)M11; array[index + 6] = (int)M12; array[index + 7] = (int)M13; array[index + 8] = (int)M20; array[index + 9] = (int)M21; array[index + 10] = (int)M22; array[index + 11] = (int)M23; array[index + 12] = (int)M30; array[index + 13] = (int)M31; array[index + 14] = (int)M32; array[index + 15] = (int)M33; } public static explicit operator M44d(long[] a) { return new M44d( (double)a[0], (double)a[1], (double)a[2], (double)a[3], (double)a[4], (double)a[5], (double)a[6], (double)a[7], (double)a[8], (double)a[9], (double)a[10], (double)a[11], (double)a[12], (double)a[13], (double)a[14], (double)a[15]); } public static explicit operator M44d(long[,] a) { return new M44d( (double)a[0, 0], (double)a[0, 1], (double)a[0, 2], (double)a[0, 3], (double)a[1, 0], (double)a[1, 1], (double)a[1, 2], (double)a[1, 3], (double)a[2, 0], (double)a[2, 1], (double)a[2, 2], (double)a[2, 3], (double)a[3, 0], (double)a[3, 1], (double)a[3, 2], (double)a[3, 3]); } public static explicit operator long[](M44d m) { return new long[] { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M03, (long)m.M10, (long)m.M11, (long)m.M12, (long)m.M13, (long)m.M20, (long)m.M21, (long)m.M22, (long)m.M23, (long)m.M30, (long)m.M31, (long)m.M32, (long)m.M33 }; } public static explicit operator long[,](M44d m) { return new long[,] { { (long)m.M00, (long)m.M01, (long)m.M02, (long)m.M03 }, { (long)m.M10, (long)m.M11, (long)m.M12, (long)m.M13 }, { (long)m.M20, (long)m.M21, (long)m.M22, (long)m.M23 }, { (long)m.M30, (long)m.M31, (long)m.M32, (long)m.M33 } }; } public readonly void CopyTo(long[] array, long index) { array[index + 0] = (long)M00; array[index + 1] = (long)M01; array[index + 2] = (long)M02; array[index + 3] = (long)M03; array[index + 4] = (long)M10; array[index + 5] = (long)M11; array[index + 6] = (long)M12; array[index + 7] = (long)M13; array[index + 8] = (long)M20; array[index + 9] = (long)M21; array[index + 10] = (long)M22; array[index + 11] = (long)M23; array[index + 12] = (long)M30; array[index + 13] = (long)M31; array[index + 14] = (long)M32; array[index + 15] = (long)M33; } public static explicit operator M44d(float[] a) { return new M44d( (double)a[0], (double)a[1], (double)a[2], (double)a[3], (double)a[4], (double)a[5], (double)a[6], (double)a[7], (double)a[8], (double)a[9], (double)a[10], (double)a[11], (double)a[12], (double)a[13], (double)a[14], (double)a[15]); } public static explicit operator M44d(float[,] a) { return new M44d( (double)a[0, 0], (double)a[0, 1], (double)a[0, 2], (double)a[0, 3], (double)a[1, 0], (double)a[1, 1], (double)a[1, 2], (double)a[1, 3], (double)a[2, 0], (double)a[2, 1], (double)a[2, 2], (double)a[2, 3], (double)a[3, 0], (double)a[3, 1], (double)a[3, 2], (double)a[3, 3]); } public static explicit operator float[](M44d m) { return new float[] { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M03, (float)m.M10, (float)m.M11, (float)m.M12, (float)m.M13, (float)m.M20, (float)m.M21, (float)m.M22, (float)m.M23, (float)m.M30, (float)m.M31, (float)m.M32, (float)m.M33 }; } public static explicit operator float[,](M44d m) { return new float[,] { { (float)m.M00, (float)m.M01, (float)m.M02, (float)m.M03 }, { (float)m.M10, (float)m.M11, (float)m.M12, (float)m.M13 }, { (float)m.M20, (float)m.M21, (float)m.M22, (float)m.M23 }, { (float)m.M30, (float)m.M31, (float)m.M32, (float)m.M33 } }; } public readonly void CopyTo(float[] array, long index) { array[index + 0] = (float)M00; array[index + 1] = (float)M01; array[index + 2] = (float)M02; array[index + 3] = (float)M03; array[index + 4] = (float)M10; array[index + 5] = (float)M11; array[index + 6] = (float)M12; array[index + 7] = (float)M13; array[index + 8] = (float)M20; array[index + 9] = (float)M21; array[index + 10] = (float)M22; array[index + 11] = (float)M23; array[index + 12] = (float)M30; array[index + 13] = (float)M31; array[index + 14] = (float)M32; array[index + 15] = (float)M33; } public static explicit operator M44d(double[] a) { return new M44d( a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); } public static explicit operator M44d(double[,] a) { return new M44d( a[0, 0], a[0, 1], a[0, 2], a[0, 3], a[1, 0], a[1, 1], a[1, 2], a[1, 3], a[2, 0], a[2, 1], a[2, 2], a[2, 3], a[3, 0], a[3, 1], a[3, 2], a[3, 3]); } public static explicit operator double[](M44d m) { return new double[] { m.M00, m.M01, m.M02, m.M03, m.M10, m.M11, m.M12, m.M13, m.M20, m.M21, m.M22, m.M23, m.M30, m.M31, m.M32, m.M33 }; } public static explicit operator double[,](M44d m) { return new double[,] { { m.M00, m.M01, m.M02, m.M03 }, { m.M10, m.M11, m.M12, m.M13 }, { m.M20, m.M21, m.M22, m.M23 }, { m.M30, m.M31, m.M32, m.M33 } }; } public readonly void CopyTo(double[] array, long index) { array[index + 0] = M00; array[index + 1] = M01; array[index + 2] = M02; array[index + 3] = M03; array[index + 4] = M10; array[index + 5] = M11; array[index + 6] = M12; array[index + 7] = M13; array[index + 8] = M20; array[index + 9] = M21; array[index + 10] = M22; array[index + 11] = M23; array[index + 12] = M30; array[index + 13] = M31; array[index + 14] = M32; array[index + 15] = M33; } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44i Copy(Func element_fun) { return new M44i( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23), element_fun(M30), element_fun(M31), element_fun(M32), element_fun(M33)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44i Copy(Func element_index0_index1_fun) { return new M44i( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3), element_index0_index1_fun(M30, 3, 0), element_index0_index1_fun(M31, 3, 1), element_index0_index1_fun(M32, 3, 2), element_index0_index1_fun(M33, 3, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44l Copy(Func element_fun) { return new M44l( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23), element_fun(M30), element_fun(M31), element_fun(M32), element_fun(M33)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44l Copy(Func element_index0_index1_fun) { return new M44l( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3), element_index0_index1_fun(M30, 3, 0), element_index0_index1_fun(M31, 3, 1), element_index0_index1_fun(M32, 3, 2), element_index0_index1_fun(M33, 3, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44f Copy(Func element_fun) { return new M44f( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23), element_fun(M30), element_fun(M31), element_fun(M32), element_fun(M33)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44f Copy(Func element_index0_index1_fun) { return new M44f( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3), element_index0_index1_fun(M30, 3, 0), element_index0_index1_fun(M31, 3, 1), element_index0_index1_fun(M32, 3, 2), element_index0_index1_fun(M33, 3, 3)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44d Copy(Func element_fun) { return new M44d( element_fun(M00), element_fun(M01), element_fun(M02), element_fun(M03), element_fun(M10), element_fun(M11), element_fun(M12), element_fun(M13), element_fun(M20), element_fun(M21), element_fun(M22), element_fun(M23), element_fun(M30), element_fun(M31), element_fun(M32), element_fun(M33)); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly M44d Copy(Func element_index0_index1_fun) { return new M44d( element_index0_index1_fun(M00, 0, 0), element_index0_index1_fun(M01, 0, 1), element_index0_index1_fun(M02, 0, 2), element_index0_index1_fun(M03, 0, 3), element_index0_index1_fun(M10, 1, 0), element_index0_index1_fun(M11, 1, 1), element_index0_index1_fun(M12, 1, 2), element_index0_index1_fun(M13, 1, 3), element_index0_index1_fun(M20, 2, 0), element_index0_index1_fun(M21, 2, 1), element_index0_index1_fun(M22, 2, 2), element_index0_index1_fun(M23, 2, 3), element_index0_index1_fun(M30, 3, 0), element_index0_index1_fun(M31, 3, 1), element_index0_index1_fun(M32, 3, 2), element_index0_index1_fun(M33, 3, 3)); } /// /// Returns a copy of the upper left sub matrix. /// public readonly M33d UpperLeftM33() { return (M33d)this; } public readonly double[] ToArray() { var array = new double[16]; array[0] = M00; array[1] = M01; array[2] = M02; array[3] = M03; array[4] = M10; array[5] = M11; array[6] = M12; array[7] = M13; array[8] = M20; array[9] = M21; array[10] = M22; array[11] = M23; array[12] = M30; array[13] = M31; array[14] = M32; array[15] = M33; return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d FromCols(V4d col0, V4d col1, V4d col2, V4d col3) { return new M44d( col0.X, col1.X, col2.X, col3.X, col0.Y, col1.Y, col2.Y, col3.Y, col0.Z, col1.Z, col2.Z, col3.Z, col0.W, col1.W, col2.W, col3.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d FromRows(V4d row0, V4d row1, V4d row2, V4d row3) { return new M44d( row0.X, row0.Y, row0.Z, row0.W, row1.X, row1.Y, row1.Z, row1.W, row2.X, row2.Y, row2.Z, row2.W, row3.X, row3.Y, row3.Z, row3.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d FromDiagonal(double value) { return new M44d( value, 0, 0, 0, 0, value, 0, 0, 0, 0, value, 0, 0, 0, 0, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d FromDiagonal(double m00, double m11, double m22, double m33) { return new M44d( m00, 0, 0, 0, 0, m11, 0, 0, 0, 0, m22, 0, 0, 0, 0, m33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d FromDiagonal(V4d s) { return new M44d( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0, 0, 0, 0, s.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d FromAntiDiagonal(double value) { return new M44d( 0, 0, 0, value, 0, 0, value, 0, 0, value, 0, 0, value, 0, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d FromAntiDiagonal(double m03, double m12, double m21, double m30) { return new M44d( 0, 0, 0, m03, 0, 0, m12, 0, 0, m21, 0, 0, m30, 0, 0, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d FromAntiDiagonal(V4d s) { return new M44d( 0, 0, 0, s.X, 0, 0, s.Y, 0, 0, s.Z, 0, 0, s.W, 0, 0, 0); } #region Scale /// /// Creates a transformation using 4 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Scale(double sX, double sY, double sZ, double sW) => FromDiagonal(sX, sY, sZ, sW); /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Scale(V4d s) => FromDiagonal(s); /// /// Creates a homogenous transformation using a uniform scale. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Scale(double s) { return new M44d( s, 0, 0, 0, 0, s, 0, 0, 0, 0, s, 0, 0, 0, 0, 1); } /// /// Creates a transformation using 3 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Scale(double sX, double sY, double sZ) { return new M44d( sX, 0, 0, 0, 0, sY, 0, 0, 0, 0, sZ, 0, 0, 0, 0, 1); } /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Scale(V3d s) { return new M44d( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0, 0, 0, 0, 1); } /// /// Creates a scaling transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Scale(Scale3d s) { return new M44d( s.X, 0, 0, 0, 0, s.Y, 0, 0, 0, 0, s.Z, 0, 0, 0, 0, 1); } #endregion #region Translation /// /// Creates a transformation with the translational component given by 3 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Translation(double tX, double tY, double tZ) { return new M44d( 1, 0, 0, tX, 0, 1, 0, tY, 0, 0, 1, tZ, 0, 0, 0, 1); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Translation(V3d t) { return new M44d( 1, 0, 0, t.X, 0, 1, 0, t.Y, 0, 0, 1, t.Z, 0, 0, 0, 1); } /// /// Creates a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Translation(Shift3d s) { return new M44d( 1, 0, 0, s.X, 0, 1, 0, s.Y, 0, 0, 1, s.Z, 0, 0, 0, 1); } #endregion #region Rotation /// /// Creates a 3D rotation matrix from a /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Rotation(Rot3d r) => (M44d)r; /// /// Creates a 3D rotation matrix from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Rotation(V3d normalizedAxis, double angleInRadians) { Debug.Assert(normalizedAxis.LengthSquared.ApproximateEquals(1, 1e-10)); return (M44d)(Rot3d.Rotation(normalizedAxis, angleInRadians)); } /// /// Creates a 3D rotation matrix from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d RotationInDegrees(V3d normalizedAxis, double angleInDegrees) => Rotation(normalizedAxis, angleInDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d RotationEuler(double rollInRadians, double pitchInRadians, double yawInRadians) { return (M44d)(Rot3d.RotationEuler(rollInRadians, pitchInRadians, yawInRadians)); } /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d RotationEulerInDegrees(double rollInDegrees, double pitchInDegrees, double yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d RotationEuler(V3d rollPitchYawInRadians) => RotationEuler( rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d RotationEulerInDegrees(V3d rollPitchYawInDegrees) => RotationEulerInDegrees( rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a 3D rotation matrix which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d RotateInto(V3d from, V3d into) { Debug.Assert(from.LengthSquared.ApproximateEquals(1, 1e-10)); Debug.Assert(into.LengthSquared.ApproximateEquals(1, 1e-10)); return (M44d)(Rot3d.RotateInto(from, into)); } /// /// Creates a 3D rotation matrix for radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d RotationX(double angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M44d( 1, 0, 0, 0, 0, a, -b, 0, 0, b, a, 0, 0, 0, 0, 1); } /// /// Creates a 3D rotation matrix for degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d RotationXInDegrees(double angleDegrees) => RotationX(angleDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix for radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d RotationY(double angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M44d( a, 0, b, 0, 0, 1, 0, 0, -b, 0, a, 0, 0, 0, 0, 1); } /// /// Creates a 3D rotation matrix for degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d RotationYInDegrees(double angleDegrees) => RotationY(angleDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix for radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d RotationZ(double angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new M44d( a, -b, 0, 0, b, a, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } /// /// Creates a 3D rotation matrix for degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d RotationZInDegrees(double angleDegrees) => RotationZ(angleDegrees.RadiansFromDegrees()); #endregion #region Shearing /// /// Creates a shear transformation matrix along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d ShearXY(double factorX, double factorY) { return new M44d( 1, 0, factorX, 0, 0, 1, factorY, 0, 0, 0, 1, 0, 0, 0, 0, 1); } /// /// Creates a shear transformation matrix along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d ShearXZ(double factorX, double factorZ) { return new M44d( 1, factorX, 0, 0, 0, 1, 0, 0, 0, factorZ, 1, 0, 0, 0, 0, 1); } /// /// Creates a shear transformation matrix along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d ShearYZ(double factorY, double factorZ) { return new M44d( 1, 0, 0, 0, factorY, 1, 0, 0, factorZ, 0, 1, 0, 0, 0, 0, 1); } #endregion #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d DivideByInt(M44d m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return M00; yield return M01; yield return M02; yield return M03; yield return M10; yield return M11; yield return M12; yield return M13; yield return M20; yield return M21; yield return M22; yield return M23; yield return M30; yield return M31; yield return M32; yield return M33; } } public readonly IEnumerable Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return R0; yield return R1; yield return R2; yield return R3; } } public readonly IEnumerable Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return C0; yield return C1; yield return C2; yield return C3; } } [XmlIgnore] public V4d R0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4d( M00, M01, M02, M03); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M01 = value.Y; M02 = value.Z; M03 = value.W; } } [XmlIgnore] public V4d R1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4d( M10, M11, M12, M13); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M10 = value.X; M11 = value.Y; M12 = value.Z; M13 = value.W; } } [XmlIgnore] public V4d R2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4d( M20, M21, M22, M23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M20 = value.X; M21 = value.Y; M22 = value.Z; M23 = value.W; } } [XmlIgnore] public V4d R3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4d( M30, M31, M32, M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M30 = value.X; M31 = value.Y; M32 = value.Z; M33 = value.W; } } [XmlIgnore] public V4d C0 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4d( M00, M10, M20, M30); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M00 = value.X; M10 = value.Y; M20 = value.Z; M30 = value.W; } } [XmlIgnore] public V4d C1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4d( M01, M11, M21, M31); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M01 = value.X; M11 = value.Y; M21 = value.Z; M31 = value.W; } } [XmlIgnore] public V4d C2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4d( M02, M12, M22, M32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M02 = value.X; M12 = value.Y; M22 = value.Z; M32 = value.W; } } [XmlIgnore] public V4d C3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V4d( M03, M13, M23, M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { M03 = value.X; M13 = value.Y; M23 = value.Z; M33 = value.W; } } public readonly V4d Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V4d(M00, M11, M22, M33); } public readonly V4d AntiDiagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V4d(M03, M12, M21, M30); } /// /// Returns the minimum element of the matrix. /// public readonly double MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23, M30, M31, M32, M33); } /// /// Returns the maximum element of the matrix. /// public readonly double MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23, M30, M31, M32, M33); } public unsafe double this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &M00) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &M00) { ptr[index] = value; } } } public unsafe double this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &M00) { return ptr[row * 4 + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &M00) { ptr[row * 4 + column] = value; } } } public readonly bool AnyFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) || Fun.IsFinite(M01) || Fun.IsFinite(M02) || Fun.IsFinite(M03) || Fun.IsFinite(M10) || Fun.IsFinite(M11) || Fun.IsFinite(M12) || Fun.IsFinite(M13) || Fun.IsFinite(M20) || Fun.IsFinite(M21) || Fun.IsFinite(M22) || Fun.IsFinite(M23) || Fun.IsFinite(M30) || Fun.IsFinite(M31) || Fun.IsFinite(M32) || Fun.IsFinite(M33); } } public readonly bool AllFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsFinite(M00) && Fun.IsFinite(M01) && Fun.IsFinite(M02) && Fun.IsFinite(M03) && Fun.IsFinite(M10) && Fun.IsFinite(M11) && Fun.IsFinite(M12) && Fun.IsFinite(M13) && Fun.IsFinite(M20) && Fun.IsFinite(M21) && Fun.IsFinite(M22) && Fun.IsFinite(M23) && Fun.IsFinite(M30) && Fun.IsFinite(M31) && Fun.IsFinite(M32) && Fun.IsFinite(M33); } } public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNaN(M00) || double.IsNaN(M01) || double.IsNaN(M02) || double.IsNaN(M03) || double.IsNaN(M10) || double.IsNaN(M11) || double.IsNaN(M12) || double.IsNaN(M13) || double.IsNaN(M20) || double.IsNaN(M21) || double.IsNaN(M22) || double.IsNaN(M23) || double.IsNaN(M30) || double.IsNaN(M31) || double.IsNaN(M32) || double.IsNaN(M33); } } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNaN(M00) && double.IsNaN(M01) && double.IsNaN(M02) && double.IsNaN(M03) && double.IsNaN(M10) && double.IsNaN(M11) && double.IsNaN(M12) && double.IsNaN(M13) && double.IsNaN(M20) && double.IsNaN(M21) && double.IsNaN(M22) && double.IsNaN(M23) && double.IsNaN(M30) && double.IsNaN(M31) && double.IsNaN(M32) && double.IsNaN(M33); } } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsInfinity(M00) || double.IsInfinity(M01) || double.IsInfinity(M02) || double.IsInfinity(M03) || double.IsInfinity(M10) || double.IsInfinity(M11) || double.IsInfinity(M12) || double.IsInfinity(M13) || double.IsInfinity(M20) || double.IsInfinity(M21) || double.IsInfinity(M22) || double.IsInfinity(M23) || double.IsInfinity(M30) || double.IsInfinity(M31) || double.IsInfinity(M32) || double.IsInfinity(M33); } } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsInfinity(M00) && double.IsInfinity(M01) && double.IsInfinity(M02) && double.IsInfinity(M03) && double.IsInfinity(M10) && double.IsInfinity(M11) && double.IsInfinity(M12) && double.IsInfinity(M13) && double.IsInfinity(M20) && double.IsInfinity(M21) && double.IsInfinity(M22) && double.IsInfinity(M23) && double.IsInfinity(M30) && double.IsInfinity(M31) && double.IsInfinity(M32) && double.IsInfinity(M33); } } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsPositiveInfinity(M00) || double.IsPositiveInfinity(M01) || double.IsPositiveInfinity(M02) || double.IsPositiveInfinity(M03) || double.IsPositiveInfinity(M10) || double.IsPositiveInfinity(M11) || double.IsPositiveInfinity(M12) || double.IsPositiveInfinity(M13) || double.IsPositiveInfinity(M20) || double.IsPositiveInfinity(M21) || double.IsPositiveInfinity(M22) || double.IsPositiveInfinity(M23) || double.IsPositiveInfinity(M30) || double.IsPositiveInfinity(M31) || double.IsPositiveInfinity(M32) || double.IsPositiveInfinity(M33); } } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsPositiveInfinity(M00) && double.IsPositiveInfinity(M01) && double.IsPositiveInfinity(M02) && double.IsPositiveInfinity(M03) && double.IsPositiveInfinity(M10) && double.IsPositiveInfinity(M11) && double.IsPositiveInfinity(M12) && double.IsPositiveInfinity(M13) && double.IsPositiveInfinity(M20) && double.IsPositiveInfinity(M21) && double.IsPositiveInfinity(M22) && double.IsPositiveInfinity(M23) && double.IsPositiveInfinity(M30) && double.IsPositiveInfinity(M31) && double.IsPositiveInfinity(M32) && double.IsPositiveInfinity(M33); } } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNegativeInfinity(M00) || double.IsNegativeInfinity(M01) || double.IsNegativeInfinity(M02) || double.IsNegativeInfinity(M03) || double.IsNegativeInfinity(M10) || double.IsNegativeInfinity(M11) || double.IsNegativeInfinity(M12) || double.IsNegativeInfinity(M13) || double.IsNegativeInfinity(M20) || double.IsNegativeInfinity(M21) || double.IsNegativeInfinity(M22) || double.IsNegativeInfinity(M23) || double.IsNegativeInfinity(M30) || double.IsNegativeInfinity(M31) || double.IsNegativeInfinity(M32) || double.IsNegativeInfinity(M33); } } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return double.IsNegativeInfinity(M00) && double.IsNegativeInfinity(M01) && double.IsNegativeInfinity(M02) && double.IsNegativeInfinity(M03) && double.IsNegativeInfinity(M10) && double.IsNegativeInfinity(M11) && double.IsNegativeInfinity(M12) && double.IsNegativeInfinity(M13) && double.IsNegativeInfinity(M20) && double.IsNegativeInfinity(M21) && double.IsNegativeInfinity(M22) && double.IsNegativeInfinity(M23) && double.IsNegativeInfinity(M30) && double.IsNegativeInfinity(M31) && double.IsNegativeInfinity(M32) && double.IsNegativeInfinity(M33); } } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) || Fun.IsTiny(M01) || Fun.IsTiny(M02) || Fun.IsTiny(M03) || Fun.IsTiny(M10) || Fun.IsTiny(M11) || Fun.IsTiny(M12) || Fun.IsTiny(M13) || Fun.IsTiny(M20) || Fun.IsTiny(M21) || Fun.IsTiny(M22) || Fun.IsTiny(M23) || Fun.IsTiny(M30) || Fun.IsTiny(M31) || Fun.IsTiny(M32) || Fun.IsTiny(M33); } } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.IsTiny(M00) && Fun.IsTiny(M01) && Fun.IsTiny(M02) && Fun.IsTiny(M03) && Fun.IsTiny(M10) && Fun.IsTiny(M11) && Fun.IsTiny(M12) && Fun.IsTiny(M13) && Fun.IsTiny(M20) && Fun.IsTiny(M21) && Fun.IsTiny(M22) && Fun.IsTiny(M23) && Fun.IsTiny(M30) && Fun.IsTiny(M31) && Fun.IsTiny(M32) && Fun.IsTiny(M33); } } /// /// Returns true if the absolute value of each element of the matrix is smaller than Constant<double>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any element of the matrix is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any element of the matrix is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any element of the matrix is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any element of the matrix is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all elements of the matrix are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Constants public const int RowCount = 4; public const int ColumnCount = 4; public const int ElementCount = 4 * 4; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(4, 4); } public static M44d Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M44d(0); } public static M44d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new M44d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly double Norm1 { get { return Fun.Abs(M00) + Fun.Abs(M01) + Fun.Abs(M02) + Fun.Abs(M03) + Fun.Abs(M10) + Fun.Abs(M11) + Fun.Abs(M12) + Fun.Abs(M13) + Fun.Abs(M20) + Fun.Abs(M21) + Fun.Abs(M22) + Fun.Abs(M23) + Fun.Abs(M30) + Fun.Abs(M31) + Fun.Abs(M32) + Fun.Abs(M33); } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly double Norm2 { get { return Fun.Sqrt( M00 * M00 + M01 * M01 + M02 * M02 + M03 * M03 + M10 * M10 + M11 * M11 + M12 * M12 + M13 * M13 + M20 * M20 + M21 * M21 + M22 * M22 + M23 * M23 + M30 * M30 + M31 * M31 + M32 * M32 + M33 * M33); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly double NormMax { get { return Fun.Max( Fun.Max( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02), Fun.Abs(M03)), Fun.Max( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12), Fun.Abs(M13)), Fun.Max( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22), Fun.Abs(M23)), Fun.Max( Fun.Abs(M30), Fun.Abs(M31), Fun.Abs(M32), Fun.Abs(M33))); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly double NormMin { get { return Fun.Min( Fun.Min( Fun.Abs(M00), Fun.Abs(M01), Fun.Abs(M02), Fun.Abs(M03)), Fun.Min( Fun.Abs(M10), Fun.Abs(M11), Fun.Abs(M12), Fun.Abs(M13)), Fun.Min( Fun.Abs(M20), Fun.Abs(M21), Fun.Abs(M22), Fun.Abs(M23)), Fun.Min( Fun.Abs(M30), Fun.Abs(M31), Fun.Abs(M32), Fun.Abs(M33))); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator -(M44d m) { return new M44d( -m.M00, -m.M01, -m.M02, -m.M03, -m.M10, -m.M11, -m.M12, -m.M13, -m.M20, -m.M21, -m.M22, -m.M23, -m.M30, -m.M31, -m.M32, -m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator + (M44d a, M44d b) { return new M44d( a.M00 + b.M00, a.M01 + b.M01, a.M02 + b.M02, a.M03 + b.M03, a.M10 + b.M10, a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M20 + b.M20, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23, a.M30 + b.M30, a.M31 + b.M31, a.M32 + b.M32, a.M33 + b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator + (M44d m, double s) { return new M44d( m.M00 + s, m.M01 + s, m.M02 + s, m.M03 + s, m.M10 + s, m.M11 + s, m.M12 + s, m.M13 + s, m.M20 + s, m.M21 + s, m.M22 + s, m.M23 + s, m.M30 + s, m.M31 + s, m.M32 + s, m.M33 + s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator + (double s, M44d m) { return new M44d( s + m.M00, s + m.M01, s + m.M02, s + m.M03, s + m.M10, s + m.M11, s + m.M12, s + m.M13, s + m.M20, s + m.M21, s + m.M22, s + m.M23, s + m.M30, s + m.M31, s + m.M32, s + m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator - (M44d a, M44d b) { return new M44d( a.M00 - b.M00, a.M01 - b.M01, a.M02 - b.M02, a.M03 - b.M03, a.M10 - b.M10, a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M20 - b.M20, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23, a.M30 - b.M30, a.M31 - b.M31, a.M32 - b.M32, a.M33 - b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator - (M44d m, double s) { return new M44d( m.M00 - s, m.M01 - s, m.M02 - s, m.M03 - s, m.M10 - s, m.M11 - s, m.M12 - s, m.M13 - s, m.M20 - s, m.M21 - s, m.M22 - s, m.M23 - s, m.M30 - s, m.M31 - s, m.M32 - s, m.M33 - s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator - (double s, M44d m) { return new M44d( s - m.M00, s - m.M01, s - m.M02, s - m.M03, s - m.M10, s - m.M11, s - m.M12, s - m.M13, s - m.M20, s - m.M21, s - m.M22, s - m.M23, s - m.M30, s - m.M31, s - m.M32, s - m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator % (M44d a, M44d b) { return new M44d( a.M00 % b.M00, a.M01 % b.M01, a.M02 % b.M02, a.M03 % b.M03, a.M10 % b.M10, a.M11 % b.M11, a.M12 % b.M12, a.M13 % b.M13, a.M20 % b.M20, a.M21 % b.M21, a.M22 % b.M22, a.M23 % b.M23, a.M30 % b.M30, a.M31 % b.M31, a.M32 % b.M32, a.M33 % b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator % (M44d m, double s) { return new M44d( m.M00 % s, m.M01 % s, m.M02 % s, m.M03 % s, m.M10 % s, m.M11 % s, m.M12 % s, m.M13 % s, m.M20 % s, m.M21 % s, m.M22 % s, m.M23 % s, m.M30 % s, m.M31 % s, m.M32 % s, m.M33 % s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator % (double s, M44d m) { return new M44d( s % m.M00, s % m.M01, s % m.M02, s % m.M03, s % m.M10, s % m.M11, s % m.M12, s % m.M13, s % m.M20, s % m.M21, s % m.M22, s % m.M23, s % m.M30, s % m.M31, s % m.M32, s % m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator / (M44d a, M44d b) { return new M44d( a.M00 / b.M00, a.M01 / b.M01, a.M02 / b.M02, a.M03 / b.M03, a.M10 / b.M10, a.M11 / b.M11, a.M12 / b.M12, a.M13 / b.M13, a.M20 / b.M20, a.M21 / b.M21, a.M22 / b.M22, a.M23 / b.M23, a.M30 / b.M30, a.M31 / b.M31, a.M32 / b.M32, a.M33 / b.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator / (M44d m, double s) { return new M44d( m.M00 / s, m.M01 / s, m.M02 / s, m.M03 / s, m.M10 / s, m.M11 / s, m.M12 / s, m.M13 / s, m.M20 / s, m.M21 / s, m.M22 / s, m.M23 / s, m.M30 / s, m.M31 / s, m.M32 / s, m.M33 / s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator / (double s, M44d m) { return new M44d( s / m.M00, s / m.M01, s / m.M02, s / m.M03, s / m.M10, s / m.M11, s / m.M12, s / m.M13, s / m.M20, s / m.M21, s / m.M22, s / m.M23, s / m.M30, s / m.M31, s / m.M32, s / m.M33); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator * (M44d m, double s) { return new M44d( m.M00 * s, m.M01 * s, m.M02 * s, m.M03 * s, m.M10 * s, m.M11 * s, m.M12 * s, m.M13 * s, m.M20 * s, m.M21 * s, m.M22 * s, m.M23 * s, m.M30 * s, m.M31 * s, m.M32 * s, m.M33 * s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator * (double s, M44d m) { return new M44d( s * m.M00, s * m.M01, s * m.M02, s * m.M03, s * m.M10, s * m.M11, s * m.M12, s * m.M13, s * m.M20, s * m.M21, s * m.M22, s * m.M23, s * m.M30, s * m.M31, s * m.M32, s * m.M33); } #endregion #region Matrix/Vector Multiplication /// /// Multiplies a M44d matrix with a V4d column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator *(M44d m, V4d v) { return new V4d( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z + m.M03 * v.W, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z + m.M13 * v.W, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z + m.M23 * v.W, m.M30 * v.X + m.M31 * v.Y + m.M32 * v.Z + m.M33 * v.W); } /// /// Multiplies a V4d row vector with a M44d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator *(V4d v, M44d m) { return new V4d( v.X * m.M00 + v.Y * m.M10 + v.Z * m.M20 + v.W * m.M30, v.X * m.M01 + v.Y * m.M11 + v.Z * m.M21 + v.W * m.M31, v.X * m.M02 + v.Y * m.M12 + v.Z * m.M22 + v.W * m.M32, v.X * m.M03 + v.Y * m.M13 + v.Z * m.M23 + v.W * m.M33); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M44d a, M44d b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M03 == b.M03 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M13 == b.M13 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22 && a.M23 == b.M23 && a.M30 == b.M30 && a.M31 == b.M31 && a.M32 == b.M32 && a.M33 == b.M33; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(M44d a, double s) { return a.M00 == s && a.M01 == s && a.M02 == s && a.M03 == s && a.M10 == s && a.M11 == s && a.M12 == s && a.M13 == s && a.M20 == s && a.M21 == s && a.M22 == s && a.M23 == s && a.M30 == s && a.M31 == s && a.M32 == s && a.M33 == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(double s, M44d a) { return s == a.M00 && s == a.M01 && s == a.M02 && s == a.M03 && s == a.M10 && s == a.M11 && s == a.M12 && s == a.M13 && s == a.M20 && s == a.M21 && s == a.M22 && s == a.M23 && s == a.M30 && s == a.M31 && s == a.M32 && s == a.M33 ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M44d a, M44d b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(M44d m, double s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(double s, M44d m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined( HashCode.GetCombined(M00, M01, M02, M03), HashCode.GetCombined(M10, M11, M12, M13), HashCode.GetCombined(M20, M21, M22, M23), HashCode.GetCombined(M30, M31, M32, M33)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(M44d other) { return M00.Equals(other.M00) && M01.Equals(other.M01) && M02.Equals(other.M02) && M03.Equals(other.M03) && M10.Equals(other.M10) && M11.Equals(other.M11) && M12.Equals(other.M12) && M13.Equals(other.M13) && M20.Equals(other.M20) && M21.Equals(other.M21) && M22.Equals(other.M22) && M23.Equals(other.M23) && M30.Equals(other.M30) && M31.Equals(other.M31) && M32.Equals(other.M32) && M33.Equals(other.M33); } public override readonly bool Equals(object other) => (other is M44d o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM + R0.ToString(format, fp, beginR, betweenR, endR) + betweenM + R1.ToString(format, fp, beginR, betweenR, endR) + betweenM + R2.ToString(format, fp, beginR, betweenR, endR) + betweenM + R3.ToString(format, fp, beginR, betweenR, endR) + endM; } public static M44d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return M44d.FromRows( V4d.Parse(x[0]), V4d.Parse(x[1]), V4d.Parse(x[2]), V4d.Parse(x[3]) ); } #endregion #region Matrix Operations /// /// Returns adjoint of this matrix. /// public readonly M44d Adjoint { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { M44d result = new M44d(); for (int row = 0; row < 4; row++) { for (int col = 0; col < 4; col++) { if (((col + row) % 2) == 0) result[col, row] = this.Minor(row, col).Determinant; else result[col, row] = -this.Minor(row, col).Determinant; } } return result; } } /// /// Returns the trace of this matrix. /// The trace is defined as the sum of the diagonal elements, /// and is only defined for square matrices. /// public readonly double Trace { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return M00 + M11 + M22 + M33 ; } } /// /// Gets the determinant of this matrix. /// The determinant is only defined for square matrices. /// public readonly double Determinant { get { // using bottom row because elements M30, M31, and M32 // are zero most of the time. double d = 0; if (M30 != 0.0f) d -= M30 * ( M01 * M12 * M23 + M02 * M13 * M21 + M03 * M11 * M22 - M21 * M12 * M03 - M22 * M13 * M01 - M23 * M11 * M02 ); if (M31 != 0.0f) d += M31 * ( M00 * M12 * M23 + M02 * M13 * M20 + M03 * M10 * M22 - M20 * M12 * M03 - M22 * M13 * M00 - M23 * M10 * M02 ); if (M32 != 0.0f) d -= M32 * ( M00 * M11 * M23 + M01 * M13 * M20 + M03 * M10 * M21 - M20 * M11 * M03 - M21 * M13 * M00 - M23 * M10 * M01 ); if (M33 != 0.0f) d += M33 * ( M00 * M11 * M22 + M01 * M12 * M20 + M02 * M10 * M21 - M20 * M11 * M02 - M21 * M12 * M00 - M22 * M10 * M01 ); return d; } } /// /// Returns whether this matrix is invertible. /// A matrix is invertible if its determinant is not zero. /// public readonly bool Invertible { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant != 0; } } /// /// Returns whether this matrix is singular. /// A matrix is singular if its determinant is zero. /// public readonly bool Singular { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant == 0; } } /// /// Gets transpose of this matrix. /// public readonly M44d Transposed { get { return new M44d { M00 = M00, M01 = M10, M02 = M20, M03 = M30, M10 = M01, M11 = M11, M12 = M21, M13 = M31, M20 = M02, M21 = M12, M22 = M22, M23 = M32, M30 = M03, M31 = M13, M32 = M23, M33 = M33 }; } } private static V2l s_luSize = new V2l(4, 4); private static V2l s_luDelta = new V2l(1, 4); /// /// Inverts the given matrix using lu factorization in place. Returns true /// if the matrix was invertible, otherwise the matrix remains unchanged. /// public unsafe bool LuInvert() { fixed (M44d* self = &this) { var lu = this; V4i perm; if (NumericExtensions.LuFactorize((double*)&lu, 0, 1, 4, (int*)&perm, 4)) { NumericExtensions.LuInverse((double*)&lu, 0, 1, 4, (int*)&perm, (double*)self, 0, 1, 4, 4); return true; } return false; } } /// /// Returns the inverse of the matrix using lu factorization. /// If the matrix is not invertible, M44d.Zero is returned. /// public unsafe readonly M44d LuInverse() { var lu = this; M44d res; V4i perm; if (NumericExtensions.LuFactorize((double*)&lu, 0, 1, 4, (int*)&perm, 4)) { NumericExtensions.LuInverse((double*)&lu, 0, 1, 4, (int*)&perm, (double*)&res, 0, 1, 4, 4); return res; } return M44d.Zero; } /// /// Returns the inverse of this matrix. If the matrix is not invertible /// M44d.Zero is returned. /// public readonly M44d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => LuInverse(); } #endregion #region Matrix Multiplication public static M44d operator *(M44d a, M44d b) { return new M44d( a.M00 * b.M00 + a.M01 * b.M10 + a.M02 * b.M20 + a.M03 * b.M30, a.M00 * b.M01 + a.M01 * b.M11 + a.M02 * b.M21 + a.M03 * b.M31, a.M00 * b.M02 + a.M01 * b.M12 + a.M02 * b.M22 + a.M03 * b.M32, a.M00 * b.M03 + a.M01 * b.M13 + a.M02 * b.M23 + a.M03 * b.M33, a.M10 * b.M00 + a.M11 * b.M10 + a.M12 * b.M20 + a.M13 * b.M30, a.M10 * b.M01 + a.M11 * b.M11 + a.M12 * b.M21 + a.M13 * b.M31, a.M10 * b.M02 + a.M11 * b.M12 + a.M12 * b.M22 + a.M13 * b.M32, a.M10 * b.M03 + a.M11 * b.M13 + a.M12 * b.M23 + a.M13 * b.M33, a.M20 * b.M00 + a.M21 * b.M10 + a.M22 * b.M20 + a.M23 * b.M30, a.M20 * b.M01 + a.M21 * b.M11 + a.M22 * b.M21 + a.M23 * b.M31, a.M20 * b.M02 + a.M21 * b.M12 + a.M22 * b.M22 + a.M23 * b.M32, a.M20 * b.M03 + a.M21 * b.M13 + a.M22 * b.M23 + a.M23 * b.M33, a.M30 * b.M00 + a.M31 * b.M10 + a.M32 * b.M20 + a.M33 * b.M30, a.M30 * b.M01 + a.M31 * b.M11 + a.M32 * b.M21 + a.M33 * b.M31, a.M30 * b.M02 + a.M31 * b.M12 + a.M32 * b.M22 + a.M33 * b.M32, a.M30 * b.M03 + a.M31 * b.M13 + a.M32 * b.M23 + a.M33 * b.M33 ); } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return this[(int)y, (int)x]; } set { this[(int)y, (int)x] = value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (double)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (double)value; } #endregion } public class M44dEqualityComparer : IEqualityComparer { public static readonly M44dEqualityComparer Default = new M44dEqualityComparer(); #region IEqualityComparer Members public bool Equals(M44d v0, M44d v1) { return v0 == v1; } public int GetHashCode(M44d v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this M44d m) => (m.C0.Length + m.C1.Length + m.C2.Length + m.C3.Length) / 4; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d GetScaleVector(this M44d m) => new V4d(m.C0.Length, m.C1.Length, m.C2.Length, m.C3.Length); /// /// Approximates the uniform scale value of the given transformation matrix (average length of 3D basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale3(this M44d m) => (m.C0.XYZ.Length + m.C1.XYZ.Length + m.C2.XYZ.Length) / 3; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the 3D basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetScaleVector3(this M44d m) => new V3d(m.C0.XYZ.Length, m.C1.XYZ.Length, m.C2.XYZ.Length); /// /// Extracts the forward vector from the given view transformation matrix. /// NOTE: A left-handed coordinates system transformation is expected, /// where the view-space z-axis points in forward direction. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetViewDirectionLH(this M44d m) => m.R2.XYZ.Normalized; /// /// Extracts the forward vector from the given view transformation matrix. /// NOTE: A right-handed coordinates system transformation is expected, where /// the view-space z-axis points opposit the forward vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetViewDirectionRH(this M44d m) => -m.R2.XYZ.Normalized; /// /// Extracts the translation component of the given transformation matrix, which when given /// a model transformation represents the model origin in world position. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetModelOrigin(this M44d m) => m.C3.XYZ; /// /// Builds a hull from the given view-projection transformation matrix (left, right, bottom, top, near, far). /// The view volume is assumed to be [-1, -1, -1] [1, 1, 1]. /// The normals of the hull planes point to the outside and are normalized. /// A point inside the visual hull will has negative height to all planes. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Hull3d GetVisualHull(this M44d viewProj) { var r0 = viewProj.R0; var r1 = viewProj.R1; var r2 = viewProj.R2; var r3 = viewProj.R3; return new Hull3d(new[] { new Plane3d((-(r3 + r0))).Normalized, // left new Plane3d((-(r3 - r0))).Normalized, // right new Plane3d((-(r3 + r1))).Normalized, // bottom new Plane3d((-(r3 - r1))).Normalized, // top new Plane3d((-(r3 + r2))).Normalized, // near new Plane3d((-(r3 - r2))).Normalized, // far }); } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm1(M44d m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(M44d m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormMax(M44d m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormMin(M44d m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this M44d m, double p) { return ( Fun.Abs(m.M00).Pow(p) + Fun.Abs(m.M01).Pow(p) + Fun.Abs(m.M02).Pow(p) + Fun.Abs(m.M03).Pow(p) + Fun.Abs(m.M10).Pow(p) + Fun.Abs(m.M11).Pow(p) + Fun.Abs(m.M12).Pow(p) + Fun.Abs(m.M13).Pow(p) + Fun.Abs(m.M20).Pow(p) + Fun.Abs(m.M21).Pow(p) + Fun.Abs(m.M22).Pow(p) + Fun.Abs(m.M23).Pow(p) + Fun.Abs(m.M30).Pow(p) + Fun.Abs(m.M31).Pow(p) + Fun.Abs(m.M32).Pow(p) + Fun.Abs(m.M33).Pow(p) ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static double Distance1(this M44d a, M44d b) { return Fun.Abs(b.M00 - a.M00) + Fun.Abs(b.M01 - a.M01) + Fun.Abs(b.M02 - a.M02) + Fun.Abs(b.M03 - a.M03) + Fun.Abs(b.M10 - a.M10) + Fun.Abs(b.M11 - a.M11) + Fun.Abs(b.M12 - a.M12) + Fun.Abs(b.M13 - a.M13) + Fun.Abs(b.M20 - a.M20) + Fun.Abs(b.M21 - a.M21) + Fun.Abs(b.M22 - a.M22) + Fun.Abs(b.M23 - a.M23) + Fun.Abs(b.M30 - a.M30) + Fun.Abs(b.M31 - a.M31) + Fun.Abs(b.M32 - a.M32) + Fun.Abs(b.M33 - a.M33); } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static double Distance2(this M44d a, M44d b) { return Fun.Sqrt( Fun.Square(b.M00 - a.M00) + Fun.Square(b.M01 - a.M01) + Fun.Square(b.M02 - a.M02) + Fun.Square(b.M03 - a.M03) + Fun.Square(b.M10 - a.M10) + Fun.Square(b.M11 - a.M11) + Fun.Square(b.M12 - a.M12) + Fun.Square(b.M13 - a.M13) + Fun.Square(b.M20 - a.M20) + Fun.Square(b.M21 - a.M21) + Fun.Square(b.M22 - a.M22) + Fun.Square(b.M23 - a.M23) + Fun.Square(b.M30 - a.M30) + Fun.Square(b.M31 - a.M31) + Fun.Square(b.M32 - a.M32) + Fun.Square(b.M33 - a.M33)); } /// /// Returns the p-distance between two matrices. /// public static double Distance(this M44d a, M44d b, double p) { return ( Fun.Abs(b.M00 - a.M00).Pow(p) + Fun.Abs(b.M01 - a.M01).Pow(p) + Fun.Abs(b.M02 - a.M02).Pow(p) + Fun.Abs(b.M03 - a.M03).Pow(p) + Fun.Abs(b.M10 - a.M10).Pow(p) + Fun.Abs(b.M11 - a.M11).Pow(p) + Fun.Abs(b.M12 - a.M12).Pow(p) + Fun.Abs(b.M13 - a.M13).Pow(p) + Fun.Abs(b.M20 - a.M20).Pow(p) + Fun.Abs(b.M21 - a.M21).Pow(p) + Fun.Abs(b.M22 - a.M22).Pow(p) + Fun.Abs(b.M23 - a.M23).Pow(p) + Fun.Abs(b.M30 - a.M30).Pow(p) + Fun.Abs(b.M31 - a.M31).Pow(p) + Fun.Abs(b.M32 - a.M32).Pow(p) + Fun.Abs(b.M33 - a.M33).Pow(p) ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static double DistanceMax(this M44d a, M44d b) { return Fun.Max( Fun.Max( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02), Fun.Abs(b.M03 - a.M03)), Fun.Max( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12), Fun.Abs(b.M13 - a.M13)), Fun.Max( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22), Fun.Abs(b.M23 - a.M23)), Fun.Max( Fun.Abs(b.M30 - a.M30), Fun.Abs(b.M31 - a.M31), Fun.Abs(b.M32 - a.M32), Fun.Abs(b.M33 - a.M33))); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static double DistanceMin(this M44d a, M44d b) { return Fun.Min( Fun.Min( Fun.Abs(b.M00 - a.M00), Fun.Abs(b.M01 - a.M01), Fun.Abs(b.M02 - a.M02), Fun.Abs(b.M03 - a.M03)), Fun.Min( Fun.Abs(b.M10 - a.M10), Fun.Abs(b.M11 - a.M11), Fun.Abs(b.M12 - a.M12), Fun.Abs(b.M13 - a.M13)), Fun.Min( Fun.Abs(b.M20 - a.M20), Fun.Abs(b.M21 - a.M21), Fun.Abs(b.M22 - a.M22), Fun.Abs(b.M23 - a.M23)), Fun.Min( Fun.Abs(b.M30 - a.M30), Fun.Abs(b.M31 - a.M31), Fun.Abs(b.M32 - a.M32), Fun.Abs(b.M33 - a.M33))); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Transform(this M44d m, V4d v) => m * v; /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d TransposedTransform(this M44d m, V4d v) => v * m; /// /// Transforms direction vector v (v.W is presumed 0.0) by matrix m. /// public static V3d TransformDir(this M44d m, V3d v) { return new V3d( m.M00 * v.X + m.M01 * v.Y + m.M02 * v.Z, m.M10 * v.X + m.M11 * v.Y + m.M12 * v.Z, m.M20 * v.X + m.M21 * v.Y + m.M22 * v.Z ); } /// /// Transforms point p (v.W is presumed 1.0) by matrix m. /// No projective transform is performed. /// public static V3d TransformPos(this M44d m, V3d p) { return new V3d( m.M00 * p.X + m.M01 * p.Y + m.M02 * p.Z + m.M03, m.M10 * p.X + m.M11 * p.Y + m.M12 * p.Z + m.M13, m.M20 * p.X + m.M21 * p.Y + m.M22 * p.Z + m.M23 ); } /// /// Transforms point p (p.W is presumed 1.0) by matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static V3d TransformPosProj(this M44d m, V3d p) { double s = m.M30 * p.X + m.M31 * p.Y + m.M32 * p.Z + m.M33; return TransformPos(m, p) * (1 / s); } /// /// Transforms point p (p.W is presumed 1.0) by matrix m. /// Projective transform is performed. /// public static V4d TransformPosProjFull(this M44d m, V3d p) { return new V4d( m.M00 * p.X + m.M01 * p.Y + m.M02 * p.Z + m.M03, m.M10 * p.X + m.M11 * p.Y + m.M12 * p.Z + m.M13, m.M20 * p.X + m.M21 * p.Y + m.M22 * p.Z + m.M23, m.M30 * p.X + m.M31 * p.Y + m.M32 * p.Z + m.M33 ); } /// /// Transforms direction vector v (v.W is presumed 0.0) by transposed version of matrix m. /// public static V3d TransposedTransformDir(this M44d m, V3d v) { return new V3d( m.M00 * v.X + m.M10 * v.Y + m.M20 * v.Z, m.M01 * v.X + m.M11 * v.Y + m.M21 * v.Z, m.M02 * v.X + m.M12 * v.Y + m.M22 * v.Z ); } /// /// Transforms point p (v.W is presumed 1.0) by transposed version of matrix m. /// No projective transform is performed. /// public static V3d TransposedTransformPos(this M44d m, V3d p) { return new V3d( m.M00 * p.X + m.M10 * p.Y + m.M20 * p.Z + m.M30, m.M01 * p.X + m.M11 * p.Y + m.M21 * p.Z + m.M31, m.M02 * p.X + m.M12 * p.Y + m.M22 * p.Z + m.M32 ); } /// /// Transforms point p (v.W is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static V3d TransposedTransformPosProj(this M44d m, V3d p) { var s = m.M03 * p.X + m.M13 * p.Y + m.M23 * p.Z + m.M33; return TransposedTransformPos(m, p) * (1 / s); } [Obsolete("Use TransposedTransformPosProj instead.")] public static V3d TransposedTransformProj(this M44d m, V3d p) => m.TransposedTransformPosProj(p); /// /// Transforms point p (v.W is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. /// public static V4d TransposedTransformPosProjFull(this M44d m, V3d p) { return new V4d( m.M00 * p.X + m.M10 * p.Y + m.M20 * p.Z + m.M30, m.M01 * p.X + m.M11 * p.Y + m.M21 * p.Z + m.M31, m.M02 * p.X + m.M12 * p.Y + m.M22 * p.Z + m.M32, m.M03 * p.X + m.M13 * p.Y + m.M23 * p.Z + m.M33 ); } [Obsolete("Use TransposedTransformPosProjFull instead.")] public static V4d TransposedTransformProjFull(this M44d m, V3d p) => m.TransposedTransformPosProjFull(p); #endregion #region Operations /// /// Returns the given to a deleting the /// specified row and column. /// public static M33d Minor(this M44d m, int row, int column) { M33d rs = new M33d(); for (int k = 0; k < 9; k++) { var i = k / 3; var j = k % 3; var ii = (i < row) ? i : i + 1; var jj = (j < column) ? j : j + 1; rs[k] = m[ii * 4 + jj]; } return rs; } /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V4d Row(this M44d m, int index) { double* ptr = &m.M00; return new V4d(ptr[index * 4], ptr[index * 4 + 1], ptr[index * 4 + 2], ptr[index * 4 + 3]); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static V4d Column(this M44d m, int index) { double* ptr = &m.M00; return new V4d(ptr[index], ptr[index + 4], ptr[index + 8], ptr[index + 12]); } /// /// Returns the determinant of the given matrix. /// The determinant is only defined for square matrices. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Determinant(M44d m) => m.Determinant; /// /// Returns the transpose of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Transposed(M44d m) => m.Transposed; /// /// Transposes the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transpose(this ref M44d m) { Fun.Swap(ref m.M10, ref m.M01); Fun.Swap(ref m.M20, ref m.M02); Fun.Swap(ref m.M21, ref m.M12); Fun.Swap(ref m.M30, ref m.M03); Fun.Swap(ref m.M31, ref m.M13); Fun.Swap(ref m.M32, ref m.M23); } /// /// Returns the inverse of the given matrix. If the matrix is not invertible /// M44d.Zero is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Inverse(M44d m) => m.Inverse; /// /// Inverts the given matrix in place. Returns true if the matrix was invertible, /// otherwise the matrix remains unchanged. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Invert(this ref M44d m) { return m.LuInvert(); } /// /// Returns if the given matrix is the identity matrix I. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIdentity(this M44d m, double epsilon) { return Fun.ApproximateEquals(m, M44d.Identity, epsilon); } /// /// Returns if the given matrix is the identity matrix I. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIdentity(this M44d m) => IsIdentity(m, Constant.PositiveTinyValue); /// /// Returns if the given matrix is orthonormal (i.e. M * M^t == I) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthonormal(this M44d m, double epsilon) { var i = m * m.Transposed; return i.IsIdentity(epsilon); } /// /// Returns if the given matrix is orthonormal (i.e. M * M^t == I) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthonormal(this M44d m) => IsOrthonormal(m, Constant.PositiveTinyValue); /// /// Returns if the given matrix is orthogonal (i.e. all non-diagonal entries of M * M^t == 0) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonal(this M44d m, double epsilon) { var i = m * m.Transposed; for (int j = 0; j < 4; j++) i[j, j] = 1; //inefficient implementation: just leave out the comparisons at the diagonal entries. return i.IsIdentity(epsilon); } /// /// Returns if the given matrix is orthogonal (i.e. all non-diagonal entries of M * M^t == 0) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonal(this M44d m) => IsOrthogonal(m, Constant.PositiveTinyValue); #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M44d a, M44d b) { return a.M00 < b.M00 && a.M01 < b.M01 && a.M02 < b.M02 && a.M03 < b.M03 && a.M10 < b.M10 && a.M11 < b.M11 && a.M12 < b.M12 && a.M13 < b.M13 && a.M20 < b.M20 && a.M21 < b.M21 && a.M22 < b.M22 && a.M23 < b.M23 && a.M30 < b.M30 && a.M31 < b.M31 && a.M32 < b.M32 && a.M33 < b.M33; } /// /// Returns whether ALL elements of m are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this M44d m, double s) { return m.M00 < s && m.M01 < s && m.M02 < s && m.M03 < s && m.M10 < s && m.M11 < s && m.M12 < s && m.M13 < s && m.M20 < s && m.M21 < s && m.M22 < s && m.M23 < s && m.M30 < s && m.M31 < s && m.M32 < s && m.M33 < s; } /// /// Returns whether a is Smaller ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(double s, M44d m) { return s < m.M00 && s < m.M01 && s < m.M02 && s < m.M03 && s < m.M10 && s < m.M11 && s < m.M12 && s < m.M13 && s < m.M20 && s < m.M21 && s < m.M22 && s < m.M23 && s < m.M30 && s < m.M31 && s < m.M32 && s < m.M33; } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M44d a, M44d b) { return a.M00 < b.M00 || a.M01 < b.M01 || a.M02 < b.M02 || a.M03 < b.M03 || a.M10 < b.M10 || a.M11 < b.M11 || a.M12 < b.M12 || a.M13 < b.M13 || a.M20 < b.M20 || a.M21 < b.M21 || a.M22 < b.M22 || a.M23 < b.M23 || a.M30 < b.M30 || a.M31 < b.M31 || a.M32 < b.M32 || a.M33 < b.M33; } /// /// Returns whether AT LEAST ONE element of m is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this M44d m, double s) { return m.M00 < s || m.M01 < s || m.M02 < s || m.M03 < s || m.M10 < s || m.M11 < s || m.M12 < s || m.M13 < s || m.M20 < s || m.M21 < s || m.M22 < s || m.M23 < s || m.M30 < s || m.M31 < s || m.M32 < s || m.M33 < s; } /// /// Returns whether a is Smaller AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(double s, M44d m) { return s < m.M00 || s < m.M01 || s < m.M02 || s < m.M03 || s < m.M10 || s < m.M11 || s < m.M12 || s < m.M13 || s < m.M20 || s < m.M21 || s < m.M22 || s < m.M23 || s < m.M30 || s < m.M31 || s < m.M32 || s < m.M33; } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M44d a, M44d b) { return a.M00 > b.M00 && a.M01 > b.M01 && a.M02 > b.M02 && a.M03 > b.M03 && a.M10 > b.M10 && a.M11 > b.M11 && a.M12 > b.M12 && a.M13 > b.M13 && a.M20 > b.M20 && a.M21 > b.M21 && a.M22 > b.M22 && a.M23 > b.M23 && a.M30 > b.M30 && a.M31 > b.M31 && a.M32 > b.M32 && a.M33 > b.M33; } /// /// Returns whether ALL elements of m are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this M44d m, double s) { return m.M00 > s && m.M01 > s && m.M02 > s && m.M03 > s && m.M10 > s && m.M11 > s && m.M12 > s && m.M13 > s && m.M20 > s && m.M21 > s && m.M22 > s && m.M23 > s && m.M30 > s && m.M31 > s && m.M32 > s && m.M33 > s; } /// /// Returns whether a is Greater ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(double s, M44d m) { return s > m.M00 && s > m.M01 && s > m.M02 && s > m.M03 && s > m.M10 && s > m.M11 && s > m.M12 && s > m.M13 && s > m.M20 && s > m.M21 && s > m.M22 && s > m.M23 && s > m.M30 && s > m.M31 && s > m.M32 && s > m.M33; } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M44d a, M44d b) { return a.M00 > b.M00 || a.M01 > b.M01 || a.M02 > b.M02 || a.M03 > b.M03 || a.M10 > b.M10 || a.M11 > b.M11 || a.M12 > b.M12 || a.M13 > b.M13 || a.M20 > b.M20 || a.M21 > b.M21 || a.M22 > b.M22 || a.M23 > b.M23 || a.M30 > b.M30 || a.M31 > b.M31 || a.M32 > b.M32 || a.M33 > b.M33; } /// /// Returns whether AT LEAST ONE element of m is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this M44d m, double s) { return m.M00 > s || m.M01 > s || m.M02 > s || m.M03 > s || m.M10 > s || m.M11 > s || m.M12 > s || m.M13 > s || m.M20 > s || m.M21 > s || m.M22 > s || m.M23 > s || m.M30 > s || m.M31 > s || m.M32 > s || m.M33 > s; } /// /// Returns whether a is Greater AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(double s, M44d m) { return s > m.M00 || s > m.M01 || s > m.M02 || s > m.M03 || s > m.M10 || s > m.M11 || s > m.M12 || s > m.M13 || s > m.M20 || s > m.M21 || s > m.M22 || s > m.M23 || s > m.M30 || s > m.M31 || s > m.M32 || s > m.M33; } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M44d a, M44d b) { return a.M00 <= b.M00 && a.M01 <= b.M01 && a.M02 <= b.M02 && a.M03 <= b.M03 && a.M10 <= b.M10 && a.M11 <= b.M11 && a.M12 <= b.M12 && a.M13 <= b.M13 && a.M20 <= b.M20 && a.M21 <= b.M21 && a.M22 <= b.M22 && a.M23 <= b.M23 && a.M30 <= b.M30 && a.M31 <= b.M31 && a.M32 <= b.M32 && a.M33 <= b.M33; } /// /// Returns whether ALL elements of m are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this M44d m, double s) { return m.M00 <= s && m.M01 <= s && m.M02 <= s && m.M03 <= s && m.M10 <= s && m.M11 <= s && m.M12 <= s && m.M13 <= s && m.M20 <= s && m.M21 <= s && m.M22 <= s && m.M23 <= s && m.M30 <= s && m.M31 <= s && m.M32 <= s && m.M33 <= s; } /// /// Returns whether a is SmallerOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(double s, M44d m) { return s <= m.M00 && s <= m.M01 && s <= m.M02 && s <= m.M03 && s <= m.M10 && s <= m.M11 && s <= m.M12 && s <= m.M13 && s <= m.M20 && s <= m.M21 && s <= m.M22 && s <= m.M23 && s <= m.M30 && s <= m.M31 && s <= m.M32 && s <= m.M33; } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M44d a, M44d b) { return a.M00 <= b.M00 || a.M01 <= b.M01 || a.M02 <= b.M02 || a.M03 <= b.M03 || a.M10 <= b.M10 || a.M11 <= b.M11 || a.M12 <= b.M12 || a.M13 <= b.M13 || a.M20 <= b.M20 || a.M21 <= b.M21 || a.M22 <= b.M22 || a.M23 <= b.M23 || a.M30 <= b.M30 || a.M31 <= b.M31 || a.M32 <= b.M32 || a.M33 <= b.M33; } /// /// Returns whether AT LEAST ONE element of m is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this M44d m, double s) { return m.M00 <= s || m.M01 <= s || m.M02 <= s || m.M03 <= s || m.M10 <= s || m.M11 <= s || m.M12 <= s || m.M13 <= s || m.M20 <= s || m.M21 <= s || m.M22 <= s || m.M23 <= s || m.M30 <= s || m.M31 <= s || m.M32 <= s || m.M33 <= s; } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(double s, M44d m) { return s <= m.M00 || s <= m.M01 || s <= m.M02 || s <= m.M03 || s <= m.M10 || s <= m.M11 || s <= m.M12 || s <= m.M13 || s <= m.M20 || s <= m.M21 || s <= m.M22 || s <= m.M23 || s <= m.M30 || s <= m.M31 || s <= m.M32 || s <= m.M33; } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M44d a, M44d b) { return a.M00 >= b.M00 && a.M01 >= b.M01 && a.M02 >= b.M02 && a.M03 >= b.M03 && a.M10 >= b.M10 && a.M11 >= b.M11 && a.M12 >= b.M12 && a.M13 >= b.M13 && a.M20 >= b.M20 && a.M21 >= b.M21 && a.M22 >= b.M22 && a.M23 >= b.M23 && a.M30 >= b.M30 && a.M31 >= b.M31 && a.M32 >= b.M32 && a.M33 >= b.M33; } /// /// Returns whether ALL elements of m are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this M44d m, double s) { return m.M00 >= s && m.M01 >= s && m.M02 >= s && m.M03 >= s && m.M10 >= s && m.M11 >= s && m.M12 >= s && m.M13 >= s && m.M20 >= s && m.M21 >= s && m.M22 >= s && m.M23 >= s && m.M30 >= s && m.M31 >= s && m.M32 >= s && m.M33 >= s; } /// /// Returns whether a is GreaterOrEqual ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(double s, M44d m) { return s >= m.M00 && s >= m.M01 && s >= m.M02 && s >= m.M03 && s >= m.M10 && s >= m.M11 && s >= m.M12 && s >= m.M13 && s >= m.M20 && s >= m.M21 && s >= m.M22 && s >= m.M23 && s >= m.M30 && s >= m.M31 && s >= m.M32 && s >= m.M33; } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M44d a, M44d b) { return a.M00 >= b.M00 || a.M01 >= b.M01 || a.M02 >= b.M02 || a.M03 >= b.M03 || a.M10 >= b.M10 || a.M11 >= b.M11 || a.M12 >= b.M12 || a.M13 >= b.M13 || a.M20 >= b.M20 || a.M21 >= b.M21 || a.M22 >= b.M22 || a.M23 >= b.M23 || a.M30 >= b.M30 || a.M31 >= b.M31 || a.M32 >= b.M32 || a.M33 >= b.M33; } /// /// Returns whether AT LEAST ONE element of m is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this M44d m, double s) { return m.M00 >= s || m.M01 >= s || m.M02 >= s || m.M03 >= s || m.M10 >= s || m.M11 >= s || m.M12 >= s || m.M13 >= s || m.M20 >= s || m.M21 >= s || m.M22 >= s || m.M23 >= s || m.M30 >= s || m.M31 >= s || m.M32 >= s || m.M33 >= s; } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(double s, M44d m) { return s >= m.M00 || s >= m.M01 || s >= m.M02 || s >= m.M03 || s >= m.M10 || s >= m.M11 || s >= m.M12 || s >= m.M13 || s >= m.M20 || s >= m.M21 || s >= m.M22 || s >= m.M23 || s >= m.M30 || s >= m.M31 || s >= m.M32 || s >= m.M33; } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M44d a, M44d b) { return a.M00 == b.M00 && a.M01 == b.M01 && a.M02 == b.M02 && a.M03 == b.M03 && a.M10 == b.M10 && a.M11 == b.M11 && a.M12 == b.M12 && a.M13 == b.M13 && a.M20 == b.M20 && a.M21 == b.M21 && a.M22 == b.M22 && a.M23 == b.M23 && a.M30 == b.M30 && a.M31 == b.M31 && a.M32 == b.M32 && a.M33 == b.M33; } /// /// Returns whether ALL elements of m are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this M44d m, double s) { return m.M00 == s && m.M01 == s && m.M02 == s && m.M03 == s && m.M10 == s && m.M11 == s && m.M12 == s && m.M13 == s && m.M20 == s && m.M21 == s && m.M22 == s && m.M23 == s && m.M30 == s && m.M31 == s && m.M32 == s && m.M33 == s; } /// /// Returns whether a is Equal ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(double s, M44d m) { return s == m.M00 && s == m.M01 && s == m.M02 && s == m.M03 && s == m.M10 && s == m.M11 && s == m.M12 && s == m.M13 && s == m.M20 && s == m.M21 && s == m.M22 && s == m.M23 && s == m.M30 && s == m.M31 && s == m.M32 && s == m.M33; } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M44d a, M44d b) { return a.M00 == b.M00 || a.M01 == b.M01 || a.M02 == b.M02 || a.M03 == b.M03 || a.M10 == b.M10 || a.M11 == b.M11 || a.M12 == b.M12 || a.M13 == b.M13 || a.M20 == b.M20 || a.M21 == b.M21 || a.M22 == b.M22 || a.M23 == b.M23 || a.M30 == b.M30 || a.M31 == b.M31 || a.M32 == b.M32 || a.M33 == b.M33; } /// /// Returns whether AT LEAST ONE element of m is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this M44d m, double s) { return m.M00 == s || m.M01 == s || m.M02 == s || m.M03 == s || m.M10 == s || m.M11 == s || m.M12 == s || m.M13 == s || m.M20 == s || m.M21 == s || m.M22 == s || m.M23 == s || m.M30 == s || m.M31 == s || m.M32 == s || m.M33 == s; } /// /// Returns whether a is Equal AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(double s, M44d m) { return s == m.M00 || s == m.M01 || s == m.M02 || s == m.M03 || s == m.M10 || s == m.M11 || s == m.M12 || s == m.M13 || s == m.M20 || s == m.M21 || s == m.M22 || s == m.M23 || s == m.M30 || s == m.M31 || s == m.M32 || s == m.M33; } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M44d a, M44d b) { return a.M00 != b.M00 && a.M01 != b.M01 && a.M02 != b.M02 && a.M03 != b.M03 && a.M10 != b.M10 && a.M11 != b.M11 && a.M12 != b.M12 && a.M13 != b.M13 && a.M20 != b.M20 && a.M21 != b.M21 && a.M22 != b.M22 && a.M23 != b.M23 && a.M30 != b.M30 && a.M31 != b.M31 && a.M32 != b.M32 && a.M33 != b.M33; } /// /// Returns whether ALL elements of m are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this M44d m, double s) { return m.M00 != s && m.M01 != s && m.M02 != s && m.M03 != s && m.M10 != s && m.M11 != s && m.M12 != s && m.M13 != s && m.M20 != s && m.M21 != s && m.M22 != s && m.M23 != s && m.M30 != s && m.M31 != s && m.M32 != s && m.M33 != s; } /// /// Returns whether a is Different ALL elements of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(double s, M44d m) { return s != m.M00 && s != m.M01 && s != m.M02 && s != m.M03 && s != m.M10 && s != m.M11 && s != m.M12 && s != m.M13 && s != m.M20 && s != m.M21 && s != m.M22 && s != m.M23 && s != m.M30 && s != m.M31 && s != m.M32 && s != m.M33; } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M44d a, M44d b) { return a.M00 != b.M00 || a.M01 != b.M01 || a.M02 != b.M02 || a.M03 != b.M03 || a.M10 != b.M10 || a.M11 != b.M11 || a.M12 != b.M12 || a.M13 != b.M13 || a.M20 != b.M20 || a.M21 != b.M21 || a.M22 != b.M22 || a.M23 != b.M23 || a.M30 != b.M30 || a.M31 != b.M31 || a.M32 != b.M32 || a.M33 != b.M33; } /// /// Returns whether AT LEAST ONE element of m is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this M44d m, double s) { return m.M00 != s || m.M01 != s || m.M02 != s || m.M03 != s || m.M10 != s || m.M11 != s || m.M12 != s || m.M13 != s || m.M20 != s || m.M21 != s || m.M22 != s || m.M23 != s || m.M30 != s || m.M31 != s || m.M32 != s || m.M33 != s; } /// /// Returns whether a is Different AT LEAST ONE element of m. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(double s, M44d m) { return s != m.M00 || s != m.M01 || s != m.M02 || s != m.M03 || s != m.M10 || s != m.M11 || s != m.M12 || s != m.M13 || s != m.M20 || s != m.M21 || s != m.M22 || s != m.M23 || s != m.M30 || s != m.M31 || s != m.M32 || s != m.M33; } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this M44d m0, M44d m1) { if (m0.M00 < m1.M00) return -1; if (m0.M00 > m1.M00) return +1; if (m0.M01 < m1.M01) return -1; if (m0.M01 > m1.M01) return +1; if (m0.M02 < m1.M02) return -1; if (m0.M02 > m1.M02) return +1; if (m0.M03 < m1.M03) return -1; if (m0.M03 > m1.M03) return +1; if (m0.M10 < m1.M10) return -1; if (m0.M10 > m1.M10) return +1; if (m0.M11 < m1.M11) return -1; if (m0.M11 > m1.M11) return +1; if (m0.M12 < m1.M12) return -1; if (m0.M12 > m1.M12) return +1; if (m0.M13 < m1.M13) return -1; if (m0.M13 > m1.M13) return +1; if (m0.M20 < m1.M20) return -1; if (m0.M20 > m1.M20) return +1; if (m0.M21 < m1.M21) return -1; if (m0.M21 > m1.M21) return +1; if (m0.M22 < m1.M22) return -1; if (m0.M22 > m1.M22) return +1; if (m0.M23 < m1.M23) return -1; if (m0.M23 > m1.M23) return +1; if (m0.M30 < m1.M30) return -1; if (m0.M30 > m1.M30) return +1; if (m0.M31 < m1.M31) return -1; if (m0.M31 > m1.M31) return +1; if (m0.M32 < m1.M32) return -1; if (m0.M32 > m1.M32) return +1; if (m0.M33 < m1.M33) return -1; if (m0.M33 > m1.M33) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MinElement(M44d m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MaxElement(M44d m) => m.MaxElement; #endregion #region Orthogonalization /// /// Orthogonalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// public static void Orthogonalize(this ref M44d matrix) { matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C0, matrix.C2) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C1, matrix.C2) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C2 -= (Vec.Dot(matrix.C0, matrix.C2) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C1, matrix.C2) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C3 -= (Vec.Dot(matrix.C0, matrix.C3) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C3 -= (Vec.Dot(matrix.C1, matrix.C3) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C3 -= (Vec.Dot(matrix.C2, matrix.C3) / Vec.Dot(matrix.C2, matrix.C2)) * matrix.C2; matrix.C3 -= (Vec.Dot(matrix.C0, matrix.C3) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C3 -= (Vec.Dot(matrix.C1, matrix.C3) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C3 -= (Vec.Dot(matrix.C2, matrix.C3) / Vec.Dot(matrix.C2, matrix.C2)) * matrix.C2; } /// /// Orthogonalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Orthogonalized(this M44d matrix) { M44d m = matrix; Orthogonalize(ref m); return m; } /// /// Orthonormalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// public static void Orthonormalize(this ref M44d matrix) { matrix.C0 = matrix.C0.Normalized; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 -= (Vec.Dot(matrix.C0, matrix.C1) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C1 = matrix.C1.Normalized; matrix.C2 -= (Vec.Dot(matrix.C0, matrix.C2) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C1, matrix.C2) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C2 -= (Vec.Dot(matrix.C0, matrix.C2) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C2 -= (Vec.Dot(matrix.C1, matrix.C2) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C2 = matrix.C2.Normalized; matrix.C3 -= (Vec.Dot(matrix.C0, matrix.C3) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C3 -= (Vec.Dot(matrix.C1, matrix.C3) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C3 -= (Vec.Dot(matrix.C2, matrix.C3) / Vec.Dot(matrix.C2, matrix.C2)) * matrix.C2; matrix.C3 -= (Vec.Dot(matrix.C0, matrix.C3) / Vec.Dot(matrix.C0, matrix.C0)) * matrix.C0; matrix.C3 -= (Vec.Dot(matrix.C1, matrix.C3) / Vec.Dot(matrix.C1, matrix.C1)) * matrix.C1; matrix.C3 -= (Vec.Dot(matrix.C2, matrix.C3) / Vec.Dot(matrix.C2, matrix.C2)) * matrix.C2; matrix.C3 = matrix.C3.Normalized; } /// /// Orthonormalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Orthonormalized(this M44d matrix) { M44d m = matrix; Orthonormalize(ref m); return m; } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this M44d m, double epsilon) => m.M00.IsTiny(epsilon) || m.M01.IsTiny(epsilon) || m.M02.IsTiny(epsilon) || m.M03.IsTiny(epsilon) || m.M10.IsTiny(epsilon) || m.M11.IsTiny(epsilon) || m.M12.IsTiny(epsilon) || m.M13.IsTiny(epsilon) || m.M20.IsTiny(epsilon) || m.M21.IsTiny(epsilon) || m.M22.IsTiny(epsilon) || m.M23.IsTiny(epsilon) || m.M30.IsTiny(epsilon) || m.M31.IsTiny(epsilon) || m.M32.IsTiny(epsilon) || m.M33.IsTiny(epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this M44d m, double epsilon) => m.M00.IsTiny(epsilon) && m.M01.IsTiny(epsilon) && m.M02.IsTiny(epsilon) && m.M03.IsTiny(epsilon) && m.M10.IsTiny(epsilon) && m.M11.IsTiny(epsilon) && m.M12.IsTiny(epsilon) && m.M13.IsTiny(epsilon) && m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon) && m.M22.IsTiny(epsilon) && m.M23.IsTiny(epsilon) && m.M30.IsTiny(epsilon) && m.M31.IsTiny(epsilon) && m.M32.IsTiny(epsilon) && m.M33.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyFinite(M44d m) => m.AnyFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllFinite(M44d m) => m.AllFinite; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(M44d m) => m.AnyNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(M44d m) => m.AllNaN; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(M44d m) => m.AnyInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(M44d m) => m.AllInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(M44d m) => m.AnyPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(M44d m) => m.AllPositiveInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(M44d m) => m.AnyNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(M44d m) => m.AllNegativeInfinity; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(M44d m) => m.AnyTiny; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(M44d m) => m.AllTiny; #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M44d a, M44d b) => ApproximateEquals(a, b, Constant.PositiveTinyValue); /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this M44d a, M44d b, double epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this M44d m, double epsilon) => Mat.AllTiny(m, epsilon); /// /// Returns whether the absolute value of each element of the given is smaller than Constant<double>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(M44d m) => m.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any element of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(M44d v) => v.IsNaN; /// /// Returns whether any element of the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(M44d v) => v.IsInfinity; /// /// Returns whether any element of the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(M44d v) => v.IsPositiveInfinity; /// /// Returns whether any element of the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(M44d v) => v.IsNegativeInfinity; /// /// Returns whether all elements of the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(M44d v) => v.IsFinite; #endregion } public static class IRandomUniformM44dExtensions { #region IRandomUniform extensions for M44d /// /// Uses UniformDouble() to generate the elements of an M44d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d UniformM44d(this IRandomUniform rnd) { return new M44d( rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble()); } /// /// Uses UniformDoubleClosed() to generate the elements of an M44d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d UniformM44dClosed(this IRandomUniform rnd) { return new M44d( rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed()); } /// /// Uses UniformDoubleOpen() to generate the elements of an M44d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d UniformM44dOpen(this IRandomUniform rnd) { return new M44d( rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen()); } /// /// Uses UniformDoubleFull() to generate the elements of an M44d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d UniformM44dFull(this IRandomUniform rnd) { return new M44d( rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull()); } /// /// Uses UniformDoubleFullClosed() to generate the elements of an M44d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d UniformM44dFullClosed(this IRandomUniform rnd) { return new M44d( rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed()); } /// /// Uses UniformDoubleFullOpen() to generate the elements of an M44d matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d UniformM44dFullOpen(this IRandomUniform rnd) { return new M44d( rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen()); } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Matrix_template.cs ================================================ using System; using System.ComponentModel; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Xml.Serialization; using System.Diagnostics; namespace Aardvark.Base { // AUTOGENERATED CODE - DO NOT CHANGE! //# Action comma = () => Out(", "); //# Action add = () => Out(" + "); //# Action xor = () => Out(" ^ "); //# Action andLit = () => Out(" and "); //# Action andand = () => Out(" && "); //# Action oror = () => Out(" || "); //# Action addqcomma = () => Out(" + \",\" "); //# Action addbetweenM = () => Out(" + betweenM "); //# Action el = () => Out("else "); //# Action bracketComma = () => Out("),"); //# var tcharA = new[] { "i", "l", "f", "d" }; //# var ftypeA = new[] { "int", "long", "float", "double" }; //# var fcapsA = new[] { "Int", "Long", "Float", "Double" }; //# var ctypeA = new[] { "double", "double", "float", "double" }; // computation types //# var fields = new[] {"X", "Y", "Z", "W"}; //# var ops = new[] {" + ", " - ", " % ", " / ", " * "}; //# var bwops = new[] { "&", "|", "^" }; //# for (int n = 2; n <= 4; n++) { //# for (int m = n; m <= (n+1) && m < 5; m++) { //# for (int t = 0; t < tcharA.Length; t++) { //# var msub1 = m - 1; //# var msub2 = m - 2; //# var nsub1 = n - 1; //# var tchar = tcharA[t]; //# var nm = n * m; //# var nmtype = "M" + n + m + tchar; // Matrix type //# var nntype = "M" + n + n + tchar; //# var mmtype = "M" + m + m + tchar; //# var vmtype = "V"+ m + tchar; //# var vmsub1type = "V"+ msub1 + tchar; //# var vntype = "V"+ n + tchar; //# var vnitype = "V"+ n + "i"; //# var vnsub1type = "V"+ nsub1 + tchar; //# var scalent = "Scale" + n + tchar; //# var scalemt = "Scale" + m + tchar; //# var scalensub1t = "Scale" + (n - 1) + tchar; //# var scalemsub1t = "Scale" + (m - 1) + tchar; //# var shiftmsub1t = "Shift" + (m - 1) + tchar; //# var rotnt = "Rot" + n + tchar; //# var rotnsub1t = "Rot" + (n - 1) + tchar; //# var nfields = fields.Take(n).ToArray(); //# var mfields = fields.Take(m).ToArray(); //# var isReal = t > 1; //# var ftype = ftypeA[t]; //# var fcaps = fcapsA[t]; //# var ctype = ctypeA[t]; //# var vnctype = "V"+ n + ctype[0]; //# var vnsub1ctype = "V"+ nsub1 + ctype[0]; //# var x2t = 2 + tchar; //# var x3t = 3 + tchar; //# var x4t = 4 + tchar; //# var xyznsub1 = "XYZW".Substring(0, nsub1); //# var xyzmsub1 = "XYZW".Substring(0, msub1); //# var getptr = "&M00"; //# var isDouble = (ftype == "double"); //# var assertEps = isDouble ? "1e-10" : "1e-5f"; #region __nmtype__ [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct __nmtype__ : IEquatable<__nmtype__>, IValidity, IMatrix { //# n.ForEach(j => { [DataMember] public __ftype__ /*# m.ForEach(k => { */M__j____k__/*# }, comma); */; //# }); #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] public __nmtype__(__ftype__ value) { //# n.ForEach(r => { /*# m.ForEach(s => { var v = r == s ? "value" : "0"; */M__r____s__ = __v__; /*# }); */ //# }); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __nmtype__(/*# n.ForEach(r => { */ /*# m.ForEach(s => {*/__ftype__ m__r____s__/*#}, comma);}, comma); */) { //# n.ForEach(r => { /*# m.ForEach(s => { */M__r____s__ = m__r____s__; /*# }); */ //# }); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __nmtype__(__ftype__[] a) { //# int l = 0; //# n.ForEach(r => { m.ForEach(s => { M__r____s__ = a[__l__]; //# l++; }); }); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public __nmtype__(__ftype__[] a, int start) { //# l = 0; //# n.ForEach(r => { m.ForEach(s => { M__r____s__ = a[start + __l__]; //# l++; }); }); } //# if (n == m - 1) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public __nmtype__(__nntype__ m, __vntype__ v) { //# n.ForEach(r => { /*# m.ForEach(s => { var value = (s < n) ? "m.M" + r + s : "v." + nfields[r]; */M__r____s__ = __value__; /*# });*/ //# }); } //# } //# for (int t1 = 0; t1 < tcharA.Length; t1++) { //# for (int a = 2; a <= 4; a++) { //# for (int b = a; b <= (a+1) && b < 5; b++) { //# var MabType1 = "M" + a + b + tcharA[t1]; //# if (n != a || m != b || t1 != t) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public __nmtype__(__MabType1__ m) { //# n.ForEach(r => { /*# m.ForEach(s => { if (r >= a || s >= b) { if (r != s) {*/M__r____s__ = 0; /*#} else if ( r == s) {*/M__r____s__ = 1; /*#}} if((r < a) && ( s < b)) {*/M__r____s__ = /*# if (t != t1) {*/(__ftype__)/*#}*/m.M__r____s__; /*#} }); */ //# }); } //# } //# } //# } //# } #endregion #region Conversions //# for (int t1 = 0; t1 < tcharA.Length; t1++) { //# for (int a = 2; a <= 4; a++) { //# for (int b = a; b <= (a+1) && b < 5; b++) { //# var MabType1 = "M" + a + b + tcharA[t1]; //# if (n != a || m != b || t1 != t) { public static explicit operator __nmtype__(__MabType1__ m) { return new __nmtype__ { //# n.ForEach(r => { /*# m.ForEach(s => { if (r >= a || s >= b) { if (r != s) {*/M__r____s__ = 0, /*#} else if ( r == s) {*/M__r____s__ = 1, /*#}} if((r < a) && ( s < b)) {*/M__r____s__ = /*# if (t != t1) {*/(__ftype__)/*#}*/m.M__r____s__, /*#} }); */ //# }); }; } //# } //# } //# } //# } //# for (int t1 = 0; t1 < tcharA.Length; t1++) { //# var ftype1 = ftypeA[t1]; public static explicit operator __nmtype__(__ftype1__[] a) { return new __nmtype__(/*# { int c = 0; n.ForEach(r => { */ /*# m.ForEach(s => { if (t != t1) { */(__ftype__)/*# } */a[__c__]/*# ++c; }, comma); }, comma); } */); } public static explicit operator __nmtype__(__ftype1__[,] a) { return new __nmtype__(/*# n.ForEach(r => { */ /*# m.ForEach(s => { if (t != t1) { */(__ftype__)/*# } */a[__r__, __s__]/*# }, comma); }, comma); */); } public static explicit operator __ftype1__[](__nmtype__ m) { return new __ftype1__[] {/*# n.ForEach(r => { */ /*# m.ForEach(s => { if (t != t1) { */(__ftype1__)/*# } */m.M__r____s__/*# }, comma); }, comma); */ }; } public static explicit operator __ftype1__[,](__nmtype__ m) { return new __ftype1__[,] {/*# n.ForEach(r => { */ { /*# m.ForEach(s => { if (t != t1) { */(__ftype1__)/*# } */m.M__r____s__/*# }, comma); */ }/*# }, comma); */ }; } public readonly void CopyTo(__ftype1__[] array, long index) { //# n.ForEach(j => { m.ForEach(k => { var jk = j * m + k; array[index + __jk__] = /*# if (t != t1) { */(__ftype1__)/*# } */M__j____k__; //# });}); } //# } //# for (int t1 = 0; t1 < tcharA.Length; t1++) { //# var nmtype1 = "M" + n + m + tcharA[t1]; //# var ftype1 = ftypeA[t1]; /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly __nmtype1__ Copy(Func<__ftype__, __ftype1__> element_fun) { return new __nmtype1__(/*# n.ForEach(r => { */ /*# m.ForEach(s => { */element_fun(M__r____s__)/*# }, comma); }, comma); */); } /// /// Returns a copy with all elements transformed by the supplied function. /// public readonly __nmtype1__ Copy(Func<__ftype__, int, int, __ftype1__> element_index0_index1_fun) { return new __nmtype1__(/*# n.ForEach(r => { */ /*# m.ForEach(s => { */element_index0_index1_fun(M__r____s__, __r__, __s__)/*# }, comma); }, comma); */); } //# } //# if (m == n && m >= 3) { //# var nmtype1x = "M" + (n-1) + (m-1); //# var nmtype1 = nmtype1x + tchar; /// /// Returns a copy of the upper left sub matrix. /// public readonly __nmtype1__ UpperLeft__nmtype1x__() { return (__nmtype1__)this; } //# } public readonly __ftype__[] ToArray() { var array = new __ftype__[__nm__]; //# n.ForEach(j => { m.ForEach(k => { var jk = j * m + k; array[__jk__] = M__j____k__; //# });}); return array; } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ FromCols(/*# m.ForEach(r => {*/__vntype__ col__r__/*#}, comma); */) { return new __nmtype__(/*# n.ForEach(r => { */ /*# m.ForEach(c => { var rf = fields[r]; */col__c__.__rf__/*#}, comma);}, comma); */); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ FromRows(/*# n.ForEach(r => {*/__vmtype__ row__r__/*#}, comma); */) { return new __nmtype__(/*# n.ForEach(r => { */ /*# mfields.ForEach(f => {*/row__r__.__f__/*#}, comma);}, comma); */); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ FromDiagonal(__ftype__ value) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var v = i == j ? "value" : "0"; */__v__/*# }, comma); }, comma); */); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ FromDiagonal(/*# n.ForEach(i => {*/__ftype__ m__i____i__/*#}, comma); */) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var v = i == j ? "m" + i + i : "0"; */__v__/*# }, comma); }, comma); */); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ FromDiagonal(__vntype__ s) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var v = i == j ? "s." + fields[i] : "0"; */__v__/*# }, comma); }, comma); */); } //# if (n == m) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ FromAntiDiagonal(__ftype__ value) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var v = (i + j == n - 1) ? "value" : "0"; */__v__/*# }, comma); }, comma); */); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ FromAntiDiagonal(/*# n.ForEach(i => { var j = n - 1 - i; */__ftype__ m__i____j__/*#}, comma); */) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var v = (i + j == n - 1) ? "m" + i + (n - 1 - i) : "0"; */__v__/*# }, comma); }, comma); */); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ FromAntiDiagonal(__vntype__ s) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var v = (i + j == n - 1) ? "s." + fields[i] : "0"; */__v__/*# }, comma); }, comma); */); } //# } #region Scale //# if (n == m) { /// /// Creates a transformation using __m__ scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Scale(/*# mfields.ForEach(f => { */__ftype__ s__f__/*# }, comma); */) => FromDiagonal(/*# mfields.ForEach(f => { */s__f__/*# }, comma); */); /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Scale(__vmtype__ s) => FromDiagonal(s); //# if (t > 1 && n < 4) { /// /// Creates a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Scale(__scalemt__ s) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var v = (i == j) ? "s." + fields[i] : "0"; */__v__/*# }, comma); }, comma); */); } //# } // isReal //# } //# if (n > 2 && Math.Abs(n-m) <= 1) { /// /// Creates a homogenous transformation using a uniform scale. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Scale(__ftype__ s) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var v = i == j ? ((i == m-1) ? "1" : "s") : "0"; */__v__/*# }, comma); }, comma); */); } /// /// Creates a transformation using __msub1__ scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Scale(/*# nfields.Take(m - 1).ForEach(f => { */__ftype__ s__f__/*# }, comma); */) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var v = (i == j) ? ((i < m - 1) ? "s" + fields[i] : "1") : "0"; */__v__/*# }, comma); }, comma); */); } /// /// Creates a transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Scale(__vmsub1type__ s) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var v = (i == j) ? ((i < m - 1) ? "s." + fields[i] : "1") : "0"; */__v__/*# }, comma); }, comma); */); } //# if (t > 1) { /// /// Creates a scaling transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Scale(__scalemsub1t__ s) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var v = (i == j) ? ((i < m - 1) ? "s." + fields[i] : "1") : "0"; */__v__/*# }, comma); }, comma); */); } //# } // isReal //# } #endregion //# if (m > 2) { #region Translation /// /// Creates a transformation with the translational component given by __msub1__ scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Translation(/*# fields.Take(m - 1).ForEach(f => { */__ftype__ t__f__/*# }, comma); */) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var v = i == j ? "1" : (j == m - 1) ? "t" + fields[i] : "0"; */__v__/*# }, comma); }, comma); */); } /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Translation(__vmsub1type__ t) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var v = i == j ? "1" : (j == m - 1) ? "t." + fields[i] : "0"; */__v__/*# }, comma); }, comma); */); } //# if (t > 1) { /// /// Creates a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Translation(__shiftmsub1t__ s) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var v = i == j ? "1" : (j == m - 1) ? "s." + fields[i] : "0"; */__v__/*# }, comma); }, comma); */); } //# } #endregion //# } //# if (t > 1) { #region Rotation //# if (m < 4) { //# var val = new string[,] { { " a", "-b" }, { " b", " a" } }; /// /// Creates a 2D rotation matrix with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Rotation(__ftype__ angleInRadians) { var a = Fun.Cos(angleInRadians); var b = Fun.Sin(angleInRadians); return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var x = (i < 2 && j < 2) ? val[i, j] : ((i == j) ? " 1" : " 0"); */__x__/*# }, comma); }, comma);*/); } /// /// Creates a 2D rotation matrix with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ RotationInDegrees(__ftype__ angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); /// /// Creates a __n__D rotation matrix from a /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Rotation(__rotnt__ r) => (__nmtype__)r; //# } //# if (n > 2) { //# if (n == m) { /// /// Creates a __nsub1__D rotation matrix from a /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Rotation(__rotnsub1t__ r) => (__nmtype__)r; //# } /// /// Creates a 3D rotation matrix from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Rotation(V__x3t__ normalizedAxis, __ftype__ angleInRadians) { Debug.Assert(normalizedAxis.LengthSquared.ApproximateEquals(1, __assertEps__)); return (__nmtype__)(Rot__x3t__.Rotation(normalizedAxis, angleInRadians)); } /// /// Creates a 3D rotation matrix from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ RotationInDegrees(V__x3t__ normalizedAxis, __ftype__ angleInDegrees) => Rotation(normalizedAxis, angleInDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ RotationEuler(__ftype__ rollInRadians, __ftype__ pitchInRadians, __ftype__ yawInRadians) { return (__nmtype__)(Rot__x3t__.RotationEuler(rollInRadians, pitchInRadians, yawInRadians)); } /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ RotationEulerInDegrees(__ftype__ rollInDegrees, __ftype__ pitchInDegrees, __ftype__ yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ RotationEuler(V__x3t__ rollPitchYawInRadians) => RotationEuler( rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a 3D rotation matrix from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ RotationEulerInDegrees(V__x3t__ rollPitchYawInDegrees) => RotationEulerInDegrees( rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a 3D rotation matrix which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ RotateInto(V__x3t__ from, V__x3t__ into) { Debug.Assert(from.LengthSquared.ApproximateEquals(1, __assertEps__)); Debug.Assert(into.LengthSquared.ApproximateEquals(1, __assertEps__)); return (__nmtype__)(Rot__x3t__.RotateInto(from, into)); } /// /// Creates a 3D rotation matrix for radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ RotationX(__ftype__ angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var val = new string[,] { {" 1", " 0", " 0" }, {" 0", " a", "-b"}, {" 0", " b", " a"} }; var x = (i < 3 && j < 3) ? val[i, j] : ((i == j) ? " 1" : " 0"); */__x__/*# }, comma); }, comma);*/); } /// /// Creates a 3D rotation matrix for degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ RotationXInDegrees(__ftype__ angleDegrees) => RotationX(angleDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix for radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ RotationY(__ftype__ angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var val = new string[,] { {" a", " 0", " b" }, {" 0", " 1", " 0"}, {"-b", " 0", " a"} }; var x = (i < 3 && j < 3) ? val[i, j] : ((i == j) ? " 1" : " 0"); */__x__/*# }, comma); }, comma);*/); } /// /// Creates a 3D rotation matrix for degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ RotationYInDegrees(__ftype__ angleDegrees) => RotationY(angleDegrees.RadiansFromDegrees()); /// /// Creates a 3D rotation matrix for radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ RotationZ(__ftype__ angleRadians) { var a = Fun.Cos(angleRadians); var b = Fun.Sin(angleRadians); return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var val = new string[,] { {" a", "-b"}, {" b", " a"} }; var x = (i < 2 && j < 2) ? val[i, j] : ((i == j) ? " 1" : " 0"); */__x__/*# }, comma); }, comma);*/); } /// /// Creates a 3D rotation matrix for degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ RotationZInDegrees(__ftype__ angleDegrees) => RotationZ(angleDegrees.RadiansFromDegrees()); //# } #endregion //# } //# if (n > 2) { #region Shearing /// /// Creates a shear transformation matrix along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ ShearXY(__ftype__ factorX, __ftype__ factorY) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var val = new string[,] { {"1", "0", "factorX" }, {"0", "1", "factorY"}, {"0", "0", "1"} }; var x = (i < 3 && j < 3) ? val[i, j] : ((i == j) ? "1" : "0"); */__x__/*# }, comma); }, comma);*/); } /// /// Creates a shear transformation matrix along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ ShearXZ(__ftype__ factorX, __ftype__ factorZ) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var val = new string[,] { {"1", "factorX", "0" }, {"0", "1", "0"}, {"0", "factorZ", "1"} }; var x = (i < 3 && j < 3) ? val[i, j] : ((i == j) ? "1" : "0"); */__x__/*# }, comma); }, comma);*/); } /// /// Creates a shear transformation matrix along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ ShearYZ(__ftype__ factorY, __ftype__ factorZ) { return new __nmtype__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var val = new string[,] { {"1", "0", "0" }, {"factorY", "1", "0"}, {"factorZ", "0", "1"} }; var x = (i < 3 && j < 3) ? val[i, j] : ((i == j) ? "1" : "0"); */__x__/*# }, comma); }, comma);*/); } #endregion //# } #endregion #region Static methods for F# core and Aardvark library support /// /// Returns the given matrix, with each element divided by . /// [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ DivideByInt(__nmtype__ m, int x) => m / x; #endregion #region Properties and Indexers public readonly bool IsValid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } public readonly bool IsInvalid { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => false; } public readonly IEnumerable<__ftype__> Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { //# n.ForEach(j => { m.ForEach(k => { yield return M__j____k__; //# });}); } } public readonly IEnumerable<__vmtype__> Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { //# n.ForEach(k => { yield return R__k__; //# }); } } public readonly IEnumerable<__vntype__> Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { //# m.ForEach(k => { yield return C__k__; //# }); } } //# n.ForEach(k => { [XmlIgnore] public __vmtype__ R__k__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new __vmtype__(/*# m.ForEach(f => {*/ M__k____f__/*#}, comma); */); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { //# mfields.ForEach((f, j) => { M__k____j__ = value.__f__; //# }); } } //# }); //# m.ForEach(k => { [XmlIgnore] public __vntype__ C__k__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new __vntype__(/*# n.ForEach(f => {*/ M__f____k__/*#}, comma); */); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { //# nfields.ForEach((f, j) => { M__j____k__ = value.__f__; //# }); } } //# }); public readonly __vntype__ Diagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __vntype__(/*# n.ForEach(i => {*/M__i____i__/*#}, comma); */); } //# if (n == m) { public readonly __vntype__ AntiDiagonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __vntype__(/*# n.ForEach(i => { var j = n - 1 - i; */M__i____j__/*#}, comma); */); } //# } /// /// Returns the minimum element of the matrix. /// public readonly __ftype__ MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(/*# n.ForEach(r => { m.ForEach(s => {*/M__r____s__/*#}, comma);}, comma); */); } /// /// Returns the maximum element of the matrix. /// public readonly __ftype__ MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(/*# n.ForEach(r => { m.ForEach(s => {*/M__r____s__/*#}, comma);}, comma); */); } public unsafe __ftype__ this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (__ftype__* ptr = __getptr__) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (__ftype__* ptr = __getptr__) { ptr[index] = value; } } } public unsafe __ftype__ this[int row, int column] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (__ftype__* ptr = __getptr__) { return ptr[row * __m__ + column]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (__ftype__* ptr = __getptr__) { ptr[row * __m__ + column] = value; } } } //# if (isReal) { //# var condArray = new[] { "Finite", "NaN", "Infinity", "PositiveInfinity", "NegativeInfinity", "Tiny" }; //# var scopeArray = new[] { "Fun", ftype, ftype, ftype, ftype, "Fun" }; //# var quantArray = new[] { "Any", "All" }; //# var actArray = new[] { oror, andand }; //# condArray.ForEach(scopeArray, (cond, scope) => { //# quantArray.ForEach(actArray, (qant, act) => { public readonly bool __qant____cond__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return /*# n.ForEach(i => {*/ /*#m.ForEach(j => { */__scope__.Is__cond__(M__i____j__)/*# }, act); }, act); */; } } //# }); // quantArray //# }); // condArray /// /// Returns true if the absolute value of each element of the matrix is smaller than Constant<__ftype__>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any element of the matrix is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any element of the matrix is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any element of the matrix is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any element of the matrix is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all elements of the matrix are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } //# } // isReal #endregion #region Constants public const int RowCount = __n__; public const int ColumnCount = __m__; public const int ElementCount = __n__ * __m__; public static V2l Dimensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new V2l(__n__, __m__); } public static __nmtype__ Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __nmtype__(0); } //# if (n == m) { public static __nmtype__ Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __nmtype__(/*# n.ForEach(i => { m.ForEach(j => { var v = i == j ? "1" : "0"; */__v__/*# }, comma); }, comma); */); } //# } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// public readonly __ftype__ Norm1 { get { return /*# n.ForEach(i => { */ /*# m.ForEach(j => { */Fun.Abs(M__i____j__)/*# }, add); }, add); */; } } /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// public readonly __ctype__ Norm2 { get { return Fun.Sqrt(/*# n.ForEach(i => { */ /*# m.ForEach(j => { */M__i____j__ * M__i____j__/*# }, add); }, add); */); } } /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// public readonly __ftype__ NormMax { get { return Fun.Max(/*# n.ForEach(i => { */ Fun.Max(/*# m.ForEach(j => { */ Fun.Abs(M__i____j__)/*# }, comma); */)/*# }, comma); */); } } /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// public readonly __ftype__ NormMin { get { return Fun.Min(/*# n.ForEach(i => { */ Fun.Min(/*# m.ForEach(j => { */ Fun.Abs(M__i____j__)/*# }, comma); */)/*# }, comma); */); } } #endregion #region Mathematical Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ operator -(__nmtype__ m) { return new __nmtype__(/*# n.ForEach(r => { */ /*# m.ForEach(s => { */-m.M__r____s__/*# }, comma); }, comma); */); } //# for (int o = 0; o < ops.Length; o++) { var op = ops[o]; var opact = "operator " + op; //# for (int t1 = t; t1 < tcharA.Length; t1++) { //# var nmtype1 = "M" + n + m + tcharA[t1]; //# var ftype1 = ftypeA[t1]; //# if (o != ops.Length-1) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype1__ __opact__(__nmtype__ a, __nmtype1__ b) { return new __nmtype1__(/*# n.ForEach(r => { */ /*# m.ForEach(s => { */a.M__r____s____op__b.M__r____s__/*# }, comma); }, comma); */); } //# } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype1__ __opact__(__nmtype__ m, __ftype1__ s) { return new __nmtype1__(/*# n.ForEach(r => { */ /*# m.ForEach(s => { */m.M__r____s____op__s/*# }, comma); }, comma); */); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype1__ __opact__(__ftype1__ s, __nmtype__ m) { return new __nmtype1__(/*# n.ForEach(r => { */ /*# m.ForEach(s => { */s__op__m.M__r____s__/*# }, comma); }, comma); */); } //# } //# } #endregion //# if (!isReal) { #region Bitwise Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ operator ~(__nmtype__ m) { return new __nmtype__(/*# n.ForEach(r => { */ /*# m.ForEach(s => { */~m.M__r____s__/*# }, comma); }, comma); */); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ operator <<(__nmtype__ a, int s) { return new __nmtype__(/*# n.ForEach(r => { */ /*# m.ForEach(s => { */a.M__r____s__ << s/*# }, comma); }, comma); */); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ operator >>(__nmtype__ a, int s) { return new __nmtype__(/*# n.ForEach(r => { */ /*# m.ForEach(s => { */a.M__r____s__ >> s/*# }, comma); }, comma); */); } //# foreach (var op in bwops) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ operator __op__(__nmtype__ a, __nmtype__ b) { return new __nmtype__(/*# n.ForEach(r => { */ /*# m.ForEach(s => { */a.M__r____s__ __op__ b.M__r____s__/*# }, comma); }, comma); */); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ operator __op__(__nmtype__ a, __ftype__ s) { return new __nmtype__(/*# n.ForEach(r => { */ /*# m.ForEach(s => { */a.M__r____s__ __op__ s/*# }, comma); }, comma); */); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ operator __op__(__ftype__ s, __nmtype__ a) { return new __nmtype__(/*# n.ForEach(r => { */ /*# m.ForEach(s => { */s __op__ a.M__r____s__/*# }, comma); }, comma); */); } //# } #endregion //# } #region Matrix/Vector Multiplication /// /// Multiplies a __nmtype__ matrix with a __vmtype__ column vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vntype__ operator *(__nmtype__ m, __vmtype__ v) { return new __vntype__(/*# n.ForEach(r => { */ /*# m.ForEach(q => { var f = fields[q]; */m.M__r____q__ * v.__f__/*# }, add); }, comma); */); } /// /// Multiplies a __vntype__ row vector with a __nmtype__ matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vmtype__ operator *(__vntype__ v, __nmtype__ m) { return new __vmtype__(/*# m.ForEach(q => { */ /*# n.ForEach(r => { var f = fields[r]; */v.__f__ * m.M__r____q__/*# }, add); }, comma); */); } #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__nmtype__ a, __nmtype__ b) { return/*# n.ForEach(i => { m.ForEach(j => { */ a.M__i____j__ == b.M__i____j__/*#}, andand);}, andand);*/; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__nmtype__ a, __ftype__ s) { return/*# n.ForEach(i => { m.ForEach(j => { */ a.M__i____j__ == s/*# }, andand); }, andand); */; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__ftype__ s, __nmtype__ a) { return/*# n.ForEach(i => { m.ForEach(j => { */ s == a.M__i____j__ /*# }, andand); }, andand); */; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__nmtype__ a, __nmtype__ b) { return !(a == b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__nmtype__ m, __ftype__ s) { return !(m == s); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__ftype__ s, __nmtype__ m) { return !(s == m); } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(/*# n.ForEach(r => { */ HashCode.GetCombined(/*# m.ForEach(s => {*/M__r____s__/*# }, comma); }, bracketComma); */)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__nmtype__ other) { return /*# n.ForEach(i => { */ /*# m.ForEach(j => { */M__i____j__.Equals(other.M__i____j__)/*#}, andand);}, andand);*/; } public override readonly bool Equals(object other) => (other is __nmtype__ o) ? Equals(o) : false; public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]", "[", ", ", "]"); } /// /// Outputs e.g. a 2x2-Matrix in the form "(beginM)(beginR)m00(betweenR)m01(endR)(betweenM)(beginR)m10(betweenR)m11(endR)(endM)". /// public readonly string ToString(string format, IFormatProvider fp, string beginM, string betweenM, string endM, string beginR, string betweenR, string endR) { if (fp == null) fp = CultureInfo.InvariantCulture; return beginM/*# n.ForEach(r => {*/ + R__r__.ToString(format, fp, beginR, betweenR, endR) /*# }, addbetweenM); */ + endM; } public static __nmtype__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return __nmtype__.FromRows(/*# n.ForEach(i => { */ __vmtype__.Parse(x[__i__])/*# }, comma); */ ); } #endregion #region Matrix Operations //# if(m == n) { /// /// Returns adjoint of this matrix. /// public readonly __nmtype__ Adjoint { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { //# if (n == 2) { return new __nmtype__(M11, -M10, -M01, M00); //# } else { __nmtype__ result = new __nmtype__(); for (int row = 0; row < __n__; row++) { for (int col = 0; col < __m__; col++) { if (((col + row) % 2) == 0) result[col, row] = this.Minor(row, col).Determinant; else result[col, row] = -this.Minor(row, col).Determinant; } } return result; //# } } } /// /// Returns the trace of this matrix. /// The trace is defined as the sum of the diagonal elements, /// and is only defined for square matrices. /// public readonly __ftype__ Trace { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return /*# n.ForEach(r => {*/M__r____r__/*# }, add);*/ ; } } /// /// Gets the determinant of this matrix. /// The determinant is only defined for square matrices. /// public readonly __ftype__ Determinant { get { //# if (n == 2) { return M00 * M11 - M10 * M01; //# } //# if (n == 3) { if (M10 == 0 && M20 == 0 && M21 == 0) { return M00 * M11 * M22; } return M00 * M11 * M22 - M00 * M12 * M21 + M01 * M12 * M20 - M01 * M10 * M22 + M02 * M10 * M21 - M02 * M11 * M20; //# } //# if (n == 4) { // using bottom row because elements M30, M31, and M32 // are zero most of the time. __ftype__ d = 0; if (M30 != 0.0f) d -= M30 * ( M01 * M12 * M23 + M02 * M13 * M21 + M03 * M11 * M22 - M21 * M12 * M03 - M22 * M13 * M01 - M23 * M11 * M02 ); if (M31 != 0.0f) d += M31 * ( M00 * M12 * M23 + M02 * M13 * M20 + M03 * M10 * M22 - M20 * M12 * M03 - M22 * M13 * M00 - M23 * M10 * M02 ); if (M32 != 0.0f) d -= M32 * ( M00 * M11 * M23 + M01 * M13 * M20 + M03 * M10 * M21 - M20 * M11 * M03 - M21 * M13 * M00 - M23 * M10 * M01 ); if (M33 != 0.0f) d += M33 * ( M00 * M11 * M22 + M01 * M12 * M20 + M02 * M10 * M21 - M20 * M11 * M02 - M21 * M12 * M00 - M22 * M10 * M01 ); return d; //# } } } /// /// Returns whether this matrix is invertible. /// A matrix is invertible if its determinant is not zero. /// public readonly bool Invertible { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant != 0; } } /// /// Returns whether this matrix is singular. /// A matrix is singular if its determinant is zero. /// public readonly bool Singular { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Determinant == 0; } } /// /// Gets transpose of this matrix. /// public readonly __nmtype__ Transposed { get { return new __nmtype__ {/*# n.ForEach(r => { */ /*# m.ForEach(s => { */ M__r____s__ = M__s____r__/*# }, comma); }, comma); */ }; } } //# if (t > 1) { private static V2l s_luSize = new V2l(__n__, __n__); private static V2l s_luDelta = new V2l(1, __n__); /// /// Inverts the given matrix using lu factorization in place. Returns true /// if the matrix was invertible, otherwise the matrix remains unchanged. /// public/*# if(ftype == "double") { Out(" unsafe"); } */ bool LuInvert() { //# if (ftype == "double") { fixed (__nmtype__* self = &this) { var lu = this; __vnitype__ perm; if (NumericExtensions.LuFactorize((__ftype__*)&lu, 0, 1, __n__, (int*)&perm, __n__)) { NumericExtensions.LuInverse((__ftype__*)&lu, 0, 1, __n__, (int*)&perm, (__ftype__*)self, 0, 1, __n__, __n__); return true; } return false; } //# } else { M__n____n__d dbl = (M__n____n__d)this; if(dbl.LuInvert()) { this = (__nmtype__)dbl; return true; } return false; //# } } /// /// Returns the inverse of the matrix using lu factorization. /// If the matrix is not invertible, __nmtype__.Zero is returned. /// public/*# if(ftype == "double") { Out(" unsafe"); } */ readonly __nmtype__ LuInverse() { //# if (ftype == "double") { var lu = this; __nmtype__ res; __vnitype__ perm; if (NumericExtensions.LuFactorize((__ftype__*)&lu, 0, 1, __n__, (int*)&perm, __n__)) { NumericExtensions.LuInverse((__ftype__*)&lu, 0, 1, __n__, (int*)&perm, (__ftype__*)&res, 0, 1, __n__, __n__); return res; } return __nmtype__.Zero; //# } else { return (__nmtype__)((M__n____n__d)this).LuInverse(); //# } } /// /// Returns the inverse of this matrix. If the matrix is not invertible /// __nmtype__.Zero is returned. /// public readonly __nmtype__ Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => LuInverse(); } //# } //# } #endregion #region Matrix Multiplication //# for (int a = n; a <= n+1 && a < 5; a++) { //# if(a == m) { public static M__n____a____tchar__ operator *(M__n____a____tchar__ a, M__a____a____tchar__ b) { return new M__n____a____tchar__(/*# n.ForEach(r => { *//*# a.ForEach(s => { */ /*# a.ForEach(u => {*/a.M__r____u__ * b.M__u____s__/*# }, add);}, comma);}, comma); */ ); } //# } //# if ((a == n) && (a < 4)) { //# int b = a+1; //# if( b == m) { public static M__n____b____tchar__ operator *(M__n____a____tchar__ a, M__a____b____tchar__ b) { return new M__n____b____tchar__(/*# n.ForEach(r => { *//*# b.ForEach(s => { */ /*# a.ForEach(u => {*/a.M__r____u__ * b.M__u____s__/*# }, add);}, comma);}, comma); */ ); } //# } //# } //# } #endregion #region IMatrix /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[long x, long y] { readonly get { return /*# if (ftype != "double") { */(double)/*# } */this[(int)y, (int)x]; } set { this[(int)y, (int)x] = /*# if (ftype != "double") { */(__ftype__)/*# } */value; } } /// /// NOTE: this indexer has reversed order of coordinates with respect to /// the default indexer!!! /// public double this[V2l v] { readonly get { return /*# if (ftype != "double") { */(double)/*# } */this[(int)v.Y, (int)v.X]; } set { this[(int)v.Y, (int)v.X] = /*# if (ftype != "double") { */(__ftype__)/*# } */value; } } #endregion #region IMatrix public readonly V2l Dim { get { return Dimensions; } } public readonly object GetValue(long x, long y) { return (object)this[(int)x, (int)y]; } public void SetValue(object value, long x, long y) { this[(int)x, (int)y] = (__ftype__)value; } public readonly object GetValue(V2l v) { return (object)this[(int)(v.X), (int)(v.Y)]; } public void SetValue(object value, V2l v) { this[(int)(v.X), (int)(v.Y)] = (__ftype__)value; } #endregion } public class __nmtype__EqualityComparer : IEqualityComparer<__nmtype__> { public static readonly __nmtype__EqualityComparer Default = new __nmtype__EqualityComparer(); #region IEqualityComparer<__nmtype__> Members public bool Equals(__nmtype__ v0, __nmtype__ v1) { return v0 == v1; } public int GetHashCode(__nmtype__ v) { return v.GetHashCode(); } #endregion } /// /// Contains static methods. /// public static partial class Mat { #region Transformation Extraction //# if (t > 1 && n == 2) { /// /// Computes the (signed) angle in radians of a rotation matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ GetRotation(this __nmtype__ m) => Fun.Atan2(m.M10, m.M00); //# } /// /// Approximates the uniform scale value of the given transformation matrix (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ctype__ GetScale(this __nmtype__ m) => (/*# n.ForEach(i => {*/m.C__i__.Length/*# }, add);*/) / __n__; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnctype__ GetScaleVector(this __nmtype__ m) => new __vnctype__(/*# n.ForEach(i => {*/m.C__i__.Length/*# }, comma);*/); //# if (n > 2 && n == m) { /// /// Approximates the uniform scale value of the given transformation matrix (average length of __nsub1__D basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ctype__ GetScale__nsub1__(this __nmtype__ m) => (/*# nsub1.ForEach(i => {*/m.C__i__.__xyznsub1__.Length/*# }, add);*/) / __nsub1__; /// /// Extracts a scale vector from the given matrix by calculating the lengths of the __nsub1__D basis vectors. /// NOTE: The extraction only gives absolute value (negative scale will be ignored) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnsub1ctype__ GetScaleVector__nsub1__(this __nmtype__ m) => new __vnsub1ctype__(/*# nsub1.ForEach(i => {*/m.C__i__.__xyznsub1__.Length/*# }, comma);*/); //# } //# if (t > 1 && m == 4) { /// /// Extracts the forward vector from the given view transformation matrix. /// NOTE: A left-handed coordinates system transformation is expected, /// where the view-space z-axis points in forward direction. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vmsub1type__ GetViewDirectionLH(this __nmtype__ m) => m.R__msub2__.__xyzmsub1__.Normalized; /// /// Extracts the forward vector from the given view transformation matrix. /// NOTE: A right-handed coordinates system transformation is expected, where /// the view-space z-axis points opposit the forward vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vmsub1type__ GetViewDirectionRH(this __nmtype__ m) => -m.R__msub2__.__xyzmsub1__.Normalized; /// /// Extracts the translation component of the given transformation matrix, which when given /// a model transformation represents the model origin in world position. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vmsub1type__ GetModelOrigin(this __nmtype__ m) => m.C__msub1__/*# if (n != msub1) {*/.__xyzmsub1__/*#} */; //# } //# if (t == 3 && n == 4 && n == m) { /// /// Builds a hull from the given view-projection transformation matrix (left, right, bottom, top, near, far). /// The view volume is assumed to be [-1, -1, -1] [1, 1, 1]. /// The normals of the hull planes point to the outside and are normalized. /// A point inside the visual hull will has negative height to all planes. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Hull3d GetVisualHull(this __nmtype__ viewProj) { var r0 = viewProj.R0; var r1 = viewProj.R1; var r2 = viewProj.R2; var r3 = viewProj.R3; return new Hull3d(new[] { new Plane3d((-(r3 + r0))).Normalized, // left new Plane3d((-(r3 - r0))).Normalized, // right new Plane3d((-(r3 + r1))).Normalized, // bottom new Plane3d((-(r3 - r1))).Normalized, // top new Plane3d((-(r3 + r2))).Normalized, // near new Plane3d((-(r3 - r2))).Normalized, // far }); } //# } #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the matrix. This is /// calculated as |M00| + |M01| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Norm1(__nmtype__ m) => m.Norm1; /// /// Returns the Euclidean (or 2-) norm of the matrix. This is /// calculated as Sqrt(M00 * M00 + M01 * M01 + ... ) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ctype__ Norm2(__nmtype__ m) => m.Norm2; /// /// Returns the infinite (or maximum) norm of the matrix. This is /// calculated as max(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ NormMax(__nmtype__ m) => m.NormMax; /// /// Returns the minimum norm of the matrix. This is calculated as /// min(|M00|, |M01|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ NormMin(__nmtype__ m) => m.NormMin; /// /// Returns the p-norm of the matrix. This is calculated as /// (|M00|^p + |M01|^p + ... )^(1/p) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ctype__ Norm(this __nmtype__ m, __ctype__ p) { return (/*# n.ForEach(i => { m.ForEach(j => { */ Fun.Abs(m.M__i____j__).Pow(p)/*# }, add); }, add); */ ).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the Manhatten (or 1-) distance between two matrices. /// public static __ftype__ Distance1(this __nmtype__ a, __nmtype__ b) { return/*# n.ForEach(i => { m.ForEach(j => { */ Fun.Abs(b.M__i____j__ - a.M__i____j__)/*# }, add); }, add); */; } /// /// Returns the Euclidean (or 2-) distance between two matrices. /// public static __ctype__ Distance2(this __nmtype__ a, __nmtype__ b) { return /*# if (ctype != "double") {*/(__ctype__)/*# } */Fun.Sqrt(/*# n.ForEach(i => { m.ForEach(j => { */ Fun.Square(b.M__i____j__ - a.M__i____j__)/*# }, add); }, add); */); } /// /// Returns the p-distance between two matrices. /// public static __ctype__ Distance(this __nmtype__ a, __nmtype__ b, __ctype__ p) { return (/*# n.ForEach(i => { m.ForEach(j => { */ Fun.Abs(b.M__i____j__ - a.M__i____j__).Pow(p)/*# }, add); }, add); */ ).Pow(1 / p); } /// /// Returns the maximal absolute distance between the components of /// the two matrices. /// public static __ftype__ DistanceMax(this __nmtype__ a, __nmtype__ b) { return Fun.Max(/*# n.ForEach(i => { */ Fun.Max(/*# m.ForEach(j => { */ Fun.Abs(b.M__i____j__ - a.M__i____j__)/*# }, comma); */)/*# }, comma); */); } /// /// Returns the minimal absolute distance between the components of /// the two matrices. /// public static __ftype__ DistanceMin(this __nmtype__ a, __nmtype__ b) { return Fun.Min(/*# n.ForEach(i => { */ Fun.Min(/*# m.ForEach(j => { */ Fun.Abs(b.M__i____j__ - a.M__i____j__)/*# }, comma); */)/*# }, comma); */); } #endregion #region Transformations /// /// Transforms vector v by matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vntype__ Transform(this __nmtype__ m, __vmtype__ v) => m * v; //# for (int k = m + 1; k <= 4; k++) { //# var d = k - m; //# var vktype = "V" + k + tchar; //# var vrettype = "V" + (n + d) + tchar; //# var constfields = fields.Skip(m).Take(d); //# var isare = (d > 1) ? "are" : "is"; /// /// Transforms vector v by matrix m. /// /*# constfields.ForEach(f => {*/v.__f__/*# }, andLit); */ __isare__ not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vrettype__ Transform(this __nmtype__ m, __vktype__ v) { return new __vrettype__(/*# n.ForEach(r => { */ /*# m.ForEach(q => { var f = fields[q]; */m.M__r____q__ * v.__f__/*# }, add); }, comma); */, /*# constfields.ForEach(f => { */v.__f__/*# }, comma);*/); } //# } /// /// Transforms vector v by the transpose of matrix m. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vmtype__ TransposedTransform(this __nmtype__ m, __vntype__ v) => v * m; //# if (n == m) { //# for (int k = n + 1; k <= 4; k++) { //# var d = k - n; //# var vktype = "V" + k + tchar; //# var vrettype = "V" + (m + d) + tchar; //# var constfields = fields.Skip(n).Take(d); //# var isare = (d > 1) ? "are" : "is"; /// /// Transforms vector v by the transpose of matrix m. /// /*# constfields.ForEach(f => {*/v.__f__/*# }, andLit); */ __isare__ not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vrettype__ TransposedTransform(this __nmtype__ m, __vktype__ v) { return new __vrettype__(/*# m.ForEach(q => { */ /*# n.ForEach(r => { var f = fields[r]; */v.__f__ * m.M__r____q__/*# }, add); }, comma); */, /*# constfields.ForEach(f => { */v.__f__/*# }, comma);*/); } //# } } //# if (m > 2) { /// /// Transforms direction vector v (v.__fields[m-1]__ is presumed 0.0) by matrix m. /// public static __vmsub1type__ TransformDir(this __nmtype__ m, __vmsub1type__ v) { return new __vmsub1type__(/*# msub1.ForEach(s => { */ /*# mfields.Take(msub1).ForEach((fr, r) => { */m.M__s____r__ * v.__fr__/*# }, add); }, comma); */ ); } /// /// Transforms point p (v.__fields[m-1]__ is presumed 1.0) by matrix m./*# if (n == m) {*/ /// No projective transform is performed./*# }*/ /// public static __vmsub1type__ TransformPos(this __nmtype__ m, __vmsub1type__ p) { return new __vmsub1type__(/*# msub1.ForEach(s => { */ /*# mfields.Take(msub1).ForEach((fr, r) => { */m.M__s____r__ * p.__fr__/*# }, add); */ + m.M__s____msub1__/*# }, comma); */ ); } //# if (n == m) { /// /// Transforms point p (p.__fields[m-1]__ is presumed 1.0) by matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static __vmsub1type__ TransformPosProj(this __nmtype__ m, __vmsub1type__ p) { __ftype__ s = /*# mfields.Take(msub1).ForEach((fr, r) => { */m.M__msub1____r__ * p.__fr__/*#}, add);*/ + m.M__msub1____msub1__; return TransformPos(m, p) * (1 / s); } /// /// Transforms point p (p.__fields[m-1]__ is presumed 1.0) by matrix m. /// Projective transform is performed. /// public static __vmtype__ TransformPosProjFull(this __nmtype__ m, __vmsub1type__ p) { return new __vmtype__(/*# m.ForEach(s => { */ /*# mfields.Take(msub1).ForEach((fr, r) => { */m.M__s____r__ * p.__fr__/*#}, add);*/ + m.M__s____msub1__/*#}, comma);*/ ); } /// /// Transforms direction vector v (v.__fields[m-1]__ is presumed 0.0) by transposed version of matrix m. /// public static __vmsub1type__ TransposedTransformDir(this __nmtype__ m, __vmsub1type__ v) { return new __vmsub1type__(/*# msub1.ForEach(s => { */ /*# mfields.Take(msub1).ForEach((fr, r) => { */m.M__r____s__ * v.__fr__/*# }, add); }, comma); */ ); } /// /// Transforms point p (v.__fields[m-1]__ is presumed 1.0) by transposed version of matrix m. /// No projective transform is performed. /// public static __vmsub1type__ TransposedTransformPos(this __nmtype__ m, __vmsub1type__ p) { return new __vmsub1type__(/*# msub1.ForEach(s => { */ /*# mfields.Take(msub1).ForEach((fr, r) => { */m.M__r____s__ * p.__fr__/*# }, add); */ + m.M__msub1____s__/*# }, comma); */ ); } /// /// Transforms point p (v.__fields[m-1]__ is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. Perspective Division is performed. /// public static __vmsub1type__ TransposedTransformPosProj(this __nmtype__ m, __vmsub1type__ p) { var s = /*# mfields.Take(msub1).ForEach((fr, r) => { */m.M__r____msub1__ * p.__fr__/*#}, add);*/ + m.M__msub1____msub1__; return TransposedTransformPos(m, p) * (1 / s); } [Obsolete("Use TransposedTransformPosProj instead.")] public static __vmsub1type__ TransposedTransformProj(this __nmtype__ m, __vmsub1type__ p) => m.TransposedTransformPosProj(p); /// /// Transforms point p (v.__fields[m-1]__ is presumed 1.0) by transposed version of matrix m. /// Projective transform is performed. /// public static __vmtype__ TransposedTransformPosProjFull(this __nmtype__ m, __vmsub1type__ p) { return new __vmtype__(/*# m.ForEach(s => { */ /*# mfields.Take(msub1).ForEach((fr, r) => { */m.M__r____s__ * p.__fr__/*#}, add);*/ + m.M__msub1____s__/*#}, comma);*/ ); } [Obsolete("Use TransposedTransformPosProjFull instead.")] public static __vmtype__ TransposedTransformProjFull(this __nmtype__ m, __vmsub1type__ p) => m.TransposedTransformPosProjFull(p); //# } // n != m //# } // m > 2 //# if (m == n + 1) { /// /// Multiplies two matrices as __m__x__m__ matrices. /// public static __nmtype__ MultiplyAffine(this __nmtype__ a, __nmtype__ b) { return new __nmtype__(/*# n.ForEach(r => { m.ForEach(c => { */ /*# n.ForEach(j => {*/a.M__r____j__ * b.M__j____c__/*# }, add); if (c == m - 1) {*/ + a.M__r____c__/*# } }, comma);}, comma); */ ); } //# } #endregion #region Operations //# if (n == m) { //# var rettype = (n > 2) ? "M" + nsub1 + msub1 + tchar : ftype; //# var size = nsub1 * nsub1; /// /// Returns the given to a deleting the /// specified row and column. /// public static __rettype__ Minor(this __nmtype__ m, int row, int column) { //# if (n == 2) { return m[1 - row, 1 - column]; //# } else { __rettype__ rs = new __rettype__(); for (int k = 0; k < __size__; k++) { var i = k / __nsub1__; var j = k % __nsub1__; var ii = (i < row) ? i : i + 1; var jj = (j < column) ? j : j + 1; rs[k] = m[ii * __n__ + jj]; } return rs; //# } } //# } /// /// Returns index-th row of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static __vmtype__ Row(this __nmtype__ m, int index) { __ftype__* ptr = &m.M00; return new __vmtype__(/*# m.ForEach(j => { */ptr[index * __m__/*# if (j > 0) {*/ + __j__/*# }*/]/*# }, comma);*/); } /// /// Returns index-th column of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static __vntype__ Column(this __nmtype__ m, int index) { __ftype__* ptr = &m.M00; return new __vntype__(/*# n.ForEach(i => { var offset = i * m; */ptr[index/*# if (offset > 0) {*/ + __offset__/*# }*/]/*# }, comma);*/); } //# if( m == n) { /// /// Returns the determinant of the given matrix. /// The determinant is only defined for square matrices. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Determinant(__nmtype__ m) => m.Determinant; /// /// Returns the transpose of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Transposed(__nmtype__ m) => m.Transposed; /// /// Transposes the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Transpose(this ref __nmtype__ m) { //# for (int r = 1; r < n; r++) { r.ForEach(s => { Fun.Swap(ref m.M__r____s__, ref m.M__s____r__); //# }); } } //# if (isReal) { /// /// Returns the inverse of the given matrix. If the matrix is not invertible /// __nmtype__.Zero is returned. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Inverse(__nmtype__ m) => m.Inverse; /// /// Inverts the given matrix in place. Returns true if the matrix was invertible, /// otherwise the matrix remains unchanged. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Invert(this ref __nmtype__ m) { return m.LuInvert(); } /// /// Returns if the given matrix is the identity matrix I. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIdentity(this __nmtype__ m, __ftype__ epsilon) { return Fun.ApproximateEquals(m, __nmtype__.Identity, epsilon); } /// /// Returns if the given matrix is the identity matrix I. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsIdentity(this __nmtype__ m) => IsIdentity(m, Constant<__ftype__>.PositiveTinyValue); /// /// Returns if the given matrix is orthonormal (i.e. M * M^t == I) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthonormal(this __nmtype__ m, __ftype__ epsilon) { var i = m * m.Transposed; return i.IsIdentity(epsilon); } /// /// Returns if the given matrix is orthonormal (i.e. M * M^t == I) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthonormal(this __nmtype__ m) => IsOrthonormal(m, Constant<__ftype__>.PositiveTinyValue); /// /// Returns if the given matrix is orthogonal (i.e. all non-diagonal entries of M * M^t == 0) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonal(this __nmtype__ m, __ftype__ epsilon) { var i = m * m.Transposed; for (int j = 0; j < __n__; j++) i[j, j] = 1; //inefficient implementation: just leave out the comparisons at the diagonal entries. return i.IsIdentity(epsilon); } /// /// Returns if the given matrix is orthogonal (i.e. all non-diagonal entries of M * M^t == 0) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOrthogonal(this __nmtype__ m) => IsOrthogonal(m, Constant<__ftype__>.PositiveTinyValue); //# } //# } #endregion #region Comparisons //# var bops = new[,] { { "<", "Smaller" }, { ">" , "Greater"}, //# { "<=", "SmallerOrEqual" }, { ">=", "GreaterOrEqual"}, //# { "==", "Equal" }, { "!=", "Different" } }; //# var attention = "ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b))."; //# for(int o = 0; o < bops.GetLength(0); o++) { //# string bop = " " + bops[o,0] + " ", opName = bops[o,1]; /// /// Returns whether ALL elements of a are __opName__ the corresponding element of b. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool All__opName__(this __nmtype__ a, __nmtype__ b) { return/*# n.ForEach(i => { m.ForEach(j => { */ a.M__i____j____bop__b.M__i____j__/*#}, andand);}, andand);*/; } /// /// Returns whether ALL elements of m are __opName__ s. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool All__opName__(this __nmtype__ m, __ftype__ s) { return/*# n.ForEach(i => { m.ForEach(j => { */ m.M__i____j____bop__s/*#}, andand);}, andand);*/; } /// /// Returns whether a is __opName__ ALL elements of m. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool All__opName__(__ftype__ s, __nmtype__ m) { return/*# n.ForEach(i => { m.ForEach(j => { */ s__bop__m.M__i____j__/*#}, andand);}, andand);*/; } /// /// Returns whether AT LEAST ONE element of a is __opName__ the corresponding element of b. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Any__opName__(this __nmtype__ a, __nmtype__ b) { return/*# n.ForEach(i => { m.ForEach(j => { */ a.M__i____j____bop__b.M__i____j__/*#}, oror);}, oror);*/; } /// /// Returns whether AT LEAST ONE element of m is __opName__ s. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Any__opName__(this __nmtype__ m, __ftype__ s) { return/*# n.ForEach(i => { m.ForEach(j => { */ m.M__i____j____bop__s/*#}, oror);}, oror);*/; } /// /// Returns whether a is __opName__ AT LEAST ONE element of m. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Any__opName__(__ftype__ s, __nmtype__ m) { return/*# n.ForEach(i => { m.ForEach(j => { */ s__bop__m.M__i____j__/*#}, oror);}, oror);*/; } //# } /// /// Compare first element of first row before second element of first row, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this __nmtype__ m0, __nmtype__ m1) { /*# n.ForEach(i => { m.ForEach(j => { */ if (m0.M__i____j__ < m1.M__i____j__) return -1; if (m0.M__i____j__ > m1.M__i____j__) return +1;/*#});});*/ return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ MinElement(__nmtype__ m) => m.MinElement; /// /// Returns the maximum element of the given matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ MaxElement(__nmtype__ m) => m.MaxElement; #endregion //# if (m == n && isReal) { #region Orthogonalization /// /// Orthogonalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// public static void Orthogonalize(this ref __nmtype__ matrix) { //# for (int j = 1; j < n; j++) { //# for (int i = 0; i < 2; i++) { //# for (int k = 0; k < j; k++) { matrix.C__j__ -= (Vec.Dot(matrix.C__k__, matrix.C__j__) / Vec.Dot(matrix.C__k__, matrix.C__k__)) * matrix.C__k__; //# } //# } //# } } /// /// Orthogonalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Orthogonalized(this __nmtype__ matrix) { __nmtype__ m = matrix; Orthogonalize(ref m); return m; } /// /// Orthonormalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// public static void Orthonormalize(this ref __nmtype__ matrix) { matrix.C0 = matrix.C0.Normalized; //# for (int j = 1; j < n; j++) { //# for (int i = 0; i < 2; i++) { //# for (int k = 0; k < j; k++) { matrix.C__j__ -= (Vec.Dot(matrix.C__k__, matrix.C__j__) / Vec.Dot(matrix.C__k__, matrix.C__k__)) * matrix.C__k__; //# } //# } matrix.C__j__ = matrix.C__j__.Normalized; //# } } /// /// Orthonormalizes the columns of the given using the (modified) Gram-Schmidt algorithm with /// an additional reorthogonalization step. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Orthonormalized(this __nmtype__ matrix) { __nmtype__ m = matrix; Orthonormalize(ref m); return m; } #endregion //# } #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this __nmtype__ m, __ftype__ epsilon) => /*# n.ForEach(r => { m.ForEach(s => {*/m.M__r____s__.IsTiny(epsilon)/*# }, oror); }, oror);*/; /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this __nmtype__ m, __ftype__ epsilon) => /*# n.ForEach(r => { m.ForEach(s => {*/m.M__r____s__.IsTiny(epsilon)/*# }, andand); }, andand);*/; #endregion //# if (isReal) { #region Special Floating Point Value Checks //# var condArray = new[] { "Finite", "NaN", "Infinity", "PositiveInfinity", "NegativeInfinity", "Tiny" }; //# var quantArray = new[] { "Any", "All" }; //# condArray.ForEach(cond => { //# quantArray.ForEach(qant => { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool __qant____cond__(__nmtype__ m) => m.__qant____cond__; //# }); // quantArray //# }); // condArray #endregion //# } // isReal } public static partial class Fun { #region ApproximateEquals //# if (isReal) { /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __nmtype__ a, __nmtype__ b) => ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); //# } /// /// Returns if all entries in the matrix a are approximately equal to the respective entries in matrix b. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __nmtype__ a, __nmtype__ b, __ftype__ epsilon) { return Mat.DistanceMax(a, b) <= epsilon; //Inefficient implementation, no early exit of comparisons. } #endregion #region IsTiny /// /// Returns whether the absolute value of each element of the given is smaller than . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this __nmtype__ m, __ftype__ epsilon) => Mat.AllTiny(m, epsilon); //# if (isReal) { /// /// Returns whether the absolute value of each element of the given is smaller than Constant<__ftype__>.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(__nmtype__ m) => m.IsTiny; //# } #endregion //# if (isReal) { #region Special Floating Point Value Checks /// /// Returns whether any element of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(__nmtype__ v) => v.IsNaN; /// /// Returns whether any element of the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(__nmtype__ v) => v.IsInfinity; /// /// Returns whether any element of the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(__nmtype__ v) => v.IsPositiveInfinity; /// /// Returns whether any element of the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(__nmtype__ v) => v.IsNegativeInfinity; /// /// Returns whether all elements of the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(__nmtype__ v) => v.IsFinite; #endregion //# } } public static class IRandomUniform__nmtype__Extensions { #region IRandomUniform extensions for __nmtype__ //# string[] variants; //# if (t == 2) { //# variants = new string[] { "", "Closed", "Open" }; //# } else if (t == 3) { //# variants = new string[] { "", "Closed", "Open", "Full", "FullClosed", "FullOpen" }; //# } else { //# variants = new string[] { "", "NonZero" }; //# } //# foreach (var v in variants) { /// /// Uses Uniform__fcaps____v__() to generate the elements of an __nmtype__ matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Uniform__nmtype____v__(this IRandomUniform rnd) { return new __nmtype__(/*# n.ForEach(r => { */ /*# m.ForEach(c => { var rf = fields[r]; */rnd.Uniform__fcaps____v__()/*#}, comma);}, comma); */); } //# } //# if (!isReal) { /// /// Uses Uniform__fcaps__(__ftype__) to generate the elements of an __nmtype__ matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Uniform__nmtype__(this IRandomUniform rnd, __ftype__ size) { return new __nmtype__(/*# n.ForEach(r => { */ /*# m.ForEach(c => { var rf = fields[r]; */rnd.Uniform__fcaps__(size)/*#}, comma);}, comma); */); } /// /// Uses Uniform__fcaps__(__ftype__) to generate the elements of an __nmtype__ matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __nmtype__ Uniform__nmtype__(this IRandomUniform rnd, __nmtype__ size) { return new __nmtype__(/*# n.ForEach(r => { */ /*# m.ForEach(c => { var rf = fields[r]; */rnd.Uniform__fcaps__(size.M__r____c__)/*#}, comma);}, comma); */); } //# } #endregion } #endregion //# } // t //# } // m //# } // n } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Rot2_auto.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; namespace Aardvark.Base { #region Rot2f /// /// Represents a 2D rotation counterclockwise around the origin. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Rot2f : IEquatable { [DataMember] public float Angle; #region Constructors /// /// Constructs a transformation given a rotation angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot2f(float angleInRadians) { Angle = angleInRadians; } /// /// Constructs a copy of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot2f(Rot2f r) { Angle = r.Angle; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot2f(Rot2d r) { Angle = (float)r.Angle; } #endregion #region Constants /// /// Gets the identity transformation. /// public static Rot2f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Rot2f(0); } #endregion #region Properties /// /// Gets the inverse of this tranformation. /// public readonly Rot2f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Rot2f(-Angle); } #endregion #region Arithmetic operators /// /// Multiplies two transformations. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2f operator *(Rot2f r0, Rot2f r1) { return new Rot2f(r0.Angle + r1.Angle); } #region Rot / Vector Multiplication /// /// Multiplies a transformation with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator *(Rot2f rot, V2f vec) { float a = Fun.Cos(rot.Angle); float b = Fun.Sin(rot.Angle); return new V2f(a * vec.X + -b * vec.Y, b * vec.X + a * vec.Y); } #endregion #region Rot / Matrix Multiplication /// /// Multiplies a transformation (as a 2x2 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator *(Rot2f r, M22f m) { float a = Fun.Cos(r.Angle); float b = Fun.Sin(r.Angle); return new M22f( a * m.M00 + -b * m.M10, a * m.M01 + -b * m.M11, b * m.M00 + a * m.M10, b * m.M01 + a * m.M11); } /// /// Multiplies a with a transformation (as a 2x2 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator *(M22f m, Rot2f r) { float a = Fun.Cos(r.Angle); float b = Fun.Sin(r.Angle); return new M22f( m.M00 * a + m.M01 * b, m.M00 * -b + m.M01 * a, m.M10 * a + m.M11 * b, m.M10 * -b + m.M11 * a); } /// /// Multiplies a transformation (as a 2x2 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(Rot2f r, M23f m) { float a = Fun.Cos(r.Angle); float b = Fun.Sin(r.Angle); return new M23f( a * m.M00 + -b * m.M10, a * m.M01 + -b * m.M11, a * m.M02 + -b * m.M12, b * m.M00 + a * m.M10, b * m.M01 + a * m.M11, b * m.M02 + a * m.M12); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(M23f m, Rot2f r) { float a = Fun.Cos(r.Angle); float b = Fun.Sin(r.Angle); return new M23f( m.M00 * a + m.M01 * b, m.M00 * -b + m.M01 * a, m.M02, m.M10 * a + m.M11 * b, m.M10 * -b + m.M11 * a, m.M12); } /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator *(Rot2f r, M33f m) { float a = Fun.Cos(r.Angle); float b = Fun.Sin(r.Angle); return new M33f( a * m.M00 + -b * m.M10, a * m.M01 + -b * m.M11, a * m.M02 + -b * m.M12, b * m.M00 + a * m.M10, b * m.M01 + a * m.M11, b * m.M02 + a * m.M12, m.M20, m.M21, m.M22); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator *(M33f m, Rot2f r) { float a = Fun.Cos(r.Angle); float b = Fun.Sin(r.Angle); return new M33f( m.M00 * a + m.M01 * b, m.M00 * -b + m.M01 * a, m.M02, m.M10 * a + m.M11 * b, m.M10 * -b + m.M11 * a, m.M12, m.M20 * a + m.M21 * b, m.M20 * -b + m.M21 * a, m.M22); } #endregion #region Rot / Shift, Scale Multiplication /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f operator *(Rot2f a, Shift2f b) => new Euclidean2f(a, a * b.V); /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Rot2f a, Scale2f b) => new Affine2f((M22f)a * (M22f)b); #endregion #endregion #region Comparison Operators /// /// Checks if 2 rotations are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rot2f rotation1, Rot2f rotation2) => Rot.Distance(rotation1, rotation2) == 0; /// /// Checks if 2 rotations are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rot2f rotation1, Rot2f rotation2) => Rot.Distance(rotation1, rotation2) != 0; #endregion #region Static Creators /// /// Creates a transformation from a matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2f FromM22f(M22f m) { return new Rot2f(m.GetRotation()); } /// /// Creates a transformation from a matrix. /// The matrix has to be homogeneous and must not contain perspective components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2f FromM33f(M33f m, float epsilon = 1e-5f) { if (!(m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (!m.C2.XY.ApproximateEquals(V2f.Zero, epsilon)) throw new ArgumentException("Matrix contains translational component."); if (m.M22.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return FromM22f(((M22f)m) / m.M22); } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2f FromEuclidean2f(Euclidean2f euclidean, float epsilon = 1e-5f) { if (!euclidean.Trans.ApproximateEquals(V2f.Zero, epsilon)) throw new ArgumentException("Euclidean transformation contains translational component"); return euclidean.Rot; } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2f FromSimilarity2f(Similarity2f similarity, float epsilon = 1e-5f) { if (!similarity.Scale.ApproximateEquals(1, epsilon)) throw new ArgumentException("Similarity transformation contains scaling component"); if (!similarity.Trans.ApproximateEquals(V2f.Zero, epsilon)) throw new ArgumentException("Similarity transformation contains translational component"); return similarity.Rot; } /// /// Creates a transformation from an . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2f FromAffine2f(Affine2f affine, float epsilon = 1e-5f) => FromM33f((M33f)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2f FromTrafo2f(Trafo2f trafo, float epsilon = 1e-5f) => FromM33f(trafo.Forward, epsilon); /// /// Creates a transformation with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2f FromRadians(float angleInRadians) => new Rot2f(angleInRadians); /// /// Creates a transformation with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2f FromDegrees(float angleInDegrees) => new Rot2f(angleInDegrees.RadiansFromDegrees()); #endregion #region Conversion Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M22f(Rot2f r) { float a = Fun.Cos(r.Angle); float b = Fun.Sin(r.Angle); return new M22f( a, -b, b, a); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M23f(Rot2f r) { float a = Fun.Cos(r.Angle); float b = Fun.Sin(r.Angle); return new M23f( a, -b, 0, b, a, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33f(Rot2f r) { float a = Fun.Cos(r.Angle); float b = Fun.Sin(r.Angle); return new M33f( a, -b, 0, b, a, 0, 0, 0, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34f(Rot2f r) { float a = Fun.Cos(r.Angle); float b = Fun.Sin(r.Angle); return new M34f( a, -b, 0, 0, b, a, 0, 0, 0, 0, 1, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44f(Rot2f r) { float a = Fun.Cos(r.Angle); float b = Fun.Sin(r.Angle); return new M44f( a, -b, 0, 0, b, a, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Euclidean2f(Rot2f r) => new Euclidean2f(r, V2f.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Similarity2f(Rot2f r) => new Similarity2f(1, r, V2f.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine2f(Rot2f r) => new Affine2f((M22f)r); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo2f(Rot2f r) => new Trafo2f((M33f)r, (M33f)r.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Rot2d(Rot2f r) => new Rot2d((double)r.Angle); #endregion #region Overrides public override readonly int GetHashCode() { return Angle.GetHashCode(); } public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}]", Angle); } public static Rot2f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Rot2f( float.Parse(x[0], CultureInfo.InvariantCulture) ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Rot2f other) => Rot.Distance(this, other) == 0; public override readonly bool Equals(object other) => (other is Rot2f o) ? Equals(o) : false; #endregion } public static partial class Rot { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2f Inverse(Rot2f rot) => rot.Inverse; /// /// Inverts a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Rot2f rot) { rot.Angle = -rot.Angle; } #endregion #region Distance /// /// Returns the absolute difference in radians between two rotations. /// The result is within the range of [0, Pi]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance(this Rot2f r1, Rot2f r2) => Fun.AngleDistance(r1.Angle, r2.Angle); /// /// Returns the signed difference in radians between two rotations. /// The result is within the range of [-Pi, Pi). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Difference(this Rot2f r1, Rot2f r2) => Fun.AngleDifference(r1.Angle, r2.Angle); #endregion #region Transform /// /// Transforms a vector by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Transform(this Rot2f rot, V2f v) { return rot * v; } /// /// Transforms a vector by a transformation. /// The z coordinate of the vector is unaffected. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Transform(this Rot2f rot, V3f v) { float a = Fun.Cos(rot.Angle); float b = Fun.Sin(rot.Angle); return new V3f(a * v.X + -b * v.Y, b * v.X + a * v.Y, v.Z); } /// /// Transforms a vector by a transformation. /// The z and w coordinates of the vector are unaffected. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Transform(this Rot2f rot, V4f v) { float a = Fun.Cos(rot.Angle); float b = Fun.Sin(rot.Angle); return new V4f(a * v.X + -b * v.Y, b * v.X + a * v.Y, v.Z, v.W); } /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f InvTransform(this Rot2f rot, V2f v) { float a = Fun.Cos(-rot.Angle); float b = Fun.Sin(-rot.Angle); return new V2f(a * v.X + -b * v.Y, b * v.X + a * v.Y); } /// /// Transforms a vector by the inverse of a transformation. /// The z coordinate of the vector is unaffected. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvTransform(this Rot2f rot, V3f v) => Transform(rot.Inverse, v); /// /// Transforms a vector by the inverse of a transformation. /// The z and w coordinates of the vector are unaffected. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f InvTransform(this Rot2f rot, V4f v) => Transform(rot.Inverse, v); #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Rot2f r0, Rot2f r1) { return ApproximateEquals(r0, r1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Rot2f r0, Rot2f r1, float tolerance) { return Rot.Distance(r0, r1) <= tolerance; } #endregion } #endregion #region Rot2d /// /// Represents a 2D rotation counterclockwise around the origin. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Rot2d : IEquatable { [DataMember] public double Angle; #region Constructors /// /// Constructs a transformation given a rotation angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot2d(double angleInRadians) { Angle = angleInRadians; } /// /// Constructs a copy of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot2d(Rot2d r) { Angle = r.Angle; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot2d(Rot2f r) { Angle = (double)r.Angle; } #endregion #region Constants /// /// Gets the identity transformation. /// public static Rot2d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Rot2d(0); } #endregion #region Properties /// /// Gets the inverse of this tranformation. /// public readonly Rot2d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Rot2d(-Angle); } #endregion #region Arithmetic operators /// /// Multiplies two transformations. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2d operator *(Rot2d r0, Rot2d r1) { return new Rot2d(r0.Angle + r1.Angle); } #region Rot / Vector Multiplication /// /// Multiplies a transformation with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator *(Rot2d rot, V2d vec) { double a = Fun.Cos(rot.Angle); double b = Fun.Sin(rot.Angle); return new V2d(a * vec.X + -b * vec.Y, b * vec.X + a * vec.Y); } #endregion #region Rot / Matrix Multiplication /// /// Multiplies a transformation (as a 2x2 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator *(Rot2d r, M22d m) { double a = Fun.Cos(r.Angle); double b = Fun.Sin(r.Angle); return new M22d( a * m.M00 + -b * m.M10, a * m.M01 + -b * m.M11, b * m.M00 + a * m.M10, b * m.M01 + a * m.M11); } /// /// Multiplies a with a transformation (as a 2x2 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator *(M22d m, Rot2d r) { double a = Fun.Cos(r.Angle); double b = Fun.Sin(r.Angle); return new M22d( m.M00 * a + m.M01 * b, m.M00 * -b + m.M01 * a, m.M10 * a + m.M11 * b, m.M10 * -b + m.M11 * a); } /// /// Multiplies a transformation (as a 2x2 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(Rot2d r, M23d m) { double a = Fun.Cos(r.Angle); double b = Fun.Sin(r.Angle); return new M23d( a * m.M00 + -b * m.M10, a * m.M01 + -b * m.M11, a * m.M02 + -b * m.M12, b * m.M00 + a * m.M10, b * m.M01 + a * m.M11, b * m.M02 + a * m.M12); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(M23d m, Rot2d r) { double a = Fun.Cos(r.Angle); double b = Fun.Sin(r.Angle); return new M23d( m.M00 * a + m.M01 * b, m.M00 * -b + m.M01 * a, m.M02, m.M10 * a + m.M11 * b, m.M10 * -b + m.M11 * a, m.M12); } /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator *(Rot2d r, M33d m) { double a = Fun.Cos(r.Angle); double b = Fun.Sin(r.Angle); return new M33d( a * m.M00 + -b * m.M10, a * m.M01 + -b * m.M11, a * m.M02 + -b * m.M12, b * m.M00 + a * m.M10, b * m.M01 + a * m.M11, b * m.M02 + a * m.M12, m.M20, m.M21, m.M22); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator *(M33d m, Rot2d r) { double a = Fun.Cos(r.Angle); double b = Fun.Sin(r.Angle); return new M33d( m.M00 * a + m.M01 * b, m.M00 * -b + m.M01 * a, m.M02, m.M10 * a + m.M11 * b, m.M10 * -b + m.M11 * a, m.M12, m.M20 * a + m.M21 * b, m.M20 * -b + m.M21 * a, m.M22); } #endregion #region Rot / Shift, Scale Multiplication /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d operator *(Rot2d a, Shift2d b) => new Euclidean2d(a, a * b.V); /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Rot2d a, Scale2d b) => new Affine2d((M22d)a * (M22d)b); #endregion #endregion #region Comparison Operators /// /// Checks if 2 rotations are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rot2d rotation1, Rot2d rotation2) => Rot.Distance(rotation1, rotation2) == 0; /// /// Checks if 2 rotations are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rot2d rotation1, Rot2d rotation2) => Rot.Distance(rotation1, rotation2) != 0; #endregion #region Static Creators /// /// Creates a transformation from a matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2d FromM22d(M22d m) { return new Rot2d(m.GetRotation()); } /// /// Creates a transformation from a matrix. /// The matrix has to be homogeneous and must not contain perspective components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2d FromM33d(M33d m, double epsilon = 1e-12) { if (!(m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (!m.C2.XY.ApproximateEquals(V2d.Zero, epsilon)) throw new ArgumentException("Matrix contains translational component."); if (m.M22.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return FromM22d(((M22d)m) / m.M22); } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2d FromEuclidean2d(Euclidean2d euclidean, double epsilon = 1e-12) { if (!euclidean.Trans.ApproximateEquals(V2d.Zero, epsilon)) throw new ArgumentException("Euclidean transformation contains translational component"); return euclidean.Rot; } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2d FromSimilarity2d(Similarity2d similarity, double epsilon = 1e-12) { if (!similarity.Scale.ApproximateEquals(1, epsilon)) throw new ArgumentException("Similarity transformation contains scaling component"); if (!similarity.Trans.ApproximateEquals(V2d.Zero, epsilon)) throw new ArgumentException("Similarity transformation contains translational component"); return similarity.Rot; } /// /// Creates a transformation from an . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2d FromAffine2d(Affine2d affine, double epsilon = 1e-12) => FromM33d((M33d)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2d FromTrafo2d(Trafo2d trafo, double epsilon = 1e-12) => FromM33d(trafo.Forward, epsilon); /// /// Creates a transformation with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2d FromRadians(double angleInRadians) => new Rot2d(angleInRadians); /// /// Creates a transformation with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2d FromDegrees(double angleInDegrees) => new Rot2d(angleInDegrees.RadiansFromDegrees()); #endregion #region Conversion Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M22d(Rot2d r) { double a = Fun.Cos(r.Angle); double b = Fun.Sin(r.Angle); return new M22d( a, -b, b, a); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M23d(Rot2d r) { double a = Fun.Cos(r.Angle); double b = Fun.Sin(r.Angle); return new M23d( a, -b, 0, b, a, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33d(Rot2d r) { double a = Fun.Cos(r.Angle); double b = Fun.Sin(r.Angle); return new M33d( a, -b, 0, b, a, 0, 0, 0, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34d(Rot2d r) { double a = Fun.Cos(r.Angle); double b = Fun.Sin(r.Angle); return new M34d( a, -b, 0, 0, b, a, 0, 0, 0, 0, 1, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44d(Rot2d r) { double a = Fun.Cos(r.Angle); double b = Fun.Sin(r.Angle); return new M44d( a, -b, 0, 0, b, a, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Euclidean2d(Rot2d r) => new Euclidean2d(r, V2d.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Similarity2d(Rot2d r) => new Similarity2d(1, r, V2d.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine2d(Rot2d r) => new Affine2d((M22d)r); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo2d(Rot2d r) => new Trafo2d((M33d)r, (M33d)r.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Rot2f(Rot2d r) => new Rot2f((float)r.Angle); #endregion #region Overrides public override readonly int GetHashCode() { return Angle.GetHashCode(); } public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}]", Angle); } public static Rot2d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Rot2d( double.Parse(x[0], CultureInfo.InvariantCulture) ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Rot2d other) => Rot.Distance(this, other) == 0; public override readonly bool Equals(object other) => (other is Rot2d o) ? Equals(o) : false; #endregion } public static partial class Rot { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot2d Inverse(Rot2d rot) => rot.Inverse; /// /// Inverts a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Rot2d rot) { rot.Angle = -rot.Angle; } #endregion #region Distance /// /// Returns the absolute difference in radians between two rotations. /// The result is within the range of [0, Pi]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this Rot2d r1, Rot2d r2) => Fun.AngleDistance(r1.Angle, r2.Angle); /// /// Returns the signed difference in radians between two rotations. /// The result is within the range of [-Pi, Pi). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Difference(this Rot2d r1, Rot2d r2) => Fun.AngleDifference(r1.Angle, r2.Angle); #endregion #region Transform /// /// Transforms a vector by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Transform(this Rot2d rot, V2d v) { return rot * v; } /// /// Transforms a vector by a transformation. /// The z coordinate of the vector is unaffected. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Transform(this Rot2d rot, V3d v) { double a = Fun.Cos(rot.Angle); double b = Fun.Sin(rot.Angle); return new V3d(a * v.X + -b * v.Y, b * v.X + a * v.Y, v.Z); } /// /// Transforms a vector by a transformation. /// The z and w coordinates of the vector are unaffected. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Transform(this Rot2d rot, V4d v) { double a = Fun.Cos(rot.Angle); double b = Fun.Sin(rot.Angle); return new V4d(a * v.X + -b * v.Y, b * v.X + a * v.Y, v.Z, v.W); } /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d InvTransform(this Rot2d rot, V2d v) { double a = Fun.Cos(-rot.Angle); double b = Fun.Sin(-rot.Angle); return new V2d(a * v.X + -b * v.Y, b * v.X + a * v.Y); } /// /// Transforms a vector by the inverse of a transformation. /// The z coordinate of the vector is unaffected. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvTransform(this Rot2d rot, V3d v) => Transform(rot.Inverse, v); /// /// Transforms a vector by the inverse of a transformation. /// The z and w coordinates of the vector are unaffected. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d InvTransform(this Rot2d rot, V4d v) => Transform(rot.Inverse, v); #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Rot2d r0, Rot2d r1) { return ApproximateEquals(r0, r1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Rot2d r0, Rot2d r1, double tolerance) { return Rot.Distance(r0, r1) <= tolerance; } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Rot2_template.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; namespace Aardvark.Base { //# Action comma = () => Out(", "); //# Action commaln = () => Out("," + Environment.NewLine); //# Action add = () => Out(" + "); //# Action and = () => Out(" && "); //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var v2t = "V2" + tc; //# var v3t = "V3" + tc; //# var v4t = "V4" + tc; //# var type = "Rot2" + tc; //# var type2 = "Rot2" + tc2; //# var rot3t = "Rot3" + tc; //# var scale2t = "Scale2" + tc; //# var shift2t = "Shift2" + tc; //# var affine2t = "Affine2" + tc; //# var similarity2t = "Similarity2" + tc; //# var euclidean2t = "Euclidean2" + tc; //# var trafo2t = "Trafo2" + tc; //# var m22t = "M22" + tc; //# var m23t = "M23" + tc; //# var m33t = "M33" + tc; //# var m34t = "M34" + tc; //# var m44t = "M44" + tc; //# var eps = isDouble ? "1e-12" : "1e-5f"; #region __type__ /// /// Represents a 2D rotation counterclockwise around the origin. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__> { [DataMember] public __ftype__ Angle; #region Constructors /// /// Constructs a transformation given a rotation angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__ angleInRadians) { Angle = angleInRadians; } /// /// Constructs a copy of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ r) { Angle = r.Angle; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ r) { Angle = (__ftype__)r.Angle; } #endregion #region Constants /// /// Gets the identity transformation. /// public static __type__ Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(0); } #endregion #region Properties /// /// Gets the inverse of this tranformation. /// public readonly __type__ Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(-Angle); } #endregion #region Arithmetic operators /// /// Multiplies two transformations. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ r0, __type__ r1) { return new __type__(r0.Angle + r1.Angle); } #region Rot / Vector Multiplication /// /// Multiplies a transformation with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ operator *(__type__ rot, __v2t__ vec) { __ftype__ a = Fun.Cos(rot.Angle); __ftype__ b = Fun.Sin(rot.Angle); return new __v2t__(a * vec.X + -b * vec.Y, b * vec.X + a * vec.Y); } #endregion #region Rot / Matrix Multiplication //# for (int n = 2; n <= 3; n++) { //# for (int m = n; m <= (n+1) && m <= 3; m++) { //# var mat = "M" + n + m + tc; //# var nsub2 = n - 2; //# var msub2 = m - 2; /// /// Multiplies a transformation (as a __n__x__n__ matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mat__ operator *(__type__ r, __mat__ m) { __ftype__ a = Fun.Cos(r.Angle); __ftype__ b = Fun.Sin(r.Angle); return new __mat__(/*# 2.ForEach(i => { m.ForEach(j => { */ //# var x = (i == 0) ? "a" : "b"; //# var y = (i == 0) ? "-b" : "a"; __x__ * m.M0__j__ + __y__ * m.M1__j__/*# }, comma); }, commaln); if (nsub2 > 0) {*/, /*# nsub2.ForEach(i => { var ip2 = i + 2; */ /*# m.ForEach(j => { */m.M__ip2____j__/*# }, comma); }, comma); }*/); } /// /// Multiplies a with a transformation (as a __m__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mat__ operator *(__mat__ m, __type__ r) { __ftype__ a = Fun.Cos(r.Angle); __ftype__ b = Fun.Sin(r.Angle); return new __mat__(/*# n.ForEach(i => { 2.ForEach(j => { */ //# var x = (j == 0) ? "a" : "-b"; //# var y = (j == 0) ? "b" : "a"; m.M__i__0 * __x__ + m.M__i__1 * __y__/*# }, comma); if (msub2 > 0) {*/, /*# msub2.ForEach(jj => { var jjp2 = jj + 2; */m.M__i____jjp2__/*# }, comma); } }, commaln);*/); } //# } } #endregion #region Rot / Shift, Scale Multiplication /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __euclidean2t__ operator *(__type__ a, __shift2t__ b) => new __euclidean2t__(a, a * b.V); /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __affine2t__ operator *(__type__ a, __scale2t__ b) => new __affine2t__((__m22t__)a * (__m22t__)b); #endregion #endregion #region Comparison Operators /// /// Checks if 2 rotations are equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ rotation1, __type__ rotation2) => Rot.Distance(rotation1, rotation2) == 0; /// /// Checks if 2 rotations are not equal. /// /// Result of comparison. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ rotation1, __type__ rotation2) => Rot.Distance(rotation1, rotation2) != 0; #endregion #region Static Creators /// /// Creates a transformation from a matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__m22t__(__m22t__ m) { return new __type__(m.GetRotation()); } /// /// Creates a transformation from a matrix. /// The matrix has to be homogeneous and must not contain perspective components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__m33t__(__m33t__ m, __ftype__ epsilon = __eps__) { if (!(/*#2.ForEach(j => {*/m.M2__j__.IsTiny(epsilon)/*# }, and);*/)) throw new ArgumentException("Matrix contains perspective components."); if (!m.C2.XY.ApproximateEquals(__v2t__.Zero, epsilon)) throw new ArgumentException("Matrix contains translational component."); if (m.M22.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return From__m22t__(((__m22t__)m) / m.M22); } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__euclidean2t__(__euclidean2t__ euclidean, __ftype__ epsilon = __eps__) { if (!euclidean.Trans.ApproximateEquals(__v2t__.Zero, epsilon)) throw new ArgumentException("Euclidean transformation contains translational component"); return euclidean.Rot; } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__similarity2t__(__similarity2t__ similarity, __ftype__ epsilon = __eps__) { if (!similarity.Scale.ApproximateEquals(1, epsilon)) throw new ArgumentException("Similarity transformation contains scaling component"); if (!similarity.Trans.ApproximateEquals(__v2t__.Zero, epsilon)) throw new ArgumentException("Similarity transformation contains translational component"); return similarity.Rot; } /// /// Creates a transformation from an . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__affine2t__(__affine2t__ affine, __ftype__ epsilon = __eps__) => From__m33t__((__m33t__)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__trafo2t__(__trafo2t__ trafo, __ftype__ epsilon = __eps__) => From__m33t__(trafo.Forward, epsilon); /// /// Creates a transformation with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromRadians(__ftype__ angleInRadians) => new __type__(angleInRadians); /// /// Creates a transformation with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromDegrees(__ftype__ angleInDegrees) => new __type__(angleInDegrees.RadiansFromDegrees()); #endregion #region Conversion Operators //# for (int n = 2; n <= 4; n++) { //# for (int m = n; m <= (n+1) && m <= 4; m++) { //# var mat = "M" + n + m + tc; //# string[,] val = new string[,] {{" a", "-b"}, {" b", " a"}}; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __mat__(__type__ r) { __ftype__ a = Fun.Cos(r.Angle); __ftype__ b = Fun.Sin(r.Angle); return new __mat__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var x = (i < 2 && j < 2) ? val[i, j] : ((i == j) ? " 1" : " 0"); */__x__/*# }, comma); }, comma);*/); } //# } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __euclidean2t__(__type__ r) => new __euclidean2t__(r, __v2t__.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __similarity2t__(__type__ r) => new __similarity2t__(1, r, __v2t__.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __affine2t__(__type__ r) => new __affine2t__((__m22t__)r); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __trafo2t__(__type__ r) => new __trafo2t__((__m33t__)r, (__m33t__)r.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type2__(__type__ r) => new __type2__((__ftype2__)r.Angle); #endregion #region Overrides public override readonly int GetHashCode() { return Angle.GetHashCode(); } public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}]", Angle); } public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__( __ftype__.Parse(x[0], CultureInfo.InvariantCulture) ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => Rot.Distance(this, other) == 0; public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; #endregion } public static partial class Rot { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Inverse(__type__ rot) => rot.Inverse; /// /// Inverts a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref __type__ rot) { rot.Angle = -rot.Angle; } #endregion #region Distance /// /// Returns the absolute difference in radians between two rotations. /// The result is within the range of [0, Pi]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Distance(this __type__ r1, __type__ r2) => Fun.AngleDistance(r1.Angle, r2.Angle); /// /// Returns the signed difference in radians between two rotations. /// The result is within the range of [-Pi, Pi). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Difference(this __type__ r1, __type__ r2) => Fun.AngleDifference(r1.Angle, r2.Angle); #endregion #region Transform /// /// Transforms a vector by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ Transform(this __type__ rot, __v2t__ v) { return rot * v; } /// /// Transforms a vector by a transformation. /// The z coordinate of the vector is unaffected. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ Transform(this __type__ rot, __v3t__ v) { __ftype__ a = Fun.Cos(rot.Angle); __ftype__ b = Fun.Sin(rot.Angle); return new __v3t__(a * v.X + -b * v.Y, b * v.X + a * v.Y, v.Z); } /// /// Transforms a vector by a transformation. /// The z and w coordinates of the vector are unaffected. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v4t__ Transform(this __type__ rot, __v4t__ v) { __ftype__ a = Fun.Cos(rot.Angle); __ftype__ b = Fun.Sin(rot.Angle); return new __v4t__(a * v.X + -b * v.Y, b * v.X + a * v.Y, v.Z, v.W); } /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v2t__ InvTransform(this __type__ rot, __v2t__ v) { __ftype__ a = Fun.Cos(-rot.Angle); __ftype__ b = Fun.Sin(-rot.Angle); return new __v2t__(a * v.X + -b * v.Y, b * v.X + a * v.Y); } /// /// Transforms a vector by the inverse of a transformation. /// The z coordinate of the vector is unaffected. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ InvTransform(this __type__ rot, __v3t__ v) => Transform(rot.Inverse, v); /// /// Transforms a vector by the inverse of a transformation. /// The z and w coordinates of the vector are unaffected. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v4t__ InvTransform(this __type__ rot, __v4t__ v) => Transform(rot.Inverse, v); #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ r0, __type__ r1) { return ApproximateEquals(r0, r1, Constant<__ftype__>.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ r0, __type__ r1, __ftype__ tolerance) { return Rot.Distance(r0, r1) <= tolerance; } #endregion } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Rot3_auto.cs ================================================ using System; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { #region Rot3f /// /// Represents a rotation in three dimensions using a unit quaternion. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Rot3f : IEquatable { /// /// Scalar (real) part of the quaternion. /// [DataMember] public float W; /// /// First component of vector (imaginary) part of the quaternion. /// [DataMember] public float X; /// /// Second component of vector (imaginary) part of the quaternion. /// [DataMember] public float Y; /// /// Third component of vector (imaginary) part of the quaternion. /// [DataMember] public float Z; #region Constructors /// /// Constructs a transformation from the quaternion (w, (x, y, z)). /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot3f(float w, float x, float y, float z) { W = w; X = x; Y = y; Z = z; Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-5f)); } /// /// Constructs a transformation from the quaternion (w, (v.x, v.y, v.z)). /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot3f(float w, V3f v) { W = w; X = v.X; Y = v.Y; Z = v.Z; Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-5f)); } /// /// Constructs a transformation from the quaternion . /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot3f(QuaternionF q) { W = q.W; X = q.X; Y = q.Y; Z = q.Z; Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-5f)); } /// /// Constructs a transformation from the quaternion . /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot3f(QuaternionD q) { W = (float)q.W; X = (float)q.X; Y = (float)q.Y; Z = (float)q.Z; Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-5f)); } /// /// Constructs a copy of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot3f(Rot3f r) { W = r.W; X = r.X; Y = r.Y; Z = r.Z; Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-5f)); } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot3f(Rot3d r) { W = (float)r.W; X = (float)r.X; Y = (float)r.Y; Z = (float)r.Z; Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-5f)); } /// /// Constructs a transformation from the quaternion (a[0], (a[1], a[2], a[3])). /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot3f(float[] a) { W = a[0]; X = a[1]; Y = a[2]; Z = a[3]; Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-5f)); } /// /// Constructs a transformation from the quaternion (a[start], (a[start + 1], a[start + 2], a[start + 3])). /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot3f(float[] a, int start) { W = a[start]; X = a[start + 1]; Y = a[start + 2]; Z = a[start + 3]; Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-5f)); } #endregion #region Properties /// /// Gets or sets the vector part (x, y, z) of this unit quaternion. /// [XmlIgnore] public V3f V { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3f(X, Y, Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value.X; Y = value.Y; Z = value.Z; } } /// /// Gets the squared norm (or squared length) of this . /// May not be exactly 1, due to numerical inaccuracy. /// public readonly float NormSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => W * W + X * X + Y * Y + Z * Z; } /// /// Gets the norm (or length) of this . /// May not be exactly 1, due to numerical inaccuracy. /// public readonly float Norm { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => NormSquared.Sqrt(); } /// /// Gets normalized (unit) quaternion from this /// public readonly Rot3f Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var rs = new Rot3f(this); rs.Normalize(); return rs; } } /// /// Gets the inverse of this transformation. /// public readonly Rot3f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-5f)); return new Rot3f(W, -X, -Y, -Z); } } #endregion #region Constants /// /// Gets the identity . /// public static Rot3f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Rot3f(1, 0, 0, 0); } #endregion #region Arithmetic Operators /// /// Returns the component-wise negation of a unit quaternion. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f operator -(Rot3f q) => new Rot3f(-q.W, -q.X, -q.Y, -q.Z); /// /// Multiplies two transformations. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f operator *(Rot3f a, Rot3f b) { return new Rot3f( a.W * b.W - a.X * b.X - a.Y * b.Y - a.Z * b.Z, a.W * b.X + a.X * b.W + a.Y * b.Z - a.Z * b.Y, a.W * b.Y + a.Y * b.W + a.Z * b.X - a.X * b.Z, a.W * b.Z + a.Z * b.W + a.X * b.Y - a.Y * b.X); } #region Rot / Vector Multiplication /// /// Transforms a vector by a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator *(Rot3f r, V3f v) { var w = -r.X * v.X - r.Y * v.Y - r.Z * v.Z; var x = r.W * v.X + r.Y * v.Z - r.Z * v.Y; var y = r.W * v.Y + r.Z * v.X - r.X * v.Z; var z = r.W * v.Z + r.X * v.Y - r.Y * v.X; return new V3f( -w * r.X + x * r.W - y * r.Z + z * r.Y, -w * r.Y + y * r.W - z * r.X + x * r.Z, -w * r.Z + z * r.W - x * r.Y + y * r.X); } #endregion #region Rot / Matrix Multiplication /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator *(Rot3f rot, M33f m) { return (M33f)rot * m; } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator *(M33f m, Rot3f rot) { return m * (M33f)rot; } /// /// Multiplies a transformation (as a 4x4 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator *(Rot3f rot, M44f m) { var r = (M33f)rot; return new M44f( r.M00 * m.M00 + r.M01 * m.M10 + r.M02 * m.M20, r.M00 * m.M01 + r.M01 * m.M11 + r.M02 * m.M21, r.M00 * m.M02 + r.M01 * m.M12 + r.M02 * m.M22, r.M00 * m.M03 + r.M01 * m.M13 + r.M02 * m.M23, r.M10 * m.M00 + r.M11 * m.M10 + r.M12 * m.M20, r.M10 * m.M01 + r.M11 * m.M11 + r.M12 * m.M21, r.M10 * m.M02 + r.M11 * m.M12 + r.M12 * m.M22, r.M10 * m.M03 + r.M11 * m.M13 + r.M12 * m.M23, r.M20 * m.M00 + r.M21 * m.M10 + r.M22 * m.M20, r.M20 * m.M01 + r.M21 * m.M11 + r.M22 * m.M21, r.M20 * m.M02 + r.M21 * m.M12 + r.M22 * m.M22, r.M20 * m.M03 + r.M21 * m.M13 + r.M22 * m.M23, m.M30, m.M31, m.M32, m.M33); } /// /// Multiplies a with a transformation (as a 4x4 matrix) . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator *(M44f m, Rot3f rot) { var r = (M33f)rot; return new M44f( m.M00 * r.M00 + m.M01 * r.M10 + m.M02 * r.M20, m.M00 * r.M01 + m.M01 * r.M11 + m.M02 * r.M21, m.M00 * r.M02 + m.M01 * r.M12 + m.M02 * r.M22, m.M03, m.M10 * r.M00 + m.M11 * r.M10 + m.M12 * r.M20, m.M10 * r.M01 + m.M11 * r.M11 + m.M12 * r.M21, m.M10 * r.M02 + m.M11 * r.M12 + m.M12 * r.M22, m.M13, m.M20 * r.M00 + m.M21 * r.M10 + m.M22 * r.M20, m.M20 * r.M01 + m.M21 * r.M11 + m.M22 * r.M21, m.M20 * r.M02 + m.M21 * r.M12 + m.M22 * r.M22, m.M23, m.M30 * r.M00 + m.M31 * r.M10 + m.M32 * r.M20, m.M30 * r.M01 + m.M31 * r.M11 + m.M32 * r.M21, m.M30 * r.M02 + m.M31 * r.M12 + m.M32 * r.M22, m.M33); } /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(Rot3f rot, M34f m) { return (M33f)rot * m; } /// /// Multiplies a with a transformation (as a 4x4 matrix) . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(M34f m, Rot3f rot) { var r = (M33f)rot; return new M34f( m.M00 * r.M00 + m.M01 * r.M10 + m.M02 * r.M20, m.M00 * r.M01 + m.M01 * r.M11 + m.M02 * r.M21, m.M00 * r.M02 + m.M01 * r.M12 + m.M02 * r.M22, m.M03, m.M10 * r.M00 + m.M11 * r.M10 + m.M12 * r.M20, m.M10 * r.M01 + m.M11 * r.M11 + m.M12 * r.M21, m.M10 * r.M02 + m.M11 * r.M12 + m.M12 * r.M22, m.M13, m.M20 * r.M00 + m.M21 * r.M10 + m.M22 * r.M20, m.M20 * r.M01 + m.M21 * r.M11 + m.M22 * r.M21, m.M20 * r.M02 + m.M21 * r.M12 + m.M22 * r.M22, m.M23); } #endregion #region Rot / Quaternion arithmetics /// /// Returns the sum of a and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator +(Rot3f r, QuaternionF q) => new QuaternionF(r.W + q.W, r.X + q.X, r.Y + q.Y, r.Z + q.Z); /// /// Returns the sum of a and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator +(QuaternionF q, Rot3f r) => new QuaternionF(q.W + r.W, q.X + r.X, q.Y + r.Y, q.Z + r.Z); /// /// Returns the sum of a and a real scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator +(Rot3f r, float s) => new QuaternionF(r.W + s, r.X, r.Y, r.Z); /// /// Returns the sum of a real scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator +(float s, Rot3f r) => new QuaternionF(r.W + s, r.X, r.Y, r.Z); /// /// Returns the difference between a and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator -(Rot3f r, QuaternionF q) => new QuaternionF(r.W - q.W, r.X - q.X, r.Y - q.Y, r.Z - q.Z); /// /// Returns the difference between a and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator -(QuaternionF q, Rot3f r) => new QuaternionF(q.W - r.W, q.X - r.X, q.Y - r.Y, q.Z - r.Z); /// /// Returns the difference between a and a real scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator -(Rot3f r, float s) => new QuaternionF(r.W - s, r.X, r.Y, r.Z); /// /// Returns the difference between a real scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator -(float s, Rot3f r) => new QuaternionF(s - r.W, -r.X, -r.Y, -r.Z); /// /// Returns the product of a and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator *(Rot3f r, float s) => new QuaternionF(r.W * s, r.X * s, r.Y * s, r.Z * s); /// /// Returns the product of a scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator *(float s, Rot3f r) => new QuaternionF(r.W * s, r.X * s, r.Y * s, r.Z * s); /// /// Multiplies a with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator *(Rot3f r, QuaternionF q) { return new QuaternionF( r.W * q.W - r.X * q.X - r.Y * q.Y - r.Z * q.Z, r.W * q.X + r.X * q.W + r.Y * q.Z - r.Z * q.Y, r.W * q.Y + r.Y * q.W + r.Z * q.X - r.X * q.Z, r.W * q.Z + r.Z * q.W + r.X * q.Y - r.Y * q.X); } /// /// Multiplies a with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator *(QuaternionF q, Rot3f r) { return new QuaternionF( q.W * r.W - q.X * r.X - q.Y * r.Y - q.Z * r.Z, q.W * r.X + q.X * r.W + q.Y * r.Z - q.Z * r.Y, q.W * r.Y + q.Y * r.W + q.Z * r.X - q.X * r.Z, q.W * r.Z + q.Z * r.W + q.X * r.Y - q.Y * r.X); } /// /// Divides a by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator /(Rot3f r, QuaternionF q) => r * q.Inverse; /// /// Divides a by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator /(QuaternionF q, Rot3f r) => q * r.Inverse; /// /// Divides a by a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator /(Rot3f r, float s) => new QuaternionF(r.W / s, r.X / s, r.Y / s, r.Z / s); /// /// Divides a scalar by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionF operator /(float s, Rot3f r) => new QuaternionF(s / r.W, s / r.X, s / r.Y, s / r.Z); #endregion #region Rot / Shift, Scale Multiplication /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f operator *(Rot3f a, Shift3f b) => new Euclidean3f(a, a * b.V); /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Rot3f a, Scale3f b) => new Affine3f((M33f)a * (M33f)b); #endregion #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rot3f r0, Rot3f r1) => Rot.Distance(r0, r1) == 0; /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rot3f r0, Rot3f r1) => !(r0 == r1); #endregion #region Static Creators /// /// Creates a transformation from an orthonormal basis. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f FromFrame(V3f x, V3f y, V3f z) { return FromM33f(M33f.FromCols(x, y, z)); } /// /// Creates a transformation from a Rodrigues axis-angle vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f FromAngleAxis(V3f angleAxis) { float theta2 = angleAxis.LengthSquared; if (theta2 > Constant.PositiveTinyValue) { var theta = Fun.Sqrt(theta2); var thetaHalf = theta / 2; var k = Fun.Sin(thetaHalf) / theta; return new Rot3f(Fun.Cos(thetaHalf), k * angleAxis); } else return new Rot3f(1, 0, 0, 0); } /// /// Creates a transformation from a rotation matrix. /// The matrix must be orthonormal. /// /// public static Rot3f FromM33f(M33f m, float epsilon = (float)1e-6) { if (!m.IsOrthonormal(epsilon)) throw new ArgumentException("Matrix is not orthonormal."); var tr = m.M00 + m.M11 + m.M22; if (tr > 0) { float s = (tr + 1).Sqrt() * 2; float x = (m.M21 - m.M12) / s; float y = (m.M02 - m.M20) / s; float z = (m.M10 - m.M01) / s; float w = s / 4; return new Rot3f(new QuaternionF(w, x, y, z).Normalized); } else if (m.M00 > m.M11 && m.M00 > m.M22) { float s = Fun.Sqrt(1 + m.M00 - m.M11 - m.M22) * 2; float x = s / 4; float y = (m.M01 + m.M10) / s; float z = (m.M02 + m.M20) / s; float w = (m.M21 - m.M12) / s; return new Rot3f(new QuaternionF(w, x, y, z).Normalized); } else if (m.M11 > m.M22) { float s = Fun.Sqrt(1 + m.M11 - m.M00 - m.M22) * 2; float x = (m.M01 + m.M10) / s; float y = s / 4; float z = (m.M12 + m.M21) / s; float w = (m.M02 - m.M20) / s; return new Rot3f(new QuaternionF(w, x, y, z).Normalized); } else { float s = Fun.Sqrt(1 + m.M22 - m.M00 - m.M11) * 2; float x = (m.M02 + m.M20) / s; float y = (m.M12 + m.M21) / s; float z = s / 4; float w = (m.M10 - m.M01) / s; return new Rot3f(new QuaternionF(w, x, y, z).Normalized); } } /// /// Creates a transformation from a matrix. /// The matrix has to be homogeneous and must not contain perspective components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f FromM44f(M44f m, float epsilon = 1e-5f) { if (!(m.M30.IsTiny(epsilon) && m.M31.IsTiny(epsilon) && m.M32.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (!m.C3.XYZ.ApproximateEquals(V3f.Zero, epsilon)) throw new ArgumentException("Matrix contains translational component."); if (m.M33.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return FromM33f(((M33f)m) / m.M33); } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f FromEuclidean3f(Euclidean3f euclidean, float epsilon = 1e-5f) { if (!euclidean.Trans.ApproximateEquals(V3f.Zero, epsilon)) throw new ArgumentException("Euclidean transformation contains translational component"); return euclidean.Rot; } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f FromSimilarity3f(Similarity3f similarity, float epsilon = 1e-5f) { if (!similarity.Scale.ApproximateEquals(1, epsilon)) throw new ArgumentException("Similarity transformation contains scaling component"); if (!similarity.Trans.ApproximateEquals(V3f.Zero, epsilon)) throw new ArgumentException("Similarity transformation contains translational component"); return similarity.Rot; } /// /// Creates a transformation from an . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f FromAffine3f(Affine3f affine, float epsilon = 1e-5f) => FromM44f((M44f)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f FromTrafo3f(Trafo3f trafo, float epsilon = 1e-5f) => FromM44f(trafo.Forward, epsilon); /// /// Creates a transformation representing a rotation around /// an axis by an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f Rotation(V3f normalizedAxis, float angleInRadians) { var halfAngle = angleInRadians / 2; var halfAngleSin = halfAngle.Sin(); return new Rot3f(halfAngle.Cos(), normalizedAxis * halfAngleSin); } /// /// Creates a transformation representing a rotation around /// an axis by an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f RotationInDegrees(V3f normalizedAxis, float angleInDegrees) => Rotation(normalizedAxis, angleInDegrees.RadiansFromDegrees()); /// /// Creates a transformation representing a rotation from one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f RotateInto(V3f from, V3f into) { var d = Vec.Dot(from, into); if (d.ApproximateEquals(-1)) return new Rot3f(0, from.AxisAlignedNormal()); else { QuaternionF q = new QuaternionF(d + 1, Vec.Cross(from, into)); return new Rot3f(q.Normalized); } } /// /// Creates a transformation by radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f RotationX(float angleInRadians) { var halfAngle = angleInRadians / 2; return new Rot3f(halfAngle.Cos(), new V3f(halfAngle.Sin(), 0, 0)); } /// /// Creates a transformation by degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f RotationXInDegrees(float angleInDegrees) => RotationX(angleInDegrees.RadiansFromDegrees()); /// /// Creates a transformation by radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f RotationY(float angleInRadians) { var halfAngle = angleInRadians / 2; return new Rot3f(halfAngle.Cos(), new V3f(0, halfAngle.Sin(), 0)); } /// /// Creates a transformation by degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f RotationYInDegrees(float angleInDegrees) => RotationY(angleInDegrees.RadiansFromDegrees()); /// /// Creates a transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f RotationZ(float angleInRadians) { var halfAngle = angleInRadians / 2; return new Rot3f(halfAngle.Cos(), new V3f(0, 0, halfAngle.Sin())); } /// /// Creates a transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f RotationZInDegrees(float angleInDegrees) => RotationZ(angleInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f RotationEuler(float rollInRadians, float pitchInRadians, float yawInRadians) { float rollHalf = rollInRadians / 2; float cr = Fun.Cos(rollHalf); float sr = Fun.Sin(rollHalf); float pitchHalf = pitchInRadians / 2; float cp = Fun.Cos(pitchHalf); float sp = Fun.Sin(pitchHalf); float yawHalf = yawInRadians / 2; float cy = Fun.Cos(yawHalf); float sy = Fun.Sin(yawHalf); return new Rot3f( cy * cp * cr + sy * sp * sr, cy * cp * sr - sy * sp * cr, sy * cp * sr + cy * sp * cr, sy * cp * cr - cy * sp * sr); } /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f RotationEulerInDegrees(float rollInDegrees, float pitchInDegrees, float yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f RotationEuler(V3f rollPitchYawInRadians) => RotationEuler(rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f RotationEulerInDegrees(V3f rollPitchYawInDegrees) => RotationEulerInDegrees(rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33f(Rot3f r) { //speed up by computing the multiplications only once (each is used 2 times below) float xx = r.X * r.X; float yy = r.Y * r.Y; float zz = r.Z * r.Z; float xy = r.X * r.Y; float xz = r.X * r.Z; float yz = r.Y * r.Z; float xw = r.X * r.W; float yw = r.Y * r.W; float zw = r.Z * r.W; return new M33f( 1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 2 * (xy + zw), 1 - 2 * (zz + xx), 2 * (yz - xw), 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (yy + xx)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34f(Rot3f r) { //speed up by computing the multiplications only once (each is used 2 times below) float xx = r.X * r.X; float yy = r.Y * r.Y; float zz = r.Z * r.Z; float xy = r.X * r.Y; float xz = r.X * r.Z; float yz = r.Y * r.Z; float xw = r.X * r.W; float yw = r.Y * r.W; float zw = r.Z * r.W; return new M34f( 1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0, 2 * (xy + zw), 1 - 2 * (zz + xx), 2 * (yz - xw), 0, 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (yy + xx), 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44f(Rot3f r) { //speed up by computing the multiplications only once (each is used 2 times below) float xx = r.X * r.X; float yy = r.Y * r.Y; float zz = r.Z * r.Z; float xy = r.X * r.Y; float xz = r.X * r.Z; float yz = r.Y * r.Z; float xw = r.X * r.W; float yw = r.Y * r.W; float zw = r.Z * r.W; return new M44f( 1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0, 2 * (xy + zw), 1 - 2 * (zz + xx), 2 * (yz - xw), 0, 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (yy + xx), 0, 0, 0, 0, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](Rot3f r) { float[] array = new float[4]; array[0] = r.W; array[1] = r.X; array[2] = r.Y; array[3] = r.Z; return array; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Euclidean3f(Rot3f r) => new Euclidean3f(r, V3f.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Similarity3f(Rot3f r) => new Similarity3f(1, r, V3f.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine3f(Rot3f r) => new Affine3f((M33f)r); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo3f(Rot3f r) => new Trafo3f((M44f)r, (M44f)r.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Rot3d(Rot3f r) => new Rot3d((double)r.W, (double)r.X, (double)r.Y, (double)r.Z); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator QuaternionF(Rot3f r) => new QuaternionF(r.W, r.X, r.Y, r.Z); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator QuaternionD(Rot3f r) => new QuaternionD((double)r.W, (double)r.X, (double)r.Y, (double)r.Z); #endregion #region Indexing /// /// Gets or sets the -th component of the unit quaternion with components (W, (X, Y, Z)). /// public unsafe float this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &W) { return ptr[i]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &W) { ptr[i] = value; } } } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(W, V); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Rot3f other) => Rot.Distance(this, other) == 0; public override readonly bool Equals(object other) => (other is Rot3f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", W, V); } public static Rot3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Rot3f(float.Parse(x[0], CultureInfo.InvariantCulture), V3f.Parse(x[1])); } #endregion } public static partial class Rot { #region Dot /// /// Returns the dot product of two unit quaternions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot(this Rot3f a, Rot3f b) { return a.W * b.W + a.X * b.X + a.Y * b.Y + a.Z * b.Z; } #endregion #region Distance /// /// Returns the absolute difference in radians between two rotations. /// The result is within the range of [0, Pi]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceFast(this Rot3f r1, Rot3f r2) { var d = Dot(r1, r2); return 2 * Fun.AcosClamped((d < 0) ? -d : d); } /// /// Returns the absolute difference in radians between two rotations /// using a numerically stable algorithm. /// The result is within the range of [0, Pi]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance(this Rot3f r1, Rot3f r2) { var q = r1.Inverse * r2; return 2 * Fun.Atan2(q.V.Length, (q.W < 0) ? -q.W : q.W); } #endregion #region Invert, Normalize /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f Inverse(Rot3f r) => r.Inverse; /// /// Inverts the given transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Rot3f r) { r.X = -r.X; r.Y = -r.Y; r.Z = -r.Z; } /// /// Returns a normalized copy of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3f Normalized(Rot3f r) => r.Normalized; /// /// Normalizes a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref Rot3f r) { var norm = r.Norm; if (norm > 0) { var scale = 1 / norm; r.W *= scale; r.X *= scale; r.Y *= scale; r.Z *= scale; } } #endregion #region Conversion /// /// Returns the Rodrigues angle-axis vector of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f ToAngleAxis(this Rot3f r) { var sinTheta2 = r.V.LengthSquared; if (sinTheta2 > Constant.PositiveTinyValue) { float sinTheta = Fun.Sqrt(sinTheta2); float cosTheta = r.W; float twoTheta = 2 * (cosTheta < 0 ? Fun.Atan2(-sinTheta, -cosTheta) : Fun.Atan2(sinTheta, cosTheta)); return r.V * (twoTheta / sinTheta); } else return V3f.Zero; } /// /// Returns the axis-angle representation of a transformation. /// /// A transformation. /// Output of normalized axis of rotation. /// Output of angle of rotation in radians about axis (Right Hand Rule). [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ToAxisAngle(this Rot3f r, ref V3f axis, ref float angleInRadians) { angleInRadians = 2 * Fun.Acos(r.W); var s = Fun.Sqrt(1 - r.W * r.W); // assuming quaternion normalised then w is less than 1, so term always positive. if (s < 0.001) { // test to avoid divide by zero, s is always positive due to sqrt // if s close to zero then direction of axis not important axis.X = r.X; // if it is important that axis is normalised then replace with x=1; y=z=0; axis.Y = r.Y; axis.Z = r.Z; } else { axis.X = r.X / s; // normalise axis axis.Y = r.Y / s; axis.Z = r.Z / s; } } #endregion #region Euler Angles /// /// Returns the Euler-Angles from the given as a vector. /// The vector components represent [roll (X), pitch (Y), yaw (Z)] with rotation order is Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetEulerAngles(this Rot3f r) { var test = r.W * r.Y - r.X * r.Z; if (test > 0.5f - Constant.PositiveTinyValue) // singularity at north pole { return new V3f( 2 * Fun.Atan2(r.X, r.W), ConstantF.PiHalf, 0); } if (test < -0.5f + Constant.PositiveTinyValue) // singularity at south pole { return new V3f( 2 * Fun.Atan2(r.X, r.W), -ConstantF.PiHalf, 0); } // From Wikipedia, conversion between quaternions and Euler angles. return new V3f( Fun.Atan2(2 * (r.W * r.X + r.Y * r.Z), 1 - 2 * (r.X * r.X + r.Y * r.Y)), Fun.AsinClamped(2 * test), Fun.Atan2(2 * (r.W * r.Z + r.X * r.Y), 1 - 2 * (r.Y * r.Y + r.Z * r.Z))); } #endregion #region Transformations /// /// Transforms a vector by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Transform(this Rot3f r, V3f v) => r * v; /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvTransform(this Rot3f r, V3f v) { var w = r.X * v.X + r.Y * v.Y + r.Z * v.Z; var x = r.W * v.X - r.Y * v.Z + r.Z * v.Y; var y = r.W * v.Y - r.Z * v.X + r.X * v.Z; var z = r.W * v.Z - r.X * v.Y + r.Y * v.X; return new V3f( w * r.X + x * r.W + y * r.Z - z * r.Y, w * r.Y + y * r.W + z * r.X - x * r.Z, w * r.Z + z * r.W + x * r.Y - y * r.X ); } #endregion #region Spherical Linear Interpolation /// /// Spherical linear interpolation. /// /// Assumes q1 and q2 are normalized and that t in [0,1]. /// /// This method interpolates along the shortest arc between q1 and q2. /// public static Rot3f SlerpShortest(this Rot3f q1, Rot3f q2, float t) { Rot3f q3 = q2; float cosomega = Dot(q1, q3); if (cosomega < 0) { cosomega = -cosomega; q3 = -q3; } if (cosomega >= 1) { // Special case: q1 and q2 are the same, so just return one of them. // This also catches the case where cosomega is very slightly > 1.0 return q1; } float sinomega = Fun.Sqrt(1 - cosomega * cosomega); Rot3f result; if (sinomega * float.MaxValue > 1) { float omega = Fun.Acos(cosomega); float s1 = Fun.Sin((1 - t) * omega) / sinomega; float s2 = Fun.Sin(t * omega) / sinomega; result = new Rot3f(s1 * q1 + s2 * q3); } else if (cosomega > 0) { // omega == 0 float s1 = 1 - t; float s2 = t; result = new Rot3f(s1 * q1 + s2 * q3); } else { // omega == -pi result = new Rot3f(q1.Z, -q1.Y, q1.X, -q1.W); float s1 = Fun.Sin((0.5f - t) * ConstantF.Pi); float s2 = Fun.Sin(t * ConstantF.Pi); result = new Rot3f(s1 * q1 + s2 * result); } return result; } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Rot3f r0, Rot3f r1) { return ApproximateEquals(r0, r1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Rot3f r0, Rot3f r1, float tolerance) { return Rot.Distance(r0, r1) <= tolerance; } #endregion } #endregion #region Rot3d /// /// Represents a rotation in three dimensions using a unit quaternion. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Rot3d : IEquatable { /// /// Scalar (real) part of the quaternion. /// [DataMember] public double W; /// /// First component of vector (imaginary) part of the quaternion. /// [DataMember] public double X; /// /// Second component of vector (imaginary) part of the quaternion. /// [DataMember] public double Y; /// /// Third component of vector (imaginary) part of the quaternion. /// [DataMember] public double Z; #region Constructors /// /// Constructs a transformation from the quaternion (w, (x, y, z)). /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot3d(double w, double x, double y, double z) { W = w; X = x; Y = y; Z = z; Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-10)); } /// /// Constructs a transformation from the quaternion (w, (v.x, v.y, v.z)). /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot3d(double w, V3d v) { W = w; X = v.X; Y = v.Y; Z = v.Z; Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-10)); } /// /// Constructs a transformation from the quaternion . /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot3d(QuaternionD q) { W = q.W; X = q.X; Y = q.Y; Z = q.Z; Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-10)); } /// /// Constructs a transformation from the quaternion . /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot3d(QuaternionF q) { W = (double)q.W; X = (double)q.X; Y = (double)q.Y; Z = (double)q.Z; Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-10)); } /// /// Constructs a copy of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot3d(Rot3d r) { W = r.W; X = r.X; Y = r.Y; Z = r.Z; Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-10)); } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot3d(Rot3f r) { W = (double)r.W; X = (double)r.X; Y = (double)r.Y; Z = (double)r.Z; Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-10)); } /// /// Constructs a transformation from the quaternion (a[0], (a[1], a[2], a[3])). /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot3d(double[] a) { W = a[0]; X = a[1]; Y = a[2]; Z = a[3]; Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-10)); } /// /// Constructs a transformation from the quaternion (a[start], (a[start + 1], a[start + 2], a[start + 3])). /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rot3d(double[] a, int start) { W = a[start]; X = a[start + 1]; Y = a[start + 2]; Z = a[start + 3]; Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-10)); } #endregion #region Properties /// /// Gets or sets the vector part (x, y, z) of this unit quaternion. /// [XmlIgnore] public V3d V { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new V3d(X, Y, Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value.X; Y = value.Y; Z = value.Z; } } /// /// Gets the squared norm (or squared length) of this . /// May not be exactly 1, due to numerical inaccuracy. /// public readonly double NormSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => W * W + X * X + Y * Y + Z * Z; } /// /// Gets the norm (or length) of this . /// May not be exactly 1, due to numerical inaccuracy. /// public readonly double Norm { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => NormSquared.Sqrt(); } /// /// Gets normalized (unit) quaternion from this /// public readonly Rot3d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var rs = new Rot3d(this); rs.Normalize(); return rs; } } /// /// Gets the inverse of this transformation. /// public readonly Rot3d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, 1e-10)); return new Rot3d(W, -X, -Y, -Z); } } #endregion #region Constants /// /// Gets the identity . /// public static Rot3d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Rot3d(1, 0, 0, 0); } #endregion #region Arithmetic Operators /// /// Returns the component-wise negation of a unit quaternion. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d operator -(Rot3d q) => new Rot3d(-q.W, -q.X, -q.Y, -q.Z); /// /// Multiplies two transformations. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d operator *(Rot3d a, Rot3d b) { return new Rot3d( a.W * b.W - a.X * b.X - a.Y * b.Y - a.Z * b.Z, a.W * b.X + a.X * b.W + a.Y * b.Z - a.Z * b.Y, a.W * b.Y + a.Y * b.W + a.Z * b.X - a.X * b.Z, a.W * b.Z + a.Z * b.W + a.X * b.Y - a.Y * b.X); } #region Rot / Vector Multiplication /// /// Transforms a vector by a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator *(Rot3d r, V3d v) { var w = -r.X * v.X - r.Y * v.Y - r.Z * v.Z; var x = r.W * v.X + r.Y * v.Z - r.Z * v.Y; var y = r.W * v.Y + r.Z * v.X - r.X * v.Z; var z = r.W * v.Z + r.X * v.Y - r.Y * v.X; return new V3d( -w * r.X + x * r.W - y * r.Z + z * r.Y, -w * r.Y + y * r.W - z * r.X + x * r.Z, -w * r.Z + z * r.W - x * r.Y + y * r.X); } #endregion #region Rot / Matrix Multiplication /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator *(Rot3d rot, M33d m) { return (M33d)rot * m; } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator *(M33d m, Rot3d rot) { return m * (M33d)rot; } /// /// Multiplies a transformation (as a 4x4 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator *(Rot3d rot, M44d m) { var r = (M33d)rot; return new M44d( r.M00 * m.M00 + r.M01 * m.M10 + r.M02 * m.M20, r.M00 * m.M01 + r.M01 * m.M11 + r.M02 * m.M21, r.M00 * m.M02 + r.M01 * m.M12 + r.M02 * m.M22, r.M00 * m.M03 + r.M01 * m.M13 + r.M02 * m.M23, r.M10 * m.M00 + r.M11 * m.M10 + r.M12 * m.M20, r.M10 * m.M01 + r.M11 * m.M11 + r.M12 * m.M21, r.M10 * m.M02 + r.M11 * m.M12 + r.M12 * m.M22, r.M10 * m.M03 + r.M11 * m.M13 + r.M12 * m.M23, r.M20 * m.M00 + r.M21 * m.M10 + r.M22 * m.M20, r.M20 * m.M01 + r.M21 * m.M11 + r.M22 * m.M21, r.M20 * m.M02 + r.M21 * m.M12 + r.M22 * m.M22, r.M20 * m.M03 + r.M21 * m.M13 + r.M22 * m.M23, m.M30, m.M31, m.M32, m.M33); } /// /// Multiplies a with a transformation (as a 4x4 matrix) . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator *(M44d m, Rot3d rot) { var r = (M33d)rot; return new M44d( m.M00 * r.M00 + m.M01 * r.M10 + m.M02 * r.M20, m.M00 * r.M01 + m.M01 * r.M11 + m.M02 * r.M21, m.M00 * r.M02 + m.M01 * r.M12 + m.M02 * r.M22, m.M03, m.M10 * r.M00 + m.M11 * r.M10 + m.M12 * r.M20, m.M10 * r.M01 + m.M11 * r.M11 + m.M12 * r.M21, m.M10 * r.M02 + m.M11 * r.M12 + m.M12 * r.M22, m.M13, m.M20 * r.M00 + m.M21 * r.M10 + m.M22 * r.M20, m.M20 * r.M01 + m.M21 * r.M11 + m.M22 * r.M21, m.M20 * r.M02 + m.M21 * r.M12 + m.M22 * r.M22, m.M23, m.M30 * r.M00 + m.M31 * r.M10 + m.M32 * r.M20, m.M30 * r.M01 + m.M31 * r.M11 + m.M32 * r.M21, m.M30 * r.M02 + m.M31 * r.M12 + m.M32 * r.M22, m.M33); } /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(Rot3d rot, M34d m) { return (M33d)rot * m; } /// /// Multiplies a with a transformation (as a 4x4 matrix) . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(M34d m, Rot3d rot) { var r = (M33d)rot; return new M34d( m.M00 * r.M00 + m.M01 * r.M10 + m.M02 * r.M20, m.M00 * r.M01 + m.M01 * r.M11 + m.M02 * r.M21, m.M00 * r.M02 + m.M01 * r.M12 + m.M02 * r.M22, m.M03, m.M10 * r.M00 + m.M11 * r.M10 + m.M12 * r.M20, m.M10 * r.M01 + m.M11 * r.M11 + m.M12 * r.M21, m.M10 * r.M02 + m.M11 * r.M12 + m.M12 * r.M22, m.M13, m.M20 * r.M00 + m.M21 * r.M10 + m.M22 * r.M20, m.M20 * r.M01 + m.M21 * r.M11 + m.M22 * r.M21, m.M20 * r.M02 + m.M21 * r.M12 + m.M22 * r.M22, m.M23); } #endregion #region Rot / Quaternion arithmetics /// /// Returns the sum of a and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator +(Rot3d r, QuaternionD q) => new QuaternionD(r.W + q.W, r.X + q.X, r.Y + q.Y, r.Z + q.Z); /// /// Returns the sum of a and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator +(QuaternionD q, Rot3d r) => new QuaternionD(q.W + r.W, q.X + r.X, q.Y + r.Y, q.Z + r.Z); /// /// Returns the sum of a and a real scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator +(Rot3d r, double s) => new QuaternionD(r.W + s, r.X, r.Y, r.Z); /// /// Returns the sum of a real scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator +(double s, Rot3d r) => new QuaternionD(r.W + s, r.X, r.Y, r.Z); /// /// Returns the difference between a and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator -(Rot3d r, QuaternionD q) => new QuaternionD(r.W - q.W, r.X - q.X, r.Y - q.Y, r.Z - q.Z); /// /// Returns the difference between a and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator -(QuaternionD q, Rot3d r) => new QuaternionD(q.W - r.W, q.X - r.X, q.Y - r.Y, q.Z - r.Z); /// /// Returns the difference between a and a real scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator -(Rot3d r, double s) => new QuaternionD(r.W - s, r.X, r.Y, r.Z); /// /// Returns the difference between a real scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator -(double s, Rot3d r) => new QuaternionD(s - r.W, -r.X, -r.Y, -r.Z); /// /// Returns the product of a and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator *(Rot3d r, double s) => new QuaternionD(r.W * s, r.X * s, r.Y * s, r.Z * s); /// /// Returns the product of a scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator *(double s, Rot3d r) => new QuaternionD(r.W * s, r.X * s, r.Y * s, r.Z * s); /// /// Multiplies a with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator *(Rot3d r, QuaternionD q) { return new QuaternionD( r.W * q.W - r.X * q.X - r.Y * q.Y - r.Z * q.Z, r.W * q.X + r.X * q.W + r.Y * q.Z - r.Z * q.Y, r.W * q.Y + r.Y * q.W + r.Z * q.X - r.X * q.Z, r.W * q.Z + r.Z * q.W + r.X * q.Y - r.Y * q.X); } /// /// Multiplies a with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator *(QuaternionD q, Rot3d r) { return new QuaternionD( q.W * r.W - q.X * r.X - q.Y * r.Y - q.Z * r.Z, q.W * r.X + q.X * r.W + q.Y * r.Z - q.Z * r.Y, q.W * r.Y + q.Y * r.W + q.Z * r.X - q.X * r.Z, q.W * r.Z + q.Z * r.W + q.X * r.Y - q.Y * r.X); } /// /// Divides a by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator /(Rot3d r, QuaternionD q) => r * q.Inverse; /// /// Divides a by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator /(QuaternionD q, Rot3d r) => q * r.Inverse; /// /// Divides a by a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator /(Rot3d r, double s) => new QuaternionD(r.W / s, r.X / s, r.Y / s, r.Z / s); /// /// Divides a scalar by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static QuaternionD operator /(double s, Rot3d r) => new QuaternionD(s / r.W, s / r.X, s / r.Y, s / r.Z); #endregion #region Rot / Shift, Scale Multiplication /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d operator *(Rot3d a, Shift3d b) => new Euclidean3d(a, a * b.V); /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Rot3d a, Scale3d b) => new Affine3d((M33d)a * (M33d)b); #endregion #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rot3d r0, Rot3d r1) => Rot.Distance(r0, r1) == 0; /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rot3d r0, Rot3d r1) => !(r0 == r1); #endregion #region Static Creators /// /// Creates a transformation from an orthonormal basis. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d FromFrame(V3d x, V3d y, V3d z) { return FromM33d(M33d.FromCols(x, y, z)); } /// /// Creates a transformation from a Rodrigues axis-angle vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d FromAngleAxis(V3d angleAxis) { double theta2 = angleAxis.LengthSquared; if (theta2 > Constant.PositiveTinyValue) { var theta = Fun.Sqrt(theta2); var thetaHalf = theta / 2; var k = Fun.Sin(thetaHalf) / theta; return new Rot3d(Fun.Cos(thetaHalf), k * angleAxis); } else return new Rot3d(1, 0, 0, 0); } /// /// Creates a transformation from a rotation matrix. /// The matrix must be orthonormal. /// /// public static Rot3d FromM33d(M33d m, double epsilon = (double)1e-6) { if (!m.IsOrthonormal(epsilon)) throw new ArgumentException("Matrix is not orthonormal."); var tr = m.M00 + m.M11 + m.M22; if (tr > 0) { double s = (tr + 1).Sqrt() * 2; double x = (m.M21 - m.M12) / s; double y = (m.M02 - m.M20) / s; double z = (m.M10 - m.M01) / s; double w = s / 4; return new Rot3d(new QuaternionD(w, x, y, z).Normalized); } else if (m.M00 > m.M11 && m.M00 > m.M22) { double s = Fun.Sqrt(1 + m.M00 - m.M11 - m.M22) * 2; double x = s / 4; double y = (m.M01 + m.M10) / s; double z = (m.M02 + m.M20) / s; double w = (m.M21 - m.M12) / s; return new Rot3d(new QuaternionD(w, x, y, z).Normalized); } else if (m.M11 > m.M22) { double s = Fun.Sqrt(1 + m.M11 - m.M00 - m.M22) * 2; double x = (m.M01 + m.M10) / s; double y = s / 4; double z = (m.M12 + m.M21) / s; double w = (m.M02 - m.M20) / s; return new Rot3d(new QuaternionD(w, x, y, z).Normalized); } else { double s = Fun.Sqrt(1 + m.M22 - m.M00 - m.M11) * 2; double x = (m.M02 + m.M20) / s; double y = (m.M12 + m.M21) / s; double z = s / 4; double w = (m.M10 - m.M01) / s; return new Rot3d(new QuaternionD(w, x, y, z).Normalized); } } /// /// Creates a transformation from a matrix. /// The matrix has to be homogeneous and must not contain perspective components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d FromM44d(M44d m, double epsilon = 1e-12) { if (!(m.M30.IsTiny(epsilon) && m.M31.IsTiny(epsilon) && m.M32.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (!m.C3.XYZ.ApproximateEquals(V3d.Zero, epsilon)) throw new ArgumentException("Matrix contains translational component."); if (m.M33.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return FromM33d(((M33d)m) / m.M33); } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d FromEuclidean3d(Euclidean3d euclidean, double epsilon = 1e-12) { if (!euclidean.Trans.ApproximateEquals(V3d.Zero, epsilon)) throw new ArgumentException("Euclidean transformation contains translational component"); return euclidean.Rot; } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d FromSimilarity3d(Similarity3d similarity, double epsilon = 1e-12) { if (!similarity.Scale.ApproximateEquals(1, epsilon)) throw new ArgumentException("Similarity transformation contains scaling component"); if (!similarity.Trans.ApproximateEquals(V3d.Zero, epsilon)) throw new ArgumentException("Similarity transformation contains translational component"); return similarity.Rot; } /// /// Creates a transformation from an . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d FromAffine3d(Affine3d affine, double epsilon = 1e-12) => FromM44d((M44d)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d FromTrafo3d(Trafo3d trafo, double epsilon = 1e-12) => FromM44d(trafo.Forward, epsilon); /// /// Creates a transformation representing a rotation around /// an axis by an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d Rotation(V3d normalizedAxis, double angleInRadians) { var halfAngle = angleInRadians / 2; var halfAngleSin = halfAngle.Sin(); return new Rot3d(halfAngle.Cos(), normalizedAxis * halfAngleSin); } /// /// Creates a transformation representing a rotation around /// an axis by an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d RotationInDegrees(V3d normalizedAxis, double angleInDegrees) => Rotation(normalizedAxis, angleInDegrees.RadiansFromDegrees()); /// /// Creates a transformation representing a rotation from one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d RotateInto(V3d from, V3d into) { var d = Vec.Dot(from, into); if (d.ApproximateEquals(-1)) return new Rot3d(0, from.AxisAlignedNormal()); else { QuaternionD q = new QuaternionD(d + 1, Vec.Cross(from, into)); return new Rot3d(q.Normalized); } } /// /// Creates a transformation by radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d RotationX(double angleInRadians) { var halfAngle = angleInRadians / 2; return new Rot3d(halfAngle.Cos(), new V3d(halfAngle.Sin(), 0, 0)); } /// /// Creates a transformation by degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d RotationXInDegrees(double angleInDegrees) => RotationX(angleInDegrees.RadiansFromDegrees()); /// /// Creates a transformation by radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d RotationY(double angleInRadians) { var halfAngle = angleInRadians / 2; return new Rot3d(halfAngle.Cos(), new V3d(0, halfAngle.Sin(), 0)); } /// /// Creates a transformation by degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d RotationYInDegrees(double angleInDegrees) => RotationY(angleInDegrees.RadiansFromDegrees()); /// /// Creates a transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d RotationZ(double angleInRadians) { var halfAngle = angleInRadians / 2; return new Rot3d(halfAngle.Cos(), new V3d(0, 0, halfAngle.Sin())); } /// /// Creates a transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d RotationZInDegrees(double angleInDegrees) => RotationZ(angleInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d RotationEuler(double rollInRadians, double pitchInRadians, double yawInRadians) { double rollHalf = rollInRadians / 2; double cr = Fun.Cos(rollHalf); double sr = Fun.Sin(rollHalf); double pitchHalf = pitchInRadians / 2; double cp = Fun.Cos(pitchHalf); double sp = Fun.Sin(pitchHalf); double yawHalf = yawInRadians / 2; double cy = Fun.Cos(yawHalf); double sy = Fun.Sin(yawHalf); return new Rot3d( cy * cp * cr + sy * sp * sr, cy * cp * sr - sy * sp * cr, sy * cp * sr + cy * sp * cr, sy * cp * cr - cy * sp * sr); } /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d RotationEulerInDegrees(double rollInDegrees, double pitchInDegrees, double yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d RotationEuler(V3d rollPitchYawInRadians) => RotationEuler(rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d RotationEulerInDegrees(V3d rollPitchYawInDegrees) => RotationEulerInDegrees(rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33d(Rot3d r) { //speed up by computing the multiplications only once (each is used 2 times below) double xx = r.X * r.X; double yy = r.Y * r.Y; double zz = r.Z * r.Z; double xy = r.X * r.Y; double xz = r.X * r.Z; double yz = r.Y * r.Z; double xw = r.X * r.W; double yw = r.Y * r.W; double zw = r.Z * r.W; return new M33d( 1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 2 * (xy + zw), 1 - 2 * (zz + xx), 2 * (yz - xw), 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (yy + xx)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34d(Rot3d r) { //speed up by computing the multiplications only once (each is used 2 times below) double xx = r.X * r.X; double yy = r.Y * r.Y; double zz = r.Z * r.Z; double xy = r.X * r.Y; double xz = r.X * r.Z; double yz = r.Y * r.Z; double xw = r.X * r.W; double yw = r.Y * r.W; double zw = r.Z * r.W; return new M34d( 1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0, 2 * (xy + zw), 1 - 2 * (zz + xx), 2 * (yz - xw), 0, 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (yy + xx), 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44d(Rot3d r) { //speed up by computing the multiplications only once (each is used 2 times below) double xx = r.X * r.X; double yy = r.Y * r.Y; double zz = r.Z * r.Z; double xy = r.X * r.Y; double xz = r.X * r.Z; double yz = r.Y * r.Z; double xw = r.X * r.W; double yw = r.Y * r.W; double zw = r.Z * r.W; return new M44d( 1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0, 2 * (xy + zw), 1 - 2 * (zz + xx), 2 * (yz - xw), 0, 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (yy + xx), 0, 0, 0, 0, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](Rot3d r) { double[] array = new double[4]; array[0] = r.W; array[1] = r.X; array[2] = r.Y; array[3] = r.Z; return array; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Euclidean3d(Rot3d r) => new Euclidean3d(r, V3d.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Similarity3d(Rot3d r) => new Similarity3d(1, r, V3d.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine3d(Rot3d r) => new Affine3d((M33d)r); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo3d(Rot3d r) => new Trafo3d((M44d)r, (M44d)r.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Rot3f(Rot3d r) => new Rot3f((float)r.W, (float)r.X, (float)r.Y, (float)r.Z); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator QuaternionD(Rot3d r) => new QuaternionD(r.W, r.X, r.Y, r.Z); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator QuaternionF(Rot3d r) => new QuaternionF((float)r.W, (float)r.X, (float)r.Y, (float)r.Z); #endregion #region Indexing /// /// Gets or sets the -th component of the unit quaternion with components (W, (X, Y, Z)). /// public unsafe double this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &W) { return ptr[i]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &W) { ptr[i] = value; } } } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(W, V); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Rot3d other) => Rot.Distance(this, other) == 0; public override readonly bool Equals(object other) => (other is Rot3d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", W, V); } public static Rot3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Rot3d(double.Parse(x[0], CultureInfo.InvariantCulture), V3d.Parse(x[1])); } #endregion } public static partial class Rot { #region Dot /// /// Returns the dot product of two unit quaternions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Dot(this Rot3d a, Rot3d b) { return a.W * b.W + a.X * b.X + a.Y * b.Y + a.Z * b.Z; } #endregion #region Distance /// /// Returns the absolute difference in radians between two rotations. /// The result is within the range of [0, Pi]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceFast(this Rot3d r1, Rot3d r2) { var d = Dot(r1, r2); return 2 * Fun.AcosClamped((d < 0) ? -d : d); } /// /// Returns the absolute difference in radians between two rotations /// using a numerically stable algorithm. /// The result is within the range of [0, Pi]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this Rot3d r1, Rot3d r2) { var q = r1.Inverse * r2; return 2 * Fun.Atan2(q.V.Length, (q.W < 0) ? -q.W : q.W); } #endregion #region Invert, Normalize /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d Inverse(Rot3d r) => r.Inverse; /// /// Inverts the given transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Rot3d r) { r.X = -r.X; r.Y = -r.Y; r.Z = -r.Z; } /// /// Returns a normalized copy of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rot3d Normalized(Rot3d r) => r.Normalized; /// /// Normalizes a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref Rot3d r) { var norm = r.Norm; if (norm > 0) { var scale = 1 / norm; r.W *= scale; r.X *= scale; r.Y *= scale; r.Z *= scale; } } #endregion #region Conversion /// /// Returns the Rodrigues angle-axis vector of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d ToAngleAxis(this Rot3d r) { var sinTheta2 = r.V.LengthSquared; if (sinTheta2 > Constant.PositiveTinyValue) { double sinTheta = Fun.Sqrt(sinTheta2); double cosTheta = r.W; double twoTheta = 2 * (cosTheta < 0 ? Fun.Atan2(-sinTheta, -cosTheta) : Fun.Atan2(sinTheta, cosTheta)); return r.V * (twoTheta / sinTheta); } else return V3d.Zero; } /// /// Returns the axis-angle representation of a transformation. /// /// A transformation. /// Output of normalized axis of rotation. /// Output of angle of rotation in radians about axis (Right Hand Rule). [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ToAxisAngle(this Rot3d r, ref V3d axis, ref double angleInRadians) { angleInRadians = 2 * Fun.Acos(r.W); var s = Fun.Sqrt(1 - r.W * r.W); // assuming quaternion normalised then w is less than 1, so term always positive. if (s < 0.001) { // test to avoid divide by zero, s is always positive due to sqrt // if s close to zero then direction of axis not important axis.X = r.X; // if it is important that axis is normalised then replace with x=1; y=z=0; axis.Y = r.Y; axis.Z = r.Z; } else { axis.X = r.X / s; // normalise axis axis.Y = r.Y / s; axis.Z = r.Z / s; } } #endregion #region Euler Angles /// /// Returns the Euler-Angles from the given as a vector. /// The vector components represent [roll (X), pitch (Y), yaw (Z)] with rotation order is Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetEulerAngles(this Rot3d r) { var test = r.W * r.Y - r.X * r.Z; if (test > 0.5 - Constant.PositiveTinyValue) // singularity at north pole { return new V3d( 2 * Fun.Atan2(r.X, r.W), Constant.PiHalf, 0); } if (test < -0.5 + Constant.PositiveTinyValue) // singularity at south pole { return new V3d( 2 * Fun.Atan2(r.X, r.W), -Constant.PiHalf, 0); } // From Wikipedia, conversion between quaternions and Euler angles. return new V3d( Fun.Atan2(2 * (r.W * r.X + r.Y * r.Z), 1 - 2 * (r.X * r.X + r.Y * r.Y)), Fun.AsinClamped(2 * test), Fun.Atan2(2 * (r.W * r.Z + r.X * r.Y), 1 - 2 * (r.Y * r.Y + r.Z * r.Z))); } #endregion #region Transformations /// /// Transforms a vector by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Transform(this Rot3d r, V3d v) => r * v; /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvTransform(this Rot3d r, V3d v) { var w = r.X * v.X + r.Y * v.Y + r.Z * v.Z; var x = r.W * v.X - r.Y * v.Z + r.Z * v.Y; var y = r.W * v.Y - r.Z * v.X + r.X * v.Z; var z = r.W * v.Z - r.X * v.Y + r.Y * v.X; return new V3d( w * r.X + x * r.W + y * r.Z - z * r.Y, w * r.Y + y * r.W + z * r.X - x * r.Z, w * r.Z + z * r.W + x * r.Y - y * r.X ); } #endregion #region Spherical Linear Interpolation /// /// Spherical linear interpolation. /// /// Assumes q1 and q2 are normalized and that t in [0,1]. /// /// This method interpolates along the shortest arc between q1 and q2. /// public static Rot3d SlerpShortest(this Rot3d q1, Rot3d q2, double t) { Rot3d q3 = q2; double cosomega = Dot(q1, q3); if (cosomega < 0) { cosomega = -cosomega; q3 = -q3; } if (cosomega >= 1) { // Special case: q1 and q2 are the same, so just return one of them. // This also catches the case where cosomega is very slightly > 1.0 return q1; } double sinomega = Fun.Sqrt(1 - cosomega * cosomega); Rot3d result; if (sinomega * double.MaxValue > 1) { double omega = Fun.Acos(cosomega); double s1 = Fun.Sin((1 - t) * omega) / sinomega; double s2 = Fun.Sin(t * omega) / sinomega; result = new Rot3d(s1 * q1 + s2 * q3); } else if (cosomega > 0) { // omega == 0 double s1 = 1 - t; double s2 = t; result = new Rot3d(s1 * q1 + s2 * q3); } else { // omega == -pi result = new Rot3d(q1.Z, -q1.Y, q1.X, -q1.W); double s1 = Fun.Sin((0.5 - t) * Constant.Pi); double s2 = Fun.Sin(t * Constant.Pi); result = new Rot3d(s1 * q1 + s2 * result); } return result; } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Rot3d r0, Rot3d r1) { return ApproximateEquals(r0, r1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Rot3d r0, Rot3d r1, double tolerance) { return Rot.Distance(r0, r1) <= tolerance; } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Rot3_template.cs ================================================ using System; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { //# Action comma = () => Out(", "); //# Action commaln = () => Out("," + Environment.NewLine); //# Action add = () => Out(" + "); //# Action and = () => Out(" && "); //# Action or = () => Out(" || "); //# Action andLit = () => Out(" and "); //# var qfields = new[] {"W", "X", "Y", "Z"}; //# var qfieldsL = new[] {"w", "x", "y", "z"}; //# foreach (var isDouble in new[] { false, true }) { //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Rot3" + tc; //# var type2 = "Rot3" + tc2; //# var quatt = "Quaternion" + tc.ToUpper(); //# var quatt2 = "Quaternion" + tc2.ToUpper(); //# var v2t = "V2" + tc; //# var v3t = "V3" + tc; //# var v4t = "V4" + tc; //# var rot2t = "Rot2" + tc; //# var scale3t = "Scale3" + tc; //# var shift3t = "Shift3" + tc; //# var affine3t = "Affine3" + tc; //# var similarity3t = "Similarity3" + tc; //# var euclidean3t = "Euclidean3" + tc; //# var trafo3t = "Trafo3" + tc; //# var m22t = "M22" + tc; //# var m23t = "M23" + tc; //# var m33t = "M33" + tc; //# var m34t = "M34" + tc; //# var m44t = "M44" + tc; //# var assertEps = isDouble ? "1e-10" : "1e-5f"; //# var half = isDouble ? "0.5" : "0.5f"; //# var pi = isDouble ? "Constant.Pi" : "ConstantF.Pi"; //# var piHalf = isDouble ? "Constant.PiHalf" : "ConstantF.PiHalf"; //# var assertNorm = "Debug.Assert(Fun.ApproximateEquals(NormSquared, 1, " + assertEps + "))"; //# var eps = isDouble ? "1e-12" : "1e-5f"; //# var getptr = "&" + qfields[0]; #region __type__ /// /// Represents a rotation in three dimensions using a unit quaternion. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__> { /// /// Scalar (real) part of the quaternion. /// [DataMember] public __ftype__ W; /// /// First component of vector (imaginary) part of the quaternion. /// [DataMember] public __ftype__ X; /// /// Second component of vector (imaginary) part of the quaternion. /// [DataMember] public __ftype__ Y; /// /// Third component of vector (imaginary) part of the quaternion. /// [DataMember] public __ftype__ Z; #region Constructors /// /// Constructs a transformation from the quaternion (w, (x, y, z)). /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__ w, __ftype__ x, __ftype__ y, __ftype__ z) { W = w; X = x; Y = y; Z = z; __assertNorm__; } /// /// Constructs a transformation from the quaternion (w, (v.x, v.y, v.z)). /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__ w, __v3t__ v) { W = w; X = v.X; Y = v.Y; Z = v.Z; __assertNorm__; } /// /// Constructs a transformation from the quaternion . /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__quatt__ q) { /*# qfields.ForEach(f => {*/__f__ = q.__f__; /*# });*/ __assertNorm__; } /// /// Constructs a transformation from the quaternion . /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__quatt2__ q) { /*# qfields.ForEach(f => {*/__f__ = (__ftype__)q.__f__; /*# });*/ __assertNorm__; } /// /// Constructs a copy of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ r) { /*# qfields.ForEach(f => {*/__f__ = r.__f__; /*# });*/ __assertNorm__; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ r) { /*# qfields.ForEach(f => {*/__f__ = (__ftype__)r.__f__; /*# });*/ __assertNorm__; } /// /// Constructs a transformation from the quaternion (a[0], (a[1], a[2], a[3])). /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__[] a) { W = a[0]; X = a[1]; Y = a[2]; Z = a[3]; __assertNorm__; } /// /// Constructs a transformation from the quaternion (a[start], (a[start + 1], a[start + 2], a[start + 3])). /// The quaternion must be of unit length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__[] a, int start) { W = a[start]; X = a[start + 1]; Y = a[start + 2]; Z = a[start + 3]; __assertNorm__; } #endregion #region Properties /// /// Gets or sets the vector part (x, y, z) of this unit quaternion. /// [XmlIgnore] public __v3t__ V { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return new __v3t__(X, Y, Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value.X; Y = value.Y; Z = value.Z; } } /// /// Gets the squared norm (or squared length) of this . /// May not be exactly 1, due to numerical inaccuracy. /// public readonly __ftype__ NormSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => /*# qfields.ForEach(f => {*/__f__ * __f__/*# }, add);*/; } /// /// Gets the norm (or length) of this . /// May not be exactly 1, due to numerical inaccuracy. /// public readonly __ftype__ Norm { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => NormSquared.Sqrt(); } /// /// Gets normalized (unit) quaternion from this /// public readonly __type__ Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var rs = new __type__(this); rs.Normalize(); return rs; } } /// /// Gets the inverse of this transformation. /// public readonly __type__ Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { __assertNorm__; return new __type__(W, -X, -Y, -Z); } } #endregion #region Constants /// /// Gets the identity . /// public static __type__ Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(1, 0, 0, 0); } #endregion #region Arithmetic Operators /// /// Returns the component-wise negation of a unit quaternion. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator -(__type__ q) => new __type__(/*# qfields.ForEach(f => {*/-q.__f__/*# }, comma);*/); /// /// Multiplies two transformations. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ a, __type__ b) { return new __type__( a.W * b.W - a.X * b.X - a.Y * b.Y - a.Z * b.Z, a.W * b.X + a.X * b.W + a.Y * b.Z - a.Z * b.Y, a.W * b.Y + a.Y * b.W + a.Z * b.X - a.X * b.Z, a.W * b.Z + a.Z * b.W + a.X * b.Y - a.Y * b.X); } #region Rot / Vector Multiplication /// /// Transforms a vector by a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ operator *(__type__ r, __v3t__ v) { var w = -r.X * v.X - r.Y * v.Y - r.Z * v.Z; var x = r.W * v.X + r.Y * v.Z - r.Z * v.Y; var y = r.W * v.Y + r.Z * v.X - r.X * v.Z; var z = r.W * v.Z + r.X * v.Y - r.Y * v.X; return new __v3t__( -w * r.X + x * r.W - y * r.Z + z * r.Y, -w * r.Y + y * r.W - z * r.X + x * r.Z, -w * r.Z + z * r.W - x * r.Y + y * r.X); } #endregion #region Rot / Matrix Multiplication /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __m33t__ operator *(__type__ rot, __m33t__ m) { return (__m33t__)rot * m; } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __m33t__ operator *(__m33t__ m, __type__ rot) { return m * (__m33t__)rot; } /// /// Multiplies a transformation (as a 4x4 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __m44t__ operator *(__type__ rot, __m44t__ m) { var r = (__m33t__)rot; return new __m44t__(/*# 3.ForEach(i => { 4.ForEach(j => {*/ /*# 3.ForEach(k => {*/r.M__i____k__ * m.M__k____j__/*# }, add); }, comma); }, commaln);*/, /*# 4.ForEach(j => {*/m.M__3____j__/*# }, comma);*/); } /// /// Multiplies a with a transformation (as a 4x4 matrix) . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __m44t__ operator *(__m44t__ m, __type__ rot) { var r = (__m33t__)rot; return new __m44t__(/*# 4.ForEach(i => { 3.ForEach(j => {*/ /*# 3.ForEach(k => {*/m.M__i____k__ * r.M__k____j__/*# }, add); }, comma);*/, m.M__i____3__/*# }, commaln);*/); } /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __m34t__ operator *(__type__ rot, __m34t__ m) { return (__m33t__)rot * m; } /// /// Multiplies a with a transformation (as a 4x4 matrix) . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __m34t__ operator *(__m34t__ m, __type__ rot) { var r = (__m33t__)rot; return new __m34t__(/*# 3.ForEach(i => { 3.ForEach(j => {*/ /*# 3.ForEach(k => {*/m.M__i____k__ * r.M__k____j__/*# }, add); }, comma);*/, m.M__i____3__/*# }, commaln);*/); } #endregion #region Rot / Quaternion arithmetics /// /// Returns the sum of a and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __quatt__ operator +(__type__ r, __quatt__ q) => new __quatt__(/*# qfields.ForEach(f => {*/r.__f__ + q.__f__/*# }, comma);*/); /// /// Returns the sum of a and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __quatt__ operator +(__quatt__ q, __type__ r) => new __quatt__(/*# qfields.ForEach(f => {*/q.__f__ + r.__f__/*# }, comma);*/); /// /// Returns the sum of a and a real scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __quatt__ operator +(__type__ r, __ftype__ s) => new __quatt__(r.W + s, r.X, r.Y, r.Z); /// /// Returns the sum of a real scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __quatt__ operator +(__ftype__ s, __type__ r) => new __quatt__(r.W + s, r.X, r.Y, r.Z); /// /// Returns the difference between a and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __quatt__ operator -(__type__ r, __quatt__ q) => new __quatt__(/*# qfields.ForEach(f => {*/r.__f__ - q.__f__/*# }, comma);*/); /// /// Returns the difference between a and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __quatt__ operator -(__quatt__ q, __type__ r) => new __quatt__(/*# qfields.ForEach(f => {*/q.__f__ - r.__f__/*# }, comma);*/); /// /// Returns the difference between a and a real scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __quatt__ operator -(__type__ r, __ftype__ s) => new __quatt__(r.W - s, r.X, r.Y, r.Z); /// /// Returns the difference between a real scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __quatt__ operator -(__ftype__ s, __type__ r) => new __quatt__(s - r.W, -r.X, -r.Y, -r.Z); /// /// Returns the product of a and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __quatt__ operator *(__type__ r, __ftype__ s) => new __quatt__(/*# qfields.ForEach(f => {*/r.__f__ * s/*# }, comma);*/); /// /// Returns the product of a scalar and a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __quatt__ operator *(__ftype__ s, __type__ r) => new __quatt__(/*# qfields.ForEach(f => {*/r.__f__ * s/*# }, comma);*/); /// /// Multiplies a with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __quatt__ operator *(__type__ r, __quatt__ q) { return new __quatt__( r.W * q.W - r.X * q.X - r.Y * q.Y - r.Z * q.Z, r.W * q.X + r.X * q.W + r.Y * q.Z - r.Z * q.Y, r.W * q.Y + r.Y * q.W + r.Z * q.X - r.X * q.Z, r.W * q.Z + r.Z * q.W + r.X * q.Y - r.Y * q.X); } /// /// Multiplies a with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __quatt__ operator *(__quatt__ q, __type__ r) { return new __quatt__( q.W * r.W - q.X * r.X - q.Y * r.Y - q.Z * r.Z, q.W * r.X + q.X * r.W + q.Y * r.Z - q.Z * r.Y, q.W * r.Y + q.Y * r.W + q.Z * r.X - q.X * r.Z, q.W * r.Z + q.Z * r.W + q.X * r.Y - q.Y * r.X); } /// /// Divides a by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __quatt__ operator /(__type__ r, __quatt__ q) => r * q.Inverse; /// /// Divides a by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __quatt__ operator /(__quatt__ q, __type__ r) => q * r.Inverse; /// /// Divides a by a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __quatt__ operator /(__type__ r, __ftype__ s) => new __quatt__(/*# qfields.ForEach(f => {*/r.__f__ / s/*# }, comma);*/); /// /// Divides a scalar by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __quatt__ operator /(__ftype__ s, __type__ r) => new __quatt__(/*# qfields.ForEach(f => {*/s / r.__f__/*# }, comma);*/); #endregion #region Rot / Shift, Scale Multiplication /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __euclidean3t__ operator *(__type__ a, __shift3t__ b) => new __euclidean3t__(a, a * b.V); /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __affine3t__ operator *(__type__ a, __scale3t__ b) => new __affine3t__((__m33t__)a * (__m33t__)b); #endregion #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ r0, __type__ r1) => Rot.Distance(r0, r1) == 0; /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ r0, __type__ r1) => !(r0 == r1); #endregion #region Static Creators /// /// Creates a transformation from an orthonormal basis. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromFrame(__v3t__ x, __v3t__ y, __v3t__ z) { return From__m33t__(__m33t__.FromCols(x, y, z)); } /// /// Creates a transformation from a Rodrigues axis-angle vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromAngleAxis(__v3t__ angleAxis) { __ftype__ theta2 = angleAxis.LengthSquared; if (theta2 > Constant<__ftype__>.PositiveTinyValue) { var theta = Fun.Sqrt(theta2); var thetaHalf = theta / 2; var k = Fun.Sin(thetaHalf) / theta; return new __type__(Fun.Cos(thetaHalf), k * angleAxis); } else return new __type__(1, 0, 0, 0); } /// /// Creates a transformation from a rotation matrix. /// The matrix must be orthonormal. /// /// public static __type__ From__m33t__(__m33t__ m, __ftype__ epsilon = (__ftype__)1e-6) { if (!m.IsOrthonormal(epsilon)) throw new ArgumentException("Matrix is not orthonormal."); var tr = m.M00 + m.M11 + m.M22; if (tr > 0) { __ftype__ s = (tr + 1).Sqrt() * 2; __ftype__ x = (m.M21 - m.M12) / s; __ftype__ y = (m.M02 - m.M20) / s; __ftype__ z = (m.M10 - m.M01) / s; __ftype__ w = s / 4; return new __type__(new __quatt__(w, x, y, z).Normalized); } else if (m.M00 > m.M11 && m.M00 > m.M22) { __ftype__ s = Fun.Sqrt(1 + m.M00 - m.M11 - m.M22) * 2; __ftype__ x = s / 4; __ftype__ y = (m.M01 + m.M10) / s; __ftype__ z = (m.M02 + m.M20) / s; __ftype__ w = (m.M21 - m.M12) / s; return new __type__(new __quatt__(w, x, y, z).Normalized); } else if (m.M11 > m.M22) { __ftype__ s = Fun.Sqrt(1 + m.M11 - m.M00 - m.M22) * 2; __ftype__ x = (m.M01 + m.M10) / s; __ftype__ y = s / 4; __ftype__ z = (m.M12 + m.M21) / s; __ftype__ w = (m.M02 - m.M20) / s; return new __type__(new __quatt__(w, x, y, z).Normalized); } else { __ftype__ s = Fun.Sqrt(1 + m.M22 - m.M00 - m.M11) * 2; __ftype__ x = (m.M02 + m.M20) / s; __ftype__ y = (m.M12 + m.M21) / s; __ftype__ z = s / 4; __ftype__ w = (m.M10 - m.M01) / s; return new __type__(new __quatt__(w, x, y, z).Normalized); } } /// /// Creates a transformation from a matrix. /// The matrix has to be homogeneous and must not contain perspective components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__m44t__(__m44t__ m, __ftype__ epsilon = __eps__) { if (!(/*#3.ForEach(j => {*/m.M3__j__.IsTiny(epsilon)/*# }, and);*/)) throw new ArgumentException("Matrix contains perspective components."); if (!m.C3.XYZ.ApproximateEquals(__v3t__.Zero, epsilon)) throw new ArgumentException("Matrix contains translational component."); if (m.M33.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return From__m33t__(((__m33t__)m) / m.M33); } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__euclidean3t__(__euclidean3t__ euclidean, __ftype__ epsilon = __eps__) { if (!euclidean.Trans.ApproximateEquals(__v3t__.Zero, epsilon)) throw new ArgumentException("Euclidean transformation contains translational component"); return euclidean.Rot; } /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__similarity3t__(__similarity3t__ similarity, __ftype__ epsilon = __eps__) { if (!similarity.Scale.ApproximateEquals(1, epsilon)) throw new ArgumentException("Similarity transformation contains scaling component"); if (!similarity.Trans.ApproximateEquals(__v3t__.Zero, epsilon)) throw new ArgumentException("Similarity transformation contains translational component"); return similarity.Rot; } /// /// Creates a transformation from an . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__affine3t__(__affine3t__ affine, __ftype__ epsilon = __eps__) => From__m44t__((__m44t__)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a rotation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__trafo3t__(__trafo3t__ trafo, __ftype__ epsilon = __eps__) => From__m44t__(trafo.Forward, epsilon); /// /// Creates a transformation representing a rotation around /// an axis by an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Rotation(__v3t__ normalizedAxis, __ftype__ angleInRadians) { var halfAngle = angleInRadians / 2; var halfAngleSin = halfAngle.Sin(); return new __type__(halfAngle.Cos(), normalizedAxis * halfAngleSin); } /// /// Creates a transformation representing a rotation around /// an axis by an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationInDegrees(__v3t__ normalizedAxis, __ftype__ angleInDegrees) => Rotation(normalizedAxis, angleInDegrees.RadiansFromDegrees()); /// /// Creates a transformation representing a rotation from one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotateInto(__v3t__ from, __v3t__ into) { var d = Vec.Dot(from, into); if (d.ApproximateEquals(-1)) return new __type__(0, from.AxisAlignedNormal()); else { __quatt__ q = new __quatt__(d + 1, Vec.Cross(from, into)); return new __type__(q.Normalized); } } /// /// Creates a transformation by radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationX(__ftype__ angleInRadians) { var halfAngle = angleInRadians / 2; return new __type__(halfAngle.Cos(), new __v3t__(halfAngle.Sin(), 0, 0)); } /// /// Creates a transformation by degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationXInDegrees(__ftype__ angleInDegrees) => RotationX(angleInDegrees.RadiansFromDegrees()); /// /// Creates a transformation by radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationY(__ftype__ angleInRadians) { var halfAngle = angleInRadians / 2; return new __type__(halfAngle.Cos(), new __v3t__(0, halfAngle.Sin(), 0)); } /// /// Creates a transformation by degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationYInDegrees(__ftype__ angleInDegrees) => RotationY(angleInDegrees.RadiansFromDegrees()); /// /// Creates a transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationZ(__ftype__ angleInRadians) { var halfAngle = angleInRadians / 2; return new __type__(halfAngle.Cos(), new __v3t__(0, 0, halfAngle.Sin())); } /// /// Creates a transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationZInDegrees(__ftype__ angleInDegrees) => RotationZ(angleInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEuler(__ftype__ rollInRadians, __ftype__ pitchInRadians, __ftype__ yawInRadians) { __ftype__ rollHalf = rollInRadians / 2; __ftype__ cr = Fun.Cos(rollHalf); __ftype__ sr = Fun.Sin(rollHalf); __ftype__ pitchHalf = pitchInRadians / 2; __ftype__ cp = Fun.Cos(pitchHalf); __ftype__ sp = Fun.Sin(pitchHalf); __ftype__ yawHalf = yawInRadians / 2; __ftype__ cy = Fun.Cos(yawHalf); __ftype__ sy = Fun.Sin(yawHalf); return new __type__( cy * cp * cr + sy * sp * sr, cy * cp * sr - sy * sp * cr, sy * cp * sr + cy * sp * cr, sy * cp * cr - cy * sp * sr); } /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEulerInDegrees(__ftype__ rollInDegrees, __ftype__ pitchInDegrees, __ftype__ yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEuler(__v3t__ rollPitchYawInRadians) => RotationEuler(rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEulerInDegrees(__v3t__ rollPitchYawInDegrees) => RotationEulerInDegrees(rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); #endregion #region Conversion //# for (int n = 3; n <= 4; n++) { //# for (int m = n; m <= (n+1) && m <= 4; m++) { //# var mat = "M" + n + m + tc; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __mat__(__type__ r) { //speed up by computing the multiplications only once (each is used 2 times below) __ftype__ xx = r.X * r.X; __ftype__ yy = r.Y * r.Y; __ftype__ zz = r.Z * r.Z; __ftype__ xy = r.X * r.Y; __ftype__ xz = r.X * r.Z; __ftype__ yz = r.Y * r.Z; __ftype__ xw = r.X * r.W; __ftype__ yw = r.Y * r.W; __ftype__ zw = r.Z * r.W; return new __mat__( 1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), /*# if (m == 4) {*/0, /*# }*/ 2 * (xy + zw), 1 - 2 * (zz + xx), 2 * (yz - xw), /*# if (m == 4) {*/0, /*# }*/ 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (yy + xx)/*# if (m == 4) {*/, 0/*# } if (n == 4) {*/, /*# m.ForEach(i => { var x = (i == m - 1) ? 1 : 0; */__x__/*# }, comma); }*/); } //# } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __ftype__[](__type__ r) { __ftype__[] array = new __ftype__[__qfields.Length__]; /*# qfields.ForEach((f, i) => {*/array[__i__] = r.__f__; /*# });*/return array; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __euclidean3t__(__type__ r) => new __euclidean3t__(r, __v3t__.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __similarity3t__(__type__ r) => new __similarity3t__(1, r, __v3t__.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __affine3t__(__type__ r) => new __affine3t__((__m33t__)r); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __trafo3t__(__type__ r) => new __trafo3t__((__m44t__)r, (__m44t__)r.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type2__(__type__ r) => new __type2__(/*# qfields.ForEach(f => {*/(__ftype2__)r.__f__/*# }, comma);*/); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __quatt__(__type__ r) => new __quatt__(/*# qfields.ForEach(f => {*/r.__f__/*# }, comma);*/); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __quatt2__(__type__ r) => new __quatt2__(/*# qfields.ForEach(f => {*/(__ftype2__)r.__f__/*# }, comma);*/); #endregion #region Indexing /// /// Gets or sets the -th component of the unit quaternion with components (W, (X, Y, Z)). /// public unsafe __ftype__ this[int i] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (__ftype__* ptr = __getptr__) { return ptr[i]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (__ftype__* ptr = __getptr__) { ptr[i] = value; } } } #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(W, V); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => Rot.Distance(this, other) == 0; public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", W, V); } public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__(__ftype__.Parse(x[0], CultureInfo.InvariantCulture), __v3t__.Parse(x[1])); } #endregion } public static partial class Rot { #region Dot /// /// Returns the dot product of two unit quaternions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Dot(this __type__ a, __type__ b) { return a.W * b.W + a.X * b.X + a.Y * b.Y + a.Z * b.Z; } #endregion #region Distance /// /// Returns the absolute difference in radians between two rotations. /// The result is within the range of [0, Pi]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ DistanceFast(this __type__ r1, __type__ r2) { var d = Dot(r1, r2); return 2 * Fun.AcosClamped((d < 0) ? -d : d); } /// /// Returns the absolute difference in radians between two rotations /// using a numerically stable algorithm. /// The result is within the range of [0, Pi]. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Distance(this __type__ r1, __type__ r2) { var q = r1.Inverse * r2; return 2 * Fun.Atan2(q.V.Length, (q.W < 0) ? -q.W : q.W); } #endregion #region Invert, Normalize /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Inverse(__type__ r) => r.Inverse; /// /// Inverts the given transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref __type__ r) { r.X = -r.X; r.Y = -r.Y; r.Z = -r.Z; } /// /// Returns a normalized copy of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Normalized(__type__ r) => r.Normalized; /// /// Normalizes a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref __type__ r) { var norm = r.Norm; if (norm > 0) { var scale = 1 / norm; /*# qfields.ForEach(f => {*/ r.__f__ *= scale;/*# });*/ } } #endregion #region Conversion /// /// Returns the Rodrigues angle-axis vector of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ ToAngleAxis(this __type__ r) { var sinTheta2 = r.V.LengthSquared; if (sinTheta2 > Constant<__ftype__>.PositiveTinyValue) { __ftype__ sinTheta = Fun.Sqrt(sinTheta2); __ftype__ cosTheta = r.W; __ftype__ twoTheta = 2 * (cosTheta < 0 ? Fun.Atan2(-sinTheta, -cosTheta) : Fun.Atan2(sinTheta, cosTheta)); return r.V * (twoTheta / sinTheta); } else return __v3t__.Zero; } /// /// Returns the axis-angle representation of a transformation. /// /// A transformation. /// Output of normalized axis of rotation. /// Output of angle of rotation in radians about axis (Right Hand Rule). [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ToAxisAngle(this __type__ r, ref __v3t__ axis, ref __ftype__ angleInRadians) { angleInRadians = 2 * Fun.Acos(r.W); var s = Fun.Sqrt(1 - r.W * r.W); // assuming quaternion normalised then w is less than 1, so term always positive. if (s < 0.001) { // test to avoid divide by zero, s is always positive due to sqrt // if s close to zero then direction of axis not important axis.X = r.X; // if it is important that axis is normalised then replace with x=1; y=z=0; axis.Y = r.Y; axis.Z = r.Z; } else { axis.X = r.X / s; // normalise axis axis.Y = r.Y / s; axis.Z = r.Z / s; } } #endregion #region Euler Angles /// /// Returns the Euler-Angles from the given as a vector. /// The vector components represent [roll (X), pitch (Y), yaw (Z)] with rotation order is Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ GetEulerAngles(this __type__ r) { var test = r.W * r.Y - r.X * r.Z; if (test > __half__ - Constant<__ftype__>.PositiveTinyValue) // singularity at north pole { return new __v3t__( 2 * Fun.Atan2(r.X, r.W), __piHalf__, 0); } if (test < -__half__ + Constant<__ftype__>.PositiveTinyValue) // singularity at south pole { return new __v3t__( 2 * Fun.Atan2(r.X, r.W), -__piHalf__, 0); } // From Wikipedia, conversion between quaternions and Euler angles. return new __v3t__( Fun.Atan2(2 * (r.W * r.X + r.Y * r.Z), 1 - 2 * (r.X * r.X + r.Y * r.Y)), Fun.AsinClamped(2 * test), Fun.Atan2(2 * (r.W * r.Z + r.X * r.Y), 1 - 2 * (r.Y * r.Y + r.Z * r.Z))); } #endregion #region Transformations /// /// Transforms a vector by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ Transform(this __type__ r, __v3t__ v) => r * v; /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __v3t__ InvTransform(this __type__ r, __v3t__ v) { var w = r.X * v.X + r.Y * v.Y + r.Z * v.Z; var x = r.W * v.X - r.Y * v.Z + r.Z * v.Y; var y = r.W * v.Y - r.Z * v.X + r.X * v.Z; var z = r.W * v.Z - r.X * v.Y + r.Y * v.X; return new __v3t__( w * r.X + x * r.W + y * r.Z - z * r.Y, w * r.Y + y * r.W + z * r.X - x * r.Z, w * r.Z + z * r.W + x * r.Y - y * r.X ); } #endregion #region Spherical Linear Interpolation /// /// Spherical linear interpolation. /// /// Assumes q1 and q2 are normalized and that t in [0,1]. /// /// This method interpolates along the shortest arc between q1 and q2. /// public static __type__ SlerpShortest(this __type__ q1, __type__ q2, __ftype__ t) { __type__ q3 = q2; __ftype__ cosomega = Dot(q1, q3); if (cosomega < 0) { cosomega = -cosomega; q3 = -q3; } if (cosomega >= 1) { // Special case: q1 and q2 are the same, so just return one of them. // This also catches the case where cosomega is very slightly > 1.0 return q1; } __ftype__ sinomega = Fun.Sqrt(1 - cosomega * cosomega); __type__ result; if (sinomega * __ftype__.MaxValue > 1) { __ftype__ omega = Fun.Acos(cosomega); __ftype__ s1 = Fun.Sin((1 - t) * omega) / sinomega; __ftype__ s2 = Fun.Sin(t * omega) / sinomega; result = new __type__(s1 * q1 + s2 * q3); } else if (cosomega > 0) { // omega == 0 __ftype__ s1 = 1 - t; __ftype__ s2 = t; result = new __type__(s1 * q1 + s2 * q3); } else { // omega == -pi result = new __type__(q1.Z, -q1.Y, q1.X, -q1.W); __ftype__ s1 = Fun.Sin((__half__ - t) * __pi__); __ftype__ s2 = Fun.Sin(t * __pi__); result = new __type__(s1 * q1 + s2 * result); } return result; } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ r0, __type__ r1) { return ApproximateEquals(r0, r1, Constant<__ftype__>.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ r0, __type__ r1, __ftype__ tolerance) { return Rot.Distance(r0, r1) <= tolerance; } #endregion } #endregion //# } } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Scale_auto.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { // AUTOGENERATED CODE - DO NOT CHANGE! #region Scale2f /// /// A 2-dimensional scaling transform with different scaling values /// in each dimension. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Scale2f : IEquatable { [DataMember] [XmlIgnore] public V2f V; #region Constructors /// /// Constructs a transformation from 2 floats. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale2f(float sX, float sY) { V = new V2f(sX, sY); } /// /// Constructs a from 2 scaling factors provided as . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale2f(V2f scalingFactors) { V = scalingFactors; } /// /// Constructs a transformation from a uniform float value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale2f(float uniform) { V = new V2f(uniform, uniform); } /// /// Constructs a copy of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale2f(Scale2f scale) { V = scale.V; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale2f(Scale2d scale) { V = (V2f)scale.V; } /// /// Constructs a transformation from a float-array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale2f(float[] array) { V = new V2f(array); } /// /// Constructs a transformation from a float-array starting from the given index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale2f(float[] array, int start) { V = new V2f(array, start); } #endregion #region Properties /// /// Gets and sets the X coordinate. /// public float X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.X = value; } } /// /// Gets and sets the Y coordinate. /// public float Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.Y = value; } } /// /// Gets the inverse of this transformation. /// public readonly Scale2f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale2f(1 / X, 1 / Y); } #endregion #region Constants /// /// Gets the identity transformation. /// public static Scale2f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale2f(1, 1); } /// /// Gets a transformation with all components set to zero. /// public static Scale2f Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale2f(0, 0); } /// /// Gets a transformation with scaling factors (1, 0). /// public static Scale2f XAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale2f(1, 0); } /// /// Gets a transformation with scaling factors (0, 1). /// public static Scale2f YAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale2f(0, 1); } #endregion #region Arithmetic Operators /// /// Negates the values of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2f operator -(Scale2f scale) { return new Scale2f(-scale.X, -scale.Y); } #region Scale / Scalar /// /// Multiplies a transformation with a float scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2f operator *(Scale2f scale, float scalar) { return new Scale2f(scale.X * scalar, scale.Y * scalar); } /// /// Multiplies a float scalar with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2f operator *(float scalar, Scale2f scale) { return new Scale2f(scale.X * scalar, scale.Y * scalar); } /// /// Divides a transformation by a float scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2f operator /(Scale2f scale, float scalar) { return new Scale2f(scale.X / scalar, scale.Y / scalar); } /// /// Divides a float scalar by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2f operator /(float scalar, Scale2f scale) { return new Scale2f(scalar / scale.X, scalar / scale.Y); } #endregion #region Scale / Vector Multiplication /// /// Multiplies a transformation with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator *(Scale2f scale, V2f vector) { return new V2f(vector.X * scale.X, vector.Y * scale.Y); } #endregion #region Scale / Scale Multiplication /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2f operator *(Scale2f a, Scale2f b) => new Scale2f(a.X * b.X, a.Y * b.Y); /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3f operator *(Scale2f a, Scale3f b) => new Scale3f(a.X * b.X, a.Y * b.Y, b.Z); #endregion #region Scale / Matrix Multiplication /// /// Multiplies a transformation (as a 2x2 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator *(Scale2f scale, M22f matrix) { return new M22f( scale.X * matrix.M00, scale.X * matrix.M01, scale.Y * matrix.M10, scale.Y * matrix.M11); } /// /// Multiplies a with a transformation (as a 2x2 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f operator *(M22f matrix, Scale2f scale) { return new M22f( matrix.M00 * scale.X, matrix.M01 * scale.Y, matrix.M10 * scale.X, matrix.M11 * scale.Y); } /// /// Multiplies a transformation (as a 2x2 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(Scale2f scale, M23f matrix) { return new M23f( scale.X * matrix.M00, scale.X * matrix.M01, scale.X * matrix.M02, scale.Y * matrix.M10, scale.Y * matrix.M11, scale.Y * matrix.M12); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(M23f matrix, Scale2f scale) { return new M23f( matrix.M00 * scale.X, matrix.M01 * scale.Y, matrix.M02, matrix.M10 * scale.X, matrix.M11 * scale.Y, matrix.M12); } /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator *(Scale2f scale, M33f matrix) { return new M33f( scale.X * matrix.M00, scale.X * matrix.M01, scale.X * matrix.M02, scale.Y * matrix.M10, scale.Y * matrix.M11, scale.Y * matrix.M12, matrix.M20, matrix.M21, matrix.M22); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator *(M33f matrix, Scale2f scale) { return new M33f( matrix.M00 * scale.X, matrix.M01 * scale.Y, matrix.M02, matrix.M10 * scale.X, matrix.M11 * scale.Y, matrix.M12, matrix.M20 * scale.X, matrix.M21 * scale.Y, matrix.M22); } #endregion #region Scale / Rot, Shift Multiplication /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Scale2f a, Rot2f b) => new Affine2f((M22f)a * (M22f)b); /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Scale2f a, Shift2f b) => new Affine2f((M22f)a, a * b.V); #endregion #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Scale2f s0, Scale2f s1) => s0.X == s1.X && s0.Y == s1.Y; /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Scale2f s0, Scale2f s1) => s0.X != s1.X || s0.Y != s1.Y; #endregion #region Static Creators /// /// Creates a transformation from a matrix. /// The matrix must only contain scaling components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2f FromM22f(M22f m, float epsilon = (float)1e-6) { if (!(Fun.IsTiny(m.C0 * V2f.OI, epsilon) && Fun.IsTiny(m.C1 * V2f.IO, epsilon))) throw new ArgumentException("Matrix is not a pure scaling matrix."); return new Scale2f(m.M00, m.M11); } /// /// Creates a transformation from a scaling matrix. /// The matrix has to be homogeneous and must not contain perspective components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2f FromM33f(M33f m, float epsilon = (float)1e-6) { if (!(Fun.IsTiny(m.C0.XY * V2f.OI, epsilon) && Fun.IsTiny(m.C1.XY * V2f.IO, epsilon))) throw new ArgumentException("Matrix is not a pure scaling matrix."); if (!(m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (!m.C2.XY.IsTiny(epsilon)) throw new ArgumentException("Matrix contains translational component."); if (m.M22.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return new Scale2f(m.M00 / m.M22, m.M11 / m.M22); } /// /// Creates a transformation from a . /// The transformation must only consist of a scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2f FromSimilarity2f(Similarity2f similarity, float epsilon = 1e-5f) { if (!similarity.Trans.IsTiny(epsilon)) throw new ArgumentException("Similarity transformation contains translational component"); if (!similarity.Rot.ApproximateEquals(Rot2f.Identity, epsilon)) throw new ArgumentException("Similarity transformation contains rotational component"); return new Scale2f(similarity.Scale); } /// /// Creates a transformation from an . /// The transformation must only consist of a scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2f FromAffine2f(Affine2f affine, float epsilon = 1e-5f) => FromM33f((M33f)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2f FromTrafo2f(Trafo2f trafo, float epsilon = 1e-5f) => FromM33f(trafo.Forward, epsilon); #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M22f(Scale2f s) { return new M22f( s.X, 0 , 0 , s.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M23f(Scale2f s) { return new M23f( s.X, 0 , 0 , 0 , s.Y, 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33f(Scale2f s) { return new M33f( s.X, 0 , 0 , 0 , s.Y, 0 , 0 , 0 , 1 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34f(Scale2f s) { return new M34f( s.X, 0 , 0 , 0 , 0 , s.Y, 0 , 0 , 0 , 0 , 1 , 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44f(Scale2f s) { return new M44f( s.X, 0 , 0 , 0 , 0 , s.Y, 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine2f(Scale2f s) => new Affine2f((M22f)s, V2f.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo2f(Scale2f s) => new Trafo2f((M33f)s, (M33f)s.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Scale2d(Scale2f s) => new Scale2d((V2d)s.V); /// /// Returns all values of a instance /// in a float[] array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](Scale2f s) => (float[])s.V; #endregion #region Indexing public float this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => V[index]; [MethodImpl(MethodImplOptions.AggressiveInlining)] set => V[index] = value; } #endregion #region Overrides public override readonly int GetHashCode() { return V.GetHashCode(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Scale2f other) => X.Equals(other.X) && Y.Equals(other.Y); public override readonly bool Equals(object other) => (other is Scale2f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", X, Y); } public static Scale2f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Scale2f( float.Parse(x[0], CultureInfo.InvariantCulture), float.Parse(x[1], CultureInfo.InvariantCulture) ); } #endregion } public static partial class Scale { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2f Inverse(Scale2f scale) => scale.Inverse; /// /// Inverts a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Scale2f scale) { scale.V.X = 1 / scale.V.X; scale.V.Y = 1 / scale.V.Y; } #endregion #region Transformations /// /// Transforms a vector by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Transform(this Scale2f s, V2f v) => new V2f(v.X * s.X, v.Y * s.Y); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f InvTransform(this Scale2f s, V2f v) => new V2f(v.X / s.X, v.Y / s.Y); /// /// Transforms a vector by a transformation. /// v.Z is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Transform(this Scale2f s, V3f v) => new V3f(v.X * s.X, v.Y * s.Y, v.Z); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvTransform(this Scale2f s, V3f v) => new V3f(v.X / s.X, v.Y / s.Y, v.Z); /// /// Transforms a vector by a transformation. /// v.Z and v.W are not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Transform(this Scale2f s, V4f v) => new V4f(v.X * s.X, v.Y * s.Y, v.Z, v.W); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f InvTransform(this Scale2f s, V4f v) => new V4f(v.X / s.X, v.Y / s.Y, v.Z, v.W); #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Scale2f s0, Scale2f s1) { return ApproximateEquals(s0.V, s1.V, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Scale2f s0, Scale2f s1, float tolerance) { return ApproximateEquals(s0.V, s1.V, tolerance); } #endregion } #endregion #region Scale3f /// /// A 3-dimensional scaling transform with different scaling values /// in each dimension. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Scale3f : IEquatable { [DataMember] [XmlIgnore] public V3f V; #region Constructors /// /// Constructs a transformation from 3 floats. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale3f(float sX, float sY, float sZ) { V = new V3f(sX, sY, sZ); } /// /// Constructs a from 3 scaling factors provided as . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale3f(V3f scalingFactors) { V = scalingFactors; } /// /// Constructs a transformation from a uniform float value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale3f(float uniform) { V = new V3f(uniform, uniform, uniform); } /// /// Constructs a copy of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale3f(Scale3f scale) { V = scale.V; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale3f(Scale3d scale) { V = (V3f)scale.V; } /// /// Constructs a transformation from a float-array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale3f(float[] array) { V = new V3f(array); } /// /// Constructs a transformation from a float-array starting from the given index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale3f(float[] array, int start) { V = new V3f(array, start); } #endregion #region Properties /// /// Gets and sets the X coordinate. /// public float X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.X = value; } } /// /// Gets and sets the Y coordinate. /// public float Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.Y = value; } } /// /// Gets and sets the Z coordinate. /// public float Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.Z = value; } } /// /// Gets the inverse of this transformation. /// public readonly Scale3f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale3f(1 / X, 1 / Y, 1 / Z); } #endregion #region Constants /// /// Gets the identity transformation. /// public static Scale3f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale3f(1, 1, 1); } /// /// Gets a transformation with all components set to zero. /// public static Scale3f Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale3f(0, 0, 0); } /// /// Gets a transformation with scaling factors (1, 0, 0). /// public static Scale3f XAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale3f(1, 0, 0); } /// /// Gets a transformation with scaling factors (0, 1, 0). /// public static Scale3f YAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale3f(0, 1, 0); } /// /// Gets a transformation with scaling factors (0, 0, 1). /// public static Scale3f ZAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale3f(0, 0, 1); } #endregion #region Arithmetic Operators /// /// Negates the values of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3f operator -(Scale3f scale) { return new Scale3f(-scale.X, -scale.Y, -scale.Z); } #region Scale / Scalar /// /// Multiplies a transformation with a float scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3f operator *(Scale3f scale, float scalar) { return new Scale3f(scale.X * scalar, scale.Y * scalar, scale.Z * scalar); } /// /// Multiplies a float scalar with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3f operator *(float scalar, Scale3f scale) { return new Scale3f(scale.X * scalar, scale.Y * scalar, scale.Z * scalar); } /// /// Divides a transformation by a float scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3f operator /(Scale3f scale, float scalar) { return new Scale3f(scale.X / scalar, scale.Y / scalar, scale.Z / scalar); } /// /// Divides a float scalar by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3f operator /(float scalar, Scale3f scale) { return new Scale3f(scalar / scale.X, scalar / scale.Y, scalar / scale.Z); } #endregion #region Scale / Vector Multiplication /// /// Multiplies a transformation with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator *(Scale3f scale, V3f vector) { return new V3f(vector.X * scale.X, vector.Y * scale.Y, vector.Z * scale.Z); } #endregion #region Scale / Scale Multiplication /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3f operator *(Scale3f a, Scale2f b) => new Scale3f(a.X * b.X, a.Y * b.Y, a.Z); /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3f operator *(Scale3f a, Scale3f b) => new Scale3f(a.X * b.X, a.Y * b.Y, a.Z * b.Z); #endregion #region Scale / Matrix Multiplication /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator *(Scale3f scale, M33f matrix) { return new M33f( scale.X * matrix.M00, scale.X * matrix.M01, scale.X * matrix.M02, scale.Y * matrix.M10, scale.Y * matrix.M11, scale.Y * matrix.M12, scale.Z * matrix.M20, scale.Z * matrix.M21, scale.Z * matrix.M22); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator *(M33f matrix, Scale3f scale) { return new M33f( matrix.M00 * scale.X, matrix.M01 * scale.Y, matrix.M02 * scale.Z, matrix.M10 * scale.X, matrix.M11 * scale.Y, matrix.M12 * scale.Z, matrix.M20 * scale.X, matrix.M21 * scale.Y, matrix.M22 * scale.Z); } /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(Scale3f scale, M34f matrix) { return new M34f( scale.X * matrix.M00, scale.X * matrix.M01, scale.X * matrix.M02, scale.X * matrix.M03, scale.Y * matrix.M10, scale.Y * matrix.M11, scale.Y * matrix.M12, scale.Y * matrix.M13, scale.Z * matrix.M20, scale.Z * matrix.M21, scale.Z * matrix.M22, scale.Z * matrix.M23); } /// /// Multiplies a with a transformation (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(M34f matrix, Scale3f scale) { return new M34f( matrix.M00 * scale.X, matrix.M01 * scale.Y, matrix.M02 * scale.Z, matrix.M03, matrix.M10 * scale.X, matrix.M11 * scale.Y, matrix.M12 * scale.Z, matrix.M13, matrix.M20 * scale.X, matrix.M21 * scale.Y, matrix.M22 * scale.Z, matrix.M23); } /// /// Multiplies a transformation (as a 4x4 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator *(Scale3f scale, M44f matrix) { return new M44f( scale.X * matrix.M00, scale.X * matrix.M01, scale.X * matrix.M02, scale.X * matrix.M03, scale.Y * matrix.M10, scale.Y * matrix.M11, scale.Y * matrix.M12, scale.Y * matrix.M13, scale.Z * matrix.M20, scale.Z * matrix.M21, scale.Z * matrix.M22, scale.Z * matrix.M23, matrix.M30, matrix.M31, matrix.M32, matrix.M33); } /// /// Multiplies a with a transformation (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator *(M44f matrix, Scale3f scale) { return new M44f( matrix.M00 * scale.X, matrix.M01 * scale.Y, matrix.M02 * scale.Z, matrix.M03, matrix.M10 * scale.X, matrix.M11 * scale.Y, matrix.M12 * scale.Z, matrix.M13, matrix.M20 * scale.X, matrix.M21 * scale.Y, matrix.M22 * scale.Z, matrix.M23, matrix.M30 * scale.X, matrix.M31 * scale.Y, matrix.M32 * scale.Z, matrix.M33); } #endregion #region Scale / Rot, Shift Multiplication /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Scale3f a, Rot3f b) => new Affine3f((M33f)a * (M33f)b); /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Scale3f a, Shift3f b) => new Affine3f((M33f)a, a * b.V); #endregion #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Scale3f s0, Scale3f s1) => s0.X == s1.X && s0.Y == s1.Y && s0.Z == s1.Z; /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Scale3f s0, Scale3f s1) => s0.X != s1.X || s0.Y != s1.Y || s0.Z != s1.Z; #endregion #region Static Creators /// /// Creates a transformation from a matrix. /// The matrix must only contain scaling components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3f FromM33f(M33f m, float epsilon = (float)1e-6) { if (!(Fun.IsTiny(m.C0 * V3f.OII, epsilon) && Fun.IsTiny(m.C1 * V3f.IOI, epsilon) && Fun.IsTiny(m.C2 * V3f.IIO, epsilon))) throw new ArgumentException("Matrix is not a pure scaling matrix."); return new Scale3f(m.M00, m.M11, m.M22); } /// /// Creates a transformation from a scaling matrix. /// The matrix has to be homogeneous and must not contain perspective components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3f FromM44f(M44f m, float epsilon = (float)1e-6) { if (!(Fun.IsTiny(m.C0.XYZ * V3f.OII, epsilon) && Fun.IsTiny(m.C1.XYZ * V3f.IOI, epsilon) && Fun.IsTiny(m.C2.XYZ * V3f.IIO, epsilon))) throw new ArgumentException("Matrix is not a pure scaling matrix."); if (!(m.M30.IsTiny(epsilon) && m.M31.IsTiny(epsilon) && m.M32.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (!m.C3.XYZ.IsTiny(epsilon)) throw new ArgumentException("Matrix contains translational component."); if (m.M33.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return new Scale3f(m.M00 / m.M33, m.M11 / m.M33, m.M22 / m.M33); } /// /// Creates a transformation from a . /// The transformation must only consist of a scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3f FromSimilarity3f(Similarity3f similarity, float epsilon = 1e-5f) { if (!similarity.Trans.IsTiny(epsilon)) throw new ArgumentException("Similarity transformation contains translational component"); if (!similarity.Rot.ApproximateEquals(Rot3f.Identity, epsilon)) throw new ArgumentException("Similarity transformation contains rotational component"); return new Scale3f(similarity.Scale); } /// /// Creates a transformation from an . /// The transformation must only consist of a scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3f FromAffine3f(Affine3f affine, float epsilon = 1e-5f) => FromM44f((M44f)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3f FromTrafo3f(Trafo3f trafo, float epsilon = 1e-5f) => FromM44f(trafo.Forward, epsilon); #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M22f(Scale3f s) { return new M22f( s.X, 0 , 0 , s.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M23f(Scale3f s) { return new M23f( s.X, 0 , 0 , 0 , s.Y, 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33f(Scale3f s) { return new M33f( s.X, 0 , 0 , 0 , s.Y, 0 , 0 , 0 , s.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34f(Scale3f s) { return new M34f( s.X, 0 , 0 , 0 , 0 , s.Y, 0 , 0 , 0 , 0 , s.Z, 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44f(Scale3f s) { return new M44f( s.X, 0 , 0 , 0 , 0 , s.Y, 0 , 0 , 0 , 0 , s.Z, 0 , 0 , 0 , 0 , 1 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine3f(Scale3f s) => new Affine3f((M33f)s, V3f.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo3f(Scale3f s) => new Trafo3f((M44f)s, (M44f)s.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Scale3d(Scale3f s) => new Scale3d((V3d)s.V); /// /// Returns all values of a instance /// in a float[] array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](Scale3f s) => (float[])s.V; #endregion #region Indexing public float this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => V[index]; [MethodImpl(MethodImplOptions.AggressiveInlining)] set => V[index] = value; } #endregion #region Overrides public override readonly int GetHashCode() { return V.GetHashCode(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Scale3f other) => X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z); public override readonly bool Equals(object other) => (other is Scale3f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", X, Y, Z); } public static Scale3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Scale3f( float.Parse(x[0], CultureInfo.InvariantCulture), float.Parse(x[1], CultureInfo.InvariantCulture), float.Parse(x[2], CultureInfo.InvariantCulture) ); } #endregion } public static partial class Scale { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3f Inverse(Scale3f scale) => scale.Inverse; /// /// Inverts a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Scale3f scale) { scale.V.X = 1 / scale.V.X; scale.V.Y = 1 / scale.V.Y; scale.V.Z = 1 / scale.V.Z; } #endregion #region Transformations /// /// Transforms a vector by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Transform(this Scale3f s, V3f v) => new V3f(v.X * s.X, v.Y * s.Y, v.Z * s.Z); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvTransform(this Scale3f s, V3f v) => new V3f(v.X / s.X, v.Y / s.Y, v.Z / s.Z); /// /// Transforms a vector by a transformation. /// v.W is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Transform(this Scale3f s, V4f v) => new V4f(v.X * s.X, v.Y * s.Y, v.Z * s.Z, v.W); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f InvTransform(this Scale3f s, V4f v) => new V4f(v.X / s.X, v.Y / s.Y, v.Z / s.Z, v.W); #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Scale3f s0, Scale3f s1) { return ApproximateEquals(s0.V, s1.V, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Scale3f s0, Scale3f s1, float tolerance) { return ApproximateEquals(s0.V, s1.V, tolerance); } #endregion } #endregion #region Scale2d /// /// A 2-dimensional scaling transform with different scaling values /// in each dimension. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Scale2d : IEquatable { [DataMember] [XmlIgnore] public V2d V; #region Constructors /// /// Constructs a transformation from 2 doubles. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale2d(double sX, double sY) { V = new V2d(sX, sY); } /// /// Constructs a from 2 scaling factors provided as . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale2d(V2d scalingFactors) { V = scalingFactors; } /// /// Constructs a transformation from a uniform double value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale2d(double uniform) { V = new V2d(uniform, uniform); } /// /// Constructs a copy of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale2d(Scale2d scale) { V = scale.V; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale2d(Scale2f scale) { V = (V2d)scale.V; } /// /// Constructs a transformation from a double-array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale2d(double[] array) { V = new V2d(array); } /// /// Constructs a transformation from a double-array starting from the given index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale2d(double[] array, int start) { V = new V2d(array, start); } #endregion #region Properties /// /// Gets and sets the X coordinate. /// public double X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.X = value; } } /// /// Gets and sets the Y coordinate. /// public double Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.Y = value; } } /// /// Gets the inverse of this transformation. /// public readonly Scale2d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale2d(1 / X, 1 / Y); } #endregion #region Constants /// /// Gets the identity transformation. /// public static Scale2d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale2d(1, 1); } /// /// Gets a transformation with all components set to zero. /// public static Scale2d Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale2d(0, 0); } /// /// Gets a transformation with scaling factors (1, 0). /// public static Scale2d XAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale2d(1, 0); } /// /// Gets a transformation with scaling factors (0, 1). /// public static Scale2d YAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale2d(0, 1); } #endregion #region Arithmetic Operators /// /// Negates the values of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2d operator -(Scale2d scale) { return new Scale2d(-scale.X, -scale.Y); } #region Scale / Scalar /// /// Multiplies a transformation with a double scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2d operator *(Scale2d scale, double scalar) { return new Scale2d(scale.X * scalar, scale.Y * scalar); } /// /// Multiplies a double scalar with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2d operator *(double scalar, Scale2d scale) { return new Scale2d(scale.X * scalar, scale.Y * scalar); } /// /// Divides a transformation by a double scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2d operator /(Scale2d scale, double scalar) { return new Scale2d(scale.X / scalar, scale.Y / scalar); } /// /// Divides a double scalar by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2d operator /(double scalar, Scale2d scale) { return new Scale2d(scalar / scale.X, scalar / scale.Y); } #endregion #region Scale / Vector Multiplication /// /// Multiplies a transformation with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator *(Scale2d scale, V2d vector) { return new V2d(vector.X * scale.X, vector.Y * scale.Y); } #endregion #region Scale / Scale Multiplication /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2d operator *(Scale2d a, Scale2d b) => new Scale2d(a.X * b.X, a.Y * b.Y); /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3d operator *(Scale2d a, Scale3d b) => new Scale3d(a.X * b.X, a.Y * b.Y, b.Z); #endregion #region Scale / Matrix Multiplication /// /// Multiplies a transformation (as a 2x2 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator *(Scale2d scale, M22d matrix) { return new M22d( scale.X * matrix.M00, scale.X * matrix.M01, scale.Y * matrix.M10, scale.Y * matrix.M11); } /// /// Multiplies a with a transformation (as a 2x2 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d operator *(M22d matrix, Scale2d scale) { return new M22d( matrix.M00 * scale.X, matrix.M01 * scale.Y, matrix.M10 * scale.X, matrix.M11 * scale.Y); } /// /// Multiplies a transformation (as a 2x2 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(Scale2d scale, M23d matrix) { return new M23d( scale.X * matrix.M00, scale.X * matrix.M01, scale.X * matrix.M02, scale.Y * matrix.M10, scale.Y * matrix.M11, scale.Y * matrix.M12); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(M23d matrix, Scale2d scale) { return new M23d( matrix.M00 * scale.X, matrix.M01 * scale.Y, matrix.M02, matrix.M10 * scale.X, matrix.M11 * scale.Y, matrix.M12); } /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator *(Scale2d scale, M33d matrix) { return new M33d( scale.X * matrix.M00, scale.X * matrix.M01, scale.X * matrix.M02, scale.Y * matrix.M10, scale.Y * matrix.M11, scale.Y * matrix.M12, matrix.M20, matrix.M21, matrix.M22); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator *(M33d matrix, Scale2d scale) { return new M33d( matrix.M00 * scale.X, matrix.M01 * scale.Y, matrix.M02, matrix.M10 * scale.X, matrix.M11 * scale.Y, matrix.M12, matrix.M20 * scale.X, matrix.M21 * scale.Y, matrix.M22); } #endregion #region Scale / Rot, Shift Multiplication /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Scale2d a, Rot2d b) => new Affine2d((M22d)a * (M22d)b); /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Scale2d a, Shift2d b) => new Affine2d((M22d)a, a * b.V); #endregion #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Scale2d s0, Scale2d s1) => s0.X == s1.X && s0.Y == s1.Y; /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Scale2d s0, Scale2d s1) => s0.X != s1.X || s0.Y != s1.Y; #endregion #region Static Creators /// /// Creates a transformation from a matrix. /// The matrix must only contain scaling components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2d FromM22d(M22d m, double epsilon = (double)1e-6) { if (!(Fun.IsTiny(m.C0 * V2d.OI, epsilon) && Fun.IsTiny(m.C1 * V2d.IO, epsilon))) throw new ArgumentException("Matrix is not a pure scaling matrix."); return new Scale2d(m.M00, m.M11); } /// /// Creates a transformation from a scaling matrix. /// The matrix has to be homogeneous and must not contain perspective components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2d FromM33d(M33d m, double epsilon = (double)1e-6) { if (!(Fun.IsTiny(m.C0.XY * V2d.OI, epsilon) && Fun.IsTiny(m.C1.XY * V2d.IO, epsilon))) throw new ArgumentException("Matrix is not a pure scaling matrix."); if (!(m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (!m.C2.XY.IsTiny(epsilon)) throw new ArgumentException("Matrix contains translational component."); if (m.M22.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return new Scale2d(m.M00 / m.M22, m.M11 / m.M22); } /// /// Creates a transformation from a . /// The transformation must only consist of a scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2d FromSimilarity2d(Similarity2d similarity, double epsilon = 1e-12) { if (!similarity.Trans.IsTiny(epsilon)) throw new ArgumentException("Similarity transformation contains translational component"); if (!similarity.Rot.ApproximateEquals(Rot2d.Identity, epsilon)) throw new ArgumentException("Similarity transformation contains rotational component"); return new Scale2d(similarity.Scale); } /// /// Creates a transformation from an . /// The transformation must only consist of a scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2d FromAffine2d(Affine2d affine, double epsilon = 1e-12) => FromM33d((M33d)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2d FromTrafo2d(Trafo2d trafo, double epsilon = 1e-12) => FromM33d(trafo.Forward, epsilon); #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M22d(Scale2d s) { return new M22d( s.X, 0 , 0 , s.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M23d(Scale2d s) { return new M23d( s.X, 0 , 0 , 0 , s.Y, 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33d(Scale2d s) { return new M33d( s.X, 0 , 0 , 0 , s.Y, 0 , 0 , 0 , 1 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34d(Scale2d s) { return new M34d( s.X, 0 , 0 , 0 , 0 , s.Y, 0 , 0 , 0 , 0 , 1 , 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44d(Scale2d s) { return new M44d( s.X, 0 , 0 , 0 , 0 , s.Y, 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine2d(Scale2d s) => new Affine2d((M22d)s, V2d.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo2d(Scale2d s) => new Trafo2d((M33d)s, (M33d)s.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Scale2f(Scale2d s) => new Scale2f((V2f)s.V); /// /// Returns all values of a instance /// in a double[] array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](Scale2d s) => (double[])s.V; #endregion #region Indexing public double this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => V[index]; [MethodImpl(MethodImplOptions.AggressiveInlining)] set => V[index] = value; } #endregion #region Overrides public override readonly int GetHashCode() { return V.GetHashCode(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Scale2d other) => X.Equals(other.X) && Y.Equals(other.Y); public override readonly bool Equals(object other) => (other is Scale2d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", X, Y); } public static Scale2d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Scale2d( double.Parse(x[0], CultureInfo.InvariantCulture), double.Parse(x[1], CultureInfo.InvariantCulture) ); } #endregion } public static partial class Scale { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale2d Inverse(Scale2d scale) => scale.Inverse; /// /// Inverts a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Scale2d scale) { scale.V.X = 1 / scale.V.X; scale.V.Y = 1 / scale.V.Y; } #endregion #region Transformations /// /// Transforms a vector by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Transform(this Scale2d s, V2d v) => new V2d(v.X * s.X, v.Y * s.Y); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d InvTransform(this Scale2d s, V2d v) => new V2d(v.X / s.X, v.Y / s.Y); /// /// Transforms a vector by a transformation. /// v.Z is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Transform(this Scale2d s, V3d v) => new V3d(v.X * s.X, v.Y * s.Y, v.Z); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvTransform(this Scale2d s, V3d v) => new V3d(v.X / s.X, v.Y / s.Y, v.Z); /// /// Transforms a vector by a transformation. /// v.Z and v.W are not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Transform(this Scale2d s, V4d v) => new V4d(v.X * s.X, v.Y * s.Y, v.Z, v.W); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d InvTransform(this Scale2d s, V4d v) => new V4d(v.X / s.X, v.Y / s.Y, v.Z, v.W); #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Scale2d s0, Scale2d s1) { return ApproximateEquals(s0.V, s1.V, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Scale2d s0, Scale2d s1, double tolerance) { return ApproximateEquals(s0.V, s1.V, tolerance); } #endregion } #endregion #region Scale3d /// /// A 3-dimensional scaling transform with different scaling values /// in each dimension. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Scale3d : IEquatable { [DataMember] [XmlIgnore] public V3d V; #region Constructors /// /// Constructs a transformation from 3 doubles. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale3d(double sX, double sY, double sZ) { V = new V3d(sX, sY, sZ); } /// /// Constructs a from 3 scaling factors provided as . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale3d(V3d scalingFactors) { V = scalingFactors; } /// /// Constructs a transformation from a uniform double value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale3d(double uniform) { V = new V3d(uniform, uniform, uniform); } /// /// Constructs a copy of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale3d(Scale3d scale) { V = scale.V; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale3d(Scale3f scale) { V = (V3d)scale.V; } /// /// Constructs a transformation from a double-array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale3d(double[] array) { V = new V3d(array); } /// /// Constructs a transformation from a double-array starting from the given index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Scale3d(double[] array, int start) { V = new V3d(array, start); } #endregion #region Properties /// /// Gets and sets the X coordinate. /// public double X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.X = value; } } /// /// Gets and sets the Y coordinate. /// public double Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.Y = value; } } /// /// Gets and sets the Z coordinate. /// public double Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.Z = value; } } /// /// Gets the inverse of this transformation. /// public readonly Scale3d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale3d(1 / X, 1 / Y, 1 / Z); } #endregion #region Constants /// /// Gets the identity transformation. /// public static Scale3d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale3d(1, 1, 1); } /// /// Gets a transformation with all components set to zero. /// public static Scale3d Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale3d(0, 0, 0); } /// /// Gets a transformation with scaling factors (1, 0, 0). /// public static Scale3d XAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale3d(1, 0, 0); } /// /// Gets a transformation with scaling factors (0, 1, 0). /// public static Scale3d YAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale3d(0, 1, 0); } /// /// Gets a transformation with scaling factors (0, 0, 1). /// public static Scale3d ZAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Scale3d(0, 0, 1); } #endregion #region Arithmetic Operators /// /// Negates the values of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3d operator -(Scale3d scale) { return new Scale3d(-scale.X, -scale.Y, -scale.Z); } #region Scale / Scalar /// /// Multiplies a transformation with a double scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3d operator *(Scale3d scale, double scalar) { return new Scale3d(scale.X * scalar, scale.Y * scalar, scale.Z * scalar); } /// /// Multiplies a double scalar with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3d operator *(double scalar, Scale3d scale) { return new Scale3d(scale.X * scalar, scale.Y * scalar, scale.Z * scalar); } /// /// Divides a transformation by a double scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3d operator /(Scale3d scale, double scalar) { return new Scale3d(scale.X / scalar, scale.Y / scalar, scale.Z / scalar); } /// /// Divides a double scalar by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3d operator /(double scalar, Scale3d scale) { return new Scale3d(scalar / scale.X, scalar / scale.Y, scalar / scale.Z); } #endregion #region Scale / Vector Multiplication /// /// Multiplies a transformation with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator *(Scale3d scale, V3d vector) { return new V3d(vector.X * scale.X, vector.Y * scale.Y, vector.Z * scale.Z); } #endregion #region Scale / Scale Multiplication /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3d operator *(Scale3d a, Scale2d b) => new Scale3d(a.X * b.X, a.Y * b.Y, a.Z); /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3d operator *(Scale3d a, Scale3d b) => new Scale3d(a.X * b.X, a.Y * b.Y, a.Z * b.Z); #endregion #region Scale / Matrix Multiplication /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator *(Scale3d scale, M33d matrix) { return new M33d( scale.X * matrix.M00, scale.X * matrix.M01, scale.X * matrix.M02, scale.Y * matrix.M10, scale.Y * matrix.M11, scale.Y * matrix.M12, scale.Z * matrix.M20, scale.Z * matrix.M21, scale.Z * matrix.M22); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator *(M33d matrix, Scale3d scale) { return new M33d( matrix.M00 * scale.X, matrix.M01 * scale.Y, matrix.M02 * scale.Z, matrix.M10 * scale.X, matrix.M11 * scale.Y, matrix.M12 * scale.Z, matrix.M20 * scale.X, matrix.M21 * scale.Y, matrix.M22 * scale.Z); } /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(Scale3d scale, M34d matrix) { return new M34d( scale.X * matrix.M00, scale.X * matrix.M01, scale.X * matrix.M02, scale.X * matrix.M03, scale.Y * matrix.M10, scale.Y * matrix.M11, scale.Y * matrix.M12, scale.Y * matrix.M13, scale.Z * matrix.M20, scale.Z * matrix.M21, scale.Z * matrix.M22, scale.Z * matrix.M23); } /// /// Multiplies a with a transformation (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(M34d matrix, Scale3d scale) { return new M34d( matrix.M00 * scale.X, matrix.M01 * scale.Y, matrix.M02 * scale.Z, matrix.M03, matrix.M10 * scale.X, matrix.M11 * scale.Y, matrix.M12 * scale.Z, matrix.M13, matrix.M20 * scale.X, matrix.M21 * scale.Y, matrix.M22 * scale.Z, matrix.M23); } /// /// Multiplies a transformation (as a 4x4 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator *(Scale3d scale, M44d matrix) { return new M44d( scale.X * matrix.M00, scale.X * matrix.M01, scale.X * matrix.M02, scale.X * matrix.M03, scale.Y * matrix.M10, scale.Y * matrix.M11, scale.Y * matrix.M12, scale.Y * matrix.M13, scale.Z * matrix.M20, scale.Z * matrix.M21, scale.Z * matrix.M22, scale.Z * matrix.M23, matrix.M30, matrix.M31, matrix.M32, matrix.M33); } /// /// Multiplies a with a transformation (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator *(M44d matrix, Scale3d scale) { return new M44d( matrix.M00 * scale.X, matrix.M01 * scale.Y, matrix.M02 * scale.Z, matrix.M03, matrix.M10 * scale.X, matrix.M11 * scale.Y, matrix.M12 * scale.Z, matrix.M13, matrix.M20 * scale.X, matrix.M21 * scale.Y, matrix.M22 * scale.Z, matrix.M23, matrix.M30 * scale.X, matrix.M31 * scale.Y, matrix.M32 * scale.Z, matrix.M33); } #endregion #region Scale / Rot, Shift Multiplication /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Scale3d a, Rot3d b) => new Affine3d((M33d)a * (M33d)b); /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Scale3d a, Shift3d b) => new Affine3d((M33d)a, a * b.V); #endregion #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Scale3d s0, Scale3d s1) => s0.X == s1.X && s0.Y == s1.Y && s0.Z == s1.Z; /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Scale3d s0, Scale3d s1) => s0.X != s1.X || s0.Y != s1.Y || s0.Z != s1.Z; #endregion #region Static Creators /// /// Creates a transformation from a matrix. /// The matrix must only contain scaling components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3d FromM33d(M33d m, double epsilon = (double)1e-6) { if (!(Fun.IsTiny(m.C0 * V3d.OII, epsilon) && Fun.IsTiny(m.C1 * V3d.IOI, epsilon) && Fun.IsTiny(m.C2 * V3d.IIO, epsilon))) throw new ArgumentException("Matrix is not a pure scaling matrix."); return new Scale3d(m.M00, m.M11, m.M22); } /// /// Creates a transformation from a scaling matrix. /// The matrix has to be homogeneous and must not contain perspective components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3d FromM44d(M44d m, double epsilon = (double)1e-6) { if (!(Fun.IsTiny(m.C0.XYZ * V3d.OII, epsilon) && Fun.IsTiny(m.C1.XYZ * V3d.IOI, epsilon) && Fun.IsTiny(m.C2.XYZ * V3d.IIO, epsilon))) throw new ArgumentException("Matrix is not a pure scaling matrix."); if (!(m.M30.IsTiny(epsilon) && m.M31.IsTiny(epsilon) && m.M32.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (!m.C3.XYZ.IsTiny(epsilon)) throw new ArgumentException("Matrix contains translational component."); if (m.M33.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return new Scale3d(m.M00 / m.M33, m.M11 / m.M33, m.M22 / m.M33); } /// /// Creates a transformation from a . /// The transformation must only consist of a scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3d FromSimilarity3d(Similarity3d similarity, double epsilon = 1e-12) { if (!similarity.Trans.IsTiny(epsilon)) throw new ArgumentException("Similarity transformation contains translational component"); if (!similarity.Rot.ApproximateEquals(Rot3d.Identity, epsilon)) throw new ArgumentException("Similarity transformation contains rotational component"); return new Scale3d(similarity.Scale); } /// /// Creates a transformation from an . /// The transformation must only consist of a scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3d FromAffine3d(Affine3d affine, double epsilon = 1e-12) => FromM44d((M44d)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3d FromTrafo3d(Trafo3d trafo, double epsilon = 1e-12) => FromM44d(trafo.Forward, epsilon); #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M22d(Scale3d s) { return new M22d( s.X, 0 , 0 , s.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M23d(Scale3d s) { return new M23d( s.X, 0 , 0 , 0 , s.Y, 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33d(Scale3d s) { return new M33d( s.X, 0 , 0 , 0 , s.Y, 0 , 0 , 0 , s.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34d(Scale3d s) { return new M34d( s.X, 0 , 0 , 0 , 0 , s.Y, 0 , 0 , 0 , 0 , s.Z, 0 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44d(Scale3d s) { return new M44d( s.X, 0 , 0 , 0 , 0 , s.Y, 0 , 0 , 0 , 0 , s.Z, 0 , 0 , 0 , 0 , 1 ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine3d(Scale3d s) => new Affine3d((M33d)s, V3d.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo3d(Scale3d s) => new Trafo3d((M44d)s, (M44d)s.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Scale3f(Scale3d s) => new Scale3f((V3f)s.V); /// /// Returns all values of a instance /// in a double[] array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](Scale3d s) => (double[])s.V; #endregion #region Indexing public double this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => V[index]; [MethodImpl(MethodImplOptions.AggressiveInlining)] set => V[index] = value; } #endregion #region Overrides public override readonly int GetHashCode() { return V.GetHashCode(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Scale3d other) => X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z); public override readonly bool Equals(object other) => (other is Scale3d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", X, Y, Z); } public static Scale3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Scale3d( double.Parse(x[0], CultureInfo.InvariantCulture), double.Parse(x[1], CultureInfo.InvariantCulture), double.Parse(x[2], CultureInfo.InvariantCulture) ); } #endregion } public static partial class Scale { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Scale3d Inverse(Scale3d scale) => scale.Inverse; /// /// Inverts a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Scale3d scale) { scale.V.X = 1 / scale.V.X; scale.V.Y = 1 / scale.V.Y; scale.V.Z = 1 / scale.V.Z; } #endregion #region Transformations /// /// Transforms a vector by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Transform(this Scale3d s, V3d v) => new V3d(v.X * s.X, v.Y * s.Y, v.Z * s.Z); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvTransform(this Scale3d s, V3d v) => new V3d(v.X / s.X, v.Y / s.Y, v.Z / s.Z); /// /// Transforms a vector by a transformation. /// v.W is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Transform(this Scale3d s, V4d v) => new V4d(v.X * s.X, v.Y * s.Y, v.Z * s.Z, v.W); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d InvTransform(this Scale3d s, V4d v) => new V4d(v.X / s.X, v.Y / s.Y, v.Z / s.Z, v.W); #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Scale3d s0, Scale3d s1) { return ApproximateEquals(s0.V, s1.V, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Scale3d s0, Scale3d s1, double tolerance) { return ApproximateEquals(s0.V, s1.V, tolerance); } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Scale_template.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { // AUTOGENERATED CODE - DO NOT CHANGE! //# Action comma = () => Out(", "); //# Action commaln = () => Out("," + Environment.NewLine); //# Action endl = () => Out(Environment.NewLine); //# Action add = () => Out(" + "); //# Action and = () => Out(" && "); //# Action or = () => Out(" || "); //# Action andLit = () => Out(" and "); //# var fields = new[] {"X", "Y", "Z", "W"}; //# foreach (var isDouble in new[] { false, true }) { //# for (int d = 2; d <= 3; d++) { //# var d1 = d + 1; //# var ftype = isDouble ? "double" : "float"; //# var xyz = "XYZW".Substring(0, d); //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Scale" + d + tc; //# var type2 = "Scale" + d + tc2; //# var trafodt = "Trafo" + d + tc; //# var affinedt = "Affine" + d + tc; //# var euclideandt = "Euclidean" + d + tc; //# var rotdt = "Rot" + d + tc; //# var shiftdt = "Shift" + d + tc; //# var similaritydt = "Similarity" + d + tc; //# var mddt = "M" + d + d + tc; //# var md1d1t = "M" + d1 + d1 + tc; //# var vdt = "V" + d + tc; //# var vdt2 = "V" + d + tc2; //# var dfields = fields.Take(d).ToArray(); //# var fd = fields[d]; //# var eps = isDouble ? "1e-12" : "1e-5f"; //# var getptr = "&" + dfields[0]; #region __type__ /// /// A __d__-dimensional scaling transform with different scaling values /// in each dimension. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__> { [DataMember] [XmlIgnore] public __vdt__ V; #region Constructors /// /// Constructs a transformation from __d__ __ftype__s. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(/*# dfields.ForEach(f => { */__ftype__ s__f__/*# }, comma); */) { V = new __vdt__(/*# dfields.ForEach(f => { */s__f__/*# }, comma); */); } /// /// Constructs a from __d__ scaling factors provided as . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__vdt__ scalingFactors) { V = scalingFactors; } /// /// Constructs a transformation from a uniform __ftype__ value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__ uniform) { V = new __vdt__(/*# dfields.ForEach(f => { */uniform/*# }, comma); */); } /// /// Constructs a copy of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ scale) { V = scale.V; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ scale) { V = (__vdt__)scale.V; } /// /// Constructs a transformation from a __ftype__-array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__[] array) { V = new __vdt__(array); } /// /// Constructs a transformation from a __ftype__-array starting from the given index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__[] array, int start) { V = new __vdt__(array, start); } #endregion #region Properties //# dfields.ForEach(f => { /// /// Gets and sets the __f__ coordinate. /// public __ftype__ __f__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.__f__; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.__f__ = value; } } //# }); /// /// Gets the inverse of this transformation. /// public readonly __type__ Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(/*# dfields.ForEach(f => { */1 / __f__/*# }, comma); */); } #endregion #region Constants /// /// Gets the identity transformation. /// public static __type__ Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(/*# dfields.ForEach(f => { */1/*# }, comma); */); } /// /// Gets a transformation with all components set to zero. /// public static __type__ Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(/*# dfields.ForEach(f => { */0/*# }, comma); */); } //# dfields.ForEach((fi, i) => { /// /// Gets a transformation with scaling factors (/*# dfields.ForEach((fj, j) => { var val = (i != j) ? "0" : "1"; */__val__/*# }, comma); */). /// public static __type__ __fi__Axis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(/*# dfields.ForEach((fj, j) => { var val = (i != j) ? "0" : "1"; */__val__/*# }, comma); */); } //# }); #endregion #region Arithmetic Operators /// /// Negates the values of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator -(__type__ scale) { return new __type__(/*# dfields.ForEach(f => { */-scale.__f__/*# }, comma); */); } #region Scale / Scalar /// /// Multiplies a transformation with a __ftype__ scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ scale, __ftype__ scalar) { return new __type__(/*# dfields.ForEach(f => { */scale.__f__ * scalar/*# }, comma); */); } /// /// Multiplies a __ftype__ scalar with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__ftype__ scalar, __type__ scale) { return new __type__(/*# dfields.ForEach(f => { */scale.__f__ * scalar/*# }, comma); */); } /// /// Divides a transformation by a __ftype__ scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator /(__type__ scale, __ftype__ scalar) { return new __type__(/*# dfields.ForEach(f => { */scale.__f__ / scalar/*# }, comma); */); } /// /// Divides a __ftype__ scalar by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator /(__ftype__ scalar, __type__ scale) { return new __type__(/*# dfields.ForEach(f => { */scalar / scale.__f__/*# }, comma); */); } #endregion #region Scale / Vector Multiplication /// /// Multiplies a transformation with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vdt__ operator *(__type__ scale, __vdt__ vector) { return new __vdt__(/*# dfields.ForEach(f => { */vector.__f__ * scale.__f__/*# }, comma); */); } #endregion #region Scale / Scale Multiplication //# for (int n = 2; n <= 3; n++) { //# var r = (d > n) ? d : n; //# var m = (d < n) ? d : n; //# var mfields = fields.Take(m); //# var rem = r - m; //# var ntype = "Scale" + n + tc; //# var rtype = "Scale" + r + tc; /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ operator *(__type__ a, __ntype__ b) => new __rtype__(/*# mfields.ForEach(f => {*/a.__f__ * b.__f__/*# }, comma); if (r > m) {*/, /*# rem.ForEach(i => { var x = (d > n) ? "a" : "b"; var f = fields[m + i]; */__x__.__f__/*#}, comma); } */); //# } #endregion #region Scale / Matrix Multiplication //# for (int n = d; n <= d+1; n++) { //# for (int m = n; m <= (n + 1) && m <= d+1; m++) { //# var mat = "M" + n + m + tc; //# var nfields = dfields.Take(n); //# var mfields = dfields.Take(m); //# var nrem = n - d; //# var mrem = m - d; /// /// Multiplies a transformation (as a __n__x__n__ matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mat__ operator *(__type__ scale, __mat__ matrix) { return new __mat__(/*# nfields.ForEach((fi, i) => { */ /*# m.ForEach(j => { */scale.__fi__ * matrix.M__i____j__/*# }, comma); }, comma); if (nrem > 0) {*/, /*# nrem.ForEach(i => { */ /*# var ipd = i + d; m.ForEach(j => { */matrix.M__ipd____j__/*# }, comma); }, comma); }*/); } //# var rem = m - d; /// /// Multiplies a with a transformation (as a __m__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mat__ operator *(__mat__ matrix, __type__ scale) { return new __mat__(/*# n.ForEach(i => { */ /*# mfields.ForEach((fj, j) => { */matrix.M__i____j__ * scale.__fj__/*# }, comma); if (mrem > 0) {*/, /*# mrem.ForEach(j => { var jpd = j + d; */matrix.M__i____jpd__/*# }, comma); } }, comma);*/); } //# } } #endregion #region Scale / Rot, Shift Multiplication /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __affinedt__ operator *(__type__ a, __rotdt__ b) => new __affinedt__((__mddt__)a * (__mddt__)b); /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __affinedt__ operator *(__type__ a, __shiftdt__ b) => new __affinedt__((__mddt__)a, a * b.V); #endregion #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ s0, __type__ s1) => /*# dfields.ForEach(f => {*/s0.__f__ == s1.__f__/*# }, and);*/; /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ s0, __type__ s1) => /*# dfields.ForEach(f => {*/s0.__f__ != s1.__f__/*# }, or);*/; #endregion #region Static Creators /// /// Creates a transformation from a matrix. /// The matrix must only contain scaling components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__mddt__(__mddt__ m, __ftype__ epsilon = (__ftype__)1e-6) { if (!(/*# d.ForEach(i => {*/Fun.IsTiny(m.C__i__ * __vdt__./*# d.ForEach(j => { var x = (i == j) ? "O" : "I"; */__x__/*# });*/, epsilon)/*# }, and);*/)) throw new ArgumentException("Matrix is not a pure scaling matrix."); return new __type__(/*# d.ForEach(i => {*/m.M__i____i__/*# }, comma);*/); } /// /// Creates a transformation from a scaling matrix. /// The matrix has to be homogeneous and must not contain perspective components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__md1d1t__(__md1d1t__ m, __ftype__ epsilon = (__ftype__)1e-6) { if (!(/*# d.ForEach(i => {*/Fun.IsTiny(m.C__i__.__xyz__ * __vdt__./*# d.ForEach(j => { var x = (i == j) ? "O" : "I"; */__x__/*# });*/, epsilon)/*# }, and);*/)) throw new ArgumentException("Matrix is not a pure scaling matrix."); if (!(/*#d.ForEach(j => {*/m.M__d____j__.IsTiny(epsilon)/*# }, and);*/)) throw new ArgumentException("Matrix contains perspective components."); if (!m.C__d__.__xyz__.IsTiny(epsilon)) throw new ArgumentException("Matrix contains translational component."); if (m.M__d____d__.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return new __type__(/*# d.ForEach(i => {*/m.M__i____i__ / m.M__d____d__/*# }, comma);*/); } /// /// Creates a transformation from a . /// The transformation must only consist of a scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__similaritydt__(__similaritydt__ similarity, __ftype__ epsilon = __eps__) { if (!similarity.Trans.IsTiny(epsilon)) throw new ArgumentException("Similarity transformation contains translational component"); if (!similarity.Rot.ApproximateEquals(__rotdt__.Identity, epsilon)) throw new ArgumentException("Similarity transformation contains rotational component"); return new __type__(similarity.Scale); } /// /// Creates a transformation from an . /// The transformation must only consist of a scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__affinedt__(__affinedt__ affine, __ftype__ epsilon = __eps__) => From__md1d1t__((__md1d1t__)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__trafodt__(__trafodt__ trafo, __ftype__ epsilon = __eps__) => From__md1d1t__(trafo.Forward, epsilon); #endregion #region Conversion //# for (int n = 2; n <= 4; n++) { //# for (int m = n; m <= (n+1) && m <= 4; m++) { //# var mat = "M" + n + m + tc; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __mat__(__type__ s) { return new __mat__(/*# n.ForEach(i => { */ /*# m.ForEach(j => { var x = (i == j) ? ((i < d) ? "s." + fields[i] : "1 ") : "0 "; */__x__/*# }, comma); }, comma);*/); } //# } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __affinedt__(__type__ s) => new __affinedt__((__mddt__)s, __vdt__.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __trafodt__(__type__ s) => new __trafodt__((__md1d1t__)s, (__md1d1t__)s.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type2__(__type__ s) => new __type2__((__vdt2__)s.V); /// /// Returns all values of a instance /// in a __ftype__[] array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __ftype__[](__type__ s) => (__ftype__[])s.V; #endregion #region Indexing public __ftype__ this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => V[index]; [MethodImpl(MethodImplOptions.AggressiveInlining)] set => V[index] = value; } #endregion #region Overrides public override readonly int GetHashCode() { return V.GetHashCode(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => /*# dfields.ForEach(f => {*/__f__.Equals(other.__f__)/*# }, and);*/; public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[/*# d.ForEach(i => {*/{__i__}/*# }, comma);*/]", /*# dfields.ForEach(f => {*/__f__/*#}, comma);*/); } public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__(/*# d.ForEach(i => {*/ __ftype__.Parse(x[__i__], CultureInfo.InvariantCulture)/*# }, comma);*/ ); } #endregion } public static partial class Scale { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Inverse(__type__ scale) => scale.Inverse; /// /// Inverts a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref __type__ scale) { //# dfields.ForEach(f => { scale.V.__f__ = 1 / scale.V.__f__; //# }); } #endregion #region Transformations //# for (int n = d; n <= 4; n++) { //# var vec = "V" + n + tc; //# var rem = n - d; //# var constfields = fields.Skip(d).Take(rem); //# var isare = (rem > 1) ? "are" : "is"; /// /// Transforms a vector by a transformation./*# if (rem > 0) { */ /// /*# constfields.ForEach(f => {*/v.__f__/*# }, andLit); */ __isare__ not modified./*# }*/ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vec__ Transform(this __type__ s, __vec__ v) => new __vec__(/*# dfields.ForEach(f => {*/v.__f__ * s.__f__/*# }, comma); if (rem > 0) {*/, /*# rem.ForEach(i => { var f = fields[d + i]; */v.__f__/*#}, comma); } */); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vec__ InvTransform(this __type__ s, __vec__ v) => new __vec__(/*# dfields.ForEach(f => {*/v.__f__ / s.__f__/*# }, comma); if (rem > 0) {*/, /*# rem.ForEach(i => { var f = fields[d + i]; */v.__f__/*#}, comma); } */); //# } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ s0, __type__ s1) { return ApproximateEquals(s0.V, s1.V, Constant<__ftype__>.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ s0, __type__ s1, __ftype__ tolerance) { return ApproximateEquals(s0.V, s1.V, tolerance); } #endregion } #endregion //# } } } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Shift_auto.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { // AUTOGENERATED CODE - DO NOT CHANGE! #region Shift2f /// /// A 2-dimensional translational transform with different translation values /// in each dimension. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Shift2f : IEquatable { [DataMember] [XmlIgnore] public V2f V; #region Constructors /// /// Constructs a transformation from 2 floats. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift2f(float x, float y) { V = new V2f(x, y); } /// /// Constructs a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift2f(V2f v) { V = v; } /// /// Constructs a copy of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift2f(Shift2f s) { V = s.V; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift2f(Shift2d shift) { V = (V2f)shift.V; } /// /// Constructs a transformation from a float-array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift2f(float[] array) { V = new V2f(array); } /// /// Constructs a transformation from a float-array starting from the given index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift2f(float[] array, int start) { V = new V2f(array, start); } #endregion #region Properties /// /// Gets and sets the X coordinate. /// public float X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.X = value; } } /// /// Gets and sets the Y coordinate. /// public float Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.Y = value; } } /// /// Gets the length of this transformation. /// public readonly float Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return V.Length; } } /// /// Gets the squared length of this transformation. /// public readonly float LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return V.LengthSquared; } } /// /// Gets the inverse of this transformation. /// public readonly Shift2f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Shift2f(-V); } } /// /// Gets the reciprocal of this transformation. /// public readonly Shift2f Reciprocal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift2f(1 / V); } #endregion #region Constants /// /// Gets the identity transformation. /// public static Shift2f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift2f(0, 0); } /// /// Gets a transformation with all components set to zero. /// Note: Equivalent to Identity. /// public static Shift2f Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Identity; } /// /// Gets a transformation with components (1, 0). /// public static Shift2f XAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift2f(1, 0); } /// /// Gets a transformation with components (0, 1). /// public static Shift2f YAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift2f(0, 1); } #endregion #region Arithmetic Operators /// /// Negates the values of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2f operator -(Shift2f shift) { return new Shift2f(-shift.X, -shift.Y); } #region Shift / Scalar /// /// Multiplies a transformation with a float scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2f operator *(Shift2f shift, float scalar) { return new Shift2f(shift.X * scalar, shift.Y * scalar); } /// /// Multiplies a float scalar with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2f operator *(float scalar, Shift2f shift) { return new Shift2f(shift.X * scalar, shift.Y * scalar); } /// /// Divides a transformation by a float scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2f operator /(Shift2f shift, float scalar) { return new Shift2f(shift.X / scalar, shift.Y / scalar); } /// /// Divides a float scalar by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2f operator /(float scalar, Shift2f shift) { return new Shift2f(scalar / shift.X, scalar / shift.Y); } #endregion #region Shift / Vector Multiplication /// /// Multiplies a transformation with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator *(Shift2f shift, V2f vector) { return new V2f(vector.X + shift.X, vector.Y + shift.Y); } #endregion #region Shift / Shift Multiplication /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2f operator *(Shift2f a, Shift2f b) => new Shift2f(a.X + b.X, a.Y + b.Y); /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3f operator *(Shift2f a, Shift3f b) => new Shift3f(a.X + b.X, a.Y + b.Y, b.Z); #endregion #region Shift / Matrix Multiplication /// /// Multiplies a transformation (as a 2x3 matrix) with a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(Shift2f shift, M22f matrix) { return new M23f(matrix, shift.V); } /// /// Multiplies a with a transformation (as a 2x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(M22f matrix, Shift2f shift) { return new M23f(matrix, matrix * shift.V); } /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator *(Shift2f s, M33f m) { return new M33f( m.M00 + s.X * m.M20, m.M01 + s.X * m.M21, m.M02 + s.X * m.M22, m.M10 + s.Y * m.M20, m.M11 + s.Y * m.M21, m.M12 + s.Y * m.M22, m.M20, m.M21, m.M22); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator *(M33f m, Shift2f s) { return new M33f( m.M00, m.M01, s.X * m.M00 + s.Y * m.M01 + m.M02, m.M10, m.M11, s.X * m.M10 + s.Y * m.M11 + m.M12, m.M20, m.M21, s.X * m.M20 + s.Y * m.M21 + m.M22); } /// /// Multiplies a transformation (as a 2x3 matrix) with a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(Shift2f s, M23f m) { return new M23f( m.M00, m.M01, m.M02 + s.X, m.M10, m.M11, m.M12 + s.Y); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(M23f m, Shift2f s) { return new M23f( m.M00, m.M01, s.X * m.M00 + s.Y * m.M01 + m.M02, m.M10, m.M11, s.X * m.M10 + s.Y * m.M11 + m.M12); } #endregion #region Shift / Rot, Scale Multiplication /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2f operator *(Shift2f a, Rot2f b) => new Euclidean2f(b, a.V); /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Shift2f a, Scale2f b) => new Affine2f((M22f)b, a.V); #endregion #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Shift2f s0, Shift2f s1) => s0.X == s1.X && s0.Y == s1.Y; /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Shift2f s0, Shift2f s1) => s0.X != s1.X || s0.Y != s1.Y; #endregion #region Static Creators /// /// Creates a transformation from a matrix. /// The matrix must only contain translation components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2f FromM23f(M23f m, float epsilon = (float)1e-6) { if (!M22f.Identity.ApproximateEquals((M22f)m, epsilon)) throw new ArgumentException("Matrix is not a pure translation matrix."); return new Shift2f(m.C2); } /// /// Creates a transformation from a translation matrix. /// The matrix has to be homogeneous and must not contain perspective components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2f FromM33f(M33f m, float epsilon = (float)1e-6) { if (!M22f.Identity.ApproximateEquals((M22f)m, epsilon)) throw new ArgumentException("Matrix is not a pure translation matrix."); if (!(m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (m.M22.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return new Shift2f(m.C2.XY / m.M22); } /// /// Creates a transformation from a . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2f FromEuclidean2f(Euclidean2f euclidean, float epsilon = 1e-5f) { if (!euclidean.Rot.ApproximateEquals(Rot2f.Identity, epsilon)) throw new ArgumentException("Euclidean transformation contains rotational component"); return new Shift2f(euclidean.Trans); } /// /// Creates a transformation from a . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2f FromSimilarity2f(Similarity2f similarity, float epsilon = 1e-5f) { if (!similarity.Scale.ApproximateEquals(1, epsilon)) throw new ArgumentException("Similarity transformation contains scaling component"); if (!similarity.Rot.ApproximateEquals(Rot2f.Identity, epsilon)) throw new ArgumentException("Similarity transformation contains rotational component"); return new Shift2f(similarity.Trans); } /// /// Creates a transformation from an . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2f FromAffine2f(Affine2f affine, float epsilon = 1e-5f) => FromM33f((M33f)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2f FromTrafo2f(Trafo2f trafo, float epsilon = 1e-5f) => FromM33f(trafo.Forward, epsilon); #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33f(Shift2f s) { return new M33f( 1, 0, s.X, 0, 1, s.Y, 0, 0, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M23f(Shift2f s) { return new M23f( 1, 0, s.X, 0, 1, s.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44f(Shift2f s) { return new M44f( 1, 0, 0, s.X, 0, 1, 0, s.Y, 0, 0, 1, 0, 0, 0, 0, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34f(Shift2f s) { return new M34f( 1, 0, 0, s.X, 0, 1, 0, s.Y, 0, 0, 1, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Euclidean2f(Shift2f s) => new Euclidean2f(Rot2f.Identity, s.V); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Similarity2f(Shift2f s) => new Similarity2f(1, Rot2f.Identity, s.V); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine2f(Shift2f s) => new Affine2f(M22f.Identity, s.V); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo2f(Shift2f s) => new Trafo2f((M33f)s, (M33f)s.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Shift2d(Shift2f s) => new Shift2d((V2d)s.V); /// /// Returns all values of a instance /// in a float[] array. /// public static explicit operator float[](Shift2f shift) { float[] array = new float[2]; array[0] = shift.X; array[1] = shift.Y; return array; } #endregion #region Indexing public float this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => V[index]; [MethodImpl(MethodImplOptions.AggressiveInlining)] set => V[index] = value; } #endregion #region Overrides public override readonly int GetHashCode() { return V.GetHashCode(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Shift2f other) => X.Equals(other.X) && Y.Equals(other.Y); public override readonly bool Equals(object other) => (other is Shift2f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", X, Y); } public static Shift2f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Shift2f( float.Parse(x[0], CultureInfo.InvariantCulture), float.Parse(x[1], CultureInfo.InvariantCulture) ); } #endregion } public static partial class Shift { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2f Inverse(Shift2f shift) => shift.Inverse; /// /// Inverts a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Shift2f shift) { shift.V.X = -shift.V.X; shift.V.Y = -shift.V.Y; } #endregion #region Transformations /// /// Transforms a vector by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Transform(this Shift2f s, V2f v) => new V2f(v.X + s.X, v.Y + s.Y); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f InvTransform(this Shift2f s, V2f v) => new V2f(v.X - s.X, v.Y - s.Y); /// /// Transforms a vector by a transformation. /// v.Z is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Transform(this Shift2f s, V3f v) => new V3f(v.X + s.X, v.Y + s.Y, v.Z); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvTransform(this Shift2f s, V3f v) => new V3f(v.X - s.X, v.Y - s.Y, v.Z); /// /// Transforms a vector by a transformation. /// v.Z and v.W are not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Transform(this Shift2f s, V4f v) => new V4f(v.X + s.X, v.Y + s.Y, v.Z, v.W); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f InvTransform(this Shift2f s, V4f v) => new V4f(v.X - s.X, v.Y - s.Y, v.Z, v.W); #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Shift2f s0, Shift2f s1) { return ApproximateEquals(s0.V, s1.V, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Shift2f s0, Shift2f s1, float tolerance) { return ApproximateEquals(s0.V, s1.V, tolerance); } #endregion } #endregion #region Shift3f /// /// A 3-dimensional translational transform with different translation values /// in each dimension. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Shift3f : IEquatable { [DataMember] [XmlIgnore] public V3f V; #region Constructors /// /// Constructs a transformation from 3 floats. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift3f(float x, float y, float z) { V = new V3f(x, y, z); } /// /// Constructs a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift3f(V3f v) { V = v; } /// /// Constructs a copy of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift3f(Shift3f s) { V = s.V; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift3f(Shift3d shift) { V = (V3f)shift.V; } /// /// Constructs a transformation from a float-array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift3f(float[] array) { V = new V3f(array); } /// /// Constructs a transformation from a float-array starting from the given index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift3f(float[] array, int start) { V = new V3f(array, start); } #endregion #region Properties /// /// Gets and sets the X coordinate. /// public float X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.X = value; } } /// /// Gets and sets the Y coordinate. /// public float Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.Y = value; } } /// /// Gets and sets the Z coordinate. /// public float Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.Z = value; } } /// /// Gets the length of this transformation. /// public readonly float Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return V.Length; } } /// /// Gets the squared length of this transformation. /// public readonly float LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return V.LengthSquared; } } /// /// Gets the inverse of this transformation. /// public readonly Shift3f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Shift3f(-V); } } /// /// Gets the reciprocal of this transformation. /// public readonly Shift3f Reciprocal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift3f(1 / V); } #endregion #region Constants /// /// Gets the identity transformation. /// public static Shift3f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift3f(0, 0, 0); } /// /// Gets a transformation with all components set to zero. /// Note: Equivalent to Identity. /// public static Shift3f Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Identity; } /// /// Gets a transformation with components (1, 0, 0). /// public static Shift3f XAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift3f(1, 0, 0); } /// /// Gets a transformation with components (0, 1, 0). /// public static Shift3f YAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift3f(0, 1, 0); } /// /// Gets a transformation with components (0, 0, 1). /// public static Shift3f ZAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift3f(0, 0, 1); } #endregion #region Arithmetic Operators /// /// Negates the values of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3f operator -(Shift3f shift) { return new Shift3f(-shift.X, -shift.Y, -shift.Z); } #region Shift / Scalar /// /// Multiplies a transformation with a float scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3f operator *(Shift3f shift, float scalar) { return new Shift3f(shift.X * scalar, shift.Y * scalar, shift.Z * scalar); } /// /// Multiplies a float scalar with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3f operator *(float scalar, Shift3f shift) { return new Shift3f(shift.X * scalar, shift.Y * scalar, shift.Z * scalar); } /// /// Divides a transformation by a float scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3f operator /(Shift3f shift, float scalar) { return new Shift3f(shift.X / scalar, shift.Y / scalar, shift.Z / scalar); } /// /// Divides a float scalar by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3f operator /(float scalar, Shift3f shift) { return new Shift3f(scalar / shift.X, scalar / shift.Y, scalar / shift.Z); } #endregion #region Shift / Vector Multiplication /// /// Multiplies a transformation with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator *(Shift3f shift, V3f vector) { return new V3f(vector.X + shift.X, vector.Y + shift.Y, vector.Z + shift.Z); } #endregion #region Shift / Shift Multiplication /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3f operator *(Shift3f a, Shift2f b) => new Shift3f(a.X + b.X, a.Y + b.Y, a.Z); /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3f operator *(Shift3f a, Shift3f b) => new Shift3f(a.X + b.X, a.Y + b.Y, a.Z + b.Z); #endregion #region Shift / Matrix Multiplication /// /// Multiplies a transformation (as a 3x4 matrix) with a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(Shift3f shift, M33f matrix) { return new M34f(matrix, shift.V); } /// /// Multiplies a with a transformation (as a 3x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(M33f matrix, Shift3f shift) { return new M34f(matrix, matrix * shift.V); } /// /// Multiplies a transformation (as a 4x4 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator *(Shift3f s, M44f m) { return new M44f( m.M00 + s.X * m.M30, m.M01 + s.X * m.M31, m.M02 + s.X * m.M32, m.M03 + s.X * m.M33, m.M10 + s.Y * m.M30, m.M11 + s.Y * m.M31, m.M12 + s.Y * m.M32, m.M13 + s.Y * m.M33, m.M20 + s.Z * m.M30, m.M21 + s.Z * m.M31, m.M22 + s.Z * m.M32, m.M23 + s.Z * m.M33, m.M30, m.M31, m.M32, m.M33); } /// /// Multiplies a with a transformation (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator *(M44f m, Shift3f s) { return new M44f( m.M00, m.M01, m.M02, s.X * m.M00 + s.Y * m.M01 + s.Z * m.M02 + m.M03, m.M10, m.M11, m.M12, s.X * m.M10 + s.Y * m.M11 + s.Z * m.M12 + m.M13, m.M20, m.M21, m.M22, s.X * m.M20 + s.Y * m.M21 + s.Z * m.M22 + m.M23, m.M30, m.M31, m.M32, s.X * m.M30 + s.Y * m.M31 + s.Z * m.M32 + m.M33); } /// /// Multiplies a transformation (as a 3x4 matrix) with a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(Shift3f s, M34f m) { return new M34f( m.M00, m.M01, m.M02, m.M03 + s.X, m.M10, m.M11, m.M12, m.M13 + s.Y, m.M20, m.M21, m.M22, m.M23 + s.Z); } /// /// Multiplies a with a transformation (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(M34f m, Shift3f s) { return new M34f( m.M00, m.M01, m.M02, s.X * m.M00 + s.Y * m.M01 + s.Z * m.M02 + m.M03, m.M10, m.M11, m.M12, s.X * m.M10 + s.Y * m.M11 + s.Z * m.M12 + m.M13, m.M20, m.M21, m.M22, s.X * m.M20 + s.Y * m.M21 + s.Z * m.M22 + m.M23); } #endregion #region Shift / Rot, Scale Multiplication /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3f operator *(Shift3f a, Rot3f b) => new Euclidean3f(b, a.V); /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Shift3f a, Scale3f b) => new Affine3f((M33f)b, a.V); #endregion #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Shift3f s0, Shift3f s1) => s0.X == s1.X && s0.Y == s1.Y && s0.Z == s1.Z; /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Shift3f s0, Shift3f s1) => s0.X != s1.X || s0.Y != s1.Y || s0.Z != s1.Z; #endregion #region Static Creators /// /// Creates a transformation from a matrix. /// The matrix must only contain translation components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3f FromM34f(M34f m, float epsilon = (float)1e-6) { if (!M33f.Identity.ApproximateEquals((M33f)m, epsilon)) throw new ArgumentException("Matrix is not a pure translation matrix."); return new Shift3f(m.C3); } /// /// Creates a transformation from a translation matrix. /// The matrix has to be homogeneous and must not contain perspective components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3f FromM44f(M44f m, float epsilon = (float)1e-6) { if (!M33f.Identity.ApproximateEquals((M33f)m, epsilon)) throw new ArgumentException("Matrix is not a pure translation matrix."); if (!(m.M30.IsTiny(epsilon) && m.M31.IsTiny(epsilon) && m.M32.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (m.M33.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return new Shift3f(m.C3.XYZ / m.M33); } /// /// Creates a transformation from a . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3f FromEuclidean3f(Euclidean3f euclidean, float epsilon = 1e-5f) { if (!euclidean.Rot.ApproximateEquals(Rot3f.Identity, epsilon)) throw new ArgumentException("Euclidean transformation contains rotational component"); return new Shift3f(euclidean.Trans); } /// /// Creates a transformation from a . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3f FromSimilarity3f(Similarity3f similarity, float epsilon = 1e-5f) { if (!similarity.Scale.ApproximateEquals(1, epsilon)) throw new ArgumentException("Similarity transformation contains scaling component"); if (!similarity.Rot.ApproximateEquals(Rot3f.Identity, epsilon)) throw new ArgumentException("Similarity transformation contains rotational component"); return new Shift3f(similarity.Trans); } /// /// Creates a transformation from an . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3f FromAffine3f(Affine3f affine, float epsilon = 1e-5f) => FromM44f((M44f)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3f FromTrafo3f(Trafo3f trafo, float epsilon = 1e-5f) => FromM44f(trafo.Forward, epsilon); #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33f(Shift3f s) { return new M33f( 1, 0, s.X, 0, 1, s.Y, 0, 0, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M23f(Shift3f s) { return new M23f( 1, 0, s.X, 0, 1, s.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44f(Shift3f s) { return new M44f( 1, 0, 0, s.X, 0, 1, 0, s.Y, 0, 0, 1, s.Z, 0, 0, 0, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34f(Shift3f s) { return new M34f( 1, 0, 0, s.X, 0, 1, 0, s.Y, 0, 0, 1, s.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Euclidean3f(Shift3f s) => new Euclidean3f(Rot3f.Identity, s.V); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Similarity3f(Shift3f s) => new Similarity3f(1, Rot3f.Identity, s.V); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine3f(Shift3f s) => new Affine3f(M33f.Identity, s.V); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo3f(Shift3f s) => new Trafo3f((M44f)s, (M44f)s.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Shift3d(Shift3f s) => new Shift3d((V3d)s.V); /// /// Returns all values of a instance /// in a float[] array. /// public static explicit operator float[](Shift3f shift) { float[] array = new float[3]; array[0] = shift.X; array[1] = shift.Y; array[2] = shift.Z; return array; } #endregion #region Indexing public float this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => V[index]; [MethodImpl(MethodImplOptions.AggressiveInlining)] set => V[index] = value; } #endregion #region Overrides public override readonly int GetHashCode() { return V.GetHashCode(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Shift3f other) => X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z); public override readonly bool Equals(object other) => (other is Shift3f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", X, Y, Z); } public static Shift3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Shift3f( float.Parse(x[0], CultureInfo.InvariantCulture), float.Parse(x[1], CultureInfo.InvariantCulture), float.Parse(x[2], CultureInfo.InvariantCulture) ); } #endregion } public static partial class Shift { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3f Inverse(Shift3f shift) => shift.Inverse; /// /// Inverts a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Shift3f shift) { shift.V.X = -shift.V.X; shift.V.Y = -shift.V.Y; shift.V.Z = -shift.V.Z; } #endregion #region Transformations /// /// Transforms a vector by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Transform(this Shift3f s, V3f v) => new V3f(v.X + s.X, v.Y + s.Y, v.Z + s.Z); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvTransform(this Shift3f s, V3f v) => new V3f(v.X - s.X, v.Y - s.Y, v.Z - s.Z); /// /// Transforms a vector by a transformation. /// v.W is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Transform(this Shift3f s, V4f v) => new V4f(v.X + s.X, v.Y + s.Y, v.Z + s.Z, v.W); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f InvTransform(this Shift3f s, V4f v) => new V4f(v.X - s.X, v.Y - s.Y, v.Z - s.Z, v.W); #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Shift3f s0, Shift3f s1) { return ApproximateEquals(s0.V, s1.V, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Shift3f s0, Shift3f s1, float tolerance) { return ApproximateEquals(s0.V, s1.V, tolerance); } #endregion } #endregion #region Shift2d /// /// A 2-dimensional translational transform with different translation values /// in each dimension. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Shift2d : IEquatable { [DataMember] [XmlIgnore] public V2d V; #region Constructors /// /// Constructs a transformation from 2 doubles. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift2d(double x, double y) { V = new V2d(x, y); } /// /// Constructs a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift2d(V2d v) { V = v; } /// /// Constructs a copy of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift2d(Shift2d s) { V = s.V; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift2d(Shift2f shift) { V = (V2d)shift.V; } /// /// Constructs a transformation from a double-array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift2d(double[] array) { V = new V2d(array); } /// /// Constructs a transformation from a double-array starting from the given index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift2d(double[] array, int start) { V = new V2d(array, start); } #endregion #region Properties /// /// Gets and sets the X coordinate. /// public double X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.X = value; } } /// /// Gets and sets the Y coordinate. /// public double Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.Y = value; } } /// /// Gets the length of this transformation. /// public readonly double Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return V.Length; } } /// /// Gets the squared length of this transformation. /// public readonly double LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return V.LengthSquared; } } /// /// Gets the inverse of this transformation. /// public readonly Shift2d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Shift2d(-V); } } /// /// Gets the reciprocal of this transformation. /// public readonly Shift2d Reciprocal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift2d(1 / V); } #endregion #region Constants /// /// Gets the identity transformation. /// public static Shift2d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift2d(0, 0); } /// /// Gets a transformation with all components set to zero. /// Note: Equivalent to Identity. /// public static Shift2d Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Identity; } /// /// Gets a transformation with components (1, 0). /// public static Shift2d XAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift2d(1, 0); } /// /// Gets a transformation with components (0, 1). /// public static Shift2d YAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift2d(0, 1); } #endregion #region Arithmetic Operators /// /// Negates the values of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2d operator -(Shift2d shift) { return new Shift2d(-shift.X, -shift.Y); } #region Shift / Scalar /// /// Multiplies a transformation with a double scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2d operator *(Shift2d shift, double scalar) { return new Shift2d(shift.X * scalar, shift.Y * scalar); } /// /// Multiplies a double scalar with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2d operator *(double scalar, Shift2d shift) { return new Shift2d(shift.X * scalar, shift.Y * scalar); } /// /// Divides a transformation by a double scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2d operator /(Shift2d shift, double scalar) { return new Shift2d(shift.X / scalar, shift.Y / scalar); } /// /// Divides a double scalar by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2d operator /(double scalar, Shift2d shift) { return new Shift2d(scalar / shift.X, scalar / shift.Y); } #endregion #region Shift / Vector Multiplication /// /// Multiplies a transformation with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator *(Shift2d shift, V2d vector) { return new V2d(vector.X + shift.X, vector.Y + shift.Y); } #endregion #region Shift / Shift Multiplication /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2d operator *(Shift2d a, Shift2d b) => new Shift2d(a.X + b.X, a.Y + b.Y); /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3d operator *(Shift2d a, Shift3d b) => new Shift3d(a.X + b.X, a.Y + b.Y, b.Z); #endregion #region Shift / Matrix Multiplication /// /// Multiplies a transformation (as a 2x3 matrix) with a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(Shift2d shift, M22d matrix) { return new M23d(matrix, shift.V); } /// /// Multiplies a with a transformation (as a 2x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(M22d matrix, Shift2d shift) { return new M23d(matrix, matrix * shift.V); } /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator *(Shift2d s, M33d m) { return new M33d( m.M00 + s.X * m.M20, m.M01 + s.X * m.M21, m.M02 + s.X * m.M22, m.M10 + s.Y * m.M20, m.M11 + s.Y * m.M21, m.M12 + s.Y * m.M22, m.M20, m.M21, m.M22); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator *(M33d m, Shift2d s) { return new M33d( m.M00, m.M01, s.X * m.M00 + s.Y * m.M01 + m.M02, m.M10, m.M11, s.X * m.M10 + s.Y * m.M11 + m.M12, m.M20, m.M21, s.X * m.M20 + s.Y * m.M21 + m.M22); } /// /// Multiplies a transformation (as a 2x3 matrix) with a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(Shift2d s, M23d m) { return new M23d( m.M00, m.M01, m.M02 + s.X, m.M10, m.M11, m.M12 + s.Y); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(M23d m, Shift2d s) { return new M23d( m.M00, m.M01, s.X * m.M00 + s.Y * m.M01 + m.M02, m.M10, m.M11, s.X * m.M10 + s.Y * m.M11 + m.M12); } #endregion #region Shift / Rot, Scale Multiplication /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean2d operator *(Shift2d a, Rot2d b) => new Euclidean2d(b, a.V); /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Shift2d a, Scale2d b) => new Affine2d((M22d)b, a.V); #endregion #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Shift2d s0, Shift2d s1) => s0.X == s1.X && s0.Y == s1.Y; /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Shift2d s0, Shift2d s1) => s0.X != s1.X || s0.Y != s1.Y; #endregion #region Static Creators /// /// Creates a transformation from a matrix. /// The matrix must only contain translation components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2d FromM23d(M23d m, double epsilon = (double)1e-6) { if (!M22d.Identity.ApproximateEquals((M22d)m, epsilon)) throw new ArgumentException("Matrix is not a pure translation matrix."); return new Shift2d(m.C2); } /// /// Creates a transformation from a translation matrix. /// The matrix has to be homogeneous and must not contain perspective components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2d FromM33d(M33d m, double epsilon = (double)1e-6) { if (!M22d.Identity.ApproximateEquals((M22d)m, epsilon)) throw new ArgumentException("Matrix is not a pure translation matrix."); if (!(m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (m.M22.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return new Shift2d(m.C2.XY / m.M22); } /// /// Creates a transformation from a . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2d FromEuclidean2d(Euclidean2d euclidean, double epsilon = 1e-12) { if (!euclidean.Rot.ApproximateEquals(Rot2d.Identity, epsilon)) throw new ArgumentException("Euclidean transformation contains rotational component"); return new Shift2d(euclidean.Trans); } /// /// Creates a transformation from a . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2d FromSimilarity2d(Similarity2d similarity, double epsilon = 1e-12) { if (!similarity.Scale.ApproximateEquals(1, epsilon)) throw new ArgumentException("Similarity transformation contains scaling component"); if (!similarity.Rot.ApproximateEquals(Rot2d.Identity, epsilon)) throw new ArgumentException("Similarity transformation contains rotational component"); return new Shift2d(similarity.Trans); } /// /// Creates a transformation from an . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2d FromAffine2d(Affine2d affine, double epsilon = 1e-12) => FromM33d((M33d)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2d FromTrafo2d(Trafo2d trafo, double epsilon = 1e-12) => FromM33d(trafo.Forward, epsilon); #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33d(Shift2d s) { return new M33d( 1, 0, s.X, 0, 1, s.Y, 0, 0, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M23d(Shift2d s) { return new M23d( 1, 0, s.X, 0, 1, s.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44d(Shift2d s) { return new M44d( 1, 0, 0, s.X, 0, 1, 0, s.Y, 0, 0, 1, 0, 0, 0, 0, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34d(Shift2d s) { return new M34d( 1, 0, 0, s.X, 0, 1, 0, s.Y, 0, 0, 1, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Euclidean2d(Shift2d s) => new Euclidean2d(Rot2d.Identity, s.V); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Similarity2d(Shift2d s) => new Similarity2d(1, Rot2d.Identity, s.V); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine2d(Shift2d s) => new Affine2d(M22d.Identity, s.V); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo2d(Shift2d s) => new Trafo2d((M33d)s, (M33d)s.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Shift2f(Shift2d s) => new Shift2f((V2f)s.V); /// /// Returns all values of a instance /// in a double[] array. /// public static explicit operator double[](Shift2d shift) { double[] array = new double[2]; array[0] = shift.X; array[1] = shift.Y; return array; } #endregion #region Indexing public double this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => V[index]; [MethodImpl(MethodImplOptions.AggressiveInlining)] set => V[index] = value; } #endregion #region Overrides public override readonly int GetHashCode() { return V.GetHashCode(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Shift2d other) => X.Equals(other.X) && Y.Equals(other.Y); public override readonly bool Equals(object other) => (other is Shift2d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", X, Y); } public static Shift2d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Shift2d( double.Parse(x[0], CultureInfo.InvariantCulture), double.Parse(x[1], CultureInfo.InvariantCulture) ); } #endregion } public static partial class Shift { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift2d Inverse(Shift2d shift) => shift.Inverse; /// /// Inverts a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Shift2d shift) { shift.V.X = -shift.V.X; shift.V.Y = -shift.V.Y; } #endregion #region Transformations /// /// Transforms a vector by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Transform(this Shift2d s, V2d v) => new V2d(v.X + s.X, v.Y + s.Y); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d InvTransform(this Shift2d s, V2d v) => new V2d(v.X - s.X, v.Y - s.Y); /// /// Transforms a vector by a transformation. /// v.Z is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Transform(this Shift2d s, V3d v) => new V3d(v.X + s.X, v.Y + s.Y, v.Z); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvTransform(this Shift2d s, V3d v) => new V3d(v.X - s.X, v.Y - s.Y, v.Z); /// /// Transforms a vector by a transformation. /// v.Z and v.W are not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Transform(this Shift2d s, V4d v) => new V4d(v.X + s.X, v.Y + s.Y, v.Z, v.W); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d InvTransform(this Shift2d s, V4d v) => new V4d(v.X - s.X, v.Y - s.Y, v.Z, v.W); #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Shift2d s0, Shift2d s1) { return ApproximateEquals(s0.V, s1.V, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Shift2d s0, Shift2d s1, double tolerance) { return ApproximateEquals(s0.V, s1.V, tolerance); } #endregion } #endregion #region Shift3d /// /// A 3-dimensional translational transform with different translation values /// in each dimension. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Shift3d : IEquatable { [DataMember] [XmlIgnore] public V3d V; #region Constructors /// /// Constructs a transformation from 3 doubles. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift3d(double x, double y, double z) { V = new V3d(x, y, z); } /// /// Constructs a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift3d(V3d v) { V = v; } /// /// Constructs a copy of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift3d(Shift3d s) { V = s.V; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift3d(Shift3f shift) { V = (V3d)shift.V; } /// /// Constructs a transformation from a double-array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift3d(double[] array) { V = new V3d(array); } /// /// Constructs a transformation from a double-array starting from the given index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Shift3d(double[] array, int start) { V = new V3d(array, start); } #endregion #region Properties /// /// Gets and sets the X coordinate. /// public double X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.X = value; } } /// /// Gets and sets the Y coordinate. /// public double Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.Y = value; } } /// /// Gets and sets the Z coordinate. /// public double Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.Z = value; } } /// /// Gets the length of this transformation. /// public readonly double Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return V.Length; } } /// /// Gets the squared length of this transformation. /// public readonly double LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return V.LengthSquared; } } /// /// Gets the inverse of this transformation. /// public readonly Shift3d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new Shift3d(-V); } } /// /// Gets the reciprocal of this transformation. /// public readonly Shift3d Reciprocal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift3d(1 / V); } #endregion #region Constants /// /// Gets the identity transformation. /// public static Shift3d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift3d(0, 0, 0); } /// /// Gets a transformation with all components set to zero. /// Note: Equivalent to Identity. /// public static Shift3d Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Identity; } /// /// Gets a transformation with components (1, 0, 0). /// public static Shift3d XAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift3d(1, 0, 0); } /// /// Gets a transformation with components (0, 1, 0). /// public static Shift3d YAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift3d(0, 1, 0); } /// /// Gets a transformation with components (0, 0, 1). /// public static Shift3d ZAxis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Shift3d(0, 0, 1); } #endregion #region Arithmetic Operators /// /// Negates the values of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3d operator -(Shift3d shift) { return new Shift3d(-shift.X, -shift.Y, -shift.Z); } #region Shift / Scalar /// /// Multiplies a transformation with a double scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3d operator *(Shift3d shift, double scalar) { return new Shift3d(shift.X * scalar, shift.Y * scalar, shift.Z * scalar); } /// /// Multiplies a double scalar with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3d operator *(double scalar, Shift3d shift) { return new Shift3d(shift.X * scalar, shift.Y * scalar, shift.Z * scalar); } /// /// Divides a transformation by a double scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3d operator /(Shift3d shift, double scalar) { return new Shift3d(shift.X / scalar, shift.Y / scalar, shift.Z / scalar); } /// /// Divides a double scalar by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3d operator /(double scalar, Shift3d shift) { return new Shift3d(scalar / shift.X, scalar / shift.Y, scalar / shift.Z); } #endregion #region Shift / Vector Multiplication /// /// Multiplies a transformation with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator *(Shift3d shift, V3d vector) { return new V3d(vector.X + shift.X, vector.Y + shift.Y, vector.Z + shift.Z); } #endregion #region Shift / Shift Multiplication /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3d operator *(Shift3d a, Shift2d b) => new Shift3d(a.X + b.X, a.Y + b.Y, a.Z); /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3d operator *(Shift3d a, Shift3d b) => new Shift3d(a.X + b.X, a.Y + b.Y, a.Z + b.Z); #endregion #region Shift / Matrix Multiplication /// /// Multiplies a transformation (as a 3x4 matrix) with a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(Shift3d shift, M33d matrix) { return new M34d(matrix, shift.V); } /// /// Multiplies a with a transformation (as a 3x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(M33d matrix, Shift3d shift) { return new M34d(matrix, matrix * shift.V); } /// /// Multiplies a transformation (as a 4x4 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator *(Shift3d s, M44d m) { return new M44d( m.M00 + s.X * m.M30, m.M01 + s.X * m.M31, m.M02 + s.X * m.M32, m.M03 + s.X * m.M33, m.M10 + s.Y * m.M30, m.M11 + s.Y * m.M31, m.M12 + s.Y * m.M32, m.M13 + s.Y * m.M33, m.M20 + s.Z * m.M30, m.M21 + s.Z * m.M31, m.M22 + s.Z * m.M32, m.M23 + s.Z * m.M33, m.M30, m.M31, m.M32, m.M33); } /// /// Multiplies a with a transformation (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator *(M44d m, Shift3d s) { return new M44d( m.M00, m.M01, m.M02, s.X * m.M00 + s.Y * m.M01 + s.Z * m.M02 + m.M03, m.M10, m.M11, m.M12, s.X * m.M10 + s.Y * m.M11 + s.Z * m.M12 + m.M13, m.M20, m.M21, m.M22, s.X * m.M20 + s.Y * m.M21 + s.Z * m.M22 + m.M23, m.M30, m.M31, m.M32, s.X * m.M30 + s.Y * m.M31 + s.Z * m.M32 + m.M33); } /// /// Multiplies a transformation (as a 3x4 matrix) with a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(Shift3d s, M34d m) { return new M34d( m.M00, m.M01, m.M02, m.M03 + s.X, m.M10, m.M11, m.M12, m.M13 + s.Y, m.M20, m.M21, m.M22, m.M23 + s.Z); } /// /// Multiplies a with a transformation (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(M34d m, Shift3d s) { return new M34d( m.M00, m.M01, m.M02, s.X * m.M00 + s.Y * m.M01 + s.Z * m.M02 + m.M03, m.M10, m.M11, m.M12, s.X * m.M10 + s.Y * m.M11 + s.Z * m.M12 + m.M13, m.M20, m.M21, m.M22, s.X * m.M20 + s.Y * m.M21 + s.Z * m.M22 + m.M23); } #endregion #region Shift / Rot, Scale Multiplication /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Euclidean3d operator *(Shift3d a, Rot3d b) => new Euclidean3d(b, a.V); /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Shift3d a, Scale3d b) => new Affine3d((M33d)b, a.V); #endregion #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Shift3d s0, Shift3d s1) => s0.X == s1.X && s0.Y == s1.Y && s0.Z == s1.Z; /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Shift3d s0, Shift3d s1) => s0.X != s1.X || s0.Y != s1.Y || s0.Z != s1.Z; #endregion #region Static Creators /// /// Creates a transformation from a matrix. /// The matrix must only contain translation components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3d FromM34d(M34d m, double epsilon = (double)1e-6) { if (!M33d.Identity.ApproximateEquals((M33d)m, epsilon)) throw new ArgumentException("Matrix is not a pure translation matrix."); return new Shift3d(m.C3); } /// /// Creates a transformation from a translation matrix. /// The matrix has to be homogeneous and must not contain perspective components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3d FromM44d(M44d m, double epsilon = (double)1e-6) { if (!M33d.Identity.ApproximateEquals((M33d)m, epsilon)) throw new ArgumentException("Matrix is not a pure translation matrix."); if (!(m.M30.IsTiny(epsilon) && m.M31.IsTiny(epsilon) && m.M32.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (m.M33.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return new Shift3d(m.C3.XYZ / m.M33); } /// /// Creates a transformation from a . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3d FromEuclidean3d(Euclidean3d euclidean, double epsilon = 1e-12) { if (!euclidean.Rot.ApproximateEquals(Rot3d.Identity, epsilon)) throw new ArgumentException("Euclidean transformation contains rotational component"); return new Shift3d(euclidean.Trans); } /// /// Creates a transformation from a . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3d FromSimilarity3d(Similarity3d similarity, double epsilon = 1e-12) { if (!similarity.Scale.ApproximateEquals(1, epsilon)) throw new ArgumentException("Similarity transformation contains scaling component"); if (!similarity.Rot.ApproximateEquals(Rot3d.Identity, epsilon)) throw new ArgumentException("Similarity transformation contains rotational component"); return new Shift3d(similarity.Trans); } /// /// Creates a transformation from an . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3d FromAffine3d(Affine3d affine, double epsilon = 1e-12) => FromM44d((M44d)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3d FromTrafo3d(Trafo3d trafo, double epsilon = 1e-12) => FromM44d(trafo.Forward, epsilon); #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33d(Shift3d s) { return new M33d( 1, 0, s.X, 0, 1, s.Y, 0, 0, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M23d(Shift3d s) { return new M23d( 1, 0, s.X, 0, 1, s.Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44d(Shift3d s) { return new M44d( 1, 0, 0, s.X, 0, 1, 0, s.Y, 0, 0, 1, s.Z, 0, 0, 0, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34d(Shift3d s) { return new M34d( 1, 0, 0, s.X, 0, 1, 0, s.Y, 0, 0, 1, s.Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Euclidean3d(Shift3d s) => new Euclidean3d(Rot3d.Identity, s.V); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Similarity3d(Shift3d s) => new Similarity3d(1, Rot3d.Identity, s.V); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine3d(Shift3d s) => new Affine3d(M33d.Identity, s.V); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo3d(Shift3d s) => new Trafo3d((M44d)s, (M44d)s.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Shift3f(Shift3d s) => new Shift3f((V3f)s.V); /// /// Returns all values of a instance /// in a double[] array. /// public static explicit operator double[](Shift3d shift) { double[] array = new double[3]; array[0] = shift.X; array[1] = shift.Y; array[2] = shift.Z; return array; } #endregion #region Indexing public double this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => V[index]; [MethodImpl(MethodImplOptions.AggressiveInlining)] set => V[index] = value; } #endregion #region Overrides public override readonly int GetHashCode() { return V.GetHashCode(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Shift3d other) => X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z); public override readonly bool Equals(object other) => (other is Shift3d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}, {2}]", X, Y, Z); } public static Shift3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Shift3d( double.Parse(x[0], CultureInfo.InvariantCulture), double.Parse(x[1], CultureInfo.InvariantCulture), double.Parse(x[2], CultureInfo.InvariantCulture) ); } #endregion } public static partial class Shift { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Shift3d Inverse(Shift3d shift) => shift.Inverse; /// /// Inverts a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Shift3d shift) { shift.V.X = -shift.V.X; shift.V.Y = -shift.V.Y; shift.V.Z = -shift.V.Z; } #endregion #region Transformations /// /// Transforms a vector by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Transform(this Shift3d s, V3d v) => new V3d(v.X + s.X, v.Y + s.Y, v.Z + s.Z); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvTransform(this Shift3d s, V3d v) => new V3d(v.X - s.X, v.Y - s.Y, v.Z - s.Z); /// /// Transforms a vector by a transformation. /// v.W is not modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Transform(this Shift3d s, V4d v) => new V4d(v.X + s.X, v.Y + s.Y, v.Z + s.Z, v.W); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d InvTransform(this Shift3d s, V4d v) => new V4d(v.X - s.X, v.Y - s.Y, v.Z - s.Z, v.W); #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Shift3d s0, Shift3d s1) { return ApproximateEquals(s0.V, s1.V, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Shift3d s0, Shift3d s1, double tolerance) { return ApproximateEquals(s0.V, s1.V, tolerance); } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Shift_template.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace Aardvark.Base { // AUTOGENERATED CODE - DO NOT CHANGE! //# Action comma = () => Out(", "); //# Action commaln = () => Out("," + Environment.NewLine); //# Action add = () => Out(" + "); //# Action and = () => Out(" && "); //# Action or = () => Out(" || "); //# Action andLit = () => Out(" and "); //# var fields = new[] {"X", "Y", "Z", "W"}; //# var fieldsL = new[] {"x", "y", "z", "w"}; //# foreach (var isDouble in new[] { false, true }) { //# for (int d = 2; d <= 3; d++) { //# var d1 = d + 1; //# var ftype = isDouble ? "double" : "float"; //# var xyz = "XYZW".Substring(0, d); //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Shift" + d + tc; //# var type2 = "Shift" + d + tc2; //# var trafodt = "Trafo" + d + tc; //# var affinedt = "Affine" + d + tc; //# var euclideandt = "Euclidean" + d + tc; //# var rotdt = "Rot" + d + tc; //# var shiftdt = "Shift" + d + tc; //# var scaledt = "Scale" + d + tc; //# var similaritydt = "Similarity" + d + tc; //# var mddt = "M" + d + d + tc; //# var md1d1t = "M" + (d + 1) + (d + 1) + tc; //# var mdd1t = "M" + d + (d + 1) + tc; //# var vdt = "V" + d + tc; //# var vdt2 = "V" + d + tc2; //# var dfields = fields.Take(d).ToArray(); //# var dfieldsL = fieldsL.Take(d).ToArray(); //# var fd = fields[d]; //# var eps = isDouble ? "1e-12" : "1e-5f"; #region __type__ /// /// A __d__-dimensional translational transform with different translation values /// in each dimension. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__> { [DataMember] [XmlIgnore] public __vdt__ V; #region Constructors /// /// Constructs a transformation from __d__ __ftype__s. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(/*# dfieldsL.ForEach(f => { */__ftype__ __f__/*# }, comma); */) { V = new __vdt__(/*# dfieldsL.ForEach(f => { */__f__/*# }, comma); */); } /// /// Constructs a from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__vdt__ v) { V = v; } /// /// Constructs a copy of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ s) { V = s.V; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ shift) { V = (__vdt__)shift.V; } /// /// Constructs a transformation from a __ftype__-array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__[] array) { V = new __vdt__(array); } /// /// Constructs a transformation from a __ftype__-array starting from the given index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__[] array, int start) { V = new __vdt__(array, start); } #endregion #region Properties //# dfields.ForEach(f => { /// /// Gets and sets the __f__ coordinate. /// public __ftype__ __f__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return V.__f__; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { V.__f__ = value; } } //# }); /// /// Gets the length of this transformation. /// public readonly __ftype__ Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return V.Length; } } /// /// Gets the squared length of this transformation. /// public readonly __ftype__ LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return V.LengthSquared; } } /// /// Gets the inverse of this transformation. /// public readonly __type__ Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new __type__(-V); } } /// /// Gets the reciprocal of this transformation. /// public readonly __type__ Reciprocal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(1 / V); } #endregion #region Constants /// /// Gets the identity transformation. /// public static __type__ Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(/*# dfields.ForEach(f => { */0/*# }, comma); */); } /// /// Gets a transformation with all components set to zero. /// Note: Equivalent to Identity. /// public static __type__ Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Identity; } //# dfields.ForEach((fi, i) => { /// /// Gets a transformation with components (/*# dfields.ForEach((fj, j) => { var val = (i != j) ? "0" : "1"; */__val__/*# }, comma); */). /// public static __type__ __fi__Axis { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(/*# dfields.ForEach((fj, j) => { var val = (i != j) ? "0" : "1"; */__val__/*# }, comma); */); } //# }); #endregion #region Arithmetic Operators /// /// Negates the values of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator -(__type__ shift) { return new __type__(/*# dfields.ForEach(f => { */-shift.__f__/*# }, comma); */); } #region Shift / Scalar /// /// Multiplies a transformation with a __ftype__ scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ shift, __ftype__ scalar) { return new __type__(/*# dfields.ForEach(f => { */shift.__f__ * scalar/*# }, comma); */); } /// /// Multiplies a __ftype__ scalar with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__ftype__ scalar, __type__ shift) { return new __type__(/*# dfields.ForEach(f => { */shift.__f__ * scalar/*# }, comma); */); } /// /// Divides a transformation by a __ftype__ scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator /(__type__ shift, __ftype__ scalar) { return new __type__(/*# dfields.ForEach(f => { */shift.__f__ / scalar/*# }, comma); */); } /// /// Divides a __ftype__ scalar by a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator /(__ftype__ scalar, __type__ shift) { return new __type__(/*# dfields.ForEach(f => { */scalar / shift.__f__/*# }, comma); */); } #endregion #region Shift / Vector Multiplication /// /// Multiplies a transformation with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vdt__ operator *(__type__ shift, __vdt__ vector) { return new __vdt__(/*# dfields.ForEach(f => { */vector.__f__ + shift.__f__/*# }, comma); */); } #endregion #region Shift / Shift Multiplication //# for (int n = 2; n <= 3; n++) { //# var r = (d > n) ? d : n; //# var m = (d < n) ? d : n; //# var mfields = fields.Take(m); //# var rem = r - m; //# var ntype = "Shift" + n + tc; //# var rtype = "Shift" + r + tc; /// /// Multiplies a transformation with a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ operator *(__type__ a, __ntype__ b) => new __rtype__(/*# mfields.ForEach(f => {*/a.__f__ + b.__f__/*# }, comma); if (r > m) {*/, /*# rem.ForEach(i => { var x = (d > n) ? "a" : "b"; var f = fields[m + i]; */__x__.__f__/*#}, comma); } */); //# } #endregion #region Shift / Matrix Multiplication /// /// Multiplies a transformation (as a __d__x__d1__ matrix) with a (as a __d1__x__d1__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mdd1t__ operator *(__type__ shift, __mddt__ matrix) { return new __mdd1t__(matrix, shift.V); } /// /// Multiplies a with a transformation (as a __d__x__d1__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mdd1t__ operator *(__mddt__ matrix, __type__ shift) { return new __mdd1t__(matrix, matrix * shift.V); } /// /// Multiplies a transformation (as a __d1__x__d1__ matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __md1d1t__ operator *(__type__ s, __md1d1t__ m) { return new __md1d1t__(/*# dfields.ForEach((fi, i) => { d1.ForEach(j => { */ m.M__i____j__ + s.__fi__ * m.M__d____j__/*# }, comma); }, commaln);*/, /*# d1.ForEach(j => {*/m.M__d____j__/*# }, comma);*/); } /// /// Multiplies a with a transformation (as a __d1__x__d1__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __md1d1t__ operator *(__md1d1t__ m, __type__ s) { return new __md1d1t__(/*# d1.ForEach(i => { dfields.ForEach((fj, j) => { */ m.M__i____j__/*# }, comma);*/, /*# dfields.ForEach((fj, j) => { */s.__fj__ * m.M__i____j__/*# }, add); */ + m.M__i____d__/*# }, commaln);*/); } /// /// Multiplies a transformation (as a __d__x__d1__ matrix) with a (as a __d1__x__d1__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mdd1t__ operator *(__type__ s, __mdd1t__ m) { return new __mdd1t__(/*# dfields.ForEach((fi, i) => { */ /*# dfields.ForEach((fj, j) => {*/m.M__i____j__/*# }, comma);*/, m.M__i____d__ + s.__fi__/*# }, comma);*/); } /// /// Multiplies a with a transformation (as a __d1__x__d1__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mdd1t__ operator *(__mdd1t__ m, __type__ s) { return new __mdd1t__(/*# d.ForEach(i => { dfields.ForEach((fj, j) => { */ m.M__i____j__/*# }, comma);*/, /*# dfields.ForEach((fj, j) => { */s.__fj__ * m.M__i____j__/*# }, add); */ + m.M__i____d__/*# }, commaln);*/); } #endregion #region Shift / Rot, Scale Multiplication /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __euclideandt__ operator *(__type__ a, __rotdt__ b) => new __euclideandt__(b, a.V); /// /// Multiplies a transformation with a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __affinedt__ operator *(__type__ a, __scaledt__ b) => new __affinedt__((__mddt__)b, a.V); #endregion #endregion #region Comparison Operators /// /// Checks whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ s0, __type__ s1) => /*# dfields.ForEach(f => {*/s0.__f__ == s1.__f__/*# }, and);*/; /// /// Checks whether two transformations are different. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ s0, __type__ s1) => /*# dfields.ForEach(f => {*/s0.__f__ != s1.__f__/*# }, or);*/; #endregion #region Static Creators /// /// Creates a transformation from a matrix. /// The matrix must only contain translation components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__mdd1t__(__mdd1t__ m, __ftype__ epsilon = (__ftype__)1e-6) { if (!__mddt__.Identity.ApproximateEquals((__mddt__)m, epsilon)) throw new ArgumentException("Matrix is not a pure translation matrix."); return new __type__(m.C__d__); } /// /// Creates a transformation from a translation matrix. /// The matrix has to be homogeneous and must not contain perspective components. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__md1d1t__(__md1d1t__ m, __ftype__ epsilon = (__ftype__)1e-6) { if (!__mddt__.Identity.ApproximateEquals((__mddt__)m, epsilon)) throw new ArgumentException("Matrix is not a pure translation matrix."); if (!(/*#d.ForEach(j => {*/m.M__d____j__.IsTiny(epsilon)/*# }, and);*/)) throw new ArgumentException("Matrix contains perspective components."); if (m.M__d____d__.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return new __type__(m.C__d__.__xyz__ / m.M__d____d__); } /// /// Creates a transformation from a . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__euclideandt__(__euclideandt__ euclidean, __ftype__ epsilon = __eps__) { if (!euclidean.Rot.ApproximateEquals(__rotdt__.Identity, epsilon)) throw new ArgumentException("Euclidean transformation contains rotational component"); return new __type__(euclidean.Trans); } /// /// Creates a transformation from a . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__similaritydt__(__similaritydt__ similarity, __ftype__ epsilon = __eps__) { if (!similarity.Scale.ApproximateEquals(1, epsilon)) throw new ArgumentException("Similarity transformation contains scaling component"); if (!similarity.Rot.ApproximateEquals(__rotdt__.Identity, epsilon)) throw new ArgumentException("Similarity transformation contains rotational component"); return new __type__(similarity.Trans); } /// /// Creates a transformation from an . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__affinedt__(__affinedt__ affine, __ftype__ epsilon = __eps__) => From__md1d1t__((__md1d1t__)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__trafodt__(__trafodt__ trafo, __ftype__ epsilon = __eps__) => From__md1d1t__(trafo.Forward, epsilon); #endregion #region Conversion //# for (int n = 3; n <= 4; n++) { //# var m = n - 1; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M__n____n____tc__(__type__ s) { return new M__n____n____tc__(/*# fields.Take(m).ForEach((fi, i) => { */ /*# var f = (i < d) ? "s." + fi : "0"; m.ForEach(j => { var x = (i == j) ? "1" : "0"; */__x__/*# }, comma);*/, __f__/*# }, comma);*/, /*# m.ForEach(i => { */0/*# }, comma);*/, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M__m____n____tc__(__type__ s) { return new M__m____n____tc__(/*# fields.Take(m).ForEach((fi, i) => { */ /*# var f = (i < d) ? "s." + fi : "0"; m.ForEach(j => { var x = (i == j) ? "1" : "0"; */__x__/*# }, comma);*/, __f__/*# }, comma);*/); } //# } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __euclideandt__(__type__ s) => new __euclideandt__(__rotdt__.Identity, s.V); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __similaritydt__(__type__ s) => new __similaritydt__(1, __rotdt__.Identity, s.V); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __affinedt__(__type__ s) => new __affinedt__(__mddt__.Identity, s.V); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __trafodt__(__type__ s) => new __trafodt__((__md1d1t__)s, (__md1d1t__)s.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type2__(__type__ s) => new __type2__((__vdt2__)s.V); /// /// Returns all values of a instance /// in a __ftype__[] array. /// public static explicit operator __ftype__[](__type__ shift) { __ftype__[] array = new __ftype__[__d__]; /*# dfields.ForEach((f, i) => {*/array[__i__] = shift.__f__; /*# });*/return array; } #endregion #region Indexing public __ftype__ this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => V[index]; [MethodImpl(MethodImplOptions.AggressiveInlining)] set => V[index] = value; } #endregion #region Overrides public override readonly int GetHashCode() { return V.GetHashCode(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => /*# dfields.ForEach(f => {*/__f__.Equals(other.__f__)/*# }, and);*/; public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[/*# d.ForEach(i => {*/{__i__}/*# }, comma);*/]", /*# dfields.ForEach(f => {*/__f__/*#}, comma);*/); } public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__(/*# d.ForEach(i => {*/ __ftype__.Parse(x[__i__], CultureInfo.InvariantCulture)/*# }, comma);*/ ); } #endregion } public static partial class Shift { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Inverse(__type__ shift) => shift.Inverse; /// /// Inverts a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref __type__ shift) { //# dfields.ForEach(f => { shift.V.__f__ = -shift.V.__f__; //# }); } #endregion #region Transformations //# for (int n = d; n <= 4; n++) { //# var vec = "V" + n + tc; //# var rem = n - d; //# var constfields = fields.Skip(d).Take(rem); //# var isare = (rem > 1) ? "are" : "is"; /// /// Transforms a vector by a transformation./*# if (rem > 0) { */ /// /*# constfields.ForEach(f => {*/v.__f__/*# }, andLit); */ __isare__ not modified./*# }*/ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vec__ Transform(this __type__ s, __vec__ v) => new __vec__(/*# dfields.ForEach(f => {*/v.__f__ + s.__f__/*# }, comma); if (rem > 0) {*/, /*# rem.ForEach(i => { var f = fields[d + i]; */v.__f__/*#}, comma); } */); /// /// Transforms a vector by the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vec__ InvTransform(this __type__ s, __vec__ v) => new __vec__(/*# dfields.ForEach(f => {*/v.__f__ - s.__f__/*# }, comma); if (rem > 0) {*/, /*# rem.ForEach(i => { var f = fields[d + i]; */v.__f__/*#}, comma); } */); //# } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ s0, __type__ s1) { return ApproximateEquals(s0.V, s1.V, Constant<__ftype__>.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ s0, __type__ s1, __ftype__ tolerance) { return ApproximateEquals(s0.V, s1.V, tolerance); } #endregion } #endregion //# } } } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Similarity_auto.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; namespace Aardvark.Base { #region Similarity2f /// /// Represents a Similarity Transformation in 2D that is composed of a /// Uniform Scale and a subsequent Euclidean transformation (2D rotation Rot and a subsequent translation by a 2D vector Trans). /// This is an angle preserving Transformation. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Similarity2f : IEquatable { [DataMember] public float Scale; [DataMember] public Euclidean2f Euclidean; /// /// Gets the rotational component of this transformation. /// public readonly Rot2f Rot { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Euclidean.Rot; } } /// /// Gets the translational component of this transformation. /// public readonly V2f Trans { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Euclidean.Trans; } } #region Constructors /// /// Constructs a copy of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2f(Similarity2f s) { Scale = s.Scale; Euclidean = s.Euclidean; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2f(Similarity2d s) { Scale = (float)s.Scale; Euclidean = (Euclidean2f)s.Euclidean; } /// /// Creates a similarity transformation from an uniform scale by factor . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2f(float scale) { Scale = scale; Euclidean = Euclidean2f.Identity; } /// /// Creates a similarity transformation from a rigid transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2f(Euclidean2f euclideanTransformation) { Scale = 1; Euclidean = euclideanTransformation; } /// /// Constructs a similarity transformation from a rotation and translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2f(Rot2f rotation, V2f translation) { Scale = 1; Euclidean = new Euclidean2f(rotation, translation); } /// /// Constructs a similarity transformation from a rotation and translation by (, ). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2f(Rot2f rotation, float tX, float tY) { Scale = 1; Euclidean = new Euclidean2f(rotation, tX, tY); } /// /// Creates a similarity transformation from a uniform scale by factor , and a (subsequent) rigid transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2f(float scale, Euclidean2f euclideanTransformation) { Scale = scale; Euclidean = euclideanTransformation; } /// /// Constructs a similarity transformation from a uniform scale by factor , and a (subsequent) rotation and translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2f(float scale, Rot2f rotation, V2f translation) { Scale = scale; Euclidean = new Euclidean2f(rotation, translation); } /// /// Constructs a similarity transformation from a uniform scale by factor , and a (subsequent) rotation and and translation by (, ). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2f(float scale, Rot2f rotation, float tX, float tY) { Scale = scale; Euclidean = new Euclidean2f(rotation, tX, tY); } #endregion #region Constants /// /// Gets the identity transformation. /// public static Similarity2f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Similarity2f(1, Euclidean2f.Identity); } #endregion #region Similarity Transformation Arithmetics /// /// Gets the (multiplicative) inverse of this Similarity transformation. /// [1/Scale, Rot^T,-Rot^T Trans/Scale] /// public readonly Similarity2f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var newS = 1 / Scale; var newR = Euclidean.Inverse; newR.Trans *= newS; return new Similarity2f(newS, newR); } } #endregion #region Arithmetic Operators /// /// Multiplies two Similarity transformations. /// This concatenates the two similarity transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f operator *(Similarity2f a, Similarity2f b) { //a.Scale * b.Scale, a.Rot * b.Rot, a.Trans + a.Rot * a.Scale * b.Trans return new Similarity2f(a.Scale * b.Scale, new Euclidean2f( a.Rot * b.Rot, a.Trans + a.Rot.Transform(a.Scale * b.Trans)) ); } /// /// Transforms a vector by a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator *(Similarity2f s, V3f v) => s.Euclidean * new V3f(s.Scale * v.X, s.Scale * v.Y, v.Z); /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator *(Similarity2f s, M33f m) { var t = (M23f)s; return new M33f( t.M00 * m.M00 + t.M01 * m.M10 + t.M02 * m.M20, t.M00 * m.M01 + t.M01 * m.M11 + t.M02 * m.M21, t.M00 * m.M02 + t.M01 * m.M12 + t.M02 * m.M22, t.M10 * m.M00 + t.M11 * m.M10 + t.M12 * m.M20, t.M10 * m.M01 + t.M11 * m.M11 + t.M12 * m.M21, t.M10 * m.M02 + t.M11 * m.M12 + t.M12 * m.M22, m.M20, m.M21, m.M22); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f operator *(M33f m, Similarity2f s) { var t = (M23f)s; return new M33f( m.M00 * t.M00 + m.M01 * t.M10, m.M00 * t.M01 + m.M01 * t.M11, m.M00 * t.M02 + m.M01 * t.M12 + m.M02, m.M10 * t.M00 + m.M11 * t.M10, m.M10 * t.M01 + m.M11 * t.M11, m.M10 * t.M02 + m.M11 * t.M12 + m.M12, m.M20 * t.M00 + m.M21 * t.M10, m.M20 * t.M01 + m.M21 * t.M11, m.M20 * t.M02 + m.M21 * t.M12 + m.M22); } /// /// Multiplies a transformation (as a 2x3 matrix) with a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(Similarity2f s, M23f m) { var t = (M23f)s; return new M23f( t.M00 * m.M00 + t.M01 * m.M10, t.M00 * m.M01 + t.M01 * m.M11, t.M00 * m.M02 + t.M01 * m.M12 + t.M02, t.M10 * m.M00 + t.M11 * m.M10, t.M10 * m.M01 + t.M11 * m.M11, t.M10 * m.M02 + t.M11 * m.M12 + t.M12); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(M23f m, Similarity2f s) { var t = (M23f)s; return new M23f( m.M00 * t.M00 + m.M01 * t.M10, m.M00 * t.M01 + m.M01 * t.M11, m.M00 * t.M02 + m.M01 * t.M12 + m.M02, m.M10 * t.M00 + m.M11 * t.M10, m.M10 * t.M01 + m.M11 * t.M11, m.M10 * t.M02 + m.M11 * t.M12 + m.M12); } /// /// Multiplies a (as a 2x3 matrix) and a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(Similarity2f s, M22f m) => new M23f(s.Rot * m * s.Scale, s.Trans); /// /// Multiplies a and a (as a 2x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23f operator *(M22f m, Similarity2f s) => new M23f(s.Scale * m * s.Rot, m * s.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f operator *(Similarity2f s, Rot2f r) => new Similarity2f(s.Scale, s.Euclidean * r); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f operator *(Rot2f r, Similarity2f s) => new Similarity2f(s.Scale, r * s.Euclidean); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f operator *(Similarity2f a, Shift2f b) => new Similarity2f(a.Scale, a.Euclidean * (a.Scale * b)); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f operator *(Shift2f a, Similarity2f b) => new Similarity2f(b.Scale, a * b.Euclidean); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Similarity2f a, Scale2f b) { var t = (M22f)a; return new Affine2f(new M22f( t.M00 * b.X, t.M01 * b.Y, t.M10 * b.X, t.M11 * b.Y), a.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2f operator *(Scale2f a, Similarity2f b) { var t = (M22f)b; return new Affine2f(new M22f( t.M00 * a.X, t.M01 * a.X, t.M10 * a.Y, t.M11 * a.Y), b.Trans * a.V); } /// /// Multiplies an Euclidean transformation by a Similarity transformation. /// This concatenates the two transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f operator *(Euclidean2f a, Similarity2f b) { return new Similarity2f(b.Scale, a * b.Euclidean); //return (Similarity2f)a * b; } /// /// Multiplies a Similarity transformation by an Euclidean transformation. /// This concatenates the two transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f operator *(Similarity2f a, Euclidean2f b) { return a * (Similarity2f)b; } #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Similarity2f t0, Similarity2f t1) { return t0.Scale == t1.Scale && t0.Euclidean == t1.Euclidean; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Similarity2f t0, Similarity2f t1) { return !(t0 == t1); } #endregion #region Static Creators /// /// Creates a transformation from a matrix and a translation . /// The matrix must not contain a non-uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f FromM22fAndV2f(M22f m, V2f trans, float epsilon = 1e-5f) { var s0 = m.C0.Norm2; var s1 = m.C1.Norm2; var s = (s0 * s1).Pow(1.0f / 2); //geometric mean of scale if (!((s0 / s - 1).IsTiny(epsilon) && (s1 / s - 1).IsTiny(epsilon))) throw new ArgumentException("Matrix features non-uniform scaling"); m /= s; return new Similarity2f(s, Euclidean2f.FromM22fAndV2f(m, trans)); } /// /// Creates a transformation from a matrix. /// The matrix must not contain a non-uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f FromM23f(M23f m, float epsilon = 1e-5f) => FromM22fAndV2f((M22f)m, m.C2); /// /// Creates a transformation from a matrix. /// The matrix has to be homogeneous and must not contain perspective components or /// a non-uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f FromM33f(M33f m, float epsilon = 1e-5f) { if (!(m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (m.M22.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return FromM22fAndV2f(((M22f)m) / m.M22, m.C2.XY); } /// /// Creates a transformation from an . /// The transformation must represent a uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f FromScale2f(Scale2f scale, float epsilon = 1e-5f) { var s = (scale.X * scale.Y).Pow(1.0f / 2); if (!scale.ApproximateEquals(new Scale2f(s), epsilon)) throw new ArgumentException("Matrix features non-uniform scaling"); return new Similarity2f(s, Euclidean2f.Identity); } /// /// Creates a transformation from an . /// The transformation must only consist of a uniform scale, rotation, and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f FromAffine2f(Affine2f affine, float epsilon = 1e-5f) => FromM33f((M33f)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a uniform scale, rotation, and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f FromTrafo2f(Trafo2f trafo, float epsilon = 1e-5f) => FromM33f(trafo.Forward, epsilon); /// /// Creates a scaling transformation using a uniform scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f Scaling(float scaleFactor) => new Similarity2f(scaleFactor); #region Translation /// /// Creates a transformation with the translational component given by 2 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f Translation(float tX, float tY) => new Similarity2f(Rot2f.Identity, tX, tY); /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f Translation(V2f vector) => new Similarity2f(Rot2f.Identity, vector); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f Translation(Shift2f shift) => new Similarity2f(Rot2f.Identity, shift.V); #endregion #region Rotation /// /// Creates a rotation transformation from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f Rotation(Rot2f rot) => new Similarity2f(rot, V2f.Zero); /// /// Creates a rotation transformation with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f Rotation(float angleInRadians) => new Similarity2f(new Rot2f(angleInRadians), V2f.Zero); /// /// Creates a rotation transformation with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f RotationInDegrees(float angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); #endregion #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M23f(Similarity2f s) { M23f rv = (M23f)s.Euclidean; rv.M00 *= s.Scale; rv.M01 *= s.Scale; rv.M10 *= s.Scale; rv.M11 *= s.Scale; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M22f(Similarity2f s) { M22f rv = (M22f)s.Euclidean; rv.M00 *= s.Scale; rv.M01 *= s.Scale; rv.M10 *= s.Scale; rv.M11 *= s.Scale; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33f(Similarity2f s) { M33f rv = (M33f)s.Euclidean; rv.M00 *= s.Scale; rv.M01 *= s.Scale; rv.M10 *= s.Scale; rv.M11 *= s.Scale; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine2f(Similarity2f s) { var m = (M23f)s; return new Affine2f((M22f)m, m.C2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo2f(Similarity2f s) => new Trafo2f((M33f)s, (M33f)s.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Similarity2d(Similarity2f s) => new Similarity2d((double)s.Scale, (Euclidean2d)s.Euclidean); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Scale, Euclidean); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Similarity2f other) => Scale.Equals(other.Scale) && Euclidean.Equals(other.Euclidean); public override readonly bool Equals(object other) => (other is Similarity2f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Scale, Euclidean); } public static Similarity2f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Similarity2f(float.Parse(x[0], CultureInfo.InvariantCulture), Euclidean2f.Parse(x[1])); } #endregion } public static partial class Similarity { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2f Inverse(Similarity2f s) => s.Inverse; /// /// Inverts the similarity transformation (multiplicative inverse). /// this = [1/Scale, Rot^T,-Rot^T Trans/Scale] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Similarity2f t) { t.Scale = 1 / t.Scale; t.Euclidean.Invert(); t.Euclidean.Trans *= t.Scale; } #endregion #region Transform /// /// Transforms a by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Transform(this Similarity2f s, V3f v) => s * v; /// /// Transforms direction vector v (v.Z is presumed 0.0) by similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f TransformDir(this Similarity2f t, V2f v) { return t.Euclidean.TransformDir(t.Scale * v); } /// /// Transforms point p (p.Z is presumed 1.0) by similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f TransformPos(this Similarity2f t, V2f p) { return t.Euclidean.TransformPos(t.Scale * p); } /// /// Transforms direction vector v (v.Z is presumed 0.0) by the inverse of the similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f InvTransformDir(this Similarity2f t, V2f v) { return t.Euclidean.InvTransformDir(v) / t.Scale; } /// /// Transforms point p (p.Z is presumed 1.0) by the inverse of the similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f InvTransformPos(this Similarity2f t, V2f p) { return t.Euclidean.InvTransformPos(p) / t.Scale; } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Similarity2f t0, Similarity2f t1) { return ApproximateEquals(t0, t1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Similarity2f t0, Similarity2f t1, float tol) { return t0.Scale.ApproximateEquals(t1.Scale, tol) && t0.Euclidean.ApproximateEquals(t1.Euclidean, tol); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Similarity2f t0, Similarity2f t1, float angleTol, float posTol, float scaleTol) { return t0.Scale.ApproximateEquals(t1.Scale, scaleTol) && t0.Euclidean.ApproximateEquals(t1.Euclidean, angleTol, posTol); } #endregion } #endregion #region Similarity3f /// /// Represents a Similarity Transformation in 3D that is composed of a /// Uniform Scale and a subsequent Euclidean transformation (3D rotation Rot and a subsequent translation by a 3D vector Trans). /// This is an angle preserving Transformation. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Similarity3f : IEquatable { [DataMember] public float Scale; [DataMember] public Euclidean3f Euclidean; /// /// Gets the rotational component of this transformation. /// public readonly Rot3f Rot { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Euclidean.Rot; } } /// /// Gets the translational component of this transformation. /// public readonly V3f Trans { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Euclidean.Trans; } } #region Constructors /// /// Constructs a copy of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3f(Similarity3f s) { Scale = s.Scale; Euclidean = s.Euclidean; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3f(Similarity3d s) { Scale = (float)s.Scale; Euclidean = (Euclidean3f)s.Euclidean; } /// /// Creates a similarity transformation from an uniform scale by factor . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3f(float scale) { Scale = scale; Euclidean = Euclidean3f.Identity; } /// /// Creates a similarity transformation from a rigid transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3f(Euclidean3f euclideanTransformation) { Scale = 1; Euclidean = euclideanTransformation; } /// /// Constructs a similarity transformation from a rotation and translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3f(Rot3f rotation, V3f translation) { Scale = 1; Euclidean = new Euclidean3f(rotation, translation); } /// /// Constructs a similarity transformation from a rotation and translation by (, , ). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3f(Rot3f rotation, float tX, float tY, float tZ) { Scale = 1; Euclidean = new Euclidean3f(rotation, tX, tY, tZ); } /// /// Creates a similarity transformation from a uniform scale by factor , and a (subsequent) rigid transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3f(float scale, Euclidean3f euclideanTransformation) { Scale = scale; Euclidean = euclideanTransformation; } /// /// Constructs a similarity transformation from a uniform scale by factor , and a (subsequent) rotation and translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3f(float scale, Rot3f rotation, V3f translation) { Scale = scale; Euclidean = new Euclidean3f(rotation, translation); } /// /// Constructs a similarity transformation from a uniform scale by factor , and a (subsequent) rotation and and translation by (, , ). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3f(float scale, Rot3f rotation, float tX, float tY, float tZ) { Scale = scale; Euclidean = new Euclidean3f(rotation, tX, tY, tZ); } #endregion #region Constants /// /// Gets the identity transformation. /// public static Similarity3f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Similarity3f(1, Euclidean3f.Identity); } #endregion #region Similarity Transformation Arithmetics /// /// Returns a new version of this Similarity transformation with a normalized rotation quaternion. /// public readonly Similarity3f Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Similarity3f(Scale, Euclidean.Normalized); } /// /// Gets the (multiplicative) inverse of this Similarity transformation. /// [1/Scale, Rot^T,-Rot^T Trans/Scale] /// public readonly Similarity3f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var newS = 1 / Scale; var newR = Euclidean.Inverse; newR.Trans *= newS; return new Similarity3f(newS, newR); } } #endregion #region Arithmetic Operators /// /// Multiplies two Similarity transformations. /// This concatenates the two similarity transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f operator *(Similarity3f a, Similarity3f b) { //a.Scale * b.Scale, a.Rot * b.Rot, a.Trans + a.Rot * a.Scale * b.Trans return new Similarity3f(a.Scale * b.Scale, new Euclidean3f( a.Rot * b.Rot, a.Trans + a.Rot.Transform(a.Scale * b.Trans)) ); } /// /// Transforms a vector by a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator *(Similarity3f s, V4f v) => s.Euclidean * new V4f(s.Scale * v.X, s.Scale * v.Y, s.Scale * v.Z, v.W); /// /// Multiplies a transformation (as a 4x4 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator *(Similarity3f s, M44f m) { var t = (M34f)s; return new M44f( t.M00 * m.M00 + t.M01 * m.M10 + t.M02 * m.M20 + t.M03 * m.M30, t.M00 * m.M01 + t.M01 * m.M11 + t.M02 * m.M21 + t.M03 * m.M31, t.M00 * m.M02 + t.M01 * m.M12 + t.M02 * m.M22 + t.M03 * m.M32, t.M00 * m.M03 + t.M01 * m.M13 + t.M02 * m.M23 + t.M03 * m.M33, t.M10 * m.M00 + t.M11 * m.M10 + t.M12 * m.M20 + t.M13 * m.M30, t.M10 * m.M01 + t.M11 * m.M11 + t.M12 * m.M21 + t.M13 * m.M31, t.M10 * m.M02 + t.M11 * m.M12 + t.M12 * m.M22 + t.M13 * m.M32, t.M10 * m.M03 + t.M11 * m.M13 + t.M12 * m.M23 + t.M13 * m.M33, t.M20 * m.M00 + t.M21 * m.M10 + t.M22 * m.M20 + t.M23 * m.M30, t.M20 * m.M01 + t.M21 * m.M11 + t.M22 * m.M21 + t.M23 * m.M31, t.M20 * m.M02 + t.M21 * m.M12 + t.M22 * m.M22 + t.M23 * m.M32, t.M20 * m.M03 + t.M21 * m.M13 + t.M22 * m.M23 + t.M23 * m.M33, m.M30, m.M31, m.M32, m.M33); } /// /// Multiplies a with a transformation (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f operator *(M44f m, Similarity3f s) { var t = (M34f)s; return new M44f( m.M00 * t.M00 + m.M01 * t.M10 + m.M02 * t.M20, m.M00 * t.M01 + m.M01 * t.M11 + m.M02 * t.M21, m.M00 * t.M02 + m.M01 * t.M12 + m.M02 * t.M22, m.M00 * t.M03 + m.M01 * t.M13 + m.M02 * t.M23 + m.M03, m.M10 * t.M00 + m.M11 * t.M10 + m.M12 * t.M20, m.M10 * t.M01 + m.M11 * t.M11 + m.M12 * t.M21, m.M10 * t.M02 + m.M11 * t.M12 + m.M12 * t.M22, m.M10 * t.M03 + m.M11 * t.M13 + m.M12 * t.M23 + m.M13, m.M20 * t.M00 + m.M21 * t.M10 + m.M22 * t.M20, m.M20 * t.M01 + m.M21 * t.M11 + m.M22 * t.M21, m.M20 * t.M02 + m.M21 * t.M12 + m.M22 * t.M22, m.M20 * t.M03 + m.M21 * t.M13 + m.M22 * t.M23 + m.M23, m.M30 * t.M00 + m.M31 * t.M10 + m.M32 * t.M20, m.M30 * t.M01 + m.M31 * t.M11 + m.M32 * t.M21, m.M30 * t.M02 + m.M31 * t.M12 + m.M32 * t.M22, m.M30 * t.M03 + m.M31 * t.M13 + m.M32 * t.M23 + m.M33); } /// /// Multiplies a transformation (as a 3x4 matrix) with a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(Similarity3f s, M34f m) { var t = (M34f)s; return new M34f( t.M00 * m.M00 + t.M01 * m.M10 + t.M02 * m.M20, t.M00 * m.M01 + t.M01 * m.M11 + t.M02 * m.M21, t.M00 * m.M02 + t.M01 * m.M12 + t.M02 * m.M22, t.M00 * m.M03 + t.M01 * m.M13 + t.M02 * m.M23 + t.M03, t.M10 * m.M00 + t.M11 * m.M10 + t.M12 * m.M20, t.M10 * m.M01 + t.M11 * m.M11 + t.M12 * m.M21, t.M10 * m.M02 + t.M11 * m.M12 + t.M12 * m.M22, t.M10 * m.M03 + t.M11 * m.M13 + t.M12 * m.M23 + t.M13, t.M20 * m.M00 + t.M21 * m.M10 + t.M22 * m.M20, t.M20 * m.M01 + t.M21 * m.M11 + t.M22 * m.M21, t.M20 * m.M02 + t.M21 * m.M12 + t.M22 * m.M22, t.M20 * m.M03 + t.M21 * m.M13 + t.M22 * m.M23 + t.M23); } /// /// Multiplies a with a transformation (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(M34f m, Similarity3f s) { var t = (M34f)s; return new M34f( m.M00 * t.M00 + m.M01 * t.M10 + m.M02 * t.M20, m.M00 * t.M01 + m.M01 * t.M11 + m.M02 * t.M21, m.M00 * t.M02 + m.M01 * t.M12 + m.M02 * t.M22, m.M00 * t.M03 + m.M01 * t.M13 + m.M02 * t.M23 + m.M03, m.M10 * t.M00 + m.M11 * t.M10 + m.M12 * t.M20, m.M10 * t.M01 + m.M11 * t.M11 + m.M12 * t.M21, m.M10 * t.M02 + m.M11 * t.M12 + m.M12 * t.M22, m.M10 * t.M03 + m.M11 * t.M13 + m.M12 * t.M23 + m.M13, m.M20 * t.M00 + m.M21 * t.M10 + m.M22 * t.M20, m.M20 * t.M01 + m.M21 * t.M11 + m.M22 * t.M21, m.M20 * t.M02 + m.M21 * t.M12 + m.M22 * t.M22, m.M20 * t.M03 + m.M21 * t.M13 + m.M22 * t.M23 + m.M23); } /// /// Multiplies a (as a 3x4 matrix) and a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(Similarity3f s, M33f m) => new M34f(s.Rot * m * s.Scale, s.Trans); /// /// Multiplies a and a (as a 3x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34f operator *(M33f m, Similarity3f s) => new M34f(s.Scale * m * s.Rot, m * s.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f operator *(Similarity3f s, Rot3f r) => new Similarity3f(s.Scale, s.Euclidean * r); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f operator *(Rot3f r, Similarity3f s) => new Similarity3f(s.Scale, r * s.Euclidean); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f operator *(Similarity3f a, Shift3f b) => new Similarity3f(a.Scale, a.Euclidean * (a.Scale * b)); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f operator *(Shift3f a, Similarity3f b) => new Similarity3f(b.Scale, a * b.Euclidean); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Similarity3f a, Scale3f b) { var t = (M33f)a; return new Affine3f(new M33f( t.M00 * b.X, t.M01 * b.Y, t.M02 * b.Z, t.M10 * b.X, t.M11 * b.Y, t.M12 * b.Z, t.M20 * b.X, t.M21 * b.Y, t.M22 * b.Z), a.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3f operator *(Scale3f a, Similarity3f b) { var t = (M33f)b; return new Affine3f(new M33f( t.M00 * a.X, t.M01 * a.X, t.M02 * a.X, t.M10 * a.Y, t.M11 * a.Y, t.M12 * a.Y, t.M20 * a.Z, t.M21 * a.Z, t.M22 * a.Z), b.Trans * a.V); } /// /// Multiplies an Euclidean transformation by a Similarity transformation. /// This concatenates the two transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f operator *(Euclidean3f a, Similarity3f b) { return new Similarity3f(b.Scale, a * b.Euclidean); //return (Similarity3f)a * b; } /// /// Multiplies a Similarity transformation by an Euclidean transformation. /// This concatenates the two transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f operator *(Similarity3f a, Euclidean3f b) { return a * (Similarity3f)b; } #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Similarity3f t0, Similarity3f t1) { return t0.Scale == t1.Scale && t0.Euclidean == t1.Euclidean; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Similarity3f t0, Similarity3f t1) { return !(t0 == t1); } #endregion #region Static Creators /// /// Creates a transformation from a matrix and a translation . /// The matrix must not contain a non-uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f FromM33fAndV3f(M33f m, V3f trans, float epsilon = 1e-5f) { var s0 = m.C0.Norm2; var s1 = m.C1.Norm2; var s2 = m.C2.Norm2; var s = (s0 * s1 * s2).Pow(1.0f / 3); //geometric mean of scale if (!((s0 / s - 1).IsTiny(epsilon) && (s1 / s - 1).IsTiny(epsilon) && (s2 / s - 1).IsTiny(epsilon))) throw new ArgumentException("Matrix features non-uniform scaling"); m /= s; return new Similarity3f(s, Euclidean3f.FromM33fAndV3f(m, trans, epsilon)); } /// /// Creates a transformation from a matrix. /// The matrix must not contain a non-uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f FromM34f(M34f m, float epsilon = 1e-5f) => FromM33fAndV3f((M33f)m, m.C3, epsilon); /// /// Creates a transformation from a matrix. /// The matrix has to be homogeneous and must not contain perspective components or /// a non-uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f FromM44f(M44f m, float epsilon = 1e-5f) { if (!(m.M30.IsTiny(epsilon) && m.M31.IsTiny(epsilon) && m.M32.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (m.M33.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return FromM33fAndV3f(((M33f)m) / m.M33, m.C3.XYZ, epsilon); } /// /// Creates a transformation from an . /// The transformation must represent a uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f FromScale3f(Scale3f scale, float epsilon = 1e-5f) { var s = (scale.X * scale.Y * scale.Z).Pow(1.0f / 3); if (!scale.ApproximateEquals(new Scale3f(s), epsilon)) throw new ArgumentException("Matrix features non-uniform scaling"); return new Similarity3f(s, Euclidean3f.Identity); } /// /// Creates a transformation from an . /// The transformation must only consist of a uniform scale, rotation, and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f FromAffine3f(Affine3f affine, float epsilon = 1e-5f) => FromM44f((M44f)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a uniform scale, rotation, and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f FromTrafo3f(Trafo3f trafo, float epsilon = 1e-5f) => FromM44f(trafo.Forward, epsilon); /// /// Creates a scaling transformation using a uniform scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f Scaling(float scaleFactor) => new Similarity3f(scaleFactor); #region Translation /// /// Creates a transformation with the translational component given by 3 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f Translation(float tX, float tY, float tZ) => new Similarity3f(Rot3f.Identity, tX, tY, tZ); /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f Translation(V3f vector) => new Similarity3f(Rot3f.Identity, vector); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f Translation(Shift3f shift) => new Similarity3f(Rot3f.Identity, shift.V); #endregion #region Rotation /// /// Creates a rotation transformation from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f Rotation(Rot3f rot) => new Similarity3f(rot, V3f.Zero); /// /// Creates a rotation transformation from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f Rotation(V3f normalizedAxis, float angleRadians) => new Similarity3f(Rot3f.Rotation(normalizedAxis, angleRadians), V3f.Zero); /// /// Creates a rotation transformation from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f RotationInDegrees(V3f normalizedAxis, float angleDegrees) => Rotation(normalizedAxis, angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f RotationEuler(float rollInRadians, float pitchInRadians, float yawInRadians) => new Similarity3f(Rot3f.RotationEuler(rollInRadians, pitchInRadians, yawInRadians), V3f.Zero); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f RotationEulerInDegrees(float rollInDegrees, float pitchInDegrees, float yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f RotationEuler(V3f rollPitchYawInRadians) => RotationEuler(rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f RotationEulerInDegrees(V3f rollPitchYawInDegrees) => RotationEulerInDegrees( rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a rotation transformation which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f RotateInto(V3f from, V3f into) => new Similarity3f(Rot3f.RotateInto(from, into), V3f.Zero); /// /// Creates a rotation transformation by radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f RotationX(float angleRadians) => new Similarity3f(Rot3f.RotationX(angleRadians), V3f.Zero); /// /// Creates a rotation transformation for degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f RotationXInDegrees(float angleDegrees) => RotationX(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f RotationY(float angleRadians) => new Similarity3f(Rot3f.RotationY(angleRadians), V3f.Zero); /// /// Creates a rotation transformation for degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f RotationYInDegrees(float angleDegrees) => RotationY(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f RotationZ(float angleRadians) => new Similarity3f(Rot3f.RotationZ(angleRadians), V3f.Zero); /// /// Creates a rotation transformation for degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f RotationZInDegrees(float angleDegrees) => RotationZ(angleDegrees.RadiansFromDegrees()); #endregion #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34f(Similarity3f s) { M34f rv = (M34f)s.Euclidean; rv.M00 *= s.Scale; rv.M01 *= s.Scale; rv.M02 *= s.Scale; rv.M10 *= s.Scale; rv.M11 *= s.Scale; rv.M12 *= s.Scale; rv.M20 *= s.Scale; rv.M21 *= s.Scale; rv.M22 *= s.Scale; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33f(Similarity3f s) { M33f rv = (M33f)s.Euclidean; rv.M00 *= s.Scale; rv.M01 *= s.Scale; rv.M02 *= s.Scale; rv.M10 *= s.Scale; rv.M11 *= s.Scale; rv.M12 *= s.Scale; rv.M20 *= s.Scale; rv.M21 *= s.Scale; rv.M22 *= s.Scale; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44f(Similarity3f s) { M44f rv = (M44f)s.Euclidean; rv.M00 *= s.Scale; rv.M01 *= s.Scale; rv.M02 *= s.Scale; rv.M10 *= s.Scale; rv.M11 *= s.Scale; rv.M12 *= s.Scale; rv.M20 *= s.Scale; rv.M21 *= s.Scale; rv.M22 *= s.Scale; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine3f(Similarity3f s) { var m = (M34f)s; return new Affine3f((M33f)m, m.C3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo3f(Similarity3f s) => new Trafo3f((M44f)s, (M44f)s.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Similarity3d(Similarity3f s) => new Similarity3d((double)s.Scale, (Euclidean3d)s.Euclidean); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Scale, Euclidean); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Similarity3f other) => Scale.Equals(other.Scale) && Euclidean.Equals(other.Euclidean); public override readonly bool Equals(object other) => (other is Similarity3f o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Scale, Euclidean); } public static Similarity3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Similarity3f(float.Parse(x[0], CultureInfo.InvariantCulture), Euclidean3f.Parse(x[1])); } #endregion } public static partial class Similarity { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f Inverse(Similarity3f s) => s.Inverse; /// /// Inverts the similarity transformation (multiplicative inverse). /// this = [1/Scale, Rot^T,-Rot^T Trans/Scale] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Similarity3f t) { t.Scale = 1 / t.Scale; t.Euclidean.Invert(); t.Euclidean.Trans *= t.Scale; } #endregion #region Normalize /// /// Returns a copy of a with its rotation quaternion normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3f Normalized(Similarity3f s) => s.Normalized; /// /// Normalizes the rotation quaternion of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref Similarity3f t) { t.Euclidean.Normalize(); } #endregion #region Transform /// /// Transforms a by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Transform(this Similarity3f s, V4f v) => s * v; /// /// Transforms direction vector v (v.W is presumed 0.0) by similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransformDir(this Similarity3f t, V3f v) { return t.Euclidean.TransformDir(t.Scale * v); } /// /// Transforms point p (p.W is presumed 1.0) by similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransformPos(this Similarity3f t, V3f p) { return t.Euclidean.TransformPos(t.Scale * p); } /// /// Transforms direction vector v (v.W is presumed 0.0) by the inverse of the similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvTransformDir(this Similarity3f t, V3f v) { return t.Euclidean.InvTransformDir(v) / t.Scale; } /// /// Transforms point p (p.W is presumed 1.0) by the inverse of the similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvTransformPos(this Similarity3f t, V3f p) { return t.Euclidean.InvTransformPos(p) / t.Scale; } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Similarity3f t0, Similarity3f t1) { return ApproximateEquals(t0, t1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Similarity3f t0, Similarity3f t1, float tol) { return t0.Scale.ApproximateEquals(t1.Scale, tol) && t0.Euclidean.ApproximateEquals(t1.Euclidean, tol); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Similarity3f t0, Similarity3f t1, float angleTol, float posTol, float scaleTol) { return t0.Scale.ApproximateEquals(t1.Scale, scaleTol) && t0.Euclidean.ApproximateEquals(t1.Euclidean, angleTol, posTol); } #endregion } #endregion #region Similarity2d /// /// Represents a Similarity Transformation in 2D that is composed of a /// Uniform Scale and a subsequent Euclidean transformation (2D rotation Rot and a subsequent translation by a 2D vector Trans). /// This is an angle preserving Transformation. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Similarity2d : IEquatable { [DataMember] public double Scale; [DataMember] public Euclidean2d Euclidean; /// /// Gets the rotational component of this transformation. /// public readonly Rot2d Rot { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Euclidean.Rot; } } /// /// Gets the translational component of this transformation. /// public readonly V2d Trans { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Euclidean.Trans; } } #region Constructors /// /// Constructs a copy of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2d(Similarity2d s) { Scale = s.Scale; Euclidean = s.Euclidean; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2d(Similarity2f s) { Scale = (double)s.Scale; Euclidean = (Euclidean2d)s.Euclidean; } /// /// Creates a similarity transformation from an uniform scale by factor . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2d(double scale) { Scale = scale; Euclidean = Euclidean2d.Identity; } /// /// Creates a similarity transformation from a rigid transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2d(Euclidean2d euclideanTransformation) { Scale = 1; Euclidean = euclideanTransformation; } /// /// Constructs a similarity transformation from a rotation and translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2d(Rot2d rotation, V2d translation) { Scale = 1; Euclidean = new Euclidean2d(rotation, translation); } /// /// Constructs a similarity transformation from a rotation and translation by (, ). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2d(Rot2d rotation, double tX, double tY) { Scale = 1; Euclidean = new Euclidean2d(rotation, tX, tY); } /// /// Creates a similarity transformation from a uniform scale by factor , and a (subsequent) rigid transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2d(double scale, Euclidean2d euclideanTransformation) { Scale = scale; Euclidean = euclideanTransformation; } /// /// Constructs a similarity transformation from a uniform scale by factor , and a (subsequent) rotation and translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2d(double scale, Rot2d rotation, V2d translation) { Scale = scale; Euclidean = new Euclidean2d(rotation, translation); } /// /// Constructs a similarity transformation from a uniform scale by factor , and a (subsequent) rotation and and translation by (, ). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity2d(double scale, Rot2d rotation, double tX, double tY) { Scale = scale; Euclidean = new Euclidean2d(rotation, tX, tY); } #endregion #region Constants /// /// Gets the identity transformation. /// public static Similarity2d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Similarity2d(1, Euclidean2d.Identity); } #endregion #region Similarity Transformation Arithmetics /// /// Gets the (multiplicative) inverse of this Similarity transformation. /// [1/Scale, Rot^T,-Rot^T Trans/Scale] /// public readonly Similarity2d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var newS = 1 / Scale; var newR = Euclidean.Inverse; newR.Trans *= newS; return new Similarity2d(newS, newR); } } #endregion #region Arithmetic Operators /// /// Multiplies two Similarity transformations. /// This concatenates the two similarity transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d operator *(Similarity2d a, Similarity2d b) { //a.Scale * b.Scale, a.Rot * b.Rot, a.Trans + a.Rot * a.Scale * b.Trans return new Similarity2d(a.Scale * b.Scale, new Euclidean2d( a.Rot * b.Rot, a.Trans + a.Rot.Transform(a.Scale * b.Trans)) ); } /// /// Transforms a vector by a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator *(Similarity2d s, V3d v) => s.Euclidean * new V3d(s.Scale * v.X, s.Scale * v.Y, v.Z); /// /// Multiplies a transformation (as a 3x3 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator *(Similarity2d s, M33d m) { var t = (M23d)s; return new M33d( t.M00 * m.M00 + t.M01 * m.M10 + t.M02 * m.M20, t.M00 * m.M01 + t.M01 * m.M11 + t.M02 * m.M21, t.M00 * m.M02 + t.M01 * m.M12 + t.M02 * m.M22, t.M10 * m.M00 + t.M11 * m.M10 + t.M12 * m.M20, t.M10 * m.M01 + t.M11 * m.M11 + t.M12 * m.M21, t.M10 * m.M02 + t.M11 * m.M12 + t.M12 * m.M22, m.M20, m.M21, m.M22); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d operator *(M33d m, Similarity2d s) { var t = (M23d)s; return new M33d( m.M00 * t.M00 + m.M01 * t.M10, m.M00 * t.M01 + m.M01 * t.M11, m.M00 * t.M02 + m.M01 * t.M12 + m.M02, m.M10 * t.M00 + m.M11 * t.M10, m.M10 * t.M01 + m.M11 * t.M11, m.M10 * t.M02 + m.M11 * t.M12 + m.M12, m.M20 * t.M00 + m.M21 * t.M10, m.M20 * t.M01 + m.M21 * t.M11, m.M20 * t.M02 + m.M21 * t.M12 + m.M22); } /// /// Multiplies a transformation (as a 2x3 matrix) with a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(Similarity2d s, M23d m) { var t = (M23d)s; return new M23d( t.M00 * m.M00 + t.M01 * m.M10, t.M00 * m.M01 + t.M01 * m.M11, t.M00 * m.M02 + t.M01 * m.M12 + t.M02, t.M10 * m.M00 + t.M11 * m.M10, t.M10 * m.M01 + t.M11 * m.M11, t.M10 * m.M02 + t.M11 * m.M12 + t.M12); } /// /// Multiplies a with a transformation (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(M23d m, Similarity2d s) { var t = (M23d)s; return new M23d( m.M00 * t.M00 + m.M01 * t.M10, m.M00 * t.M01 + m.M01 * t.M11, m.M00 * t.M02 + m.M01 * t.M12 + m.M02, m.M10 * t.M00 + m.M11 * t.M10, m.M10 * t.M01 + m.M11 * t.M11, m.M10 * t.M02 + m.M11 * t.M12 + m.M12); } /// /// Multiplies a (as a 2x3 matrix) and a (as a 3x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(Similarity2d s, M22d m) => new M23d(s.Rot * m * s.Scale, s.Trans); /// /// Multiplies a and a (as a 2x3 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M23d operator *(M22d m, Similarity2d s) => new M23d(s.Scale * m * s.Rot, m * s.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d operator *(Similarity2d s, Rot2d r) => new Similarity2d(s.Scale, s.Euclidean * r); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d operator *(Rot2d r, Similarity2d s) => new Similarity2d(s.Scale, r * s.Euclidean); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d operator *(Similarity2d a, Shift2d b) => new Similarity2d(a.Scale, a.Euclidean * (a.Scale * b)); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d operator *(Shift2d a, Similarity2d b) => new Similarity2d(b.Scale, a * b.Euclidean); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Similarity2d a, Scale2d b) { var t = (M22d)a; return new Affine2d(new M22d( t.M00 * b.X, t.M01 * b.Y, t.M10 * b.X, t.M11 * b.Y), a.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine2d operator *(Scale2d a, Similarity2d b) { var t = (M22d)b; return new Affine2d(new M22d( t.M00 * a.X, t.M01 * a.X, t.M10 * a.Y, t.M11 * a.Y), b.Trans * a.V); } /// /// Multiplies an Euclidean transformation by a Similarity transformation. /// This concatenates the two transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d operator *(Euclidean2d a, Similarity2d b) { return new Similarity2d(b.Scale, a * b.Euclidean); //return (Similarity2d)a * b; } /// /// Multiplies a Similarity transformation by an Euclidean transformation. /// This concatenates the two transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d operator *(Similarity2d a, Euclidean2d b) { return a * (Similarity2d)b; } #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Similarity2d t0, Similarity2d t1) { return t0.Scale == t1.Scale && t0.Euclidean == t1.Euclidean; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Similarity2d t0, Similarity2d t1) { return !(t0 == t1); } #endregion #region Static Creators /// /// Creates a transformation from a matrix and a translation . /// The matrix must not contain a non-uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d FromM22dAndV2d(M22d m, V2d trans, double epsilon = 1e-12) { var s0 = m.C0.Norm2; var s1 = m.C1.Norm2; var s = (s0 * s1).Pow(1.0 / 2); //geometric mean of scale if (!((s0 / s - 1).IsTiny(epsilon) && (s1 / s - 1).IsTiny(epsilon))) throw new ArgumentException("Matrix features non-uniform scaling"); m /= s; return new Similarity2d(s, Euclidean2d.FromM22dAndV2d(m, trans)); } /// /// Creates a transformation from a matrix. /// The matrix must not contain a non-uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d FromM23d(M23d m, double epsilon = 1e-12) => FromM22dAndV2d((M22d)m, m.C2); /// /// Creates a transformation from a matrix. /// The matrix has to be homogeneous and must not contain perspective components or /// a non-uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d FromM33d(M33d m, double epsilon = 1e-12) { if (!(m.M20.IsTiny(epsilon) && m.M21.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (m.M22.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return FromM22dAndV2d(((M22d)m) / m.M22, m.C2.XY); } /// /// Creates a transformation from an . /// The transformation must represent a uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d FromScale2d(Scale2d scale, double epsilon = 1e-12) { var s = (scale.X * scale.Y).Pow(1.0 / 2); if (!scale.ApproximateEquals(new Scale2d(s), epsilon)) throw new ArgumentException("Matrix features non-uniform scaling"); return new Similarity2d(s, Euclidean2d.Identity); } /// /// Creates a transformation from an . /// The transformation must only consist of a uniform scale, rotation, and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d FromAffine2d(Affine2d affine, double epsilon = 1e-12) => FromM33d((M33d)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a uniform scale, rotation, and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d FromTrafo2d(Trafo2d trafo, double epsilon = 1e-12) => FromM33d(trafo.Forward, epsilon); /// /// Creates a scaling transformation using a uniform scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d Scaling(double scaleFactor) => new Similarity2d(scaleFactor); #region Translation /// /// Creates a transformation with the translational component given by 2 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d Translation(double tX, double tY) => new Similarity2d(Rot2d.Identity, tX, tY); /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d Translation(V2d vector) => new Similarity2d(Rot2d.Identity, vector); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d Translation(Shift2d shift) => new Similarity2d(Rot2d.Identity, shift.V); #endregion #region Rotation /// /// Creates a rotation transformation from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d Rotation(Rot2d rot) => new Similarity2d(rot, V2d.Zero); /// /// Creates a rotation transformation with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d Rotation(double angleInRadians) => new Similarity2d(new Rot2d(angleInRadians), V2d.Zero); /// /// Creates a rotation transformation with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d RotationInDegrees(double angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); #endregion #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M23d(Similarity2d s) { M23d rv = (M23d)s.Euclidean; rv.M00 *= s.Scale; rv.M01 *= s.Scale; rv.M10 *= s.Scale; rv.M11 *= s.Scale; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M22d(Similarity2d s) { M22d rv = (M22d)s.Euclidean; rv.M00 *= s.Scale; rv.M01 *= s.Scale; rv.M10 *= s.Scale; rv.M11 *= s.Scale; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33d(Similarity2d s) { M33d rv = (M33d)s.Euclidean; rv.M00 *= s.Scale; rv.M01 *= s.Scale; rv.M10 *= s.Scale; rv.M11 *= s.Scale; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine2d(Similarity2d s) { var m = (M23d)s; return new Affine2d((M22d)m, m.C2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo2d(Similarity2d s) => new Trafo2d((M33d)s, (M33d)s.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Similarity2f(Similarity2d s) => new Similarity2f((float)s.Scale, (Euclidean2f)s.Euclidean); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Scale, Euclidean); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Similarity2d other) => Scale.Equals(other.Scale) && Euclidean.Equals(other.Euclidean); public override readonly bool Equals(object other) => (other is Similarity2d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Scale, Euclidean); } public static Similarity2d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Similarity2d(double.Parse(x[0], CultureInfo.InvariantCulture), Euclidean2d.Parse(x[1])); } #endregion } public static partial class Similarity { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity2d Inverse(Similarity2d s) => s.Inverse; /// /// Inverts the similarity transformation (multiplicative inverse). /// this = [1/Scale, Rot^T,-Rot^T Trans/Scale] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Similarity2d t) { t.Scale = 1 / t.Scale; t.Euclidean.Invert(); t.Euclidean.Trans *= t.Scale; } #endregion #region Transform /// /// Transforms a by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Transform(this Similarity2d s, V3d v) => s * v; /// /// Transforms direction vector v (v.Z is presumed 0.0) by similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d TransformDir(this Similarity2d t, V2d v) { return t.Euclidean.TransformDir(t.Scale * v); } /// /// Transforms point p (p.Z is presumed 1.0) by similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d TransformPos(this Similarity2d t, V2d p) { return t.Euclidean.TransformPos(t.Scale * p); } /// /// Transforms direction vector v (v.Z is presumed 0.0) by the inverse of the similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d InvTransformDir(this Similarity2d t, V2d v) { return t.Euclidean.InvTransformDir(v) / t.Scale; } /// /// Transforms point p (p.Z is presumed 1.0) by the inverse of the similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d InvTransformPos(this Similarity2d t, V2d p) { return t.Euclidean.InvTransformPos(p) / t.Scale; } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Similarity2d t0, Similarity2d t1) { return ApproximateEquals(t0, t1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Similarity2d t0, Similarity2d t1, double tol) { return t0.Scale.ApproximateEquals(t1.Scale, tol) && t0.Euclidean.ApproximateEquals(t1.Euclidean, tol); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Similarity2d t0, Similarity2d t1, double angleTol, double posTol, double scaleTol) { return t0.Scale.ApproximateEquals(t1.Scale, scaleTol) && t0.Euclidean.ApproximateEquals(t1.Euclidean, angleTol, posTol); } #endregion } #endregion #region Similarity3d /// /// Represents a Similarity Transformation in 3D that is composed of a /// Uniform Scale and a subsequent Euclidean transformation (3D rotation Rot and a subsequent translation by a 3D vector Trans). /// This is an angle preserving Transformation. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct Similarity3d : IEquatable { [DataMember] public double Scale; [DataMember] public Euclidean3d Euclidean; /// /// Gets the rotational component of this transformation. /// public readonly Rot3d Rot { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Euclidean.Rot; } } /// /// Gets the translational component of this transformation. /// public readonly V3d Trans { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Euclidean.Trans; } } #region Constructors /// /// Constructs a copy of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3d(Similarity3d s) { Scale = s.Scale; Euclidean = s.Euclidean; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3d(Similarity3f s) { Scale = (double)s.Scale; Euclidean = (Euclidean3d)s.Euclidean; } /// /// Creates a similarity transformation from an uniform scale by factor . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3d(double scale) { Scale = scale; Euclidean = Euclidean3d.Identity; } /// /// Creates a similarity transformation from a rigid transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3d(Euclidean3d euclideanTransformation) { Scale = 1; Euclidean = euclideanTransformation; } /// /// Constructs a similarity transformation from a rotation and translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3d(Rot3d rotation, V3d translation) { Scale = 1; Euclidean = new Euclidean3d(rotation, translation); } /// /// Constructs a similarity transformation from a rotation and translation by (, , ). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3d(Rot3d rotation, double tX, double tY, double tZ) { Scale = 1; Euclidean = new Euclidean3d(rotation, tX, tY, tZ); } /// /// Creates a similarity transformation from a uniform scale by factor , and a (subsequent) rigid transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3d(double scale, Euclidean3d euclideanTransformation) { Scale = scale; Euclidean = euclideanTransformation; } /// /// Constructs a similarity transformation from a uniform scale by factor , and a (subsequent) rotation and translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3d(double scale, Rot3d rotation, V3d translation) { Scale = scale; Euclidean = new Euclidean3d(rotation, translation); } /// /// Constructs a similarity transformation from a uniform scale by factor , and a (subsequent) rotation and and translation by (, , ). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Similarity3d(double scale, Rot3d rotation, double tX, double tY, double tZ) { Scale = scale; Euclidean = new Euclidean3d(rotation, tX, tY, tZ); } #endregion #region Constants /// /// Gets the identity transformation. /// public static Similarity3d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Similarity3d(1, Euclidean3d.Identity); } #endregion #region Similarity Transformation Arithmetics /// /// Returns a new version of this Similarity transformation with a normalized rotation quaternion. /// public readonly Similarity3d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Similarity3d(Scale, Euclidean.Normalized); } /// /// Gets the (multiplicative) inverse of this Similarity transformation. /// [1/Scale, Rot^T,-Rot^T Trans/Scale] /// public readonly Similarity3d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var newS = 1 / Scale; var newR = Euclidean.Inverse; newR.Trans *= newS; return new Similarity3d(newS, newR); } } #endregion #region Arithmetic Operators /// /// Multiplies two Similarity transformations. /// This concatenates the two similarity transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d operator *(Similarity3d a, Similarity3d b) { //a.Scale * b.Scale, a.Rot * b.Rot, a.Trans + a.Rot * a.Scale * b.Trans return new Similarity3d(a.Scale * b.Scale, new Euclidean3d( a.Rot * b.Rot, a.Trans + a.Rot.Transform(a.Scale * b.Trans)) ); } /// /// Transforms a vector by a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator *(Similarity3d s, V4d v) => s.Euclidean * new V4d(s.Scale * v.X, s.Scale * v.Y, s.Scale * v.Z, v.W); /// /// Multiplies a transformation (as a 4x4 matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator *(Similarity3d s, M44d m) { var t = (M34d)s; return new M44d( t.M00 * m.M00 + t.M01 * m.M10 + t.M02 * m.M20 + t.M03 * m.M30, t.M00 * m.M01 + t.M01 * m.M11 + t.M02 * m.M21 + t.M03 * m.M31, t.M00 * m.M02 + t.M01 * m.M12 + t.M02 * m.M22 + t.M03 * m.M32, t.M00 * m.M03 + t.M01 * m.M13 + t.M02 * m.M23 + t.M03 * m.M33, t.M10 * m.M00 + t.M11 * m.M10 + t.M12 * m.M20 + t.M13 * m.M30, t.M10 * m.M01 + t.M11 * m.M11 + t.M12 * m.M21 + t.M13 * m.M31, t.M10 * m.M02 + t.M11 * m.M12 + t.M12 * m.M22 + t.M13 * m.M32, t.M10 * m.M03 + t.M11 * m.M13 + t.M12 * m.M23 + t.M13 * m.M33, t.M20 * m.M00 + t.M21 * m.M10 + t.M22 * m.M20 + t.M23 * m.M30, t.M20 * m.M01 + t.M21 * m.M11 + t.M22 * m.M21 + t.M23 * m.M31, t.M20 * m.M02 + t.M21 * m.M12 + t.M22 * m.M22 + t.M23 * m.M32, t.M20 * m.M03 + t.M21 * m.M13 + t.M22 * m.M23 + t.M23 * m.M33, m.M30, m.M31, m.M32, m.M33); } /// /// Multiplies a with a transformation (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d operator *(M44d m, Similarity3d s) { var t = (M34d)s; return new M44d( m.M00 * t.M00 + m.M01 * t.M10 + m.M02 * t.M20, m.M00 * t.M01 + m.M01 * t.M11 + m.M02 * t.M21, m.M00 * t.M02 + m.M01 * t.M12 + m.M02 * t.M22, m.M00 * t.M03 + m.M01 * t.M13 + m.M02 * t.M23 + m.M03, m.M10 * t.M00 + m.M11 * t.M10 + m.M12 * t.M20, m.M10 * t.M01 + m.M11 * t.M11 + m.M12 * t.M21, m.M10 * t.M02 + m.M11 * t.M12 + m.M12 * t.M22, m.M10 * t.M03 + m.M11 * t.M13 + m.M12 * t.M23 + m.M13, m.M20 * t.M00 + m.M21 * t.M10 + m.M22 * t.M20, m.M20 * t.M01 + m.M21 * t.M11 + m.M22 * t.M21, m.M20 * t.M02 + m.M21 * t.M12 + m.M22 * t.M22, m.M20 * t.M03 + m.M21 * t.M13 + m.M22 * t.M23 + m.M23, m.M30 * t.M00 + m.M31 * t.M10 + m.M32 * t.M20, m.M30 * t.M01 + m.M31 * t.M11 + m.M32 * t.M21, m.M30 * t.M02 + m.M31 * t.M12 + m.M32 * t.M22, m.M30 * t.M03 + m.M31 * t.M13 + m.M32 * t.M23 + m.M33); } /// /// Multiplies a transformation (as a 3x4 matrix) with a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(Similarity3d s, M34d m) { var t = (M34d)s; return new M34d( t.M00 * m.M00 + t.M01 * m.M10 + t.M02 * m.M20, t.M00 * m.M01 + t.M01 * m.M11 + t.M02 * m.M21, t.M00 * m.M02 + t.M01 * m.M12 + t.M02 * m.M22, t.M00 * m.M03 + t.M01 * m.M13 + t.M02 * m.M23 + t.M03, t.M10 * m.M00 + t.M11 * m.M10 + t.M12 * m.M20, t.M10 * m.M01 + t.M11 * m.M11 + t.M12 * m.M21, t.M10 * m.M02 + t.M11 * m.M12 + t.M12 * m.M22, t.M10 * m.M03 + t.M11 * m.M13 + t.M12 * m.M23 + t.M13, t.M20 * m.M00 + t.M21 * m.M10 + t.M22 * m.M20, t.M20 * m.M01 + t.M21 * m.M11 + t.M22 * m.M21, t.M20 * m.M02 + t.M21 * m.M12 + t.M22 * m.M22, t.M20 * m.M03 + t.M21 * m.M13 + t.M22 * m.M23 + t.M23); } /// /// Multiplies a with a transformation (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(M34d m, Similarity3d s) { var t = (M34d)s; return new M34d( m.M00 * t.M00 + m.M01 * t.M10 + m.M02 * t.M20, m.M00 * t.M01 + m.M01 * t.M11 + m.M02 * t.M21, m.M00 * t.M02 + m.M01 * t.M12 + m.M02 * t.M22, m.M00 * t.M03 + m.M01 * t.M13 + m.M02 * t.M23 + m.M03, m.M10 * t.M00 + m.M11 * t.M10 + m.M12 * t.M20, m.M10 * t.M01 + m.M11 * t.M11 + m.M12 * t.M21, m.M10 * t.M02 + m.M11 * t.M12 + m.M12 * t.M22, m.M10 * t.M03 + m.M11 * t.M13 + m.M12 * t.M23 + m.M13, m.M20 * t.M00 + m.M21 * t.M10 + m.M22 * t.M20, m.M20 * t.M01 + m.M21 * t.M11 + m.M22 * t.M21, m.M20 * t.M02 + m.M21 * t.M12 + m.M22 * t.M22, m.M20 * t.M03 + m.M21 * t.M13 + m.M22 * t.M23 + m.M23); } /// /// Multiplies a (as a 3x4 matrix) and a (as a 4x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(Similarity3d s, M33d m) => new M34d(s.Rot * m * s.Scale, s.Trans); /// /// Multiplies a and a (as a 3x4 matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M34d operator *(M33d m, Similarity3d s) => new M34d(s.Scale * m * s.Rot, m * s.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d operator *(Similarity3d s, Rot3d r) => new Similarity3d(s.Scale, s.Euclidean * r); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d operator *(Rot3d r, Similarity3d s) => new Similarity3d(s.Scale, r * s.Euclidean); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d operator *(Similarity3d a, Shift3d b) => new Similarity3d(a.Scale, a.Euclidean * (a.Scale * b)); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d operator *(Shift3d a, Similarity3d b) => new Similarity3d(b.Scale, a * b.Euclidean); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Similarity3d a, Scale3d b) { var t = (M33d)a; return new Affine3d(new M33d( t.M00 * b.X, t.M01 * b.Y, t.M02 * b.Z, t.M10 * b.X, t.M11 * b.Y, t.M12 * b.Z, t.M20 * b.X, t.M21 * b.Y, t.M22 * b.Z), a.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Affine3d operator *(Scale3d a, Similarity3d b) { var t = (M33d)b; return new Affine3d(new M33d( t.M00 * a.X, t.M01 * a.X, t.M02 * a.X, t.M10 * a.Y, t.M11 * a.Y, t.M12 * a.Y, t.M20 * a.Z, t.M21 * a.Z, t.M22 * a.Z), b.Trans * a.V); } /// /// Multiplies an Euclidean transformation by a Similarity transformation. /// This concatenates the two transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d operator *(Euclidean3d a, Similarity3d b) { return new Similarity3d(b.Scale, a * b.Euclidean); //return (Similarity3d)a * b; } /// /// Multiplies a Similarity transformation by an Euclidean transformation. /// This concatenates the two transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d operator *(Similarity3d a, Euclidean3d b) { return a * (Similarity3d)b; } #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Similarity3d t0, Similarity3d t1) { return t0.Scale == t1.Scale && t0.Euclidean == t1.Euclidean; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Similarity3d t0, Similarity3d t1) { return !(t0 == t1); } #endregion #region Static Creators /// /// Creates a transformation from a matrix and a translation . /// The matrix must not contain a non-uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d FromM33dAndV3d(M33d m, V3d trans, double epsilon = 1e-12) { var s0 = m.C0.Norm2; var s1 = m.C1.Norm2; var s2 = m.C2.Norm2; var s = (s0 * s1 * s2).Pow(1.0 / 3); //geometric mean of scale if (!((s0 / s - 1).IsTiny(epsilon) && (s1 / s - 1).IsTiny(epsilon) && (s2 / s - 1).IsTiny(epsilon))) throw new ArgumentException("Matrix features non-uniform scaling"); m /= s; return new Similarity3d(s, Euclidean3d.FromM33dAndV3d(m, trans, epsilon)); } /// /// Creates a transformation from a matrix. /// The matrix must not contain a non-uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d FromM34d(M34d m, double epsilon = 1e-12) => FromM33dAndV3d((M33d)m, m.C3, epsilon); /// /// Creates a transformation from a matrix. /// The matrix has to be homogeneous and must not contain perspective components or /// a non-uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d FromM44d(M44d m, double epsilon = 1e-12) { if (!(m.M30.IsTiny(epsilon) && m.M31.IsTiny(epsilon) && m.M32.IsTiny(epsilon))) throw new ArgumentException("Matrix contains perspective components."); if (m.M33.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return FromM33dAndV3d(((M33d)m) / m.M33, m.C3.XYZ, epsilon); } /// /// Creates a transformation from an . /// The transformation must represent a uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d FromScale3d(Scale3d scale, double epsilon = 1e-12) { var s = (scale.X * scale.Y * scale.Z).Pow(1.0 / 3); if (!scale.ApproximateEquals(new Scale3d(s), epsilon)) throw new ArgumentException("Matrix features non-uniform scaling"); return new Similarity3d(s, Euclidean3d.Identity); } /// /// Creates a transformation from an . /// The transformation must only consist of a uniform scale, rotation, and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d FromAffine3d(Affine3d affine, double epsilon = 1e-12) => FromM44d((M44d)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a uniform scale, rotation, and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d FromTrafo3d(Trafo3d trafo, double epsilon = 1e-12) => FromM44d(trafo.Forward, epsilon); /// /// Creates a scaling transformation using a uniform scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d Scaling(double scaleFactor) => new Similarity3d(scaleFactor); #region Translation /// /// Creates a transformation with the translational component given by 3 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d Translation(double tX, double tY, double tZ) => new Similarity3d(Rot3d.Identity, tX, tY, tZ); /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d Translation(V3d vector) => new Similarity3d(Rot3d.Identity, vector); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d Translation(Shift3d shift) => new Similarity3d(Rot3d.Identity, shift.V); #endregion #region Rotation /// /// Creates a rotation transformation from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d Rotation(Rot3d rot) => new Similarity3d(rot, V3d.Zero); /// /// Creates a rotation transformation from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d Rotation(V3d normalizedAxis, double angleRadians) => new Similarity3d(Rot3d.Rotation(normalizedAxis, angleRadians), V3d.Zero); /// /// Creates a rotation transformation from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d RotationInDegrees(V3d normalizedAxis, double angleDegrees) => Rotation(normalizedAxis, angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d RotationEuler(double rollInRadians, double pitchInRadians, double yawInRadians) => new Similarity3d(Rot3d.RotationEuler(rollInRadians, pitchInRadians, yawInRadians), V3d.Zero); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d RotationEulerInDegrees(double rollInDegrees, double pitchInDegrees, double yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d RotationEuler(V3d rollPitchYawInRadians) => RotationEuler(rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d RotationEulerInDegrees(V3d rollPitchYawInDegrees) => RotationEulerInDegrees( rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a rotation transformation which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d RotateInto(V3d from, V3d into) => new Similarity3d(Rot3d.RotateInto(from, into), V3d.Zero); /// /// Creates a rotation transformation by radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d RotationX(double angleRadians) => new Similarity3d(Rot3d.RotationX(angleRadians), V3d.Zero); /// /// Creates a rotation transformation for degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d RotationXInDegrees(double angleDegrees) => RotationX(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d RotationY(double angleRadians) => new Similarity3d(Rot3d.RotationY(angleRadians), V3d.Zero); /// /// Creates a rotation transformation for degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d RotationYInDegrees(double angleDegrees) => RotationY(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d RotationZ(double angleRadians) => new Similarity3d(Rot3d.RotationZ(angleRadians), V3d.Zero); /// /// Creates a rotation transformation for degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d RotationZInDegrees(double angleDegrees) => RotationZ(angleDegrees.RadiansFromDegrees()); #endregion #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M34d(Similarity3d s) { M34d rv = (M34d)s.Euclidean; rv.M00 *= s.Scale; rv.M01 *= s.Scale; rv.M02 *= s.Scale; rv.M10 *= s.Scale; rv.M11 *= s.Scale; rv.M12 *= s.Scale; rv.M20 *= s.Scale; rv.M21 *= s.Scale; rv.M22 *= s.Scale; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M33d(Similarity3d s) { M33d rv = (M33d)s.Euclidean; rv.M00 *= s.Scale; rv.M01 *= s.Scale; rv.M02 *= s.Scale; rv.M10 *= s.Scale; rv.M11 *= s.Scale; rv.M12 *= s.Scale; rv.M20 *= s.Scale; rv.M21 *= s.Scale; rv.M22 *= s.Scale; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator M44d(Similarity3d s) { M44d rv = (M44d)s.Euclidean; rv.M00 *= s.Scale; rv.M01 *= s.Scale; rv.M02 *= s.Scale; rv.M10 *= s.Scale; rv.M11 *= s.Scale; rv.M12 *= s.Scale; rv.M20 *= s.Scale; rv.M21 *= s.Scale; rv.M22 *= s.Scale; return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Affine3d(Similarity3d s) { var m = (M34d)s; return new Affine3d((M33d)m, m.C3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo3d(Similarity3d s) => new Trafo3d((M44d)s, (M44d)s.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Similarity3f(Similarity3d s) => new Similarity3f((float)s.Scale, (Euclidean3f)s.Euclidean); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Scale, Euclidean); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Similarity3d other) => Scale.Equals(other.Scale) && Euclidean.Equals(other.Euclidean); public override readonly bool Equals(object other) => (other is Similarity3d o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Scale, Euclidean); } public static Similarity3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Similarity3d(double.Parse(x[0], CultureInfo.InvariantCulture), Euclidean3d.Parse(x[1])); } #endregion } public static partial class Similarity { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d Inverse(Similarity3d s) => s.Inverse; /// /// Inverts the similarity transformation (multiplicative inverse). /// this = [1/Scale, Rot^T,-Rot^T Trans/Scale] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref Similarity3d t) { t.Scale = 1 / t.Scale; t.Euclidean.Invert(); t.Euclidean.Trans *= t.Scale; } #endregion #region Normalize /// /// Returns a copy of a with its rotation quaternion normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Similarity3d Normalized(Similarity3d s) => s.Normalized; /// /// Normalizes the rotation quaternion of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref Similarity3d t) { t.Euclidean.Normalize(); } #endregion #region Transform /// /// Transforms a by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Transform(this Similarity3d s, V4d v) => s * v; /// /// Transforms direction vector v (v.W is presumed 0.0) by similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransformDir(this Similarity3d t, V3d v) { return t.Euclidean.TransformDir(t.Scale * v); } /// /// Transforms point p (p.W is presumed 1.0) by similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransformPos(this Similarity3d t, V3d p) { return t.Euclidean.TransformPos(t.Scale * p); } /// /// Transforms direction vector v (v.W is presumed 0.0) by the inverse of the similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvTransformDir(this Similarity3d t, V3d v) { return t.Euclidean.InvTransformDir(v) / t.Scale; } /// /// Transforms point p (p.W is presumed 1.0) by the inverse of the similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvTransformPos(this Similarity3d t, V3d p) { return t.Euclidean.InvTransformPos(p) / t.Scale; } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Similarity3d t0, Similarity3d t1) { return ApproximateEquals(t0, t1, Constant.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Similarity3d t0, Similarity3d t1, double tol) { return t0.Scale.ApproximateEquals(t1.Scale, tol) && t0.Euclidean.ApproximateEquals(t1.Euclidean, tol); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Similarity3d t0, Similarity3d t1, double angleTol, double posTol, double scaleTol) { return t0.Scale.ApproximateEquals(t1.Scale, scaleTol) && t0.Euclidean.ApproximateEquals(t1.Euclidean, angleTol, posTol); } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Similarity_template.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; namespace Aardvark.Base { //# Action comma = () => Out(", "); //# Action commaln = () => Out("," + Environment.NewLine); //# Action add = () => Out(" + "); //# Action mul = () => Out(" * "); //# Action and = () => Out(" && "); //# Action or = () => Out(" || "); //# Action andLit = () => Out(" and "); //# var fields = new[] {"X", "Y", "Z", "W"}; //# foreach (var isDouble in new[] { false, true }) { //# for (int n = 2; n <= 3; n++) { //# var m = n + 1; //# var ftype = isDouble ? "double" : "float"; //# var ftype2 = isDouble ? "float" : "double"; //# var one = isDouble ? "1.0" : "1.0f"; //# var xyz = "XYZW".Substring(0, n); //# var tc = isDouble ? "d" : "f"; //# var tc2 = isDouble ? "f" : "d"; //# var type = "Similarity" + n + tc; //# var type2 = "Similarity" + n + tc2; //# var vnt = "V" + n + tc; //# var vmt = "V" + m + tc; //# var mnnt = "M" + n + n + tc; //# var mmmt = "M" + m + m + tc; //# var mnmt = "M" + n + m + tc; //# var rotnt = "Rot" + n + tc; //# var trafont = "Trafo" + n + tc; //# var affinent = "Affine" + n + tc; //# var scalent = "Scale" + n + tc; //# var shiftnt = "Shift" + n + tc; //# var euclideannt = "Euclidean" + n + tc; //# var euclideannt2 = "Euclidean" + n + tc2; //# var nfields = fields.Take(n).ToArray(); //# var mfields = fields.Take(m).ToArray(); //# var fn = fields[n]; //# var eps = isDouble ? "1e-12" : "1e-5f"; #region __type__ /// /// Represents a Similarity Transformation in __n__D that is composed of a /// Uniform Scale and a subsequent Euclidean transformation (__n__D rotation Rot and a subsequent translation by a __n__D vector Trans). /// This is an angle preserving Transformation. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public partial struct __type__ : IEquatable<__type__> { [DataMember] public __ftype__ Scale; [DataMember] public __euclideannt__ Euclidean; /// /// Gets the rotational component of this transformation. /// public readonly __rotnt__ Rot { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Euclidean.Rot; } } /// /// Gets the translational component of this transformation. /// public readonly __vnt__ Trans { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Euclidean.Trans; } } #region Constructors /// /// Constructs a copy of an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ s) { Scale = s.Scale; Euclidean = s.Euclidean; } /// /// Constructs a transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ s) { Scale = (__ftype__)s.Scale; Euclidean = (__euclideannt__)s.Euclidean; } /// /// Creates a similarity transformation from an uniform scale by factor . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__ scale) { Scale = scale; Euclidean = __euclideannt__.Identity; } /// /// Creates a similarity transformation from a rigid transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__euclideannt__ euclideanTransformation) { Scale = 1; Euclidean = euclideanTransformation; } /// /// Constructs a similarity transformation from a rotation and translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__rotnt__ rotation, __vnt__ translation) { Scale = 1; Euclidean = new __euclideannt__(rotation, translation); } /// /// Constructs a similarity transformation from a rotation and translation by (/*# nfields.ForEach(f => { *//*# }, comma);*/). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__rotnt__ rotation, /*# nfields.ForEach(f => { */__ftype__ t__f__/*# }, comma);*/) { Scale = 1; Euclidean = new __euclideannt__(rotation, /*# nfields.ForEach(f => { */t__f__/*# }, comma);*/); } /// /// Creates a similarity transformation from a uniform scale by factor , and a (subsequent) rigid transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__ scale, __euclideannt__ euclideanTransformation) { Scale = scale; Euclidean = euclideanTransformation; } /// /// Constructs a similarity transformation from a uniform scale by factor , and a (subsequent) rotation and translation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__ scale, __rotnt__ rotation, __vnt__ translation) { Scale = scale; Euclidean = new __euclideannt__(rotation, translation); } /// /// Constructs a similarity transformation from a uniform scale by factor , and a (subsequent) rotation and and translation by (/*# nfields.ForEach(f => { *//*# }, comma);*/). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__ftype__ scale, __rotnt__ rotation, /*# nfields.ForEach(f => { */__ftype__ t__f__/*# }, comma);*/) { Scale = scale; Euclidean = new __euclideannt__(rotation, /*# nfields.ForEach(f => { */t__f__/*# }, comma);*/); } #endregion #region Constants /// /// Gets the identity transformation. /// public static __type__ Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(1, __euclideannt__.Identity); } #endregion #region Similarity Transformation Arithmetics //# if (n > 2) { /// /// Returns a new version of this Similarity transformation with a normalized rotation quaternion. /// public readonly __type__ Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(Scale, Euclidean.Normalized); } //# } /// /// Gets the (multiplicative) inverse of this Similarity transformation. /// [1/Scale, Rot^T,-Rot^T Trans/Scale] /// public readonly __type__ Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var newS = 1 / Scale; var newR = Euclidean.Inverse; newR.Trans *= newS; return new __type__(newS, newR); } } #endregion #region Arithmetic Operators /// /// Multiplies two Similarity transformations. /// This concatenates the two similarity transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ a, __type__ b) { //a.Scale * b.Scale, a.Rot * b.Rot, a.Trans + a.Rot * a.Scale * b.Trans return new __type__(a.Scale * b.Scale, new __euclideannt__( a.Rot * b.Rot, a.Trans + a.Rot.Transform(a.Scale * b.Trans)) ); } /// /// Transforms a vector by a transformation. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vmt__ operator *(__type__ s, __vmt__ v) => s.Euclidean * new __vmt__(/*# nfields.ForEach(f => {*/s.Scale * v.__f__/*#}, comma);*/, v.__fn__); /// /// Multiplies a transformation (as a __m__x__m__ matrix) with a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mmmt__ operator *(__type__ s, __mmmt__ m) { var t = (__mnmt__)s; return new __mmmt__(/*# n.ForEach(i => { m.ForEach(j => { */ /*# m.ForEach(k => { */t.M__i____k__ * m.M__k____j__/*# }, add); }, comma); }, commaln);*/, /*# m.ForEach(i => { */m.M__n____i__/*# }, comma);*/); } /// /// Multiplies a with a transformation (as a __m__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mmmt__ operator *(__mmmt__ m, __type__ s) { var t = (__mnmt__)s; return new __mmmt__(/*# m.ForEach(i => { m.ForEach(j => { */ /*# n.ForEach(k => { */m.M__i____k__ * t.M__k____j__/*# }, add); if (j == n) {*/ + m.M__i____n__/*# } }, comma); }, commaln);*/); } /// /// Multiplies a transformation (as a __n__x__m__ matrix) with a (as a __m__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mnmt__ operator *(__type__ s, __mnmt__ m) { var t = (__mnmt__)s; return new __mnmt__(/*# n.ForEach(i => { m.ForEach(j => { */ /*# n.ForEach(k => { */t.M__i____k__ * m.M__k____j__/*# }, add); if (j == n) {*/ + t.M__i____n__/*# } }, comma); }, commaln);*/); } /// /// Multiplies a with a transformation (as a __m__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mnmt__ operator *(__mnmt__ m, __type__ s) { var t = (__mnmt__)s; return new __mnmt__(/*# n.ForEach(i => { m.ForEach(j => { */ /*# n.ForEach(k => { */m.M__i____k__ * t.M__k____j__/*# }, add); if (j == n) {*/ + m.M__i____n__/*# } }, comma); }, commaln);*/); } /// /// Multiplies a (as a __n__x__m__ matrix) and a (as a __m__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mnmt__ operator *(__type__ s, __mnnt__ m) => new __mnmt__(s.Rot * m * s.Scale, s.Trans); /// /// Multiplies a and a (as a __n__x__m__ matrix). /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mnmt__ operator *(__mnnt__ m, __type__ s) => new __mnmt__(s.Scale * m * s.Rot, m * s.Trans); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ s, __rotnt__ r) => new __type__(s.Scale, s.Euclidean * r); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__rotnt__ r, __type__ s) => new __type__(s.Scale, r * s.Euclidean); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ a, __shiftnt__ b) => new __type__(a.Scale, a.Euclidean * (a.Scale * b)); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__shiftnt__ a, __type__ b) => new __type__(b.Scale, a * b.Euclidean); /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __affinent__ operator *(__type__ a, __scalent__ b) { var t = (__mnnt__)a; return new __affinent__(new __mnnt__(/*# nfields.ForEach((fi, i) => { */ /*# nfields.ForEach((fj, j) => { */t.M__i____j__ * b.__fj__/*# }, comma); }, comma);*/), a.Trans); } /// /// Multiplies a and a . /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __affinent__ operator *(__scalent__ a, __type__ b) { var t = (__mnnt__)b; return new __affinent__(new __mnnt__(/*# nfields.ForEach((fi, i) => { */ /*# nfields.ForEach((fj, j) => { */t.M__i____j__ * a.__fi__/*# }, comma); }, comma);*/), b.Trans * a.V); } /// /// Multiplies an Euclidean transformation by a Similarity transformation. /// This concatenates the two transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__euclideannt__ a, __type__ b) { return new __type__(b.Scale, a * b.Euclidean); //return (__type__)a * b; } /// /// Multiplies a Similarity transformation by an Euclidean transformation. /// This concatenates the two transformations into a single one, first b is applied, then a. /// Attention: Multiplication is NOT commutative! /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ operator *(__type__ a, __euclideannt__ b) { return a * (__type__)b; } #endregion #region Comparison Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ t0, __type__ t1) { return t0.Scale == t1.Scale && t0.Euclidean == t1.Euclidean; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__type__ t0, __type__ t1) { return !(t0 == t1); } #endregion #region Static Creators /// /// Creates a transformation from a matrix and a translation . /// The matrix must not contain a non-uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__mnnt__And__vnt__(__mnnt__ m, __vnt__ trans, __ftype__ epsilon = __eps__) { //# n.ForEach(i => { var s__i__ = m.C__i__.Norm2; //# }); var s = (/*# n.ForEach(i => {*/s__i__/*# }, mul);*/).Pow(__one__ / __n__); //geometric mean of scale if (!(/*#n.ForEach(i => {*/(s__i__ / s - 1).IsTiny(epsilon)/*# }, and);*/)) throw new ArgumentException("Matrix features non-uniform scaling"); m /= s; return new __type__(s, __euclideannt__.From__mnnt__And__vnt__(m, trans/*# if (n > 2) {*/, epsilon/*# }*/)); } /// /// Creates a transformation from a matrix. /// The matrix must not contain a non-uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__mnmt__(__mnmt__ m, __ftype__ epsilon = __eps__) => From__mnnt__And__vnt__((__mnnt__)m, m.C__n__/*# if (n > 2) {*/, epsilon/*# }*/); /// /// Creates a transformation from a matrix. /// The matrix has to be homogeneous and must not contain perspective components or /// a non-uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__mmmt__(__mmmt__ m, __ftype__ epsilon = __eps__) { if (!(/*#n.ForEach(j => {*/m.M__n____j__.IsTiny(epsilon)/*# }, and);*/)) throw new ArgumentException("Matrix contains perspective components."); if (m.M__n____n__.IsTiny(epsilon)) throw new ArgumentException("Matrix is not homogeneous."); return From__mnnt__And__vnt__(((__mnnt__)m) / m.M__n____n__, m.C__n__.__xyz__/*# if (n > 2) {*/, epsilon/*# }*/); } /// /// Creates a transformation from an . /// The transformation must represent a uniform scaling. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__scalent__(__scalent__ scale, __ftype__ epsilon = __eps__) { var s = (/*# nfields.ForEach(f => {*/scale.__f__/*# }, mul);*/).Pow(__one__ / __n__); if (!scale.ApproximateEquals(new __scalent__(s), epsilon)) throw new ArgumentException("Matrix features non-uniform scaling"); return new __type__(s, __euclideannt__.Identity); } /// /// Creates a transformation from an . /// The transformation must only consist of a uniform scale, rotation, and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__affinent__(__affinent__ affine, __ftype__ epsilon = __eps__) => From__mmmt__((__mmmt__)affine, epsilon); /// /// Creates a transformation from a . /// The transformation must only consist of a uniform scale, rotation, and translation. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ From__trafont__(__trafont__ trafo, __ftype__ epsilon = __eps__) => From__mmmt__(trafo.Forward, epsilon); /// /// Creates a scaling transformation using a uniform scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Scaling(__ftype__ scaleFactor) => new __type__(scaleFactor); #region Translation /// /// Creates a transformation with the translational component given by __n__ scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Translation(/*# nfields.ForEach(f => { */__ftype__ t__f__/*# }, comma); */) => new __type__(__rotnt__.Identity, /*# nfields.ForEach(f => { */t__f__/*# }, comma); */); /// /// Creates a transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Translation(__vnt__ vector) => new __type__(__rotnt__.Identity, vector); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Translation(__shiftnt__ shift) => new __type__(__rotnt__.Identity, shift.V); #endregion #region Rotation /// /// Creates a rotation transformation from a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Rotation(__rotnt__ rot) => new __type__(rot, __vnt__.Zero); //# if (n == 2) { /// /// Creates a rotation transformation with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Rotation(__ftype__ angleInRadians) => new __type__(new __rotnt__(angleInRadians), __vnt__.Zero); /// /// Creates a rotation transformation with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationInDegrees(__ftype__ angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); //# } else if (n == 3) { /// /// Creates a rotation transformation from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Rotation(__vnt__ normalizedAxis, __ftype__ angleRadians) => new __type__(__rotnt__.Rotation(normalizedAxis, angleRadians), __vnt__.Zero); /// /// Creates a rotation transformation from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationInDegrees(__vnt__ normalizedAxis, __ftype__ angleDegrees) => Rotation(normalizedAxis, angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEuler(__ftype__ rollInRadians, __ftype__ pitchInRadians, __ftype__ yawInRadians) => new __type__(__rotnt__.RotationEuler(rollInRadians, pitchInRadians, yawInRadians), __vnt__.Zero); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEulerInDegrees(__ftype__ rollInDegrees, __ftype__ pitchInDegrees, __ftype__ yawInDegrees) => RotationEuler( rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEuler(__vnt__ rollPitchYawInRadians) => RotationEuler(rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEulerInDegrees(__vnt__ rollPitchYawInDegrees) => RotationEulerInDegrees( rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a rotation transformation which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotateInto(__vnt__ from, __vnt__ into) => new __type__(__rotnt__.RotateInto(from, into), __vnt__.Zero); /// /// Creates a rotation transformation by radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationX(__ftype__ angleRadians) => new __type__(__rotnt__.RotationX(angleRadians), __vnt__.Zero); /// /// Creates a rotation transformation for degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationXInDegrees(__ftype__ angleDegrees) => RotationX(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationY(__ftype__ angleRadians) => new __type__(__rotnt__.RotationY(angleRadians), __vnt__.Zero); /// /// Creates a rotation transformation for degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationYInDegrees(__ftype__ angleDegrees) => RotationY(angleDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationZ(__ftype__ angleRadians) => new __type__(__rotnt__.RotationZ(angleRadians), __vnt__.Zero); /// /// Creates a rotation transformation for degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationZInDegrees(__ftype__ angleDegrees) => RotationZ(angleDegrees.RadiansFromDegrees()); //# } #endregion #endregion #region Conversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __mnmt__(__type__ s) { __mnmt__ rv = (__mnmt__)s.Euclidean; //# n.ForEach(i => { /*# n.ForEach(j => {*/rv.M__i____j__ *= s.Scale; /*# });*/ //# }); return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __mnnt__(__type__ s) { __mnnt__ rv = (__mnnt__)s.Euclidean; //# n.ForEach(i => { /*# n.ForEach(j => {*/rv.M__i____j__ *= s.Scale; /*# });*/ //# }); return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __mmmt__(__type__ s) { __mmmt__ rv = (__mmmt__)s.Euclidean; //# n.ForEach(i => { /*# n.ForEach(j => {*/rv.M__i____j__ *= s.Scale; /*# });*/ //# }); return rv; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __affinent__(__type__ s) { var m = (__mnmt__)s; return new __affinent__((__mnnt__)m, m.C__n__); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __trafont__(__type__ s) => new __trafont__((__mmmt__)s, (__mmmt__)s.Inverse); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type2__(__type__ s) => new __type2__((__ftype2__)s.Scale, (__euclideannt2__)s.Euclidean); #endregion #region Overrides public override readonly int GetHashCode() { return HashCode.GetCombined(Scale, Euclidean); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__type__ other) => Scale.Equals(other.Scale) && Euclidean.Equals(other.Euclidean); public override readonly bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; public override readonly string ToString() { return string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Scale, Euclidean); } public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__(__ftype__.Parse(x[0], CultureInfo.InvariantCulture), __euclideannt__.Parse(x[1])); } #endregion } public static partial class Similarity { #region Invert /// /// Returns the inverse of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Inverse(__type__ s) => s.Inverse; /// /// Inverts the similarity transformation (multiplicative inverse). /// this = [1/Scale, Rot^T,-Rot^T Trans/Scale] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invert(this ref __type__ t) { t.Scale = 1 / t.Scale; t.Euclidean.Invert(); t.Euclidean.Trans *= t.Scale; } #endregion //# if (n > 2) { #region Normalize /// /// Returns a copy of a with its rotation quaternion normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Normalized(__type__ s) => s.Normalized; /// /// Normalizes the rotation quaternion of a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref __type__ t) { t.Euclidean.Normalize(); } #endregion //# } #region Transform /// /// Transforms a by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vmt__ Transform(this __type__ s, __vmt__ v) => s * v; /// /// Transforms direction vector v (v.__fn__ is presumed 0.0) by similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ TransformDir(this __type__ t, __vnt__ v) { return t.Euclidean.TransformDir(t.Scale * v); } /// /// Transforms point p (p.__fn__ is presumed 1.0) by similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ TransformPos(this __type__ t, __vnt__ p) { return t.Euclidean.TransformPos(t.Scale * p); } /// /// Transforms direction vector v (v.__fn__ is presumed 0.0) by the inverse of the similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ InvTransformDir(this __type__ t, __vnt__ v) { return t.Euclidean.InvTransformDir(v) / t.Scale; } /// /// Transforms point p (p.__fn__ is presumed 1.0) by the inverse of the similarity transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ InvTransformPos(this __type__ t, __vnt__ p) { return t.Euclidean.InvTransformPos(p) / t.Scale; } #endregion } public static partial class Fun { #region ApproximateEquals [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ t0, __type__ t1) { return ApproximateEquals(t0, t1, Constant<__ftype__>.PositiveTinyValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ t0, __type__ t1, __ftype__ tol) { return t0.Scale.ApproximateEquals(t1.Scale, tol) && t0.Euclidean.ApproximateEquals(t1.Euclidean, tol); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ t0, __type__ t1, __ftype__ angleTol, __ftype__ posTol, __ftype__ scaleTol) { return t0.Scale.ApproximateEquals(t1.Scale, scaleTol) && t0.Euclidean.ApproximateEquals(t1.Euclidean, angleTol, posTol); } #endregion } #endregion //# } } } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Trafo_auto.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Trafo2f /// /// A trafo is a container for a forward and a backward matrix. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public readonly partial struct Trafo2f : IEquatable { [DataMember] public readonly M33f Forward; [DataMember] public readonly M33f Backward; #region Constructors /// /// Constructs a from a forward and backward transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2f(M33f forward, M33f backward) { Forward = forward; Backward = backward; } /// /// Constructs a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2f(Trafo2f trafo) { Forward = trafo.Forward; Backward = trafo.Backward; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2f(Trafo2d trafo) { Forward = (M33f)trafo.Forward; Backward = (M33f)trafo.Backward; } /// /// Constructs a from an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2f(Affine2f trafo) { Forward = (M33f)trafo; Backward = (M33f)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2f(Euclidean2f trafo) { Forward = (M33f)trafo; Backward = (M33f)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2f(Similarity2f trafo) { Forward = (M33f)trafo; Backward = (M33f)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2f(Rot2f trafo) { Forward = (M33f)trafo; Backward = (M33f)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2f(Scale2f trafo) { Forward = (M33f)trafo; Backward = (M33f)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2f(Shift2f trafo) { Forward = (M33f)trafo; Backward = (M33f)trafo.Inverse; } #endregion #region Constants /// /// Gets the identity transformation. /// public static Trafo2f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Trafo2f(M33f.Identity, M33f.Identity); } #endregion #region Properties /// /// Gets the inverse of this . /// public Trafo2f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Trafo2f(Backward, Forward); } #endregion #region Overrides public override int GetHashCode() => HashCode.GetCombined(Forward, Backward); [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Trafo2f other) => Forward.Equals(other.Forward) && Backward.Equals(other.Backward); public override bool Equals(object other) => (other is Trafo2f o) ? Equals(o) : false; public override string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Forward, Backward); public static Trafo2f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Trafo2f( M33f.Parse(x[0].ToString()), M33f.Parse(x[1].ToString()) ); } #endregion #region Static Creators /// /// Builds a transformation matrix using the scale, rotation (in radians) and translation components. /// NOTE: Uses the Scale * Rotation * Translation notion. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2f FromComponents(V2f scale, float rotationInRadians, V2f translation) => Scale(scale) * Rotation(rotationInRadians) * Translation(translation); /// /// Returns the that transforms from the coordinate system /// specified by the basis into the world coordinate system. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2f FromBasis(V2f xAxis, V2f yAxis, V2f origin) { var mat = new M33f( xAxis.X, yAxis.X, origin.X, xAxis.Y, yAxis.Y, origin.Y, 0, 0, 1); return new Trafo2f(mat, mat.Inverse); } /// /// Returns the that transforms from the coordinate system /// specified by the basis into the world coordinate system. /// Note that the axes MUST be normalized and normal to each other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2f FromOrthoNormalBasis(V2f xAxis, V2f yAxis) { return new Trafo2f( new M33f( xAxis.X, yAxis.X, 0, xAxis.Y, yAxis.Y, 0, 0, 0, 1), new M33f( xAxis.X, xAxis.Y, 0, yAxis.X, yAxis.Y, 0, 0, 0, 1) ); } #region Translation /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2f Translation(V2f v) => new Trafo2f(M33f.Translation(v), M33f.Translation(-v)); /// /// Creates a transformation with the translational component given by 2 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2f Translation(float tX, float tY) => Translation(new V2f(tX, tY)); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2f Translation(Shift2f shift) => Translation(shift.V); #endregion #region Scale /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2f Scale(V2f v) => new Trafo2f(M33f.Scale(v), M33f.Scale(1 / v)); /// /// Creates a scaling transformation using 2 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2f Scale(float sX, float sY) => new Trafo2f(M33f.Scale(sX, sY), M33f.Scale(1 / sX, 1 / sY)); /// /// Creates a scaling transformation using a uniform scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2f Scale(float s) { var t = 1 / s; return new Trafo2f(M33f.Scale(s), M33f.Scale(t)); } /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2f Scale(Scale2f scale) => new Trafo2f(scale); #endregion #region Rotation /// /// Creates a rotation transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2f Rotation(Rot2f rotation) => new Trafo2f(rotation); /// /// Creates a rotation transformation with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2f Rotation(float angleInRadians) => new Trafo2f(M33f.Rotation(angleInRadians), M33f.Rotation(-angleInRadians)); /// /// Creates a rotation transformation with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2f RotationInDegrees(float angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); #endregion #endregion #region Conversion Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo2d(Trafo2f r) => new Trafo2d(r); #endregion #region Operators /// /// Returns whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Trafo2f a, Trafo2f b) => a.Forward == b.Forward && a.Backward == b.Backward; /// /// Returns whether two transformations are different. /// public static bool operator !=(Trafo2f a, Trafo2f b) => a.Forward != b.Forward || a.Backward != b.Backward; /// /// The order of operation of Trafo2f multiplicaition is backward /// with respect to M33f multiplication in order to provide /// natural postfix notation. /// public static Trafo2f operator *(Trafo2f t0, Trafo2f t1) => new Trafo2f(t1.Forward * t0.Forward, t0.Backward * t1.Backward); #endregion } public static partial class Trafo { #region Operations /// /// Returns the inverse of the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2f Inverse(Trafo2f trafo) => trafo.Inverse; /// /// Returns the forward matrix the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Forward(Trafo2f trafo) => trafo.Forward; /// /// Returns the backward matrix the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Backward(Trafo2f trafo) => trafo.Backward; #endregion #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetScale(this Trafo2f trafo) => trafo.Forward.GetScale2(); /// /// Extracts a scale vector from the given transformation by calculating the lengths of the basis vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GetScaleVector(this Trafo2f trafo) => trafo.Forward.GetScaleVector2(); #endregion #region Transformations /// /// Transforms a by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Transform(this Trafo2f r, V3f v) => r.Forward.Transform(v); /// /// Transforms direction vector v (v.Z is presumed 0.0) by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f TransformDir(this Trafo2f r, V2f v) => r.Forward.TransformDir(v); /// /// Transforms point p (p.Z is presumed 1.0) by a . /// No projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f TransformPos(this Trafo2f r, V2f p) => r.Forward.TransformPos(p); /// /// Transforms point p (p.Z is presumed 1.0) by a . /// Projective transform is performed. Perspective Division is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f TransformPosProj(this Trafo2f r, V2f p) => r.Forward.TransformPosProj(p); /// /// Transforms point p (p.Z is presumed 1.0) by a . /// Projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransformPosProjFull(this Trafo2f r, V2f p) => r.Forward.TransformPosProjFull(p); /// /// Transforms normal vector n (n.Z is presumed 0.0) by a /// (i.e. by its transposed backward matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f TransformNormal(this Trafo2f r, V2f n) => r.Backward.TransposedTransformDir(n); /// /// Transforms a by the inverse of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvTransform(this Trafo2f r, V3f v) => r.Backward.Transform(v); /// /// Transforms direction vector v (v.Z is presumed 0.0) by the inverse of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f InvTransformDir(this Trafo2f r, V2f v) => r.Backward.TransformDir(v); /// /// Transforms point p (p.Z is presumed 1.0) by the inverse of a . /// No projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f InvTransformPos(this Trafo2f r, V2f p) => r.Backward.TransformPos(p); /// /// Transforms point p (p.Z is presumed 1.0) by the inverse of a . /// Projective transform is performed. Perspective Division is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f InvTransformPosProj(this Trafo2f r, V2f p) => r.Backward.TransformPosProj(p); /// /// Transforms point p (p.Z is presumed 1.0) by the inverse of a . /// Projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvTransformPosProjFull(this Trafo2f r, V2f p) => r.Backward.TransformPosProjFull(p); /// /// Transforms normal vector n (n.Z is presumed 0.0) by the inverse of a /// (i.e. by its transposed forward matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f InvTransformNormal(this Trafo2f r, V2f n) => r.Forward.TransposedTransformDir(n); #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if two transformations are equal with regard to a threshold . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Trafo2f a, Trafo2f b, float epsilon) => a.Forward.ApproximateEquals(b.Forward, epsilon) && a.Backward.ApproximateEquals(b.Backward, epsilon); #endregion } #endregion #region Trafo3f /// /// A trafo is a container for a forward and a backward matrix. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public readonly partial struct Trafo3f : IEquatable { [DataMember] public readonly M44f Forward; [DataMember] public readonly M44f Backward; #region Constructors /// /// Constructs a from a forward and backward transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3f(M44f forward, M44f backward) { Forward = forward; Backward = backward; } /// /// Constructs a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3f(Trafo3f trafo) { Forward = trafo.Forward; Backward = trafo.Backward; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3f(Trafo3d trafo) { Forward = (M44f)trafo.Forward; Backward = (M44f)trafo.Backward; } /// /// Constructs a from an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3f(Affine3f trafo) { Forward = (M44f)trafo; Backward = (M44f)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3f(Euclidean3f trafo) { Forward = (M44f)trafo; Backward = (M44f)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3f(Similarity3f trafo) { Forward = (M44f)trafo; Backward = (M44f)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3f(Rot3f trafo) { Forward = (M44f)trafo; Backward = (M44f)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3f(Scale3f trafo) { Forward = (M44f)trafo; Backward = (M44f)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3f(Shift3f trafo) { Forward = (M44f)trafo; Backward = (M44f)trafo.Inverse; } #endregion #region Constants /// /// Gets the identity transformation. /// public static Trafo3f Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Trafo3f(M44f.Identity, M44f.Identity); } #endregion #region Properties /// /// Gets the inverse of this . /// public Trafo3f Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Trafo3f(Backward, Forward); } #endregion #region Overrides public override int GetHashCode() => HashCode.GetCombined(Forward, Backward); [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Trafo3f other) => Forward.Equals(other.Forward) && Backward.Equals(other.Backward); public override bool Equals(object other) => (other is Trafo3f o) ? Equals(o) : false; public override string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Forward, Backward); public static Trafo3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Trafo3f( M44f.Parse(x[0].ToString()), M44f.Parse(x[1].ToString()) ); } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f FromNormalFrame(V3f origin, V3f normal) { M44f.NormalFrame(origin, normal, out M44f forward, out M44f backward); return new Trafo3f(forward, backward); } /// /// Builds a transformation matrix using the scale, rotation and translation components. /// NOTE: Uses the Scale * Rotation * Translation notion. /// The rotation is in Euler-Angles (roll, pitch, yaw) in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f FromComponents(V3f scale, V3f rotationInRadians, V3f translation) => Scale(scale) * RotationEuler(rotationInRadians) * Translation(translation); /// /// Returns the that transforms from the coordinate system /// specified by the basis into the world coordinate system. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f FromBasis(V3f xAxis, V3f yAxis, V3f zAxis, V3f origin) { var mat = new M44f( xAxis.X, yAxis.X, zAxis.X, origin.X, xAxis.Y, yAxis.Y, zAxis.Y, origin.Y, xAxis.Z, yAxis.Z, zAxis.Z, origin.Z, 0, 0, 0, 1); return new Trafo3f(mat, mat.Inverse); } /// /// Returns the that transforms from the coordinate system /// specified by the basis into the world coordinate system. /// Note that the axes MUST be normalized and normal to each other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f FromOrthoNormalBasis(V3f xAxis, V3f yAxis, V3f zAxis) { return new Trafo3f( new M44f( xAxis.X, yAxis.X, zAxis.X, 0, xAxis.Y, yAxis.Y, zAxis.Y, 0, xAxis.Z, yAxis.Z, zAxis.Z, 0, 0, 0, 0, 1), new M44f( xAxis.X, xAxis.Y, xAxis.Z, 0, yAxis.X, yAxis.Y, yAxis.Z, 0, zAxis.X, zAxis.Y, zAxis.Z, 0, 0, 0, 0, 1) ); } #region Translation /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f Translation(V3f v) => new Trafo3f(M44f.Translation(v), M44f.Translation(-v)); /// /// Creates a transformation with the translational component given by 3 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f Translation(float tX, float tY, float tZ) => Translation(new V3f(tX, tY, tZ)); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f Translation(Shift3f shift) => Translation(shift.V); #endregion #region Scale /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f Scale(V3f v) => new Trafo3f(M44f.Scale(v), M44f.Scale(1 / v)); /// /// Creates a scaling transformation using 3 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f Scale(float sX, float sY, float sZ) => new Trafo3f(M44f.Scale(sX, sY, sZ), M44f.Scale(1 / sX, 1 / sY, 1 / sZ)); /// /// Creates a scaling transformation using a uniform scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f Scale(float s) { var t = 1 / s; return new Trafo3f(M44f.Scale(s), M44f.Scale(t)); } /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f Scale(Scale3f scale) => new Trafo3f(scale); #endregion #region Rotation /// /// Creates a rotation transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f Rotation(Rot3f rotation) => new Trafo3f(rotation); /// /// Creates a rotation transformation from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f Rotation(V3f normalizedAxis, float angleInRadians) => new Trafo3f(M44f.Rotation(normalizedAxis, angleInRadians), M44f.Rotation(normalizedAxis, -angleInRadians)); /// /// Creates a rotation transformation from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f RotationInDegrees(V3f normalizedAxis, float angleInDegrees) => Rotation(normalizedAxis, Conversion.RadiansFromDegrees(angleInDegrees)); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f RotationEuler(float rollInRadians, float pitchInRadians, float yawInRadians) { var m = M44f.RotationEuler(rollInRadians, pitchInRadians, yawInRadians); return new Trafo3f(m, m.Transposed); //transposed is equal but faster to inverted on orthonormal matrices like rotations. } /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f RotationEulerInDegrees(float rollInDegrees, float pitchInDegrees, float yawInDegrees) => RotationEuler(rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f RotationEuler(V3f rollPitchYawInRadians) => RotationEuler(rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f RotationEulerInDegrees(V3f rollPitchYawInDegrees) => RotationEulerInDegrees(rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a rotation transformation which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f RotateInto(V3f from, V3f into) { var rot = Rot3f.RotateInto(from, into); var inv = rot.Inverse; return new Trafo3f((M44f)rot, (M44f)inv); } /// /// Creates a rotation transformation by radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f RotationX(float angleInRadians) => new Trafo3f(M44f.RotationX(angleInRadians), M44f.RotationX(-angleInRadians)); /// /// Creates a rotation transformation by degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f RotationXInDegrees(float angleInDegrees) => RotationX(Conversion.RadiansFromDegrees(angleInDegrees)); /// /// Creates a rotation transformation by radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f RotationY(float angleInRadians) => new Trafo3f(M44f.RotationY(angleInRadians), M44f.RotationY(-angleInRadians)); /// /// Creates a rotation transformation by degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f RotationYInDegrees(float angleInDegrees) => RotationY(Conversion.RadiansFromDegrees(angleInDegrees)); /// /// Creates a rotation transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f RotationZ(float angleInRadians) => new Trafo3f(M44f.RotationZ(angleInRadians), M44f.RotationZ(-angleInRadians)); /// /// Creates a rotation transformation by degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f RotationZInDegrees(float angleInDegrees) => RotationZ(Conversion.RadiansFromDegrees(angleInDegrees)); #endregion #region Shear /// /// Creates a shear transformation along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f ShearYZ(float factorY, float factorZ) => new Trafo3f(M44f.ShearYZ(factorY, factorZ), M44f.ShearYZ(-factorY, -factorZ)); /// /// Creates a shear transformation along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f ShearXZ(float factorX, float factorZ) => new Trafo3f(M44f.ShearXZ(factorX, factorZ), M44f.ShearXZ(-factorX, -factorZ)); /// /// Creates a shear transformation along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f ShearXY(float factorX, float factorY) => new Trafo3f(M44f.ShearXY(factorX, factorY), M44f.ShearXY(-factorX, -factorY)); #endregion #region View transformation /// /// Creates a view transformation from the given vectors. /// /// Origin of the view /// Right vector of the view-plane /// Up vector of the view-plane /// Normal vector of the view-plane. This vector is supposed to point in view-direction for a left-handed view transformation and in opposite direction in the right-handed case. /// The view transformation [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f ViewTrafo(V3f location, V3f u, V3f v, V3f z) { return new Trafo3f( new M44f( u.X, u.Y, u.Z, -Vec.Dot(u, location), v.X, v.Y, v.Z, -Vec.Dot(v, location), z.X, z.Y, z.Z, -Vec.Dot(z, location), 0, 0, 0, 1 ), new M44f( u.X, v.X, z.X, location.X, u.Y, v.Y, z.Y, location.Y, u.Z, v.Z, z.Z, location.Z, 0, 0, 0, 1 )); } /// /// Creates a right-handed view trafo, where z-negative points into the scene. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f ViewTrafoRH(V3f location, V3f up, V3f forward) => ViewTrafo(location, forward.Cross(up), up, -forward); /// /// Creates a left-handed view trafo, where z-positive points into the scene. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f ViewTrafoLH(V3f location, V3f up, V3f forward) => ViewTrafo(location, up.Cross(forward), up, forward); #endregion #region Projection transformation /// /// Creates a right-handed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, 0), (+1, +1, +1)]. /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. Can be infinite. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f PerspectiveProjectionRH(float l, float r, float b, float t, float n, float f = float.PositiveInfinity) { float m22, m23, m32i; if (f.IsPositiveInfinity()) { m22 = -1; m23 = -n; m32i = -1 / n; } else { m22 = f / (n - f); m23 = (f * n) / (n - f); m32i = (n - f) / (f * n); } return new Trafo3f( new M44f( (2 * n) / (r - l), 0, (r + l) / (r - l), 0, 0, (2 * n) / (t - b), (t + b) / (t - b), 0, 0, 0, m22, m23, 0, 0, -1, 0 ), new M44f( (r - l) / (2 * n), 0, 0, (r + l) / (2 * n), 0, (t - b) / (2 * n), 0, (t + b) / (2 * n), 0, 0, 0, -1, 0, 0, m32i, 1 / n ) ); } /// /// Creates a right-handed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, 0), (+1, +1, +1)]. /// /// Horizontal field of view in radians. /// Aspect ratio, defined as view space width divided by height. /// Z-value of the near view-plane. /// Z-value of the far view-plane. Can be infinite. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f PerspectiveProjectionRH(float horizontalFovInRadians, float aspect, float n, float f = float.PositiveInfinity) { float d = Fun.Tan(0.5f * horizontalFovInRadians) * n; return Trafo3f.PerspectiveProjectionRH(-d, d, -d / aspect, d / aspect, n, f); } /// /// Creates a right-handed reversed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, +1), (+1, +1, 0)]. /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. Can be infinite. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f PerspectiveProjectionReversedRH(float l, float r, float b, float t, float n, float f = float.PositiveInfinity) { float m22, m23, m32i, m33i; if (f.IsPositiveInfinity()) { m22 = 0; m23 = n; m32i = 1 / n; m33i = 0; } else { m22 = n / (f - n); m23 = (f * n) / (f - n); m32i = (f - n) / (f * n); m33i = 1 / f; } return new Trafo3f( new M44f( (2 * n) / (r - l), 0, (r + l) / (r - l), 0, 0, (2 * n) / (t - b), (t + b) / (t - b), 0, 0, 0, m22, m23, 0, 0, -1, 0 ), new M44f( (r - l) / (2 * n), 0, 0, (r + l) / (2 * n), 0, (t - b) / (2 * n), 0, (t + b) / (2 * n), 0, 0, 0, -1, 0, 0, m32i, m33i ) ); } /// /// Creates a right-handed reversed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, +1), (+1, +1, 0)]. /// /// Horizontal field of view in radians. /// Aspect ratio, defined as view space width divided by height. /// Z-value of the near view-plane. /// Z-value of the far view-plane. Can be infinite. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f PerspectiveProjectionReversedRH(float horizontalFovInRadians, float aspect, float n, float f = float.PositiveInfinity) { float d = Fun.Tan(0.5f * horizontalFovInRadians) * n; return Trafo3f.PerspectiveProjectionReversedRH(-d, d, -d / aspect, d / aspect, n, f); } /// /// Creates a right-handed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, -1), (+1, +1, +1)] and left-handed (handedness flip between view and NDC space). /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. Can be infinite. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f PerspectiveProjectionGL(float l, float r, float b, float t, float n, float f = float.PositiveInfinity) { float m22, m23, m32i, m33i; if (f.IsPositiveInfinity()) { m22 = -1; m23 = -2 * n; m32i = -1 / (2 * n); m33i = -m32i; } else { m22 = (f + n) / (n - f); m23 = (2 * f * n) / (n - f); m32i = (n - f) / (2 * f * n); m33i = (f + n) / (2 * f * n); } return new Trafo3f( new M44f( (2 * n) / (r - l), 0, (r + l) / (r - l), 0, 0, (2 * n) / (t - b), (t + b) / (t - b), 0, 0, 0, m22, m23, 0, 0, -1, 0 ), new M44f( (r - l) / (2 * n), 0, 0, (r + l) / (2 * n), 0, (t - b) / (2 * n), 0, (t + b) / (2 * n), 0, 0, 0, -1, 0, 0, m32i, m33i ) ); } /// /// Creates a right-handed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, -1), (+1, +1, +1)] and left-handed (handedness flip between view and NDC space). /// /// Horizontal field of view in radians. /// Aspect ratio, defined as view space width divided by height. /// Z-value of the near view-plane. /// Z-value of the far view-plane. Can be infinite. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f PerspectiveProjectionGL(float horizontalFovInRadians, float aspect, float n, float f = float.PositiveInfinity) { float d = Fun.Tan(0.5f * horizontalFovInRadians) * n; return Trafo3f.PerspectiveProjectionGL(-d, d, -d / aspect, d / aspect, n, f); } /// /// Creates a right-handed reversed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, +1), (+1, +1, -1)]. /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. Can be infinite. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f PerspectiveProjectionReversedGL(float l, float r, float b, float t, float n, float f = float.PositiveInfinity) { float m22, m23, m32i, m33i; if (f.IsPositiveInfinity()) { m22 = 1; m23 = 2 * n; m32i = 1 / (2 * n); m33i = m32i; } else { m22 = (f + n) / (f - n); m23 = (2 * f * n) / (f - n); m32i = (f - n) / (2 * f * n); m33i = (f + n) / (2 * f * n); } return new Trafo3f( new M44f( (2 * n) / (r - l), 0, (r + l) / (r - l), 0, 0, (2 * n) / (t - b), (t + b) / (t - b), 0, 0, 0, m22, m23, 0, 0, -1, 0 ), new M44f( (r - l) / (2 * n), 0, 0, (r + l) / (2 * n), 0, (t - b) / (2 * n), 0, (t + b) / (2 * n), 0, 0, 0, -1, 0, 0, m32i, m33i ) ); } /// /// Creates a right-handed reversed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, +1), (+1, +1, -1)]. /// /// Horizontal field of view in radians. /// Aspect ratio, defined as view space width divided by height. /// Z-value of the near view-plane. /// Z-value of the far view-plane. Can be infinite. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f PerspectiveProjectionReversedGL(float horizontalFovInRadians, float aspect, float n, float f = float.PositiveInfinity) { float d = Fun.Tan(0.5f * horizontalFovInRadians) * n; return Trafo3f.PerspectiveProjectionReversedGL(-d, d, -d / aspect, d / aspect, n, f); } /// /// Creates a right-handed orthographic projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, 0), (+1, +1, +1)]. /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f OrthoProjectionRH(float l, float r, float b, float t, float n, float f) { return new Trafo3f( new M44f( 2 / (r - l), 0, 0, (l + r) / (l - r), 0, 2 / (t - b), 0, (b + t) / (b - t), 0, 0, 1 / (n - f), n / (n - f), 0, 0, 0, 1 ), new M44f( (r - l) / 2, 0, 0, (l + r) / 2, 0, (t - b) / 2, 0, (b + t) / 2, 0, 0, n - f, -n, 0, 0, 0, 1 ) ); } /// /// Creates a right-handed orthographic projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, -1), (+1, +1, +1)] and left-handed (handedness flip between view and NDC space). /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f OrthoProjectionGL(float l, float r, float b, float t, float n, float f) { return new Trafo3f( new M44f( 2 / (r - l), 0, 0, (l + r) / (l - r), 0, 2 / (t - b), 0, (b + t) / (b - t), 0, 0, 2 / (n - f), (f + n) / (n - f), 0, 0, 0, 1 ), new M44f( (r - l) / 2, 0, 0, (l + r) / 2, 0, (t - b) / 2, 0, (b + t) / 2, 0, 0, (n - f) / 2, -(f + n) / 2, 0, 0, 0, 1 ) ); } #endregion #endregion #region Conversion Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo3d(Trafo3f r) => new Trafo3d(r); #endregion #region Operators /// /// Returns whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Trafo3f a, Trafo3f b) => a.Forward == b.Forward && a.Backward == b.Backward; /// /// Returns whether two transformations are different. /// public static bool operator !=(Trafo3f a, Trafo3f b) => a.Forward != b.Forward || a.Backward != b.Backward; /// /// The order of operation of Trafo3f multiplicaition is backward /// with respect to M44f multiplication in order to provide /// natural postfix notation. /// public static Trafo3f operator *(Trafo3f t0, Trafo3f t1) => new Trafo3f(t1.Forward * t0.Forward, t0.Backward * t1.Backward); #endregion } public static partial class Trafo { #region Operations /// /// Returns the inverse of the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f Inverse(Trafo3f trafo) => trafo.Inverse; /// /// Returns the forward matrix the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Forward(Trafo3f trafo) => trafo.Forward; /// /// Returns the backward matrix the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Backward(Trafo3f trafo) => trafo.Backward; #endregion #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetScale(this Trafo3f trafo) => trafo.Forward.GetScale3(); /// /// Extracts a scale vector from the given transformation by calculating the lengths of the basis vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetScaleVector(this Trafo3f trafo) => trafo.Forward.GetScaleVector3(); /// /// Extracts the inverse/backward translation component of the given transformation, which when given /// a view transformation represents the location of the camera in world space. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetViewPosition(this Trafo3f trafo) => trafo.Backward.C3.XYZ; /// /// Extracts the forward vector from the given view transformation. /// NOTE: A left-handed coordinates system transformation is expected, /// where the view-space z-axis points in forward direction. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetViewDirectionLH(this Trafo3f trafo) => trafo.Forward.GetViewDirectionLH(); /// /// Extracts the forward vector from the given view transformation. /// NOTE: A right-handed coordinates system transformation is expected, where /// the view-space z-axis points opposit the forward vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetViewDirectionRH(this Trafo3f trafo) => trafo.Forward.GetViewDirectionRH(); /// /// Extracts the translation component of the given transformation, which when given /// a model transformation represents the model origin in world position. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GetModelOrigin(this Trafo3f trafo) => trafo.Forward.GetModelOrigin(); /// /// Builds an ortho-normal orientation transformation form the given transform. /// Scale and Translation will be removed and basis vectors will be ortho-normalized. /// NOTE: The x-axis is untouched and y/z are forced to a normal-angle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3f GetOrthoNormalOrientation(this Trafo3f trafo) { var x = trafo.Forward.C0.XYZ.Normalized; var z = trafo.Forward.C2.XYZ; var y = z.Cross(x).Normalized; z = x.Cross(y).Normalized; return Trafo3f.FromOrthoNormalBasis(x, y, z); } /// /// Decomposes a transformation into a scale, rotation and translation component. /// NOTE: The input is assumed to be a valid affine transformation. /// The rotation output is a vector with Euler-Angles [roll (X), pitch (Y), yaw (Z)] in radians of rotation order Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Decompose(this Trafo3f trafo, out V3f scale, out V3f rotationInRadians, out V3f translation) { translation = trafo.GetModelOrigin(); var rt = trafo.GetOrthoNormalOrientation(); if (rt.Forward.Determinant.IsTiny()) { rotationInRadians = V3f.Zero; } else { var rot = Rot3f.FromFrame(rt.Forward.C0.XYZ, rt.Forward.C1.XYZ, rt.Forward.C2.XYZ); rotationInRadians = rot.GetEulerAngles(); } scale = trafo.GetScaleVector(); // if matrix is left-handed there must be some negative scale // since rotation remains the x-axis, the y-axis must be flipped if (trafo.Forward.Determinant < 0) scale.Y = -scale.Y; } #endregion #region Transformations /// /// Transforms a by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Transform(this Trafo3f r, V4f v) => r.Forward.Transform(v); /// /// Transforms direction vector v (v.W is presumed 0.0) by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransformDir(this Trafo3f r, V3f v) => r.Forward.TransformDir(v); /// /// Transforms point p (p.W is presumed 1.0) by a . /// No projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransformPos(this Trafo3f r, V3f p) => r.Forward.TransformPos(p); /// /// Transforms point p (p.W is presumed 1.0) by a . /// Projective transform is performed. Perspective Division is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransformPosProj(this Trafo3f r, V3f p) => r.Forward.TransformPosProj(p); /// /// Transforms point p (p.W is presumed 1.0) by a . /// Projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f TransformPosProjFull(this Trafo3f r, V3f p) => r.Forward.TransformPosProjFull(p); /// /// Transforms normal vector n (n.W is presumed 0.0) by a /// (i.e. by its transposed backward matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f TransformNormal(this Trafo3f r, V3f n) => r.Backward.TransposedTransformDir(n); /// /// Transforms a by the inverse of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f InvTransform(this Trafo3f r, V4f v) => r.Backward.Transform(v); /// /// Transforms direction vector v (v.W is presumed 0.0) by the inverse of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvTransformDir(this Trafo3f r, V3f v) => r.Backward.TransformDir(v); /// /// Transforms point p (p.W is presumed 1.0) by the inverse of a . /// No projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvTransformPos(this Trafo3f r, V3f p) => r.Backward.TransformPos(p); /// /// Transforms point p (p.W is presumed 1.0) by the inverse of a . /// Projective transform is performed. Perspective Division is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvTransformPosProj(this Trafo3f r, V3f p) => r.Backward.TransformPosProj(p); /// /// Transforms point p (p.W is presumed 1.0) by the inverse of a . /// Projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f InvTransformPosProjFull(this Trafo3f r, V3f p) => r.Backward.TransformPosProjFull(p); /// /// Transforms normal vector n (n.W is presumed 0.0) by the inverse of a /// (i.e. by its transposed forward matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvTransformNormal(this Trafo3f r, V3f n) => r.Forward.TransposedTransformDir(n); #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if two transformations are equal with regard to a threshold . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Trafo3f a, Trafo3f b, float epsilon) => a.Forward.ApproximateEquals(b.Forward, epsilon) && a.Backward.ApproximateEquals(b.Backward, epsilon); #endregion } #endregion #region Trafo2d /// /// A trafo is a container for a forward and a backward matrix. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public readonly partial struct Trafo2d : IEquatable { [DataMember] public readonly M33d Forward; [DataMember] public readonly M33d Backward; #region Constructors /// /// Constructs a from a forward and backward transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2d(M33d forward, M33d backward) { Forward = forward; Backward = backward; } /// /// Constructs a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2d(Trafo2d trafo) { Forward = trafo.Forward; Backward = trafo.Backward; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2d(Trafo2f trafo) { Forward = (M33d)trafo.Forward; Backward = (M33d)trafo.Backward; } /// /// Constructs a from an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2d(Affine2d trafo) { Forward = (M33d)trafo; Backward = (M33d)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2d(Euclidean2d trafo) { Forward = (M33d)trafo; Backward = (M33d)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2d(Similarity2d trafo) { Forward = (M33d)trafo; Backward = (M33d)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2d(Rot2d trafo) { Forward = (M33d)trafo; Backward = (M33d)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2d(Scale2d trafo) { Forward = (M33d)trafo; Backward = (M33d)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo2d(Shift2d trafo) { Forward = (M33d)trafo; Backward = (M33d)trafo.Inverse; } #endregion #region Constants /// /// Gets the identity transformation. /// public static Trafo2d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Trafo2d(M33d.Identity, M33d.Identity); } #endregion #region Properties /// /// Gets the inverse of this . /// public Trafo2d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Trafo2d(Backward, Forward); } #endregion #region Overrides public override int GetHashCode() => HashCode.GetCombined(Forward, Backward); [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Trafo2d other) => Forward.Equals(other.Forward) && Backward.Equals(other.Backward); public override bool Equals(object other) => (other is Trafo2d o) ? Equals(o) : false; public override string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Forward, Backward); public static Trafo2d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Trafo2d( M33d.Parse(x[0].ToString()), M33d.Parse(x[1].ToString()) ); } #endregion #region Static Creators /// /// Builds a transformation matrix using the scale, rotation (in radians) and translation components. /// NOTE: Uses the Scale * Rotation * Translation notion. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2d FromComponents(V2d scale, double rotationInRadians, V2d translation) => Scale(scale) * Rotation(rotationInRadians) * Translation(translation); /// /// Returns the that transforms from the coordinate system /// specified by the basis into the world coordinate system. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2d FromBasis(V2d xAxis, V2d yAxis, V2d origin) { var mat = new M33d( xAxis.X, yAxis.X, origin.X, xAxis.Y, yAxis.Y, origin.Y, 0, 0, 1); return new Trafo2d(mat, mat.Inverse); } /// /// Returns the that transforms from the coordinate system /// specified by the basis into the world coordinate system. /// Note that the axes MUST be normalized and normal to each other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2d FromOrthoNormalBasis(V2d xAxis, V2d yAxis) { return new Trafo2d( new M33d( xAxis.X, yAxis.X, 0, xAxis.Y, yAxis.Y, 0, 0, 0, 1), new M33d( xAxis.X, xAxis.Y, 0, yAxis.X, yAxis.Y, 0, 0, 0, 1) ); } #region Translation /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2d Translation(V2d v) => new Trafo2d(M33d.Translation(v), M33d.Translation(-v)); /// /// Creates a transformation with the translational component given by 2 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2d Translation(double tX, double tY) => Translation(new V2d(tX, tY)); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2d Translation(Shift2d shift) => Translation(shift.V); #endregion #region Scale /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2d Scale(V2d v) => new Trafo2d(M33d.Scale(v), M33d.Scale(1 / v)); /// /// Creates a scaling transformation using 2 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2d Scale(double sX, double sY) => new Trafo2d(M33d.Scale(sX, sY), M33d.Scale(1 / sX, 1 / sY)); /// /// Creates a scaling transformation using a uniform scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2d Scale(double s) { var t = 1 / s; return new Trafo2d(M33d.Scale(s), M33d.Scale(t)); } /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2d Scale(Scale2d scale) => new Trafo2d(scale); #endregion #region Rotation /// /// Creates a rotation transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2d Rotation(Rot2d rotation) => new Trafo2d(rotation); /// /// Creates a rotation transformation with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2d Rotation(double angleInRadians) => new Trafo2d(M33d.Rotation(angleInRadians), M33d.Rotation(-angleInRadians)); /// /// Creates a rotation transformation with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2d RotationInDegrees(double angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); #endregion #endregion #region Conversion Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo2f(Trafo2d r) => new Trafo2f(r); #endregion #region Operators /// /// Returns whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Trafo2d a, Trafo2d b) => a.Forward == b.Forward && a.Backward == b.Backward; /// /// Returns whether two transformations are different. /// public static bool operator !=(Trafo2d a, Trafo2d b) => a.Forward != b.Forward || a.Backward != b.Backward; /// /// The order of operation of Trafo2d multiplicaition is backward /// with respect to M33d multiplication in order to provide /// natural postfix notation. /// public static Trafo2d operator *(Trafo2d t0, Trafo2d t1) => new Trafo2d(t1.Forward * t0.Forward, t0.Backward * t1.Backward); #endregion } public static partial class Trafo { #region Operations /// /// Returns the inverse of the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo2d Inverse(Trafo2d trafo) => trafo.Inverse; /// /// Returns the forward matrix the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Forward(Trafo2d trafo) => trafo.Forward; /// /// Returns the backward matrix the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Backward(Trafo2d trafo) => trafo.Backward; #endregion #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this Trafo2d trafo) => trafo.Forward.GetScale2(); /// /// Extracts a scale vector from the given transformation by calculating the lengths of the basis vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GetScaleVector(this Trafo2d trafo) => trafo.Forward.GetScaleVector2(); #endregion #region Transformations /// /// Transforms a by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Transform(this Trafo2d r, V3d v) => r.Forward.Transform(v); /// /// Transforms direction vector v (v.Z is presumed 0.0) by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d TransformDir(this Trafo2d r, V2d v) => r.Forward.TransformDir(v); /// /// Transforms point p (p.Z is presumed 1.0) by a . /// No projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d TransformPos(this Trafo2d r, V2d p) => r.Forward.TransformPos(p); /// /// Transforms point p (p.Z is presumed 1.0) by a . /// Projective transform is performed. Perspective Division is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d TransformPosProj(this Trafo2d r, V2d p) => r.Forward.TransformPosProj(p); /// /// Transforms point p (p.Z is presumed 1.0) by a . /// Projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransformPosProjFull(this Trafo2d r, V2d p) => r.Forward.TransformPosProjFull(p); /// /// Transforms normal vector n (n.Z is presumed 0.0) by a /// (i.e. by its transposed backward matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d TransformNormal(this Trafo2d r, V2d n) => r.Backward.TransposedTransformDir(n); /// /// Transforms a by the inverse of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvTransform(this Trafo2d r, V3d v) => r.Backward.Transform(v); /// /// Transforms direction vector v (v.Z is presumed 0.0) by the inverse of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d InvTransformDir(this Trafo2d r, V2d v) => r.Backward.TransformDir(v); /// /// Transforms point p (p.Z is presumed 1.0) by the inverse of a . /// No projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d InvTransformPos(this Trafo2d r, V2d p) => r.Backward.TransformPos(p); /// /// Transforms point p (p.Z is presumed 1.0) by the inverse of a . /// Projective transform is performed. Perspective Division is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d InvTransformPosProj(this Trafo2d r, V2d p) => r.Backward.TransformPosProj(p); /// /// Transforms point p (p.Z is presumed 1.0) by the inverse of a . /// Projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvTransformPosProjFull(this Trafo2d r, V2d p) => r.Backward.TransformPosProjFull(p); /// /// Transforms normal vector n (n.Z is presumed 0.0) by the inverse of a /// (i.e. by its transposed forward matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d InvTransformNormal(this Trafo2d r, V2d n) => r.Forward.TransposedTransformDir(n); #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if two transformations are equal with regard to a threshold . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Trafo2d a, Trafo2d b, double epsilon) => a.Forward.ApproximateEquals(b.Forward, epsilon) && a.Backward.ApproximateEquals(b.Backward, epsilon); #endregion } #endregion #region Trafo3d /// /// A trafo is a container for a forward and a backward matrix. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public readonly partial struct Trafo3d : IEquatable { [DataMember] public readonly M44d Forward; [DataMember] public readonly M44d Backward; #region Constructors /// /// Constructs a from a forward and backward transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3d(M44d forward, M44d backward) { Forward = forward; Backward = backward; } /// /// Constructs a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3d(Trafo3d trafo) { Forward = trafo.Forward; Backward = trafo.Backward; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3d(Trafo3f trafo) { Forward = (M44d)trafo.Forward; Backward = (M44d)trafo.Backward; } /// /// Constructs a from an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3d(Affine3d trafo) { Forward = (M44d)trafo; Backward = (M44d)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3d(Euclidean3d trafo) { Forward = (M44d)trafo; Backward = (M44d)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3d(Similarity3d trafo) { Forward = (M44d)trafo; Backward = (M44d)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3d(Rot3d trafo) { Forward = (M44d)trafo; Backward = (M44d)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3d(Scale3d trafo) { Forward = (M44d)trafo; Backward = (M44d)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Trafo3d(Shift3d trafo) { Forward = (M44d)trafo; Backward = (M44d)trafo.Inverse; } #endregion #region Constants /// /// Gets the identity transformation. /// public static Trafo3d Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Trafo3d(M44d.Identity, M44d.Identity); } #endregion #region Properties /// /// Gets the inverse of this . /// public Trafo3d Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Trafo3d(Backward, Forward); } #endregion #region Overrides public override int GetHashCode() => HashCode.GetCombined(Forward, Backward); [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Trafo3d other) => Forward.Equals(other.Forward) && Backward.Equals(other.Backward); public override bool Equals(object other) => (other is Trafo3d o) ? Equals(o) : false; public override string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Forward, Backward); public static Trafo3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new Trafo3d( M44d.Parse(x[0].ToString()), M44d.Parse(x[1].ToString()) ); } #endregion #region Static Creators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d FromNormalFrame(V3d origin, V3d normal) { M44d.NormalFrame(origin, normal, out M44d forward, out M44d backward); return new Trafo3d(forward, backward); } /// /// Builds a transformation matrix using the scale, rotation and translation components. /// NOTE: Uses the Scale * Rotation * Translation notion. /// The rotation is in Euler-Angles (roll, pitch, yaw) in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d FromComponents(V3d scale, V3d rotationInRadians, V3d translation) => Scale(scale) * RotationEuler(rotationInRadians) * Translation(translation); /// /// Returns the that transforms from the coordinate system /// specified by the basis into the world coordinate system. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d FromBasis(V3d xAxis, V3d yAxis, V3d zAxis, V3d origin) { var mat = new M44d( xAxis.X, yAxis.X, zAxis.X, origin.X, xAxis.Y, yAxis.Y, zAxis.Y, origin.Y, xAxis.Z, yAxis.Z, zAxis.Z, origin.Z, 0, 0, 0, 1); return new Trafo3d(mat, mat.Inverse); } /// /// Returns the that transforms from the coordinate system /// specified by the basis into the world coordinate system. /// Note that the axes MUST be normalized and normal to each other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d FromOrthoNormalBasis(V3d xAxis, V3d yAxis, V3d zAxis) { return new Trafo3d( new M44d( xAxis.X, yAxis.X, zAxis.X, 0, xAxis.Y, yAxis.Y, zAxis.Y, 0, xAxis.Z, yAxis.Z, zAxis.Z, 0, 0, 0, 0, 1), new M44d( xAxis.X, xAxis.Y, xAxis.Z, 0, yAxis.X, yAxis.Y, yAxis.Z, 0, zAxis.X, zAxis.Y, zAxis.Z, 0, 0, 0, 0, 1) ); } #region Translation /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d Translation(V3d v) => new Trafo3d(M44d.Translation(v), M44d.Translation(-v)); /// /// Creates a transformation with the translational component given by 3 scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d Translation(double tX, double tY, double tZ) => Translation(new V3d(tX, tY, tZ)); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d Translation(Shift3d shift) => Translation(shift.V); #endregion #region Scale /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d Scale(V3d v) => new Trafo3d(M44d.Scale(v), M44d.Scale(1 / v)); /// /// Creates a scaling transformation using 3 scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d Scale(double sX, double sY, double sZ) => new Trafo3d(M44d.Scale(sX, sY, sZ), M44d.Scale(1 / sX, 1 / sY, 1 / sZ)); /// /// Creates a scaling transformation using a uniform scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d Scale(double s) { var t = 1 / s; return new Trafo3d(M44d.Scale(s), M44d.Scale(t)); } /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d Scale(Scale3d scale) => new Trafo3d(scale); #endregion #region Rotation /// /// Creates a rotation transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d Rotation(Rot3d rotation) => new Trafo3d(rotation); /// /// Creates a rotation transformation from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d Rotation(V3d normalizedAxis, double angleInRadians) => new Trafo3d(M44d.Rotation(normalizedAxis, angleInRadians), M44d.Rotation(normalizedAxis, -angleInRadians)); /// /// Creates a rotation transformation from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d RotationInDegrees(V3d normalizedAxis, double angleInDegrees) => Rotation(normalizedAxis, Conversion.RadiansFromDegrees(angleInDegrees)); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d RotationEuler(double rollInRadians, double pitchInRadians, double yawInRadians) { var m = M44d.RotationEuler(rollInRadians, pitchInRadians, yawInRadians); return new Trafo3d(m, m.Transposed); //transposed is equal but faster to inverted on orthonormal matrices like rotations. } /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d RotationEulerInDegrees(double rollInDegrees, double pitchInDegrees, double yawInDegrees) => RotationEuler(rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d RotationEuler(V3d rollPitchYawInRadians) => RotationEuler(rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d RotationEulerInDegrees(V3d rollPitchYawInDegrees) => RotationEulerInDegrees(rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a rotation transformation which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d RotateInto(V3d from, V3d into) { var rot = Rot3d.RotateInto(from, into); var inv = rot.Inverse; return new Trafo3d((M44d)rot, (M44d)inv); } /// /// Creates a rotation transformation by radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d RotationX(double angleInRadians) => new Trafo3d(M44d.RotationX(angleInRadians), M44d.RotationX(-angleInRadians)); /// /// Creates a rotation transformation by degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d RotationXInDegrees(double angleInDegrees) => RotationX(Conversion.RadiansFromDegrees(angleInDegrees)); /// /// Creates a rotation transformation by radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d RotationY(double angleInRadians) => new Trafo3d(M44d.RotationY(angleInRadians), M44d.RotationY(-angleInRadians)); /// /// Creates a rotation transformation by degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d RotationYInDegrees(double angleInDegrees) => RotationY(Conversion.RadiansFromDegrees(angleInDegrees)); /// /// Creates a rotation transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d RotationZ(double angleInRadians) => new Trafo3d(M44d.RotationZ(angleInRadians), M44d.RotationZ(-angleInRadians)); /// /// Creates a rotation transformation by degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d RotationZInDegrees(double angleInDegrees) => RotationZ(Conversion.RadiansFromDegrees(angleInDegrees)); #endregion #region Shear /// /// Creates a shear transformation along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d ShearYZ(double factorY, double factorZ) => new Trafo3d(M44d.ShearYZ(factorY, factorZ), M44d.ShearYZ(-factorY, -factorZ)); /// /// Creates a shear transformation along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d ShearXZ(double factorX, double factorZ) => new Trafo3d(M44d.ShearXZ(factorX, factorZ), M44d.ShearXZ(-factorX, -factorZ)); /// /// Creates a shear transformation along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d ShearXY(double factorX, double factorY) => new Trafo3d(M44d.ShearXY(factorX, factorY), M44d.ShearXY(-factorX, -factorY)); #endregion #region View transformation /// /// Creates a view transformation from the given vectors. /// /// Origin of the view /// Right vector of the view-plane /// Up vector of the view-plane /// Normal vector of the view-plane. This vector is supposed to point in view-direction for a left-handed view transformation and in opposite direction in the right-handed case. /// The view transformation [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d ViewTrafo(V3d location, V3d u, V3d v, V3d z) { return new Trafo3d( new M44d( u.X, u.Y, u.Z, -Vec.Dot(u, location), v.X, v.Y, v.Z, -Vec.Dot(v, location), z.X, z.Y, z.Z, -Vec.Dot(z, location), 0, 0, 0, 1 ), new M44d( u.X, v.X, z.X, location.X, u.Y, v.Y, z.Y, location.Y, u.Z, v.Z, z.Z, location.Z, 0, 0, 0, 1 )); } /// /// Creates a right-handed view trafo, where z-negative points into the scene. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d ViewTrafoRH(V3d location, V3d up, V3d forward) => ViewTrafo(location, forward.Cross(up), up, -forward); /// /// Creates a left-handed view trafo, where z-positive points into the scene. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d ViewTrafoLH(V3d location, V3d up, V3d forward) => ViewTrafo(location, up.Cross(forward), up, forward); #endregion #region Projection transformation /// /// Creates a right-handed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, 0), (+1, +1, +1)]. /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. Can be infinite. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d PerspectiveProjectionRH(double l, double r, double b, double t, double n, double f = double.PositiveInfinity) { double m22, m23, m32i; if (f.IsPositiveInfinity()) { m22 = -1; m23 = -n; m32i = -1 / n; } else { m22 = f / (n - f); m23 = (f * n) / (n - f); m32i = (n - f) / (f * n); } return new Trafo3d( new M44d( (2 * n) / (r - l), 0, (r + l) / (r - l), 0, 0, (2 * n) / (t - b), (t + b) / (t - b), 0, 0, 0, m22, m23, 0, 0, -1, 0 ), new M44d( (r - l) / (2 * n), 0, 0, (r + l) / (2 * n), 0, (t - b) / (2 * n), 0, (t + b) / (2 * n), 0, 0, 0, -1, 0, 0, m32i, 1 / n ) ); } /// /// Creates a right-handed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, 0), (+1, +1, +1)]. /// /// Horizontal field of view in radians. /// Aspect ratio, defined as view space width divided by height. /// Z-value of the near view-plane. /// Z-value of the far view-plane. Can be infinite. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d PerspectiveProjectionRH(double horizontalFovInRadians, double aspect, double n, double f = double.PositiveInfinity) { double d = Fun.Tan(0.5 * horizontalFovInRadians) * n; return Trafo3d.PerspectiveProjectionRH(-d, d, -d / aspect, d / aspect, n, f); } /// /// Creates a right-handed reversed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, +1), (+1, +1, 0)]. /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. Can be infinite. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d PerspectiveProjectionReversedRH(double l, double r, double b, double t, double n, double f = double.PositiveInfinity) { double m22, m23, m32i, m33i; if (f.IsPositiveInfinity()) { m22 = 0; m23 = n; m32i = 1 / n; m33i = 0; } else { m22 = n / (f - n); m23 = (f * n) / (f - n); m32i = (f - n) / (f * n); m33i = 1 / f; } return new Trafo3d( new M44d( (2 * n) / (r - l), 0, (r + l) / (r - l), 0, 0, (2 * n) / (t - b), (t + b) / (t - b), 0, 0, 0, m22, m23, 0, 0, -1, 0 ), new M44d( (r - l) / (2 * n), 0, 0, (r + l) / (2 * n), 0, (t - b) / (2 * n), 0, (t + b) / (2 * n), 0, 0, 0, -1, 0, 0, m32i, m33i ) ); } /// /// Creates a right-handed reversed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, +1), (+1, +1, 0)]. /// /// Horizontal field of view in radians. /// Aspect ratio, defined as view space width divided by height. /// Z-value of the near view-plane. /// Z-value of the far view-plane. Can be infinite. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d PerspectiveProjectionReversedRH(double horizontalFovInRadians, double aspect, double n, double f = double.PositiveInfinity) { double d = Fun.Tan(0.5 * horizontalFovInRadians) * n; return Trafo3d.PerspectiveProjectionReversedRH(-d, d, -d / aspect, d / aspect, n, f); } /// /// Creates a right-handed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, -1), (+1, +1, +1)] and left-handed (handedness flip between view and NDC space). /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. Can be infinite. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d PerspectiveProjectionGL(double l, double r, double b, double t, double n, double f = double.PositiveInfinity) { double m22, m23, m32i, m33i; if (f.IsPositiveInfinity()) { m22 = -1; m23 = -2 * n; m32i = -1 / (2 * n); m33i = -m32i; } else { m22 = (f + n) / (n - f); m23 = (2 * f * n) / (n - f); m32i = (n - f) / (2 * f * n); m33i = (f + n) / (2 * f * n); } return new Trafo3d( new M44d( (2 * n) / (r - l), 0, (r + l) / (r - l), 0, 0, (2 * n) / (t - b), (t + b) / (t - b), 0, 0, 0, m22, m23, 0, 0, -1, 0 ), new M44d( (r - l) / (2 * n), 0, 0, (r + l) / (2 * n), 0, (t - b) / (2 * n), 0, (t + b) / (2 * n), 0, 0, 0, -1, 0, 0, m32i, m33i ) ); } /// /// Creates a right-handed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, -1), (+1, +1, +1)] and left-handed (handedness flip between view and NDC space). /// /// Horizontal field of view in radians. /// Aspect ratio, defined as view space width divided by height. /// Z-value of the near view-plane. /// Z-value of the far view-plane. Can be infinite. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d PerspectiveProjectionGL(double horizontalFovInRadians, double aspect, double n, double f = double.PositiveInfinity) { double d = Fun.Tan(0.5 * horizontalFovInRadians) * n; return Trafo3d.PerspectiveProjectionGL(-d, d, -d / aspect, d / aspect, n, f); } /// /// Creates a right-handed reversed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, +1), (+1, +1, -1)]. /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. Can be infinite. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d PerspectiveProjectionReversedGL(double l, double r, double b, double t, double n, double f = double.PositiveInfinity) { double m22, m23, m32i, m33i; if (f.IsPositiveInfinity()) { m22 = 1; m23 = 2 * n; m32i = 1 / (2 * n); m33i = m32i; } else { m22 = (f + n) / (f - n); m23 = (2 * f * n) / (f - n); m32i = (f - n) / (2 * f * n); m33i = (f + n) / (2 * f * n); } return new Trafo3d( new M44d( (2 * n) / (r - l), 0, (r + l) / (r - l), 0, 0, (2 * n) / (t - b), (t + b) / (t - b), 0, 0, 0, m22, m23, 0, 0, -1, 0 ), new M44d( (r - l) / (2 * n), 0, 0, (r + l) / (2 * n), 0, (t - b) / (2 * n), 0, (t + b) / (2 * n), 0, 0, 0, -1, 0, 0, m32i, m33i ) ); } /// /// Creates a right-handed reversed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, +1), (+1, +1, -1)]. /// /// Horizontal field of view in radians. /// Aspect ratio, defined as view space width divided by height. /// Z-value of the near view-plane. /// Z-value of the far view-plane. Can be infinite. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d PerspectiveProjectionReversedGL(double horizontalFovInRadians, double aspect, double n, double f = double.PositiveInfinity) { double d = Fun.Tan(0.5 * horizontalFovInRadians) * n; return Trafo3d.PerspectiveProjectionReversedGL(-d, d, -d / aspect, d / aspect, n, f); } /// /// Creates a right-handed orthographic projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, 0), (+1, +1, +1)]. /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d OrthoProjectionRH(double l, double r, double b, double t, double n, double f) { return new Trafo3d( new M44d( 2 / (r - l), 0, 0, (l + r) / (l - r), 0, 2 / (t - b), 0, (b + t) / (b - t), 0, 0, 1 / (n - f), n / (n - f), 0, 0, 0, 1 ), new M44d( (r - l) / 2, 0, 0, (l + r) / 2, 0, (t - b) / 2, 0, (b + t) / 2, 0, 0, n - f, -n, 0, 0, 0, 1 ) ); } /// /// Creates a right-handed orthographic projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, -1), (+1, +1, +1)] and left-handed (handedness flip between view and NDC space). /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d OrthoProjectionGL(double l, double r, double b, double t, double n, double f) { return new Trafo3d( new M44d( 2 / (r - l), 0, 0, (l + r) / (l - r), 0, 2 / (t - b), 0, (b + t) / (b - t), 0, 0, 2 / (n - f), (f + n) / (n - f), 0, 0, 0, 1 ), new M44d( (r - l) / 2, 0, 0, (l + r) / 2, 0, (t - b) / 2, 0, (b + t) / 2, 0, 0, (n - f) / 2, -(f + n) / 2, 0, 0, 0, 1 ) ); } #endregion #endregion #region Conversion Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Trafo3f(Trafo3d r) => new Trafo3f(r); #endregion #region Operators /// /// Returns whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Trafo3d a, Trafo3d b) => a.Forward == b.Forward && a.Backward == b.Backward; /// /// Returns whether two transformations are different. /// public static bool operator !=(Trafo3d a, Trafo3d b) => a.Forward != b.Forward || a.Backward != b.Backward; /// /// The order of operation of Trafo3d multiplicaition is backward /// with respect to M44d multiplication in order to provide /// natural postfix notation. /// public static Trafo3d operator *(Trafo3d t0, Trafo3d t1) => new Trafo3d(t1.Forward * t0.Forward, t0.Backward * t1.Backward); #endregion } public static partial class Trafo { #region Operations /// /// Returns the inverse of the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d Inverse(Trafo3d trafo) => trafo.Inverse; /// /// Returns the forward matrix the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Forward(Trafo3d trafo) => trafo.Forward; /// /// Returns the backward matrix the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Backward(Trafo3d trafo) => trafo.Backward; #endregion #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double GetScale(this Trafo3d trafo) => trafo.Forward.GetScale3(); /// /// Extracts a scale vector from the given transformation by calculating the lengths of the basis vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetScaleVector(this Trafo3d trafo) => trafo.Forward.GetScaleVector3(); /// /// Extracts the inverse/backward translation component of the given transformation, which when given /// a view transformation represents the location of the camera in world space. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetViewPosition(this Trafo3d trafo) => trafo.Backward.C3.XYZ; /// /// Extracts the forward vector from the given view transformation. /// NOTE: A left-handed coordinates system transformation is expected, /// where the view-space z-axis points in forward direction. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetViewDirectionLH(this Trafo3d trafo) => trafo.Forward.GetViewDirectionLH(); /// /// Extracts the forward vector from the given view transformation. /// NOTE: A right-handed coordinates system transformation is expected, where /// the view-space z-axis points opposit the forward vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetViewDirectionRH(this Trafo3d trafo) => trafo.Forward.GetViewDirectionRH(); /// /// Extracts the translation component of the given transformation, which when given /// a model transformation represents the model origin in world position. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GetModelOrigin(this Trafo3d trafo) => trafo.Forward.GetModelOrigin(); /// /// Builds a hull from the given view-projection transformation (left, right, bottom, top, near, far). /// The view volume is assumed to be [-1, -1, -1] [1, 1, 1]. /// The normals of the hull planes point to the outside and are normalized. /// A point inside the visual hull will has negative height to all planes. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Hull3d GetVisualHull(this Trafo3d viewProj) => viewProj.Forward.GetVisualHull(); /// /// Builds an ortho-normal orientation transformation form the given transform. /// Scale and Translation will be removed and basis vectors will be ortho-normalized. /// NOTE: The x-axis is untouched and y/z are forced to a normal-angle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Trafo3d GetOrthoNormalOrientation(this Trafo3d trafo) { var x = trafo.Forward.C0.XYZ.Normalized; var z = trafo.Forward.C2.XYZ; var y = z.Cross(x).Normalized; z = x.Cross(y).Normalized; return Trafo3d.FromOrthoNormalBasis(x, y, z); } /// /// Decomposes a transformation into a scale, rotation and translation component. /// NOTE: The input is assumed to be a valid affine transformation. /// The rotation output is a vector with Euler-Angles [roll (X), pitch (Y), yaw (Z)] in radians of rotation order Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Decompose(this Trafo3d trafo, out V3d scale, out V3d rotationInRadians, out V3d translation) { translation = trafo.GetModelOrigin(); var rt = trafo.GetOrthoNormalOrientation(); if (rt.Forward.Determinant.IsTiny()) { rotationInRadians = V3d.Zero; } else { var rot = Rot3d.FromFrame(rt.Forward.C0.XYZ, rt.Forward.C1.XYZ, rt.Forward.C2.XYZ); rotationInRadians = rot.GetEulerAngles(); } scale = trafo.GetScaleVector(); // if matrix is left-handed there must be some negative scale // since rotation remains the x-axis, the y-axis must be flipped if (trafo.Forward.Determinant < 0) scale.Y = -scale.Y; } #endregion #region Transformations /// /// Transforms a by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Transform(this Trafo3d r, V4d v) => r.Forward.Transform(v); /// /// Transforms direction vector v (v.W is presumed 0.0) by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransformDir(this Trafo3d r, V3d v) => r.Forward.TransformDir(v); /// /// Transforms point p (p.W is presumed 1.0) by a . /// No projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransformPos(this Trafo3d r, V3d p) => r.Forward.TransformPos(p); /// /// Transforms point p (p.W is presumed 1.0) by a . /// Projective transform is performed. Perspective Division is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransformPosProj(this Trafo3d r, V3d p) => r.Forward.TransformPosProj(p); /// /// Transforms point p (p.W is presumed 1.0) by a . /// Projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d TransformPosProjFull(this Trafo3d r, V3d p) => r.Forward.TransformPosProjFull(p); /// /// Transforms normal vector n (n.W is presumed 0.0) by a /// (i.e. by its transposed backward matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d TransformNormal(this Trafo3d r, V3d n) => r.Backward.TransposedTransformDir(n); /// /// Transforms a by the inverse of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d InvTransform(this Trafo3d r, V4d v) => r.Backward.Transform(v); /// /// Transforms direction vector v (v.W is presumed 0.0) by the inverse of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvTransformDir(this Trafo3d r, V3d v) => r.Backward.TransformDir(v); /// /// Transforms point p (p.W is presumed 1.0) by the inverse of a . /// No projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvTransformPos(this Trafo3d r, V3d p) => r.Backward.TransformPos(p); /// /// Transforms point p (p.W is presumed 1.0) by the inverse of a . /// Projective transform is performed. Perspective Division is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvTransformPosProj(this Trafo3d r, V3d p) => r.Backward.TransformPosProj(p); /// /// Transforms point p (p.W is presumed 1.0) by the inverse of a . /// Projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d InvTransformPosProjFull(this Trafo3d r, V3d p) => r.Backward.TransformPosProjFull(p); /// /// Transforms normal vector n (n.W is presumed 0.0) by the inverse of a /// (i.e. by its transposed forward matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvTransformNormal(this Trafo3d r, V3d n) => r.Forward.TransposedTransformDir(n); #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if two transformations are equal with regard to a threshold . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this Trafo3d a, Trafo3d b, double epsilon) => a.Forward.ApproximateEquals(b.Forward, epsilon) && a.Backward.ApproximateEquals(b.Backward, epsilon); #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Trafos/Trafo_template.cs ================================================ using System; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.CompilerServices; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# Action comma = () => Out(", "); //# Action commaln = () => Out("," + Environment.NewLine); //# Action add = () => Out(" + "); //# Action and = () => Out(" && "); //# var fields = new[] {"X", "Y", "Z", "W"}; //# var fieldsL = new[] {"x", "y", "z", "w"}; //# foreach (var rt in Meta.RealTypes) { //# for (int n = 2; n <= 3; n++) { //# var m = n + 1; //# var rt2 = (rt == Meta.DoubleType) ? Meta.FloatType : Meta.DoubleType; //# var rtype = rt.Name; //# var rtype2 = rt2.Name; //# var tc = rt.Char; //# var tc2 = rt2.Char; //# var type = "Trafo" + n + tc; //# var type2 = "Trafo" + n + tc2; //# var mnnt = "M" + n + n + tc; //# var mnnt2 = "M" + n + n + tc2; //# var mmmt = "M" + m + m + tc; //# var mmmt2 = "M" + m + m + tc2; //# var rotnt = "Rot" + n + tc; //# var euclideannt = "Euclidean" + n + tc; //# var similaritynt = "Similarity" + n + tc; //# var affinent = "Affine" + n + tc; //# var shiftnt = "Shift" + n + tc; //# var scalent = "Scale" + n + tc; //# var vnt = "V" + n + tc; //# var vmt = "V" + m + tc; //# var nfields = fields.Take(n).ToArray(); //# var nfieldsL = fieldsL.Take(n).ToArray(); //# var fn = fields[n]; //# var isDouble = (rt == Meta.DoubleType); //# var half = (rt != Meta.DoubleType) ? "0.5f" : "0.5"; #region __type__ /// /// A trafo is a container for a forward and a backward matrix. /// [DataContract] [StructLayout(LayoutKind.Sequential)] public readonly partial struct __type__ : IEquatable<__type__> { [DataMember] public readonly __mmmt__ Forward; [DataMember] public readonly __mmmt__ Backward; #region Constructors /// /// Constructs a from a forward and backward transformation . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__mmmt__ forward, __mmmt__ backward) { Forward = forward; Backward = backward; } /// /// Constructs a from another . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type__ trafo) { Forward = trafo.Forward; Backward = trafo.Backward; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__type2__ trafo) { Forward = (__mmmt__)trafo.Forward; Backward = (__mmmt__)trafo.Backward; } /// /// Constructs a from an transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__affinent__ trafo) { Forward = (__mmmt__)trafo; Backward = (__mmmt__)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__euclideannt__ trafo) { Forward = (__mmmt__)trafo; Backward = (__mmmt__)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__similaritynt__ trafo) { Forward = (__mmmt__)trafo; Backward = (__mmmt__)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__rotnt__ trafo) { Forward = (__mmmt__)trafo; Backward = (__mmmt__)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__scalent__ trafo) { Forward = (__mmmt__)trafo; Backward = (__mmmt__)trafo.Inverse; } /// /// Constructs a from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __type__(__shiftnt__ trafo) { Forward = (__mmmt__)trafo; Backward = (__mmmt__)trafo.Inverse; } #endregion #region Constants /// /// Gets the identity transformation. /// public static __type__ Identity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(__mmmt__.Identity, __mmmt__.Identity); } #endregion #region Properties /// /// Gets the inverse of this . /// public __type__ Inverse { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new __type__(Backward, Forward); } #endregion #region Overrides public override int GetHashCode() => HashCode.GetCombined(Forward, Backward); [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(__type__ other) => Forward.Equals(other.Forward) && Backward.Equals(other.Backward); public override bool Equals(object other) => (other is __type__ o) ? Equals(o) : false; public override string ToString() => string.Format(CultureInfo.InvariantCulture, "[{0}, {1}]", Forward, Backward); public static __type__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __type__( __mmmt__.Parse(x[0].ToString()), __mmmt__.Parse(x[1].ToString()) ); } #endregion #region Static Creators //# if (n == 3) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromNormalFrame(__vnt__ origin, __vnt__ normal) { __mmmt__.NormalFrame(origin, normal, out __mmmt__ forward, out __mmmt__ backward); return new __type__(forward, backward); } //# } //# if (n == 2) { /// /// Builds a transformation matrix using the scale, rotation (in radians) and translation components. /// NOTE: Uses the Scale * Rotation * Translation notion. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromComponents(__vnt__ scale, __rtype__ rotationInRadians, __vnt__ translation) => Scale(scale) * Rotation(rotationInRadians) * Translation(translation); //# } else { /// /// Builds a transformation matrix using the scale, rotation and translation components. /// NOTE: Uses the Scale * Rotation * Translation notion. /// The rotation is in Euler-Angles (roll, pitch, yaw) in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromComponents(__vnt__ scale, __vnt__ rotationInRadians, __vnt__ translation) => Scale(scale) * RotationEuler(rotationInRadians) * Translation(translation); //# } /// /// Returns the that transforms from the coordinate system /// specified by the basis into the world coordinate system. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromBasis(/*# nfieldsL.ForEach(f => {*/__vnt__ __f__Axis/*# }, comma);*/, __vnt__ origin) { var mat = new __mmmt__(/*# nfields.ForEach(fi => {*/ /*# nfieldsL.ForEach(fj => {*/__fj__Axis.__fi__/*# }, comma);*/, origin.__fi__/*#}, comma);*/, /*# n.ForEach(j => {*/0/*# }, comma);*/, 1); return new __type__(mat, mat.Inverse); } /// /// Returns the that transforms from the coordinate system /// specified by the basis into the world coordinate system. /// Note that the axes MUST be normalized and normal to each other. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ FromOrthoNormalBasis(/*# nfieldsL.ForEach(f => {*/__vnt__ __f__Axis/*# }, comma);*/) { return new __type__( new __mmmt__(/*# nfields.ForEach(fi => {*/ /*# nfieldsL.ForEach(fj => {*/__fj__Axis.__fi__/*# }, comma);*/, 0/*#}, comma);*/, /*# n.ForEach(j => {*/0/*# }, comma);*/, 1), new __mmmt__(/*# nfieldsL.ForEach(fi => {*/ /*# nfields.ForEach(fj => {*/__fi__Axis.__fj__/*# }, comma);*/, 0/*#}, comma);*/, /*# n.ForEach(j => {*/0/*# }, comma);*/, 1) ); } #region Translation /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Translation(__vnt__ v) => new __type__(__mmmt__.Translation(v), __mmmt__.Translation(-v)); /// /// Creates a transformation with the translational component given by __n__ scalars. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Translation(/*# nfields.ForEach(f => { */__rtype__ t__f__/*# }, comma); */) => Translation(new __vnt__(/*# nfields.ForEach(f => { */t__f__/*# }, comma); */)); /// /// Creates an transformation with the translational component given by a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Translation(__shiftnt__ shift) => Translation(shift.V); #endregion #region Scale /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Scale(__vnt__ v) => new __type__(__mmmt__.Scale(v), __mmmt__.Scale(1 / v)); /// /// Creates a scaling transformation using __n__ scalars as scaling factors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Scale(/*# nfields.ForEach(f => { */__rtype__ s__f__/*# }, comma); */) => new __type__(__mmmt__.Scale(/*# nfields.ForEach(f => { */s__f__/*# }, comma); */), __mmmt__.Scale(/*# nfields.ForEach(f => { */1 / s__f__/*# }, comma); */)); /// /// Creates a scaling transformation using a uniform scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Scale(__rtype__ s) { var t = 1 / s; return new __type__(__mmmt__.Scale(s), __mmmt__.Scale(t)); } /// /// Creates a scaling transformation using a as scaling factor. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Scale(__scalent__ scale) => new __type__(scale); #endregion #region Rotation /// /// Creates a rotation transformation from a transformation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Rotation(__rotnt__ rotation) => new __type__(rotation); //# if (n == 2) { /// /// Creates a rotation transformation with the specified angle in radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Rotation(__rtype__ angleInRadians) => new __type__(__mmmt__.Rotation(angleInRadians), __mmmt__.Rotation(-angleInRadians)); /// /// Creates a rotation transformation with the specified angle in degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationInDegrees(__rtype__ angleInDegrees) => Rotation(angleInDegrees.RadiansFromDegrees()); //# } else if (n == 3) { /// /// Creates a rotation transformation from an axis vector and an angle in radians. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Rotation(__vnt__ normalizedAxis, __rtype__ angleInRadians) => new __type__(__mmmt__.Rotation(normalizedAxis, angleInRadians), __mmmt__.Rotation(normalizedAxis, -angleInRadians)); /// /// Creates a rotation transformation from an axis vector and an angle in degrees. /// The axis vector has to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationInDegrees(__vnt__ normalizedAxis, __rtype__ angleInDegrees) => Rotation(normalizedAxis, Conversion.RadiansFromDegrees(angleInDegrees)); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEuler(__rtype__ rollInRadians, __rtype__ pitchInRadians, __rtype__ yawInRadians) { var m = __mmmt__.RotationEuler(rollInRadians, pitchInRadians, yawInRadians); return new __type__(m, m.Transposed); //transposed is equal but faster to inverted on orthonormal matrices like rotations. } /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEulerInDegrees(__rtype__ rollInDegrees, __rtype__ pitchInDegrees, __rtype__ yawInDegrees) => RotationEuler(rollInDegrees.RadiansFromDegrees(), pitchInDegrees.RadiansFromDegrees(), yawInDegrees.RadiansFromDegrees()); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in radians. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEuler(__vnt__ rollPitchYawInRadians) => RotationEuler(rollPitchYawInRadians.X, rollPitchYawInRadians.Y, rollPitchYawInRadians.Z); /// /// Creates a rotation transformation from roll (X), pitch (Y), and yaw (Z) vector in degrees. /// The rotation order is: Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationEulerInDegrees(__vnt__ rollPitchYawInDegrees) => RotationEulerInDegrees(rollPitchYawInDegrees.X, rollPitchYawInDegrees.Y, rollPitchYawInDegrees.Z); /// /// Creates a rotation transformation which rotates one vector into another. /// The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotateInto(__vnt__ from, __vnt__ into) { var rot = __rotnt__.RotateInto(from, into); var inv = rot.Inverse; return new __type__((__mmmt__)rot, (__mmmt__)inv); } /// /// Creates a rotation transformation by radians around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationX(__rtype__ angleInRadians) => new __type__(__mmmt__.RotationX(angleInRadians), __mmmt__.RotationX(-angleInRadians)); /// /// Creates a rotation transformation by degrees around the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationXInDegrees(__rtype__ angleInDegrees) => RotationX(Conversion.RadiansFromDegrees(angleInDegrees)); /// /// Creates a rotation transformation by radians around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationY(__rtype__ angleInRadians) => new __type__(__mmmt__.RotationY(angleInRadians), __mmmt__.RotationY(-angleInRadians)); /// /// Creates a rotation transformation by degrees around the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationYInDegrees(__rtype__ angleInDegrees) => RotationY(Conversion.RadiansFromDegrees(angleInDegrees)); /// /// Creates a rotation transformation by radians around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationZ(__rtype__ angleInRadians) => new __type__(__mmmt__.RotationZ(angleInRadians), __mmmt__.RotationZ(-angleInRadians)); /// /// Creates a rotation transformation by degrees around the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ RotationZInDegrees(__rtype__ angleInDegrees) => RotationZ(Conversion.RadiansFromDegrees(angleInDegrees)); //# } #endregion //# if (n == 3) { #region Shear /// /// Creates a shear transformation along the x-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ ShearYZ(__rtype__ factorY, __rtype__ factorZ) => new __type__(__mmmt__.ShearYZ(factorY, factorZ), __mmmt__.ShearYZ(-factorY, -factorZ)); /// /// Creates a shear transformation along the y-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ ShearXZ(__rtype__ factorX, __rtype__ factorZ) => new __type__(__mmmt__.ShearXZ(factorX, factorZ), __mmmt__.ShearXZ(-factorX, -factorZ)); /// /// Creates a shear transformation along the z-axis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ ShearXY(__rtype__ factorX, __rtype__ factorY) => new __type__(__mmmt__.ShearXY(factorX, factorY), __mmmt__.ShearXY(-factorX, -factorY)); #endregion #region View transformation /// /// Creates a view transformation from the given vectors. /// /// Origin of the view /// Right vector of the view-plane /// Up vector of the view-plane /// Normal vector of the view-plane. This vector is supposed to point in view-direction for a left-handed view transformation and in opposite direction in the right-handed case. /// The view transformation [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ ViewTrafo(__vnt__ location, __vnt__ u, __vnt__ v, __vnt__ z) { return new __type__( new __mmmt__( u.X, u.Y, u.Z, -Vec.Dot(u, location), v.X, v.Y, v.Z, -Vec.Dot(v, location), z.X, z.Y, z.Z, -Vec.Dot(z, location), 0, 0, 0, 1 ), new __mmmt__( u.X, v.X, z.X, location.X, u.Y, v.Y, z.Y, location.Y, u.Z, v.Z, z.Z, location.Z, 0, 0, 0, 1 )); } /// /// Creates a right-handed view trafo, where z-negative points into the scene. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ ViewTrafoRH(__vnt__ location, __vnt__ up, __vnt__ forward) => ViewTrafo(location, forward.Cross(up), up, -forward); /// /// Creates a left-handed view trafo, where z-positive points into the scene. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ ViewTrafoLH(__vnt__ location, __vnt__ up, __vnt__ forward) => ViewTrafo(location, up.Cross(forward), up, forward); #endregion #region Projection transformation /// /// Creates a right-handed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, 0), (+1, +1, +1)]. /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. Can be infinite. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ PerspectiveProjectionRH(__rtype__ l, __rtype__ r, __rtype__ b, __rtype__ t, __rtype__ n, __rtype__ f = __rtype__.PositiveInfinity) { __rtype__ m22, m23, m32i; if (f.IsPositiveInfinity()) { m22 = -1; m23 = -n; m32i = -1 / n; } else { m22 = f / (n - f); m23 = (f * n) / (n - f); m32i = (n - f) / (f * n); } return new __type__( new __mmmt__( (2 * n) / (r - l), 0, (r + l) / (r - l), 0, 0, (2 * n) / (t - b), (t + b) / (t - b), 0, 0, 0, m22, m23, 0, 0, -1, 0 ), new __mmmt__( (r - l) / (2 * n), 0, 0, (r + l) / (2 * n), 0, (t - b) / (2 * n), 0, (t + b) / (2 * n), 0, 0, 0, -1, 0, 0, m32i, 1 / n ) ); } /// /// Creates a right-handed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, 0), (+1, +1, +1)]. /// /// Horizontal field of view in radians. /// Aspect ratio, defined as view space width divided by height. /// Z-value of the near view-plane. /// Z-value of the far view-plane. Can be infinite. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ PerspectiveProjectionRH(__rtype__ horizontalFovInRadians, __rtype__ aspect, __rtype__ n, __rtype__ f = __rtype__.PositiveInfinity) { __rtype__ d = Fun.Tan(__half__ * horizontalFovInRadians) * n; return __type__.PerspectiveProjectionRH(-d, d, -d / aspect, d / aspect, n, f); } /// /// Creates a right-handed reversed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, +1), (+1, +1, 0)]. /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. Can be infinite. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ PerspectiveProjectionReversedRH(__rtype__ l, __rtype__ r, __rtype__ b, __rtype__ t, __rtype__ n, __rtype__ f = __rtype__.PositiveInfinity) { __rtype__ m22, m23, m32i, m33i; if (f.IsPositiveInfinity()) { m22 = 0; m23 = n; m32i = 1 / n; m33i = 0; } else { m22 = n / (f - n); m23 = (f * n) / (f - n); m32i = (f - n) / (f * n); m33i = 1 / f; } return new __type__( new __mmmt__( (2 * n) / (r - l), 0, (r + l) / (r - l), 0, 0, (2 * n) / (t - b), (t + b) / (t - b), 0, 0, 0, m22, m23, 0, 0, -1, 0 ), new __mmmt__( (r - l) / (2 * n), 0, 0, (r + l) / (2 * n), 0, (t - b) / (2 * n), 0, (t + b) / (2 * n), 0, 0, 0, -1, 0, 0, m32i, m33i ) ); } /// /// Creates a right-handed reversed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, +1), (+1, +1, 0)]. /// /// Horizontal field of view in radians. /// Aspect ratio, defined as view space width divided by height. /// Z-value of the near view-plane. /// Z-value of the far view-plane. Can be infinite. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ PerspectiveProjectionReversedRH(__rtype__ horizontalFovInRadians, __rtype__ aspect, __rtype__ n, __rtype__ f = __rtype__.PositiveInfinity) { __rtype__ d = Fun.Tan(__half__ * horizontalFovInRadians) * n; return __type__.PerspectiveProjectionReversedRH(-d, d, -d / aspect, d / aspect, n, f); } /// /// Creates a right-handed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, -1), (+1, +1, +1)] and left-handed (handedness flip between view and NDC space). /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. Can be infinite. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ PerspectiveProjectionGL(__rtype__ l, __rtype__ r, __rtype__ b, __rtype__ t, __rtype__ n, __rtype__ f = __rtype__.PositiveInfinity) { __rtype__ m22, m23, m32i, m33i; if (f.IsPositiveInfinity()) { m22 = -1; m23 = -2 * n; m32i = -1 / (2 * n); m33i = -m32i; } else { m22 = (f + n) / (n - f); m23 = (2 * f * n) / (n - f); m32i = (n - f) / (2 * f * n); m33i = (f + n) / (2 * f * n); } return new __type__( new __mmmt__( (2 * n) / (r - l), 0, (r + l) / (r - l), 0, 0, (2 * n) / (t - b), (t + b) / (t - b), 0, 0, 0, m22, m23, 0, 0, -1, 0 ), new __mmmt__( (r - l) / (2 * n), 0, 0, (r + l) / (2 * n), 0, (t - b) / (2 * n), 0, (t + b) / (2 * n), 0, 0, 0, -1, 0, 0, m32i, m33i ) ); } /// /// Creates a right-handed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, -1), (+1, +1, +1)] and left-handed (handedness flip between view and NDC space). /// /// Horizontal field of view in radians. /// Aspect ratio, defined as view space width divided by height. /// Z-value of the near view-plane. /// Z-value of the far view-plane. Can be infinite. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ PerspectiveProjectionGL(__rtype__ horizontalFovInRadians, __rtype__ aspect, __rtype__ n, __rtype__ f = __rtype__.PositiveInfinity) { __rtype__ d = Fun.Tan(__half__ * horizontalFovInRadians) * n; return __type__.PerspectiveProjectionGL(-d, d, -d / aspect, d / aspect, n, f); } /// /// Creates a right-handed reversed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, +1), (+1, +1, -1)]. /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. Can be infinite. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ PerspectiveProjectionReversedGL(__rtype__ l, __rtype__ r, __rtype__ b, __rtype__ t, __rtype__ n, __rtype__ f = __rtype__.PositiveInfinity) { __rtype__ m22, m23, m32i, m33i; if (f.IsPositiveInfinity()) { m22 = 1; m23 = 2 * n; m32i = 1 / (2 * n); m33i = m32i; } else { m22 = (f + n) / (f - n); m23 = (2 * f * n) / (f - n); m32i = (f - n) / (2 * f * n); m33i = (f + n) / (2 * f * n); } return new __type__( new __mmmt__( (2 * n) / (r - l), 0, (r + l) / (r - l), 0, 0, (2 * n) / (t - b), (t + b) / (t - b), 0, 0, 0, m22, m23, 0, 0, -1, 0 ), new __mmmt__( (r - l) / (2 * n), 0, 0, (r + l) / (2 * n), 0, (t - b) / (2 * n), 0, (t + b) / (2 * n), 0, 0, 0, -1, 0, 0, m32i, m33i ) ); } /// /// Creates a right-handed reversed perspective projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, +1), (+1, +1, -1)]. /// /// Horizontal field of view in radians. /// Aspect ratio, defined as view space width divided by height. /// Z-value of the near view-plane. /// Z-value of the far view-plane. Can be infinite. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ PerspectiveProjectionReversedGL(__rtype__ horizontalFovInRadians, __rtype__ aspect, __rtype__ n, __rtype__ f = __rtype__.PositiveInfinity) { __rtype__ d = Fun.Tan(__half__ * horizontalFovInRadians) * n; return __type__.PerspectiveProjectionReversedGL(-d, d, -d / aspect, d / aspect, n, f); } /// /// Creates a right-handed orthographic projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, 0), (+1, +1, +1)]. /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ OrthoProjectionRH(__rtype__ l, __rtype__ r, __rtype__ b, __rtype__ t, __rtype__ n, __rtype__ f) { return new __type__( new __mmmt__( 2 / (r - l), 0, 0, (l + r) / (l - r), 0, 2 / (t - b), 0, (b + t) / (b - t), 0, 0, 1 / (n - f), n / (n - f), 0, 0, 0, 1 ), new __mmmt__( (r - l) / 2, 0, 0, (l + r) / 2, 0, (t - b) / 2, 0, (b + t) / 2, 0, 0, n - f, -n, 0, 0, 0, 1 ) ); } /// /// Creates a right-handed orthographic projection transform, where z-negative points into the scene. /// The resulting canonical view volume is [(-1, -1, -1), (+1, +1, +1)] and left-handed (handedness flip between view and NDC space). /// /// Minimum x-value of the view volume. /// Maximum x-value of the view volume. /// Minimum y-value of the view volume. /// Maximum y-value of the view volume. /// Minimum z-value of the view volume. /// Maximum z-value of the view volume. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ OrthoProjectionGL(__rtype__ l, __rtype__ r, __rtype__ b, __rtype__ t, __rtype__ n, __rtype__ f) { return new __type__( new __mmmt__( 2 / (r - l), 0, 0, (l + r) / (l - r), 0, 2 / (t - b), 0, (b + t) / (b - t), 0, 0, 2 / (n - f), (f + n) / (n - f), 0, 0, 0, 1 ), new __mmmt__( (r - l) / 2, 0, 0, (l + r) / 2, 0, (t - b) / 2, 0, (b + t) / 2, 0, 0, (n - f) / 2, -(f + n) / 2, 0, 0, 0, 1 ) ); } #endregion //# } #endregion #region Conversion Operators [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __type2__(__type__ r) => new __type2__(r); #endregion #region Operators /// /// Returns whether two transformations are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__type__ a, __type__ b) => a.Forward == b.Forward && a.Backward == b.Backward; /// /// Returns whether two transformations are different. /// public static bool operator !=(__type__ a, __type__ b) => a.Forward != b.Forward || a.Backward != b.Backward; /// /// The order of operation of __type__ multiplicaition is backward /// with respect to __mmmt__ multiplication in order to provide /// natural postfix notation. /// public static __type__ operator *(__type__ t0, __type__ t1) => new __type__(t1.Forward * t0.Forward, t0.Backward * t1.Backward); #endregion } public static partial class Trafo { #region Operations /// /// Returns the inverse of the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ Inverse(__type__ trafo) => trafo.Inverse; /// /// Returns the forward matrix the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mmmt__ Forward(__type__ trafo) => trafo.Forward; /// /// Returns the backward matrix the given . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mmmt__ Backward(__type__ trafo) => trafo.Backward; #endregion #region Transformation Extraction /// /// Approximates the uniform scale value of the given transformation (average length of basis vectors). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __rtype__ GetScale(this __type__ trafo) => trafo.Forward.GetScale__n__(); /// /// Extracts a scale vector from the given transformation by calculating the lengths of the basis vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ GetScaleVector(this __type__ trafo) => trafo.Forward.GetScaleVector__n__(); //# if (n == 3) { /// /// Extracts the inverse/backward translation component of the given transformation, which when given /// a view transformation represents the location of the camera in world space. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ GetViewPosition(this __type__ trafo) => trafo.Backward.C3.XYZ; /// /// Extracts the forward vector from the given view transformation. /// NOTE: A left-handed coordinates system transformation is expected, /// where the view-space z-axis points in forward direction. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ GetViewDirectionLH(this __type__ trafo) => trafo.Forward.GetViewDirectionLH(); /// /// Extracts the forward vector from the given view transformation. /// NOTE: A right-handed coordinates system transformation is expected, where /// the view-space z-axis points opposit the forward vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ GetViewDirectionRH(this __type__ trafo) => trafo.Forward.GetViewDirectionRH(); /// /// Extracts the translation component of the given transformation, which when given /// a model transformation represents the model origin in world position. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ GetModelOrigin(this __type__ trafo) => trafo.Forward.GetModelOrigin(); //# if (isDouble) { /// /// Builds a hull from the given view-projection transformation (left, right, bottom, top, near, far). /// The view volume is assumed to be [-1, -1, -1] [1, 1, 1]. /// The normals of the hull planes point to the outside and are normalized. /// A point inside the visual hull will has negative height to all planes. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Hull3d GetVisualHull(this __type__ viewProj) => viewProj.Forward.GetVisualHull(); //# } /// /// Builds an ortho-normal orientation transformation form the given transform. /// Scale and Translation will be removed and basis vectors will be ortho-normalized. /// NOTE: The x-axis is untouched and y/z are forced to a normal-angle. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __type__ GetOrthoNormalOrientation(this __type__ trafo) { var x = trafo.Forward.C0.XYZ.Normalized; var z = trafo.Forward.C2.XYZ; var y = z.Cross(x).Normalized; z = x.Cross(y).Normalized; return __type__.FromOrthoNormalBasis(x, y, z); } /// /// Decomposes a transformation into a scale, rotation and translation component. /// NOTE: The input is assumed to be a valid affine transformation. /// The rotation output is a vector with Euler-Angles [roll (X), pitch (Y), yaw (Z)] in radians of rotation order Z, Y, X. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Decompose(this __type__ trafo, out __vnt__ scale, out __vnt__ rotationInRadians, out __vnt__ translation) { translation = trafo.GetModelOrigin(); var rt = trafo.GetOrthoNormalOrientation(); if (rt.Forward.Determinant.IsTiny()) { rotationInRadians = __vnt__.Zero; } else { var rot = __rotnt__.FromFrame(rt.Forward.C0.XYZ, rt.Forward.C1.XYZ, rt.Forward.C2.XYZ); rotationInRadians = rot.GetEulerAngles(); } scale = trafo.GetScaleVector(); // if matrix is left-handed there must be some negative scale // since rotation remains the x-axis, the y-axis must be flipped if (trafo.Forward.Determinant < 0) scale.Y = -scale.Y; } //# } #endregion #region Transformations /// /// Transforms a by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vmt__ Transform(this __type__ r, __vmt__ v) => r.Forward.Transform(v); /// /// Transforms direction vector v (v.__fn__ is presumed 0.0) by a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ TransformDir(this __type__ r, __vnt__ v) => r.Forward.TransformDir(v); /// /// Transforms point p (p.__fn__ is presumed 1.0) by a . /// No projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ TransformPos(this __type__ r, __vnt__ p) => r.Forward.TransformPos(p); /// /// Transforms point p (p.__fn__ is presumed 1.0) by a . /// Projective transform is performed. Perspective Division is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ TransformPosProj(this __type__ r, __vnt__ p) => r.Forward.TransformPosProj(p); /// /// Transforms point p (p.__fn__ is presumed 1.0) by a . /// Projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vmt__ TransformPosProjFull(this __type__ r, __vnt__ p) => r.Forward.TransformPosProjFull(p); /// /// Transforms normal vector n (n.__fn__ is presumed 0.0) by a /// (i.e. by its transposed backward matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ TransformNormal(this __type__ r, __vnt__ n) => r.Backward.TransposedTransformDir(n); /// /// Transforms a by the inverse of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vmt__ InvTransform(this __type__ r, __vmt__ v) => r.Backward.Transform(v); /// /// Transforms direction vector v (v.__fn__ is presumed 0.0) by the inverse of a . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ InvTransformDir(this __type__ r, __vnt__ v) => r.Backward.TransformDir(v); /// /// Transforms point p (p.__fn__ is presumed 1.0) by the inverse of a . /// No projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ InvTransformPos(this __type__ r, __vnt__ p) => r.Backward.TransformPos(p); /// /// Transforms point p (p.__fn__ is presumed 1.0) by the inverse of a . /// Projective transform is performed. Perspective Division is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ InvTransformPosProj(this __type__ r, __vnt__ p) => r.Backward.TransformPosProj(p); /// /// Transforms point p (p.__fn__ is presumed 1.0) by the inverse of a . /// Projective transform is performed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vmt__ InvTransformPosProjFull(this __type__ r, __vnt__ p) => r.Backward.TransformPosProjFull(p); /// /// Transforms normal vector n (n.__fn__ is presumed 0.0) by the inverse of a /// (i.e. by its transposed forward matrix). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vnt__ InvTransformNormal(this __type__ r, __vnt__ n) => r.Forward.TransposedTransformDir(n); #endregion } public static partial class Fun { #region ApproximateEquals /// /// Returns if two transformations are equal with regard to a threshold . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __type__ a, __type__ b, __rtype__ epsilon) => a.Forward.ApproximateEquals(b.Forward, epsilon) && a.Backward.ApproximateEquals(b.Backward, epsilon); #endregion } #endregion //# } } } ================================================ FILE: src/Aardvark.Base/Math/Vectors/HashCode.cs ================================================ using static Aardvark.Base.HashCode; using static System.Math; namespace Aardvark.Base { public static class VectorHashCodeExtensions { /// /// Compute the first of four possible hashcodes for hashing in a 2-D /// unit grid. Add items with this function, retrieve with function /// HashCode.Get4. /// public static int Get1of4(V2d point) { var xi = (long)Floor(point.X); var yi = (long)Floor(point.Y); return Combine((int)(xi >> 1), (int)(yi >> 1)); } /// /// Compute all four possible hashcodes for hashing in a 2-D unit grid. /// Retrive all items with the four hashodes written into the supplied /// array. Items need to be added just with the first of the four /// hashcodes (also computed by function HashCodeGet1of4). /// public static void Get4(V2d point, int[] hca) { var xi = (long)Floor(point.X); var yi = (long)Floor(point.Y); int xh0 = (int)(xi >> 1), xh1 = xh0 - 1 + ((int)(xi & 1) << 1); int yh0 = (int)(yi >> 1), yh1 = yh0 - 1 + ((int)(yi & 1) << 1); hca[0] = Combine(xh0, yh0); hca[1] = Combine(xh1, yh0); hca[2] = Combine(xh0, yh1); hca[3] = Combine(xh1, yh1); } /// /// Compute the first of eight possible hashcodes for hashing in a 3-D /// unit grid. Add items with this function, retrieve with function /// HashCode.Get8. /// public static int Get1of8(V3d point) { var xi = (long)Floor(point.X); var yi = (long)Floor(point.Y); var zi = (long)Floor(point.Z); return Combine((int)(xi >> 1), (int)(yi >> 1), (int)(zi >> 1)); } /// /// Compute all eight possible hashcodes for hashing in a 3-D unit grid. /// Retrive all items with the eight hashodes written into the supplied /// array. Items need to be added just with the first of the eight /// hashcodes (also computed by function HashCodeGet1of2). /// public static void Get8(V3d point, int[] hca) { var xi = (long)Floor(point.X); var yi = (long)Floor(point.Y); var zi = (long)Floor(point.Z); int xh0 = (int)(xi >> 1), xh1 = xh0 - 1 + ((int)(xi & 1) << 1); int yh0 = (int)(yi >> 1), yh1 = yh0 - 1 + ((int)(yi & 1) << 1); int zh0 = (int)(zi >> 1), zh1 = zh0 - 1 + ((int)(zi & 1) << 1); hca[0] = Combine(xh0, yh0, zh0); hca[1] = Combine(xh1, yh0, zh0); hca[2] = Combine(xh0, yh1, zh0); hca[3] = Combine(xh1, yh1, zh0); hca[4] = Combine(xh0, yh0, zh1); hca[5] = Combine(xh1, yh0, zh1); hca[6] = Combine(xh0, yh1, zh1); hca[7] = Combine(xh1, yh1, zh1); } /// /// Compute the first of 16 possible hashcodes for hashing in a 4-D /// unit grid. Add items with this function, retrieve with function /// HashCode.Get16. /// public static int Get1of16(V4d point) { var xi = (long)Floor(point.X); var yi = (long)Floor(point.Y); var zi = (long)Floor(point.Z); var wi = (long)Floor(point.W); return Combine((int)(xi >> 1), (int)(yi >> 1), (int)(zi >> 1), (int)(wi >> 1)); } /// /// Compute all 16 possible hashcodes for hashing in a 4-D unit grid. /// Retrive all items with the 16 hashodes written into the supplied /// array. Items need to be added just with the first of the 16 /// hashcodes (also computed by function HashCodeGet1of16). /// public static void Get16(V4d point, int[] hca) { var xi = (long)Floor(point.X); var yi = (long)Floor(point.Y); var zi = (long)Floor(point.Z); var wi = (long)Floor(point.W); int xh0 = (int)(xi >> 1), xh1 = xh0 - 1 + ((int)(xi & 1) << 1); int yh0 = (int)(yi >> 1), yh1 = yh0 - 1 + ((int)(yi & 1) << 1); int zh0 = (int)(zi >> 1), zh1 = zh0 - 1 + ((int)(zi & 1) << 1); int dh0 = (int)(wi >> 1), dh1 = dh0 - 1 + ((int)(wi & 1) << 1); hca[0] = Combine(xh0, yh0, zh0, dh0); hca[1] = Combine(xh1, yh0, zh0, dh0); hca[2] = Combine(xh0, yh1, zh0, dh0); hca[3] = Combine(xh1, yh1, zh0, dh0); hca[4] = Combine(xh0, yh0, zh1, dh0); hca[5] = Combine(xh1, yh0, zh1, dh0); hca[6] = Combine(xh0, yh1, zh1, dh0); hca[7] = Combine(xh1, yh1, zh1, dh0); hca[8] = Combine(xh0, yh0, zh0, dh1); hca[9] = Combine(xh1, yh0, zh0, dh1); hca[10] = Combine(xh0, yh1, zh0, dh1); hca[11] = Combine(xh1, yh1, zh0, dh1); hca[12] = Combine(xh0, yh0, zh1, dh1); hca[13] = Combine(xh1, yh0, zh1, dh1); hca[14] = Combine(xh0, yh1, zh1, dh1); hca[15] = Combine(xh1, yh1, zh1, dh1); } } } ================================================ FILE: src/Aardvark.Base/Math/Vectors/V3fCoder.cs ================================================ // The decode table would grow to large for 64bit codes, and should not // be used in this case. However it is very likely that the 64 bit version // does not work as of yet. // The actual savings by using a table are small enough, that it is // normally not worth the associated initialization cost. // #define V3FCODER_DECODE_TABLE // The following option is mostly for debugging: // #define V3FCODER_NO_WARP using System; namespace Aardvark.Base { /// /// A V3fCoder can be used to encode direction vectors in unsigned /// integers. /// public class V3fCoder { // private uint m_raster; private readonly uint m_r2Sub1; private readonly double m_doubleRaster; private readonly double m_invDoubleRaster; private readonly uint m_edgeBasis; private readonly uint m_cornerBasis; #if V3FCODER_DECODE_TABLE private double[] m_unWarpTable; #endif private readonly double m_dRp05; #region Constructor /// /// Create a V3fCoder with supplied raster. The raster defines the /// number of discretized directons along an octant of one of the /// major circumferences of the sphere. Thus on each of the 3 major /// circumferences of the sphere 8 * raster evenly spaced different /// directions are encoded. /// /// public V3fCoder(uint raster) { // m_raster = raster; m_r2Sub1 = 2 * raster - 1; m_doubleRaster = (double)raster; m_invDoubleRaster = 1.0/m_doubleRaster; m_edgeBasis = 6 * m_r2Sub1 * m_r2Sub1; m_cornerBasis = m_edgeBasis + 12 * m_r2Sub1; m_dRp05 = m_doubleRaster + 0.5; #if V3FCODER_DECODE_TABLE // build a table for slightly faster decoding m_unWarpTable = new double[m_r2Sub1]; for (int i = 0; i < m_r2Sub1; i++) { double u = (i+1) * m_invDoubleRaster - 1.0; #if (!V3FCODER_NO_WARP) u = SphericalOfBox(u); #endif m_unWarpTable[i] = u; } #endif } #endregion #region Static Creator public static V3fCoder ForBits(int bits) { if (bits < 5) return null; if (bits > 32) bits = 32; return s_coderForBits[bits]; } #endregion #region Constants static readonly uint[] s_rasterForBitsTable = { // bits raster, used bits /* 0 */ 0, /* 1 */ 0, /* 2 */ 0, /* 3 */ 0, /* 4 */ 0, /* 5 */ 1, // 4.7004397181 /* 6 */ 1, // 4.7004397181 /* 7 */ 2, // 6.6147098441 /* 8 */ 3, // 7.7681843248 /* 9 */ 4, // 8.5924570373 /* 10 */ 6, // 9.7582232147 /* 11 */ 9, // 10.9262959948 /* 12 */ 13, // 11.9865531498 /* 13 */ 18, // 12.9251835194 /* 14 */ 26, // 13.9860197731 /* 15 */ 36, // 14.9249052665 /* 16 */ 52, // 15.9858863980 /* 17 */ 73, // 16.9646341787 /* 18 */ 104, // 17.9858530524 /* 19 */ 147, // 18.9843127540 /* 20 */ 209, // 19.9996835172 /* 21 */ 295, // 20.9941061707 /* 22 */ 418, // 21.9996814530 /* 23 */ 591, // 22.9989914853 /* 24 */ 836, // 23.9996809369 /* 25 */ 1182, // 24.9989912271 /* 26 */ 1672, // 25.9996808079 /* 27 */ 2364, // 26.9989911626 /* 28 */ 3344, // 27.9996807756 /* 29 */ 4729, // 28.9996013590 /* 30 */ 6688, // 29.9996807676 /* 31 */ 9459, // 30.9999064129 /* 32 */ 13377, // 31.9998964715 /* For the following codes to work, the algorithm has to be changed to 64-bit ints. */ /* 33 */ 18918, // 32.9999064119 /* 34 */ 26754, // 33.9998964710 /* 35 */ 37837, // 34.9999826710 /* 36 */ 53509, // 35.9999503948 /* 37 */ 75674, // 36.9999826710 /* 38 */ 107019, // 37.9999773564 /* 39 */ 151348, // 38.9999826710 /* 40 */ 214039, // 39.9999908371 /* 41 */ 302697, // 40.9999922033 /* 42 */ 428079, // 41.9999975774 /* 43 */ 605395, // 42.9999969694 /* 44 */ 856158, // 43.9999975774 /* 45 */ 1210791, // 44.9999993524 /* 46 */ 1712317, // 45.9999992625 /* 47 */ 2421582, // 46.9999993524 /* 48 */ 3424634, // 47.9999992625 /* 49 */ 4843165, // 48.9999999482 /* 50 */ 6849269, // 49.9999996837 /* 51 */ 9686330, // 50.9999999482 /* 52 */ 13698539, // 51.9999998944 /* 53 */ 19372660, // 52.9999999482 /* 54 */ 27397079, // 53.9999999997 /* 55 */ 38745320, // 54.9999999482 /* 56 */ 54794158, // 55.9999999997 /* 57 */ 77490641, // 56.9999999854 /* 58 */ 109588316, // 57.9999999997 /* 59 */ 154981282, // 58.9999999854 /* 60 */ 219176632, // 59.9999999997 /* 61 */ 309962565, // 60.9999999948 /* 62 */ 438353264, // 61.9999999997 /* 63 */ 619925131, // 62.9999999994 /* 64 */ 876706528, // 63.9999999997 }; const double c_piOver4 = Constant.Pi * 0.25; const double c_4OverPi = 4.0 / Constant.Pi; private static readonly V3fCoder[] s_coderForBits = new V3fCoder[33]; static V3fCoder() { for (int bits = 5; bits < 33; bits++) s_coderForBits[bits] = new V3fCoder(RasterForBits(bits)); } #endregion #region Encoding Helpers public static double SphericalOfBox(double x) { return System.Math.Tan(x * c_piOver4); } public static double BoxOfSpherical(double x) { return System.Math.Atan(x) * c_4OverPi; } #if (!V3FCODER_DECODE_TABLE) #if (V3FCODER_NO_WARP) private double Unwarp(uint u) { return (u+1) * m_invDoubleRaster - 1.0; } #else private double Unwarp(uint u) { return System.Math.Tan(((u + 1) * m_invDoubleRaster - 1.0) * c_piOver4); } #endif #else private double Unwarp(uint u) { return m_unWarpTable[u]; } #endif /* The directions are coded based on the faces, edges, and corners of a cube of size 2, centered at the origin. Within an uint the first codes are for the faces, then the edges and finally the corners. The coding within these three groups is performed according to the following table: faces: 0: -1 u v 1: v -1 u 2: u v -1 3: +1 u v 4: v +1 u 5: u v +1 edges: 0: u -1 -1 faces 1,-,u 2,u,- corners 0, 1 1: u +1 -1 faces 4,-,u 2,u,+ corners 2, 3 2: u -1 +1 faces 1,+,u 5,u,- corners 4, 5 3: u +1 +1 faces 4,+,u 5,u,+ corners 6, 7 4: -1 u -1 faces 2,-,u 0,u,- corners 0, 2 5: +1 u -1 faces 2,+,u 3,u,- corners 1, 3 6: -1 u +1 faces 5,-,u 0,u,+ corners 4, 6 7: +1 u +1 faces 5,+,u 3,u,+ corners 5, 7 8: -1 -1 u faces 0,-,u 1,u,- corners 0, 4 9: +1 -1 u faces 3,-,u 1,u,+ corners 1, 5 10: -1 +1 u faces 0,+,u 4,u,- corners 2, 6 11: +1 +1 u faces 3,+,u 4,u,+ corners 3, 7 corners: 0: -1 -1 -1 edges 0, 4, 8 faces 0, 1, 2 1: +1 -1 -1 edges 0, 5, 9 2: -1 +1 -1 edges 1, 4, 10 3: +1 +1 -1 edges 1, 5, 11 4: -1 -1 +1 edges 2, 6, 8 5: +1 -1 +1 edges 2, 7, 9 6: -1 +1 +1 edges 3, 6, 10 7: +1 +1 +1 edges 3, 7, 11 */ uint EncodeCornerIndex(uint corner) { return m_cornerBasis + corner; } static readonly uint[] s_edgeNegCorner = new uint[] { 0, 2, 4, 6, 0, 1, 4, 5, 0, 1, 2, 3 }; static readonly uint[] s_edgePosCorner = new uint[] { 1, 3, 5, 7, 2, 3, 6, 7, 4, 5, 6, 7 }; uint EncodeEdgeIndex(uint edge, int iu) { if (iu < 0) return m_cornerBasis + s_edgeNegCorner[edge]; if (iu >= m_r2Sub1) return m_cornerBasis + s_edgePosCorner[edge]; return m_edgeBasis + (uint)(edge * m_r2Sub1 + iu); } uint RawEncodeEdgeIndex(uint edge, int iu) { return m_edgeBasis + (uint)(edge * m_r2Sub1 + iu); } static readonly uint[] s_faceNegUedge = new uint[] { 8, 0, 4, 9, 1, 6 }; static readonly uint[] s_facePosUedge = new uint[] { 10, 2, 5, 11, 3, 7 }; static readonly uint[] s_faceNegVedge = new uint[] { 4, 8, 0, 5, 10, 2 }; static readonly uint[] s_facePosVedge = new uint[] { 6, 9, 1, 7, 11, 3 }; uint EncodeFaceIndex(uint face, int iu, int iv) { if (iu < 0) return EncodeEdgeIndex(s_faceNegUedge[face], iv); if (iu >= m_r2Sub1) return EncodeEdgeIndex(s_facePosUedge[face], iv); if (iv < 0) return EncodeEdgeIndex(s_faceNegVedge[face], iu); if (iv >= m_r2Sub1) return EncodeEdgeIndex(s_facePosVedge[face], iu); return (uint)((face * m_r2Sub1 + iv ) * m_r2Sub1 + iu); } uint RawEncodeFaceIndex(uint face, int iu, int iv) { return (uint)((face * m_r2Sub1 + iv) * m_r2Sub1 + iu); } #endregion #region Encoding /// /// Encode the given direction in an unsigned integer. The direction /// does not need to be normalized! /// /// The direction to encode. /// public uint Encode(V3f dir) { int mAxis; double aX = System.Math.Abs(dir.X); double aY = System.Math.Abs(dir.Y); double aZ = System.Math.Abs(dir.Z); double u, v; if (aX > aY) { if (aX > aZ) { double invSize = 1.0/aX; mAxis = 0; u = dir.Y * invSize; v = dir.Z * invSize; } else { double invSize = 1.0/aZ; mAxis = 2; u = dir.X * invSize; v = dir.Y * invSize; } } else { if (aY > aZ) { double invSize = 1.0/aY; mAxis = 1; u = dir.Z * invSize; v = dir.X * invSize; } else { double invSize = 1.0/aZ; mAxis = 2; u = dir.X * invSize; v = dir.Y * invSize; } } #if (!V3FCODER_NO_WARP) u = BoxOfSpherical(u); v = BoxOfSpherical(v); #endif uint face = (uint)(mAxis + (dir[mAxis] < 0 ? 0 : 3)); return EncodeFaceIndex(face, (int)(u * m_doubleRaster + m_dRp05) - 1, (int)(v * m_doubleRaster + m_dRp05) - 1); } #endregion #region Decoding Helpers static readonly V3f[] s_vecToCornerTableNonNormalized = { new V3f( -1.0f, -1.0f, -1.0f ), new V3f( +1.0f, -1.0f, -1.0f ), new V3f( -1.0f, +1.0f, -1.0f ), new V3f( +1.0f, +1.0f, -1.0f ), new V3f( -1.0f, -1.0f, +1.0f ), new V3f( +1.0f, -1.0f, +1.0f ), new V3f( -1.0f, +1.0f, +1.0f ), new V3f( +1.0f, +1.0f, +1.0f ) }; const float c_oneOverSqrt3 = 0.57735026918962584f; static readonly V3f[] s_vecToCornerTable = { new V3f( -c_oneOverSqrt3, -c_oneOverSqrt3, -c_oneOverSqrt3 ), new V3f( +c_oneOverSqrt3, -c_oneOverSqrt3, -c_oneOverSqrt3 ), new V3f( -c_oneOverSqrt3, +c_oneOverSqrt3, -c_oneOverSqrt3 ), new V3f( +c_oneOverSqrt3, +c_oneOverSqrt3, -c_oneOverSqrt3 ), new V3f( -c_oneOverSqrt3, -c_oneOverSqrt3, +c_oneOverSqrt3 ), new V3f( +c_oneOverSqrt3, -c_oneOverSqrt3, +c_oneOverSqrt3 ), new V3f( -c_oneOverSqrt3, +c_oneOverSqrt3, +c_oneOverSqrt3 ), new V3f( +c_oneOverSqrt3, +c_oneOverSqrt3, +c_oneOverSqrt3 ) }; static readonly double[] s_uSignOfEdge = { -1, +1, -1, +1 }; static readonly double[] s_vSignOfEdge = { -1, -1, +1, +1 }; static readonly int[] s_uAxis = { 1, 0, 0 }; static readonly int[] s_vAxis = { 2, 2, 1 }; #endregion #region Decoding /// /// Decode the unsigned integer direction code. /// /// /// A normalized direction. public V3f Decode(uint code) { if (code < m_edgeBasis) // face number is code { double u = Unwarp(code % m_r2Sub1); code /= m_r2Sub1; double v = Unwarp(code % m_r2Sub1); code /= m_r2Sub1; double scale = 1.0 / System.Math.Sqrt(1.0 + u * u + v * v); switch (code) { case 0: return new V3f(-scale, u * scale, v * scale); case 1: return new V3f(v * scale, -scale, u * scale); case 2: return new V3f(u * scale, v * scale, -scale); case 3: return new V3f(+scale, u * scale, v * scale); case 4: return new V3f(v * scale, +scale, u * scale); case 5: return new V3f(u * scale, v * scale, +scale); default: throw new ArgumentException(); } } else if (code < m_cornerBasis) { code -= m_edgeBasis; double u = Unwarp(code % m_r2Sub1); code /= m_r2Sub1; // edge number in code double scale = 1.0 / System.Math.Sqrt(2.0 + u * u); uint edge = code & 3; code >>= 2; V3f dir = new V3f(0, 0, 0); // init to make compiler happy dir[(int)code] = (float)(u * scale); dir[s_uAxis[code]] = (float)(s_uSignOfEdge[edge] * scale); dir[s_vAxis[code]] = (float)(s_vSignOfEdge[edge] * scale); return dir; #if NEVERMORE float edgeOne = (code & 1) == 0 ? -scale : scale; float edgeTwo = (code & 2) == 0 ? -scale : scale; switch (code >> 2) { case 0: return new V3f((float)(u * scale), edgeOne, edgeTwo); case 1: return new V3f(edgeOne, (float)(u * scale), edgeTwo); case 2: return new V3f(edgeOne, edgeTwo, (float)(u * scale)); default: throw new ArgumentException(); } #endif } else return s_vecToCornerTable[code - m_cornerBasis]; } public V3f DecodeOnCube(uint code, bool warped) { if (code < m_edgeBasis) // face number is code { double u = warped ? Unwarp(code % m_r2Sub1) : (code % m_r2Sub1 + 1) * m_invDoubleRaster - 1.0; code /= m_r2Sub1; double v = warped ? Unwarp(code % m_r2Sub1) : (code % m_r2Sub1 + 1) * m_invDoubleRaster - 1.0; code /= m_r2Sub1; switch (code) { case 0: return new V3f(-1, u, v); case 1: return new V3f(v, -1, u); case 2: return new V3f(u, v, -1); case 3: return new V3f(+1, u, v); case 4: return new V3f(v, +1, u); case 5: return new V3f(u, v, +1); default: throw new ArgumentException(); } } else if (code < m_cornerBasis) { code -= m_edgeBasis; double u = warped ? Unwarp(code % m_r2Sub1) : (code % m_r2Sub1+1) * m_invDoubleRaster - 1.0; code /= m_r2Sub1; // edge number in code uint edge = code & 3; code >>= 2; V3f dir = new V3f(0, 0, 0); // init to make compiler happy dir[(int)code] = (float)u; dir[s_uAxis[code]] = (float)(s_uSignOfEdge[edge]); dir[s_vAxis[code]] = (float)(s_vSignOfEdge[edge]); return dir; #if NEVERMORE float edgeOne = (code & 1) == 0 ? -1.0f : 1.0f; float edgeTwo = (code & 2) == 0 ? -1.0f : 1.0f; switch (code >> 2) { case 0: return new V3f((float)u, edgeOne, edgeTwo); case 1: return new V3f(edgeOne, (float)u, edgeTwo); case 2: return new V3f(edgeOne, edgeTwo, (float)u); default: throw new ArgumentException(); } #endif } else return s_vecToCornerTableNonNormalized[code - m_cornerBasis]; } #endregion #region Neighbours Helpers static readonly uint[] s_edgeFace0 = new uint[] { 1, 4, 1, 4, 2, 2, 5, 5, 0, 3, 0, 3 }; static readonly int[] s_edgeFace0u = new int[] { 0, 0, 1, 1, 0, 1, 0, 1, 0 ,0, 1, 1 }; static readonly uint[] s_edgeFace1 = new uint[] { 2, 2, 5, 5, 0, 3, 0, 3, 1, 1, 4, 4 }; static readonly int[] s_edgeFace1v = new int[] { 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1 }; #endregion #region Neigbours /// /// Fills the array neighbourCodes with the codes of all neigbouring /// cells of the code discretization. /// /// The code for which to calculate all /// neighbours. /// The array that is filled with /// the neighbourcodes /// The number of neigbouring cells (maximal 8). public uint NeighbourCodes(uint code, uint[] neighbourCodes) { if (code < m_edgeBasis) // face number is code { int iu = (int)(code % m_r2Sub1); code /= m_r2Sub1; int iv = (int)(code % m_r2Sub1); code /= m_r2Sub1; if (iu > 0 && iu < m_r2Sub1 - 1 && iv > 0 && iv < m_r2Sub1 - 1) { neighbourCodes[0] = RawEncodeFaceIndex(code, iu - 1, iv - 1); neighbourCodes[1] = RawEncodeFaceIndex(code, iu - 1, iv); neighbourCodes[2] = RawEncodeFaceIndex(code, iu - 1, iv + 1); neighbourCodes[3] = RawEncodeFaceIndex(code, iu, iv - 1); neighbourCodes[4] = RawEncodeFaceIndex(code, iu, iv + 1); neighbourCodes[5] = RawEncodeFaceIndex(code, iu + 1, iv - 1); neighbourCodes[6] = RawEncodeFaceIndex(code, iu + 1, iv); neighbourCodes[7] = RawEncodeFaceIndex(code, iu + 1, iv + 1); } else { neighbourCodes[0] = EncodeFaceIndex(code, iu - 1, iv - 1); neighbourCodes[1] = EncodeFaceIndex(code, iu - 1, iv); neighbourCodes[2] = EncodeFaceIndex(code, iu - 1, iv + 1); neighbourCodes[3] = EncodeFaceIndex(code, iu, iv - 1); neighbourCodes[4] = EncodeFaceIndex(code, iu, iv + 1); neighbourCodes[5] = EncodeFaceIndex(code, iu + 1, iv - 1); neighbourCodes[6] = EncodeFaceIndex(code, iu + 1, iv); neighbourCodes[7] = EncodeFaceIndex(code, iu + 1, iv + 1); } return 8; } if (code < m_cornerBasis) { int nc = 0; code -= m_edgeBasis; int iu = (int)(code % m_r2Sub1); code /= m_r2Sub1; // edge number in code neighbourCodes[nc++] = EncodeEdgeIndex(code, iu - 1); neighbourCodes[nc++] = EncodeEdgeIndex(code, iu + 1); int m = ((int)m_r2Sub1 - 1); for (int i = -1; i < 2; i++) { neighbourCodes[nc++] = EncodeFaceIndex( s_edgeFace0[code], s_edgeFace0u[code] * m, iu + i); neighbourCodes[nc++] = EncodeFaceIndex( s_edgeFace1[code], iu + i, s_edgeFace1v[code] * m); } return 8; } else { code -= m_cornerBasis; int m = (int)m_r2Sub1 - 1; switch (code) { case 0: neighbourCodes[0] = RawEncodeFaceIndex(0, 0, 0); neighbourCodes[1] = RawEncodeFaceIndex(1, 0, 0); neighbourCodes[2] = RawEncodeFaceIndex(2, 0, 0); neighbourCodes[3] = RawEncodeEdgeIndex(0, 0); neighbourCodes[4] = RawEncodeEdgeIndex(4, 0); neighbourCodes[5] = RawEncodeEdgeIndex(8, 0); break; case 1: neighbourCodes[0] = RawEncodeEdgeIndex(0, m); neighbourCodes[1] = RawEncodeFaceIndex(1, 0, m); neighbourCodes[2] = RawEncodeFaceIndex(2, m, 0); neighbourCodes[3] = RawEncodeFaceIndex(3, 0, 0); neighbourCodes[4] = RawEncodeEdgeIndex(5, 0); neighbourCodes[5] = RawEncodeEdgeIndex(9, 0); break; case 2: neighbourCodes[0] = RawEncodeFaceIndex(0, m, 0); neighbourCodes[1] = RawEncodeEdgeIndex(4, m); neighbourCodes[2] = RawEncodeFaceIndex(2, 0, m); neighbourCodes[3] = RawEncodeEdgeIndex(1, 0); neighbourCodes[4] = RawEncodeFaceIndex(4, 0, 0); neighbourCodes[5] = RawEncodeEdgeIndex(10, 0); break; case 3: neighbourCodes[0] = RawEncodeEdgeIndex(1, m); neighbourCodes[1] = RawEncodeEdgeIndex(5, m); neighbourCodes[2] = RawEncodeFaceIndex(2, m, m); neighbourCodes[3] = RawEncodeFaceIndex(3, m, 0); neighbourCodes[4] = RawEncodeFaceIndex(4, 0, m); neighbourCodes[5] = RawEncodeEdgeIndex(11, 0); break; case 4: neighbourCodes[0] = RawEncodeFaceIndex(0, 0, m); neighbourCodes[1] = RawEncodeFaceIndex(1, m, 0); neighbourCodes[2] = RawEncodeEdgeIndex(8, m); neighbourCodes[3] = RawEncodeEdgeIndex(2, 0); neighbourCodes[4] = RawEncodeEdgeIndex(6, 0); neighbourCodes[5] = RawEncodeFaceIndex(5, 0, 0); break; case 5: neighbourCodes[0] = RawEncodeEdgeIndex(2, m); neighbourCodes[1] = RawEncodeFaceIndex(1, m, m); neighbourCodes[2] = RawEncodeEdgeIndex(9, m); neighbourCodes[3] = RawEncodeFaceIndex(3, 0, m); neighbourCodes[4] = RawEncodeEdgeIndex(7, 0); neighbourCodes[5] = RawEncodeFaceIndex(5, m, 0); break; case 6: neighbourCodes[0] = RawEncodeFaceIndex(0, m, m); neighbourCodes[1] = RawEncodeEdgeIndex(6, m); neighbourCodes[2] = RawEncodeEdgeIndex(10, m); neighbourCodes[3] = RawEncodeEdgeIndex(3, 0); neighbourCodes[4] = RawEncodeFaceIndex(4, m, 0); neighbourCodes[5] = RawEncodeFaceIndex(5, 0, m); break; case 7: neighbourCodes[0] = RawEncodeEdgeIndex(3, m); neighbourCodes[1] = RawEncodeEdgeIndex(7, m); neighbourCodes[2] = RawEncodeEdgeIndex(11, m); neighbourCodes[3] = RawEncodeFaceIndex(3, m, m); neighbourCodes[4] = RawEncodeFaceIndex(4, m, m); neighbourCodes[5] = RawEncodeFaceIndex(5, m, m); break; } return 6; } } #endregion #region Info Methods /// /// Calculate the maximal raster for a given number of bits. /// Currently maximal 32 bits are supported. /// /// The number of bits. /// The maximal possible raster value. public static uint RasterForBits(int bits) { if (bits < 5) return 0; if (bits > 32) bits = 32; return s_rasterForBitsTable[bits]; } /// /// Calculate the number of different codes that are available. /// /// public uint Count { get { return m_cornerBasis + 8; } } /// /// Calculate all directions that are exactly encoded. /// /// An array of directions. public V3f[] GenerateTable() { uint dirCount = Count; V3f[] directionTable = new V3f[dirCount]; for (uint dc = 0; dc < dirCount; dc++) { directionTable[dc] = Decode(dc); } return directionTable; } #endregion #region Code Generator /// /// Code generation. /// public void WriteCode(uint code) { if (code < m_edgeBasis) // face number is code { uint iu = code % m_r2Sub1; code /= m_r2Sub1; uint iv = code % m_r2Sub1; code /= m_r2Sub1; string u = iu == 0 ? "0" : (iu == m_r2Sub1 - 1 ? "m" : "u"); string v = iv == 0 ? "0" : (iv == m_r2Sub1 - 1 ? "m" : "v"); Console.WriteLine("EncodeFaceIndex({0}, {1}, {2});", code, u, v); } else if (code < m_cornerBasis) { code -= m_edgeBasis; uint iu = code % m_r2Sub1; code /= m_r2Sub1; // edge number in code string u = iu == 0 ? "0" : (iu == m_r2Sub1 - 1 ? "m" : "u"); Console.WriteLine("EncodeEdgeIndex({0}, {1});", code, u); } else Console.WriteLine("EncodeCornerIndex({0});", code - m_cornerBasis); } /// /// Code generation. /// public void WriteCornerNeighbours(uint corner) { V3f v = s_vecToCornerTableNonNormalized[corner]; string f = " neighbourCodes[{0}] = "; float s = (float)m_invDoubleRaster; Console.Write(f, 0); WriteCode(Encode(v + s * new V3f(-1, 0, 0))); Console.Write(f, 1); WriteCode(Encode(v + s * new V3f(0, -1, 0))); Console.Write(f, 2); WriteCode(Encode(v + s * new V3f(0, 0, -1))); Console.Write(f, 3); WriteCode(Encode(v + s * new V3f(1, 0, 0))); Console.Write(f, 4); WriteCode(Encode(v + s * new V3f(0, 1, 0))); Console.Write(f, 5); WriteCode(Encode(v + s * new V3f(0, 0, 1))); } /// /// Code generation. /// public void WriteAllCornerNeighbours() { for (uint c = 0; c < 8; c++) { Console.WriteLine("case {0}:", c); WriteCornerNeighbours(c); Console.WriteLine(" break;"); } } #endregion } } ================================================ FILE: src/Aardvark.Base/Math/Vectors/VectorArrayExtensions.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace Aardvark.Base { #region ArrayVectorExtensions public static class ArrayVectorExtensions // this *must not* be named 'ArrayExtensions' { public static float Lerp(this float[] array, WeightedIndex[] wia) { var result = default(float); foreach (var wi in wia) result += (float)wi.Weight * array[wi.Index]; return result; } public static double Lerp(this double[] array, WeightedIndex[] wia) { var result = default(double); foreach (var wi in wia) result += wi.Weight * array[wi.Index]; return result; } public static C3b Lerp(this C3b[] array, WeightedIndex[] wia) { var result = default(V3d); foreach (var wi in wia) result += wi.Weight * (V3d)array[wi.Index]; return (C3b)result; } public static C3us Lerp(this C3us[] array, WeightedIndex[] wia) { var result = default(V3d); foreach (var wi in wia) result += wi.Weight * (V3d)array[wi.Index]; return (C3us)result; } public static C3ui Lerp(this C3ui[] array, WeightedIndex[] wia) { var result = default(V3d); foreach (var wi in wia) result += wi.Weight * (V3d)array[wi.Index]; return (C3ui)result; } public static C3f Lerp(this C3f[] array, WeightedIndex[] wia) { var result = default(V3d); foreach (var wi in wia) result += wi.Weight * (V3d)array[wi.Index]; return (C3f)result; } public static C3d Lerp(this C3d[] array, WeightedIndex[] wia) { var result = default(V3d); foreach (var wi in wia) result += wi.Weight * (V3d)array[wi.Index]; return (C3d)result; } public static C4b Lerp(this C4b[] array, WeightedIndex[] wia) { var result = default(V4d); foreach (var wi in wia) result += wi.Weight * (V4d)array[wi.Index]; return (C4b)result; } public static C4us Lerp(this C4us[] array, WeightedIndex[] wia) { var result = default(V4d); foreach (var wi in wia) result += wi.Weight * (V4d)array[wi.Index]; return (C4us)result; } public static C4ui Lerp(this C4ui[] array, WeightedIndex[] wia) { var result = default(V4d); foreach (var wi in wia) result += wi.Weight * (V4d)array[wi.Index]; return (C4ui)result; } public static C4f Lerp(this C4f[] array, WeightedIndex[] wia) { var result = default(V4d); foreach (var wi in wia) result += wi.Weight * (V4d)array[wi.Index]; return (C4f)result; } public static C4d Lerp(this C4d[] array, WeightedIndex[] wia) { var result = default(V4d); foreach (var wi in wia) result += wi.Weight * (V4d)array[wi.Index]; return (C4d)result; } public static V2f Lerp(this V2f[] array, WeightedIndex[] wia) { var result = default(V2d); foreach (var wi in wia) result += wi.Weight * (V2d)array[wi.Index]; return (V2f)result; } public static V2d Lerp(this V2d[] array, WeightedIndex[] wia) { var result = default(V2d); foreach (var wi in wia) result += wi.Weight * array[wi.Index]; return result; } public static V3f Lerp(this V3f[] array, WeightedIndex[] wia) { var result = default(V3d); foreach (var wi in wia) result += wi.Weight * (V3d)array[wi.Index]; return (V3f)result; } public static V3d Lerp(this V3d[] array, WeightedIndex[] wia) { var result = default(V3d); foreach (var wi in wia) result += wi.Weight * array[wi.Index]; return result; } public static V4f Lerp(this V4f[] array, WeightedIndex[] wia) { var result = default(V4d); foreach (var wi in wia) result += wi.Weight * (V4d)array[wi.Index]; return (V4f)result; } public static V4d Lerp(this V4d[] array, WeightedIndex[] wia) { var result = default(V4d); foreach (var wi in wia) result += wi.Weight * array[wi.Index]; return result; } static readonly Dictionary, Array>> s_backwardIndexedLerpMap = new Dictionary, Array>> { { typeof(float[]), (a, bm, im) => (Array)BackwardIndexedCopy((float[])a, bm, im, (t, u, v) => Fun.Lerp((float) t, u, v)) }, { typeof(double[]), (a, bm, im) => (Array)BackwardIndexedCopy((double[])a, bm, im, Fun.Lerp) }, { typeof(C3b[]), (a, bm, im) => (Array)BackwardIndexedCopy((C3b[])a, bm, im, Fun.Lerp) }, { typeof(C3us[]), (a, bm, im) => (Array)BackwardIndexedCopy((C3us[])a, bm, im, Fun.Lerp) }, { typeof(C3ui[]), (a, bm, im) => (Array)BackwardIndexedCopy((C3ui[])a, bm, im, Fun.Lerp) }, { typeof(C3f[]), (a, bm, im) => (Array)BackwardIndexedCopy((C3f[])a, bm, im, (t, u, v) => Fun.Lerp((float) t, u, v)) }, { typeof(C3d[]), (a, bm, im) => (Array)BackwardIndexedCopy((C3d[])a, bm, im, Fun.Lerp) }, { typeof(C4b[]), (a, bm, im) => (Array)BackwardIndexedCopy((C4b[])a, bm, im, Fun.Lerp) }, { typeof(C4us[]), (a, bm, im) => (Array)BackwardIndexedCopy((C4us[])a, bm, im, Fun.Lerp) }, { typeof(C4ui[]), (a, bm, im) => (Array)BackwardIndexedCopy((C4ui[])a, bm, im, Fun.Lerp) }, { typeof(C4f[]), (a, bm, im) => (Array)BackwardIndexedCopy((C4f[])a, bm, im, (t, u, v) => Fun.Lerp((float) t, u, v)) }, { typeof(C4d[]), (a, bm, im) => (Array)BackwardIndexedCopy((C4d[])a, bm, im, Fun.Lerp) }, { typeof(V2f[]), (a, bm, im) => (Array)BackwardIndexedCopy((V2f[])a, bm, im, (t, u, v) => Fun.Lerp((float) t, u, v)) }, { typeof(V2d[]), (a, bm, im) => (Array)BackwardIndexedCopy((V2d[])a, bm, im, Fun.Lerp) }, { typeof(V3f[]), (a, bm, im) => (Array)BackwardIndexedCopy((V3f[])a, bm, im, (t, u, v) => Fun.Lerp((float) t, u, v)) }, { typeof(V3d[]), (a, bm, im) => (Array)BackwardIndexedCopy((V3d[])a, bm, im, Fun.Lerp) }, { typeof(V4f[]), (a, bm, im) => (Array)BackwardIndexedCopy((V4f[])a, bm, im, (t, u, v) => Fun.Lerp((float) t, u, v)) }, { typeof(V4d[]), (a, bm, im) => (Array)BackwardIndexedCopy((V4d[])a, bm, im, Fun.Lerp) }, }; public static Array BackwardIndexedLerpCopy( this Array array, int[] backwardMap, Dictionary interpolationMap) { var type = array.GetType(); return s_backwardIndexedLerpMap[type]( array, backwardMap, interpolationMap); } static readonly Dictionary, Array>> s_backwardIndexedNormalMap = new Dictionary, Array>> { { typeof(V3f[]), (a, bm, im) => (Array)BackwardIndexedCopy( (V3f[])a, bm, im, (t, v0, v1) => Fun.Lerp((float) t, v0, v1).Normalized) }, { typeof(V3d[]), (a, bm, im) => (Array)BackwardIndexedCopy( (V3d[])a, bm, im, (t, v0, v1) => Fun.Lerp((float) t, v0, v1).Normalized) }, }; public static Array BackwardIndexedNormalCopy( this Array array, int[] backwardMap, Dictionary interpolationMap) { var type = array.GetType(); return s_backwardIndexedNormalMap[type]( array, backwardMap, interpolationMap); } public static T[] BackwardIndexedCopy( this T[] array, int[] backwardMap, Dictionary interpolationMap, Func interpolator) { int length = backwardMap.Length; T[] result = new T[length]; for (int i = 0; i < length; i++) { int si = backwardMap[i]; if (si < 0) { var sp = interpolationMap[i]; result[i] = interpolator(sp.T, array[sp.Line.I0], array[sp.Line.I1]); } else result[i] = array[si]; } return result; } public static void CombineTo( this T[] source, IEnumerable weightedIndexArrays, Func combine, T[] target, int offset, int length) { length += offset; foreach (var wia in weightedIndexArrays) { target[offset++] = combine(source, wia); if (offset == length) break; } } private static readonly Dictionary, Array, int, int>> s_lerpToOffsetMap = new Dictionary, Array, int, int>> { { typeof(float[]), (s, w, t, o, l) => CombineTo((float[])s, w, Lerp, (float[])t, o, l) }, { typeof(double[]), (s, w, t, o, l) => CombineTo((double[])s, w, Lerp, (double[])t, o, l) }, { typeof(C3b[]), (s, w, t, o, l) => CombineTo((C3b[])s, w, Lerp, (C3b[])t, o, l) }, { typeof(C3us[]), (s, w, t, o, l) => CombineTo((C3us[])s, w, Lerp, (C3us[])t, o, l) }, { typeof(C3ui[]), (s, w, t, o, l) => CombineTo((C3ui[])s, w, Lerp, (C3ui[])t, o, l) }, { typeof(C3f[]), (s, w, t, o, l) => CombineTo((C3f[])s, w, Lerp, (C3f[])t, o, l) }, { typeof(C3d[]), (s, w, t, o, l) => CombineTo((C3d[])s, w, Lerp, (C3d[])t, o, l) }, { typeof(C4b[]), (s, w, t, o, l) => CombineTo((C4b[])s, w, Lerp, (C4b[])t, o, l) }, { typeof(C4us[]), (s, w, t, o, l) => CombineTo((C4us[])s, w, Lerp, (C4us[])t, o, l) }, { typeof(C4ui[]), (s, w, t, o, l) => CombineTo((C4ui[])s, w, Lerp, (C4ui[])t, o, l) }, { typeof(C4f[]), (s, w, t, o, l) => CombineTo((C4f[])s, w, Lerp, (C4f[])t, o, l) }, { typeof(C4d[]), (s, w, t, o, l) => CombineTo((C4d[])s, w, Lerp, (C4d[])t, o, l) }, { typeof(V2f[]), (s, w, t, o, l) => CombineTo((V2f[])s, w, Lerp, (V2f[])t, o, l) }, { typeof(V2d[]), (s, w, t, o, l) => CombineTo((V2d[])s, w, Lerp, (V2d[])t, o, l) }, { typeof(V3f[]), (s, w, t, o, l) => CombineTo((V3f[])s, w, Lerp, (V3f[])t, o, l) }, { typeof(V3d[]), (s, w, t, o, l) => CombineTo((V3d[])s, w, Lerp, (V3d[])t, o, l) }, { typeof(V4f[]), (s, w, t, o, l) => CombineTo((V4f[])s, w, Lerp, (V4f[])t, o, l) }, { typeof(V4d[]), (s, w, t, o, l) => CombineTo((V4d[])s, w, Lerp, (V4d[])t, o, l) }, }; /// /// Fills the target array starting at offset for length entries /// with Lerp/weighted combinations of the source array. /// public static Array LerpTo( this Array source, IEnumerable weightedIndexArrays, Array target, int offset, int length) { var type = source.GetType(); s_lerpToOffsetMap[type]( source, weightedIndexArrays, target, offset, length); return target; } /// /// Fills the target array starting at offset with Lerp/weighted /// combinations of the source array. /// public static Array LerpTo( this Array source, IEnumerable weightedIndexArrays, Array target, int offset) { int length = Fun.Min(weightedIndexArrays.Count(), target.Length - offset); return source.LerpTo(weightedIndexArrays, target, offset, length); } private static readonly Dictionary, Array, int, int>> s_lerpAndNormalizeToOffsetMap = new Dictionary, Array, int, int>> { { typeof(V3f[]), (s, w, t, o, l) => CombineTo((V3f[])s, w, (wi,sa) => Lerp(wi,sa).Normalized, (V3f[])t, o, l) }, { typeof(V3d[]), (s, w, t, o, l) => CombineTo((V3d[])s, w, (wi,sa) => Lerp(wi,sa).Normalized, (V3d[])t, o, l) }, }; /// /// Fills the target array starting at offset for length entries /// with normalized Lerp/weighted combinations of the source array. /// public static Array LerpAndNormalizeTo( this Array source, IEnumerable weightedIndexArrays, Array target, int offset, int length) { var type = source.GetType(); s_lerpAndNormalizeToOffsetMap[type]( source, weightedIndexArrays, target, offset, length); return target; } /// /// Fills the target array starting at offset with normalized /// Lerp/weighted combinations of the source array. /// public static Array LerpAndNormalizeTo( this Array source, IEnumerable weightedIndexArrays, Array target, int offset) { int length = Fun.Min(weightedIndexArrays.Count(), target.Length - offset); return source.LerpAndNormalizeTo(weightedIndexArrays, target, offset, length); } public static V3d[] Transformed(this V3d[] points, M33d matrix) { return points.Map(p => matrix.Transform(p)); } public static V3d[] TransformedPos(this V3d[] points, M44d matrix) { return points.Map(p => matrix.TransformPos(p)); } } public static class V2dArrayExtensions { #region Transformations /// /// Returns a version of the point array scaled by a factor of s about /// the supplied center. /// public static V2d[] Scaled(this V2d[] pointArray, V2d center, double s) { long count = pointArray.LongLength; var pa = new V2d[count]; for (long i = 0; i < count; i++) pa[i] = center + (pointArray[i] - center) * s; return pa; } /// /// Returns a version of the point array scaled by a factor of s about /// the supplied center. /// public static V2d[] ScaledAboutCentroid(this V2d[] pointArray, double s) { return pointArray.Scaled(VectorIEnumerableExtensions.ComputeCentroid(pointArray), s); } /// /// Returns new array containing transformed points. /// public static V2d[] Transformed(this V2d[] pointArray, M22d m) { return new V2d[pointArray.LongLength].SetByIndexLong(i => m.Transform(pointArray[i])); } /// /// Returns new array containing transformed points. /// public static V2d[] TransformedPos(this V2d[] pointArray, M33d m) { return new V2d[pointArray.LongLength].SetByIndexLong(i => m.TransformPos(pointArray[i])); } /// /// Returns new array containing transformed points. /// public static V2d[] TransformedDir(this V2d[] pointArray, M33d m) { return new V2d[pointArray.LongLength].SetByIndexLong(i => m.TransformDir(pointArray[i])); } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Vectors/VectorIEnumerableExtensions_auto.cs ================================================ using System.Collections.Generic; namespace Aardvark.Base { public static class VectorIEnumerableExtensions { #region V2i #region Sum /// /// Calculates the sum for a given set of V2is. /// public static V2i Sum(this IEnumerable vectors) { V2i sum = V2i.Zero; foreach (var e in vectors) { sum += e; } return sum; } /// /// Calculates the sum for a given set of V2is. /// public static V2i Sum(this V2i[] vectors) { V2i sum = V2i.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum; } #endregion #region Centroid /// /// Calculates the centroid for a given set of V2is. /// public static V2d ComputeCentroid(this IEnumerable vectors) { V2d sum = V2d.Zero; int count = 0; foreach (var e in vectors) { sum += (V2d)e; count++; } return sum / (double)count; } /// /// Calculates the centroid for a given set of V2is. /// public static V2d ComputeCentroid(this V2i[] vectors) { V2d sum = V2d.Zero; for (var i = 0; i < vectors.Length; i++) { sum += (V2d)vectors[i]; } return sum / (double)vectors.Length; } /// /// Calculates the centroid for a given set of V2is. /// public static V2d ComputeCentroid(this V2i[] vectors, int[] indices) { V2d sum = V2d.Zero; for (var i = 0; i < indices.Length; i++) { sum += (V2d)vectors[indices[i]]; } return sum / (double)indices.Length; } /// /// Calculates a weighted centroid for a given array of V2is. /// public static V2d ComputeCentroid(this V2i[] vectors, double[] weights) { V2d sum = V2d.Zero; double weightSum = 0; for(int i = 0; i < vectors.Length; i++) { sum += weights[i] * (V2d)vectors[i]; weightSum += weights[i]; } return sum / weightSum; } /// /// Calculates a weighted centroid for vectors and weights given by indices. /// Sum(vectors[indices[i]] * weights[indices[i]]) / Sum(weights[indices[i]]. /// public static V2d ComputeCentroid(this V2i[] vectors, double[] weights, int[] indices) { V2d sum = V2d.Zero; double weightSum = 0; for (int i = 0; i < indices.Length; i++) { var w = weights[indices[i]]; sum += w * (V2d)vectors[indices[i]]; weightSum += w; } return sum / weightSum; } #endregion #endregion #region V3i #region Sum /// /// Calculates the sum for a given set of V3is. /// public static V3i Sum(this IEnumerable vectors) { V3i sum = V3i.Zero; foreach (var e in vectors) { sum += e; } return sum; } /// /// Calculates the sum for a given set of V3is. /// public static V3i Sum(this V3i[] vectors) { V3i sum = V3i.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum; } #endregion #region Centroid /// /// Calculates the centroid for a given set of V3is. /// public static V3d ComputeCentroid(this IEnumerable vectors) { V3d sum = V3d.Zero; int count = 0; foreach (var e in vectors) { sum += (V3d)e; count++; } return sum / (double)count; } /// /// Calculates the centroid for a given set of V3is. /// public static V3d ComputeCentroid(this V3i[] vectors) { V3d sum = V3d.Zero; for (var i = 0; i < vectors.Length; i++) { sum += (V3d)vectors[i]; } return sum / (double)vectors.Length; } /// /// Calculates the centroid for a given set of V3is. /// public static V3d ComputeCentroid(this V3i[] vectors, int[] indices) { V3d sum = V3d.Zero; for (var i = 0; i < indices.Length; i++) { sum += (V3d)vectors[indices[i]]; } return sum / (double)indices.Length; } /// /// Calculates a weighted centroid for a given array of V3is. /// public static V3d ComputeCentroid(this V3i[] vectors, double[] weights) { V3d sum = V3d.Zero; double weightSum = 0; for(int i = 0; i < vectors.Length; i++) { sum += weights[i] * (V3d)vectors[i]; weightSum += weights[i]; } return sum / weightSum; } /// /// Calculates a weighted centroid for vectors and weights given by indices. /// Sum(vectors[indices[i]] * weights[indices[i]]) / Sum(weights[indices[i]]. /// public static V3d ComputeCentroid(this V3i[] vectors, double[] weights, int[] indices) { V3d sum = V3d.Zero; double weightSum = 0; for (int i = 0; i < indices.Length; i++) { var w = weights[indices[i]]; sum += w * (V3d)vectors[indices[i]]; weightSum += w; } return sum / weightSum; } #endregion #endregion #region V4i #region Sum /// /// Calculates the sum for a given set of V4is. /// public static V4i Sum(this IEnumerable vectors) { V4i sum = V4i.Zero; foreach (var e in vectors) { sum += e; } return sum; } /// /// Calculates the sum for a given set of V4is. /// public static V4i Sum(this V4i[] vectors) { V4i sum = V4i.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum; } #endregion #region Centroid /// /// Calculates the centroid for a given set of V4is. /// public static V4d ComputeCentroid(this IEnumerable vectors) { V4d sum = V4d.Zero; int count = 0; foreach (var e in vectors) { sum += (V4d)e; count++; } return sum / (double)count; } /// /// Calculates the centroid for a given set of V4is. /// public static V4d ComputeCentroid(this V4i[] vectors) { V4d sum = V4d.Zero; for (var i = 0; i < vectors.Length; i++) { sum += (V4d)vectors[i]; } return sum / (double)vectors.Length; } /// /// Calculates the centroid for a given set of V4is. /// public static V4d ComputeCentroid(this V4i[] vectors, int[] indices) { V4d sum = V4d.Zero; for (var i = 0; i < indices.Length; i++) { sum += (V4d)vectors[indices[i]]; } return sum / (double)indices.Length; } /// /// Calculates a weighted centroid for a given array of V4is. /// public static V4d ComputeCentroid(this V4i[] vectors, double[] weights) { V4d sum = V4d.Zero; double weightSum = 0; for(int i = 0; i < vectors.Length; i++) { sum += weights[i] * (V4d)vectors[i]; weightSum += weights[i]; } return sum / weightSum; } /// /// Calculates a weighted centroid for vectors and weights given by indices. /// Sum(vectors[indices[i]] * weights[indices[i]]) / Sum(weights[indices[i]]. /// public static V4d ComputeCentroid(this V4i[] vectors, double[] weights, int[] indices) { V4d sum = V4d.Zero; double weightSum = 0; for (int i = 0; i < indices.Length; i++) { var w = weights[indices[i]]; sum += w * (V4d)vectors[indices[i]]; weightSum += w; } return sum / weightSum; } #endregion #endregion #region V2ui #region Sum /// /// Calculates the sum for a given set of V2uis. /// public static V2ui Sum(this IEnumerable vectors) { V2ui sum = V2ui.Zero; foreach (var e in vectors) { sum += e; } return sum; } /// /// Calculates the sum for a given set of V2uis. /// public static V2ui Sum(this V2ui[] vectors) { V2ui sum = V2ui.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum; } #endregion #region Centroid /// /// Calculates the centroid for a given set of V2uis. /// public static V2d ComputeCentroid(this IEnumerable vectors) { V2d sum = V2d.Zero; int count = 0; foreach (var e in vectors) { sum += (V2d)e; count++; } return sum / (double)count; } /// /// Calculates the centroid for a given set of V2uis. /// public static V2d ComputeCentroid(this V2ui[] vectors) { V2d sum = V2d.Zero; for (var i = 0; i < vectors.Length; i++) { sum += (V2d)vectors[i]; } return sum / (double)vectors.Length; } /// /// Calculates the centroid for a given set of V2uis. /// public static V2d ComputeCentroid(this V2ui[] vectors, int[] indices) { V2d sum = V2d.Zero; for (var i = 0; i < indices.Length; i++) { sum += (V2d)vectors[indices[i]]; } return sum / (double)indices.Length; } /// /// Calculates a weighted centroid for a given array of V2uis. /// public static V2d ComputeCentroid(this V2ui[] vectors, double[] weights) { V2d sum = V2d.Zero; double weightSum = 0; for(int i = 0; i < vectors.Length; i++) { sum += weights[i] * (V2d)vectors[i]; weightSum += weights[i]; } return sum / weightSum; } /// /// Calculates a weighted centroid for vectors and weights given by indices. /// Sum(vectors[indices[i]] * weights[indices[i]]) / Sum(weights[indices[i]]. /// public static V2d ComputeCentroid(this V2ui[] vectors, double[] weights, int[] indices) { V2d sum = V2d.Zero; double weightSum = 0; for (int i = 0; i < indices.Length; i++) { var w = weights[indices[i]]; sum += w * (V2d)vectors[indices[i]]; weightSum += w; } return sum / weightSum; } #endregion #endregion #region V3ui #region Sum /// /// Calculates the sum for a given set of V3uis. /// public static V3ui Sum(this IEnumerable vectors) { V3ui sum = V3ui.Zero; foreach (var e in vectors) { sum += e; } return sum; } /// /// Calculates the sum for a given set of V3uis. /// public static V3ui Sum(this V3ui[] vectors) { V3ui sum = V3ui.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum; } #endregion #region Centroid /// /// Calculates the centroid for a given set of V3uis. /// public static V3d ComputeCentroid(this IEnumerable vectors) { V3d sum = V3d.Zero; int count = 0; foreach (var e in vectors) { sum += (V3d)e; count++; } return sum / (double)count; } /// /// Calculates the centroid for a given set of V3uis. /// public static V3d ComputeCentroid(this V3ui[] vectors) { V3d sum = V3d.Zero; for (var i = 0; i < vectors.Length; i++) { sum += (V3d)vectors[i]; } return sum / (double)vectors.Length; } /// /// Calculates the centroid for a given set of V3uis. /// public static V3d ComputeCentroid(this V3ui[] vectors, int[] indices) { V3d sum = V3d.Zero; for (var i = 0; i < indices.Length; i++) { sum += (V3d)vectors[indices[i]]; } return sum / (double)indices.Length; } /// /// Calculates a weighted centroid for a given array of V3uis. /// public static V3d ComputeCentroid(this V3ui[] vectors, double[] weights) { V3d sum = V3d.Zero; double weightSum = 0; for(int i = 0; i < vectors.Length; i++) { sum += weights[i] * (V3d)vectors[i]; weightSum += weights[i]; } return sum / weightSum; } /// /// Calculates a weighted centroid for vectors and weights given by indices. /// Sum(vectors[indices[i]] * weights[indices[i]]) / Sum(weights[indices[i]]. /// public static V3d ComputeCentroid(this V3ui[] vectors, double[] weights, int[] indices) { V3d sum = V3d.Zero; double weightSum = 0; for (int i = 0; i < indices.Length; i++) { var w = weights[indices[i]]; sum += w * (V3d)vectors[indices[i]]; weightSum += w; } return sum / weightSum; } #endregion #endregion #region V4ui #region Sum /// /// Calculates the sum for a given set of V4uis. /// public static V4ui Sum(this IEnumerable vectors) { V4ui sum = V4ui.Zero; foreach (var e in vectors) { sum += e; } return sum; } /// /// Calculates the sum for a given set of V4uis. /// public static V4ui Sum(this V4ui[] vectors) { V4ui sum = V4ui.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum; } #endregion #region Centroid /// /// Calculates the centroid for a given set of V4uis. /// public static V4d ComputeCentroid(this IEnumerable vectors) { V4d sum = V4d.Zero; int count = 0; foreach (var e in vectors) { sum += (V4d)e; count++; } return sum / (double)count; } /// /// Calculates the centroid for a given set of V4uis. /// public static V4d ComputeCentroid(this V4ui[] vectors) { V4d sum = V4d.Zero; for (var i = 0; i < vectors.Length; i++) { sum += (V4d)vectors[i]; } return sum / (double)vectors.Length; } /// /// Calculates the centroid for a given set of V4uis. /// public static V4d ComputeCentroid(this V4ui[] vectors, int[] indices) { V4d sum = V4d.Zero; for (var i = 0; i < indices.Length; i++) { sum += (V4d)vectors[indices[i]]; } return sum / (double)indices.Length; } /// /// Calculates a weighted centroid for a given array of V4uis. /// public static V4d ComputeCentroid(this V4ui[] vectors, double[] weights) { V4d sum = V4d.Zero; double weightSum = 0; for(int i = 0; i < vectors.Length; i++) { sum += weights[i] * (V4d)vectors[i]; weightSum += weights[i]; } return sum / weightSum; } /// /// Calculates a weighted centroid for vectors and weights given by indices. /// Sum(vectors[indices[i]] * weights[indices[i]]) / Sum(weights[indices[i]]. /// public static V4d ComputeCentroid(this V4ui[] vectors, double[] weights, int[] indices) { V4d sum = V4d.Zero; double weightSum = 0; for (int i = 0; i < indices.Length; i++) { var w = weights[indices[i]]; sum += w * (V4d)vectors[indices[i]]; weightSum += w; } return sum / weightSum; } #endregion #endregion #region V2l #region Sum /// /// Calculates the sum for a given set of V2ls. /// public static V2l Sum(this IEnumerable vectors) { V2l sum = V2l.Zero; foreach (var e in vectors) { sum += e; } return sum; } /// /// Calculates the sum for a given set of V2ls. /// public static V2l Sum(this V2l[] vectors) { V2l sum = V2l.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum; } #endregion #region Centroid /// /// Calculates the centroid for a given set of V2ls. /// public static V2d ComputeCentroid(this IEnumerable vectors) { V2d sum = V2d.Zero; int count = 0; foreach (var e in vectors) { sum += (V2d)e; count++; } return sum / (double)count; } /// /// Calculates the centroid for a given set of V2ls. /// public static V2d ComputeCentroid(this V2l[] vectors) { V2d sum = V2d.Zero; for (var i = 0; i < vectors.Length; i++) { sum += (V2d)vectors[i]; } return sum / (double)vectors.Length; } /// /// Calculates the centroid for a given set of V2ls. /// public static V2d ComputeCentroid(this V2l[] vectors, int[] indices) { V2d sum = V2d.Zero; for (var i = 0; i < indices.Length; i++) { sum += (V2d)vectors[indices[i]]; } return sum / (double)indices.Length; } /// /// Calculates a weighted centroid for a given array of V2ls. /// public static V2d ComputeCentroid(this V2l[] vectors, double[] weights) { V2d sum = V2d.Zero; double weightSum = 0; for(int i = 0; i < vectors.Length; i++) { sum += weights[i] * (V2d)vectors[i]; weightSum += weights[i]; } return sum / weightSum; } /// /// Calculates a weighted centroid for vectors and weights given by indices. /// Sum(vectors[indices[i]] * weights[indices[i]]) / Sum(weights[indices[i]]. /// public static V2d ComputeCentroid(this V2l[] vectors, double[] weights, int[] indices) { V2d sum = V2d.Zero; double weightSum = 0; for (int i = 0; i < indices.Length; i++) { var w = weights[indices[i]]; sum += w * (V2d)vectors[indices[i]]; weightSum += w; } return sum / weightSum; } #endregion #endregion #region V3l #region Sum /// /// Calculates the sum for a given set of V3ls. /// public static V3l Sum(this IEnumerable vectors) { V3l sum = V3l.Zero; foreach (var e in vectors) { sum += e; } return sum; } /// /// Calculates the sum for a given set of V3ls. /// public static V3l Sum(this V3l[] vectors) { V3l sum = V3l.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum; } #endregion #region Centroid /// /// Calculates the centroid for a given set of V3ls. /// public static V3d ComputeCentroid(this IEnumerable vectors) { V3d sum = V3d.Zero; int count = 0; foreach (var e in vectors) { sum += (V3d)e; count++; } return sum / (double)count; } /// /// Calculates the centroid for a given set of V3ls. /// public static V3d ComputeCentroid(this V3l[] vectors) { V3d sum = V3d.Zero; for (var i = 0; i < vectors.Length; i++) { sum += (V3d)vectors[i]; } return sum / (double)vectors.Length; } /// /// Calculates the centroid for a given set of V3ls. /// public static V3d ComputeCentroid(this V3l[] vectors, int[] indices) { V3d sum = V3d.Zero; for (var i = 0; i < indices.Length; i++) { sum += (V3d)vectors[indices[i]]; } return sum / (double)indices.Length; } /// /// Calculates a weighted centroid for a given array of V3ls. /// public static V3d ComputeCentroid(this V3l[] vectors, double[] weights) { V3d sum = V3d.Zero; double weightSum = 0; for(int i = 0; i < vectors.Length; i++) { sum += weights[i] * (V3d)vectors[i]; weightSum += weights[i]; } return sum / weightSum; } /// /// Calculates a weighted centroid for vectors and weights given by indices. /// Sum(vectors[indices[i]] * weights[indices[i]]) / Sum(weights[indices[i]]. /// public static V3d ComputeCentroid(this V3l[] vectors, double[] weights, int[] indices) { V3d sum = V3d.Zero; double weightSum = 0; for (int i = 0; i < indices.Length; i++) { var w = weights[indices[i]]; sum += w * (V3d)vectors[indices[i]]; weightSum += w; } return sum / weightSum; } #endregion #endregion #region V4l #region Sum /// /// Calculates the sum for a given set of V4ls. /// public static V4l Sum(this IEnumerable vectors) { V4l sum = V4l.Zero; foreach (var e in vectors) { sum += e; } return sum; } /// /// Calculates the sum for a given set of V4ls. /// public static V4l Sum(this V4l[] vectors) { V4l sum = V4l.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum; } #endregion #region Centroid /// /// Calculates the centroid for a given set of V4ls. /// public static V4d ComputeCentroid(this IEnumerable vectors) { V4d sum = V4d.Zero; int count = 0; foreach (var e in vectors) { sum += (V4d)e; count++; } return sum / (double)count; } /// /// Calculates the centroid for a given set of V4ls. /// public static V4d ComputeCentroid(this V4l[] vectors) { V4d sum = V4d.Zero; for (var i = 0; i < vectors.Length; i++) { sum += (V4d)vectors[i]; } return sum / (double)vectors.Length; } /// /// Calculates the centroid for a given set of V4ls. /// public static V4d ComputeCentroid(this V4l[] vectors, int[] indices) { V4d sum = V4d.Zero; for (var i = 0; i < indices.Length; i++) { sum += (V4d)vectors[indices[i]]; } return sum / (double)indices.Length; } /// /// Calculates a weighted centroid for a given array of V4ls. /// public static V4d ComputeCentroid(this V4l[] vectors, double[] weights) { V4d sum = V4d.Zero; double weightSum = 0; for(int i = 0; i < vectors.Length; i++) { sum += weights[i] * (V4d)vectors[i]; weightSum += weights[i]; } return sum / weightSum; } /// /// Calculates a weighted centroid for vectors and weights given by indices. /// Sum(vectors[indices[i]] * weights[indices[i]]) / Sum(weights[indices[i]]. /// public static V4d ComputeCentroid(this V4l[] vectors, double[] weights, int[] indices) { V4d sum = V4d.Zero; double weightSum = 0; for (int i = 0; i < indices.Length; i++) { var w = weights[indices[i]]; sum += w * (V4d)vectors[indices[i]]; weightSum += w; } return sum / weightSum; } #endregion #endregion #region V2f #region Sum /// /// Calculates the sum for a given set of V2fs. /// public static V2f Sum(this IEnumerable vectors) { V2f sum = V2f.Zero; foreach (var e in vectors) { sum += e; } return sum; } /// /// Calculates the sum for a given set of V2fs. /// public static V2f Sum(this V2f[] vectors) { V2f sum = V2f.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum; } #endregion #region Centroid /// /// Calculates the centroid for a given set of V2fs. /// public static V2f ComputeCentroid(this IEnumerable vectors) { V2f sum = V2f.Zero; int count = 0; foreach (var e in vectors) { sum += e; count++; } return sum / (float)count; } /// /// Calculates the centroid for a given set of V2fs. /// public static V2f ComputeCentroid(this V2f[] vectors) { V2f sum = V2f.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum / (float)vectors.Length; } /// /// Calculates the centroid for a given set of V2fs. /// public static V2f ComputeCentroid(this V2f[] vectors, int[] indices) { V2f sum = V2f.Zero; for (var i = 0; i < indices.Length; i++) { sum += vectors[indices[i]]; } return sum / (float)indices.Length; } /// /// Calculates a weighted centroid for a given array of V2fs. /// public static V2f ComputeCentroid(this V2f[] vectors, float[] weights) { V2f sum = V2f.Zero; float weightSum = 0; for(int i = 0; i < vectors.Length; i++) { sum += weights[i] * vectors[i]; weightSum += weights[i]; } return sum / weightSum; } /// /// Calculates a weighted centroid for vectors and weights given by indices. /// Sum(vectors[indices[i]] * weights[indices[i]]) / Sum(weights[indices[i]]. /// public static V2f ComputeCentroid(this V2f[] vectors, float[] weights, int[] indices) { V2f sum = V2f.Zero; float weightSum = 0; for (int i = 0; i < indices.Length; i++) { var w = weights[indices[i]]; sum += w * vectors[indices[i]]; weightSum += w; } return sum / weightSum; } #endregion #endregion #region V3f #region Sum /// /// Calculates the sum for a given set of V3fs. /// public static V3f Sum(this IEnumerable vectors) { V3f sum = V3f.Zero; foreach (var e in vectors) { sum += e; } return sum; } /// /// Calculates the sum for a given set of V3fs. /// public static V3f Sum(this V3f[] vectors) { V3f sum = V3f.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum; } #endregion #region Centroid /// /// Calculates the centroid for a given set of V3fs. /// public static V3f ComputeCentroid(this IEnumerable vectors) { V3f sum = V3f.Zero; int count = 0; foreach (var e in vectors) { sum += e; count++; } return sum / (float)count; } /// /// Calculates the centroid for a given set of V3fs. /// public static V3f ComputeCentroid(this V3f[] vectors) { V3f sum = V3f.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum / (float)vectors.Length; } /// /// Calculates the centroid for a given set of V3fs. /// public static V3f ComputeCentroid(this V3f[] vectors, int[] indices) { V3f sum = V3f.Zero; for (var i = 0; i < indices.Length; i++) { sum += vectors[indices[i]]; } return sum / (float)indices.Length; } /// /// Calculates a weighted centroid for a given array of V3fs. /// public static V3f ComputeCentroid(this V3f[] vectors, float[] weights) { V3f sum = V3f.Zero; float weightSum = 0; for(int i = 0; i < vectors.Length; i++) { sum += weights[i] * vectors[i]; weightSum += weights[i]; } return sum / weightSum; } /// /// Calculates a weighted centroid for vectors and weights given by indices. /// Sum(vectors[indices[i]] * weights[indices[i]]) / Sum(weights[indices[i]]. /// public static V3f ComputeCentroid(this V3f[] vectors, float[] weights, int[] indices) { V3f sum = V3f.Zero; float weightSum = 0; for (int i = 0; i < indices.Length; i++) { var w = weights[indices[i]]; sum += w * vectors[indices[i]]; weightSum += w; } return sum / weightSum; } #endregion #endregion #region V4f #region Sum /// /// Calculates the sum for a given set of V4fs. /// public static V4f Sum(this IEnumerable vectors) { V4f sum = V4f.Zero; foreach (var e in vectors) { sum += e; } return sum; } /// /// Calculates the sum for a given set of V4fs. /// public static V4f Sum(this V4f[] vectors) { V4f sum = V4f.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum; } #endregion #region Centroid /// /// Calculates the centroid for a given set of V4fs. /// public static V4f ComputeCentroid(this IEnumerable vectors) { V4f sum = V4f.Zero; int count = 0; foreach (var e in vectors) { sum += e; count++; } return sum / (float)count; } /// /// Calculates the centroid for a given set of V4fs. /// public static V4f ComputeCentroid(this V4f[] vectors) { V4f sum = V4f.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum / (float)vectors.Length; } /// /// Calculates the centroid for a given set of V4fs. /// public static V4f ComputeCentroid(this V4f[] vectors, int[] indices) { V4f sum = V4f.Zero; for (var i = 0; i < indices.Length; i++) { sum += vectors[indices[i]]; } return sum / (float)indices.Length; } /// /// Calculates a weighted centroid for a given array of V4fs. /// public static V4f ComputeCentroid(this V4f[] vectors, float[] weights) { V4f sum = V4f.Zero; float weightSum = 0; for(int i = 0; i < vectors.Length; i++) { sum += weights[i] * vectors[i]; weightSum += weights[i]; } return sum / weightSum; } /// /// Calculates a weighted centroid for vectors and weights given by indices. /// Sum(vectors[indices[i]] * weights[indices[i]]) / Sum(weights[indices[i]]. /// public static V4f ComputeCentroid(this V4f[] vectors, float[] weights, int[] indices) { V4f sum = V4f.Zero; float weightSum = 0; for (int i = 0; i < indices.Length; i++) { var w = weights[indices[i]]; sum += w * vectors[indices[i]]; weightSum += w; } return sum / weightSum; } #endregion #endregion #region V2d #region Sum /// /// Calculates the sum for a given set of V2ds. /// public static V2d Sum(this IEnumerable vectors) { V2d sum = V2d.Zero; foreach (var e in vectors) { sum += e; } return sum; } /// /// Calculates the sum for a given set of V2ds. /// public static V2d Sum(this V2d[] vectors) { V2d sum = V2d.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum; } #endregion #region Centroid /// /// Calculates the centroid for a given set of V2ds. /// public static V2d ComputeCentroid(this IEnumerable vectors) { V2d sum = V2d.Zero; int count = 0; foreach (var e in vectors) { sum += e; count++; } return sum / (double)count; } /// /// Calculates the centroid for a given set of V2ds. /// public static V2d ComputeCentroid(this V2d[] vectors) { V2d sum = V2d.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum / (double)vectors.Length; } /// /// Calculates the centroid for a given set of V2ds. /// public static V2d ComputeCentroid(this V2d[] vectors, int[] indices) { V2d sum = V2d.Zero; for (var i = 0; i < indices.Length; i++) { sum += vectors[indices[i]]; } return sum / (double)indices.Length; } /// /// Calculates a weighted centroid for a given array of V2ds. /// public static V2d ComputeCentroid(this V2d[] vectors, double[] weights) { V2d sum = V2d.Zero; double weightSum = 0; for(int i = 0; i < vectors.Length; i++) { sum += weights[i] * vectors[i]; weightSum += weights[i]; } return sum / weightSum; } /// /// Calculates a weighted centroid for vectors and weights given by indices. /// Sum(vectors[indices[i]] * weights[indices[i]]) / Sum(weights[indices[i]]. /// public static V2d ComputeCentroid(this V2d[] vectors, double[] weights, int[] indices) { V2d sum = V2d.Zero; double weightSum = 0; for (int i = 0; i < indices.Length; i++) { var w = weights[indices[i]]; sum += w * vectors[indices[i]]; weightSum += w; } return sum / weightSum; } #endregion #endregion #region V3d #region Sum /// /// Calculates the sum for a given set of V3ds. /// public static V3d Sum(this IEnumerable vectors) { V3d sum = V3d.Zero; foreach (var e in vectors) { sum += e; } return sum; } /// /// Calculates the sum for a given set of V3ds. /// public static V3d Sum(this V3d[] vectors) { V3d sum = V3d.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum; } #endregion #region Centroid /// /// Calculates the centroid for a given set of V3ds. /// public static V3d ComputeCentroid(this IEnumerable vectors) { V3d sum = V3d.Zero; int count = 0; foreach (var e in vectors) { sum += e; count++; } return sum / (double)count; } /// /// Calculates the centroid for a given set of V3ds. /// public static V3d ComputeCentroid(this V3d[] vectors) { V3d sum = V3d.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum / (double)vectors.Length; } /// /// Calculates the centroid for a given set of V3ds. /// public static V3d ComputeCentroid(this V3d[] vectors, int[] indices) { V3d sum = V3d.Zero; for (var i = 0; i < indices.Length; i++) { sum += vectors[indices[i]]; } return sum / (double)indices.Length; } /// /// Calculates a weighted centroid for a given array of V3ds. /// public static V3d ComputeCentroid(this V3d[] vectors, double[] weights) { V3d sum = V3d.Zero; double weightSum = 0; for(int i = 0; i < vectors.Length; i++) { sum += weights[i] * vectors[i]; weightSum += weights[i]; } return sum / weightSum; } /// /// Calculates a weighted centroid for vectors and weights given by indices. /// Sum(vectors[indices[i]] * weights[indices[i]]) / Sum(weights[indices[i]]. /// public static V3d ComputeCentroid(this V3d[] vectors, double[] weights, int[] indices) { V3d sum = V3d.Zero; double weightSum = 0; for (int i = 0; i < indices.Length; i++) { var w = weights[indices[i]]; sum += w * vectors[indices[i]]; weightSum += w; } return sum / weightSum; } #endregion #endregion #region V4d #region Sum /// /// Calculates the sum for a given set of V4ds. /// public static V4d Sum(this IEnumerable vectors) { V4d sum = V4d.Zero; foreach (var e in vectors) { sum += e; } return sum; } /// /// Calculates the sum for a given set of V4ds. /// public static V4d Sum(this V4d[] vectors) { V4d sum = V4d.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum; } #endregion #region Centroid /// /// Calculates the centroid for a given set of V4ds. /// public static V4d ComputeCentroid(this IEnumerable vectors) { V4d sum = V4d.Zero; int count = 0; foreach (var e in vectors) { sum += e; count++; } return sum / (double)count; } /// /// Calculates the centroid for a given set of V4ds. /// public static V4d ComputeCentroid(this V4d[] vectors) { V4d sum = V4d.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum / (double)vectors.Length; } /// /// Calculates the centroid for a given set of V4ds. /// public static V4d ComputeCentroid(this V4d[] vectors, int[] indices) { V4d sum = V4d.Zero; for (var i = 0; i < indices.Length; i++) { sum += vectors[indices[i]]; } return sum / (double)indices.Length; } /// /// Calculates a weighted centroid for a given array of V4ds. /// public static V4d ComputeCentroid(this V4d[] vectors, double[] weights) { V4d sum = V4d.Zero; double weightSum = 0; for(int i = 0; i < vectors.Length; i++) { sum += weights[i] * vectors[i]; weightSum += weights[i]; } return sum / weightSum; } /// /// Calculates a weighted centroid for vectors and weights given by indices. /// Sum(vectors[indices[i]] * weights[indices[i]]) / Sum(weights[indices[i]]. /// public static V4d ComputeCentroid(this V4d[] vectors, double[] weights, int[] indices) { V4d sum = V4d.Zero; double weightSum = 0; for (int i = 0; i < indices.Length; i++) { var w = weights[indices[i]]; sum += w * vectors[indices[i]]; weightSum += w; } return sum / weightSum; } #endregion #endregion } } ================================================ FILE: src/Aardvark.Base/Math/Vectors/VectorIEnumerableExtensions_template.cs ================================================ using System.Collections.Generic; namespace Aardvark.Base { public static class VectorIEnumerableExtensions { //# foreach(var scalar in Meta.VecFieldTypes) //# { //# foreach(var dim in Meta.VecTypeDimensions) //# { //# var inputVecType = Meta.VecTypeOf(dim, scalar).Name; //# var outputVecType = scalar.IsReal ? inputVecType : Meta.VecTypeOf(dim, Meta.DoubleType).Name; //# var scalarType = scalar.IsReal ? scalar.Name : Meta.DoubleType.Name; //# var cast = scalar.IsReal ? "" : "(" + outputVecType + ")"; #region __inputVecType__ #region Sum /// /// Calculates the sum for a given set of __inputVecType__s. /// public static __inputVecType__ Sum(this IEnumerable<__inputVecType__> vectors) { __inputVecType__ sum = __inputVecType__.Zero; foreach (var e in vectors) { sum += e; } return sum; } /// /// Calculates the sum for a given set of __inputVecType__s. /// public static __inputVecType__ Sum(this __inputVecType__[] vectors) { __inputVecType__ sum = __inputVecType__.Zero; for (var i = 0; i < vectors.Length; i++) { sum += vectors[i]; } return sum; } #endregion #region Centroid /// /// Calculates the centroid for a given set of __inputVecType__s. /// public static __outputVecType__ ComputeCentroid(this IEnumerable<__inputVecType__> vectors) { __outputVecType__ sum = __outputVecType__.Zero; int count = 0; foreach (var e in vectors) { sum += __cast__e; count++; } return sum / (__scalarType__)count; } /// /// Calculates the centroid for a given set of __inputVecType__s. /// public static __outputVecType__ ComputeCentroid(this __inputVecType__[] vectors) { __outputVecType__ sum = __outputVecType__.Zero; for (var i = 0; i < vectors.Length; i++) { sum += __cast__vectors[i]; } return sum / (__scalarType__)vectors.Length; } /// /// Calculates the centroid for a given set of __inputVecType__s. /// public static __outputVecType__ ComputeCentroid(this __inputVecType__[] vectors, int[] indices) { __outputVecType__ sum = __outputVecType__.Zero; for (var i = 0; i < indices.Length; i++) { sum += __cast__vectors[indices[i]]; } return sum / (__scalarType__)indices.Length; } /// /// Calculates a weighted centroid for a given array of __inputVecType__s. /// public static __outputVecType__ ComputeCentroid(this __inputVecType__[] vectors, __scalarType__[] weights) { __outputVecType__ sum = __outputVecType__.Zero; __scalarType__ weightSum = 0; for(int i = 0; i < vectors.Length; i++) { sum += weights[i] * __cast__vectors[i]; weightSum += weights[i]; } return sum / weightSum; } /// /// Calculates a weighted centroid for vectors and weights given by indices. /// Sum(vectors[indices[i]] * weights[indices[i]]) / Sum(weights[indices[i]]. /// public static __outputVecType__ ComputeCentroid(this __inputVecType__[] vectors, __scalarType__[] weights, int[] indices) { __outputVecType__ sum = __outputVecType__.Zero; __scalarType__ weightSum = 0; for (int i = 0; i < indices.Length; i++) { var w = weights[indices[i]]; sum += w * __cast__vectors[indices[i]]; weightSum += w; } return sum / weightSum; } #endregion #endregion //# } ///foreach(Meta.VecTypeDimensions); //# } ///foreach(Meta.VecTypes) } } ================================================ FILE: src/Aardvark.Base/Math/Vectors/VectorTypeConverter_auto.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.Design.Serialization; using System.Globalization; using System.Reflection; using System.Text; // AUTO-GENERATED CODE - DO NOT EDIT! namespace Aardvark.Base { ///////////////////////////////////////////////////////////////////// // dimension is 2 // primitive type is int // vector type is V2i [TypeConverter(typeof(V2iConverter))] public partial struct V2i { } public class V2iConverter : TypeConverter { /// /// Can the framework call CreateInstance? /// public override bool GetCreateInstanceSupported( ITypeDescriptorContext context) { return true; } /// /// Satisfy the CreateInstance call by reading data from the /// propertyValues dictionary /// public override object CreateInstance( ITypeDescriptorContext context, IDictionary propertyValues ) { if (propertyValues.Contains("Value")) { var v = new V2i((V2i)(propertyValues["Value"])); return v; } else { return new V2i( (int)propertyValues["X0"], (int)propertyValues["X1"] ); } } /// /// Does this struct expose properties? /// public override bool GetPropertiesSupported(ITypeDescriptorContext context) { return true; } /// /// Return the properties of this struct /// public override PropertyDescriptorCollection GetProperties( ITypeDescriptorContext context, object value, Attribute[] attributes ) { return TypeDescriptor.GetProperties(value, attributes); } /// /// Check what this type can be created from /// public override bool CanConvertFrom( ITypeDescriptorContext context, System.Type sourceType ) { // Just strings for now bool canConvert = (sourceType == typeof(string)); if (!canConvert) canConvert = base.CanConvertFrom(context, sourceType); return canConvert; } /// /// Convert from a specified type to a V2i, if possible /// public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value ) { string sValue = value as string; object retVal = null; if (sValue != null) { // Check that the string actually has something in it... sValue = sValue.Trim(); if (sValue.Length != 0) { // Parse the string if (null == culture) culture = CultureInfo.CurrentCulture; // Split the string based on the cultures list separator var parms = sValue.Split( new char[] { culture.TextInfo.ListSeparator[0] } ); if (parms.Length == 2) { // Should have an integer and a string. var x0 = (int)Convert.ToDouble(parms[0]); var x1 = (int)Convert.ToDouble(parms[1]); // And finally create the object retVal = new V2i(x0, x1); } } } else { retVal = base.ConvertFrom(context, culture, value); } return retVal; } /// /// Check what the type can be converted to /// public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType ) { // InstanceDescriptor is used in the code behind bool canConvert = (destinationType == typeof(InstanceDescriptor)); if (!canConvert) canConvert = base.CanConvertFrom(context, destinationType); return canConvert; } /// /// Convert to a specified type /// public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType ) { object retVal = null; var v = (V2i)value; // If this is an instance descriptor... if (destinationType == typeof(InstanceDescriptor)) { var argTypes = new System.Type[2]; argTypes[0] = typeof(int); argTypes[1] = typeof(int); // Lookup the appropriate $TVector$ constructor ConstructorInfo constructor = typeof(V2i).GetConstructor(argTypes); var arguments = new object[2]; arguments[0] = v[0]; arguments[1] = v[1]; // And return an instance descriptor to the caller. // Will fill in the CodeBehind stuff in VS.Net retVal = new InstanceDescriptor(constructor, arguments); } else if (destinationType == typeof(string)) { // If it's a string, return one to the caller if (null == culture) culture = CultureInfo.CurrentCulture; var values = new string[2]; // I'm a bit of a culture vulture - do it properly! TypeConverter numberConverter = TypeDescriptor.GetConverter(typeof(int)); values[0] = numberConverter.ConvertToString(context, culture, v[0]); values[1] = numberConverter.ConvertToString(context, culture, v[1]); // A useful method - join an array of strings using a separator, in this instance the culture specific one retVal = String.Join(culture.TextInfo.ListSeparator + " ", values); } else retVal = base.ConvertTo(context, culture, value, destinationType); return retVal; } } ///////////////////////////////////////////////////////////////////// // dimension is 2 // primitive type is long // vector type is V2l [TypeConverter(typeof(V2lConverter))] public partial struct V2l { } public class V2lConverter : TypeConverter { /// /// Can the framework call CreateInstance? /// public override bool GetCreateInstanceSupported( ITypeDescriptorContext context) { return true; } /// /// Satisfy the CreateInstance call by reading data from the /// propertyValues dictionary /// public override object CreateInstance( ITypeDescriptorContext context, IDictionary propertyValues ) { if (propertyValues.Contains("Value")) { var v = new V2l((V2l)(propertyValues["Value"])); return v; } else { return new V2l( (long)propertyValues["X0"], (long)propertyValues["X1"] ); } } /// /// Does this struct expose properties? /// public override bool GetPropertiesSupported(ITypeDescriptorContext context) { return true; } /// /// Return the properties of this struct /// public override PropertyDescriptorCollection GetProperties( ITypeDescriptorContext context, object value, Attribute[] attributes ) { return TypeDescriptor.GetProperties(value, attributes); } /// /// Check what this type can be created from /// public override bool CanConvertFrom( ITypeDescriptorContext context, System.Type sourceType ) { // Just strings for now bool canConvert = (sourceType == typeof(string)); if (!canConvert) canConvert = base.CanConvertFrom(context, sourceType); return canConvert; } /// /// Convert from a specified type to a V2l, if possible /// public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value ) { string sValue = value as string; object retVal = null; if (sValue != null) { // Check that the string actually has something in it... sValue = sValue.Trim(); if (sValue.Length != 0) { // Parse the string if (null == culture) culture = CultureInfo.CurrentCulture; // Split the string based on the cultures list separator var parms = sValue.Split( new char[] { culture.TextInfo.ListSeparator[0] } ); if (parms.Length == 2) { // Should have an integer and a string. var x0 = (long)Convert.ToDouble(parms[0]); var x1 = (long)Convert.ToDouble(parms[1]); // And finally create the object retVal = new V2l(x0, x1); } } } else { retVal = base.ConvertFrom(context, culture, value); } return retVal; } /// /// Check what the type can be converted to /// public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType ) { // InstanceDescriptor is used in the code behind bool canConvert = (destinationType == typeof(InstanceDescriptor)); if (!canConvert) canConvert = base.CanConvertFrom(context, destinationType); return canConvert; } /// /// Convert to a specified type /// public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType ) { object retVal = null; var v = (V2l)value; // If this is an instance descriptor... if (destinationType == typeof(InstanceDescriptor)) { var argTypes = new System.Type[2]; argTypes[0] = typeof(long); argTypes[1] = typeof(long); // Lookup the appropriate $TVector$ constructor ConstructorInfo constructor = typeof(V2l).GetConstructor(argTypes); var arguments = new object[2]; arguments[0] = v[0]; arguments[1] = v[1]; // And return an instance descriptor to the caller. // Will fill in the CodeBehind stuff in VS.Net retVal = new InstanceDescriptor(constructor, arguments); } else if (destinationType == typeof(string)) { // If it's a string, return one to the caller if (null == culture) culture = CultureInfo.CurrentCulture; var values = new string[2]; // I'm a bit of a culture vulture - do it properly! TypeConverter numberConverter = TypeDescriptor.GetConverter(typeof(long)); values[0] = numberConverter.ConvertToString(context, culture, v[0]); values[1] = numberConverter.ConvertToString(context, culture, v[1]); // A useful method - join an array of strings using a separator, in this instance the culture specific one retVal = String.Join(culture.TextInfo.ListSeparator + " ", values); } else retVal = base.ConvertTo(context, culture, value, destinationType); return retVal; } } ///////////////////////////////////////////////////////////////////// // dimension is 2 // primitive type is float // vector type is V2f [TypeConverter(typeof(V2fConverter))] public partial struct V2f { } public class V2fConverter : TypeConverter { /// /// Can the framework call CreateInstance? /// public override bool GetCreateInstanceSupported( ITypeDescriptorContext context) { return true; } /// /// Satisfy the CreateInstance call by reading data from the /// propertyValues dictionary /// public override object CreateInstance( ITypeDescriptorContext context, IDictionary propertyValues ) { if (propertyValues.Contains("Value")) { var v = new V2f((V2f)(propertyValues["Value"])); return v; } else { return new V2f( (float)propertyValues["X0"], (float)propertyValues["X1"] ); } } /// /// Does this struct expose properties? /// public override bool GetPropertiesSupported(ITypeDescriptorContext context) { return true; } /// /// Return the properties of this struct /// public override PropertyDescriptorCollection GetProperties( ITypeDescriptorContext context, object value, Attribute[] attributes ) { return TypeDescriptor.GetProperties(value, attributes); } /// /// Check what this type can be created from /// public override bool CanConvertFrom( ITypeDescriptorContext context, System.Type sourceType ) { // Just strings for now bool canConvert = (sourceType == typeof(string)); if (!canConvert) canConvert = base.CanConvertFrom(context, sourceType); return canConvert; } /// /// Convert from a specified type to a V2f, if possible /// public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value ) { string sValue = value as string; object retVal = null; if (sValue != null) { // Check that the string actually has something in it... sValue = sValue.Trim(); if (sValue.Length != 0) { // Parse the string if (null == culture) culture = CultureInfo.CurrentCulture; // Split the string based on the cultures list separator var parms = sValue.Split( new char[] { culture.TextInfo.ListSeparator[0] } ); if (parms.Length == 2) { // Should have an integer and a string. var x0 = (float)Convert.ToDouble(parms[0]); var x1 = (float)Convert.ToDouble(parms[1]); // And finally create the object retVal = new V2f(x0, x1); } } } else { retVal = base.ConvertFrom(context, culture, value); } return retVal; } /// /// Check what the type can be converted to /// public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType ) { // InstanceDescriptor is used in the code behind bool canConvert = (destinationType == typeof(InstanceDescriptor)); if (!canConvert) canConvert = base.CanConvertFrom(context, destinationType); return canConvert; } /// /// Convert to a specified type /// public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType ) { object retVal = null; var v = (V2f)value; // If this is an instance descriptor... if (destinationType == typeof(InstanceDescriptor)) { var argTypes = new System.Type[2]; argTypes[0] = typeof(float); argTypes[1] = typeof(float); // Lookup the appropriate $TVector$ constructor ConstructorInfo constructor = typeof(V2f).GetConstructor(argTypes); var arguments = new object[2]; arguments[0] = v[0]; arguments[1] = v[1]; // And return an instance descriptor to the caller. // Will fill in the CodeBehind stuff in VS.Net retVal = new InstanceDescriptor(constructor, arguments); } else if (destinationType == typeof(string)) { // If it's a string, return one to the caller if (null == culture) culture = CultureInfo.CurrentCulture; var values = new string[2]; // I'm a bit of a culture vulture - do it properly! TypeConverter numberConverter = TypeDescriptor.GetConverter(typeof(float)); values[0] = numberConverter.ConvertToString(context, culture, v[0]); values[1] = numberConverter.ConvertToString(context, culture, v[1]); // A useful method - join an array of strings using a separator, in this instance the culture specific one retVal = String.Join(culture.TextInfo.ListSeparator + " ", values); } else retVal = base.ConvertTo(context, culture, value, destinationType); return retVal; } } ///////////////////////////////////////////////////////////////////// // dimension is 2 // primitive type is double // vector type is V2d [TypeConverter(typeof(V2dConverter))] public partial struct V2d { } public class V2dConverter : TypeConverter { /// /// Can the framework call CreateInstance? /// public override bool GetCreateInstanceSupported( ITypeDescriptorContext context) { return true; } /// /// Satisfy the CreateInstance call by reading data from the /// propertyValues dictionary /// public override object CreateInstance( ITypeDescriptorContext context, IDictionary propertyValues ) { if (propertyValues.Contains("Value")) { var v = new V2d((V2d)(propertyValues["Value"])); return v; } else { return new V2d( (double)propertyValues["X0"], (double)propertyValues["X1"] ); } } /// /// Does this struct expose properties? /// public override bool GetPropertiesSupported(ITypeDescriptorContext context) { return true; } /// /// Return the properties of this struct /// public override PropertyDescriptorCollection GetProperties( ITypeDescriptorContext context, object value, Attribute[] attributes ) { return TypeDescriptor.GetProperties(value, attributes); } /// /// Check what this type can be created from /// public override bool CanConvertFrom( ITypeDescriptorContext context, System.Type sourceType ) { // Just strings for now bool canConvert = (sourceType == typeof(string)); if (!canConvert) canConvert = base.CanConvertFrom(context, sourceType); return canConvert; } /// /// Convert from a specified type to a V2d, if possible /// public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value ) { string sValue = value as string; object retVal = null; if (sValue != null) { // Check that the string actually has something in it... sValue = sValue.Trim(); if (sValue.Length != 0) { // Parse the string if (null == culture) culture = CultureInfo.CurrentCulture; // Split the string based on the cultures list separator var parms = sValue.Split( new char[] { culture.TextInfo.ListSeparator[0] } ); if (parms.Length == 2) { // Should have an integer and a string. var x0 = (double)Convert.ToDouble(parms[0]); var x1 = (double)Convert.ToDouble(parms[1]); // And finally create the object retVal = new V2d(x0, x1); } } } else { retVal = base.ConvertFrom(context, culture, value); } return retVal; } /// /// Check what the type can be converted to /// public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType ) { // InstanceDescriptor is used in the code behind bool canConvert = (destinationType == typeof(InstanceDescriptor)); if (!canConvert) canConvert = base.CanConvertFrom(context, destinationType); return canConvert; } /// /// Convert to a specified type /// public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType ) { object retVal = null; var v = (V2d)value; // If this is an instance descriptor... if (destinationType == typeof(InstanceDescriptor)) { var argTypes = new System.Type[2]; argTypes[0] = typeof(double); argTypes[1] = typeof(double); // Lookup the appropriate $TVector$ constructor ConstructorInfo constructor = typeof(V2d).GetConstructor(argTypes); var arguments = new object[2]; arguments[0] = v[0]; arguments[1] = v[1]; // And return an instance descriptor to the caller. // Will fill in the CodeBehind stuff in VS.Net retVal = new InstanceDescriptor(constructor, arguments); } else if (destinationType == typeof(string)) { // If it's a string, return one to the caller if (null == culture) culture = CultureInfo.CurrentCulture; var values = new string[2]; // I'm a bit of a culture vulture - do it properly! TypeConverter numberConverter = TypeDescriptor.GetConverter(typeof(double)); values[0] = numberConverter.ConvertToString(context, culture, v[0]); values[1] = numberConverter.ConvertToString(context, culture, v[1]); // A useful method - join an array of strings using a separator, in this instance the culture specific one retVal = String.Join(culture.TextInfo.ListSeparator + " ", values); } else retVal = base.ConvertTo(context, culture, value, destinationType); return retVal; } } ///////////////////////////////////////////////////////////////////// // dimension is 3 // primitive type is int // vector type is V3i [TypeConverter(typeof(V3iConverter))] public partial struct V3i { } public class V3iConverter : TypeConverter { /// /// Can the framework call CreateInstance? /// public override bool GetCreateInstanceSupported( ITypeDescriptorContext context) { return true; } /// /// Satisfy the CreateInstance call by reading data from the /// propertyValues dictionary /// public override object CreateInstance( ITypeDescriptorContext context, IDictionary propertyValues ) { if (propertyValues.Contains("Value")) { var v = new V3i((V3i)(propertyValues["Value"])); return v; } else { return new V3i( (int)propertyValues["X0"], (int)propertyValues["X1"], (int)propertyValues["X2"] ); } } /// /// Does this struct expose properties? /// public override bool GetPropertiesSupported(ITypeDescriptorContext context) { return true; } /// /// Return the properties of this struct /// public override PropertyDescriptorCollection GetProperties( ITypeDescriptorContext context, object value, Attribute[] attributes ) { return TypeDescriptor.GetProperties(value, attributes); } /// /// Check what this type can be created from /// public override bool CanConvertFrom( ITypeDescriptorContext context, System.Type sourceType ) { // Just strings for now bool canConvert = (sourceType == typeof(string)); if (!canConvert) canConvert = base.CanConvertFrom(context, sourceType); return canConvert; } /// /// Convert from a specified type to a V3i, if possible /// public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value ) { string sValue = value as string; object retVal = null; if (sValue != null) { // Check that the string actually has something in it... sValue = sValue.Trim(); if (sValue.Length != 0) { // Parse the string if (null == culture) culture = CultureInfo.CurrentCulture; // Split the string based on the cultures list separator var parms = sValue.Split( new char[] { culture.TextInfo.ListSeparator[0] } ); if (parms.Length == 3) { // Should have an integer and a string. var x0 = (int)Convert.ToDouble(parms[0]); var x1 = (int)Convert.ToDouble(parms[1]); var x2 = (int)Convert.ToDouble(parms[2]); // And finally create the object retVal = new V3i(x0, x1, x2); } } } else { retVal = base.ConvertFrom(context, culture, value); } return retVal; } /// /// Check what the type can be converted to /// public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType ) { // InstanceDescriptor is used in the code behind bool canConvert = (destinationType == typeof(InstanceDescriptor)); if (!canConvert) canConvert = base.CanConvertFrom(context, destinationType); return canConvert; } /// /// Convert to a specified type /// public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType ) { object retVal = null; var v = (V3i)value; // If this is an instance descriptor... if (destinationType == typeof(InstanceDescriptor)) { var argTypes = new System.Type[3]; argTypes[0] = typeof(int); argTypes[1] = typeof(int); argTypes[2] = typeof(int); // Lookup the appropriate $TVector$ constructor ConstructorInfo constructor = typeof(V3i).GetConstructor(argTypes); var arguments = new object[3]; arguments[0] = v[0]; arguments[1] = v[1]; arguments[2] = v[2]; // And return an instance descriptor to the caller. // Will fill in the CodeBehind stuff in VS.Net retVal = new InstanceDescriptor(constructor, arguments); } else if (destinationType == typeof(string)) { // If it's a string, return one to the caller if (null == culture) culture = CultureInfo.CurrentCulture; var values = new string[3]; // I'm a bit of a culture vulture - do it properly! TypeConverter numberConverter = TypeDescriptor.GetConverter(typeof(int)); values[0] = numberConverter.ConvertToString(context, culture, v[0]); values[1] = numberConverter.ConvertToString(context, culture, v[1]); values[2] = numberConverter.ConvertToString(context, culture, v[2]); // A useful method - join an array of strings using a separator, in this instance the culture specific one retVal = String.Join(culture.TextInfo.ListSeparator + " ", values); } else retVal = base.ConvertTo(context, culture, value, destinationType); return retVal; } } ///////////////////////////////////////////////////////////////////// // dimension is 3 // primitive type is long // vector type is V3l [TypeConverter(typeof(V3lConverter))] public partial struct V3l { } public class V3lConverter : TypeConverter { /// /// Can the framework call CreateInstance? /// public override bool GetCreateInstanceSupported( ITypeDescriptorContext context) { return true; } /// /// Satisfy the CreateInstance call by reading data from the /// propertyValues dictionary /// public override object CreateInstance( ITypeDescriptorContext context, IDictionary propertyValues ) { if (propertyValues.Contains("Value")) { var v = new V3l((V3l)(propertyValues["Value"])); return v; } else { return new V3l( (long)propertyValues["X0"], (long)propertyValues["X1"], (long)propertyValues["X2"] ); } } /// /// Does this struct expose properties? /// public override bool GetPropertiesSupported(ITypeDescriptorContext context) { return true; } /// /// Return the properties of this struct /// public override PropertyDescriptorCollection GetProperties( ITypeDescriptorContext context, object value, Attribute[] attributes ) { return TypeDescriptor.GetProperties(value, attributes); } /// /// Check what this type can be created from /// public override bool CanConvertFrom( ITypeDescriptorContext context, System.Type sourceType ) { // Just strings for now bool canConvert = (sourceType == typeof(string)); if (!canConvert) canConvert = base.CanConvertFrom(context, sourceType); return canConvert; } /// /// Convert from a specified type to a V3l, if possible /// public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value ) { string sValue = value as string; object retVal = null; if (sValue != null) { // Check that the string actually has something in it... sValue = sValue.Trim(); if (sValue.Length != 0) { // Parse the string if (null == culture) culture = CultureInfo.CurrentCulture; // Split the string based on the cultures list separator var parms = sValue.Split( new char[] { culture.TextInfo.ListSeparator[0] } ); if (parms.Length == 3) { // Should have an integer and a string. var x0 = (long)Convert.ToDouble(parms[0]); var x1 = (long)Convert.ToDouble(parms[1]); var x2 = (long)Convert.ToDouble(parms[2]); // And finally create the object retVal = new V3l(x0, x1, x2); } } } else { retVal = base.ConvertFrom(context, culture, value); } return retVal; } /// /// Check what the type can be converted to /// public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType ) { // InstanceDescriptor is used in the code behind bool canConvert = (destinationType == typeof(InstanceDescriptor)); if (!canConvert) canConvert = base.CanConvertFrom(context, destinationType); return canConvert; } /// /// Convert to a specified type /// public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType ) { object retVal = null; var v = (V3l)value; // If this is an instance descriptor... if (destinationType == typeof(InstanceDescriptor)) { var argTypes = new System.Type[3]; argTypes[0] = typeof(long); argTypes[1] = typeof(long); argTypes[2] = typeof(long); // Lookup the appropriate $TVector$ constructor ConstructorInfo constructor = typeof(V3l).GetConstructor(argTypes); var arguments = new object[3]; arguments[0] = v[0]; arguments[1] = v[1]; arguments[2] = v[2]; // And return an instance descriptor to the caller. // Will fill in the CodeBehind stuff in VS.Net retVal = new InstanceDescriptor(constructor, arguments); } else if (destinationType == typeof(string)) { // If it's a string, return one to the caller if (null == culture) culture = CultureInfo.CurrentCulture; var values = new string[3]; // I'm a bit of a culture vulture - do it properly! TypeConverter numberConverter = TypeDescriptor.GetConverter(typeof(long)); values[0] = numberConverter.ConvertToString(context, culture, v[0]); values[1] = numberConverter.ConvertToString(context, culture, v[1]); values[2] = numberConverter.ConvertToString(context, culture, v[2]); // A useful method - join an array of strings using a separator, in this instance the culture specific one retVal = String.Join(culture.TextInfo.ListSeparator + " ", values); } else retVal = base.ConvertTo(context, culture, value, destinationType); return retVal; } } ///////////////////////////////////////////////////////////////////// // dimension is 3 // primitive type is float // vector type is V3f [TypeConverter(typeof(V3fConverter))] public partial struct V3f { } public class V3fConverter : TypeConverter { /// /// Can the framework call CreateInstance? /// public override bool GetCreateInstanceSupported( ITypeDescriptorContext context) { return true; } /// /// Satisfy the CreateInstance call by reading data from the /// propertyValues dictionary /// public override object CreateInstance( ITypeDescriptorContext context, IDictionary propertyValues ) { if (propertyValues.Contains("Value")) { var v = new V3f((V3f)(propertyValues["Value"])); return v; } else { return new V3f( (float)propertyValues["X0"], (float)propertyValues["X1"], (float)propertyValues["X2"] ); } } /// /// Does this struct expose properties? /// public override bool GetPropertiesSupported(ITypeDescriptorContext context) { return true; } /// /// Return the properties of this struct /// public override PropertyDescriptorCollection GetProperties( ITypeDescriptorContext context, object value, Attribute[] attributes ) { return TypeDescriptor.GetProperties(value, attributes); } /// /// Check what this type can be created from /// public override bool CanConvertFrom( ITypeDescriptorContext context, System.Type sourceType ) { // Just strings for now bool canConvert = (sourceType == typeof(string)); if (!canConvert) canConvert = base.CanConvertFrom(context, sourceType); return canConvert; } /// /// Convert from a specified type to a V3f, if possible /// public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value ) { string sValue = value as string; object retVal = null; if (sValue != null) { // Check that the string actually has something in it... sValue = sValue.Trim(); if (sValue.Length != 0) { // Parse the string if (null == culture) culture = CultureInfo.CurrentCulture; // Split the string based on the cultures list separator var parms = sValue.Split( new char[] { culture.TextInfo.ListSeparator[0] } ); if (parms.Length == 3) { // Should have an integer and a string. var x0 = (float)Convert.ToDouble(parms[0]); var x1 = (float)Convert.ToDouble(parms[1]); var x2 = (float)Convert.ToDouble(parms[2]); // And finally create the object retVal = new V3f(x0, x1, x2); } } } else { retVal = base.ConvertFrom(context, culture, value); } return retVal; } /// /// Check what the type can be converted to /// public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType ) { // InstanceDescriptor is used in the code behind bool canConvert = (destinationType == typeof(InstanceDescriptor)); if (!canConvert) canConvert = base.CanConvertFrom(context, destinationType); return canConvert; } /// /// Convert to a specified type /// public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType ) { object retVal = null; var v = (V3f)value; // If this is an instance descriptor... if (destinationType == typeof(InstanceDescriptor)) { var argTypes = new System.Type[3]; argTypes[0] = typeof(float); argTypes[1] = typeof(float); argTypes[2] = typeof(float); // Lookup the appropriate $TVector$ constructor ConstructorInfo constructor = typeof(V3f).GetConstructor(argTypes); var arguments = new object[3]; arguments[0] = v[0]; arguments[1] = v[1]; arguments[2] = v[2]; // And return an instance descriptor to the caller. // Will fill in the CodeBehind stuff in VS.Net retVal = new InstanceDescriptor(constructor, arguments); } else if (destinationType == typeof(string)) { // If it's a string, return one to the caller if (null == culture) culture = CultureInfo.CurrentCulture; var values = new string[3]; // I'm a bit of a culture vulture - do it properly! TypeConverter numberConverter = TypeDescriptor.GetConverter(typeof(float)); values[0] = numberConverter.ConvertToString(context, culture, v[0]); values[1] = numberConverter.ConvertToString(context, culture, v[1]); values[2] = numberConverter.ConvertToString(context, culture, v[2]); // A useful method - join an array of strings using a separator, in this instance the culture specific one retVal = String.Join(culture.TextInfo.ListSeparator + " ", values); } else retVal = base.ConvertTo(context, culture, value, destinationType); return retVal; } } ///////////////////////////////////////////////////////////////////// // dimension is 3 // primitive type is double // vector type is V3d [TypeConverter(typeof(V3dConverter))] public partial struct V3d { } public class V3dConverter : TypeConverter { /// /// Can the framework call CreateInstance? /// public override bool GetCreateInstanceSupported( ITypeDescriptorContext context) { return true; } /// /// Satisfy the CreateInstance call by reading data from the /// propertyValues dictionary /// public override object CreateInstance( ITypeDescriptorContext context, IDictionary propertyValues ) { if (propertyValues.Contains("Value")) { var v = new V3d((V3d)(propertyValues["Value"])); return v; } else { return new V3d( (double)propertyValues["X0"], (double)propertyValues["X1"], (double)propertyValues["X2"] ); } } /// /// Does this struct expose properties? /// public override bool GetPropertiesSupported(ITypeDescriptorContext context) { return true; } /// /// Return the properties of this struct /// public override PropertyDescriptorCollection GetProperties( ITypeDescriptorContext context, object value, Attribute[] attributes ) { return TypeDescriptor.GetProperties(value, attributes); } /// /// Check what this type can be created from /// public override bool CanConvertFrom( ITypeDescriptorContext context, System.Type sourceType ) { // Just strings for now bool canConvert = (sourceType == typeof(string)); if (!canConvert) canConvert = base.CanConvertFrom(context, sourceType); return canConvert; } /// /// Convert from a specified type to a V3d, if possible /// public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value ) { string sValue = value as string; object retVal = null; if (sValue != null) { // Check that the string actually has something in it... sValue = sValue.Trim(); if (sValue.Length != 0) { // Parse the string if (null == culture) culture = CultureInfo.CurrentCulture; // Split the string based on the cultures list separator var parms = sValue.Split( new char[] { culture.TextInfo.ListSeparator[0] } ); if (parms.Length == 3) { // Should have an integer and a string. var x0 = (double)Convert.ToDouble(parms[0]); var x1 = (double)Convert.ToDouble(parms[1]); var x2 = (double)Convert.ToDouble(parms[2]); // And finally create the object retVal = new V3d(x0, x1, x2); } } } else { retVal = base.ConvertFrom(context, culture, value); } return retVal; } /// /// Check what the type can be converted to /// public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType ) { // InstanceDescriptor is used in the code behind bool canConvert = (destinationType == typeof(InstanceDescriptor)); if (!canConvert) canConvert = base.CanConvertFrom(context, destinationType); return canConvert; } /// /// Convert to a specified type /// public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType ) { object retVal = null; var v = (V3d)value; // If this is an instance descriptor... if (destinationType == typeof(InstanceDescriptor)) { var argTypes = new System.Type[3]; argTypes[0] = typeof(double); argTypes[1] = typeof(double); argTypes[2] = typeof(double); // Lookup the appropriate $TVector$ constructor ConstructorInfo constructor = typeof(V3d).GetConstructor(argTypes); var arguments = new object[3]; arguments[0] = v[0]; arguments[1] = v[1]; arguments[2] = v[2]; // And return an instance descriptor to the caller. // Will fill in the CodeBehind stuff in VS.Net retVal = new InstanceDescriptor(constructor, arguments); } else if (destinationType == typeof(string)) { // If it's a string, return one to the caller if (null == culture) culture = CultureInfo.CurrentCulture; var values = new string[3]; // I'm a bit of a culture vulture - do it properly! TypeConverter numberConverter = TypeDescriptor.GetConverter(typeof(double)); values[0] = numberConverter.ConvertToString(context, culture, v[0]); values[1] = numberConverter.ConvertToString(context, culture, v[1]); values[2] = numberConverter.ConvertToString(context, culture, v[2]); // A useful method - join an array of strings using a separator, in this instance the culture specific one retVal = String.Join(culture.TextInfo.ListSeparator + " ", values); } else retVal = base.ConvertTo(context, culture, value, destinationType); return retVal; } } ///////////////////////////////////////////////////////////////////// // dimension is 4 // primitive type is int // vector type is V4i [TypeConverter(typeof(V4iConverter))] public partial struct V4i { } public class V4iConverter : TypeConverter { /// /// Can the framework call CreateInstance? /// public override bool GetCreateInstanceSupported( ITypeDescriptorContext context) { return true; } /// /// Satisfy the CreateInstance call by reading data from the /// propertyValues dictionary /// public override object CreateInstance( ITypeDescriptorContext context, IDictionary propertyValues ) { if (propertyValues.Contains("Value")) { var v = new V4i((V4i)(propertyValues["Value"])); return v; } else { return new V4i( (int)propertyValues["X0"], (int)propertyValues["X1"], (int)propertyValues["X2"], (int)propertyValues["X3"] ); } } /// /// Does this struct expose properties? /// public override bool GetPropertiesSupported(ITypeDescriptorContext context) { return true; } /// /// Return the properties of this struct /// public override PropertyDescriptorCollection GetProperties( ITypeDescriptorContext context, object value, Attribute[] attributes ) { return TypeDescriptor.GetProperties(value, attributes); } /// /// Check what this type can be created from /// public override bool CanConvertFrom( ITypeDescriptorContext context, System.Type sourceType ) { // Just strings for now bool canConvert = (sourceType == typeof(string)); if (!canConvert) canConvert = base.CanConvertFrom(context, sourceType); return canConvert; } /// /// Convert from a specified type to a V4i, if possible /// public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value ) { string sValue = value as string; object retVal = null; if (sValue != null) { // Check that the string actually has something in it... sValue = sValue.Trim(); if (sValue.Length != 0) { // Parse the string if (null == culture) culture = CultureInfo.CurrentCulture; // Split the string based on the cultures list separator var parms = sValue.Split( new char[] { culture.TextInfo.ListSeparator[0] } ); if (parms.Length == 4) { // Should have an integer and a string. var x0 = (int)Convert.ToDouble(parms[0]); var x1 = (int)Convert.ToDouble(parms[1]); var x2 = (int)Convert.ToDouble(parms[2]); var x3 = (int)Convert.ToDouble(parms[3]); // And finally create the object retVal = new V4i(x0, x1, x2, x3); } } } else { retVal = base.ConvertFrom(context, culture, value); } return retVal; } /// /// Check what the type can be converted to /// public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType ) { // InstanceDescriptor is used in the code behind bool canConvert = (destinationType == typeof(InstanceDescriptor)); if (!canConvert) canConvert = base.CanConvertFrom(context, destinationType); return canConvert; } /// /// Convert to a specified type /// public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType ) { object retVal = null; var v = (V4i)value; // If this is an instance descriptor... if (destinationType == typeof(InstanceDescriptor)) { var argTypes = new System.Type[4]; argTypes[0] = typeof(int); argTypes[1] = typeof(int); argTypes[2] = typeof(int); argTypes[3] = typeof(int); // Lookup the appropriate $TVector$ constructor ConstructorInfo constructor = typeof(V4i).GetConstructor(argTypes); var arguments = new object[4]; arguments[0] = v[0]; arguments[1] = v[1]; arguments[2] = v[2]; arguments[3] = v[3]; // And return an instance descriptor to the caller. // Will fill in the CodeBehind stuff in VS.Net retVal = new InstanceDescriptor(constructor, arguments); } else if (destinationType == typeof(string)) { // If it's a string, return one to the caller if (null == culture) culture = CultureInfo.CurrentCulture; var values = new string[4]; // I'm a bit of a culture vulture - do it properly! TypeConverter numberConverter = TypeDescriptor.GetConverter(typeof(int)); values[0] = numberConverter.ConvertToString(context, culture, v[0]); values[1] = numberConverter.ConvertToString(context, culture, v[1]); values[2] = numberConverter.ConvertToString(context, culture, v[2]); values[3] = numberConverter.ConvertToString(context, culture, v[3]); // A useful method - join an array of strings using a separator, in this instance the culture specific one retVal = String.Join(culture.TextInfo.ListSeparator + " ", values); } else retVal = base.ConvertTo(context, culture, value, destinationType); return retVal; } } ///////////////////////////////////////////////////////////////////// // dimension is 4 // primitive type is long // vector type is V4l [TypeConverter(typeof(V4lConverter))] public partial struct V4l { } public class V4lConverter : TypeConverter { /// /// Can the framework call CreateInstance? /// public override bool GetCreateInstanceSupported( ITypeDescriptorContext context) { return true; } /// /// Satisfy the CreateInstance call by reading data from the /// propertyValues dictionary /// public override object CreateInstance( ITypeDescriptorContext context, IDictionary propertyValues ) { if (propertyValues.Contains("Value")) { var v = new V4l((V4l)(propertyValues["Value"])); return v; } else { return new V4l( (long)propertyValues["X0"], (long)propertyValues["X1"], (long)propertyValues["X2"], (long)propertyValues["X3"] ); } } /// /// Does this struct expose properties? /// public override bool GetPropertiesSupported(ITypeDescriptorContext context) { return true; } /// /// Return the properties of this struct /// public override PropertyDescriptorCollection GetProperties( ITypeDescriptorContext context, object value, Attribute[] attributes ) { return TypeDescriptor.GetProperties(value, attributes); } /// /// Check what this type can be created from /// public override bool CanConvertFrom( ITypeDescriptorContext context, System.Type sourceType ) { // Just strings for now bool canConvert = (sourceType == typeof(string)); if (!canConvert) canConvert = base.CanConvertFrom(context, sourceType); return canConvert; } /// /// Convert from a specified type to a V4l, if possible /// public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value ) { string sValue = value as string; object retVal = null; if (sValue != null) { // Check that the string actually has something in it... sValue = sValue.Trim(); if (sValue.Length != 0) { // Parse the string if (null == culture) culture = CultureInfo.CurrentCulture; // Split the string based on the cultures list separator var parms = sValue.Split( new char[] { culture.TextInfo.ListSeparator[0] } ); if (parms.Length == 4) { // Should have an integer and a string. var x0 = (long)Convert.ToDouble(parms[0]); var x1 = (long)Convert.ToDouble(parms[1]); var x2 = (long)Convert.ToDouble(parms[2]); var x3 = (long)Convert.ToDouble(parms[3]); // And finally create the object retVal = new V4l(x0, x1, x2, x3); } } } else { retVal = base.ConvertFrom(context, culture, value); } return retVal; } /// /// Check what the type can be converted to /// public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType ) { // InstanceDescriptor is used in the code behind bool canConvert = (destinationType == typeof(InstanceDescriptor)); if (!canConvert) canConvert = base.CanConvertFrom(context, destinationType); return canConvert; } /// /// Convert to a specified type /// public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType ) { object retVal = null; var v = (V4l)value; // If this is an instance descriptor... if (destinationType == typeof(InstanceDescriptor)) { var argTypes = new System.Type[4]; argTypes[0] = typeof(long); argTypes[1] = typeof(long); argTypes[2] = typeof(long); argTypes[3] = typeof(long); // Lookup the appropriate $TVector$ constructor ConstructorInfo constructor = typeof(V4l).GetConstructor(argTypes); var arguments = new object[4]; arguments[0] = v[0]; arguments[1] = v[1]; arguments[2] = v[2]; arguments[3] = v[3]; // And return an instance descriptor to the caller. // Will fill in the CodeBehind stuff in VS.Net retVal = new InstanceDescriptor(constructor, arguments); } else if (destinationType == typeof(string)) { // If it's a string, return one to the caller if (null == culture) culture = CultureInfo.CurrentCulture; var values = new string[4]; // I'm a bit of a culture vulture - do it properly! TypeConverter numberConverter = TypeDescriptor.GetConverter(typeof(long)); values[0] = numberConverter.ConvertToString(context, culture, v[0]); values[1] = numberConverter.ConvertToString(context, culture, v[1]); values[2] = numberConverter.ConvertToString(context, culture, v[2]); values[3] = numberConverter.ConvertToString(context, culture, v[3]); // A useful method - join an array of strings using a separator, in this instance the culture specific one retVal = String.Join(culture.TextInfo.ListSeparator + " ", values); } else retVal = base.ConvertTo(context, culture, value, destinationType); return retVal; } } ///////////////////////////////////////////////////////////////////// // dimension is 4 // primitive type is float // vector type is V4f [TypeConverter(typeof(V4fConverter))] public partial struct V4f { } public class V4fConverter : TypeConverter { /// /// Can the framework call CreateInstance? /// public override bool GetCreateInstanceSupported( ITypeDescriptorContext context) { return true; } /// /// Satisfy the CreateInstance call by reading data from the /// propertyValues dictionary /// public override object CreateInstance( ITypeDescriptorContext context, IDictionary propertyValues ) { if (propertyValues.Contains("Value")) { var v = new V4f((V4f)(propertyValues["Value"])); return v; } else { return new V4f( (float)propertyValues["X0"], (float)propertyValues["X1"], (float)propertyValues["X2"], (float)propertyValues["X3"] ); } } /// /// Does this struct expose properties? /// public override bool GetPropertiesSupported(ITypeDescriptorContext context) { return true; } /// /// Return the properties of this struct /// public override PropertyDescriptorCollection GetProperties( ITypeDescriptorContext context, object value, Attribute[] attributes ) { return TypeDescriptor.GetProperties(value, attributes); } /// /// Check what this type can be created from /// public override bool CanConvertFrom( ITypeDescriptorContext context, System.Type sourceType ) { // Just strings for now bool canConvert = (sourceType == typeof(string)); if (!canConvert) canConvert = base.CanConvertFrom(context, sourceType); return canConvert; } /// /// Convert from a specified type to a V4f, if possible /// public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value ) { string sValue = value as string; object retVal = null; if (sValue != null) { // Check that the string actually has something in it... sValue = sValue.Trim(); if (sValue.Length != 0) { // Parse the string if (null == culture) culture = CultureInfo.CurrentCulture; // Split the string based on the cultures list separator var parms = sValue.Split( new char[] { culture.TextInfo.ListSeparator[0] } ); if (parms.Length == 4) { // Should have an integer and a string. var x0 = (float)Convert.ToDouble(parms[0]); var x1 = (float)Convert.ToDouble(parms[1]); var x2 = (float)Convert.ToDouble(parms[2]); var x3 = (float)Convert.ToDouble(parms[3]); // And finally create the object retVal = new V4f(x0, x1, x2, x3); } } } else { retVal = base.ConvertFrom(context, culture, value); } return retVal; } /// /// Check what the type can be converted to /// public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType ) { // InstanceDescriptor is used in the code behind bool canConvert = (destinationType == typeof(InstanceDescriptor)); if (!canConvert) canConvert = base.CanConvertFrom(context, destinationType); return canConvert; } /// /// Convert to a specified type /// public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType ) { object retVal = null; var v = (V4f)value; // If this is an instance descriptor... if (destinationType == typeof(InstanceDescriptor)) { var argTypes = new System.Type[4]; argTypes[0] = typeof(float); argTypes[1] = typeof(float); argTypes[2] = typeof(float); argTypes[3] = typeof(float); // Lookup the appropriate $TVector$ constructor ConstructorInfo constructor = typeof(V4f).GetConstructor(argTypes); var arguments = new object[4]; arguments[0] = v[0]; arguments[1] = v[1]; arguments[2] = v[2]; arguments[3] = v[3]; // And return an instance descriptor to the caller. // Will fill in the CodeBehind stuff in VS.Net retVal = new InstanceDescriptor(constructor, arguments); } else if (destinationType == typeof(string)) { // If it's a string, return one to the caller if (null == culture) culture = CultureInfo.CurrentCulture; var values = new string[4]; // I'm a bit of a culture vulture - do it properly! TypeConverter numberConverter = TypeDescriptor.GetConverter(typeof(float)); values[0] = numberConverter.ConvertToString(context, culture, v[0]); values[1] = numberConverter.ConvertToString(context, culture, v[1]); values[2] = numberConverter.ConvertToString(context, culture, v[2]); values[3] = numberConverter.ConvertToString(context, culture, v[3]); // A useful method - join an array of strings using a separator, in this instance the culture specific one retVal = String.Join(culture.TextInfo.ListSeparator + " ", values); } else retVal = base.ConvertTo(context, culture, value, destinationType); return retVal; } } ///////////////////////////////////////////////////////////////////// // dimension is 4 // primitive type is double // vector type is V4d [TypeConverter(typeof(V4dConverter))] public partial struct V4d { } public class V4dConverter : TypeConverter { /// /// Can the framework call CreateInstance? /// public override bool GetCreateInstanceSupported( ITypeDescriptorContext context) { return true; } /// /// Satisfy the CreateInstance call by reading data from the /// propertyValues dictionary /// public override object CreateInstance( ITypeDescriptorContext context, IDictionary propertyValues ) { if (propertyValues.Contains("Value")) { var v = new V4d((V4d)(propertyValues["Value"])); return v; } else { return new V4d( (double)propertyValues["X0"], (double)propertyValues["X1"], (double)propertyValues["X2"], (double)propertyValues["X3"] ); } } /// /// Does this struct expose properties? /// public override bool GetPropertiesSupported(ITypeDescriptorContext context) { return true; } /// /// Return the properties of this struct /// public override PropertyDescriptorCollection GetProperties( ITypeDescriptorContext context, object value, Attribute[] attributes ) { return TypeDescriptor.GetProperties(value, attributes); } /// /// Check what this type can be created from /// public override bool CanConvertFrom( ITypeDescriptorContext context, System.Type sourceType ) { // Just strings for now bool canConvert = (sourceType == typeof(string)); if (!canConvert) canConvert = base.CanConvertFrom(context, sourceType); return canConvert; } /// /// Convert from a specified type to a V4d, if possible /// public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value ) { string sValue = value as string; object retVal = null; if (sValue != null) { // Check that the string actually has something in it... sValue = sValue.Trim(); if (sValue.Length != 0) { // Parse the string if (null == culture) culture = CultureInfo.CurrentCulture; // Split the string based on the cultures list separator var parms = sValue.Split( new char[] { culture.TextInfo.ListSeparator[0] } ); if (parms.Length == 4) { // Should have an integer and a string. var x0 = (double)Convert.ToDouble(parms[0]); var x1 = (double)Convert.ToDouble(parms[1]); var x2 = (double)Convert.ToDouble(parms[2]); var x3 = (double)Convert.ToDouble(parms[3]); // And finally create the object retVal = new V4d(x0, x1, x2, x3); } } } else { retVal = base.ConvertFrom(context, culture, value); } return retVal; } /// /// Check what the type can be converted to /// public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType ) { // InstanceDescriptor is used in the code behind bool canConvert = (destinationType == typeof(InstanceDescriptor)); if (!canConvert) canConvert = base.CanConvertFrom(context, destinationType); return canConvert; } /// /// Convert to a specified type /// public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType ) { object retVal = null; var v = (V4d)value; // If this is an instance descriptor... if (destinationType == typeof(InstanceDescriptor)) { var argTypes = new System.Type[4]; argTypes[0] = typeof(double); argTypes[1] = typeof(double); argTypes[2] = typeof(double); argTypes[3] = typeof(double); // Lookup the appropriate $TVector$ constructor ConstructorInfo constructor = typeof(V4d).GetConstructor(argTypes); var arguments = new object[4]; arguments[0] = v[0]; arguments[1] = v[1]; arguments[2] = v[2]; arguments[3] = v[3]; // And return an instance descriptor to the caller. // Will fill in the CodeBehind stuff in VS.Net retVal = new InstanceDescriptor(constructor, arguments); } else if (destinationType == typeof(string)) { // If it's a string, return one to the caller if (null == culture) culture = CultureInfo.CurrentCulture; var values = new string[4]; // I'm a bit of a culture vulture - do it properly! TypeConverter numberConverter = TypeDescriptor.GetConverter(typeof(double)); values[0] = numberConverter.ConvertToString(context, culture, v[0]); values[1] = numberConverter.ConvertToString(context, culture, v[1]); values[2] = numberConverter.ConvertToString(context, culture, v[2]); values[3] = numberConverter.ConvertToString(context, culture, v[3]); // A useful method - join an array of strings using a separator, in this instance the culture specific one retVal = String.Join(culture.TextInfo.ListSeparator + " ", values); } else retVal = base.ConvertTo(context, culture, value, destinationType); return retVal; } } } ================================================ FILE: src/Aardvark.Base/Math/Vectors/VectorTypeConverter_template.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.Design.Serialization; using System.Globalization; using System.Reflection; using System.Text; // AUTO-GENERATED CODE - DO NOT EDIT! namespace Aardvark.Base { /*# for (int Dim = 2; Dim <= 4; Dim++) { foreach (var TPrimitive in new string[] { "int", "long", "float", "double" }) { var TVector = "V" + Dim + TPrimitive[0]; */ ///////////////////////////////////////////////////////////////////// // dimension is __Dim__ // primitive type is __TPrimitive__ // vector type is __TVector__ [TypeConverter(typeof(__TVector__Converter))] public partial struct __TVector__ { } public class __TVector__Converter : TypeConverter { /// /// Can the framework call CreateInstance? /// public override bool GetCreateInstanceSupported( ITypeDescriptorContext context) { return true; } /// /// Satisfy the CreateInstance call by reading data from the /// propertyValues dictionary /// public override object CreateInstance( ITypeDescriptorContext context, IDictionary propertyValues ) { if (propertyValues.Contains("Value")) { var v = new __TVector__((__TVector__)(propertyValues["Value"])); return v; } else { return new __TVector__( //# for (int i = 0; i < Dim; i++) { (__TPrimitive__)propertyValues["X__i__"]__(i < Dim-1)?", ":""__ //# } ); } } /// /// Does this struct expose properties? /// public override bool GetPropertiesSupported(ITypeDescriptorContext context) { return true; } /// /// Return the properties of this struct /// public override PropertyDescriptorCollection GetProperties( ITypeDescriptorContext context, object value, Attribute[] attributes ) { return TypeDescriptor.GetProperties(value, attributes); } /// /// Check what this type can be created from /// public override bool CanConvertFrom( ITypeDescriptorContext context, System.Type sourceType ) { // Just strings for now bool canConvert = (sourceType == typeof(string)); if (!canConvert) canConvert = base.CanConvertFrom(context, sourceType); return canConvert; } /// /// Convert from a specified type to a __TVector__, if possible /// public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value ) { string sValue = value as string; object retVal = null; if (sValue != null) { // Check that the string actually has something in it... sValue = sValue.Trim(); if (sValue.Length != 0) { // Parse the string if (null == culture) culture = CultureInfo.CurrentCulture; // Split the string based on the cultures list separator var parms = sValue.Split( new char[] { culture.TextInfo.ListSeparator[0] } ); if (parms.Length == __Dim__) { // Should have an integer and a string. //# for (int i = 0; i < Dim; i++) { var x__i__ = (__TPrimitive__)Convert.ToDouble(parms[__i__]); //# } // And finally create the object /*# var elements = new List(); for (int i = 0; i < Dim; i++) elements.Add("x" + i); */ retVal = new __TVector__(__elements.Join(", ")__); } } } else { retVal = base.ConvertFrom(context, culture, value); } return retVal; } /// /// Check what the type can be converted to /// public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType ) { // InstanceDescriptor is used in the code behind bool canConvert = (destinationType == typeof(InstanceDescriptor)); if (!canConvert) canConvert = base.CanConvertFrom(context, destinationType); return canConvert; } /// /// Convert to a specified type /// public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType ) { object retVal = null; var v = (__TVector__)value; // If this is an instance descriptor... if (destinationType == typeof(InstanceDescriptor)) { var argTypes = new System.Type[__Dim__]; //# for (int i = 0; i < Dim; i++) { argTypes[__i__] = typeof(__TPrimitive__); //# } // Lookup the appropriate $TVector$ constructor ConstructorInfo constructor = typeof(__TVector__).GetConstructor(argTypes); var arguments = new object[__Dim__]; //# for (int i = 0; i < Dim; i++) { arguments[__i__] = v[__i__]; //# } // And return an instance descriptor to the caller. // Will fill in the CodeBehind stuff in VS.Net retVal = new InstanceDescriptor(constructor, arguments); } else if (destinationType == typeof(string)) { // If it's a string, return one to the caller if (null == culture) culture = CultureInfo.CurrentCulture; var values = new string[__Dim__]; // I'm a bit of a culture vulture - do it properly! TypeConverter numberConverter = TypeDescriptor.GetConverter(typeof(__TPrimitive__)); //# for (int i = 0; i < Dim; i++) { values[__i__] = numberConverter.ConvertToString(context, culture, v[__i__]); //# } // A useful method - join an array of strings using a separator, in this instance the culture specific one retVal = String.Join(culture.TextInfo.ListSeparator + " ", values); } else retVal = base.ConvertTo(context, culture, value, destinationType); return retVal; } } //# } //# } } ================================================ FILE: src/Aardvark.Base/Math/Vectors/Vector_auto.cs ================================================ using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Xml.Serialization; #if NETCOREAPP3_1_OR_GREATER using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics; #endif using Aardbase = Aardvark.Base; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! [Flags] public enum DirFlags { None = 0x00, NegativeX = 0x01, PositiveX = 0x02, NegativeY = 0x04, PositiveY = 0x08, NegativeZ = 0x10, PositiveZ = 0x20, NegativeW = 0x40, PositiveW = 0x80, X = NegativeX | PositiveX, Y = NegativeY | PositiveY, Z = NegativeZ | PositiveZ, }; #region V2i [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct V2i : IVector, ISize2i, IFormattable, IEquatable { [DataMember] public int X; [DataMember] public int Y; #region Constructors /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(int x, int y) { X = x; Y = y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(int v) { X = v; Y = v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(int[] a) { X = a[0]; Y = a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(int[] a, int start) { X = a[start + 0]; Y = a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(uint x, uint y) { X = (int)x; Y = (int)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(uint v) { X = (int)v; Y = (int)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(uint[] a) { X = (int)a[0]; Y = (int)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(uint[] a, int start) { X = (int)a[start + 0]; Y = (int)a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(long x, long y) { X = (int)x; Y = (int)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(long v) { X = (int)v; Y = (int)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(long[] a) { X = (int)a[0]; Y = (int)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(long[] a, int start) { X = (int)a[start + 0]; Y = (int)a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(float x, float y) { X = (int)x; Y = (int)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(float v) { X = (int)v; Y = (int)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(float[] a) { X = (int)a[0]; Y = (int)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(float[] a, int start) { X = (int)a[start + 0]; Y = (int)a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(double x, double y) { X = (int)x; Y = (int)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(double v) { X = (int)v; Y = (int)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(double[] a) { X = (int)a[0]; Y = (int)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(double[] a, int start) { X = (int)a[start + 0]; Y = (int)a[start + 1]; } /// /// Creates a vector from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(Func index_fun) { X = index_fun(0); Y = index_fun(1); } /// /// Creates a vector from a general vector implementing the IVector<int> interface. /// The caller has to verify that the dimension of is at least 2. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(IVector v) : this(v[0], v[1]) { } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(V2i v) { X = v.X; Y = v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(V2ui v) { X = (int)v.X; Y = (int)v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(V2l v) { X = (int)v.X; Y = (int)v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(V2f v) { X = (int)v.X; Y = (int)v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(V2d v) { X = (int)v.X; Y = (int)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(V3i v) { X = v.X; Y = v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(V3ui v) { X = (int)v.X; Y = (int)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(V3l v) { X = (int)v.X; Y = (int)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(V3f v) { X = (int)v.X; Y = (int)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(V3d v) { X = (int)v.X; Y = (int)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(V4i v) { X = v.X; Y = v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(V4ui v) { X = (int)v.X; Y = (int)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(V4l v) { X = (int)v.X; Y = (int)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(V4f v) { X = (int)v.X; Y = (int)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2i(V4d v) { X = (int)v.X; Y = (int)v.Y; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(V2ui v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(V2l v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(V2f v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(V2d v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(V3i v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(V3ui v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(V3l v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(V3f v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(V3d v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(V4i v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(V4ui v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(V4l v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(V4f v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(V4d v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui ToV2ui() => (V2ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToV2l() => (V2l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f ToV2f() => (V2f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d ToV2d() => (V2d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int[](V2i v) => new int[] { v.X, v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(int[] v) => new V2i(v[0], v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](V2i v) => new uint[] { (uint)v.X, (uint)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(uint[] v) => new V2i((int)v[0], (int)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long[](V2i v) => new long[] { (long)v.X, (long)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(long[] v) => new V2i((int)v[0], (int)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](V2i v) => new float[] { (float)v.X, (float)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(float[] v) => new V2i((int)v[0], (int)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](V2i v) => new double[] { (double)v.X, (double)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2i(double[] v) => new V2i((int)v[0], (int)v[1]); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i Copy(Func element_fun) => new V2i(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i Copy(Func element_index_fun) => new V2i(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(int[] array, int start) { array[start + 0] = X; array[start + 1] = Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui Copy(Func element_fun) => new V2ui(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui Copy(Func element_index_fun) => new V2ui(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(uint[] array, int start) { array[start + 0] = (uint)X; array[start + 1] = (uint)Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l Copy(Func element_fun) => new V2l(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l Copy(Func element_index_fun) => new V2l(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(long[] array, int start) { array[start + 0] = (long)X; array[start + 1] = (long)Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f Copy(Func element_fun) => new V2f(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f Copy(Func element_index_fun) => new V2f(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(float[] array, int start) { array[start + 0] = (float)X; array[start + 1] = (float)Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d Copy(Func element_fun) => new V2d(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d Copy(Func element_index_fun) => new V2d(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(double[] array, int start) { array[start + 0] = (double)X; array[start + 1] = (double)Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(X); array[start + 1] = element_fun(Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(X, 0); array[start + 1] = element_index_fun(Y, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int[] ToArray() => new int[] { X, Y }; #endregion #region Properties and Indexers /// /// Property for the field X. /// Useful when properties are required, but the field X is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public int P_X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value; } } /// /// Property for the field Y. /// Useful when properties are required, but the field Y is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public int P_Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Y = value; } } /// /// Enumerates all elements of this vector. /// public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return X; yield return Y; } } /// /// Gets or sets element with given index. /// public unsafe int this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (int* ptr = &X) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (int* ptr = &X) { ptr[index] = value; } } } /// /// Returns the index of the largest dimension of the vector. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X >= Y ? 0 : 1; } } /// /// Returns the index of the smallest dimension of the vector. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X <= Y ? 0 : 1; } } /// /// Returns the minimum element of the vector. /// public readonly int MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(X, Y); } /// /// Returns the maximum element of the vector. /// public readonly int MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(X, Y); } #endregion #region Constants /// /// Number of elements in this vector. /// public const int Dimension = 2; /// /// All elements zero. /// public static V2i Zero { get { return new V2i(0, 0); } } /// /// All elements one. /// public static V2i One { get { return new V2i(1, 1); } } /// /// All elements set to maximum possible value. /// public static V2i MaxValue { get { return new V2i(Constant.ParseableMaxValue, Constant.ParseableMaxValue); } } /// /// All elements set to minimum possible value. /// public static V2i MinValue { get { return new V2i(Constant.ParseableMinValue, Constant.ParseableMinValue); } } /// /// Normalized X-axis. /// public static V2i XAxis { get { return new V2i(1, 0); } } /// /// Normalized Y-axis. /// public static V2i YAxis { get { return new V2i(0, 1); } } /// /// An array of accessor functions for the coordinates of the vector. /// public static readonly Func[] SelectorArray = new Func[] { v => v.X, v => v.Y }; /// /// Element getter function. /// public static readonly Func Getter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref V2i v, int i, int s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; default: throw new IndexOutOfRangeException(); } }; /// /// Element getter function with long index. /// public static readonly Func LongGetter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action with long index. /// public static readonly ActionRefValVal LongSetter = (ref V2i v, long i, int s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Static factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i FromV2ui(V2ui v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i FromV2l(V2l v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i FromV2f(V2f v) => new V2i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i FromV2d(V2d v) => new V2i(v); #endregion #region Norms /// /// Returns the squared length of the vector. /// public readonly int LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X * X + Y * Y ; } } /// /// Returns the length of the vector. /// public readonly double Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y ); } } /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// public readonly int Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Abs(X) + Fun.Abs(Y); } } /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y); } } /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// public readonly int NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(Fun.Abs(X), Fun.Abs(Y)); } } /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// public readonly int NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(Fun.Abs(X), Fun.Abs(Y)); } } /// /// Returns a normalized copy of this vector. /// public readonly V2d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Length; if (s == 0) return V2d.Zero; s = 1 / s; return new V2d(X * s, Y * s); } } /// /// Vector rotated 90° counter clockwise: (-Y, X) /// public readonly V2i Rot90 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2i(-Y, X); } } /// /// Vector rotated 180° counter clockwise: (-X, -Y) /// public readonly V2i Rot180 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2i(-X, -Y); } } /// /// Vector rotated 270° counter clockwise: (Y, -X) /// public readonly V2i Rot270 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2i(Y, -X); } } #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Abs(V2i v) => v.Abs(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i LinearInterp(float t, V2i a, V2i b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i LinearInterp(V2f t, V2i a, V2i b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i LinearInterp(double t, V2i a, V2i b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i LinearInterp(V2d t, V2i a, V2i b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Min(V2i v0, V2i v1) => Fun.Min(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Min(V2i v, int x) => Fun.Min(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Max(V2i v0, V2i v1) => Fun.Max(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Max(V2i v, int x) => Fun.Max(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Saturate(V2i v) => Fun.Saturate(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i DivideByInt(V2i v, int x) => v / x; #endregion #region Operations /// /// Sets the elements of a vector to the given int elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(int x, int y) { X = x; Y = y; } /// /// Sets the elements of a vector to the given uint elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(uint x, uint y) { X = (int)x; Y = (int)y; } /// /// Sets the elements of a vector to the given long elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(long x, long y) { X = (int)x; Y = (int)y; } /// /// Sets the elements of a vector to the given float elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(float x, float y) { X = (int)x; Y = (int)y; } /// /// Sets the elements of a vector to the given double elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(double x, double y) { X = (int)x; Y = (int)y; } /// /// Returns a negated copy of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator -(V2i v) => new V2i(-v.X, -v.Y); /// /// Returns the component-wise bitwise complement of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator ~(V2i v) => new V2i(~v.X, ~v.Y); /// /// Returns a vector that is orthogonal to this one (i.e. {x,y} -> {-y,x}). /// public readonly V2i Orthogonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2i(-Y, X); } } /// /// Returns the component-wise sum of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator +(V2i a, V2i b) => new V2i(a.X + b.X, a.Y + b.Y); /// /// Returns the component-wise sum of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator +(V2i v, int s) => new V2i(v.X + s, v.Y + s); /// /// Returns the component-wise sum of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator +(int s, V2i v) => new V2i(s + v.X, s + v.Y); /// /// Returns the component-wise difference of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator -(V2i a, V2i b) => new V2i(a.X - b.X, a.Y - b.Y); /// /// Returns the component-wise difference of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator -(V2i v, int s) => new V2i(v.X - s, v.Y - s); /// /// Returns the component-wise difference of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator -(int s, V2i v) => new V2i(s - v.X, s - v.Y); /// /// Returns the component-wise product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator *(V2i a, V2i b) => new V2i(a.X * b.X, a.Y * b.Y); /// /// Returns the component-wise product of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator *(V2i v, int s) => new V2i(v.X * s, v.Y * s); /// /// Returns the component-wise product of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator *(int s, V2i v) => new V2i(s * v.X, s * v.Y); /// /// Returns the component-wise fraction of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator /(V2i a, V2i b) => new V2i(a.X / b.X, a.Y / b.Y); /// /// Returns the component-wise fraction of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator /(V2i v, int s) => new V2i(v.X / s, v.Y / s); /// /// Returns the component-wise fraction of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator /(int s, V2i v) => new V2i(s / v.X, s / v.Y); /// /// Returns the component-wise remainder of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator %(V2i a, V2i b) => new V2i(a.X % b.X, a.Y % b.Y); /// /// Returns the component-wise remainder of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator %(V2i v, int s) => new V2i(v.X % s, v.Y % s); /// /// Returns the component-wise remainder of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator %(int s, V2i v) => new V2i(s % v.X, s % v.Y); /// /// Returns the component-wise bitwise and of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator &(V2i a, V2i b) => new V2i(a.X & b.X, a.Y & b.Y); /// /// Returns the component-wise bitwise and of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator &(V2i v, int s) => new V2i(v.X & s, v.Y & s); /// /// Returns the component-wise bitwise and of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator &(int s, V2i v) => new V2i(s & v.X, s & v.Y); /// /// Returns the component-wise bitwise or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator |(V2i a, V2i b) => new V2i(a.X | b.X, a.Y | b.Y); /// /// Returns the component-wise bitwise or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator |(V2i v, int s) => new V2i(v.X | s, v.Y | s); /// /// Returns the component-wise bitwise or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator |(int s, V2i v) => new V2i(s | v.X, s | v.Y); /// /// Returns the component-wise bitwise exclusive or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator ^(V2i a, V2i b) => new V2i(a.X ^ b.X, a.Y ^ b.Y); /// /// Returns the component-wise bitwise exclusive or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator ^(V2i v, int s) => new V2i(v.X ^ s, v.Y ^ s); /// /// Returns the component-wise bitwise exclusive or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator ^(int s, V2i v) => new V2i(s ^ v.X, s ^ v.Y); /// /// Returns the component-wise left bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator <<(V2i v, int s) => new V2i(v.X << s, v.Y << s); /// /// Returns the component-wise right bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i operator >>(V2i v, int s) => new V2i(v.X >> s, v.Y >> s); /// Attention: NEVER implement operators <, <=, >=, >, /// since these are not defined in a Vector space. /// Use AllSmaller() and similar comparators! #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V2i a, V2i b) { return a.X == b.X && a.Y == b.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V2i v, int s) { return v.X == s && v.Y == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(int s, V2i v) { return s == v.X && s == v.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V2i a, V2i b) { return a.X != b.X || a.Y != b.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V2i v, int s) { return v.X != s || v.Y != s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(int s, V2i v) { return s != v.X || s != v.Y; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(V2i other) { return X.Equals(other.X) && Y.Equals(other.Y); } #endregion #region Overrides public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + X.ToString(format, fp) + between + Y.ToString(format, fp) + end; } public override readonly int GetHashCode() { return HashCode.GetCombined(X, Y); } public override readonly bool Equals(object other) => (other is V2i o) ? Equals(o) : false; public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + X.ToString(null, CultureInfo.InvariantCulture) + ", " + Y.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Parsing public static V2i Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new V2i( int.Parse(x[0], CultureInfo.InvariantCulture), int.Parse(x[1], CultureInfo.InvariantCulture) ); } public static V2i Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, V2i.Setter); } public static V2i Parse(Text t, int bracketLevel) { return t.NestedBracketSplit(bracketLevel, Text.Parse, V2i.Setter); } #endregion #region Swizzle Methods [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2i OO => new V2i(0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2i OI => new V2i(0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2i ON => new V2i(0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i OX => new V2i(0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i OY => new V2i(0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2i IO => new V2i(1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2i II => new V2i(1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2i PN => new V2i(1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i IX => new V2i(1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i IY => new V2i(1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2i NO => new V2i(-1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2i NP => new V2i(-1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2i NN => new V2i(-1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i NX => new V2i(-1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i NY => new V2i(-1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i XO => new V2i(X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i XI => new V2i(X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i XN => new V2i(X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i XX => new V2i(X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i XY { readonly get => new V2i(X, Y); set { X = value.X; Y = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i YO => new V2i(Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i YI => new V2i(Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i YN => new V2i(Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i YX { readonly get => new V2i(Y, X); set { Y = value.X; X = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i YY => new V2i(Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OOX => new V3i(0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OOY => new V3i(0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OIX => new V3i(0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OIY => new V3i(0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ONX => new V3i(0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ONY => new V3i(0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXO => new V3i(0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXI => new V3i(0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXN => new V3i(0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXX => new V3i(0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXY => new V3i(0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYO => new V3i(0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYI => new V3i(0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYN => new V3i(0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYX => new V3i(0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYY => new V3i(0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IOX => new V3i(1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IOY => new V3i(1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IIX => new V3i(1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IIY => new V3i(1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PNX => new V3i(1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PNY => new V3i(1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IXO => new V3i(1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IXI => new V3i(1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PXN => new V3i(1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IXX => new V3i(1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IXY => new V3i(1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IYO => new V3i(1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IYI => new V3i(1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PYN => new V3i(1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IYX => new V3i(1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IYY => new V3i(1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NOX => new V3i(-1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NOY => new V3i(-1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NPX => new V3i(-1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NPY => new V3i(-1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NNX => new V3i(-1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NNY => new V3i(-1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXO => new V3i(-1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXP => new V3i(-1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXN => new V3i(-1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXX => new V3i(-1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXY => new V3i(-1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYO => new V3i(-1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYP => new V3i(-1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYN => new V3i(-1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYX => new V3i(-1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYY => new V3i(-1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XOO => new V3i(X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XOI => new V3i(X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XON => new V3i(X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XOX => new V3i(X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XOY => new V3i(X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XIO => new V3i(X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XII => new V3i(X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XPN => new V3i(X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XIX => new V3i(X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XIY => new V3i(X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNO => new V3i(X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNP => new V3i(X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNN => new V3i(X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNX => new V3i(X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNY => new V3i(X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXO => new V3i(X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXI => new V3i(X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXN => new V3i(X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXX => new V3i(X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXY => new V3i(X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XYO => new V3i(X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XYI => new V3i(X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XYN => new V3i(X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XYX => new V3i(X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XYY => new V3i(X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YOO => new V3i(Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YOI => new V3i(Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YON => new V3i(Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YOX => new V3i(Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YOY => new V3i(Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YIO => new V3i(Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YII => new V3i(Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YPN => new V3i(Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YIX => new V3i(Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YIY => new V3i(Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNO => new V3i(Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNP => new V3i(Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNN => new V3i(Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNX => new V3i(Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNY => new V3i(Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YXO => new V3i(Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YXI => new V3i(Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YXN => new V3i(Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YXX => new V3i(Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YXY => new V3i(Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYO => new V3i(Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYI => new V3i(Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYN => new V3i(Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYX => new V3i(Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYY => new V3i(Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOOX => new V4i(0, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOOY => new V4i(0, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOIX => new V4i(0, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOIY => new V4i(0, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OONX => new V4i(0, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OONY => new V4i(0, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXO => new V4i(0, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXI => new V4i(0, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXN => new V4i(0, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXX => new V4i(0, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXY => new V4i(0, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYO => new V4i(0, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYI => new V4i(0, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYN => new V4i(0, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYX => new V4i(0, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYY => new V4i(0, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIOX => new V4i(0, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIOY => new V4i(0, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIIX => new V4i(0, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIIY => new V4i(0, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPNX => new V4i(0, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPNY => new V4i(0, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIXO => new V4i(0, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIXI => new V4i(0, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPXN => new V4i(0, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIXX => new V4i(0, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIXY => new V4i(0, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIYO => new V4i(0, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIYI => new V4i(0, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPYN => new V4i(0, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIYX => new V4i(0, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIYY => new V4i(0, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONOX => new V4i(0, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONOY => new V4i(0, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONPX => new V4i(0, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONPY => new V4i(0, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONNX => new V4i(0, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONNY => new V4i(0, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXO => new V4i(0, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXP => new V4i(0, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXN => new V4i(0, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXX => new V4i(0, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXY => new V4i(0, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYO => new V4i(0, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYP => new V4i(0, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYN => new V4i(0, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYX => new V4i(0, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYY => new V4i(0, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXOO => new V4i(0, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXOI => new V4i(0, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXON => new V4i(0, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXOX => new V4i(0, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXOY => new V4i(0, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXIO => new V4i(0, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXII => new V4i(0, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXPN => new V4i(0, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXIX => new V4i(0, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXIY => new V4i(0, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNO => new V4i(0, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNP => new V4i(0, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNN => new V4i(0, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNX => new V4i(0, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNY => new V4i(0, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXO => new V4i(0, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXI => new V4i(0, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXN => new V4i(0, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXX => new V4i(0, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXY => new V4i(0, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYO => new V4i(0, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYI => new V4i(0, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYN => new V4i(0, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYX => new V4i(0, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYY => new V4i(0, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYOO => new V4i(0, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYOI => new V4i(0, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYON => new V4i(0, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYOX => new V4i(0, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYOY => new V4i(0, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYIO => new V4i(0, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYII => new V4i(0, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYPN => new V4i(0, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYIX => new V4i(0, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYIY => new V4i(0, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNO => new V4i(0, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNP => new V4i(0, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNN => new V4i(0, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNX => new V4i(0, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNY => new V4i(0, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXO => new V4i(0, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXI => new V4i(0, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXN => new V4i(0, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXX => new V4i(0, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXY => new V4i(0, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYO => new V4i(0, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYI => new V4i(0, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYN => new V4i(0, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYX => new V4i(0, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYY => new V4i(0, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOOX => new V4i(1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOOY => new V4i(1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOIX => new V4i(1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOIY => new V4i(1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PONX => new V4i(1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PONY => new V4i(1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOXO => new V4i(1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOXI => new V4i(1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i POXN => new V4i(1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOXX => new V4i(1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOXY => new V4i(1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOYO => new V4i(1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOYI => new V4i(1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i POYN => new V4i(1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOYX => new V4i(1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOYY => new V4i(1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIOX => new V4i(1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIOY => new V4i(1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIIX => new V4i(1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIIY => new V4i(1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPNX => new V4i(1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPNY => new V4i(1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIXO => new V4i(1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIXI => new V4i(1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPXN => new V4i(1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIXX => new V4i(1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIXY => new V4i(1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIYO => new V4i(1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIYI => new V4i(1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPYN => new V4i(1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIYX => new V4i(1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIYY => new V4i(1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNOX => new V4i(1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNOY => new V4i(1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNPX => new V4i(1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNPY => new V4i(1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNNX => new V4i(1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNNY => new V4i(1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXO => new V4i(1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXP => new V4i(1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXN => new V4i(1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXX => new V4i(1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXY => new V4i(1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYO => new V4i(1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYP => new V4i(1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYN => new V4i(1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYX => new V4i(1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYY => new V4i(1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXOO => new V4i(1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXOI => new V4i(1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXON => new V4i(1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXOX => new V4i(1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXOY => new V4i(1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXIO => new V4i(1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXII => new V4i(1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXPN => new V4i(1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXIX => new V4i(1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXIY => new V4i(1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNO => new V4i(1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNP => new V4i(1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNN => new V4i(1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNX => new V4i(1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNY => new V4i(1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXXO => new V4i(1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXXI => new V4i(1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXXN => new V4i(1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXXX => new V4i(1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXXY => new V4i(1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXYO => new V4i(1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXYI => new V4i(1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXYN => new V4i(1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXYX => new V4i(1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXYY => new V4i(1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYOO => new V4i(1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYOI => new V4i(1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYON => new V4i(1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYOX => new V4i(1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYOY => new V4i(1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYIO => new V4i(1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYII => new V4i(1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYPN => new V4i(1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYIX => new V4i(1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYIY => new V4i(1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNO => new V4i(1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNP => new V4i(1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNN => new V4i(1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNX => new V4i(1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNY => new V4i(1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYXO => new V4i(1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYXI => new V4i(1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYXN => new V4i(1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYXX => new V4i(1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYXY => new V4i(1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYYO => new V4i(1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYYI => new V4i(1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYYN => new V4i(1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYYX => new V4i(1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYYY => new V4i(1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOOX => new V4i(-1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOOY => new V4i(-1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOPX => new V4i(-1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOPY => new V4i(-1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NONX => new V4i(-1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NONY => new V4i(-1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXO => new V4i(-1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXP => new V4i(-1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXN => new V4i(-1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXX => new V4i(-1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXY => new V4i(-1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYO => new V4i(-1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYP => new V4i(-1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYN => new V4i(-1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYX => new V4i(-1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYY => new V4i(-1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPOX => new V4i(-1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPOY => new V4i(-1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPPX => new V4i(-1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPPY => new V4i(-1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPNX => new V4i(-1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPNY => new V4i(-1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXO => new V4i(-1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXP => new V4i(-1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXN => new V4i(-1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXX => new V4i(-1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXY => new V4i(-1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYO => new V4i(-1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYP => new V4i(-1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYN => new V4i(-1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYX => new V4i(-1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYY => new V4i(-1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNOX => new V4i(-1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNOY => new V4i(-1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNPX => new V4i(-1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNPY => new V4i(-1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNNX => new V4i(-1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNNY => new V4i(-1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXO => new V4i(-1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXP => new V4i(-1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXN => new V4i(-1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXX => new V4i(-1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXY => new V4i(-1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYO => new V4i(-1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYP => new V4i(-1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYN => new V4i(-1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYX => new V4i(-1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYY => new V4i(-1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXOO => new V4i(-1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXOP => new V4i(-1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXON => new V4i(-1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXOX => new V4i(-1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXOY => new V4i(-1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPO => new V4i(-1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPP => new V4i(-1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPN => new V4i(-1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPX => new V4i(-1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPY => new V4i(-1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNO => new V4i(-1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNP => new V4i(-1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNN => new V4i(-1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNX => new V4i(-1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNY => new V4i(-1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXO => new V4i(-1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXP => new V4i(-1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXN => new V4i(-1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXX => new V4i(-1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXY => new V4i(-1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYO => new V4i(-1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYP => new V4i(-1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYN => new V4i(-1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYX => new V4i(-1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYY => new V4i(-1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYOO => new V4i(-1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYOP => new V4i(-1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYON => new V4i(-1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYOX => new V4i(-1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYOY => new V4i(-1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPO => new V4i(-1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPP => new V4i(-1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPN => new V4i(-1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPX => new V4i(-1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPY => new V4i(-1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNO => new V4i(-1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNP => new V4i(-1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNN => new V4i(-1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNX => new V4i(-1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNY => new V4i(-1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXO => new V4i(-1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXP => new V4i(-1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXN => new V4i(-1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXX => new V4i(-1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXY => new V4i(-1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYO => new V4i(-1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYP => new V4i(-1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYN => new V4i(-1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYX => new V4i(-1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYY => new V4i(-1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOOO => new V4i(X, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOOI => new V4i(X, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOON => new V4i(X, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOOX => new V4i(X, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOOY => new V4i(X, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOIO => new V4i(X, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOII => new V4i(X, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOPN => new V4i(X, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOIX => new V4i(X, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOIY => new V4i(X, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONO => new V4i(X, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONP => new V4i(X, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONN => new V4i(X, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONX => new V4i(X, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONY => new V4i(X, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXO => new V4i(X, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXI => new V4i(X, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXN => new V4i(X, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXX => new V4i(X, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXY => new V4i(X, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYO => new V4i(X, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYI => new V4i(X, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYN => new V4i(X, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYX => new V4i(X, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYY => new V4i(X, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIOO => new V4i(X, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIOI => new V4i(X, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPON => new V4i(X, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIOX => new V4i(X, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIOY => new V4i(X, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIIO => new V4i(X, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIII => new V4i(X, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPPN => new V4i(X, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIIX => new V4i(X, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIIY => new V4i(X, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNO => new V4i(X, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNP => new V4i(X, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNN => new V4i(X, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNX => new V4i(X, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNY => new V4i(X, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIXO => new V4i(X, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIXI => new V4i(X, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPXN => new V4i(X, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIXX => new V4i(X, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIXY => new V4i(X, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIYO => new V4i(X, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIYI => new V4i(X, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPYN => new V4i(X, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIYX => new V4i(X, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIYY => new V4i(X, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNOO => new V4i(X, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNOP => new V4i(X, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNON => new V4i(X, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNOX => new V4i(X, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNOY => new V4i(X, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPO => new V4i(X, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPP => new V4i(X, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPN => new V4i(X, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPX => new V4i(X, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPY => new V4i(X, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNO => new V4i(X, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNP => new V4i(X, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNN => new V4i(X, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNX => new V4i(X, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNY => new V4i(X, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXO => new V4i(X, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXP => new V4i(X, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXN => new V4i(X, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXX => new V4i(X, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXY => new V4i(X, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYO => new V4i(X, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYP => new V4i(X, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYN => new V4i(X, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYX => new V4i(X, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYY => new V4i(X, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXOO => new V4i(X, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXOI => new V4i(X, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXON => new V4i(X, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXOX => new V4i(X, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXOY => new V4i(X, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXIO => new V4i(X, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXII => new V4i(X, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXPN => new V4i(X, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXIX => new V4i(X, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXIY => new V4i(X, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNO => new V4i(X, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNP => new V4i(X, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNN => new V4i(X, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNX => new V4i(X, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNY => new V4i(X, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXO => new V4i(X, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXI => new V4i(X, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXN => new V4i(X, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXX => new V4i(X, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXY => new V4i(X, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYO => new V4i(X, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYI => new V4i(X, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYN => new V4i(X, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYX => new V4i(X, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYY => new V4i(X, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYOO => new V4i(X, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYOI => new V4i(X, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYON => new V4i(X, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYOX => new V4i(X, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYOY => new V4i(X, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYIO => new V4i(X, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYII => new V4i(X, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYPN => new V4i(X, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYIX => new V4i(X, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYIY => new V4i(X, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNO => new V4i(X, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNP => new V4i(X, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNN => new V4i(X, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNX => new V4i(X, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNY => new V4i(X, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXO => new V4i(X, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXI => new V4i(X, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXN => new V4i(X, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXX => new V4i(X, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXY => new V4i(X, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYO => new V4i(X, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYI => new V4i(X, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYN => new V4i(X, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYX => new V4i(X, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYY => new V4i(X, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOOO => new V4i(Y, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOOI => new V4i(Y, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOON => new V4i(Y, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOOX => new V4i(Y, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOOY => new V4i(Y, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOIO => new V4i(Y, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOII => new V4i(Y, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOPN => new V4i(Y, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOIX => new V4i(Y, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOIY => new V4i(Y, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONO => new V4i(Y, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONP => new V4i(Y, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONN => new V4i(Y, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONX => new V4i(Y, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONY => new V4i(Y, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXO => new V4i(Y, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXI => new V4i(Y, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXN => new V4i(Y, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXX => new V4i(Y, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXY => new V4i(Y, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYO => new V4i(Y, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYI => new V4i(Y, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYN => new V4i(Y, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYX => new V4i(Y, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYY => new V4i(Y, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIOO => new V4i(Y, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIOI => new V4i(Y, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPON => new V4i(Y, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIOX => new V4i(Y, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIOY => new V4i(Y, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIIO => new V4i(Y, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIII => new V4i(Y, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPPN => new V4i(Y, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIIX => new V4i(Y, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIIY => new V4i(Y, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNO => new V4i(Y, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNP => new V4i(Y, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNN => new V4i(Y, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNX => new V4i(Y, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNY => new V4i(Y, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIXO => new V4i(Y, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIXI => new V4i(Y, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPXN => new V4i(Y, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIXX => new V4i(Y, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIXY => new V4i(Y, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIYO => new V4i(Y, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIYI => new V4i(Y, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPYN => new V4i(Y, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIYX => new V4i(Y, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIYY => new V4i(Y, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNOO => new V4i(Y, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNOP => new V4i(Y, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNON => new V4i(Y, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNOX => new V4i(Y, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNOY => new V4i(Y, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPO => new V4i(Y, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPP => new V4i(Y, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPN => new V4i(Y, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPX => new V4i(Y, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPY => new V4i(Y, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNO => new V4i(Y, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNP => new V4i(Y, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNN => new V4i(Y, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNX => new V4i(Y, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNY => new V4i(Y, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXO => new V4i(Y, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXP => new V4i(Y, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXN => new V4i(Y, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXX => new V4i(Y, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXY => new V4i(Y, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYO => new V4i(Y, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYP => new V4i(Y, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYN => new V4i(Y, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYX => new V4i(Y, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYY => new V4i(Y, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXOO => new V4i(Y, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXOI => new V4i(Y, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXON => new V4i(Y, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXOX => new V4i(Y, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXOY => new V4i(Y, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXIO => new V4i(Y, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXII => new V4i(Y, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXPN => new V4i(Y, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXIX => new V4i(Y, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXIY => new V4i(Y, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNO => new V4i(Y, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNP => new V4i(Y, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNN => new V4i(Y, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNX => new V4i(Y, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNY => new V4i(Y, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXO => new V4i(Y, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXI => new V4i(Y, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXN => new V4i(Y, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXX => new V4i(Y, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXY => new V4i(Y, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYO => new V4i(Y, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYI => new V4i(Y, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYN => new V4i(Y, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYX => new V4i(Y, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYY => new V4i(Y, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYOO => new V4i(Y, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYOI => new V4i(Y, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYON => new V4i(Y, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYOX => new V4i(Y, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYOY => new V4i(Y, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYIO => new V4i(Y, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYII => new V4i(Y, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYPN => new V4i(Y, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYIX => new V4i(Y, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYIY => new V4i(Y, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNO => new V4i(Y, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNP => new V4i(Y, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNN => new V4i(Y, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNX => new V4i(Y, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNY => new V4i(Y, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXO => new V4i(Y, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXI => new V4i(Y, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXN => new V4i(Y, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXX => new V4i(Y, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXY => new V4i(Y, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYO => new V4i(Y, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYI => new V4i(Y, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYN => new V4i(Y, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYX => new V4i(Y, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYY => new V4i(Y, Y, Y, Y); #endregion #region IVector Members /// /// By using long indices, the IVector<double> interface is /// accessed. /// public double this[long i] { readonly get { return (double)this[(int)i]; } set { this[(int)i] = (int)value; } } #endregion #region ISize2i Members public readonly V2i Size2i { get { return this; } } #endregion #region IVector public readonly long Dim { get { return 2; } } public readonly object GetValue(long index) { return (object)this[(int)index]; } public void SetValue(object value, long index) { this[(int)index] = (int)value; } #endregion } public class V2iEqualityComparer : IEqualityComparer { public static V2iEqualityComparer Default => new V2iEqualityComparer(); #region IEqualityComparer Members public bool Equals(V2i v0, V2i v1) { return v0 == v1; } public int GetHashCode(V2i v) { return v.GetHashCode(); } #endregion } public static partial class Fun { #region Min and Max /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Min(this V2i a, V2i b) { return new V2i(Min(a.X, b.X), Min(a.Y, b.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Min(this V2i a, int b) { return new V2i(Min(a.X, b), Min(a.Y, b)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Min(this int a, V2i b) { return new V2i(Min(a, b.X), Min(a, b.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Max(this V2i a, V2i b) { return new V2i(Max(a.X, b.X), Max(a.Y, b.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Max(this V2i a, int b) { return new V2i(Max(a.X, b), Max(a.Y, b)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Max(this int a, V2i b) { return new V2i(Max(a, b.X), Max(a, b.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Min(this V2i a, V2i b, V2i c) { return new V2i(Min(a.X, b.X, c.X), Min(a.Y, b.Y, c.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Max(this V2i a, V2i b, V2i c) { return new V2i(Max(a.X, b.X, c.X), Max(a.Y, b.Y, c.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Min(this V2i a, V2i b, V2i c, V2i d) { return new V2i(Min(a.X, b.X, c.X, d.X), Min(a.Y, b.Y, c.Y, d.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Max(this V2i a, V2i b, V2i c, V2i d) { return new V2i(Max(a.X, b.X, c.X, d.X), Max(a.Y, b.Y, c.Y, d.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Min(this V2i x, params V2i[] values) { return new V2i(Min(x.X, values.Map(a => a.X)), Min(x.Y, values.Map(a => a.Y))); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Max(this V2i x, params V2i[] values) { return new V2i(Max(x.X, values.Map(a => a.X)), Max(x.Y, values.Map(a => a.Y))); } #endregion #region Abs /// /// Applies Fun.Abs to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Abs(this V2i x) { return new V2i(Abs(x.X), Abs(x.Y)); } #endregion #region Clamping /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Clamp(this V2i x, V2i a, V2i b) { return new V2i(Clamp(x.X, a.X, b.X), Clamp(x.Y, a.Y, b.Y)); } /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Clamp(this V2i x, int a, int b) { return new V2i(Clamp(x.X, a, b), Clamp(x.Y, a, b)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i ClampExcl(this V2i x, V2i a, V2i b) { return new V2i(ClampExcl(x.X, a.X, b.X), ClampExcl(x.Y, a.Y, b.Y)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i ClampExcl(this V2i x, int a, int b) { return new V2i(ClampExcl(x.X, a, b), ClampExcl(x.Y, a, b)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i ClampWrap(this V2i x, V2i a, V2i b) { return new V2i(ClampWrap(x.X, a.X, b.X), ClampWrap(x.Y, a.Y, b.Y)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i ClampWrap(this V2i x, int a, int b) { return new V2i(ClampWrap(x.X, a, b), ClampWrap(x.Y, a, b)); } /// /// Applies Fun.Saturate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Saturate(this V2i x) { return new V2i(Saturate(x.X), Saturate(x.Y)); } #endregion #region Sign /// /// Applies Fun.Sign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Sign(this V2i x) { return new V2i(Sign(x.X), Sign(x.Y)); } /// /// Applies Fun.Signumi to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Signumi(this V2i x) { return new V2i(Signumi(x.X), Signumi(x.Y)); } /// /// Applies Fun.Signum to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Signum(this V2i x) { return new V2i(Signum(x.X), Signum(x.Y)); } #endregion #region Multiply-Add /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i MultiplyAdd(V2i x, V2i y, V2i z) { return new V2i(MultiplyAdd(x.X, y.X, z.X), MultiplyAdd(x.Y, y.Y, z.Y)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i MultiplyAdd(V2i x, int y, V2i z) { return new V2i(MultiplyAdd(x.X, y, z.X), MultiplyAdd(x.Y, y, z.Y)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i MultiplyAdd(int x, V2i y, V2i z) { return new V2i(MultiplyAdd(x, y.X, z.X), MultiplyAdd(x, y.Y, z.Y)); } #endregion #region Roots /// /// Applies Fun.Sqrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Sqrt(this V2i x) { return new V2d(Sqrt(x.X), Sqrt(x.Y)); } /// /// Applies Fun.Cbrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Cbrt(this V2i x) { return new V2d(Cbrt(x.X), Cbrt(x.Y)); } #endregion #region Square /// /// Applies Fun.Square to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Square(this V2i x) { return new V2i(Square(x.X), Square(x.Y)); } #endregion #region Power /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Pown(this V2i x, V2i y) { return new V2i(Pown(x.X, y.X), Pown(x.Y, y.Y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Pown(this V2i x, int y) { return new V2i(Pown(x.X, y), Pown(x.Y, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Pown(this int x, V2i y) { return new V2i(Pown(x, y.X), Pown(x, y.Y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Pow(this V2i x, V2f y) { return new V2f(Pow(x.X, y.X), Pow(x.Y, y.Y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Pow(this V2i x, float y) { return new V2f(Pow(x.X, y), Pow(x.Y, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Pow(this int x, V2f y) { return new V2f(Pow(x, y.X), Pow(x, y.Y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Pow(this V2i x, V2d y) { return new V2d(Pow(x.X, y.X), Pow(x.Y, y.Y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Pow(this V2i x, double y) { return new V2d(Pow(x.X, y), Pow(x.Y, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Pow(this int x, V2d y) { return new V2d(Pow(x, y.X), Pow(x, y.Y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Power(this V2i x, V2f y) { return new V2f(Power(x.X, y.X), Power(x.Y, y.Y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Power(this V2i x, float y) { return new V2f(Power(x.X, y), Power(x.Y, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Power(this int x, V2f y) { return new V2f(Power(x, y.X), Power(x, y.Y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Power(this V2i x, V2d y) { return new V2d(Power(x.X, y.X), Power(x.Y, y.Y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Power(this V2i x, double y) { return new V2d(Power(x.X, y), Power(x.Y, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Power(this int x, V2d y) { return new V2d(Power(x, y.X), Power(x, y.Y)); } #endregion #region Exp and Log /// /// Applies Fun.Exp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Exp(this V2i x) { return new V2d(Exp(x.X), Exp(x.Y)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log(this V2i x) { return new V2d(Log(x.X), Log(x.Y)); } /// /// Applies Fun.Log2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log2(this V2i x) { return new V2d(Log2(x.X), Log2(x.Y)); } /// /// Applies Fun.Log2Int to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Log2Int(this V2i x) { return new V2i(Log2Int(x.X), Log2Int(x.Y)); } /// /// Applies Fun.Log10 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log10(this V2i x) { return new V2d(Log10(x.X), Log10(x.Y)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log(this V2i x, double basis) { return new V2d(Log(x.X, basis), Log(x.Y, basis)); } #endregion #region ModP /// /// Applies Fun.ModP to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i ModP(this V2i a, V2i b) { return new V2i(ModP(a.X, b.X), ModP(a.Y, b.Y)); } #endregion #region Power of Two /// /// Applies Fun.PowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l PowerOfTwo(this V2i x) { return new V2l(PowerOfTwo(x.X), PowerOfTwo(x.Y)); } /// /// Applies Fun.NextPowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i NextPowerOfTwo(this V2i x) { return new V2i(NextPowerOfTwo(x.X), NextPowerOfTwo(x.Y)); } /// /// Applies Fun.PrevPowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i PrevPowerOfTwo(this V2i x) { return new V2i(PrevPowerOfTwo(x.X), PrevPowerOfTwo(x.Y)); } #endregion #region Step functions /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Step(this V2i x, V2i edge) { return new V2i(Step(x.X, edge.X), Step(x.Y, edge.Y)); } /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Step(this V2i x, int edge) { return new V2i(Step(x.X, edge), Step(x.Y, edge)); } #endregion #region Interpolation /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Lerp(this float t, V2i a, V2i b) { return new V2i(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Lerp(this V2f t, V2i a, V2i b) { return new V2i(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Lerp(this double t, V2i a, V2i b) { return new V2i(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Lerp(this V2d t, V2i a, V2i b) { return new V2i(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y)); } /// /// Applies Fun.InvLerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d InvLerp(this V2i y, V2i a, V2i b) { return new V2d(InvLerp(y.X, a.X, b.X), InvLerp(y.Y, a.Y, b.Y)); } #endregion #region Common Divisor and Multiple /// /// Applies Fun.GreatestCommonDivisor to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i GreatestCommonDivisor(this V2i a, V2i b) { return new V2i(GreatestCommonDivisor(a.X, b.X), GreatestCommonDivisor(a.Y, b.Y)); } /// /// Applies Fun.LeastCommonMultiple to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i LeastCommonMultiple(this V2i a, V2i b) { return new V2i(LeastCommonMultiple(a.X, b.X), LeastCommonMultiple(a.Y, b.Y)); } #endregion #region Floating point bits /// /// Applies Fun.FloatFromBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f FloatFromBits(this V2i x) { return new V2f(FloatFromBits(x.X), FloatFromBits(x.Y)); } #endregion #region ApproximateEquals /// /// Returns whether the given vectors are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V2i a, V2i b, int tolerance) { return ApproximateEquals(a.X, b.X, tolerance) && ApproximateEquals(a.Y, b.Y, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this V2i v, int epsilon) => Vec.AllTiny(v, epsilon); #endregion } /// /// Contains static methods /// public static partial class Vec { #region Length /// /// Returns the squared length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LengthSquared(V2i v) => v.LengthSquared; /// /// Returns the length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Length(V2i v) => v.Length; #endregion #region Normalize /// /// Returns a normalized copy of this vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Normalized(V2i v) => v.Normalized; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Norm1(V2i v) => v.Norm1; /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(V2i v) => v.Norm2; /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NormMax(V2i v) => v.NormMax; /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NormMin(V2i v) => v.NormMin; /// /// Gets the p-norm. This is calculated as the p-th root of (|x|^n + |y|^n + ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this V2i v, double p) { return ( Fun.Abs(v.X).Pow(p) + Fun.Abs(v.Y).Pow(p)).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the squared distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int DistanceSquared(this V2i a, V2i b) => Fun.Square(b.X - a.X) + Fun.Square(b.Y - a.Y); /// /// Returns the distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V2i a, V2i b) => Fun.Sqrt(DistanceSquared(a, b)); /// /// Returns the Manhatten (or 1-) distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Distance1(this V2i a, V2i b) => Fun.Abs(b.X - a.X) + Fun.Abs(b.Y - a.Y); /// /// Returns the p-distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V2i a, V2i b, double p) => (Fun.Abs(b.X - a.X).Pow(p) + Fun.Abs(b.Y - a.Y).Pow(p)).Pow(1 / p); /// /// Returns the maximal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int DistanceMax(this V2i a, V2i b) => Fun.Max(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y)); /// /// Returns the minimal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int DistanceMin(this V2i a, V2i b) => Fun.Min(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y)); /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V2i query, V2i p0, V2i p1) { return DistanceToLine((V2d) query, (V2d) p0, (V2d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V2i query, V2i p0, V2i p1) { return DistanceToInfiniteLine((V2d) query, (V2d) p0, (V2d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V2i query, V2i p0, V2i p1, out double t) { return DistanceToLine((V2d) query, (V2d) p0, (V2d) p1, out t); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V2i query, V2i p0, V2i p1, out double t) { return DistanceToInfiniteLine((V2d) query, (V2d) p0, (V2d) p1, out t); } #endregion #region Operations /// /// Returns a vector that is orthogonal to the given one (i.e. {x,y} -> {-y,x}). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Orthogonal(V2i v) => v.Orthogonal; /// /// Negates the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Negate(this ref V2i v) { v.X = -v.X; v.Y = -v.Y; } /// /// Returns the outer product (tensor-product) of a * b^T as a 2x2 matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22i Outer(this V2i a, V2i b) { return new M22i( a.X * b.X, a.X * b.Y, a.Y * b.X, a.Y * b.Y); } /// /// Returns the dot product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Dot(this V2i a, V2i b) { return a.X * b.X + a.Y * b.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DirFlags DirFlags(this V2i v) { DirFlags flags = Aardbase.DirFlags.None; if (v.X > 0) flags |= Aardbase.DirFlags.PositiveX; if (v.X < 0) flags |= Aardbase.DirFlags.NegativeX; if (v.Y > 0) flags |= Aardbase.DirFlags.PositiveY; if (v.Y < 0) flags |= Aardbase.DirFlags.NegativeY; return flags; } /// /// Returns the cross product of vector a. /// In 2D the cross product is simply a vector that is normal /// to the given vector (i.e. {x,y} -> {-y,x}) /// public static V2i Cross(this V2i a) { return new V2i(-a.Y, a.X); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V2i a, V2i b) { return (a.X < b.X && a.Y < b.Y); } /// /// Returns whether ALL elements of v are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V2i v, int s) { return (v.X < s && v.Y < s); } /// /// Returns whether a is Smaller ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(int s, V2i v) { return (s < v.X && s < v.Y); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V2i a, V2i b) { return (a.X < b.X || a.Y < b.Y); } /// /// Returns whether AT LEAST ONE element of v is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V2i v, int s) { return (v.X < s || v.Y < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(int s, V2i v) { return (s < v.X || s < v.Y); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V2i a, V2i b) { return (a.X > b.X && a.Y > b.Y); } /// /// Returns whether ALL elements of v are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V2i v, int s) { return (v.X > s && v.Y > s); } /// /// Returns whether a is Greater ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(int s, V2i v) { return (s > v.X && s > v.Y); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V2i a, V2i b) { return (a.X > b.X || a.Y > b.Y); } /// /// Returns whether AT LEAST ONE element of v is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V2i v, int s) { return (v.X > s || v.Y > s); } /// /// Returns whether a is Greater AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(int s, V2i v) { return (s > v.X || s > v.Y); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V2i a, V2i b) { return (a.X <= b.X && a.Y <= b.Y); } /// /// Returns whether ALL elements of v are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V2i v, int s) { return (v.X <= s && v.Y <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(int s, V2i v) { return (s <= v.X && s <= v.Y); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V2i a, V2i b) { return (a.X <= b.X || a.Y <= b.Y); } /// /// Returns whether AT LEAST ONE element of v is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V2i v, int s) { return (v.X <= s || v.Y <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(int s, V2i v) { return (s <= v.X || s <= v.Y); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V2i a, V2i b) { return (a.X >= b.X && a.Y >= b.Y); } /// /// Returns whether ALL elements of v are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V2i v, int s) { return (v.X >= s && v.Y >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(int s, V2i v) { return (s >= v.X && s >= v.Y); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V2i a, V2i b) { return (a.X >= b.X || a.Y >= b.Y); } /// /// Returns whether AT LEAST ONE element of v is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V2i v, int s) { return (v.X >= s || v.Y >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(int s, V2i v) { return (s >= v.X || s >= v.Y); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V2i a, V2i b) { return (a.X == b.X && a.Y == b.Y); } /// /// Returns whether ALL elements of v are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V2i v, int s) { return (v.X == s && v.Y == s); } /// /// Returns whether a is Equal ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(int s, V2i v) { return (s == v.X && s == v.Y); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V2i a, V2i b) { return (a.X == b.X || a.Y == b.Y); } /// /// Returns whether AT LEAST ONE element of v is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V2i v, int s) { return (v.X == s || v.Y == s); } /// /// Returns whether a is Equal AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(int s, V2i v) { return (s == v.X || s == v.Y); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V2i a, V2i b) { return (a.X != b.X && a.Y != b.Y); } /// /// Returns whether ALL elements of v are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V2i v, int s) { return (v.X != s && v.Y != s); } /// /// Returns whether a is Different ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(int s, V2i v) { return (s != v.X && s != v.Y); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V2i a, V2i b) { return (a.X != b.X || a.Y != b.Y); } /// /// Returns whether AT LEAST ONE element of v is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V2i v, int s) { return (v.X != s || v.Y != s); } /// /// Returns whether a is Different AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(int s, V2i v) { return (s != v.X || s != v.Y); } /// /// Compare x-coordinate before y-coordinate, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this V2i v0, V2i v1) { if (v0.X < v1.X) return -1; if (v0.X > v1.X) return +1; if (v0.Y < v1.Y) return -1; if (v0.Y > v1.Y) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MinElement(V2i v) => v.MinElement; /// /// Returns the maximum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MaxElement(V2i v) => v.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this V2i v, int epsilon) => v.X.IsTiny(epsilon) || v.Y.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this V2i v, int epsilon) => v.X.IsTiny(epsilon) && v.Y.IsTiny(epsilon); #endregion #region ArrayExtensions public static int IndexOfClosestPoint(this V2i[] pointArray, V2i point) { var bestDist = DistanceSquared(point, pointArray[0]); int bestIndex = 0; int count = pointArray.Length; for (int i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this V2i[] array, int start, int count, V2i point) { var bestDist = DistanceSquared(point, array[start]); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this T[] array, int start, int count, Func pointSelector, V2i point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint(this V2i[] pointArray, V2i point) { var bestDist = DistanceSquared(point, pointArray[0]); long bestIndex = 0; long count = pointArray.LongLength; for (long i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this V2i[] array, long start, long count, V2i point) { var bestDist = DistanceSquared(point, array[start]); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this T[] array, long start, long count, Func pointSelector, V2i point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static int IndexOfMinX(this V2i[] vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static long LongIndexOfMinX(this V2i[] vectorArray, long count = 0) { var minimum = vectorArray[0].X; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static int IndexOfMaxX(this V2i[] vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static long LongIndexOfMaxX(this V2i[] vectorArray, long count = 0) { var maximum = vectorArray[0].X; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static int IndexOfMinY(this V2i[] vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static long LongIndexOfMinY(this V2i[] vectorArray, long count = 0) { var minimum = vectorArray[0].Y; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static int IndexOfMaxY(this V2i[] vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static long LongIndexOfMaxY(this V2i[] vectorArray, long count = 0) { var maximum = vectorArray[0].Y; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the list. /// public static int IndexOfMinX(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the list. /// public static int IndexOfMaxX(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the list. /// public static int IndexOfMinY(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the list. /// public static int IndexOfMaxY(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the array of the index-th coordinate of each vector. /// public static int[] CopyCoord(this V2i[] self, int index) { switch (index) { case 0: return self.Map(v => v.X); case 1: return self.Map(v => v.Y); default: throw new IndexOutOfRangeException(); } } #endregion } public static class IRandomUniformV2iExtensions { #region IRandomUniform extensions for V2i /// /// Uses UniformInt() to generate the elements of a V2i vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i UniformV2i(this IRandomUniform rnd) { return new V2i(rnd.UniformInt(), rnd.UniformInt()); } /// /// Uses UniformIntNonZero() to generate the elements of a V2i vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i UniformV2iNonZero(this IRandomUniform rnd) { return new V2i(rnd.UniformIntNonZero(), rnd.UniformIntNonZero()); } /// /// Uses UniformInt(int) to generate the elements of a V2i vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i UniformV2i(this IRandomUniform rnd, int size) { return new V2i(rnd.UniformInt(size), rnd.UniformInt(size)); } /// /// Uses UniformInt(int) to generate the elements of a V2i vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i UniformV2i(this IRandomUniform rnd, V2i size) { return new V2i(rnd.UniformInt(size.X), rnd.UniformInt(size.Y)); } #endregion } #endregion #region V2ui [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct V2ui : IVector, ISize2ui, IFormattable, IEquatable { [DataMember] public uint X; [DataMember] public uint Y; #region Constructors /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(int x, int y) { X = (uint)x; Y = (uint)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(int v) { X = (uint)v; Y = (uint)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(int[] a) { X = (uint)a[0]; Y = (uint)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(int[] a, int start) { X = (uint)a[start + 0]; Y = (uint)a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(uint x, uint y) { X = x; Y = y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(uint v) { X = v; Y = v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(uint[] a) { X = a[0]; Y = a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(uint[] a, int start) { X = a[start + 0]; Y = a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(long x, long y) { X = (uint)x; Y = (uint)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(long v) { X = (uint)v; Y = (uint)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(long[] a) { X = (uint)a[0]; Y = (uint)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(long[] a, int start) { X = (uint)a[start + 0]; Y = (uint)a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(float x, float y) { X = (uint)x; Y = (uint)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(float v) { X = (uint)v; Y = (uint)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(float[] a) { X = (uint)a[0]; Y = (uint)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(float[] a, int start) { X = (uint)a[start + 0]; Y = (uint)a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(double x, double y) { X = (uint)x; Y = (uint)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(double v) { X = (uint)v; Y = (uint)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(double[] a) { X = (uint)a[0]; Y = (uint)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(double[] a, int start) { X = (uint)a[start + 0]; Y = (uint)a[start + 1]; } /// /// Creates a vector from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(Func index_fun) { X = index_fun(0); Y = index_fun(1); } /// /// Creates a vector from a general vector implementing the IVector<uint> interface. /// The caller has to verify that the dimension of is at least 2. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(IVector v) : this(v[0], v[1]) { } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(V2i v) { X = (uint)v.X; Y = (uint)v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(V2ui v) { X = v.X; Y = v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(V2l v) { X = (uint)v.X; Y = (uint)v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(V2f v) { X = (uint)v.X; Y = (uint)v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(V2d v) { X = (uint)v.X; Y = (uint)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(V3i v) { X = (uint)v.X; Y = (uint)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(V3ui v) { X = v.X; Y = v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(V3l v) { X = (uint)v.X; Y = (uint)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(V3f v) { X = (uint)v.X; Y = (uint)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(V3d v) { X = (uint)v.X; Y = (uint)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(V4i v) { X = (uint)v.X; Y = (uint)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(V4ui v) { X = v.X; Y = v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(V4l v) { X = (uint)v.X; Y = (uint)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(V4f v) { X = (uint)v.X; Y = (uint)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2ui(V4d v) { X = (uint)v.X; Y = (uint)v.Y; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(V2i v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(V2l v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(V2f v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(V2d v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(V3i v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(V3ui v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(V3l v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(V3f v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(V3d v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(V4i v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(V4ui v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(V4l v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(V4f v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(V4d v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToV2i() => (V2i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToV2l() => (V2l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f ToV2f() => (V2f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d ToV2d() => (V2d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int[](V2ui v) => new int[] { (int)v.X, (int)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(int[] v) => new V2ui((uint)v[0], (uint)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](V2ui v) => new uint[] { v.X, v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(uint[] v) => new V2ui(v[0], v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long[](V2ui v) => new long[] { (long)v.X, (long)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(long[] v) => new V2ui((uint)v[0], (uint)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](V2ui v) => new float[] { (float)v.X, (float)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(float[] v) => new V2ui((uint)v[0], (uint)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](V2ui v) => new double[] { (double)v.X, (double)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2ui(double[] v) => new V2ui((uint)v[0], (uint)v[1]); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i Copy(Func element_fun) => new V2i(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i Copy(Func element_index_fun) => new V2i(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(int[] array, int start) { array[start + 0] = (int)X; array[start + 1] = (int)Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui Copy(Func element_fun) => new V2ui(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui Copy(Func element_index_fun) => new V2ui(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(uint[] array, int start) { array[start + 0] = X; array[start + 1] = Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l Copy(Func element_fun) => new V2l(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l Copy(Func element_index_fun) => new V2l(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(long[] array, int start) { array[start + 0] = (long)X; array[start + 1] = (long)Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f Copy(Func element_fun) => new V2f(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f Copy(Func element_index_fun) => new V2f(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(float[] array, int start) { array[start + 0] = (float)X; array[start + 1] = (float)Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d Copy(Func element_fun) => new V2d(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d Copy(Func element_index_fun) => new V2d(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(double[] array, int start) { array[start + 0] = (double)X; array[start + 1] = (double)Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(X); array[start + 1] = element_fun(Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(X, 0); array[start + 1] = element_index_fun(Y, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly uint[] ToArray() => new uint[] { X, Y }; #endregion #region Properties and Indexers /// /// Property for the field X. /// Useful when properties are required, but the field X is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public uint P_X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value; } } /// /// Property for the field Y. /// Useful when properties are required, but the field Y is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public uint P_Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Y = value; } } /// /// Enumerates all elements of this vector. /// public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return X; yield return Y; } } /// /// Gets or sets element with given index. /// public unsafe uint this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (uint* ptr = &X) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (uint* ptr = &X) { ptr[index] = value; } } } /// /// Returns the index of the largest dimension of the vector. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X >= Y ? 0 : 1; } } /// /// Returns the index of the smallest dimension of the vector. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X <= Y ? 0 : 1; } } /// /// Returns the minimum element of the vector. /// public readonly uint MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(X, Y); } /// /// Returns the maximum element of the vector. /// public readonly uint MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(X, Y); } #endregion #region Constants /// /// Number of elements in this vector. /// public const int Dimension = 2; /// /// All elements zero. /// public static V2ui Zero { get { return new V2ui(0, 0); } } /// /// All elements one. /// public static V2ui One { get { return new V2ui(1, 1); } } /// /// All elements set to maximum possible value. /// public static V2ui MaxValue { get { return new V2ui(Constant.ParseableMaxValue, Constant.ParseableMaxValue); } } /// /// All elements set to minimum possible value. /// public static V2ui MinValue { get { return new V2ui(Constant.ParseableMinValue, Constant.ParseableMinValue); } } /// /// Normalized X-axis. /// public static V2ui XAxis { get { return new V2ui(1, 0); } } /// /// Normalized Y-axis. /// public static V2ui YAxis { get { return new V2ui(0, 1); } } /// /// An array of accessor functions for the coordinates of the vector. /// public static readonly Func[] SelectorArray = new Func[] { v => v.X, v => v.Y }; /// /// Element getter function. /// public static readonly Func Getter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref V2ui v, int i, uint s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; default: throw new IndexOutOfRangeException(); } }; /// /// Element getter function with long index. /// public static readonly Func LongGetter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action with long index. /// public static readonly ActionRefValVal LongSetter = (ref V2ui v, long i, uint s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Static factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui FromV2i(V2i v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui FromV2l(V2l v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui FromV2f(V2f v) => new V2ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui FromV2d(V2d v) => new V2ui(v); #endregion #region Norms /// /// Returns the squared length of the vector. /// public readonly uint LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X * X + Y * Y ; } } /// /// Returns the length of the vector. /// public readonly double Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y ); } } /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// public readonly uint Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X + Y; } } /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y); } } /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// public readonly uint NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(X, Y); } } /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// public readonly uint NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(X, Y); } } /// /// Returns a normalized copy of this vector. /// public readonly V2d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Length; if (s == 0) return V2d.Zero; s = 1 / s; return new V2d(X * s, Y * s); } } #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui LinearInterp(float t, V2ui a, V2ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui LinearInterp(V2f t, V2ui a, V2ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui LinearInterp(double t, V2ui a, V2ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui LinearInterp(V2d t, V2ui a, V2ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Min(V2ui v0, V2ui v1) => Fun.Min(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Min(V2ui v, uint x) => Fun.Min(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Max(V2ui v0, V2ui v1) => Fun.Max(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Max(V2ui v, uint x) => Fun.Max(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Saturate(V2ui v) => Fun.Saturate(v); #endregion #region Operations /// /// Sets the elements of a vector to the given int elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(int x, int y) { X = (uint)x; Y = (uint)y; } /// /// Sets the elements of a vector to the given uint elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(uint x, uint y) { X = x; Y = y; } /// /// Sets the elements of a vector to the given long elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(long x, long y) { X = (uint)x; Y = (uint)y; } /// /// Sets the elements of a vector to the given float elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(float x, float y) { X = (uint)x; Y = (uint)y; } /// /// Sets the elements of a vector to the given double elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(double x, double y) { X = (uint)x; Y = (uint)y; } /// /// Returns the component-wise bitwise complement of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator ~(V2ui v) => new V2ui(~v.X, ~v.Y); /// /// Returns the component-wise sum of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator +(V2ui a, V2ui b) => new V2ui(a.X + b.X, a.Y + b.Y); /// /// Returns the component-wise sum of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator +(V2ui v, uint s) => new V2ui(v.X + s, v.Y + s); /// /// Returns the component-wise sum of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator +(uint s, V2ui v) => new V2ui(s + v.X, s + v.Y); /// /// Returns the component-wise difference of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator -(V2ui a, V2ui b) => new V2ui(a.X - b.X, a.Y - b.Y); /// /// Returns the component-wise difference of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator -(V2ui v, uint s) => new V2ui(v.X - s, v.Y - s); /// /// Returns the component-wise difference of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator -(uint s, V2ui v) => new V2ui(s - v.X, s - v.Y); /// /// Returns the component-wise product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator *(V2ui a, V2ui b) => new V2ui(a.X * b.X, a.Y * b.Y); /// /// Returns the component-wise product of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator *(V2ui v, uint s) => new V2ui(v.X * s, v.Y * s); /// /// Returns the component-wise product of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator *(uint s, V2ui v) => new V2ui(s * v.X, s * v.Y); /// /// Returns the component-wise fraction of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator /(V2ui a, V2ui b) => new V2ui(a.X / b.X, a.Y / b.Y); /// /// Returns the component-wise fraction of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator /(V2ui v, uint s) => new V2ui(v.X / s, v.Y / s); /// /// Returns the component-wise fraction of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator /(uint s, V2ui v) => new V2ui(s / v.X, s / v.Y); /// /// Returns the component-wise remainder of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator %(V2ui a, V2ui b) => new V2ui(a.X % b.X, a.Y % b.Y); /// /// Returns the component-wise remainder of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator %(V2ui v, uint s) => new V2ui(v.X % s, v.Y % s); /// /// Returns the component-wise remainder of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator %(uint s, V2ui v) => new V2ui(s % v.X, s % v.Y); /// /// Returns the component-wise bitwise and of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator &(V2ui a, V2ui b) => new V2ui(a.X & b.X, a.Y & b.Y); /// /// Returns the component-wise bitwise and of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator &(V2ui v, uint s) => new V2ui(v.X & s, v.Y & s); /// /// Returns the component-wise bitwise and of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator &(uint s, V2ui v) => new V2ui(s & v.X, s & v.Y); /// /// Returns the component-wise bitwise or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator |(V2ui a, V2ui b) => new V2ui(a.X | b.X, a.Y | b.Y); /// /// Returns the component-wise bitwise or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator |(V2ui v, uint s) => new V2ui(v.X | s, v.Y | s); /// /// Returns the component-wise bitwise or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator |(uint s, V2ui v) => new V2ui(s | v.X, s | v.Y); /// /// Returns the component-wise bitwise exclusive or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator ^(V2ui a, V2ui b) => new V2ui(a.X ^ b.X, a.Y ^ b.Y); /// /// Returns the component-wise bitwise exclusive or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator ^(V2ui v, uint s) => new V2ui(v.X ^ s, v.Y ^ s); /// /// Returns the component-wise bitwise exclusive or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator ^(uint s, V2ui v) => new V2ui(s ^ v.X, s ^ v.Y); /// /// Returns the component-wise left bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator <<(V2ui v, int s) => new V2ui(v.X << s, v.Y << s); /// /// Returns the component-wise right bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui operator >>(V2ui v, int s) => new V2ui(v.X >> s, v.Y >> s); /// Attention: NEVER implement operators <, <=, >=, >, /// since these are not defined in a Vector space. /// Use AllSmaller() and similar comparators! #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V2ui a, V2ui b) { return a.X == b.X && a.Y == b.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V2ui v, uint s) { return v.X == s && v.Y == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(uint s, V2ui v) { return s == v.X && s == v.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V2ui a, V2ui b) { return a.X != b.X || a.Y != b.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V2ui v, uint s) { return v.X != s || v.Y != s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(uint s, V2ui v) { return s != v.X || s != v.Y; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(V2ui other) { return X.Equals(other.X) && Y.Equals(other.Y); } #endregion #region Overrides public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + X.ToString(format, fp) + between + Y.ToString(format, fp) + end; } public override readonly int GetHashCode() { return HashCode.GetCombined(X, Y); } public override readonly bool Equals(object other) => (other is V2ui o) ? Equals(o) : false; public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + X.ToString(null, CultureInfo.InvariantCulture) + ", " + Y.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Parsing public static V2ui Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new V2ui( uint.Parse(x[0], CultureInfo.InvariantCulture), uint.Parse(x[1], CultureInfo.InvariantCulture) ); } public static V2ui Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, V2ui.Setter); } public static V2ui Parse(Text t, int bracketLevel) { return t.NestedBracketSplit(bracketLevel, Text.Parse, V2ui.Setter); } #endregion #region Swizzle Methods [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2ui OO => new V2ui(0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2ui OI => new V2ui(0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui OX => new V2ui(0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui OY => new V2ui(0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2ui IO => new V2ui(1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2ui II => new V2ui(1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui IX => new V2ui(1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui IY => new V2ui(1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui XO => new V2ui(X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui XI => new V2ui(X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui XX => new V2ui(X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui XY { readonly get => new V2ui(X, Y); set { X = value.X; Y = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui YO => new V2ui(Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui YI => new V2ui(Y, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui YX { readonly get => new V2ui(Y, X); set { Y = value.X; X = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui YY => new V2ui(Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OOX => new V3ui(0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OOY => new V3ui(0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OIX => new V3ui(0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OIY => new V3ui(0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OXO => new V3ui(0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OXI => new V3ui(0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OXX => new V3ui(0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OXY => new V3ui(0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OYO => new V3ui(0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OYI => new V3ui(0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OYX => new V3ui(0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OYY => new V3ui(0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IOX => new V3ui(1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IOY => new V3ui(1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IIX => new V3ui(1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IIY => new V3ui(1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IXO => new V3ui(1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IXI => new V3ui(1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IXX => new V3ui(1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IXY => new V3ui(1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IYO => new V3ui(1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IYI => new V3ui(1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IYX => new V3ui(1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IYY => new V3ui(1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XOO => new V3ui(X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XOI => new V3ui(X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XOX => new V3ui(X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XOY => new V3ui(X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XIO => new V3ui(X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XII => new V3ui(X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XIX => new V3ui(X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XIY => new V3ui(X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XXO => new V3ui(X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XXI => new V3ui(X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XXX => new V3ui(X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XXY => new V3ui(X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XYO => new V3ui(X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XYI => new V3ui(X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XYX => new V3ui(X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XYY => new V3ui(X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YOO => new V3ui(Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YOI => new V3ui(Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YOX => new V3ui(Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YOY => new V3ui(Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YIO => new V3ui(Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YII => new V3ui(Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YIX => new V3ui(Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YIY => new V3ui(Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YXO => new V3ui(Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YXI => new V3ui(Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YXX => new V3ui(Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YXY => new V3ui(Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YYO => new V3ui(Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YYI => new V3ui(Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YYX => new V3ui(Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YYY => new V3ui(Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOOX => new V4ui(0, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOOY => new V4ui(0, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOIX => new V4ui(0, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOIY => new V4ui(0, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOXO => new V4ui(0, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOXI => new V4ui(0, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOXX => new V4ui(0, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOXY => new V4ui(0, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOYO => new V4ui(0, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOYI => new V4ui(0, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOYX => new V4ui(0, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOYY => new V4ui(0, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIOX => new V4ui(0, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIOY => new V4ui(0, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIIX => new V4ui(0, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIIY => new V4ui(0, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIXO => new V4ui(0, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIXI => new V4ui(0, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIXX => new V4ui(0, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIXY => new V4ui(0, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIYO => new V4ui(0, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIYI => new V4ui(0, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIYX => new V4ui(0, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIYY => new V4ui(0, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXOO => new V4ui(0, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXOI => new V4ui(0, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXOX => new V4ui(0, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXOY => new V4ui(0, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXIO => new V4ui(0, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXII => new V4ui(0, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXIX => new V4ui(0, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXIY => new V4ui(0, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXXO => new V4ui(0, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXXI => new V4ui(0, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXXX => new V4ui(0, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXXY => new V4ui(0, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXYO => new V4ui(0, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXYI => new V4ui(0, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXYX => new V4ui(0, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXYY => new V4ui(0, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYOO => new V4ui(0, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYOI => new V4ui(0, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYOX => new V4ui(0, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYOY => new V4ui(0, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYIO => new V4ui(0, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYII => new V4ui(0, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYIX => new V4ui(0, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYIY => new V4ui(0, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYXO => new V4ui(0, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYXI => new V4ui(0, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYXX => new V4ui(0, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYXY => new V4ui(0, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYYO => new V4ui(0, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYYI => new V4ui(0, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYYX => new V4ui(0, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYYY => new V4ui(0, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOOX => new V4ui(1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOOY => new V4ui(1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOIX => new V4ui(1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOIY => new V4ui(1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOXO => new V4ui(1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOXI => new V4ui(1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOXX => new V4ui(1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOXY => new V4ui(1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOYO => new V4ui(1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOYI => new V4ui(1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOYX => new V4ui(1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOYY => new V4ui(1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIOX => new V4ui(1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIOY => new V4ui(1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIIX => new V4ui(1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIIY => new V4ui(1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIXO => new V4ui(1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIXI => new V4ui(1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIXX => new V4ui(1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIXY => new V4ui(1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIYO => new V4ui(1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIYI => new V4ui(1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIYX => new V4ui(1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIYY => new V4ui(1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXOO => new V4ui(1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXOI => new V4ui(1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXOX => new V4ui(1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXOY => new V4ui(1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXIO => new V4ui(1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXII => new V4ui(1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXIX => new V4ui(1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXIY => new V4ui(1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXXO => new V4ui(1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXXI => new V4ui(1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXXX => new V4ui(1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXXY => new V4ui(1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXYO => new V4ui(1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXYI => new V4ui(1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXYX => new V4ui(1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXYY => new V4ui(1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYOO => new V4ui(1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYOI => new V4ui(1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYOX => new V4ui(1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYOY => new V4ui(1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYIO => new V4ui(1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYII => new V4ui(1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYIX => new V4ui(1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYIY => new V4ui(1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYXO => new V4ui(1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYXI => new V4ui(1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYXX => new V4ui(1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYXY => new V4ui(1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYYO => new V4ui(1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYYI => new V4ui(1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYYX => new V4ui(1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYYY => new V4ui(1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOOO => new V4ui(X, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOOI => new V4ui(X, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOOX => new V4ui(X, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOOY => new V4ui(X, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOIO => new V4ui(X, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOII => new V4ui(X, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOIX => new V4ui(X, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOIY => new V4ui(X, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOXO => new V4ui(X, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOXI => new V4ui(X, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOXX => new V4ui(X, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOXY => new V4ui(X, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOYO => new V4ui(X, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOYI => new V4ui(X, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOYX => new V4ui(X, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOYY => new V4ui(X, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIOO => new V4ui(X, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIOI => new V4ui(X, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIOX => new V4ui(X, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIOY => new V4ui(X, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIIO => new V4ui(X, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIII => new V4ui(X, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIIX => new V4ui(X, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIIY => new V4ui(X, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIXO => new V4ui(X, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIXI => new V4ui(X, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIXX => new V4ui(X, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIXY => new V4ui(X, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIYO => new V4ui(X, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIYI => new V4ui(X, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIYX => new V4ui(X, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIYY => new V4ui(X, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXOO => new V4ui(X, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXOI => new V4ui(X, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXOX => new V4ui(X, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXOY => new V4ui(X, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXIO => new V4ui(X, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXII => new V4ui(X, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXIX => new V4ui(X, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXIY => new V4ui(X, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXXO => new V4ui(X, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXXI => new V4ui(X, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXXX => new V4ui(X, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXXY => new V4ui(X, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXYO => new V4ui(X, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXYI => new V4ui(X, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXYX => new V4ui(X, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXYY => new V4ui(X, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYOO => new V4ui(X, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYOI => new V4ui(X, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYOX => new V4ui(X, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYOY => new V4ui(X, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYIO => new V4ui(X, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYII => new V4ui(X, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYIX => new V4ui(X, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYIY => new V4ui(X, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYXO => new V4ui(X, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYXI => new V4ui(X, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYXX => new V4ui(X, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYXY => new V4ui(X, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYYO => new V4ui(X, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYYI => new V4ui(X, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYYX => new V4ui(X, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYYY => new V4ui(X, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOOO => new V4ui(Y, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOOI => new V4ui(Y, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOOX => new V4ui(Y, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOOY => new V4ui(Y, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOIO => new V4ui(Y, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOII => new V4ui(Y, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOIX => new V4ui(Y, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOIY => new V4ui(Y, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOXO => new V4ui(Y, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOXI => new V4ui(Y, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOXX => new V4ui(Y, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOXY => new V4ui(Y, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOYO => new V4ui(Y, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOYI => new V4ui(Y, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOYX => new V4ui(Y, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOYY => new V4ui(Y, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIOO => new V4ui(Y, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIOI => new V4ui(Y, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIOX => new V4ui(Y, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIOY => new V4ui(Y, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIIO => new V4ui(Y, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIII => new V4ui(Y, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIIX => new V4ui(Y, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIIY => new V4ui(Y, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIXO => new V4ui(Y, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIXI => new V4ui(Y, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIXX => new V4ui(Y, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIXY => new V4ui(Y, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIYO => new V4ui(Y, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIYI => new V4ui(Y, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIYX => new V4ui(Y, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIYY => new V4ui(Y, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXOO => new V4ui(Y, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXOI => new V4ui(Y, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXOX => new V4ui(Y, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXOY => new V4ui(Y, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXIO => new V4ui(Y, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXII => new V4ui(Y, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXIX => new V4ui(Y, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXIY => new V4ui(Y, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXXO => new V4ui(Y, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXXI => new V4ui(Y, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXXX => new V4ui(Y, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXXY => new V4ui(Y, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXYO => new V4ui(Y, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXYI => new V4ui(Y, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXYX => new V4ui(Y, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXYY => new V4ui(Y, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYOO => new V4ui(Y, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYOI => new V4ui(Y, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYOX => new V4ui(Y, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYOY => new V4ui(Y, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYIO => new V4ui(Y, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYII => new V4ui(Y, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYIX => new V4ui(Y, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYIY => new V4ui(Y, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYXO => new V4ui(Y, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYXI => new V4ui(Y, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYXX => new V4ui(Y, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYXY => new V4ui(Y, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYYO => new V4ui(Y, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYYI => new V4ui(Y, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYYX => new V4ui(Y, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYYY => new V4ui(Y, Y, Y, Y); #endregion #region IVector Members /// /// By using long indices, the IVector<double> interface is /// accessed. /// public double this[long i] { readonly get { return (double)this[(int)i]; } set { this[(int)i] = (uint)value; } } #endregion #region ISize2ui Members public readonly V2ui Size2ui { get { return this; } } #endregion #region IVector public readonly long Dim { get { return 2; } } public readonly object GetValue(long index) { return (object)this[(int)index]; } public void SetValue(object value, long index) { this[(int)index] = (uint)value; } #endregion } public class V2uiEqualityComparer : IEqualityComparer { public static V2uiEqualityComparer Default => new V2uiEqualityComparer(); #region IEqualityComparer Members public bool Equals(V2ui v0, V2ui v1) { return v0 == v1; } public int GetHashCode(V2ui v) { return v.GetHashCode(); } #endregion } public static partial class Fun { #region Min and Max /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Min(this V2ui a, V2ui b) { return new V2ui(Min(a.X, b.X), Min(a.Y, b.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Min(this V2ui a, uint b) { return new V2ui(Min(a.X, b), Min(a.Y, b)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Min(this uint a, V2ui b) { return new V2ui(Min(a, b.X), Min(a, b.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Max(this V2ui a, V2ui b) { return new V2ui(Max(a.X, b.X), Max(a.Y, b.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Max(this V2ui a, uint b) { return new V2ui(Max(a.X, b), Max(a.Y, b)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Max(this uint a, V2ui b) { return new V2ui(Max(a, b.X), Max(a, b.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Min(this V2ui a, V2ui b, V2ui c) { return new V2ui(Min(a.X, b.X, c.X), Min(a.Y, b.Y, c.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Max(this V2ui a, V2ui b, V2ui c) { return new V2ui(Max(a.X, b.X, c.X), Max(a.Y, b.Y, c.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Min(this V2ui a, V2ui b, V2ui c, V2ui d) { return new V2ui(Min(a.X, b.X, c.X, d.X), Min(a.Y, b.Y, c.Y, d.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Max(this V2ui a, V2ui b, V2ui c, V2ui d) { return new V2ui(Max(a.X, b.X, c.X, d.X), Max(a.Y, b.Y, c.Y, d.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Min(this V2ui x, params V2ui[] values) { return new V2ui(Min(x.X, values.Map(a => a.X)), Min(x.Y, values.Map(a => a.Y))); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Max(this V2ui x, params V2ui[] values) { return new V2ui(Max(x.X, values.Map(a => a.X)), Max(x.Y, values.Map(a => a.Y))); } #endregion #region Clamping /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Clamp(this V2ui x, V2ui a, V2ui b) { return new V2ui(Clamp(x.X, a.X, b.X), Clamp(x.Y, a.Y, b.Y)); } /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Clamp(this V2ui x, uint a, uint b) { return new V2ui(Clamp(x.X, a, b), Clamp(x.Y, a, b)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui ClampExcl(this V2ui x, V2ui a, V2ui b) { return new V2ui(ClampExcl(x.X, a.X, b.X), ClampExcl(x.Y, a.Y, b.Y)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui ClampExcl(this V2ui x, uint a, uint b) { return new V2ui(ClampExcl(x.X, a, b), ClampExcl(x.Y, a, b)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui ClampWrap(this V2ui x, V2ui a, V2ui b) { return new V2ui(ClampWrap(x.X, a.X, b.X), ClampWrap(x.Y, a.Y, b.Y)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui ClampWrap(this V2ui x, uint a, uint b) { return new V2ui(ClampWrap(x.X, a, b), ClampWrap(x.Y, a, b)); } /// /// Applies Fun.Saturate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Saturate(this V2ui x) { return new V2ui(Saturate(x.X), Saturate(x.Y)); } #endregion #region Multiply-Add /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui MultiplyAdd(V2ui x, V2ui y, V2ui z) { return new V2ui(MultiplyAdd(x.X, y.X, z.X), MultiplyAdd(x.Y, y.Y, z.Y)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui MultiplyAdd(V2ui x, uint y, V2ui z) { return new V2ui(MultiplyAdd(x.X, y, z.X), MultiplyAdd(x.Y, y, z.Y)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui MultiplyAdd(uint x, V2ui y, V2ui z) { return new V2ui(MultiplyAdd(x, y.X, z.X), MultiplyAdd(x, y.Y, z.Y)); } #endregion #region Roots /// /// Applies Fun.Sqrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Sqrt(this V2ui x) { return new V2d(Sqrt(x.X), Sqrt(x.Y)); } /// /// Applies Fun.Cbrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Cbrt(this V2ui x) { return new V2d(Cbrt(x.X), Cbrt(x.Y)); } #endregion #region Square /// /// Applies Fun.Square to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Square(this V2ui x) { return new V2ui(Square(x.X), Square(x.Y)); } #endregion #region Power /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Pown(this V2ui x, V2ui y) { return new V2ui(Pown(x.X, y.X), Pown(x.Y, y.Y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Pown(this V2ui x, uint y) { return new V2ui(Pown(x.X, y), Pown(x.Y, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Pown(this uint x, V2ui y) { return new V2ui(Pown(x, y.X), Pown(x, y.Y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Pown(this V2ui x, V2i y) { return new V2ui(Pown(x.X, y.X), Pown(x.Y, y.Y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Pown(this V2ui x, int y) { return new V2ui(Pown(x.X, y), Pown(x.Y, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Pown(this uint x, V2i y) { return new V2ui(Pown(x, y.X), Pown(x, y.Y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Pow(this V2ui x, V2f y) { return new V2f(Pow(x.X, y.X), Pow(x.Y, y.Y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Pow(this V2ui x, float y) { return new V2f(Pow(x.X, y), Pow(x.Y, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Pow(this uint x, V2f y) { return new V2f(Pow(x, y.X), Pow(x, y.Y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Pow(this V2ui x, V2d y) { return new V2d(Pow(x.X, y.X), Pow(x.Y, y.Y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Pow(this V2ui x, double y) { return new V2d(Pow(x.X, y), Pow(x.Y, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Pow(this uint x, V2d y) { return new V2d(Pow(x, y.X), Pow(x, y.Y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Power(this V2ui x, V2f y) { return new V2f(Power(x.X, y.X), Power(x.Y, y.Y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Power(this V2ui x, float y) { return new V2f(Power(x.X, y), Power(x.Y, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Power(this uint x, V2f y) { return new V2f(Power(x, y.X), Power(x, y.Y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Power(this V2ui x, V2d y) { return new V2d(Power(x.X, y.X), Power(x.Y, y.Y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Power(this V2ui x, double y) { return new V2d(Power(x.X, y), Power(x.Y, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Power(this uint x, V2d y) { return new V2d(Power(x, y.X), Power(x, y.Y)); } #endregion #region Exp and Log /// /// Applies Fun.Exp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Exp(this V2ui x) { return new V2d(Exp(x.X), Exp(x.Y)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log(this V2ui x) { return new V2d(Log(x.X), Log(x.Y)); } /// /// Applies Fun.Log2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log2(this V2ui x) { return new V2d(Log2(x.X), Log2(x.Y)); } /// /// Applies Fun.Log2Int to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Log2Int(this V2ui x) { return new V2i(Log2Int(x.X), Log2Int(x.Y)); } /// /// Applies Fun.Log10 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log10(this V2ui x) { return new V2d(Log10(x.X), Log10(x.Y)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log(this V2ui x, double basis) { return new V2d(Log(x.X, basis), Log(x.Y, basis)); } #endregion #region Step functions /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Step(this V2ui x, V2ui edge) { return new V2ui(Step(x.X, edge.X), Step(x.Y, edge.Y)); } /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Step(this V2ui x, uint edge) { return new V2ui(Step(x.X, edge), Step(x.Y, edge)); } #endregion #region Interpolation /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Lerp(this float t, V2ui a, V2ui b) { return new V2ui(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Lerp(this V2f t, V2ui a, V2ui b) { return new V2ui(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Lerp(this double t, V2ui a, V2ui b) { return new V2ui(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui Lerp(this V2d t, V2ui a, V2ui b) { return new V2ui(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y)); } /// /// Applies Fun.InvLerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d InvLerp(this V2ui y, V2ui a, V2ui b) { return new V2d(InvLerp(y.X, a.X, b.X), InvLerp(y.Y, a.Y, b.Y)); } #endregion #region Common Divisor and Multiple /// /// Applies Fun.GreatestCommonDivisor to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui GreatestCommonDivisor(this V2ui a, V2ui b) { return new V2ui(GreatestCommonDivisor(a.X, b.X), GreatestCommonDivisor(a.Y, b.Y)); } /// /// Applies Fun.LeastCommonMultiple to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui LeastCommonMultiple(this V2ui a, V2ui b) { return new V2ui(LeastCommonMultiple(a.X, b.X), LeastCommonMultiple(a.Y, b.Y)); } #endregion #region Floating point bits /// /// Applies Fun.FloatFromUnsignedBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f FloatFromUnsignedBits(this V2ui x) { return new V2f(FloatFromUnsignedBits(x.X), FloatFromUnsignedBits(x.Y)); } #endregion #region ApproximateEquals /// /// Returns whether the given vectors are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V2ui a, V2ui b, uint tolerance) { return ApproximateEquals(a.X, b.X, tolerance) && ApproximateEquals(a.Y, b.Y, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this V2ui v, uint epsilon) => Vec.AllTiny(v, epsilon); #endregion } /// /// Contains static methods /// public static partial class Vec { #region Length /// /// Returns the squared length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint LengthSquared(V2ui v) => v.LengthSquared; /// /// Returns the length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Length(V2ui v) => v.Length; #endregion #region Normalize /// /// Returns a normalized copy of this vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Normalized(V2ui v) => v.Normalized; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Norm1(V2ui v) => v.Norm1; /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(V2ui v) => v.Norm2; /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint NormMax(V2ui v) => v.NormMax; /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint NormMin(V2ui v) => v.NormMin; /// /// Gets the p-norm. This is calculated as the p-th root of (|x|^n + |y|^n + ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this V2ui v, double p) { return ( Fun.Abs(v.X).Pow(p) + Fun.Abs(v.Y).Pow(p)).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the squared distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint DistanceSquared(this V2ui a, V2ui b) => Fun.Square((a.X < b.X) ? (b.X - a.X) : (a.X - b.X)) + Fun.Square((a.Y < b.Y) ? (b.Y - a.Y) : (a.Y - b.Y)); /// /// Returns the distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V2ui a, V2ui b) => Fun.Sqrt(DistanceSquared(a, b)); /// /// Returns the Manhatten (or 1-) distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Distance1(this V2ui a, V2ui b) => ((a.X < b.X) ? (b.X - a.X) : (a.X - b.X)) + ((a.Y < b.Y) ? (b.Y - a.Y) : (a.Y - b.Y)); /// /// Returns the p-distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V2ui a, V2ui b, double p) => (((a.X < b.X) ? (b.X - a.X) : (a.X - b.X)).Pow(p) + ((a.Y < b.Y) ? (b.Y - a.Y) : (a.Y - b.Y)).Pow(p)).Pow(1 / p); /// /// Returns the maximal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint DistanceMax(this V2ui a, V2ui b) => Fun.Max(((a.X < b.X) ? (b.X - a.X) : (a.X - b.X)), ((a.Y < b.Y) ? (b.Y - a.Y) : (a.Y - b.Y))); /// /// Returns the minimal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint DistanceMin(this V2ui a, V2ui b) => Fun.Min(((a.X < b.X) ? (b.X - a.X) : (a.X - b.X)), ((a.Y < b.Y) ? (b.Y - a.Y) : (a.Y - b.Y))); /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V2ui query, V2ui p0, V2ui p1) { return DistanceToLine((V2d) query, (V2d) p0, (V2d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V2ui query, V2ui p0, V2ui p1) { return DistanceToInfiniteLine((V2d) query, (V2d) p0, (V2d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V2ui query, V2ui p0, V2ui p1, out double t) { return DistanceToLine((V2d) query, (V2d) p0, (V2d) p1, out t); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V2ui query, V2ui p0, V2ui p1, out double t) { return DistanceToInfiniteLine((V2d) query, (V2d) p0, (V2d) p1, out t); } #endregion #region Operations /// /// Returns the dot product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Dot(this V2ui a, V2ui b) { return a.X * b.X + a.Y * b.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DirFlags DirFlags(this V2ui v) { DirFlags flags = Aardbase.DirFlags.None; if (v.X > 0) flags |= Aardbase.DirFlags.PositiveX; if (v.X < 0) flags |= Aardbase.DirFlags.NegativeX; if (v.Y > 0) flags |= Aardbase.DirFlags.PositiveY; if (v.Y < 0) flags |= Aardbase.DirFlags.NegativeY; return flags; } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V2ui a, V2ui b) { return (a.X < b.X && a.Y < b.Y); } /// /// Returns whether ALL elements of v are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V2ui v, uint s) { return (v.X < s && v.Y < s); } /// /// Returns whether a is Smaller ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(uint s, V2ui v) { return (s < v.X && s < v.Y); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V2ui a, V2ui b) { return (a.X < b.X || a.Y < b.Y); } /// /// Returns whether AT LEAST ONE element of v is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V2ui v, uint s) { return (v.X < s || v.Y < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(uint s, V2ui v) { return (s < v.X || s < v.Y); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V2ui a, V2ui b) { return (a.X > b.X && a.Y > b.Y); } /// /// Returns whether ALL elements of v are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V2ui v, uint s) { return (v.X > s && v.Y > s); } /// /// Returns whether a is Greater ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(uint s, V2ui v) { return (s > v.X && s > v.Y); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V2ui a, V2ui b) { return (a.X > b.X || a.Y > b.Y); } /// /// Returns whether AT LEAST ONE element of v is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V2ui v, uint s) { return (v.X > s || v.Y > s); } /// /// Returns whether a is Greater AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(uint s, V2ui v) { return (s > v.X || s > v.Y); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V2ui a, V2ui b) { return (a.X <= b.X && a.Y <= b.Y); } /// /// Returns whether ALL elements of v are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V2ui v, uint s) { return (v.X <= s && v.Y <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(uint s, V2ui v) { return (s <= v.X && s <= v.Y); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V2ui a, V2ui b) { return (a.X <= b.X || a.Y <= b.Y); } /// /// Returns whether AT LEAST ONE element of v is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V2ui v, uint s) { return (v.X <= s || v.Y <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(uint s, V2ui v) { return (s <= v.X || s <= v.Y); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V2ui a, V2ui b) { return (a.X >= b.X && a.Y >= b.Y); } /// /// Returns whether ALL elements of v are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V2ui v, uint s) { return (v.X >= s && v.Y >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(uint s, V2ui v) { return (s >= v.X && s >= v.Y); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V2ui a, V2ui b) { return (a.X >= b.X || a.Y >= b.Y); } /// /// Returns whether AT LEAST ONE element of v is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V2ui v, uint s) { return (v.X >= s || v.Y >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(uint s, V2ui v) { return (s >= v.X || s >= v.Y); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V2ui a, V2ui b) { return (a.X == b.X && a.Y == b.Y); } /// /// Returns whether ALL elements of v are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V2ui v, uint s) { return (v.X == s && v.Y == s); } /// /// Returns whether a is Equal ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(uint s, V2ui v) { return (s == v.X && s == v.Y); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V2ui a, V2ui b) { return (a.X == b.X || a.Y == b.Y); } /// /// Returns whether AT LEAST ONE element of v is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V2ui v, uint s) { return (v.X == s || v.Y == s); } /// /// Returns whether a is Equal AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(uint s, V2ui v) { return (s == v.X || s == v.Y); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V2ui a, V2ui b) { return (a.X != b.X && a.Y != b.Y); } /// /// Returns whether ALL elements of v are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V2ui v, uint s) { return (v.X != s && v.Y != s); } /// /// Returns whether a is Different ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(uint s, V2ui v) { return (s != v.X && s != v.Y); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V2ui a, V2ui b) { return (a.X != b.X || a.Y != b.Y); } /// /// Returns whether AT LEAST ONE element of v is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V2ui v, uint s) { return (v.X != s || v.Y != s); } /// /// Returns whether a is Different AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(uint s, V2ui v) { return (s != v.X || s != v.Y); } /// /// Compare x-coordinate before y-coordinate, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this V2ui v0, V2ui v1) { if (v0.X < v1.X) return -1; if (v0.X > v1.X) return +1; if (v0.Y < v1.Y) return -1; if (v0.Y > v1.Y) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint MinElement(V2ui v) => v.MinElement; /// /// Returns the maximum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint MaxElement(V2ui v) => v.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this V2ui v, uint epsilon) => v.X.IsTiny(epsilon) || v.Y.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this V2ui v, uint epsilon) => v.X.IsTiny(epsilon) && v.Y.IsTiny(epsilon); #endregion #region ArrayExtensions public static int IndexOfClosestPoint(this V2ui[] pointArray, V2ui point) { var bestDist = DistanceSquared(point, pointArray[0]); int bestIndex = 0; int count = pointArray.Length; for (int i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this V2ui[] array, int start, int count, V2ui point) { var bestDist = DistanceSquared(point, array[start]); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this T[] array, int start, int count, Func pointSelector, V2ui point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint(this V2ui[] pointArray, V2ui point) { var bestDist = DistanceSquared(point, pointArray[0]); long bestIndex = 0; long count = pointArray.LongLength; for (long i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this V2ui[] array, long start, long count, V2ui point) { var bestDist = DistanceSquared(point, array[start]); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this T[] array, long start, long count, Func pointSelector, V2ui point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static int IndexOfMinX(this V2ui[] vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static long LongIndexOfMinX(this V2ui[] vectorArray, long count = 0) { var minimum = vectorArray[0].X; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static int IndexOfMaxX(this V2ui[] vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static long LongIndexOfMaxX(this V2ui[] vectorArray, long count = 0) { var maximum = vectorArray[0].X; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static int IndexOfMinY(this V2ui[] vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static long LongIndexOfMinY(this V2ui[] vectorArray, long count = 0) { var minimum = vectorArray[0].Y; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static int IndexOfMaxY(this V2ui[] vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static long LongIndexOfMaxY(this V2ui[] vectorArray, long count = 0) { var maximum = vectorArray[0].Y; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the list. /// public static int IndexOfMinX(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the list. /// public static int IndexOfMaxX(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the list. /// public static int IndexOfMinY(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the list. /// public static int IndexOfMaxY(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the array of the index-th coordinate of each vector. /// public static uint[] CopyCoord(this V2ui[] self, int index) { switch (index) { case 0: return self.Map(v => v.X); case 1: return self.Map(v => v.Y); default: throw new IndexOutOfRangeException(); } } #endregion } public static class IRandomUniformV2uiExtensions { #region IRandomUniform extensions for V2ui /// /// Uses UniformUInt() to generate the elements of a V2ui vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui UniformV2ui(this IRandomUniform rnd) { return new V2ui(rnd.UniformUInt(), rnd.UniformUInt()); } #endregion } #endregion #region V2l [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct V2l : IVector, ISize2l, IFormattable, IEquatable { [DataMember] public long X; [DataMember] public long Y; #region Constructors /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(int x, int y) { X = (long)x; Y = (long)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(int v) { X = (long)v; Y = (long)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(int[] a) { X = (long)a[0]; Y = (long)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(int[] a, int start) { X = (long)a[start + 0]; Y = (long)a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(uint x, uint y) { X = (long)x; Y = (long)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(uint v) { X = (long)v; Y = (long)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(uint[] a) { X = (long)a[0]; Y = (long)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(uint[] a, int start) { X = (long)a[start + 0]; Y = (long)a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(long x, long y) { X = x; Y = y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(long v) { X = v; Y = v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(long[] a) { X = a[0]; Y = a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(long[] a, int start) { X = a[start + 0]; Y = a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(float x, float y) { X = (long)x; Y = (long)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(float v) { X = (long)v; Y = (long)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(float[] a) { X = (long)a[0]; Y = (long)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(float[] a, int start) { X = (long)a[start + 0]; Y = (long)a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(double x, double y) { X = (long)x; Y = (long)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(double v) { X = (long)v; Y = (long)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(double[] a) { X = (long)a[0]; Y = (long)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(double[] a, int start) { X = (long)a[start + 0]; Y = (long)a[start + 1]; } /// /// Creates a vector from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(Func index_fun) { X = index_fun(0); Y = index_fun(1); } /// /// Creates a vector from a general vector implementing the IVector<long> interface. /// The caller has to verify that the dimension of is at least 2. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(IVector v) : this(v[0], v[1]) { } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(V2i v) { X = (long)v.X; Y = (long)v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(V2ui v) { X = (long)v.X; Y = (long)v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(V2l v) { X = v.X; Y = v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(V2f v) { X = (long)v.X; Y = (long)v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(V2d v) { X = (long)v.X; Y = (long)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(V3i v) { X = (long)v.X; Y = (long)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(V3ui v) { X = (long)v.X; Y = (long)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(V3l v) { X = v.X; Y = v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(V3f v) { X = (long)v.X; Y = (long)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(V3d v) { X = (long)v.X; Y = (long)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(V4i v) { X = (long)v.X; Y = (long)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(V4ui v) { X = (long)v.X; Y = (long)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(V4l v) { X = v.X; Y = v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(V4f v) { X = (long)v.X; Y = (long)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2l(V4d v) { X = (long)v.X; Y = (long)v.Y; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(V2i v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(V2ui v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(V2f v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(V2d v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(V3i v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(V3ui v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(V3l v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(V3f v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(V3d v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(V4i v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(V4ui v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(V4l v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(V4f v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(V4d v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToV2i() => (V2i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui ToV2ui() => (V2ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f ToV2f() => (V2f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d ToV2d() => (V2d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int[](V2l v) => new int[] { (int)v.X, (int)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(int[] v) => new V2l((long)v[0], (long)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](V2l v) => new uint[] { (uint)v.X, (uint)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(uint[] v) => new V2l((long)v[0], (long)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long[](V2l v) => new long[] { v.X, v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(long[] v) => new V2l(v[0], v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](V2l v) => new float[] { (float)v.X, (float)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(float[] v) => new V2l((long)v[0], (long)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](V2l v) => new double[] { (double)v.X, (double)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2l(double[] v) => new V2l((long)v[0], (long)v[1]); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i Copy(Func element_fun) => new V2i(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i Copy(Func element_index_fun) => new V2i(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(int[] array, int start) { array[start + 0] = (int)X; array[start + 1] = (int)Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui Copy(Func element_fun) => new V2ui(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui Copy(Func element_index_fun) => new V2ui(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(uint[] array, int start) { array[start + 0] = (uint)X; array[start + 1] = (uint)Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l Copy(Func element_fun) => new V2l(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l Copy(Func element_index_fun) => new V2l(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(long[] array, int start) { array[start + 0] = X; array[start + 1] = Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f Copy(Func element_fun) => new V2f(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f Copy(Func element_index_fun) => new V2f(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(float[] array, int start) { array[start + 0] = (float)X; array[start + 1] = (float)Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d Copy(Func element_fun) => new V2d(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d Copy(Func element_index_fun) => new V2d(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(double[] array, int start) { array[start + 0] = (double)X; array[start + 1] = (double)Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(X); array[start + 1] = element_fun(Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(X, 0); array[start + 1] = element_index_fun(Y, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly long[] ToArray() => new long[] { X, Y }; #endregion #region Properties and Indexers /// /// Property for the field X. /// Useful when properties are required, but the field X is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public long P_X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value; } } /// /// Property for the field Y. /// Useful when properties are required, but the field Y is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public long P_Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Y = value; } } /// /// Enumerates all elements of this vector. /// public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return X; yield return Y; } } /// /// Gets or sets element with given index. /// public unsafe long this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (long* ptr = &X) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (long* ptr = &X) { ptr[index] = value; } } } /// /// Returns the index of the largest dimension of the vector. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X >= Y ? 0 : 1; } } /// /// Returns the index of the smallest dimension of the vector. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X <= Y ? 0 : 1; } } /// /// Returns the minimum element of the vector. /// public readonly long MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(X, Y); } /// /// Returns the maximum element of the vector. /// public readonly long MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(X, Y); } #endregion #region Constants /// /// Number of elements in this vector. /// public const int Dimension = 2; /// /// All elements zero. /// public static V2l Zero { get { return new V2l(0, 0); } } /// /// All elements one. /// public static V2l One { get { return new V2l(1, 1); } } /// /// All elements set to maximum possible value. /// public static V2l MaxValue { get { return new V2l(Constant.ParseableMaxValue, Constant.ParseableMaxValue); } } /// /// All elements set to minimum possible value. /// public static V2l MinValue { get { return new V2l(Constant.ParseableMinValue, Constant.ParseableMinValue); } } /// /// Normalized X-axis. /// public static V2l XAxis { get { return new V2l(1, 0); } } /// /// Normalized Y-axis. /// public static V2l YAxis { get { return new V2l(0, 1); } } /// /// An array of accessor functions for the coordinates of the vector. /// public static readonly Func[] SelectorArray = new Func[] { v => v.X, v => v.Y }; /// /// Element getter function. /// public static readonly Func Getter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref V2l v, int i, long s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; default: throw new IndexOutOfRangeException(); } }; /// /// Element getter function with long index. /// public static readonly Func LongGetter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action with long index. /// public static readonly ActionRefValVal LongSetter = (ref V2l v, long i, long s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Static factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l FromV2i(V2i v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l FromV2ui(V2ui v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l FromV2f(V2f v) => new V2l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l FromV2d(V2d v) => new V2l(v); #endregion #region Norms /// /// Returns the squared length of the vector. /// public readonly long LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X * X + Y * Y ; } } /// /// Returns the length of the vector. /// public readonly double Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y ); } } /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// public readonly long Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Abs(X) + Fun.Abs(Y); } } /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y); } } /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// public readonly long NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(Fun.Abs(X), Fun.Abs(Y)); } } /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// public readonly long NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(Fun.Abs(X), Fun.Abs(Y)); } } /// /// Returns a normalized copy of this vector. /// public readonly V2d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Length; if (s == 0) return V2d.Zero; s = 1 / s; return new V2d(X * s, Y * s); } } /// /// Vector rotated 90° counter clockwise: (-Y, X) /// public readonly V2l Rot90 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2l(-Y, X); } } /// /// Vector rotated 180° counter clockwise: (-X, -Y) /// public readonly V2l Rot180 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2l(-X, -Y); } } /// /// Vector rotated 270° counter clockwise: (Y, -X) /// public readonly V2l Rot270 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2l(Y, -X); } } #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Abs(V2l v) => v.Abs(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l LinearInterp(float t, V2l a, V2l b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l LinearInterp(V2f t, V2l a, V2l b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l LinearInterp(double t, V2l a, V2l b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l LinearInterp(V2d t, V2l a, V2l b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Min(V2l v0, V2l v1) => Fun.Min(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Min(V2l v, long x) => Fun.Min(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Max(V2l v0, V2l v1) => Fun.Max(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Max(V2l v, long x) => Fun.Max(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Saturate(V2l v) => Fun.Saturate(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l DivideByInt(V2l v, int x) => v / x; #endregion #region Operations /// /// Sets the elements of a vector to the given int elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(int x, int y) { X = (long)x; Y = (long)y; } /// /// Sets the elements of a vector to the given uint elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(uint x, uint y) { X = (long)x; Y = (long)y; } /// /// Sets the elements of a vector to the given long elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(long x, long y) { X = x; Y = y; } /// /// Sets the elements of a vector to the given float elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(float x, float y) { X = (long)x; Y = (long)y; } /// /// Sets the elements of a vector to the given double elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(double x, double y) { X = (long)x; Y = (long)y; } /// /// Returns a negated copy of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator -(V2l v) => new V2l(-v.X, -v.Y); /// /// Returns the component-wise bitwise complement of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator ~(V2l v) => new V2l(~v.X, ~v.Y); /// /// Returns a vector that is orthogonal to this one (i.e. {x,y} -> {-y,x}). /// public readonly V2l Orthogonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2l(-Y, X); } } /// /// Returns the component-wise sum of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator +(V2l a, V2l b) => new V2l(a.X + b.X, a.Y + b.Y); /// /// Returns the component-wise sum of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator +(V2l v, long s) => new V2l(v.X + s, v.Y + s); /// /// Returns the component-wise sum of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator +(long s, V2l v) => new V2l(s + v.X, s + v.Y); /// /// Returns the component-wise difference of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator -(V2l a, V2l b) => new V2l(a.X - b.X, a.Y - b.Y); /// /// Returns the component-wise difference of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator -(V2l v, long s) => new V2l(v.X - s, v.Y - s); /// /// Returns the component-wise difference of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator -(long s, V2l v) => new V2l(s - v.X, s - v.Y); /// /// Returns the component-wise product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator *(V2l a, V2l b) => new V2l(a.X * b.X, a.Y * b.Y); /// /// Returns the component-wise product of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator *(V2l v, long s) => new V2l(v.X * s, v.Y * s); /// /// Returns the component-wise product of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator *(long s, V2l v) => new V2l(s * v.X, s * v.Y); /// /// Returns the component-wise fraction of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator /(V2l a, V2l b) => new V2l(a.X / b.X, a.Y / b.Y); /// /// Returns the component-wise fraction of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator /(V2l v, long s) => new V2l(v.X / s, v.Y / s); /// /// Returns the component-wise fraction of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator /(long s, V2l v) => new V2l(s / v.X, s / v.Y); /// /// Returns the component-wise remainder of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator %(V2l a, V2l b) => new V2l(a.X % b.X, a.Y % b.Y); /// /// Returns the component-wise remainder of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator %(V2l v, long s) => new V2l(v.X % s, v.Y % s); /// /// Returns the component-wise remainder of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator %(long s, V2l v) => new V2l(s % v.X, s % v.Y); /// /// Returns the component-wise bitwise and of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator &(V2l a, V2l b) => new V2l(a.X & b.X, a.Y & b.Y); /// /// Returns the component-wise bitwise and of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator &(V2l v, long s) => new V2l(v.X & s, v.Y & s); /// /// Returns the component-wise bitwise and of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator &(long s, V2l v) => new V2l(s & v.X, s & v.Y); /// /// Returns the component-wise bitwise or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator |(V2l a, V2l b) => new V2l(a.X | b.X, a.Y | b.Y); /// /// Returns the component-wise bitwise or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator |(V2l v, long s) => new V2l(v.X | s, v.Y | s); /// /// Returns the component-wise bitwise or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator |(long s, V2l v) => new V2l(s | v.X, s | v.Y); /// /// Returns the component-wise bitwise exclusive or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator ^(V2l a, V2l b) => new V2l(a.X ^ b.X, a.Y ^ b.Y); /// /// Returns the component-wise bitwise exclusive or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator ^(V2l v, long s) => new V2l(v.X ^ s, v.Y ^ s); /// /// Returns the component-wise bitwise exclusive or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator ^(long s, V2l v) => new V2l(s ^ v.X, s ^ v.Y); /// /// Returns the component-wise left bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator <<(V2l v, int s) => new V2l(v.X << s, v.Y << s); /// /// Returns the component-wise right bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l operator >>(V2l v, int s) => new V2l(v.X >> s, v.Y >> s); /// Attention: NEVER implement operators <, <=, >=, >, /// since these are not defined in a Vector space. /// Use AllSmaller() and similar comparators! #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V2l a, V2l b) { return a.X == b.X && a.Y == b.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V2l v, long s) { return v.X == s && v.Y == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(long s, V2l v) { return s == v.X && s == v.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V2l a, V2l b) { return a.X != b.X || a.Y != b.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V2l v, long s) { return v.X != s || v.Y != s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(long s, V2l v) { return s != v.X || s != v.Y; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(V2l other) { return X.Equals(other.X) && Y.Equals(other.Y); } #endregion #region Overrides public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + X.ToString(format, fp) + between + Y.ToString(format, fp) + end; } public override readonly int GetHashCode() { return HashCode.GetCombined(X, Y); } public override readonly bool Equals(object other) => (other is V2l o) ? Equals(o) : false; public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + X.ToString(null, CultureInfo.InvariantCulture) + ", " + Y.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Parsing public static V2l Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new V2l( long.Parse(x[0], CultureInfo.InvariantCulture), long.Parse(x[1], CultureInfo.InvariantCulture) ); } public static V2l Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, V2l.Setter); } public static V2l Parse(Text t, int bracketLevel) { return t.NestedBracketSplit(bracketLevel, Text.Parse, V2l.Setter); } #endregion #region Swizzle Methods [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2l OO => new V2l(0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2l OI => new V2l(0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2l ON => new V2l(0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l OX => new V2l(0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l OY => new V2l(0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2l IO => new V2l(1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2l II => new V2l(1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2l PN => new V2l(1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l IX => new V2l(1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l IY => new V2l(1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2l NO => new V2l(-1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2l NP => new V2l(-1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2l NN => new V2l(-1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l NX => new V2l(-1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l NY => new V2l(-1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l XO => new V2l(X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l XI => new V2l(X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l XN => new V2l(X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l XX => new V2l(X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l XY { readonly get => new V2l(X, Y); set { X = value.X; Y = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l YO => new V2l(Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l YI => new V2l(Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l YN => new V2l(Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l YX { readonly get => new V2l(Y, X); set { Y = value.X; X = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l YY => new V2l(Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OOX => new V3l(0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OOY => new V3l(0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OIX => new V3l(0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OIY => new V3l(0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ONX => new V3l(0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ONY => new V3l(0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXO => new V3l(0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXI => new V3l(0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXN => new V3l(0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXX => new V3l(0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXY => new V3l(0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYO => new V3l(0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYI => new V3l(0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYN => new V3l(0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYX => new V3l(0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYY => new V3l(0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IOX => new V3l(1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IOY => new V3l(1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IIX => new V3l(1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IIY => new V3l(1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PNX => new V3l(1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PNY => new V3l(1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IXO => new V3l(1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IXI => new V3l(1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PXN => new V3l(1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IXX => new V3l(1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IXY => new V3l(1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IYO => new V3l(1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IYI => new V3l(1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PYN => new V3l(1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IYX => new V3l(1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IYY => new V3l(1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NOX => new V3l(-1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NOY => new V3l(-1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NPX => new V3l(-1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NPY => new V3l(-1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NNX => new V3l(-1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NNY => new V3l(-1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXO => new V3l(-1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXP => new V3l(-1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXN => new V3l(-1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXX => new V3l(-1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXY => new V3l(-1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYO => new V3l(-1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYP => new V3l(-1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYN => new V3l(-1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYX => new V3l(-1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYY => new V3l(-1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XOO => new V3l(X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XOI => new V3l(X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XON => new V3l(X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XOX => new V3l(X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XOY => new V3l(X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XIO => new V3l(X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XII => new V3l(X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XPN => new V3l(X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XIX => new V3l(X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XIY => new V3l(X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNO => new V3l(X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNP => new V3l(X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNN => new V3l(X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNX => new V3l(X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNY => new V3l(X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXO => new V3l(X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXI => new V3l(X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXN => new V3l(X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXX => new V3l(X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXY => new V3l(X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XYO => new V3l(X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XYI => new V3l(X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XYN => new V3l(X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XYX => new V3l(X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XYY => new V3l(X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YOO => new V3l(Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YOI => new V3l(Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YON => new V3l(Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YOX => new V3l(Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YOY => new V3l(Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YIO => new V3l(Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YII => new V3l(Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YPN => new V3l(Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YIX => new V3l(Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YIY => new V3l(Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNO => new V3l(Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNP => new V3l(Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNN => new V3l(Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNX => new V3l(Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNY => new V3l(Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YXO => new V3l(Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YXI => new V3l(Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YXN => new V3l(Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YXX => new V3l(Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YXY => new V3l(Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYO => new V3l(Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYI => new V3l(Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYN => new V3l(Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYX => new V3l(Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYY => new V3l(Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOOX => new V4l(0, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOOY => new V4l(0, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOIX => new V4l(0, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOIY => new V4l(0, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OONX => new V4l(0, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OONY => new V4l(0, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXO => new V4l(0, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXI => new V4l(0, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXN => new V4l(0, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXX => new V4l(0, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXY => new V4l(0, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYO => new V4l(0, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYI => new V4l(0, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYN => new V4l(0, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYX => new V4l(0, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYY => new V4l(0, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIOX => new V4l(0, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIOY => new V4l(0, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIIX => new V4l(0, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIIY => new V4l(0, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPNX => new V4l(0, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPNY => new V4l(0, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIXO => new V4l(0, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIXI => new V4l(0, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPXN => new V4l(0, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIXX => new V4l(0, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIXY => new V4l(0, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIYO => new V4l(0, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIYI => new V4l(0, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPYN => new V4l(0, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIYX => new V4l(0, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIYY => new V4l(0, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONOX => new V4l(0, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONOY => new V4l(0, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONPX => new V4l(0, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONPY => new V4l(0, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONNX => new V4l(0, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONNY => new V4l(0, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXO => new V4l(0, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXP => new V4l(0, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXN => new V4l(0, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXX => new V4l(0, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXY => new V4l(0, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYO => new V4l(0, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYP => new V4l(0, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYN => new V4l(0, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYX => new V4l(0, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYY => new V4l(0, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXOO => new V4l(0, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXOI => new V4l(0, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXON => new V4l(0, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXOX => new V4l(0, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXOY => new V4l(0, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXIO => new V4l(0, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXII => new V4l(0, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXPN => new V4l(0, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXIX => new V4l(0, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXIY => new V4l(0, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNO => new V4l(0, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNP => new V4l(0, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNN => new V4l(0, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNX => new V4l(0, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNY => new V4l(0, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXO => new V4l(0, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXI => new V4l(0, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXN => new V4l(0, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXX => new V4l(0, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXY => new V4l(0, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYO => new V4l(0, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYI => new V4l(0, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYN => new V4l(0, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYX => new V4l(0, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYY => new V4l(0, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYOO => new V4l(0, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYOI => new V4l(0, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYON => new V4l(0, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYOX => new V4l(0, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYOY => new V4l(0, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYIO => new V4l(0, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYII => new V4l(0, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYPN => new V4l(0, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYIX => new V4l(0, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYIY => new V4l(0, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNO => new V4l(0, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNP => new V4l(0, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNN => new V4l(0, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNX => new V4l(0, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNY => new V4l(0, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXO => new V4l(0, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXI => new V4l(0, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXN => new V4l(0, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXX => new V4l(0, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXY => new V4l(0, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYO => new V4l(0, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYI => new V4l(0, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYN => new V4l(0, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYX => new V4l(0, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYY => new V4l(0, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOOX => new V4l(1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOOY => new V4l(1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOIX => new V4l(1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOIY => new V4l(1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PONX => new V4l(1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PONY => new V4l(1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOXO => new V4l(1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOXI => new V4l(1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l POXN => new V4l(1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOXX => new V4l(1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOXY => new V4l(1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOYO => new V4l(1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOYI => new V4l(1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l POYN => new V4l(1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOYX => new V4l(1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOYY => new V4l(1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIOX => new V4l(1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIOY => new V4l(1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIIX => new V4l(1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIIY => new V4l(1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPNX => new V4l(1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPNY => new V4l(1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIXO => new V4l(1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIXI => new V4l(1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPXN => new V4l(1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIXX => new V4l(1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIXY => new V4l(1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIYO => new V4l(1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIYI => new V4l(1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPYN => new V4l(1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIYX => new V4l(1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIYY => new V4l(1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNOX => new V4l(1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNOY => new V4l(1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNPX => new V4l(1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNPY => new V4l(1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNNX => new V4l(1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNNY => new V4l(1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXO => new V4l(1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXP => new V4l(1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXN => new V4l(1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXX => new V4l(1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXY => new V4l(1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYO => new V4l(1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYP => new V4l(1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYN => new V4l(1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYX => new V4l(1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYY => new V4l(1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXOO => new V4l(1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXOI => new V4l(1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXON => new V4l(1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXOX => new V4l(1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXOY => new V4l(1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXIO => new V4l(1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXII => new V4l(1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXPN => new V4l(1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXIX => new V4l(1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXIY => new V4l(1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNO => new V4l(1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNP => new V4l(1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNN => new V4l(1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNX => new V4l(1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNY => new V4l(1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXXO => new V4l(1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXXI => new V4l(1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXXN => new V4l(1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXXX => new V4l(1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXXY => new V4l(1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXYO => new V4l(1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXYI => new V4l(1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXYN => new V4l(1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXYX => new V4l(1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXYY => new V4l(1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYOO => new V4l(1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYOI => new V4l(1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYON => new V4l(1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYOX => new V4l(1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYOY => new V4l(1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYIO => new V4l(1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYII => new V4l(1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYPN => new V4l(1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYIX => new V4l(1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYIY => new V4l(1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNO => new V4l(1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNP => new V4l(1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNN => new V4l(1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNX => new V4l(1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNY => new V4l(1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYXO => new V4l(1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYXI => new V4l(1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYXN => new V4l(1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYXX => new V4l(1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYXY => new V4l(1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYYO => new V4l(1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYYI => new V4l(1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYYN => new V4l(1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYYX => new V4l(1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYYY => new V4l(1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOOX => new V4l(-1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOOY => new V4l(-1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOPX => new V4l(-1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOPY => new V4l(-1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NONX => new V4l(-1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NONY => new V4l(-1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXO => new V4l(-1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXP => new V4l(-1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXN => new V4l(-1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXX => new V4l(-1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXY => new V4l(-1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYO => new V4l(-1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYP => new V4l(-1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYN => new V4l(-1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYX => new V4l(-1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYY => new V4l(-1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPOX => new V4l(-1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPOY => new V4l(-1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPPX => new V4l(-1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPPY => new V4l(-1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPNX => new V4l(-1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPNY => new V4l(-1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXO => new V4l(-1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXP => new V4l(-1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXN => new V4l(-1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXX => new V4l(-1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXY => new V4l(-1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYO => new V4l(-1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYP => new V4l(-1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYN => new V4l(-1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYX => new V4l(-1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYY => new V4l(-1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNOX => new V4l(-1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNOY => new V4l(-1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNPX => new V4l(-1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNPY => new V4l(-1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNNX => new V4l(-1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNNY => new V4l(-1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXO => new V4l(-1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXP => new V4l(-1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXN => new V4l(-1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXX => new V4l(-1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXY => new V4l(-1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYO => new V4l(-1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYP => new V4l(-1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYN => new V4l(-1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYX => new V4l(-1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYY => new V4l(-1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXOO => new V4l(-1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXOP => new V4l(-1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXON => new V4l(-1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXOX => new V4l(-1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXOY => new V4l(-1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPO => new V4l(-1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPP => new V4l(-1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPN => new V4l(-1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPX => new V4l(-1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPY => new V4l(-1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNO => new V4l(-1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNP => new V4l(-1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNN => new V4l(-1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNX => new V4l(-1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNY => new V4l(-1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXO => new V4l(-1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXP => new V4l(-1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXN => new V4l(-1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXX => new V4l(-1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXY => new V4l(-1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYO => new V4l(-1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYP => new V4l(-1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYN => new V4l(-1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYX => new V4l(-1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYY => new V4l(-1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYOO => new V4l(-1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYOP => new V4l(-1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYON => new V4l(-1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYOX => new V4l(-1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYOY => new V4l(-1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPO => new V4l(-1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPP => new V4l(-1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPN => new V4l(-1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPX => new V4l(-1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPY => new V4l(-1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNO => new V4l(-1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNP => new V4l(-1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNN => new V4l(-1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNX => new V4l(-1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNY => new V4l(-1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXO => new V4l(-1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXP => new V4l(-1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXN => new V4l(-1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXX => new V4l(-1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXY => new V4l(-1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYO => new V4l(-1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYP => new V4l(-1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYN => new V4l(-1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYX => new V4l(-1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYY => new V4l(-1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOOO => new V4l(X, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOOI => new V4l(X, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOON => new V4l(X, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOOX => new V4l(X, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOOY => new V4l(X, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOIO => new V4l(X, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOII => new V4l(X, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOPN => new V4l(X, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOIX => new V4l(X, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOIY => new V4l(X, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONO => new V4l(X, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONP => new V4l(X, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONN => new V4l(X, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONX => new V4l(X, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONY => new V4l(X, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXO => new V4l(X, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXI => new V4l(X, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXN => new V4l(X, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXX => new V4l(X, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXY => new V4l(X, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYO => new V4l(X, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYI => new V4l(X, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYN => new V4l(X, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYX => new V4l(X, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYY => new V4l(X, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIOO => new V4l(X, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIOI => new V4l(X, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPON => new V4l(X, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIOX => new V4l(X, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIOY => new V4l(X, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIIO => new V4l(X, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIII => new V4l(X, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPPN => new V4l(X, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIIX => new V4l(X, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIIY => new V4l(X, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNO => new V4l(X, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNP => new V4l(X, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNN => new V4l(X, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNX => new V4l(X, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNY => new V4l(X, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIXO => new V4l(X, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIXI => new V4l(X, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPXN => new V4l(X, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIXX => new V4l(X, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIXY => new V4l(X, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIYO => new V4l(X, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIYI => new V4l(X, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPYN => new V4l(X, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIYX => new V4l(X, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIYY => new V4l(X, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNOO => new V4l(X, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNOP => new V4l(X, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNON => new V4l(X, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNOX => new V4l(X, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNOY => new V4l(X, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPO => new V4l(X, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPP => new V4l(X, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPN => new V4l(X, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPX => new V4l(X, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPY => new V4l(X, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNO => new V4l(X, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNP => new V4l(X, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNN => new V4l(X, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNX => new V4l(X, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNY => new V4l(X, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXO => new V4l(X, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXP => new V4l(X, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXN => new V4l(X, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXX => new V4l(X, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXY => new V4l(X, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYO => new V4l(X, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYP => new V4l(X, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYN => new V4l(X, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYX => new V4l(X, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYY => new V4l(X, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXOO => new V4l(X, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXOI => new V4l(X, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXON => new V4l(X, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXOX => new V4l(X, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXOY => new V4l(X, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXIO => new V4l(X, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXII => new V4l(X, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXPN => new V4l(X, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXIX => new V4l(X, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXIY => new V4l(X, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNO => new V4l(X, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNP => new V4l(X, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNN => new V4l(X, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNX => new V4l(X, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNY => new V4l(X, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXO => new V4l(X, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXI => new V4l(X, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXN => new V4l(X, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXX => new V4l(X, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXY => new V4l(X, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYO => new V4l(X, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYI => new V4l(X, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYN => new V4l(X, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYX => new V4l(X, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYY => new V4l(X, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYOO => new V4l(X, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYOI => new V4l(X, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYON => new V4l(X, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYOX => new V4l(X, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYOY => new V4l(X, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYIO => new V4l(X, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYII => new V4l(X, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYPN => new V4l(X, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYIX => new V4l(X, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYIY => new V4l(X, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNO => new V4l(X, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNP => new V4l(X, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNN => new V4l(X, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNX => new V4l(X, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNY => new V4l(X, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXO => new V4l(X, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXI => new V4l(X, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXN => new V4l(X, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXX => new V4l(X, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXY => new V4l(X, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYO => new V4l(X, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYI => new V4l(X, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYN => new V4l(X, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYX => new V4l(X, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYY => new V4l(X, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOOO => new V4l(Y, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOOI => new V4l(Y, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOON => new V4l(Y, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOOX => new V4l(Y, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOOY => new V4l(Y, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOIO => new V4l(Y, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOII => new V4l(Y, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOPN => new V4l(Y, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOIX => new V4l(Y, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOIY => new V4l(Y, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONO => new V4l(Y, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONP => new V4l(Y, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONN => new V4l(Y, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONX => new V4l(Y, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONY => new V4l(Y, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXO => new V4l(Y, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXI => new V4l(Y, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXN => new V4l(Y, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXX => new V4l(Y, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXY => new V4l(Y, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYO => new V4l(Y, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYI => new V4l(Y, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYN => new V4l(Y, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYX => new V4l(Y, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYY => new V4l(Y, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIOO => new V4l(Y, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIOI => new V4l(Y, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPON => new V4l(Y, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIOX => new V4l(Y, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIOY => new V4l(Y, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIIO => new V4l(Y, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIII => new V4l(Y, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPPN => new V4l(Y, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIIX => new V4l(Y, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIIY => new V4l(Y, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNO => new V4l(Y, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNP => new V4l(Y, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNN => new V4l(Y, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNX => new V4l(Y, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNY => new V4l(Y, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIXO => new V4l(Y, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIXI => new V4l(Y, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPXN => new V4l(Y, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIXX => new V4l(Y, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIXY => new V4l(Y, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIYO => new V4l(Y, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIYI => new V4l(Y, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPYN => new V4l(Y, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIYX => new V4l(Y, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIYY => new V4l(Y, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNOO => new V4l(Y, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNOP => new V4l(Y, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNON => new V4l(Y, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNOX => new V4l(Y, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNOY => new V4l(Y, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPO => new V4l(Y, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPP => new V4l(Y, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPN => new V4l(Y, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPX => new V4l(Y, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPY => new V4l(Y, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNO => new V4l(Y, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNP => new V4l(Y, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNN => new V4l(Y, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNX => new V4l(Y, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNY => new V4l(Y, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXO => new V4l(Y, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXP => new V4l(Y, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXN => new V4l(Y, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXX => new V4l(Y, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXY => new V4l(Y, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYO => new V4l(Y, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYP => new V4l(Y, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYN => new V4l(Y, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYX => new V4l(Y, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYY => new V4l(Y, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXOO => new V4l(Y, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXOI => new V4l(Y, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXON => new V4l(Y, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXOX => new V4l(Y, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXOY => new V4l(Y, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXIO => new V4l(Y, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXII => new V4l(Y, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXPN => new V4l(Y, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXIX => new V4l(Y, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXIY => new V4l(Y, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNO => new V4l(Y, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNP => new V4l(Y, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNN => new V4l(Y, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNX => new V4l(Y, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNY => new V4l(Y, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXO => new V4l(Y, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXI => new V4l(Y, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXN => new V4l(Y, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXX => new V4l(Y, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXY => new V4l(Y, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYO => new V4l(Y, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYI => new V4l(Y, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYN => new V4l(Y, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYX => new V4l(Y, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYY => new V4l(Y, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYOO => new V4l(Y, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYOI => new V4l(Y, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYON => new V4l(Y, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYOX => new V4l(Y, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYOY => new V4l(Y, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYIO => new V4l(Y, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYII => new V4l(Y, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYPN => new V4l(Y, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYIX => new V4l(Y, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYIY => new V4l(Y, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNO => new V4l(Y, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNP => new V4l(Y, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNN => new V4l(Y, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNX => new V4l(Y, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNY => new V4l(Y, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXO => new V4l(Y, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXI => new V4l(Y, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXN => new V4l(Y, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXX => new V4l(Y, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXY => new V4l(Y, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYO => new V4l(Y, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYI => new V4l(Y, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYN => new V4l(Y, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYX => new V4l(Y, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYY => new V4l(Y, Y, Y, Y); #endregion #region IVector Members /// /// By using long indices, the IVector<double> interface is /// accessed. /// public double this[long i] { readonly get { return (double)this[(int)i]; } set { this[(int)i] = (long)value; } } #endregion #region ISize2l Members public readonly V2l Size2l { get { return this; } } #endregion #region IVector public readonly long Dim { get { return 2; } } public readonly object GetValue(long index) { return (object)this[(int)index]; } public void SetValue(object value, long index) { this[(int)index] = (long)value; } #endregion } public class V2lEqualityComparer : IEqualityComparer { public static V2lEqualityComparer Default => new V2lEqualityComparer(); #region IEqualityComparer Members public bool Equals(V2l v0, V2l v1) { return v0 == v1; } public int GetHashCode(V2l v) { return v.GetHashCode(); } #endregion } public static partial class Fun { #region Min and Max /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Min(this V2l a, V2l b) { return new V2l(Min(a.X, b.X), Min(a.Y, b.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Min(this V2l a, long b) { return new V2l(Min(a.X, b), Min(a.Y, b)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Min(this long a, V2l b) { return new V2l(Min(a, b.X), Min(a, b.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Max(this V2l a, V2l b) { return new V2l(Max(a.X, b.X), Max(a.Y, b.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Max(this V2l a, long b) { return new V2l(Max(a.X, b), Max(a.Y, b)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Max(this long a, V2l b) { return new V2l(Max(a, b.X), Max(a, b.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Min(this V2l a, V2l b, V2l c) { return new V2l(Min(a.X, b.X, c.X), Min(a.Y, b.Y, c.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Max(this V2l a, V2l b, V2l c) { return new V2l(Max(a.X, b.X, c.X), Max(a.Y, b.Y, c.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Min(this V2l a, V2l b, V2l c, V2l d) { return new V2l(Min(a.X, b.X, c.X, d.X), Min(a.Y, b.Y, c.Y, d.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Max(this V2l a, V2l b, V2l c, V2l d) { return new V2l(Max(a.X, b.X, c.X, d.X), Max(a.Y, b.Y, c.Y, d.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Min(this V2l x, params V2l[] values) { return new V2l(Min(x.X, values.Map(a => a.X)), Min(x.Y, values.Map(a => a.Y))); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Max(this V2l x, params V2l[] values) { return new V2l(Max(x.X, values.Map(a => a.X)), Max(x.Y, values.Map(a => a.Y))); } #endregion #region Abs /// /// Applies Fun.Abs to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Abs(this V2l x) { return new V2l(Abs(x.X), Abs(x.Y)); } #endregion #region Clamping /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Clamp(this V2l x, V2l a, V2l b) { return new V2l(Clamp(x.X, a.X, b.X), Clamp(x.Y, a.Y, b.Y)); } /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Clamp(this V2l x, long a, long b) { return new V2l(Clamp(x.X, a, b), Clamp(x.Y, a, b)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l ClampExcl(this V2l x, V2l a, V2l b) { return new V2l(ClampExcl(x.X, a.X, b.X), ClampExcl(x.Y, a.Y, b.Y)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l ClampExcl(this V2l x, long a, long b) { return new V2l(ClampExcl(x.X, a, b), ClampExcl(x.Y, a, b)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l ClampWrap(this V2l x, V2l a, V2l b) { return new V2l(ClampWrap(x.X, a.X, b.X), ClampWrap(x.Y, a.Y, b.Y)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l ClampWrap(this V2l x, long a, long b) { return new V2l(ClampWrap(x.X, a, b), ClampWrap(x.Y, a, b)); } /// /// Applies Fun.Saturate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Saturate(this V2l x) { return new V2l(Saturate(x.X), Saturate(x.Y)); } #endregion #region Sign /// /// Applies Fun.Sign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Sign(this V2l x) { return new V2i(Sign(x.X), Sign(x.Y)); } /// /// Applies Fun.Signumi to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Signumi(this V2l x) { return new V2i(Signumi(x.X), Signumi(x.Y)); } /// /// Applies Fun.Signum to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Signum(this V2l x) { return new V2l(Signum(x.X), Signum(x.Y)); } #endregion #region Multiply-Add /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l MultiplyAdd(V2l x, V2l y, V2l z) { return new V2l(MultiplyAdd(x.X, y.X, z.X), MultiplyAdd(x.Y, y.Y, z.Y)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l MultiplyAdd(V2l x, long y, V2l z) { return new V2l(MultiplyAdd(x.X, y, z.X), MultiplyAdd(x.Y, y, z.Y)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l MultiplyAdd(long x, V2l y, V2l z) { return new V2l(MultiplyAdd(x, y.X, z.X), MultiplyAdd(x, y.Y, z.Y)); } #endregion #region Roots /// /// Applies Fun.Sqrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Sqrt(this V2l x) { return new V2d(Sqrt(x.X), Sqrt(x.Y)); } /// /// Applies Fun.Cbrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Cbrt(this V2l x) { return new V2d(Cbrt(x.X), Cbrt(x.Y)); } #endregion #region Square /// /// Applies Fun.Square to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Square(this V2l x) { return new V2l(Square(x.X), Square(x.Y)); } #endregion #region Power /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Pown(this V2l x, V2l y) { return new V2l(Pown(x.X, y.X), Pown(x.Y, y.Y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Pown(this V2l x, long y) { return new V2l(Pown(x.X, y), Pown(x.Y, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Pown(this long x, V2l y) { return new V2l(Pown(x, y.X), Pown(x, y.Y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Pown(this V2l x, V2i y) { return new V2l(Pown(x.X, y.X), Pown(x.Y, y.Y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Pown(this V2l x, int y) { return new V2l(Pown(x.X, y), Pown(x.Y, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Pown(this long x, V2i y) { return new V2l(Pown(x, y.X), Pown(x, y.Y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Pow(this V2l x, V2f y) { return new V2f(Pow(x.X, y.X), Pow(x.Y, y.Y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Pow(this V2l x, float y) { return new V2f(Pow(x.X, y), Pow(x.Y, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Pow(this long x, V2f y) { return new V2f(Pow(x, y.X), Pow(x, y.Y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Pow(this V2l x, V2d y) { return new V2d(Pow(x.X, y.X), Pow(x.Y, y.Y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Pow(this V2l x, double y) { return new V2d(Pow(x.X, y), Pow(x.Y, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Pow(this long x, V2d y) { return new V2d(Pow(x, y.X), Pow(x, y.Y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Power(this V2l x, V2f y) { return new V2f(Power(x.X, y.X), Power(x.Y, y.Y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Power(this V2l x, float y) { return new V2f(Power(x.X, y), Power(x.Y, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Power(this long x, V2f y) { return new V2f(Power(x, y.X), Power(x, y.Y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Power(this V2l x, V2d y) { return new V2d(Power(x.X, y.X), Power(x.Y, y.Y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Power(this V2l x, double y) { return new V2d(Power(x.X, y), Power(x.Y, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Power(this long x, V2d y) { return new V2d(Power(x, y.X), Power(x, y.Y)); } #endregion #region Exp and Log /// /// Applies Fun.Exp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Exp(this V2l x) { return new V2d(Exp(x.X), Exp(x.Y)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log(this V2l x) { return new V2d(Log(x.X), Log(x.Y)); } /// /// Applies Fun.Log2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log2(this V2l x) { return new V2d(Log2(x.X), Log2(x.Y)); } /// /// Applies Fun.Log2Int to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Log2Int(this V2l x) { return new V2i(Log2Int(x.X), Log2Int(x.Y)); } /// /// Applies Fun.Log10 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log10(this V2l x) { return new V2d(Log10(x.X), Log10(x.Y)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log(this V2l x, double basis) { return new V2d(Log(x.X, basis), Log(x.Y, basis)); } #endregion #region ModP /// /// Applies Fun.ModP to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l ModP(this V2l a, V2l b) { return new V2l(ModP(a.X, b.X), ModP(a.Y, b.Y)); } #endregion #region Power of Two /// /// Applies Fun.PowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l PowerOfTwo(this V2l x) { return new V2l(PowerOfTwo(x.X), PowerOfTwo(x.Y)); } /// /// Applies Fun.NextPowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l NextPowerOfTwo(this V2l x) { return new V2l(NextPowerOfTwo(x.X), NextPowerOfTwo(x.Y)); } /// /// Applies Fun.PrevPowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l PrevPowerOfTwo(this V2l x) { return new V2l(PrevPowerOfTwo(x.X), PrevPowerOfTwo(x.Y)); } #endregion #region Step functions /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Step(this V2l x, V2l edge) { return new V2l(Step(x.X, edge.X), Step(x.Y, edge.Y)); } /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Step(this V2l x, long edge) { return new V2l(Step(x.X, edge), Step(x.Y, edge)); } #endregion #region Interpolation /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Lerp(this float t, V2l a, V2l b) { return new V2l(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Lerp(this V2f t, V2l a, V2l b) { return new V2l(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Lerp(this double t, V2l a, V2l b) { return new V2l(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Lerp(this V2d t, V2l a, V2l b) { return new V2l(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y)); } /// /// Applies Fun.InvLerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d InvLerp(this V2l y, V2l a, V2l b) { return new V2d(InvLerp(y.X, a.X, b.X), InvLerp(y.Y, a.Y, b.Y)); } #endregion #region Common Divisor and Multiple /// /// Applies Fun.GreatestCommonDivisor to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l GreatestCommonDivisor(this V2l a, V2l b) { return new V2l(GreatestCommonDivisor(a.X, b.X), GreatestCommonDivisor(a.Y, b.Y)); } /// /// Applies Fun.LeastCommonMultiple to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l LeastCommonMultiple(this V2l a, V2l b) { return new V2l(LeastCommonMultiple(a.X, b.X), LeastCommonMultiple(a.Y, b.Y)); } #endregion #region Floating point bits /// /// Applies Fun.FloatFromBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d FloatFromBits(this V2l x) { return new V2d(FloatFromBits(x.X), FloatFromBits(x.Y)); } #endregion #region ApproximateEquals /// /// Returns whether the given vectors are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V2l a, V2l b, long tolerance) { return ApproximateEquals(a.X, b.X, tolerance) && ApproximateEquals(a.Y, b.Y, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this V2l v, long epsilon) => Vec.AllTiny(v, epsilon); #endregion } /// /// Contains static methods /// public static partial class Vec { #region Length /// /// Returns the squared length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long LengthSquared(V2l v) => v.LengthSquared; /// /// Returns the length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Length(V2l v) => v.Length; #endregion #region Normalize /// /// Returns a normalized copy of this vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Normalized(V2l v) => v.Normalized; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Norm1(V2l v) => v.Norm1; /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(V2l v) => v.Norm2; /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NormMax(V2l v) => v.NormMax; /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NormMin(V2l v) => v.NormMin; /// /// Gets the p-norm. This is calculated as the p-th root of (|x|^n + |y|^n + ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this V2l v, double p) { return ( Fun.Abs(v.X).Pow(p) + Fun.Abs(v.Y).Pow(p)).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the squared distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long DistanceSquared(this V2l a, V2l b) => Fun.Square(b.X - a.X) + Fun.Square(b.Y - a.Y); /// /// Returns the distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V2l a, V2l b) => Fun.Sqrt(DistanceSquared(a, b)); /// /// Returns the Manhatten (or 1-) distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Distance1(this V2l a, V2l b) => Fun.Abs(b.X - a.X) + Fun.Abs(b.Y - a.Y); /// /// Returns the p-distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V2l a, V2l b, double p) => (Fun.Abs(b.X - a.X).Pow(p) + Fun.Abs(b.Y - a.Y).Pow(p)).Pow(1 / p); /// /// Returns the maximal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long DistanceMax(this V2l a, V2l b) => Fun.Max(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y)); /// /// Returns the minimal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long DistanceMin(this V2l a, V2l b) => Fun.Min(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y)); /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V2l query, V2l p0, V2l p1) { return DistanceToLine((V2d) query, (V2d) p0, (V2d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V2l query, V2l p0, V2l p1) { return DistanceToInfiniteLine((V2d) query, (V2d) p0, (V2d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V2l query, V2l p0, V2l p1, out double t) { return DistanceToLine((V2d) query, (V2d) p0, (V2d) p1, out t); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V2l query, V2l p0, V2l p1, out double t) { return DistanceToInfiniteLine((V2d) query, (V2d) p0, (V2d) p1, out t); } #endregion #region Operations /// /// Returns a vector that is orthogonal to the given one (i.e. {x,y} -> {-y,x}). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l Orthogonal(V2l v) => v.Orthogonal; /// /// Negates the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Negate(this ref V2l v) { v.X = -v.X; v.Y = -v.Y; } /// /// Returns the outer product (tensor-product) of a * b^T as a 2x2 matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22l Outer(this V2l a, V2l b) { return new M22l( a.X * b.X, a.X * b.Y, a.Y * b.X, a.Y * b.Y); } /// /// Returns the dot product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Dot(this V2l a, V2l b) { return a.X * b.X + a.Y * b.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DirFlags DirFlags(this V2l v) { DirFlags flags = Aardbase.DirFlags.None; if (v.X > 0) flags |= Aardbase.DirFlags.PositiveX; if (v.X < 0) flags |= Aardbase.DirFlags.NegativeX; if (v.Y > 0) flags |= Aardbase.DirFlags.PositiveY; if (v.Y < 0) flags |= Aardbase.DirFlags.NegativeY; return flags; } /// /// Returns the cross product of vector a. /// In 2D the cross product is simply a vector that is normal /// to the given vector (i.e. {x,y} -> {-y,x}) /// public static V2l Cross(this V2l a) { return new V2l(-a.Y, a.X); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V2l a, V2l b) { return (a.X < b.X && a.Y < b.Y); } /// /// Returns whether ALL elements of v are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V2l v, long s) { return (v.X < s && v.Y < s); } /// /// Returns whether a is Smaller ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(long s, V2l v) { return (s < v.X && s < v.Y); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V2l a, V2l b) { return (a.X < b.X || a.Y < b.Y); } /// /// Returns whether AT LEAST ONE element of v is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V2l v, long s) { return (v.X < s || v.Y < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(long s, V2l v) { return (s < v.X || s < v.Y); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V2l a, V2l b) { return (a.X > b.X && a.Y > b.Y); } /// /// Returns whether ALL elements of v are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V2l v, long s) { return (v.X > s && v.Y > s); } /// /// Returns whether a is Greater ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(long s, V2l v) { return (s > v.X && s > v.Y); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V2l a, V2l b) { return (a.X > b.X || a.Y > b.Y); } /// /// Returns whether AT LEAST ONE element of v is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V2l v, long s) { return (v.X > s || v.Y > s); } /// /// Returns whether a is Greater AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(long s, V2l v) { return (s > v.X || s > v.Y); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V2l a, V2l b) { return (a.X <= b.X && a.Y <= b.Y); } /// /// Returns whether ALL elements of v are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V2l v, long s) { return (v.X <= s && v.Y <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(long s, V2l v) { return (s <= v.X && s <= v.Y); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V2l a, V2l b) { return (a.X <= b.X || a.Y <= b.Y); } /// /// Returns whether AT LEAST ONE element of v is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V2l v, long s) { return (v.X <= s || v.Y <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(long s, V2l v) { return (s <= v.X || s <= v.Y); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V2l a, V2l b) { return (a.X >= b.X && a.Y >= b.Y); } /// /// Returns whether ALL elements of v are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V2l v, long s) { return (v.X >= s && v.Y >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(long s, V2l v) { return (s >= v.X && s >= v.Y); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V2l a, V2l b) { return (a.X >= b.X || a.Y >= b.Y); } /// /// Returns whether AT LEAST ONE element of v is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V2l v, long s) { return (v.X >= s || v.Y >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(long s, V2l v) { return (s >= v.X || s >= v.Y); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V2l a, V2l b) { return (a.X == b.X && a.Y == b.Y); } /// /// Returns whether ALL elements of v are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V2l v, long s) { return (v.X == s && v.Y == s); } /// /// Returns whether a is Equal ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(long s, V2l v) { return (s == v.X && s == v.Y); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V2l a, V2l b) { return (a.X == b.X || a.Y == b.Y); } /// /// Returns whether AT LEAST ONE element of v is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V2l v, long s) { return (v.X == s || v.Y == s); } /// /// Returns whether a is Equal AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(long s, V2l v) { return (s == v.X || s == v.Y); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V2l a, V2l b) { return (a.X != b.X && a.Y != b.Y); } /// /// Returns whether ALL elements of v are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V2l v, long s) { return (v.X != s && v.Y != s); } /// /// Returns whether a is Different ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(long s, V2l v) { return (s != v.X && s != v.Y); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V2l a, V2l b) { return (a.X != b.X || a.Y != b.Y); } /// /// Returns whether AT LEAST ONE element of v is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V2l v, long s) { return (v.X != s || v.Y != s); } /// /// Returns whether a is Different AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(long s, V2l v) { return (s != v.X || s != v.Y); } /// /// Compare x-coordinate before y-coordinate, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this V2l v0, V2l v1) { if (v0.X < v1.X) return -1; if (v0.X > v1.X) return +1; if (v0.Y < v1.Y) return -1; if (v0.Y > v1.Y) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MinElement(V2l v) => v.MinElement; /// /// Returns the maximum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MaxElement(V2l v) => v.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this V2l v, long epsilon) => v.X.IsTiny(epsilon) || v.Y.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this V2l v, long epsilon) => v.X.IsTiny(epsilon) && v.Y.IsTiny(epsilon); #endregion #region ArrayExtensions public static int IndexOfClosestPoint(this V2l[] pointArray, V2l point) { var bestDist = DistanceSquared(point, pointArray[0]); int bestIndex = 0; int count = pointArray.Length; for (int i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this V2l[] array, int start, int count, V2l point) { var bestDist = DistanceSquared(point, array[start]); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this T[] array, int start, int count, Func pointSelector, V2l point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint(this V2l[] pointArray, V2l point) { var bestDist = DistanceSquared(point, pointArray[0]); long bestIndex = 0; long count = pointArray.LongLength; for (long i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this V2l[] array, long start, long count, V2l point) { var bestDist = DistanceSquared(point, array[start]); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this T[] array, long start, long count, Func pointSelector, V2l point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static int IndexOfMinX(this V2l[] vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static long LongIndexOfMinX(this V2l[] vectorArray, long count = 0) { var minimum = vectorArray[0].X; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static int IndexOfMaxX(this V2l[] vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static long LongIndexOfMaxX(this V2l[] vectorArray, long count = 0) { var maximum = vectorArray[0].X; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static int IndexOfMinY(this V2l[] vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static long LongIndexOfMinY(this V2l[] vectorArray, long count = 0) { var minimum = vectorArray[0].Y; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static int IndexOfMaxY(this V2l[] vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static long LongIndexOfMaxY(this V2l[] vectorArray, long count = 0) { var maximum = vectorArray[0].Y; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the list. /// public static int IndexOfMinX(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the list. /// public static int IndexOfMaxX(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the list. /// public static int IndexOfMinY(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the list. /// public static int IndexOfMaxY(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the array of the index-th coordinate of each vector. /// public static long[] CopyCoord(this V2l[] self, int index) { switch (index) { case 0: return self.Map(v => v.X); case 1: return self.Map(v => v.Y); default: throw new IndexOutOfRangeException(); } } #endregion } public static class IRandomUniformV2lExtensions { #region IRandomUniform extensions for V2l /// /// Uses UniformLong() to generate the elements of a V2l vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l UniformV2l(this IRandomUniform rnd) { return new V2l(rnd.UniformLong(), rnd.UniformLong()); } /// /// Uses UniformLongNonZero() to generate the elements of a V2l vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l UniformV2lNonZero(this IRandomUniform rnd) { return new V2l(rnd.UniformLongNonZero(), rnd.UniformLongNonZero()); } /// /// Uses UniformLong(long) to generate the elements of a V2l vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l UniformV2l(this IRandomUniform rnd, long size) { return new V2l(rnd.UniformLong(size), rnd.UniformLong(size)); } /// /// Uses UniformLong(long) to generate the elements of a V2l vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l UniformV2l(this IRandomUniform rnd, V2l size) { return new V2l(rnd.UniformLong(size.X), rnd.UniformLong(size.Y)); } #endregion } #endregion #region V2f [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct V2f : IVector, ISize2f, IFormattable, IEquatable { [DataMember] public float X; [DataMember] public float Y; #region Constructors /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(int x, int y) { X = (float)x; Y = (float)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(int v) { X = (float)v; Y = (float)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(int[] a) { X = (float)a[0]; Y = (float)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(int[] a, int start) { X = (float)a[start + 0]; Y = (float)a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(uint x, uint y) { X = (float)x; Y = (float)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(uint v) { X = (float)v; Y = (float)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(uint[] a) { X = (float)a[0]; Y = (float)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(uint[] a, int start) { X = (float)a[start + 0]; Y = (float)a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(long x, long y) { X = (float)x; Y = (float)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(long v) { X = (float)v; Y = (float)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(long[] a) { X = (float)a[0]; Y = (float)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(long[] a, int start) { X = (float)a[start + 0]; Y = (float)a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(float x, float y) { X = x; Y = y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(float v) { X = v; Y = v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(float[] a) { X = a[0]; Y = a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(float[] a, int start) { X = a[start + 0]; Y = a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(double x, double y) { X = (float)x; Y = (float)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(double v) { X = (float)v; Y = (float)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(double[] a) { X = (float)a[0]; Y = (float)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(double[] a, int start) { X = (float)a[start + 0]; Y = (float)a[start + 1]; } /// /// Creates a vector from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(Func index_fun) { X = index_fun(0); Y = index_fun(1); } /// /// Creates a vector from a general vector implementing the IVector<float> interface. /// The caller has to verify that the dimension of is at least 2. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(IVector v) : this(v[0], v[1]) { } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(V2i v) { X = (float)v.X; Y = (float)v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(V2ui v) { X = (float)v.X; Y = (float)v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(V2l v) { X = (float)v.X; Y = (float)v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(V2f v) { X = v.X; Y = v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(V2d v) { X = (float)v.X; Y = (float)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(V3i v) { X = (float)v.X; Y = (float)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(V3ui v) { X = (float)v.X; Y = (float)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(V3l v) { X = (float)v.X; Y = (float)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(V3f v) { X = v.X; Y = v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(V3d v) { X = (float)v.X; Y = (float)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(V4i v) { X = (float)v.X; Y = (float)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(V4ui v) { X = (float)v.X; Y = (float)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(V4l v) { X = (float)v.X; Y = (float)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(V4f v) { X = v.X; Y = v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2f(V4d v) { X = (float)v.X; Y = (float)v.Y; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(V2i v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(V2ui v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(V2l v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(V2d v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(V3i v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(V3ui v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(V3l v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(V3f v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(V3d v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(V4i v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(V4ui v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(V4l v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(V4f v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(V4d v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToV2i() => (V2i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui ToV2ui() => (V2ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToV2l() => (V2l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d ToV2d() => (V2d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int[](V2f v) => new int[] { (int)v.X, (int)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(int[] v) => new V2f((float)v[0], (float)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](V2f v) => new uint[] { (uint)v.X, (uint)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(uint[] v) => new V2f((float)v[0], (float)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long[](V2f v) => new long[] { (long)v.X, (long)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(long[] v) => new V2f((float)v[0], (float)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](V2f v) => new float[] { v.X, v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(float[] v) => new V2f(v[0], v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](V2f v) => new double[] { (double)v.X, (double)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2f(double[] v) => new V2f((float)v[0], (float)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToFloorV2i() => new V2i((int)Fun.Floor(X), (int)Fun.Floor(Y)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToCeilingV2i() => new V2i((int)Fun.Ceiling(X), (int)Fun.Ceiling(Y)); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3iHomo() => new V3i(X, Y, 1); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3uiHomo() => new V3ui(X, Y, 1); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3lHomo() => new V3l(X, Y, 1); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3fHomo() => new V3f(X, Y, 1); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3dHomo() => new V3d(X, Y, 1); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i Copy(Func element_fun) => new V2i(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i Copy(Func element_index_fun) => new V2i(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(int[] array, int start) { array[start + 0] = (int)X; array[start + 1] = (int)Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui Copy(Func element_fun) => new V2ui(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui Copy(Func element_index_fun) => new V2ui(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(uint[] array, int start) { array[start + 0] = (uint)X; array[start + 1] = (uint)Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l Copy(Func element_fun) => new V2l(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l Copy(Func element_index_fun) => new V2l(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(long[] array, int start) { array[start + 0] = (long)X; array[start + 1] = (long)Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f Copy(Func element_fun) => new V2f(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f Copy(Func element_index_fun) => new V2f(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(float[] array, int start) { array[start + 0] = X; array[start + 1] = Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d Copy(Func element_fun) => new V2d(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d Copy(Func element_index_fun) => new V2d(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(double[] array, int start) { array[start + 0] = (double)X; array[start + 1] = (double)Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(X); array[start + 1] = element_fun(Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(X, 0); array[start + 1] = element_index_fun(Y, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float[] ToArray() => new float[] { X, Y }; #endregion #region Properties and Indexers /// /// Property for the field X. /// Useful when properties are required, but the field X is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public float P_X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value; } } /// /// Property for the field Y. /// Useful when properties are required, but the field Y is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public float P_Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Y = value; } } /// /// Enumerates all elements of this vector. /// public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return X; yield return Y; } } /// /// Gets or sets element with given index. /// public unsafe float this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &X) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &X) { ptr[index] = value; } } } /// /// Returns the index of the largest dimension of the vector. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X >= Y ? 0 : 1; } } /// /// Returns the index of the smallest dimension of the vector. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X <= Y ? 0 : 1; } } /// /// Returns the minimum element of the vector. /// public readonly float MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(X, Y); } /// /// Returns the maximum element of the vector. /// public readonly float MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(X, Y); } public readonly bool AnyFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsFinite(X) || Fun.IsFinite(Y); } public readonly bool AllFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsFinite(X) && Fun.IsFinite(Y); } public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNaN(X) || float.IsNaN(Y); } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNaN(X) && float.IsNaN(Y); } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsInfinity(X) || float.IsInfinity(Y); } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsInfinity(X) && float.IsInfinity(Y); } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsPositiveInfinity(X) || float.IsPositiveInfinity(Y); } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsPositiveInfinity(X) && float.IsPositiveInfinity(Y); } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNegativeInfinity(X) || float.IsNegativeInfinity(Y); } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNegativeInfinity(X) && float.IsNegativeInfinity(Y); } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(X) || Fun.IsTiny(Y); } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(X) && Fun.IsTiny(Y); } /// /// Returns true if the absolute value of each component of the vector is smaller than Constant<float>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any component of the vector is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any component of the vector is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any component of the vector is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any component of the vector is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all components of the vector are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Constants /// /// Number of elements in this vector. /// public const int Dimension = 2; /// /// All elements zero. /// public static V2f Zero { get { return new V2f(0, 0); } } /// /// All elements half. /// public static V2f Half { get { return new V2f(0.5, 0.5); } } /// /// All elements one. /// public static V2f One { get { return new V2f(1, 1); } } /// /// All elements set to maximum possible value. /// public static V2f MaxValue { get { return new V2f(Constant.ParseableMaxValue, Constant.ParseableMaxValue); } } /// /// All elements set to minimum possible value. /// public static V2f MinValue { get { return new V2f(Constant.ParseableMinValue, Constant.ParseableMinValue); } } /// /// All elements set to negative infinity. /// public static V2f NegativeInfinity { get { return new V2f(float.NegativeInfinity, float.NegativeInfinity); } } /// /// All elements set to positive infinity. /// public static V2f PositiveInfinity { get { return new V2f(float.PositiveInfinity, float.PositiveInfinity); } } /// /// All elements set to NaN. /// public static V2f NaN { get { return new V2f(float.NaN, float.NaN); } } /// /// Normalized X-axis. /// public static V2f XAxis { get { return new V2f(1, 0); } } /// /// Normalized Y-axis. /// public static V2f YAxis { get { return new V2f(0, 1); } } /// /// An array of accessor functions for the coordinates of the vector. /// public static readonly Func[] SelectorArray = new Func[] { v => v.X, v => v.Y }; /// /// Element getter function. /// public static readonly Func Getter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref V2f v, int i, float s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; default: throw new IndexOutOfRangeException(); } }; /// /// Element getter function with long index. /// public static readonly Func LongGetter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action with long index. /// public static readonly ActionRefValVal LongSetter = (ref V2f v, long i, float s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Static factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f FromV2i(V2i v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f FromV2ui(V2ui v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f FromV2l(V2l v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f FromV2d(V2d v) => new V2f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f FromPolar(float angleInRadians, float radius) => new V2f(Fun.Cos(angleInRadians) * radius, Fun.Sin(angleInRadians) * radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f FromPolar(float angleInRadians) => new V2f(Fun.Cos(angleInRadians), Fun.Sin(angleInRadians)); #endregion #region Norms /// /// Returns the squared length of the vector. /// public readonly float LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X * X + Y * Y ; } } /// /// Returns the length of the vector. /// public readonly float Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y ); } } /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// public readonly float Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Abs(X) + Fun.Abs(Y); } } /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// public readonly float Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y); } } /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// public readonly float NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(Fun.Abs(X), Fun.Abs(Y)); } } /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// public readonly float NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(Fun.Abs(X), Fun.Abs(Y)); } } /// /// Returns a normalized copy of this vector. /// public readonly V2f Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Length; if (s == 0) return V2f.Zero; s = 1 / s; return new V2f(X * s, Y * s); } } /// /// Vector rotated 90° counter clockwise: (-Y, X) /// public readonly V2f Rot90 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2f(-Y, X); } } /// /// Vector rotated 180° counter clockwise: (-X, -Y) /// public readonly V2f Rot180 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2f(-X, -Y); } } /// /// Vector rotated 270° counter clockwise: (Y, -X) /// public readonly V2f Rot270 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2f(Y, -X); } } /// /// Returns a copy of the vector with the maximum component length of /// exactly 1. This corresponds to mapping the vector onto an origin- /// centered square with side length 2. /// public readonly V2f CubeMapped { get { float x = Fun.Abs(X); float y = Fun.Abs(Y); return x > y ? new V2f(Fun.Sign(X), Y / x) : new V2f(X / y, Fun.Sign(Y)); } } #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Abs(V2f v) => v.Abs(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Floor(V2f v) => v.Floor(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Ceiling(V2f v) => v.Ceiling(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Round(V2f v) => v.Round(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Truncate(V2f v) => v.Truncate(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Acos(V2f v) => Fun.Acos(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Acoshb(V2f v) => Fun.Acosh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Cos(V2f v) => Fun.Cos(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Cosh(V2f v) => Fun.Cosh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Asin(V2f v) => Fun.Asin(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Asinhb(V2f v) => Fun.Asinh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Sin(V2f v) => Fun.Sin(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Sinh(V2f v) => Fun.Sinh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Atan(V2f v) => Fun.Atan(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Atanhb(V2f v) => Fun.Atanh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Atan2(V2f a, V2f b) => Fun.Atan2(a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Tan(V2f v) => Fun.Tan(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Tanh(V2f v) => Fun.Tanh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Sqrt(V2f v) => Fun.Sqrt(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f CubeRoot(V2f v) => Fun.Cbrt(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Exp(V2f v) => Fun.Exp(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Log(V2f v) => Fun.Log(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f LogBinary(V2f v) => Fun.Log2(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Log10(V2f v) => Fun.Log10(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f CopySgn(V2f value, V2f sign) => Fun.CopySign(value, sign); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f CopySgn(V2f value, float sign) => Fun.CopySign(value, sign); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f LinearInterp(float t, V2f a, V2f b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f LinearInterp(V2f t, V2f a, V2f b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Min(V2f v0, V2f v1) => Fun.Min(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Min(V2f v, float x) => Fun.Min(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Max(V2f v0, V2f v1) => Fun.Max(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Max(V2f v, float x) => Fun.Max(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Saturate(V2f v) => Fun.Saturate(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f DivideByInt(V2f v, int x) => v / x; #endregion #region Operations /// /// Sets the elements of a vector to the given int elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(int x, int y) { X = (float)x; Y = (float)y; } /// /// Sets the elements of a vector to the given uint elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(uint x, uint y) { X = (float)x; Y = (float)y; } /// /// Sets the elements of a vector to the given long elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(long x, long y) { X = (float)x; Y = (float)y; } /// /// Sets the elements of a vector to the given float elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(float x, float y) { X = x; Y = y; } /// /// Sets the elements of a vector to the given double elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(double x, double y) { X = (float)x; Y = (float)y; } /// /// Returns a negated copy of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator -(V2f v) => new V2f(-v.X, -v.Y); /// /// Returns a vector that is orthogonal to this one (i.e. {x,y} -> {-y,x}). /// public readonly V2f Orthogonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2f(-Y, X); } } /// /// Gets a copy of this vector containing the reciprocal (1/x) of each element. /// public readonly V2f Reciprocal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2f(1 / X, 1 / Y); } } /// /// Returns the component-wise sum of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator +(V2f a, V2f b) => new V2f(a.X + b.X, a.Y + b.Y); /// /// Returns the component-wise sum of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator +(V2f v, float s) => new V2f(v.X + s, v.Y + s); /// /// Returns the component-wise sum of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator +(float s, V2f v) => new V2f(s + v.X, s + v.Y); /// /// Returns the component-wise difference of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator -(V2f a, V2f b) => new V2f(a.X - b.X, a.Y - b.Y); /// /// Returns the component-wise difference of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator -(V2f v, float s) => new V2f(v.X - s, v.Y - s); /// /// Returns the component-wise difference of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator -(float s, V2f v) => new V2f(s - v.X, s - v.Y); /// /// Returns the component-wise product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator *(V2f a, V2f b) => new V2f(a.X * b.X, a.Y * b.Y); /// /// Returns the component-wise product of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator *(V2f v, float s) => new V2f(v.X * s, v.Y * s); /// /// Returns the component-wise product of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator *(float s, V2f v) => new V2f(s * v.X, s * v.Y); /// /// Returns the component-wise fraction of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator /(V2f a, V2f b) => new V2f(a.X / b.X, a.Y / b.Y); /// /// Returns the component-wise fraction of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator /(V2f v, float s) => new V2f(v.X / s, v.Y / s); /// /// Returns the component-wise fraction of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator /(float s, V2f v) => new V2f(s / v.X, s / v.Y); /// /// Returns the component-wise remainder of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator %(V2f a, V2f b) => new V2f(a.X % b.X, a.Y % b.Y); /// /// Returns the component-wise remainder of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator %(V2f v, float s) => new V2f(v.X % s, v.Y % s); /// /// Returns the component-wise remainder of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f operator %(float s, V2f v) => new V2f(s % v.X, s % v.Y); /// Attention: NEVER implement operators <, <=, >=, >, /// since these are not defined in a Vector space. /// Use AllSmaller() and similar comparators! #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V2f a, V2f b) { return a.X == b.X && a.Y == b.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V2f v, float s) { return v.X == s && v.Y == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(float s, V2f v) { return s == v.X && s == v.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V2f a, V2f b) { return a.X != b.X || a.Y != b.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V2f v, float s) { return v.X != s || v.Y != s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(float s, V2f v) { return s != v.X || s != v.Y; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(V2f other) { return X.Equals(other.X) && Y.Equals(other.Y); } #endregion #region Overrides public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + X.ToString(format, fp) + between + Y.ToString(format, fp) + end; } public override readonly int GetHashCode() { return HashCode.GetCombined(X, Y); } public override readonly bool Equals(object other) => (other is V2f o) ? Equals(o) : false; public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + X.ToString(null, CultureInfo.InvariantCulture) + ", " + Y.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Parsing public static V2f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new V2f( float.Parse(x[0], CultureInfo.InvariantCulture), float.Parse(x[1], CultureInfo.InvariantCulture) ); } public static V2f Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, V2f.Setter); } public static V2f Parse(Text t, int bracketLevel) { return t.NestedBracketSplit(bracketLevel, Text.Parse, V2f.Setter); } #endregion #region Swizzle Methods [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2f OO => new V2f(0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2f OI => new V2f(0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2f ON => new V2f(0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f OX => new V2f(0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f OY => new V2f(0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2f IO => new V2f(1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2f II => new V2f(1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2f PN => new V2f(1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f IX => new V2f(1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f IY => new V2f(1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2f NO => new V2f(-1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2f NP => new V2f(-1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2f NN => new V2f(-1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f NX => new V2f(-1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f NY => new V2f(-1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f XO => new V2f(X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f XI => new V2f(X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f XN => new V2f(X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f XX => new V2f(X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f XY { readonly get => new V2f(X, Y); set { X = value.X; Y = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f YO => new V2f(Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f YI => new V2f(Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f YN => new V2f(Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f YX { readonly get => new V2f(Y, X); set { Y = value.X; X = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f YY => new V2f(Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OOX => new V3f(0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OOY => new V3f(0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OIX => new V3f(0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OIY => new V3f(0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ONX => new V3f(0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ONY => new V3f(0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXO => new V3f(0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXI => new V3f(0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXN => new V3f(0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXX => new V3f(0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXY => new V3f(0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYO => new V3f(0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYI => new V3f(0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYN => new V3f(0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYX => new V3f(0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYY => new V3f(0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IOX => new V3f(1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IOY => new V3f(1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IIX => new V3f(1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IIY => new V3f(1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PNX => new V3f(1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PNY => new V3f(1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IXO => new V3f(1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IXI => new V3f(1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PXN => new V3f(1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IXX => new V3f(1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IXY => new V3f(1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IYO => new V3f(1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IYI => new V3f(1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PYN => new V3f(1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IYX => new V3f(1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IYY => new V3f(1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NOX => new V3f(-1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NOY => new V3f(-1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NPX => new V3f(-1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NPY => new V3f(-1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NNX => new V3f(-1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NNY => new V3f(-1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXO => new V3f(-1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXP => new V3f(-1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXN => new V3f(-1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXX => new V3f(-1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXY => new V3f(-1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYO => new V3f(-1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYP => new V3f(-1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYN => new V3f(-1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYX => new V3f(-1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYY => new V3f(-1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XOO => new V3f(X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XOI => new V3f(X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XON => new V3f(X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XOX => new V3f(X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XOY => new V3f(X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XIO => new V3f(X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XII => new V3f(X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XPN => new V3f(X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XIX => new V3f(X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XIY => new V3f(X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNO => new V3f(X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNP => new V3f(X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNN => new V3f(X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNX => new V3f(X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNY => new V3f(X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXO => new V3f(X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXI => new V3f(X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXN => new V3f(X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXX => new V3f(X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXY => new V3f(X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XYO => new V3f(X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XYI => new V3f(X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XYN => new V3f(X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XYX => new V3f(X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XYY => new V3f(X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YOO => new V3f(Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YOI => new V3f(Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YON => new V3f(Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YOX => new V3f(Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YOY => new V3f(Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YIO => new V3f(Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YII => new V3f(Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YPN => new V3f(Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YIX => new V3f(Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YIY => new V3f(Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNO => new V3f(Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNP => new V3f(Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNN => new V3f(Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNX => new V3f(Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNY => new V3f(Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YXO => new V3f(Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YXI => new V3f(Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YXN => new V3f(Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YXX => new V3f(Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YXY => new V3f(Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYO => new V3f(Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYI => new V3f(Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYN => new V3f(Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYX => new V3f(Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYY => new V3f(Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOOX => new V4f(0, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOOY => new V4f(0, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOIX => new V4f(0, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOIY => new V4f(0, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OONX => new V4f(0, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OONY => new V4f(0, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXO => new V4f(0, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXI => new V4f(0, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXN => new V4f(0, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXX => new V4f(0, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXY => new V4f(0, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYO => new V4f(0, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYI => new V4f(0, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYN => new V4f(0, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYX => new V4f(0, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYY => new V4f(0, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIOX => new V4f(0, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIOY => new V4f(0, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIIX => new V4f(0, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIIY => new V4f(0, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPNX => new V4f(0, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPNY => new V4f(0, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIXO => new V4f(0, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIXI => new V4f(0, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPXN => new V4f(0, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIXX => new V4f(0, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIXY => new V4f(0, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIYO => new V4f(0, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIYI => new V4f(0, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPYN => new V4f(0, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIYX => new V4f(0, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIYY => new V4f(0, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONOX => new V4f(0, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONOY => new V4f(0, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONPX => new V4f(0, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONPY => new V4f(0, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONNX => new V4f(0, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONNY => new V4f(0, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXO => new V4f(0, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXP => new V4f(0, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXN => new V4f(0, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXX => new V4f(0, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXY => new V4f(0, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYO => new V4f(0, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYP => new V4f(0, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYN => new V4f(0, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYX => new V4f(0, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYY => new V4f(0, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXOO => new V4f(0, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXOI => new V4f(0, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXON => new V4f(0, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXOX => new V4f(0, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXOY => new V4f(0, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXIO => new V4f(0, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXII => new V4f(0, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXPN => new V4f(0, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXIX => new V4f(0, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXIY => new V4f(0, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNO => new V4f(0, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNP => new V4f(0, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNN => new V4f(0, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNX => new V4f(0, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNY => new V4f(0, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXO => new V4f(0, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXI => new V4f(0, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXN => new V4f(0, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXX => new V4f(0, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXY => new V4f(0, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYO => new V4f(0, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYI => new V4f(0, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYN => new V4f(0, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYX => new V4f(0, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYY => new V4f(0, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYOO => new V4f(0, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYOI => new V4f(0, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYON => new V4f(0, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYOX => new V4f(0, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYOY => new V4f(0, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYIO => new V4f(0, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYII => new V4f(0, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYPN => new V4f(0, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYIX => new V4f(0, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYIY => new V4f(0, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNO => new V4f(0, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNP => new V4f(0, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNN => new V4f(0, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNX => new V4f(0, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNY => new V4f(0, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXO => new V4f(0, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXI => new V4f(0, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXN => new V4f(0, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXX => new V4f(0, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXY => new V4f(0, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYO => new V4f(0, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYI => new V4f(0, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYN => new V4f(0, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYX => new V4f(0, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYY => new V4f(0, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOOX => new V4f(1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOOY => new V4f(1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOIX => new V4f(1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOIY => new V4f(1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PONX => new V4f(1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PONY => new V4f(1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOXO => new V4f(1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOXI => new V4f(1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f POXN => new V4f(1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOXX => new V4f(1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOXY => new V4f(1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOYO => new V4f(1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOYI => new V4f(1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f POYN => new V4f(1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOYX => new V4f(1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOYY => new V4f(1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIOX => new V4f(1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIOY => new V4f(1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIIX => new V4f(1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIIY => new V4f(1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPNX => new V4f(1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPNY => new V4f(1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIXO => new V4f(1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIXI => new V4f(1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPXN => new V4f(1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIXX => new V4f(1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIXY => new V4f(1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIYO => new V4f(1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIYI => new V4f(1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPYN => new V4f(1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIYX => new V4f(1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIYY => new V4f(1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNOX => new V4f(1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNOY => new V4f(1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNPX => new V4f(1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNPY => new V4f(1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNNX => new V4f(1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNNY => new V4f(1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXO => new V4f(1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXP => new V4f(1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXN => new V4f(1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXX => new V4f(1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXY => new V4f(1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYO => new V4f(1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYP => new V4f(1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYN => new V4f(1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYX => new V4f(1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYY => new V4f(1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXOO => new V4f(1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXOI => new V4f(1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXON => new V4f(1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXOX => new V4f(1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXOY => new V4f(1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXIO => new V4f(1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXII => new V4f(1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXPN => new V4f(1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXIX => new V4f(1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXIY => new V4f(1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNO => new V4f(1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNP => new V4f(1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNN => new V4f(1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNX => new V4f(1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNY => new V4f(1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXXO => new V4f(1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXXI => new V4f(1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXXN => new V4f(1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXXX => new V4f(1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXXY => new V4f(1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXYO => new V4f(1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXYI => new V4f(1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXYN => new V4f(1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXYX => new V4f(1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXYY => new V4f(1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYOO => new V4f(1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYOI => new V4f(1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYON => new V4f(1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYOX => new V4f(1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYOY => new V4f(1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYIO => new V4f(1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYII => new V4f(1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYPN => new V4f(1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYIX => new V4f(1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYIY => new V4f(1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNO => new V4f(1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNP => new V4f(1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNN => new V4f(1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNX => new V4f(1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNY => new V4f(1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYXO => new V4f(1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYXI => new V4f(1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYXN => new V4f(1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYXX => new V4f(1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYXY => new V4f(1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYYO => new V4f(1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYYI => new V4f(1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYYN => new V4f(1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYYX => new V4f(1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYYY => new V4f(1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOOX => new V4f(-1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOOY => new V4f(-1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOPX => new V4f(-1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOPY => new V4f(-1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NONX => new V4f(-1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NONY => new V4f(-1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXO => new V4f(-1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXP => new V4f(-1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXN => new V4f(-1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXX => new V4f(-1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXY => new V4f(-1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYO => new V4f(-1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYP => new V4f(-1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYN => new V4f(-1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYX => new V4f(-1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYY => new V4f(-1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPOX => new V4f(-1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPOY => new V4f(-1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPPX => new V4f(-1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPPY => new V4f(-1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPNX => new V4f(-1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPNY => new V4f(-1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXO => new V4f(-1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXP => new V4f(-1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXN => new V4f(-1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXX => new V4f(-1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXY => new V4f(-1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYO => new V4f(-1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYP => new V4f(-1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYN => new V4f(-1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYX => new V4f(-1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYY => new V4f(-1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNOX => new V4f(-1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNOY => new V4f(-1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNPX => new V4f(-1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNPY => new V4f(-1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNNX => new V4f(-1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNNY => new V4f(-1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXO => new V4f(-1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXP => new V4f(-1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXN => new V4f(-1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXX => new V4f(-1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXY => new V4f(-1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYO => new V4f(-1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYP => new V4f(-1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYN => new V4f(-1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYX => new V4f(-1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYY => new V4f(-1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXOO => new V4f(-1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXOP => new V4f(-1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXON => new V4f(-1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXOX => new V4f(-1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXOY => new V4f(-1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPO => new V4f(-1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPP => new V4f(-1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPN => new V4f(-1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPX => new V4f(-1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPY => new V4f(-1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNO => new V4f(-1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNP => new V4f(-1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNN => new V4f(-1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNX => new V4f(-1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNY => new V4f(-1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXO => new V4f(-1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXP => new V4f(-1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXN => new V4f(-1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXX => new V4f(-1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXY => new V4f(-1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYO => new V4f(-1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYP => new V4f(-1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYN => new V4f(-1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYX => new V4f(-1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYY => new V4f(-1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYOO => new V4f(-1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYOP => new V4f(-1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYON => new V4f(-1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYOX => new V4f(-1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYOY => new V4f(-1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPO => new V4f(-1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPP => new V4f(-1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPN => new V4f(-1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPX => new V4f(-1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPY => new V4f(-1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNO => new V4f(-1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNP => new V4f(-1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNN => new V4f(-1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNX => new V4f(-1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNY => new V4f(-1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXO => new V4f(-1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXP => new V4f(-1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXN => new V4f(-1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXX => new V4f(-1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXY => new V4f(-1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYO => new V4f(-1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYP => new V4f(-1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYN => new V4f(-1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYX => new V4f(-1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYY => new V4f(-1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOOO => new V4f(X, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOOI => new V4f(X, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOON => new V4f(X, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOOX => new V4f(X, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOOY => new V4f(X, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOIO => new V4f(X, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOII => new V4f(X, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOPN => new V4f(X, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOIX => new V4f(X, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOIY => new V4f(X, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONO => new V4f(X, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONP => new V4f(X, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONN => new V4f(X, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONX => new V4f(X, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONY => new V4f(X, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXO => new V4f(X, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXI => new V4f(X, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXN => new V4f(X, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXX => new V4f(X, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXY => new V4f(X, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYO => new V4f(X, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYI => new V4f(X, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYN => new V4f(X, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYX => new V4f(X, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYY => new V4f(X, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIOO => new V4f(X, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIOI => new V4f(X, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPON => new V4f(X, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIOX => new V4f(X, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIOY => new V4f(X, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIIO => new V4f(X, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIII => new V4f(X, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPPN => new V4f(X, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIIX => new V4f(X, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIIY => new V4f(X, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNO => new V4f(X, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNP => new V4f(X, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNN => new V4f(X, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNX => new V4f(X, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNY => new V4f(X, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIXO => new V4f(X, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIXI => new V4f(X, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPXN => new V4f(X, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIXX => new V4f(X, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIXY => new V4f(X, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIYO => new V4f(X, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIYI => new V4f(X, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPYN => new V4f(X, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIYX => new V4f(X, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIYY => new V4f(X, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNOO => new V4f(X, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNOP => new V4f(X, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNON => new V4f(X, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNOX => new V4f(X, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNOY => new V4f(X, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPO => new V4f(X, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPP => new V4f(X, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPN => new V4f(X, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPX => new V4f(X, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPY => new V4f(X, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNO => new V4f(X, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNP => new V4f(X, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNN => new V4f(X, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNX => new V4f(X, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNY => new V4f(X, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXO => new V4f(X, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXP => new V4f(X, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXN => new V4f(X, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXX => new V4f(X, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXY => new V4f(X, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYO => new V4f(X, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYP => new V4f(X, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYN => new V4f(X, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYX => new V4f(X, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYY => new V4f(X, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXOO => new V4f(X, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXOI => new V4f(X, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXON => new V4f(X, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXOX => new V4f(X, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXOY => new V4f(X, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXIO => new V4f(X, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXII => new V4f(X, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXPN => new V4f(X, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXIX => new V4f(X, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXIY => new V4f(X, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNO => new V4f(X, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNP => new V4f(X, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNN => new V4f(X, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNX => new V4f(X, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNY => new V4f(X, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXO => new V4f(X, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXI => new V4f(X, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXN => new V4f(X, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXX => new V4f(X, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXY => new V4f(X, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYO => new V4f(X, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYI => new V4f(X, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYN => new V4f(X, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYX => new V4f(X, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYY => new V4f(X, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYOO => new V4f(X, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYOI => new V4f(X, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYON => new V4f(X, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYOX => new V4f(X, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYOY => new V4f(X, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYIO => new V4f(X, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYII => new V4f(X, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYPN => new V4f(X, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYIX => new V4f(X, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYIY => new V4f(X, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNO => new V4f(X, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNP => new V4f(X, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNN => new V4f(X, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNX => new V4f(X, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNY => new V4f(X, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXO => new V4f(X, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXI => new V4f(X, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXN => new V4f(X, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXX => new V4f(X, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXY => new V4f(X, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYO => new V4f(X, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYI => new V4f(X, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYN => new V4f(X, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYX => new V4f(X, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYY => new V4f(X, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOOO => new V4f(Y, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOOI => new V4f(Y, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOON => new V4f(Y, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOOX => new V4f(Y, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOOY => new V4f(Y, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOIO => new V4f(Y, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOII => new V4f(Y, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOPN => new V4f(Y, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOIX => new V4f(Y, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOIY => new V4f(Y, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONO => new V4f(Y, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONP => new V4f(Y, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONN => new V4f(Y, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONX => new V4f(Y, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONY => new V4f(Y, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXO => new V4f(Y, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXI => new V4f(Y, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXN => new V4f(Y, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXX => new V4f(Y, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXY => new V4f(Y, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYO => new V4f(Y, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYI => new V4f(Y, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYN => new V4f(Y, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYX => new V4f(Y, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYY => new V4f(Y, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIOO => new V4f(Y, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIOI => new V4f(Y, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPON => new V4f(Y, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIOX => new V4f(Y, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIOY => new V4f(Y, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIIO => new V4f(Y, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIII => new V4f(Y, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPPN => new V4f(Y, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIIX => new V4f(Y, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIIY => new V4f(Y, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNO => new V4f(Y, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNP => new V4f(Y, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNN => new V4f(Y, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNX => new V4f(Y, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNY => new V4f(Y, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIXO => new V4f(Y, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIXI => new V4f(Y, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPXN => new V4f(Y, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIXX => new V4f(Y, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIXY => new V4f(Y, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIYO => new V4f(Y, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIYI => new V4f(Y, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPYN => new V4f(Y, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIYX => new V4f(Y, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIYY => new V4f(Y, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNOO => new V4f(Y, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNOP => new V4f(Y, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNON => new V4f(Y, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNOX => new V4f(Y, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNOY => new V4f(Y, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPO => new V4f(Y, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPP => new V4f(Y, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPN => new V4f(Y, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPX => new V4f(Y, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPY => new V4f(Y, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNO => new V4f(Y, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNP => new V4f(Y, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNN => new V4f(Y, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNX => new V4f(Y, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNY => new V4f(Y, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXO => new V4f(Y, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXP => new V4f(Y, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXN => new V4f(Y, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXX => new V4f(Y, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXY => new V4f(Y, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYO => new V4f(Y, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYP => new V4f(Y, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYN => new V4f(Y, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYX => new V4f(Y, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYY => new V4f(Y, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXOO => new V4f(Y, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXOI => new V4f(Y, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXON => new V4f(Y, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXOX => new V4f(Y, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXOY => new V4f(Y, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXIO => new V4f(Y, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXII => new V4f(Y, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXPN => new V4f(Y, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXIX => new V4f(Y, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXIY => new V4f(Y, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNO => new V4f(Y, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNP => new V4f(Y, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNN => new V4f(Y, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNX => new V4f(Y, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNY => new V4f(Y, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXO => new V4f(Y, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXI => new V4f(Y, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXN => new V4f(Y, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXX => new V4f(Y, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXY => new V4f(Y, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYO => new V4f(Y, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYI => new V4f(Y, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYN => new V4f(Y, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYX => new V4f(Y, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYY => new V4f(Y, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYOO => new V4f(Y, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYOI => new V4f(Y, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYON => new V4f(Y, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYOX => new V4f(Y, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYOY => new V4f(Y, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYIO => new V4f(Y, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYII => new V4f(Y, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYPN => new V4f(Y, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYIX => new V4f(Y, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYIY => new V4f(Y, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNO => new V4f(Y, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNP => new V4f(Y, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNN => new V4f(Y, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNX => new V4f(Y, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNY => new V4f(Y, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXO => new V4f(Y, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXI => new V4f(Y, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXN => new V4f(Y, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXX => new V4f(Y, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXY => new V4f(Y, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYO => new V4f(Y, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYI => new V4f(Y, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYN => new V4f(Y, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYX => new V4f(Y, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYY => new V4f(Y, Y, Y, Y); #endregion #region IVector Members /// /// By using long indices, the IVector<double> interface is /// accessed. /// public double this[long i] { readonly get { return (double)this[(int)i]; } set { this[(int)i] = (float)value; } } #endregion #region ISize2f Members public readonly V2f Size2f { get { return this; } } #endregion #region IVector public readonly long Dim { get { return 2; } } public readonly object GetValue(long index) { return (object)this[(int)index]; } public void SetValue(object value, long index) { this[(int)index] = (float)value; } #endregion } public class V2fEqualityComparer : IEqualityComparer { public static V2fEqualityComparer Default => new V2fEqualityComparer(); #region IEqualityComparer Members public bool Equals(V2f v0, V2f v1) { return v0 == v1; } public int GetHashCode(V2f v) { return v.GetHashCode(); } #endregion } public static partial class Fun { #region Min and Max /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Min(this V2f a, V2f b) { return new V2f(Min(a.X, b.X), Min(a.Y, b.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Min(this V2f a, float b) { return new V2f(Min(a.X, b), Min(a.Y, b)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Min(this float a, V2f b) { return new V2f(Min(a, b.X), Min(a, b.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Max(this V2f a, V2f b) { return new V2f(Max(a.X, b.X), Max(a.Y, b.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Max(this V2f a, float b) { return new V2f(Max(a.X, b), Max(a.Y, b)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Max(this float a, V2f b) { return new V2f(Max(a, b.X), Max(a, b.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Min(this V2f a, V2f b, V2f c) { return new V2f(Min(a.X, b.X, c.X), Min(a.Y, b.Y, c.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Max(this V2f a, V2f b, V2f c) { return new V2f(Max(a.X, b.X, c.X), Max(a.Y, b.Y, c.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Min(this V2f a, V2f b, V2f c, V2f d) { return new V2f(Min(a.X, b.X, c.X, d.X), Min(a.Y, b.Y, c.Y, d.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Max(this V2f a, V2f b, V2f c, V2f d) { return new V2f(Max(a.X, b.X, c.X, d.X), Max(a.Y, b.Y, c.Y, d.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Min(this V2f x, params V2f[] values) { return new V2f(Min(x.X, values.Map(a => a.X)), Min(x.Y, values.Map(a => a.Y))); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Max(this V2f x, params V2f[] values) { return new V2f(Max(x.X, values.Map(a => a.X)), Max(x.Y, values.Map(a => a.Y))); } #endregion #region Abs /// /// Applies Fun.Abs to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Abs(this V2f x) { return new V2f(Abs(x.X), Abs(x.Y)); } #endregion #region Rounding /// /// Applies Fun.Floor to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Floor(this V2f x) { return new V2f(Floor(x.X), Floor(x.Y)); } /// /// Applies Fun.Ceiling to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Ceiling(this V2f x) { return new V2f(Ceiling(x.X), Ceiling(x.Y)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Round(this V2f x) { return new V2f(Round(x.X), Round(x.Y)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Round(this V2f x, MidpointRounding mode) { return new V2f(Round(x.X, mode), Round(x.Y, mode)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Round(this V2f x, int digits) { return new V2f(Round(x.X, digits), Round(x.Y, digits)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Round(this V2f x, int digits, MidpointRounding mode) { return new V2f(Round(x.X, digits, mode), Round(x.Y, digits, mode)); } /// /// Applies Fun.Truncate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Truncate(this V2f x) { return new V2f(Truncate(x.X), Truncate(x.Y)); } #endregion #region Frac /// /// Applies Fun.Frac to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Frac(this V2f x) { return new V2f(Frac(x.X), Frac(x.Y)); } #endregion #region Clamping /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Clamp(this V2f x, V2f a, V2f b) { return new V2f(Clamp(x.X, a.X, b.X), Clamp(x.Y, a.Y, b.Y)); } /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Clamp(this V2f x, float a, float b) { return new V2f(Clamp(x.X, a, b), Clamp(x.Y, a, b)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f ClampWrap(this V2f x, V2f a, V2f b) { return new V2f(ClampWrap(x.X, a.X, b.X), ClampWrap(x.Y, a.Y, b.Y)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f ClampWrap(this V2f x, float a, float b) { return new V2f(ClampWrap(x.X, a, b), ClampWrap(x.Y, a, b)); } /// /// Applies Fun.Saturate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Saturate(this V2f x) { return new V2f(Saturate(x.X), Saturate(x.Y)); } #endregion #region MapToUnitInterval /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f MapToUnitInterval(this V2f t, V2f tMax, bool repeat, bool mirror) { return new V2f(MapToUnitInterval(t.X, tMax.X, repeat, mirror), MapToUnitInterval(t.Y, tMax.Y, repeat, mirror)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f MapToUnitInterval(this V2f t, V2f tMax, bool repeat) { return new V2f(MapToUnitInterval(t.X, tMax.X, repeat), MapToUnitInterval(t.Y, tMax.Y, repeat)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f MapToUnitInterval(this V2f t, V2f tMax) { return new V2f(MapToUnitInterval(t.X, tMax.X), MapToUnitInterval(t.Y, tMax.Y)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f MapToUnitInterval(this V2f t, V2f tMin, V2f tMax) { return new V2f(MapToUnitInterval(t.X, tMin.X, tMax.X), MapToUnitInterval(t.Y, tMin.Y, tMax.Y)); } #endregion #region Sign /// /// Applies Fun.Sign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Sign(this V2f x) { return new V2i(Sign(x.X), Sign(x.Y)); } /// /// Applies Fun.Signumi to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Signumi(this V2f x) { return new V2i(Signumi(x.X), Signumi(x.Y)); } /// /// Applies Fun.Signum to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Signum(this V2f x) { return new V2f(Signum(x.X), Signum(x.Y)); } #endregion #region Multiply-Add /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f MultiplyAdd(V2f x, V2f y, V2f z) { return new V2f(MultiplyAdd(x.X, y.X, z.X), MultiplyAdd(x.Y, y.Y, z.Y)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f MultiplyAdd(V2f x, float y, V2f z) { return new V2f(MultiplyAdd(x.X, y, z.X), MultiplyAdd(x.Y, y, z.Y)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f MultiplyAdd(float x, V2f y, V2f z) { return new V2f(MultiplyAdd(x, y.X, z.X), MultiplyAdd(x, y.Y, z.Y)); } #endregion #region Copy sign /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f CopySign(V2f value, V2f sign) { return new V2f(CopySign(value.X, sign.X), CopySign(value.Y, sign.Y)); } /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f CopySign(float value, V2f sign) { return new V2f(CopySign(value, sign.X), CopySign(value, sign.Y)); } /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f CopySign(V2f value, float sign) { return new V2f(CopySign(value.X, sign), CopySign(value.Y, sign)); } #endregion #region Roots /// /// Applies Fun.Sqrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Sqrt(this V2f x) { return new V2f(Sqrt(x.X), Sqrt(x.Y)); } /// /// Applies Fun.Cbrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Cbrt(this V2f x) { return new V2f(Cbrt(x.X), Cbrt(x.Y)); } #endregion #region Square /// /// Applies Fun.Square to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Square(this V2f x) { return new V2f(Square(x.X), Square(x.Y)); } #endregion #region Power /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Pown(this V2f x, V2i y) { return new V2f(Pown(x.X, y.X), Pown(x.Y, y.Y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Pown(this V2f x, int y) { return new V2f(Pown(x.X, y), Pown(x.Y, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Pown(this float x, V2i y) { return new V2f(Pown(x, y.X), Pown(x, y.Y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Pow(this V2f x, V2f y) { return new V2f(Pow(x.X, y.X), Pow(x.Y, y.Y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Pow(this V2f x, float y) { return new V2f(Pow(x.X, y), Pow(x.Y, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Pow(this float x, V2f y) { return new V2f(Pow(x, y.X), Pow(x, y.Y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Power(this V2f x, V2f y) { return new V2f(Power(x.X, y.X), Power(x.Y, y.Y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Power(this V2f x, float y) { return new V2f(Power(x.X, y), Power(x.Y, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Power(this float x, V2f y) { return new V2f(Power(x, y.X), Power(x, y.Y)); } #endregion #region Exp and Log /// /// Applies Fun.Exp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Exp(this V2f x) { return new V2f(Exp(x.X), Exp(x.Y)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Log(this V2f x) { return new V2f(Log(x.X), Log(x.Y)); } /// /// Applies Fun.Log2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Log2(this V2f x) { return new V2f(Log2(x.X), Log2(x.Y)); } /// /// Applies Fun.Log2Int to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Log2Int(this V2f x) { return new V2i(Log2Int(x.X), Log2Int(x.Y)); } /// /// Applies Fun.Log10 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Log10(this V2f x) { return new V2f(Log10(x.X), Log10(x.Y)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Log(this V2f x, float basis) { return new V2f(Log(x.X, basis), Log(x.Y, basis)); } #endregion #region ModP /// /// Applies Fun.ModP to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f ModP(this V2f a, V2f b) { return new V2f(ModP(a.X, b.X), ModP(a.Y, b.Y)); } #endregion #region Power of Two /// /// Applies Fun.PowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f PowerOfTwo(this V2f x) { return new V2f(PowerOfTwo(x.X), PowerOfTwo(x.Y)); } #endregion #region Trigonometry /// /// Applies Fun.Sin to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Sin(this V2f x) { return new V2f(Sin(x.X), Sin(x.Y)); } /// /// Applies Fun.Cos to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Cos(this V2f x) { return new V2f(Cos(x.X), Cos(x.Y)); } /// /// Applies Fun.Tan to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Tan(this V2f x) { return new V2f(Tan(x.X), Tan(x.Y)); } /// /// Applies Fun.Asin to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Asin(this V2f x) { return new V2f(Asin(x.X), Asin(x.Y)); } /// /// Applies Fun.AsinClamped to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f AsinClamped(this V2f x) { return new V2f(AsinClamped(x.X), AsinClamped(x.Y)); } /// /// Applies Fun.Acos to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Acos(this V2f x) { return new V2f(Acos(x.X), Acos(x.Y)); } /// /// Applies Fun.AcosClamped to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f AcosClamped(this V2f x) { return new V2f(AcosClamped(x.X), AcosClamped(x.Y)); } /// /// Applies Fun.Atan to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Atan(this V2f x) { return new V2f(Atan(x.X), Atan(x.Y)); } /// /// Applies Fun.Atan2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Atan2(V2f y, V2f x) { return new V2f(Atan2(y.X, x.X), Atan2(y.Y, x.Y)); } /// /// Applies Fun.FastAtan2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f FastAtan2(V2f y, V2f x) { return new V2f(FastAtan2(y.X, x.X), FastAtan2(y.Y, x.Y)); } /// /// Applies Fun.Sinh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Sinh(this V2f x) { return new V2f(Sinh(x.X), Sinh(x.Y)); } /// /// Applies Fun.Cosh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Cosh(this V2f x) { return new V2f(Cosh(x.X), Cosh(x.Y)); } /// /// Applies Fun.Tanh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Tanh(this V2f x) { return new V2f(Tanh(x.X), Tanh(x.Y)); } /// /// Applies Fun.Asinh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Asinh(this V2f x) { return new V2f(Asinh(x.X), Asinh(x.Y)); } /// /// Applies Fun.Acosh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Acosh(this V2f x) { return new V2f(Acosh(x.X), Acosh(x.Y)); } /// /// Applies Fun.Atanh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Atanh(this V2f x) { return new V2f(Atanh(x.X), Atanh(x.Y)); } #endregion #region Step functions /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Step(this V2f x, V2f edge) { return new V2f(Step(x.X, edge.X), Step(x.Y, edge.Y)); } /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Step(this V2f x, float edge) { return new V2f(Step(x.X, edge), Step(x.Y, edge)); } /// /// Applies Fun.Linearstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Linearstep(this V2f x, V2f edge0, V2f edge1) { return new V2f(Linearstep(x.X, edge0.X, edge1.X), Linearstep(x.Y, edge0.Y, edge1.Y)); } /// /// Applies Fun.Linearstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Linearstep(this V2f x, float edge0, float edge1) { return new V2f(Linearstep(x.X, edge0, edge1), Linearstep(x.Y, edge0, edge1)); } /// /// Applies Fun.Smoothstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Smoothstep(this V2f x, V2f edge0, V2f edge1) { return new V2f(Smoothstep(x.X, edge0.X, edge1.X), Smoothstep(x.Y, edge0.Y, edge1.Y)); } /// /// Applies Fun.Smoothstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Smoothstep(this V2f x, float edge0, float edge1) { return new V2f(Smoothstep(x.X, edge0, edge1), Smoothstep(x.Y, edge0, edge1)); } #endregion #region Interpolation /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Lerp(this float t, V2f a, V2f b) { return new V2f(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Lerp(this V2f t, V2f a, V2f b) { return new V2f(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y)); } /// /// Applies Fun.InvLerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f InvLerp(this V2f y, V2f a, V2f b) { return new V2f(InvLerp(y.X, a.X, b.X), InvLerp(y.Y, a.Y, b.Y)); } #endregion #region Floating point bits /// /// Applies Fun.FloatToBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i FloatToBits(this V2f x) { return new V2i(FloatToBits(x.X), FloatToBits(x.Y)); } /// /// Applies Fun.FloatToUnsignedBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2ui FloatToUnsignedBits(this V2f x) { return new V2ui(FloatToUnsignedBits(x.X), FloatToUnsignedBits(x.Y)); } #endregion #region ApproximateEquals /// /// Returns whether the given vectors are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V2f a, V2f b, float tolerance) { return ApproximateEquals(a.X, b.X, tolerance) && ApproximateEquals(a.Y, b.Y, tolerance); } /// /// Returns whether the given vectors are equal within /// Constant{float}.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V2f a, V2f b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this V2f v, float epsilon) => Vec.AllTiny(v, epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than Constant<float>.PositiveTinyValue. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(V2f v) => v.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any component of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(V2f v) => v.IsNaN; /// /// Returns whether any component of the the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(V2f v) => v.IsInfinity; /// /// Returns whether any component of the the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(V2f v) => v.IsPositiveInfinity; /// /// Returns whether any component of the the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(V2f v) => v.IsNegativeInfinity; /// /// Returns whether all components of the the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(V2f v) => v.IsFinite; #endregion } public static partial class Conversion { #region Angles (Radians, Degrees, Gons) /// /// Converts the angles given in degrees to radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f RadiansFromDegrees(this V2f degrees) => new V2f( RadiansFromDegrees(degrees.X), RadiansFromDegrees(degrees.Y) ); /// /// Converts the angles given in gons to radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f RadiansFromGons(this V2f gons) => new V2f( RadiansFromGons(gons.X), RadiansFromGons(gons.Y) ); /// /// Converts the angles given in radians to degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f DegreesFromRadians(this V2f radians) => new V2f( DegreesFromRadians(radians.X), DegreesFromRadians(radians.Y) ); /// /// Converts the angles given in gons to degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f DegreesFromGons(this V2f gons) => new V2f( DegreesFromGons(gons.X), DegreesFromGons(gons.Y) ); /// /// Converts the angles given in radians to gons. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GonsFromRadians(this V2f radians) => new V2f( GonsFromRadians(radians.X), GonsFromRadians(radians.Y) ); /// /// Converts the angles given in degrees to gons. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f GonsFromDegrees(this V2f degrees) => new V2f( GonsFromDegrees(degrees.X), GonsFromDegrees(degrees.Y) ); #endregion } /// /// Contains static methods /// public static partial class Vec { #region Length /// /// Returns the squared length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LengthSquared(V2f v) => v.LengthSquared; /// /// Returns the length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Length(V2f v) => v.Length; #endregion #region Normalize /// /// Normalizes the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref V2f v) { var s = v.Length; if (s == 0) return; s = 1 / s; v.X *= s; v.Y *= s; } /// /// Returns a normalized copy of this vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Normalized(V2f v) => v.Normalized; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm1(V2f v) => v.Norm1; /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm2(V2f v) => v.Norm2; /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormMax(V2f v) => v.NormMax; /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormMin(V2f v) => v.NormMin; /// /// Gets the p-norm. This is calculated as the p-th root of (|x|^n + |y|^n + ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm(this V2f v, float p) { return ( Fun.Abs(v.X).Pow(p) + Fun.Abs(v.Y).Pow(p)).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the squared distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceSquared(this V2f a, V2f b) => Fun.Square(b.X - a.X) + Fun.Square(b.Y - a.Y); /// /// Returns the distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance(this V2f a, V2f b) => Fun.Sqrt(DistanceSquared(a, b)); /// /// Returns the Manhatten (or 1-) distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance1(this V2f a, V2f b) => Fun.Abs(b.X - a.X) + Fun.Abs(b.Y - a.Y); /// /// Returns the p-distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance(this V2f a, V2f b, float p) => (Fun.Abs(b.X - a.X).Pow(p) + Fun.Abs(b.Y - a.Y).Pow(p)).Pow(1 / p); /// /// Returns the maximal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceMax(this V2f a, V2f b) => Fun.Max(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y)); /// /// Returns the minimal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceMin(this V2f a, V2f b) => Fun.Min(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y)); /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceToLine( this V2f query, V2f p0, V2f p1) { var p0p1 = p1 - p0; var p0q = query - p0; var t = Dot(p0q, p0p1); if (t <= 0) { return p0q.Length; } var denom = p0p1.LengthSquared; if (t >= denom) { return Distance(query, p1); } t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceToInfiniteLine( this V2f query, V2f p0, V2f p1) { var p0p1 = p1 - p0; var p0q = query - p0; var t = Dot(p0q, p0p1); var denom = p0p1.LengthSquared; t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceToLine( this V2f query, V2f p0, V2f p1, out float t) { var p0p1 = p1 - p0; var p0q = query - p0; t = Dot(p0q, p0p1); if (t <= 0) { t = 0; return p0q.Length; } var denom = p0p1.LengthSquared; if (t >= denom) { t = 1; return Distance(query, p1); } t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceToInfiniteLine( this V2f query, V2f p0, V2f p1, out float t) { var p0p1 = p1 - p0; var p0q = query - p0; t = Dot(p0q, p0p1); var denom = p0p1.LengthSquared; t /= denom; return (p0q - t * p0p1).Length; } #endregion #region Operations /// /// Returns a vector that is orthogonal to the given one (i.e. {x,y} -> {-y,x}). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Orthogonal(V2f v) => v.Orthogonal; /// /// Gets a copy of the given vector containing the reciprocal (1/x) of each element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Reciprocal(V2f v) => v.Reciprocal; /// /// Negates the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Negate(this ref V2f v) { v.X = -v.X; v.Y = -v.Y; } /// /// Returns the outer product (tensor-product) of a * b^T as a 2x2 matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22f Outer(this V2f a, V2f b) { return new M22f( a.X * b.X, a.X * b.Y, a.Y * b.X, a.Y * b.Y); } /// /// Returns the dot product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot(this V2f a, V2f b) { return a.X * b.X + a.Y * b.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DirFlags DirFlags(this V2f v) { DirFlags flags = Aardbase.DirFlags.None; if (v.X > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveX; if (v.X < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeX; if (v.Y > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveY; if (v.Y < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeY; return flags; } /// /// Returns the reflection direction of the given vector v (pointing to the surface) for the given normal (should be normalized). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Reflect(this V2f v, V2f normal) { return v - 2 * v.Dot(normal) * normal; } /// /// Returns the refraction direction of the given vector v (pointing to the surface) for the given normal and ratio of refraction indices (n_out / n_in). /// Both the input vectors should be normalized. /// Returns a zero-vector in case of total internal reflection. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f Refract(this V2f v, V2f normal, float eta) { var t = v.Dot(normal); var k = 1 - eta * eta * (1 - t * t); if (k < 0) { return V2f.Zero; } else { return eta * v - (eta * t + Fun.Sqrt(k)) * normal; } } /// /// Returns the cross product of vector a. /// In 2D the cross product is simply a vector that is normal /// to the given vector (i.e. {x,y} -> {-y,x}) /// public static V2f Cross(this V2f a) { return new V2f(-a.Y, a.X); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V2f a, V2f b) { return (a.X < b.X && a.Y < b.Y); } /// /// Returns whether ALL elements of v are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V2f v, float s) { return (v.X < s && v.Y < s); } /// /// Returns whether a is Smaller ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(float s, V2f v) { return (s < v.X && s < v.Y); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V2f a, V2f b) { return (a.X < b.X || a.Y < b.Y); } /// /// Returns whether AT LEAST ONE element of v is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V2f v, float s) { return (v.X < s || v.Y < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(float s, V2f v) { return (s < v.X || s < v.Y); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V2f a, V2f b) { return (a.X > b.X && a.Y > b.Y); } /// /// Returns whether ALL elements of v are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V2f v, float s) { return (v.X > s && v.Y > s); } /// /// Returns whether a is Greater ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(float s, V2f v) { return (s > v.X && s > v.Y); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V2f a, V2f b) { return (a.X > b.X || a.Y > b.Y); } /// /// Returns whether AT LEAST ONE element of v is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V2f v, float s) { return (v.X > s || v.Y > s); } /// /// Returns whether a is Greater AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(float s, V2f v) { return (s > v.X || s > v.Y); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V2f a, V2f b) { return (a.X <= b.X && a.Y <= b.Y); } /// /// Returns whether ALL elements of v are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V2f v, float s) { return (v.X <= s && v.Y <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(float s, V2f v) { return (s <= v.X && s <= v.Y); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V2f a, V2f b) { return (a.X <= b.X || a.Y <= b.Y); } /// /// Returns whether AT LEAST ONE element of v is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V2f v, float s) { return (v.X <= s || v.Y <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(float s, V2f v) { return (s <= v.X || s <= v.Y); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V2f a, V2f b) { return (a.X >= b.X && a.Y >= b.Y); } /// /// Returns whether ALL elements of v are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V2f v, float s) { return (v.X >= s && v.Y >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(float s, V2f v) { return (s >= v.X && s >= v.Y); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V2f a, V2f b) { return (a.X >= b.X || a.Y >= b.Y); } /// /// Returns whether AT LEAST ONE element of v is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V2f v, float s) { return (v.X >= s || v.Y >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(float s, V2f v) { return (s >= v.X || s >= v.Y); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V2f a, V2f b) { return (a.X == b.X && a.Y == b.Y); } /// /// Returns whether ALL elements of v are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V2f v, float s) { return (v.X == s && v.Y == s); } /// /// Returns whether a is Equal ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(float s, V2f v) { return (s == v.X && s == v.Y); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V2f a, V2f b) { return (a.X == b.X || a.Y == b.Y); } /// /// Returns whether AT LEAST ONE element of v is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V2f v, float s) { return (v.X == s || v.Y == s); } /// /// Returns whether a is Equal AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(float s, V2f v) { return (s == v.X || s == v.Y); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V2f a, V2f b) { return (a.X != b.X && a.Y != b.Y); } /// /// Returns whether ALL elements of v are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V2f v, float s) { return (v.X != s && v.Y != s); } /// /// Returns whether a is Different ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(float s, V2f v) { return (s != v.X && s != v.Y); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V2f a, V2f b) { return (a.X != b.X || a.Y != b.Y); } /// /// Returns whether AT LEAST ONE element of v is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V2f v, float s) { return (v.X != s || v.Y != s); } /// /// Returns whether a is Different AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(float s, V2f v) { return (s != v.X || s != v.Y); } /// /// Compare x-coordinate before y-coordinate, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this V2f v0, V2f v1) { if (v0.X < v1.X) return -1; if (v0.X > v1.X) return +1; if (v0.Y < v1.Y) return -1; if (v0.Y > v1.Y) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MinElement(V2f v) => v.MinElement; /// /// Returns the maximum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MaxElement(V2f v) => v.MaxElement; #endregion #region Angle between two vectors /// /// Computes the angle between two given vectors in radians. The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float AngleBetweenFast(this V2f x, V2f y) { return Fun.AcosClamped(x.Dot(y)); } /// /// Computes the angle between two given vectors in radians using a numerically stable algorithm. /// The input vectors have to be normalized. /// // https://scicomp.stackexchange.com/a/27769 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float AngleBetween(this V2f x, V2f y) { var a = x + y; var b = x - y; return 2 * Fun.Atan2(b.Length, a.Length); } /// /// Computes the signed angle between two given vectors in radians. The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float AngleBetweenSigned(this V2f x, V2f y) { var a = x.X * y.Y - x.Y * y.X; var b = x.X * y.X + x.Y * y.Y; return Fun.Atan2(a, b); } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this V2f v, float epsilon) => v.X.IsTiny(epsilon) || v.Y.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this V2f v, float epsilon) => v.X.IsTiny(epsilon) && v.Y.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyFinite(V2f v) => v.AnyFinite; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllFinite(V2f v) => v.AllFinite; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(V2f v) => v.AnyNaN; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(V2f v) => v.AllNaN; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(V2f v) => v.AnyInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(V2f v) => v.AllInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(V2f v) => v.AnyPositiveInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(V2f v) => v.AllPositiveInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(V2f v) => v.AnyNegativeInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(V2f v) => v.AllNegativeInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(V2f v) => v.AnyTiny; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(V2f v) => v.AllTiny; #endregion #region 2D Vector Arithmetics /// /// Dot product of vector with dir rotated by 90 degrees counterclockwise. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot90(this V2f v, V2f dir) { return v.Y * dir.X - v.X * dir.Y; } /// /// Dot product of vector with dir rotated by 180 degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot180(this V2f v, V2f dir) { return -(v.X * dir.X + v.Y * dir.Y); } /// /// Dot product of vector with dir rotated by 270 degrees counterclockwise. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot270(this V2f v, V2f dir) { return v.X * dir.Y - v.Y * dir.X; } /// /// Returns the left value of the direction v with respect to the /// line from p0 to p1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DirLeftOfLineValue(this V2f v, V2f p0, V2f p1) { return v.X * (p0.Y - p1.Y) + v.Y * (p1.X - p0.X); } /// /// Returns the right value of the direction v with respect to the /// line from p0 to p1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DirRightOfLineValue(this V2f v, V2f p0, V2f p1) { return v.X * (p1.Y - p0.Y) + v.Y * (p0.X - p1.X); } /// /// Returns the left value of the point p with respect to the /// line from p0 to p1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float PosLeftOfLineValue(this V2f p, V2f p0, V2f p1) { return (p.X - p0.X) * (p0.Y - p1.Y) + (p.Y - p0.Y) * (p1.X - p0.X); } /// /// Returns the right value of the point p with respect to the /// line from p0 to p1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float PosRightOfLineValue(this V2f p, V2f p0, V2f p1) { return (p.X - p0.X) * (p1.Y - p0.Y) + (p.Y - p0.Y) * (p0.X - p1.X); } #endregion #region Linear Combination [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f LinCom(V2f p0, V2f p1, ref Tup2 w) { return p0 * w.E0 + p1 * w.E1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f LinCom(V2f p0, V2f p1, V2f p2, ref Tup3 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f LinCom(V2f p0, V2f p1, V2f p2, V2f p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f LinCom(V2f p0, V2f p1, V2f p2, V2f p3, V2f p4, ref Tup5 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f LinCom(V2f p0, V2f p1, V2f p2, V2f p3, V2f p4, V2f p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f LinCom(V2f p0, V2f p1, V2f p2, V2f p3, V2f p4, V2f p5, V2f p6, ref Tup7 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5 + p6 * w.E6; } #endregion #region ArrayExtensions public static int IndexOfClosestPoint(this V2f[] pointArray, V2f point) { var bestDist = DistanceSquared(point, pointArray[0]); int bestIndex = 0; int count = pointArray.Length; for (int i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this V2f[] array, int start, int count, V2f point) { var bestDist = DistanceSquared(point, array[start]); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this T[] array, int start, int count, Func pointSelector, V2f point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint(this V2f[] pointArray, V2f point) { var bestDist = DistanceSquared(point, pointArray[0]); long bestIndex = 0; long count = pointArray.LongLength; for (long i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this V2f[] array, long start, long count, V2f point) { var bestDist = DistanceSquared(point, array[start]); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this T[] array, long start, long count, Func pointSelector, V2f point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static int IndexOfMinX(this V2f[] vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static long LongIndexOfMinX(this V2f[] vectorArray, long count = 0) { var minimum = vectorArray[0].X; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static int IndexOfMaxX(this V2f[] vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static long LongIndexOfMaxX(this V2f[] vectorArray, long count = 0) { var maximum = vectorArray[0].X; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static int IndexOfMinY(this V2f[] vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static long LongIndexOfMinY(this V2f[] vectorArray, long count = 0) { var minimum = vectorArray[0].Y; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static int IndexOfMaxY(this V2f[] vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static long LongIndexOfMaxY(this V2f[] vectorArray, long count = 0) { var maximum = vectorArray[0].Y; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the list. /// public static int IndexOfMinX(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the list. /// public static int IndexOfMaxX(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the list. /// public static int IndexOfMinY(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the list. /// public static int IndexOfMaxY(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the array of the index-th coordinate of each vector. /// public static float[] CopyCoord(this V2f[] self, int index) { switch (index) { case 0: return self.Map(v => v.X); case 1: return self.Map(v => v.Y); default: throw new IndexOutOfRangeException(); } } public static V2f WeightedSum( this V2f[] vectorArray, float[] weightArray) { var r = V2f.Zero; var count = vectorArray.LongLength; for (long i = 0; i < count; i++) r += vectorArray[i] * weightArray[i]; return r; } #endregion } public static class IRandomUniformV2fExtensions { #region IRandomUniform extensions for V2f /// /// Uses UniformFloat() to generate the elements of a V2f vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f UniformV2f(this IRandomUniform rnd) { return new V2f(rnd.UniformFloat(), rnd.UniformFloat()); } /// /// Uses UniformFloat() to generate the elements of a V2f /// vector within the given Box2f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f UniformV2f(this IRandomUniform rnd, Box2f box) { return new V2f(box.Min.X + rnd.UniformFloat() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformFloat() * (box.Max.Y - box.Min.Y)); } /// /// Uses UniformFloatClosed() to generate the elements of a V2f vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f UniformV2fClosed(this IRandomUniform rnd) { return new V2f(rnd.UniformFloatClosed(), rnd.UniformFloatClosed()); } /// /// Uses UniformFloatClosed() to generate the elements of a V2f /// vector within the given Box2f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f UniformV2fClosed(this IRandomUniform rnd, Box2f box) { return new V2f(box.Min.X + rnd.UniformFloatClosed() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformFloatClosed() * (box.Max.Y - box.Min.Y)); } /// /// Uses UniformFloatOpen() to generate the elements of a V2f vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f UniformV2fOpen(this IRandomUniform rnd) { return new V2f(rnd.UniformFloatOpen(), rnd.UniformFloatOpen()); } /// /// Uses UniformFloatOpen() to generate the elements of a V2f /// vector within the given Box2f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f UniformV2fOpen(this IRandomUniform rnd, Box2f box) { return new V2f(box.Min.X + rnd.UniformFloatOpen() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformFloatOpen() * (box.Max.Y - box.Min.Y)); } /// /// Returns a uniformly distributed vector (corresponds to a /// uniformly distributed point on the unit circle). Uses UniformFloat() internally. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2f UniformV2fDirection(this IRandomUniform rnd) { float phi = rnd.UniformFloat() * ConstantF.PiTimesTwo; return new V2f(Fun.Cos(phi), Fun.Sin(phi)); } #endregion } #endregion #region V2d [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct V2d : IVector, ISize2d, IFormattable, IEquatable { [DataMember] public double X; [DataMember] public double Y; #region Constructors /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(int x, int y) { X = (double)x; Y = (double)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(int v) { X = (double)v; Y = (double)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(int[] a) { X = (double)a[0]; Y = (double)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(int[] a, int start) { X = (double)a[start + 0]; Y = (double)a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(uint x, uint y) { X = (double)x; Y = (double)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(uint v) { X = (double)v; Y = (double)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(uint[] a) { X = (double)a[0]; Y = (double)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(uint[] a, int start) { X = (double)a[start + 0]; Y = (double)a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(long x, long y) { X = (double)x; Y = (double)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(long v) { X = (double)v; Y = (double)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(long[] a) { X = (double)a[0]; Y = (double)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(long[] a, int start) { X = (double)a[start + 0]; Y = (double)a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(float x, float y) { X = (double)x; Y = (double)y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(float v) { X = (double)v; Y = (double)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(float[] a) { X = (double)a[0]; Y = (double)a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(float[] a, int start) { X = (double)a[start + 0]; Y = (double)a[start + 1]; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(double x, double y) { X = x; Y = y; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(double v) { X = v; Y = v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(double[] a) { X = a[0]; Y = a[1]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(double[] a, int start) { X = a[start + 0]; Y = a[start + 1]; } /// /// Creates a vector from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(Func index_fun) { X = index_fun(0); Y = index_fun(1); } /// /// Creates a vector from a general vector implementing the IVector<double> interface. /// The caller has to verify that the dimension of is at least 2. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(IVector v) : this(v[0], v[1]) { } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(V2i v) { X = (double)v.X; Y = (double)v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(V2ui v) { X = (double)v.X; Y = (double)v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(V2l v) { X = (double)v.X; Y = (double)v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(V2f v) { X = (double)v.X; Y = (double)v.Y; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(V2d v) { X = v.X; Y = v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(V3i v) { X = (double)v.X; Y = (double)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(V3ui v) { X = (double)v.X; Y = (double)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(V3l v) { X = (double)v.X; Y = (double)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(V3f v) { X = (double)v.X; Y = (double)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(V3d v) { X = v.X; Y = v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(V4i v) { X = (double)v.X; Y = (double)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(V4ui v) { X = (double)v.X; Y = (double)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(V4l v) { X = (double)v.X; Y = (double)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(V4f v) { X = (double)v.X; Y = (double)v.Y; } /// /// Creates a vector from another vector of type . /// v.Z, v.W are ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V2d(V4d v) { X = v.X; Y = v.Y; } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(V2i v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(V2ui v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(V2l v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(V2f v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(V3i v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(V3ui v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(V3l v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(V3f v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(V3d v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(V4i v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(V4ui v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(V4l v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(V4f v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(V4d v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToV2i() => (V2i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui ToV2ui() => (V2ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToV2l() => (V2l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f ToV2f() => (V2f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int[](V2d v) => new int[] { (int)v.X, (int)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(int[] v) => new V2d((double)v[0], (double)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](V2d v) => new uint[] { (uint)v.X, (uint)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(uint[] v) => new V2d((double)v[0], (double)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long[](V2d v) => new long[] { (long)v.X, (long)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(long[] v) => new V2d((double)v[0], (double)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](V2d v) => new float[] { (float)v.X, (float)v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(float[] v) => new V2d((double)v[0], (double)v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](V2d v) => new double[] { v.X, v.Y }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V2d(double[] v) => new V2d(v[0], v[1]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToFloorV2l() => new V2l((long)Fun.Floor(X), (long)Fun.Floor(Y)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToCeilingV2l() => new V2l((long)Fun.Ceiling(X), (long)Fun.Ceiling(Y)); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3iHomo() => new V3i(X, Y, 1); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3uiHomo() => new V3ui(X, Y, 1); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3lHomo() => new V3l(X, Y, 1); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3fHomo() => new V3f(X, Y, 1); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3dHomo() => new V3d(X, Y, 1); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i Copy(Func element_fun) => new V2i(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i Copy(Func element_index_fun) => new V2i(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(int[] array, int start) { array[start + 0] = (int)X; array[start + 1] = (int)Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui Copy(Func element_fun) => new V2ui(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui Copy(Func element_index_fun) => new V2ui(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(uint[] array, int start) { array[start + 0] = (uint)X; array[start + 1] = (uint)Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l Copy(Func element_fun) => new V2l(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l Copy(Func element_index_fun) => new V2l(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(long[] array, int start) { array[start + 0] = (long)X; array[start + 1] = (long)Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f Copy(Func element_fun) => new V2f(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f Copy(Func element_index_fun) => new V2f(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(float[] array, int start) { array[start + 0] = (float)X; array[start + 1] = (float)Y; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d Copy(Func element_fun) => new V2d(element_fun(X), element_fun(Y)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d Copy(Func element_index_fun) => new V2d(element_index_fun(X, 0), element_index_fun(Y, 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(double[] array, int start) { array[start + 0] = X; array[start + 1] = Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(X); array[start + 1] = element_fun(Y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(X, 0); array[start + 1] = element_index_fun(Y, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double[] ToArray() => new double[] { X, Y }; #endregion #region Properties and Indexers /// /// Property for the field X. /// Useful when properties are required, but the field X is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public double P_X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value; } } /// /// Property for the field Y. /// Useful when properties are required, but the field Y is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public double P_Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Y = value; } } /// /// Enumerates all elements of this vector. /// public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return X; yield return Y; } } /// /// Gets or sets element with given index. /// public unsafe double this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &X) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &X) { ptr[index] = value; } } } /// /// Returns the index of the largest dimension of the vector. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X >= Y ? 0 : 1; } } /// /// Returns the index of the smallest dimension of the vector. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X <= Y ? 0 : 1; } } /// /// Returns the minimum element of the vector. /// public readonly double MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(X, Y); } /// /// Returns the maximum element of the vector. /// public readonly double MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(X, Y); } public readonly bool AnyFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsFinite(X) || Fun.IsFinite(Y); } public readonly bool AllFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsFinite(X) && Fun.IsFinite(Y); } public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNaN(X) || double.IsNaN(Y); } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNaN(X) && double.IsNaN(Y); } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsInfinity(X) || double.IsInfinity(Y); } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsInfinity(X) && double.IsInfinity(Y); } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsPositiveInfinity(X) || double.IsPositiveInfinity(Y); } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsPositiveInfinity(X) && double.IsPositiveInfinity(Y); } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNegativeInfinity(X) || double.IsNegativeInfinity(Y); } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNegativeInfinity(X) && double.IsNegativeInfinity(Y); } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(X) || Fun.IsTiny(Y); } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(X) && Fun.IsTiny(Y); } /// /// Returns true if the absolute value of each component of the vector is smaller than Constant<double>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any component of the vector is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any component of the vector is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any component of the vector is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any component of the vector is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all components of the vector are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Constants /// /// Number of elements in this vector. /// public const int Dimension = 2; /// /// All elements zero. /// public static V2d Zero { get { return new V2d(0, 0); } } /// /// All elements half. /// public static V2d Half { get { return new V2d(0.5, 0.5); } } /// /// All elements one. /// public static V2d One { get { return new V2d(1, 1); } } /// /// All elements set to maximum possible value. /// public static V2d MaxValue { get { return new V2d(Constant.ParseableMaxValue, Constant.ParseableMaxValue); } } /// /// All elements set to minimum possible value. /// public static V2d MinValue { get { return new V2d(Constant.ParseableMinValue, Constant.ParseableMinValue); } } /// /// All elements set to negative infinity. /// public static V2d NegativeInfinity { get { return new V2d(double.NegativeInfinity, double.NegativeInfinity); } } /// /// All elements set to positive infinity. /// public static V2d PositiveInfinity { get { return new V2d(double.PositiveInfinity, double.PositiveInfinity); } } /// /// All elements set to NaN. /// public static V2d NaN { get { return new V2d(double.NaN, double.NaN); } } /// /// Normalized X-axis. /// public static V2d XAxis { get { return new V2d(1, 0); } } /// /// Normalized Y-axis. /// public static V2d YAxis { get { return new V2d(0, 1); } } /// /// An array of accessor functions for the coordinates of the vector. /// public static readonly Func[] SelectorArray = new Func[] { v => v.X, v => v.Y }; /// /// Element getter function. /// public static readonly Func Getter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref V2d v, int i, double s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; default: throw new IndexOutOfRangeException(); } }; /// /// Element getter function with long index. /// public static readonly Func LongGetter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action with long index. /// public static readonly ActionRefValVal LongSetter = (ref V2d v, long i, double s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Static factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d FromV2i(V2i v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d FromV2ui(V2ui v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d FromV2l(V2l v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d FromV2f(V2f v) => new V2d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d FromPolar(double angleInRadians, double radius) => new V2d(Fun.Cos(angleInRadians) * radius, Fun.Sin(angleInRadians) * radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d FromPolar(double angleInRadians) => new V2d(Fun.Cos(angleInRadians), Fun.Sin(angleInRadians)); #endregion #region Norms /// /// Returns the squared length of the vector. /// public readonly double LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X * X + Y * Y ; } } /// /// Returns the length of the vector. /// public readonly double Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y ); } } /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// public readonly double Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Abs(X) + Fun.Abs(Y); } } /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y); } } /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// public readonly double NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(Fun.Abs(X), Fun.Abs(Y)); } } /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// public readonly double NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(Fun.Abs(X), Fun.Abs(Y)); } } /// /// Returns a normalized copy of this vector. /// public readonly V2d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Length; if (s == 0) return V2d.Zero; s = 1 / s; return new V2d(X * s, Y * s); } } /// /// Vector rotated 90° counter clockwise: (-Y, X) /// public readonly V2d Rot90 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2d(-Y, X); } } /// /// Vector rotated 180° counter clockwise: (-X, -Y) /// public readonly V2d Rot180 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2d(-X, -Y); } } /// /// Vector rotated 270° counter clockwise: (Y, -X) /// public readonly V2d Rot270 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2d(Y, -X); } } /// /// Returns a copy of the vector with the maximum component length of /// exactly 1. This corresponds to mapping the vector onto an origin- /// centered square with side length 2. /// public readonly V2d CubeMapped { get { double x = Fun.Abs(X); double y = Fun.Abs(Y); return x > y ? new V2d(Fun.Sign(X), Y / x) : new V2d(X / y, Fun.Sign(Y)); } } #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Abs(V2d v) => v.Abs(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Floor(V2d v) => v.Floor(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Ceiling(V2d v) => v.Ceiling(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Round(V2d v) => v.Round(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Truncate(V2d v) => v.Truncate(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Acos(V2d v) => Fun.Acos(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Acoshb(V2d v) => Fun.Acosh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Cos(V2d v) => Fun.Cos(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Cosh(V2d v) => Fun.Cosh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Asin(V2d v) => Fun.Asin(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Asinhb(V2d v) => Fun.Asinh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Sin(V2d v) => Fun.Sin(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Sinh(V2d v) => Fun.Sinh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Atan(V2d v) => Fun.Atan(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Atanhb(V2d v) => Fun.Atanh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Atan2(V2d a, V2d b) => Fun.Atan2(a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Tan(V2d v) => Fun.Tan(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Tanh(V2d v) => Fun.Tanh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Sqrt(V2d v) => Fun.Sqrt(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d CubeRoot(V2d v) => Fun.Cbrt(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Exp(V2d v) => Fun.Exp(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log(V2d v) => Fun.Log(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d LogBinary(V2d v) => Fun.Log2(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log10(V2d v) => Fun.Log10(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d CopySgn(V2d value, V2d sign) => Fun.CopySign(value, sign); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d CopySgn(V2d value, double sign) => Fun.CopySign(value, sign); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d LinearInterp(double t, V2d a, V2d b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d LinearInterp(V2d t, V2d a, V2d b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Min(V2d v0, V2d v1) => Fun.Min(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Min(V2d v, double x) => Fun.Min(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Max(V2d v0, V2d v1) => Fun.Max(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Max(V2d v, double x) => Fun.Max(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Saturate(V2d v) => Fun.Saturate(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d DivideByInt(V2d v, int x) => v / x; #endregion #region Operations /// /// Sets the elements of a vector to the given int elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(int x, int y) { X = (double)x; Y = (double)y; } /// /// Sets the elements of a vector to the given uint elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(uint x, uint y) { X = (double)x; Y = (double)y; } /// /// Sets the elements of a vector to the given long elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(long x, long y) { X = (double)x; Y = (double)y; } /// /// Sets the elements of a vector to the given float elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(float x, float y) { X = (double)x; Y = (double)y; } /// /// Sets the elements of a vector to the given double elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(double x, double y) { X = x; Y = y; } /// /// Returns a negated copy of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator -(V2d v) => new V2d(-v.X, -v.Y); /// /// Returns a vector that is orthogonal to this one (i.e. {x,y} -> {-y,x}). /// public readonly V2d Orthogonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2d(-Y, X); } } /// /// Gets a copy of this vector containing the reciprocal (1/x) of each element. /// public readonly V2d Reciprocal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V2d(1 / X, 1 / Y); } } /// /// Returns the component-wise sum of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator +(V2d a, V2d b) => new V2d(a.X + b.X, a.Y + b.Y); /// /// Returns the component-wise sum of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator +(V2d v, double s) => new V2d(v.X + s, v.Y + s); /// /// Returns the component-wise sum of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator +(double s, V2d v) => new V2d(s + v.X, s + v.Y); /// /// Returns the component-wise difference of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator -(V2d a, V2d b) => new V2d(a.X - b.X, a.Y - b.Y); /// /// Returns the component-wise difference of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator -(V2d v, double s) => new V2d(v.X - s, v.Y - s); /// /// Returns the component-wise difference of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator -(double s, V2d v) => new V2d(s - v.X, s - v.Y); /// /// Returns the component-wise product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator *(V2d a, V2d b) => new V2d(a.X * b.X, a.Y * b.Y); /// /// Returns the component-wise product of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator *(V2d v, double s) => new V2d(v.X * s, v.Y * s); /// /// Returns the component-wise product of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator *(double s, V2d v) => new V2d(s * v.X, s * v.Y); /// /// Returns the component-wise fraction of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator /(V2d a, V2d b) => new V2d(a.X / b.X, a.Y / b.Y); /// /// Returns the component-wise fraction of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator /(V2d v, double s) => new V2d(v.X / s, v.Y / s); /// /// Returns the component-wise fraction of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator /(double s, V2d v) => new V2d(s / v.X, s / v.Y); /// /// Returns the component-wise remainder of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator %(V2d a, V2d b) => new V2d(a.X % b.X, a.Y % b.Y); /// /// Returns the component-wise remainder of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator %(V2d v, double s) => new V2d(v.X % s, v.Y % s); /// /// Returns the component-wise remainder of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d operator %(double s, V2d v) => new V2d(s % v.X, s % v.Y); /// Attention: NEVER implement operators <, <=, >=, >, /// since these are not defined in a Vector space. /// Use AllSmaller() and similar comparators! #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V2d a, V2d b) { return a.X == b.X && a.Y == b.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V2d v, double s) { return v.X == s && v.Y == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(double s, V2d v) { return s == v.X && s == v.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V2d a, V2d b) { return a.X != b.X || a.Y != b.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V2d v, double s) { return v.X != s || v.Y != s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(double s, V2d v) { return s != v.X || s != v.Y; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(V2d other) { return X.Equals(other.X) && Y.Equals(other.Y); } #endregion #region Overrides public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + X.ToString(format, fp) + between + Y.ToString(format, fp) + end; } public override readonly int GetHashCode() { return HashCode.GetCombined(X, Y); } public override readonly bool Equals(object other) => (other is V2d o) ? Equals(o) : false; public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + X.ToString(null, CultureInfo.InvariantCulture) + ", " + Y.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Parsing public static V2d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new V2d( double.Parse(x[0], CultureInfo.InvariantCulture), double.Parse(x[1], CultureInfo.InvariantCulture) ); } public static V2d Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, V2d.Setter); } public static V2d Parse(Text t, int bracketLevel) { return t.NestedBracketSplit(bracketLevel, Text.Parse, V2d.Setter); } #endregion #region Swizzle Methods [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2d OO => new V2d(0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2d OI => new V2d(0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2d ON => new V2d(0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d OX => new V2d(0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d OY => new V2d(0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2d IO => new V2d(1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2d II => new V2d(1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2d PN => new V2d(1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d IX => new V2d(1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d IY => new V2d(1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2d NO => new V2d(-1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2d NP => new V2d(-1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V2d NN => new V2d(-1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d NX => new V2d(-1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d NY => new V2d(-1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d XO => new V2d(X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d XI => new V2d(X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d XN => new V2d(X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d XX => new V2d(X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d XY { readonly get => new V2d(X, Y); set { X = value.X; Y = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d YO => new V2d(Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d YI => new V2d(Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d YN => new V2d(Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d YX { readonly get => new V2d(Y, X); set { Y = value.X; X = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d YY => new V2d(Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OOX => new V3d(0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OOY => new V3d(0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OIX => new V3d(0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OIY => new V3d(0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ONX => new V3d(0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ONY => new V3d(0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXO => new V3d(0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXI => new V3d(0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXN => new V3d(0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXX => new V3d(0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXY => new V3d(0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYO => new V3d(0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYI => new V3d(0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYN => new V3d(0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYX => new V3d(0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYY => new V3d(0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IOX => new V3d(1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IOY => new V3d(1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IIX => new V3d(1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IIY => new V3d(1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PNX => new V3d(1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PNY => new V3d(1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IXO => new V3d(1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IXI => new V3d(1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PXN => new V3d(1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IXX => new V3d(1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IXY => new V3d(1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IYO => new V3d(1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IYI => new V3d(1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PYN => new V3d(1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IYX => new V3d(1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IYY => new V3d(1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NOX => new V3d(-1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NOY => new V3d(-1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NPX => new V3d(-1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NPY => new V3d(-1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NNX => new V3d(-1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NNY => new V3d(-1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXO => new V3d(-1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXP => new V3d(-1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXN => new V3d(-1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXX => new V3d(-1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXY => new V3d(-1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYO => new V3d(-1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYP => new V3d(-1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYN => new V3d(-1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYX => new V3d(-1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYY => new V3d(-1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XOO => new V3d(X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XOI => new V3d(X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XON => new V3d(X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XOX => new V3d(X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XOY => new V3d(X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XIO => new V3d(X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XII => new V3d(X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XPN => new V3d(X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XIX => new V3d(X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XIY => new V3d(X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNO => new V3d(X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNP => new V3d(X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNN => new V3d(X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNX => new V3d(X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNY => new V3d(X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXO => new V3d(X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXI => new V3d(X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXN => new V3d(X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXX => new V3d(X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXY => new V3d(X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XYO => new V3d(X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XYI => new V3d(X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XYN => new V3d(X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XYX => new V3d(X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XYY => new V3d(X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YOO => new V3d(Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YOI => new V3d(Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YON => new V3d(Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YOX => new V3d(Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YOY => new V3d(Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YIO => new V3d(Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YII => new V3d(Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YPN => new V3d(Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YIX => new V3d(Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YIY => new V3d(Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNO => new V3d(Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNP => new V3d(Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNN => new V3d(Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNX => new V3d(Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNY => new V3d(Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YXO => new V3d(Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YXI => new V3d(Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YXN => new V3d(Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YXX => new V3d(Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YXY => new V3d(Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYO => new V3d(Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYI => new V3d(Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYN => new V3d(Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYX => new V3d(Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYY => new V3d(Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOOX => new V4d(0, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOOY => new V4d(0, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOIX => new V4d(0, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOIY => new V4d(0, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OONX => new V4d(0, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OONY => new V4d(0, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXO => new V4d(0, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXI => new V4d(0, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXN => new V4d(0, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXX => new V4d(0, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXY => new V4d(0, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYO => new V4d(0, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYI => new V4d(0, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYN => new V4d(0, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYX => new V4d(0, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYY => new V4d(0, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIOX => new V4d(0, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIOY => new V4d(0, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIIX => new V4d(0, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIIY => new V4d(0, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPNX => new V4d(0, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPNY => new V4d(0, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIXO => new V4d(0, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIXI => new V4d(0, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPXN => new V4d(0, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIXX => new V4d(0, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIXY => new V4d(0, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIYO => new V4d(0, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIYI => new V4d(0, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPYN => new V4d(0, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIYX => new V4d(0, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIYY => new V4d(0, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONOX => new V4d(0, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONOY => new V4d(0, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONPX => new V4d(0, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONPY => new V4d(0, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONNX => new V4d(0, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONNY => new V4d(0, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXO => new V4d(0, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXP => new V4d(0, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXN => new V4d(0, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXX => new V4d(0, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXY => new V4d(0, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYO => new V4d(0, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYP => new V4d(0, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYN => new V4d(0, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYX => new V4d(0, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYY => new V4d(0, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXOO => new V4d(0, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXOI => new V4d(0, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXON => new V4d(0, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXOX => new V4d(0, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXOY => new V4d(0, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXIO => new V4d(0, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXII => new V4d(0, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXPN => new V4d(0, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXIX => new V4d(0, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXIY => new V4d(0, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNO => new V4d(0, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNP => new V4d(0, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNN => new V4d(0, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNX => new V4d(0, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNY => new V4d(0, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXO => new V4d(0, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXI => new V4d(0, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXN => new V4d(0, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXX => new V4d(0, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXY => new V4d(0, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYO => new V4d(0, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYI => new V4d(0, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYN => new V4d(0, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYX => new V4d(0, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYY => new V4d(0, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYOO => new V4d(0, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYOI => new V4d(0, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYON => new V4d(0, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYOX => new V4d(0, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYOY => new V4d(0, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYIO => new V4d(0, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYII => new V4d(0, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYPN => new V4d(0, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYIX => new V4d(0, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYIY => new V4d(0, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNO => new V4d(0, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNP => new V4d(0, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNN => new V4d(0, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNX => new V4d(0, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNY => new V4d(0, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXO => new V4d(0, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXI => new V4d(0, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXN => new V4d(0, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXX => new V4d(0, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXY => new V4d(0, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYO => new V4d(0, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYI => new V4d(0, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYN => new V4d(0, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYX => new V4d(0, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYY => new V4d(0, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOOX => new V4d(1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOOY => new V4d(1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOIX => new V4d(1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOIY => new V4d(1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PONX => new V4d(1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PONY => new V4d(1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOXO => new V4d(1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOXI => new V4d(1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d POXN => new V4d(1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOXX => new V4d(1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOXY => new V4d(1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOYO => new V4d(1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOYI => new V4d(1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d POYN => new V4d(1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOYX => new V4d(1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOYY => new V4d(1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIOX => new V4d(1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIOY => new V4d(1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIIX => new V4d(1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIIY => new V4d(1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPNX => new V4d(1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPNY => new V4d(1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIXO => new V4d(1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIXI => new V4d(1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPXN => new V4d(1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIXX => new V4d(1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIXY => new V4d(1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIYO => new V4d(1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIYI => new V4d(1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPYN => new V4d(1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIYX => new V4d(1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIYY => new V4d(1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNOX => new V4d(1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNOY => new V4d(1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNPX => new V4d(1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNPY => new V4d(1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNNX => new V4d(1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNNY => new V4d(1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXO => new V4d(1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXP => new V4d(1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXN => new V4d(1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXX => new V4d(1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXY => new V4d(1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYO => new V4d(1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYP => new V4d(1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYN => new V4d(1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYX => new V4d(1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYY => new V4d(1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXOO => new V4d(1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXOI => new V4d(1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXON => new V4d(1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXOX => new V4d(1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXOY => new V4d(1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXIO => new V4d(1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXII => new V4d(1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXPN => new V4d(1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXIX => new V4d(1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXIY => new V4d(1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNO => new V4d(1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNP => new V4d(1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNN => new V4d(1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNX => new V4d(1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNY => new V4d(1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXXO => new V4d(1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXXI => new V4d(1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXXN => new V4d(1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXXX => new V4d(1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXXY => new V4d(1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXYO => new V4d(1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXYI => new V4d(1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXYN => new V4d(1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXYX => new V4d(1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXYY => new V4d(1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYOO => new V4d(1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYOI => new V4d(1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYON => new V4d(1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYOX => new V4d(1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYOY => new V4d(1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYIO => new V4d(1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYII => new V4d(1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYPN => new V4d(1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYIX => new V4d(1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYIY => new V4d(1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNO => new V4d(1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNP => new V4d(1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNN => new V4d(1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNX => new V4d(1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNY => new V4d(1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYXO => new V4d(1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYXI => new V4d(1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYXN => new V4d(1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYXX => new V4d(1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYXY => new V4d(1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYYO => new V4d(1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYYI => new V4d(1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYYN => new V4d(1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYYX => new V4d(1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYYY => new V4d(1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOOX => new V4d(-1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOOY => new V4d(-1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOPX => new V4d(-1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOPY => new V4d(-1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NONX => new V4d(-1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NONY => new V4d(-1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXO => new V4d(-1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXP => new V4d(-1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXN => new V4d(-1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXX => new V4d(-1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXY => new V4d(-1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYO => new V4d(-1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYP => new V4d(-1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYN => new V4d(-1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYX => new V4d(-1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYY => new V4d(-1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPOX => new V4d(-1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPOY => new V4d(-1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPPX => new V4d(-1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPPY => new V4d(-1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPNX => new V4d(-1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPNY => new V4d(-1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXO => new V4d(-1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXP => new V4d(-1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXN => new V4d(-1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXX => new V4d(-1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXY => new V4d(-1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYO => new V4d(-1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYP => new V4d(-1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYN => new V4d(-1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYX => new V4d(-1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYY => new V4d(-1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNOX => new V4d(-1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNOY => new V4d(-1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNPX => new V4d(-1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNPY => new V4d(-1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNNX => new V4d(-1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNNY => new V4d(-1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXO => new V4d(-1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXP => new V4d(-1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXN => new V4d(-1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXX => new V4d(-1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXY => new V4d(-1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYO => new V4d(-1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYP => new V4d(-1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYN => new V4d(-1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYX => new V4d(-1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYY => new V4d(-1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXOO => new V4d(-1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXOP => new V4d(-1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXON => new V4d(-1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXOX => new V4d(-1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXOY => new V4d(-1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPO => new V4d(-1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPP => new V4d(-1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPN => new V4d(-1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPX => new V4d(-1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPY => new V4d(-1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNO => new V4d(-1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNP => new V4d(-1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNN => new V4d(-1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNX => new V4d(-1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNY => new V4d(-1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXO => new V4d(-1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXP => new V4d(-1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXN => new V4d(-1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXX => new V4d(-1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXY => new V4d(-1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYO => new V4d(-1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYP => new V4d(-1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYN => new V4d(-1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYX => new V4d(-1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYY => new V4d(-1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYOO => new V4d(-1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYOP => new V4d(-1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYON => new V4d(-1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYOX => new V4d(-1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYOY => new V4d(-1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPO => new V4d(-1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPP => new V4d(-1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPN => new V4d(-1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPX => new V4d(-1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPY => new V4d(-1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNO => new V4d(-1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNP => new V4d(-1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNN => new V4d(-1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNX => new V4d(-1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNY => new V4d(-1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXO => new V4d(-1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXP => new V4d(-1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXN => new V4d(-1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXX => new V4d(-1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXY => new V4d(-1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYO => new V4d(-1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYP => new V4d(-1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYN => new V4d(-1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYX => new V4d(-1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYY => new V4d(-1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOOO => new V4d(X, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOOI => new V4d(X, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOON => new V4d(X, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOOX => new V4d(X, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOOY => new V4d(X, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOIO => new V4d(X, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOII => new V4d(X, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOPN => new V4d(X, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOIX => new V4d(X, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOIY => new V4d(X, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONO => new V4d(X, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONP => new V4d(X, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONN => new V4d(X, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONX => new V4d(X, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONY => new V4d(X, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXO => new V4d(X, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXI => new V4d(X, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXN => new V4d(X, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXX => new V4d(X, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXY => new V4d(X, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYO => new V4d(X, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYI => new V4d(X, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYN => new V4d(X, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYX => new V4d(X, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYY => new V4d(X, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIOO => new V4d(X, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIOI => new V4d(X, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPON => new V4d(X, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIOX => new V4d(X, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIOY => new V4d(X, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIIO => new V4d(X, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIII => new V4d(X, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPPN => new V4d(X, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIIX => new V4d(X, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIIY => new V4d(X, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNO => new V4d(X, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNP => new V4d(X, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNN => new V4d(X, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNX => new V4d(X, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNY => new V4d(X, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIXO => new V4d(X, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIXI => new V4d(X, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPXN => new V4d(X, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIXX => new V4d(X, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIXY => new V4d(X, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIYO => new V4d(X, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIYI => new V4d(X, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPYN => new V4d(X, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIYX => new V4d(X, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIYY => new V4d(X, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNOO => new V4d(X, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNOP => new V4d(X, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNON => new V4d(X, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNOX => new V4d(X, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNOY => new V4d(X, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPO => new V4d(X, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPP => new V4d(X, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPN => new V4d(X, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPX => new V4d(X, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPY => new V4d(X, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNO => new V4d(X, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNP => new V4d(X, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNN => new V4d(X, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNX => new V4d(X, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNY => new V4d(X, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXO => new V4d(X, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXP => new V4d(X, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXN => new V4d(X, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXX => new V4d(X, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXY => new V4d(X, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYO => new V4d(X, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYP => new V4d(X, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYN => new V4d(X, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYX => new V4d(X, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYY => new V4d(X, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXOO => new V4d(X, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXOI => new V4d(X, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXON => new V4d(X, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXOX => new V4d(X, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXOY => new V4d(X, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXIO => new V4d(X, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXII => new V4d(X, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXPN => new V4d(X, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXIX => new V4d(X, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXIY => new V4d(X, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNO => new V4d(X, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNP => new V4d(X, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNN => new V4d(X, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNX => new V4d(X, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNY => new V4d(X, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXO => new V4d(X, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXI => new V4d(X, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXN => new V4d(X, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXX => new V4d(X, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXY => new V4d(X, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYO => new V4d(X, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYI => new V4d(X, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYN => new V4d(X, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYX => new V4d(X, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYY => new V4d(X, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYOO => new V4d(X, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYOI => new V4d(X, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYON => new V4d(X, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYOX => new V4d(X, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYOY => new V4d(X, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYIO => new V4d(X, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYII => new V4d(X, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYPN => new V4d(X, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYIX => new V4d(X, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYIY => new V4d(X, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNO => new V4d(X, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNP => new V4d(X, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNN => new V4d(X, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNX => new V4d(X, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNY => new V4d(X, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXO => new V4d(X, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXI => new V4d(X, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXN => new V4d(X, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXX => new V4d(X, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXY => new V4d(X, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYO => new V4d(X, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYI => new V4d(X, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYN => new V4d(X, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYX => new V4d(X, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYY => new V4d(X, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOOO => new V4d(Y, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOOI => new V4d(Y, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOON => new V4d(Y, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOOX => new V4d(Y, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOOY => new V4d(Y, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOIO => new V4d(Y, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOII => new V4d(Y, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOPN => new V4d(Y, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOIX => new V4d(Y, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOIY => new V4d(Y, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONO => new V4d(Y, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONP => new V4d(Y, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONN => new V4d(Y, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONX => new V4d(Y, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONY => new V4d(Y, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXO => new V4d(Y, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXI => new V4d(Y, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXN => new V4d(Y, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXX => new V4d(Y, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXY => new V4d(Y, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYO => new V4d(Y, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYI => new V4d(Y, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYN => new V4d(Y, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYX => new V4d(Y, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYY => new V4d(Y, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIOO => new V4d(Y, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIOI => new V4d(Y, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPON => new V4d(Y, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIOX => new V4d(Y, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIOY => new V4d(Y, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIIO => new V4d(Y, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIII => new V4d(Y, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPPN => new V4d(Y, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIIX => new V4d(Y, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIIY => new V4d(Y, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNO => new V4d(Y, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNP => new V4d(Y, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNN => new V4d(Y, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNX => new V4d(Y, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNY => new V4d(Y, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIXO => new V4d(Y, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIXI => new V4d(Y, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPXN => new V4d(Y, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIXX => new V4d(Y, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIXY => new V4d(Y, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIYO => new V4d(Y, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIYI => new V4d(Y, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPYN => new V4d(Y, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIYX => new V4d(Y, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIYY => new V4d(Y, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNOO => new V4d(Y, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNOP => new V4d(Y, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNON => new V4d(Y, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNOX => new V4d(Y, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNOY => new V4d(Y, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPO => new V4d(Y, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPP => new V4d(Y, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPN => new V4d(Y, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPX => new V4d(Y, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPY => new V4d(Y, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNO => new V4d(Y, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNP => new V4d(Y, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNN => new V4d(Y, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNX => new V4d(Y, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNY => new V4d(Y, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXO => new V4d(Y, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXP => new V4d(Y, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXN => new V4d(Y, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXX => new V4d(Y, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXY => new V4d(Y, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYO => new V4d(Y, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYP => new V4d(Y, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYN => new V4d(Y, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYX => new V4d(Y, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYY => new V4d(Y, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXOO => new V4d(Y, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXOI => new V4d(Y, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXON => new V4d(Y, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXOX => new V4d(Y, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXOY => new V4d(Y, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXIO => new V4d(Y, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXII => new V4d(Y, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXPN => new V4d(Y, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXIX => new V4d(Y, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXIY => new V4d(Y, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNO => new V4d(Y, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNP => new V4d(Y, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNN => new V4d(Y, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNX => new V4d(Y, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNY => new V4d(Y, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXO => new V4d(Y, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXI => new V4d(Y, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXN => new V4d(Y, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXX => new V4d(Y, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXY => new V4d(Y, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYO => new V4d(Y, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYI => new V4d(Y, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYN => new V4d(Y, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYX => new V4d(Y, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYY => new V4d(Y, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYOO => new V4d(Y, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYOI => new V4d(Y, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYON => new V4d(Y, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYOX => new V4d(Y, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYOY => new V4d(Y, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYIO => new V4d(Y, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYII => new V4d(Y, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYPN => new V4d(Y, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYIX => new V4d(Y, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYIY => new V4d(Y, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNO => new V4d(Y, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNP => new V4d(Y, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNN => new V4d(Y, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNX => new V4d(Y, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNY => new V4d(Y, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXO => new V4d(Y, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXI => new V4d(Y, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXN => new V4d(Y, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXX => new V4d(Y, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXY => new V4d(Y, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYO => new V4d(Y, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYI => new V4d(Y, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYN => new V4d(Y, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYX => new V4d(Y, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYY => new V4d(Y, Y, Y, Y); #endregion #region IVector Members /// /// By using long indices, the IVector<double> interface is /// accessed. /// public double this[long i] { readonly get { return (double)this[(int)i]; } set { this[(int)i] = (double)value; } } #endregion #region ISize2d Members public readonly V2d Size2d { get { return this; } } #endregion #region IVector public readonly long Dim { get { return 2; } } public readonly object GetValue(long index) { return (object)this[(int)index]; } public void SetValue(object value, long index) { this[(int)index] = (double)value; } #endregion } public class V2dEqualityComparer : IEqualityComparer { public static V2dEqualityComparer Default => new V2dEqualityComparer(); #region IEqualityComparer Members public bool Equals(V2d v0, V2d v1) { return v0 == v1; } public int GetHashCode(V2d v) { return v.GetHashCode(); } #endregion } public static partial class Fun { #region Min and Max /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Min(this V2d a, V2d b) { return new V2d(Min(a.X, b.X), Min(a.Y, b.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Min(this V2d a, double b) { return new V2d(Min(a.X, b), Min(a.Y, b)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Min(this double a, V2d b) { return new V2d(Min(a, b.X), Min(a, b.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Max(this V2d a, V2d b) { return new V2d(Max(a.X, b.X), Max(a.Y, b.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Max(this V2d a, double b) { return new V2d(Max(a.X, b), Max(a.Y, b)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Max(this double a, V2d b) { return new V2d(Max(a, b.X), Max(a, b.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Min(this V2d a, V2d b, V2d c) { return new V2d(Min(a.X, b.X, c.X), Min(a.Y, b.Y, c.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Max(this V2d a, V2d b, V2d c) { return new V2d(Max(a.X, b.X, c.X), Max(a.Y, b.Y, c.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Min(this V2d a, V2d b, V2d c, V2d d) { return new V2d(Min(a.X, b.X, c.X, d.X), Min(a.Y, b.Y, c.Y, d.Y)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Max(this V2d a, V2d b, V2d c, V2d d) { return new V2d(Max(a.X, b.X, c.X, d.X), Max(a.Y, b.Y, c.Y, d.Y)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Min(this V2d x, params V2d[] values) { return new V2d(Min(x.X, values.Map(a => a.X)), Min(x.Y, values.Map(a => a.Y))); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Max(this V2d x, params V2d[] values) { return new V2d(Max(x.X, values.Map(a => a.X)), Max(x.Y, values.Map(a => a.Y))); } #endregion #region Abs /// /// Applies Fun.Abs to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Abs(this V2d x) { return new V2d(Abs(x.X), Abs(x.Y)); } #endregion #region Rounding /// /// Applies Fun.Floor to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Floor(this V2d x) { return new V2d(Floor(x.X), Floor(x.Y)); } /// /// Applies Fun.Ceiling to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Ceiling(this V2d x) { return new V2d(Ceiling(x.X), Ceiling(x.Y)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Round(this V2d x) { return new V2d(Round(x.X), Round(x.Y)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Round(this V2d x, MidpointRounding mode) { return new V2d(Round(x.X, mode), Round(x.Y, mode)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Round(this V2d x, int digits) { return new V2d(Round(x.X, digits), Round(x.Y, digits)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Round(this V2d x, int digits, MidpointRounding mode) { return new V2d(Round(x.X, digits, mode), Round(x.Y, digits, mode)); } /// /// Applies Fun.Truncate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Truncate(this V2d x) { return new V2d(Truncate(x.X), Truncate(x.Y)); } #endregion #region Frac /// /// Applies Fun.Frac to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Frac(this V2d x) { return new V2d(Frac(x.X), Frac(x.Y)); } #endregion #region Clamping /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Clamp(this V2d x, V2d a, V2d b) { return new V2d(Clamp(x.X, a.X, b.X), Clamp(x.Y, a.Y, b.Y)); } /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Clamp(this V2d x, double a, double b) { return new V2d(Clamp(x.X, a, b), Clamp(x.Y, a, b)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d ClampWrap(this V2d x, V2d a, V2d b) { return new V2d(ClampWrap(x.X, a.X, b.X), ClampWrap(x.Y, a.Y, b.Y)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d ClampWrap(this V2d x, double a, double b) { return new V2d(ClampWrap(x.X, a, b), ClampWrap(x.Y, a, b)); } /// /// Applies Fun.Saturate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Saturate(this V2d x) { return new V2d(Saturate(x.X), Saturate(x.Y)); } #endregion #region MapToUnitInterval /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d MapToUnitInterval(this V2d t, V2d tMax, bool repeat, bool mirror) { return new V2d(MapToUnitInterval(t.X, tMax.X, repeat, mirror), MapToUnitInterval(t.Y, tMax.Y, repeat, mirror)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d MapToUnitInterval(this V2d t, V2d tMax, bool repeat) { return new V2d(MapToUnitInterval(t.X, tMax.X, repeat), MapToUnitInterval(t.Y, tMax.Y, repeat)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d MapToUnitInterval(this V2d t, V2d tMax) { return new V2d(MapToUnitInterval(t.X, tMax.X), MapToUnitInterval(t.Y, tMax.Y)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d MapToUnitInterval(this V2d t, V2d tMin, V2d tMax) { return new V2d(MapToUnitInterval(t.X, tMin.X, tMax.X), MapToUnitInterval(t.Y, tMin.Y, tMax.Y)); } #endregion #region Sign /// /// Applies Fun.Sign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Sign(this V2d x) { return new V2i(Sign(x.X), Sign(x.Y)); } /// /// Applies Fun.Signumi to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Signumi(this V2d x) { return new V2i(Signumi(x.X), Signumi(x.Y)); } /// /// Applies Fun.Signum to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Signum(this V2d x) { return new V2d(Signum(x.X), Signum(x.Y)); } #endregion #region Multiply-Add /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d MultiplyAdd(V2d x, V2d y, V2d z) { return new V2d(MultiplyAdd(x.X, y.X, z.X), MultiplyAdd(x.Y, y.Y, z.Y)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d MultiplyAdd(V2d x, double y, V2d z) { return new V2d(MultiplyAdd(x.X, y, z.X), MultiplyAdd(x.Y, y, z.Y)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d MultiplyAdd(double x, V2d y, V2d z) { return new V2d(MultiplyAdd(x, y.X, z.X), MultiplyAdd(x, y.Y, z.Y)); } #endregion #region Copy sign /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d CopySign(V2d value, V2d sign) { return new V2d(CopySign(value.X, sign.X), CopySign(value.Y, sign.Y)); } /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d CopySign(double value, V2d sign) { return new V2d(CopySign(value, sign.X), CopySign(value, sign.Y)); } /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d CopySign(V2d value, double sign) { return new V2d(CopySign(value.X, sign), CopySign(value.Y, sign)); } #endregion #region Roots /// /// Applies Fun.Sqrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Sqrt(this V2d x) { return new V2d(Sqrt(x.X), Sqrt(x.Y)); } /// /// Applies Fun.Cbrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Cbrt(this V2d x) { return new V2d(Cbrt(x.X), Cbrt(x.Y)); } #endregion #region Square /// /// Applies Fun.Square to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Square(this V2d x) { return new V2d(Square(x.X), Square(x.Y)); } #endregion #region Power /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Pown(this V2d x, V2i y) { return new V2d(Pown(x.X, y.X), Pown(x.Y, y.Y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Pown(this V2d x, int y) { return new V2d(Pown(x.X, y), Pown(x.Y, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Pown(this double x, V2i y) { return new V2d(Pown(x, y.X), Pown(x, y.Y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Pow(this V2d x, V2d y) { return new V2d(Pow(x.X, y.X), Pow(x.Y, y.Y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Pow(this V2d x, double y) { return new V2d(Pow(x.X, y), Pow(x.Y, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Pow(this double x, V2d y) { return new V2d(Pow(x, y.X), Pow(x, y.Y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Power(this V2d x, V2d y) { return new V2d(Power(x.X, y.X), Power(x.Y, y.Y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Power(this V2d x, double y) { return new V2d(Power(x.X, y), Power(x.Y, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Power(this double x, V2d y) { return new V2d(Power(x, y.X), Power(x, y.Y)); } #endregion #region Exp and Log /// /// Applies Fun.Exp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Exp(this V2d x) { return new V2d(Exp(x.X), Exp(x.Y)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log(this V2d x) { return new V2d(Log(x.X), Log(x.Y)); } /// /// Applies Fun.Log2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log2(this V2d x) { return new V2d(Log2(x.X), Log2(x.Y)); } /// /// Applies Fun.Log2Int to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2i Log2Int(this V2d x) { return new V2i(Log2Int(x.X), Log2Int(x.Y)); } /// /// Applies Fun.Log10 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log10(this V2d x) { return new V2d(Log10(x.X), Log10(x.Y)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Log(this V2d x, double basis) { return new V2d(Log(x.X, basis), Log(x.Y, basis)); } #endregion #region ModP /// /// Applies Fun.ModP to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d ModP(this V2d a, V2d b) { return new V2d(ModP(a.X, b.X), ModP(a.Y, b.Y)); } #endregion #region Power of Two /// /// Applies Fun.PowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d PowerOfTwo(this V2d x) { return new V2d(PowerOfTwo(x.X), PowerOfTwo(x.Y)); } #endregion #region Trigonometry /// /// Applies Fun.Sin to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Sin(this V2d x) { return new V2d(Sin(x.X), Sin(x.Y)); } /// /// Applies Fun.Cos to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Cos(this V2d x) { return new V2d(Cos(x.X), Cos(x.Y)); } /// /// Applies Fun.Tan to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Tan(this V2d x) { return new V2d(Tan(x.X), Tan(x.Y)); } /// /// Applies Fun.Asin to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Asin(this V2d x) { return new V2d(Asin(x.X), Asin(x.Y)); } /// /// Applies Fun.AsinClamped to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d AsinClamped(this V2d x) { return new V2d(AsinClamped(x.X), AsinClamped(x.Y)); } /// /// Applies Fun.Acos to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Acos(this V2d x) { return new V2d(Acos(x.X), Acos(x.Y)); } /// /// Applies Fun.AcosClamped to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d AcosClamped(this V2d x) { return new V2d(AcosClamped(x.X), AcosClamped(x.Y)); } /// /// Applies Fun.Atan to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Atan(this V2d x) { return new V2d(Atan(x.X), Atan(x.Y)); } /// /// Applies Fun.Atan2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Atan2(V2d y, V2d x) { return new V2d(Atan2(y.X, x.X), Atan2(y.Y, x.Y)); } /// /// Applies Fun.FastAtan2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d FastAtan2(V2d y, V2d x) { return new V2d(FastAtan2(y.X, x.X), FastAtan2(y.Y, x.Y)); } /// /// Applies Fun.Sinh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Sinh(this V2d x) { return new V2d(Sinh(x.X), Sinh(x.Y)); } /// /// Applies Fun.Cosh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Cosh(this V2d x) { return new V2d(Cosh(x.X), Cosh(x.Y)); } /// /// Applies Fun.Tanh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Tanh(this V2d x) { return new V2d(Tanh(x.X), Tanh(x.Y)); } /// /// Applies Fun.Asinh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Asinh(this V2d x) { return new V2d(Asinh(x.X), Asinh(x.Y)); } /// /// Applies Fun.Acosh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Acosh(this V2d x) { return new V2d(Acosh(x.X), Acosh(x.Y)); } /// /// Applies Fun.Atanh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Atanh(this V2d x) { return new V2d(Atanh(x.X), Atanh(x.Y)); } #endregion #region Step functions /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Step(this V2d x, V2d edge) { return new V2d(Step(x.X, edge.X), Step(x.Y, edge.Y)); } /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Step(this V2d x, double edge) { return new V2d(Step(x.X, edge), Step(x.Y, edge)); } /// /// Applies Fun.Linearstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Linearstep(this V2d x, V2d edge0, V2d edge1) { return new V2d(Linearstep(x.X, edge0.X, edge1.X), Linearstep(x.Y, edge0.Y, edge1.Y)); } /// /// Applies Fun.Linearstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Linearstep(this V2d x, double edge0, double edge1) { return new V2d(Linearstep(x.X, edge0, edge1), Linearstep(x.Y, edge0, edge1)); } /// /// Applies Fun.Smoothstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Smoothstep(this V2d x, V2d edge0, V2d edge1) { return new V2d(Smoothstep(x.X, edge0.X, edge1.X), Smoothstep(x.Y, edge0.Y, edge1.Y)); } /// /// Applies Fun.Smoothstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Smoothstep(this V2d x, double edge0, double edge1) { return new V2d(Smoothstep(x.X, edge0, edge1), Smoothstep(x.Y, edge0, edge1)); } #endregion #region Interpolation /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Lerp(this double t, V2d a, V2d b) { return new V2d(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Lerp(this V2d t, V2d a, V2d b) { return new V2d(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y)); } /// /// Applies Fun.InvLerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d InvLerp(this V2d y, V2d a, V2d b) { return new V2d(InvLerp(y.X, a.X, b.X), InvLerp(y.Y, a.Y, b.Y)); } #endregion #region Floating point bits /// /// Applies Fun.FloatToBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2l FloatToBits(this V2d x) { return new V2l(FloatToBits(x.X), FloatToBits(x.Y)); } #endregion #region ApproximateEquals /// /// Returns whether the given vectors are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V2d a, V2d b, double tolerance) { return ApproximateEquals(a.X, b.X, tolerance) && ApproximateEquals(a.Y, b.Y, tolerance); } /// /// Returns whether the given vectors are equal within /// Constant{double}.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V2d a, V2d b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this V2d v, double epsilon) => Vec.AllTiny(v, epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than Constant<double>.PositiveTinyValue. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(V2d v) => v.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any component of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(V2d v) => v.IsNaN; /// /// Returns whether any component of the the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(V2d v) => v.IsInfinity; /// /// Returns whether any component of the the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(V2d v) => v.IsPositiveInfinity; /// /// Returns whether any component of the the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(V2d v) => v.IsNegativeInfinity; /// /// Returns whether all components of the the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(V2d v) => v.IsFinite; #endregion } public static partial class Conversion { #region Angles (Radians, Degrees, Gons) /// /// Converts the angles given in degrees to radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d RadiansFromDegrees(this V2d degrees) => new V2d( RadiansFromDegrees(degrees.X), RadiansFromDegrees(degrees.Y) ); /// /// Converts the angles given in gons to radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d RadiansFromGons(this V2d gons) => new V2d( RadiansFromGons(gons.X), RadiansFromGons(gons.Y) ); /// /// Converts the angles given in radians to degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d DegreesFromRadians(this V2d radians) => new V2d( DegreesFromRadians(radians.X), DegreesFromRadians(radians.Y) ); /// /// Converts the angles given in gons to degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d DegreesFromGons(this V2d gons) => new V2d( DegreesFromGons(gons.X), DegreesFromGons(gons.Y) ); /// /// Converts the angles given in radians to gons. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GonsFromRadians(this V2d radians) => new V2d( GonsFromRadians(radians.X), GonsFromRadians(radians.Y) ); /// /// Converts the angles given in degrees to gons. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d GonsFromDegrees(this V2d degrees) => new V2d( GonsFromDegrees(degrees.X), GonsFromDegrees(degrees.Y) ); #endregion } /// /// Contains static methods /// public static partial class Vec { #region Length /// /// Returns the squared length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LengthSquared(V2d v) => v.LengthSquared; /// /// Returns the length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Length(V2d v) => v.Length; #endregion #region Normalize /// /// Normalizes the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref V2d v) { var s = v.Length; if (s == 0) return; s = 1 / s; v.X *= s; v.Y *= s; } /// /// Returns a normalized copy of this vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Normalized(V2d v) => v.Normalized; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm1(V2d v) => v.Norm1; /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(V2d v) => v.Norm2; /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormMax(V2d v) => v.NormMax; /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormMin(V2d v) => v.NormMin; /// /// Gets the p-norm. This is calculated as the p-th root of (|x|^n + |y|^n + ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this V2d v, double p) { return ( Fun.Abs(v.X).Pow(p) + Fun.Abs(v.Y).Pow(p)).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the squared distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceSquared(this V2d a, V2d b) => Fun.Square(b.X - a.X) + Fun.Square(b.Y - a.Y); /// /// Returns the distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V2d a, V2d b) => Fun.Sqrt(DistanceSquared(a, b)); /// /// Returns the Manhatten (or 1-) distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance1(this V2d a, V2d b) => Fun.Abs(b.X - a.X) + Fun.Abs(b.Y - a.Y); /// /// Returns the p-distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V2d a, V2d b, double p) => (Fun.Abs(b.X - a.X).Pow(p) + Fun.Abs(b.Y - a.Y).Pow(p)).Pow(1 / p); /// /// Returns the maximal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceMax(this V2d a, V2d b) => Fun.Max(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y)); /// /// Returns the minimal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceMin(this V2d a, V2d b) => Fun.Min(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y)); /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V2d query, V2d p0, V2d p1) { var p0p1 = p1 - p0; var p0q = query - p0; var t = Dot(p0q, p0p1); if (t <= 0) { return p0q.Length; } var denom = p0p1.LengthSquared; if (t >= denom) { return Distance(query, p1); } t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V2d query, V2d p0, V2d p1) { var p0p1 = p1 - p0; var p0q = query - p0; var t = Dot(p0q, p0p1); var denom = p0p1.LengthSquared; t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V2d query, V2d p0, V2d p1, out double t) { var p0p1 = p1 - p0; var p0q = query - p0; t = Dot(p0q, p0p1); if (t <= 0) { t = 0; return p0q.Length; } var denom = p0p1.LengthSquared; if (t >= denom) { t = 1; return Distance(query, p1); } t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V2d query, V2d p0, V2d p1, out double t) { var p0p1 = p1 - p0; var p0q = query - p0; t = Dot(p0q, p0p1); var denom = p0p1.LengthSquared; t /= denom; return (p0q - t * p0p1).Length; } #endregion #region Operations /// /// Returns a vector that is orthogonal to the given one (i.e. {x,y} -> {-y,x}). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Orthogonal(V2d v) => v.Orthogonal; /// /// Gets a copy of the given vector containing the reciprocal (1/x) of each element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Reciprocal(V2d v) => v.Reciprocal; /// /// Negates the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Negate(this ref V2d v) { v.X = -v.X; v.Y = -v.Y; } /// /// Returns the outer product (tensor-product) of a * b^T as a 2x2 matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M22d Outer(this V2d a, V2d b) { return new M22d( a.X * b.X, a.X * b.Y, a.Y * b.X, a.Y * b.Y); } /// /// Returns the dot product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Dot(this V2d a, V2d b) { return a.X * b.X + a.Y * b.Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DirFlags DirFlags(this V2d v) { DirFlags flags = Aardbase.DirFlags.None; if (v.X > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveX; if (v.X < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeX; if (v.Y > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveY; if (v.Y < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeY; return flags; } /// /// Returns the reflection direction of the given vector v (pointing to the surface) for the given normal (should be normalized). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Reflect(this V2d v, V2d normal) { return v - 2 * v.Dot(normal) * normal; } /// /// Returns the refraction direction of the given vector v (pointing to the surface) for the given normal and ratio of refraction indices (n_out / n_in). /// Both the input vectors should be normalized. /// Returns a zero-vector in case of total internal reflection. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d Refract(this V2d v, V2d normal, double eta) { var t = v.Dot(normal); var k = 1 - eta * eta * (1 - t * t); if (k < 0) { return V2d.Zero; } else { return eta * v - (eta * t + Fun.Sqrt(k)) * normal; } } /// /// Returns the cross product of vector a. /// In 2D the cross product is simply a vector that is normal /// to the given vector (i.e. {x,y} -> {-y,x}) /// public static V2d Cross(this V2d a) { return new V2d(-a.Y, a.X); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V2d a, V2d b) { return (a.X < b.X && a.Y < b.Y); } /// /// Returns whether ALL elements of v are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V2d v, double s) { return (v.X < s && v.Y < s); } /// /// Returns whether a is Smaller ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(double s, V2d v) { return (s < v.X && s < v.Y); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V2d a, V2d b) { return (a.X < b.X || a.Y < b.Y); } /// /// Returns whether AT LEAST ONE element of v is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V2d v, double s) { return (v.X < s || v.Y < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(double s, V2d v) { return (s < v.X || s < v.Y); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V2d a, V2d b) { return (a.X > b.X && a.Y > b.Y); } /// /// Returns whether ALL elements of v are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V2d v, double s) { return (v.X > s && v.Y > s); } /// /// Returns whether a is Greater ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(double s, V2d v) { return (s > v.X && s > v.Y); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V2d a, V2d b) { return (a.X > b.X || a.Y > b.Y); } /// /// Returns whether AT LEAST ONE element of v is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V2d v, double s) { return (v.X > s || v.Y > s); } /// /// Returns whether a is Greater AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(double s, V2d v) { return (s > v.X || s > v.Y); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V2d a, V2d b) { return (a.X <= b.X && a.Y <= b.Y); } /// /// Returns whether ALL elements of v are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V2d v, double s) { return (v.X <= s && v.Y <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(double s, V2d v) { return (s <= v.X && s <= v.Y); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V2d a, V2d b) { return (a.X <= b.X || a.Y <= b.Y); } /// /// Returns whether AT LEAST ONE element of v is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V2d v, double s) { return (v.X <= s || v.Y <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(double s, V2d v) { return (s <= v.X || s <= v.Y); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V2d a, V2d b) { return (a.X >= b.X && a.Y >= b.Y); } /// /// Returns whether ALL elements of v are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V2d v, double s) { return (v.X >= s && v.Y >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(double s, V2d v) { return (s >= v.X && s >= v.Y); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V2d a, V2d b) { return (a.X >= b.X || a.Y >= b.Y); } /// /// Returns whether AT LEAST ONE element of v is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V2d v, double s) { return (v.X >= s || v.Y >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(double s, V2d v) { return (s >= v.X || s >= v.Y); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V2d a, V2d b) { return (a.X == b.X && a.Y == b.Y); } /// /// Returns whether ALL elements of v are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V2d v, double s) { return (v.X == s && v.Y == s); } /// /// Returns whether a is Equal ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(double s, V2d v) { return (s == v.X && s == v.Y); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V2d a, V2d b) { return (a.X == b.X || a.Y == b.Y); } /// /// Returns whether AT LEAST ONE element of v is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V2d v, double s) { return (v.X == s || v.Y == s); } /// /// Returns whether a is Equal AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(double s, V2d v) { return (s == v.X || s == v.Y); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V2d a, V2d b) { return (a.X != b.X && a.Y != b.Y); } /// /// Returns whether ALL elements of v are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V2d v, double s) { return (v.X != s && v.Y != s); } /// /// Returns whether a is Different ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(double s, V2d v) { return (s != v.X && s != v.Y); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V2d a, V2d b) { return (a.X != b.X || a.Y != b.Y); } /// /// Returns whether AT LEAST ONE element of v is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V2d v, double s) { return (v.X != s || v.Y != s); } /// /// Returns whether a is Different AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(double s, V2d v) { return (s != v.X || s != v.Y); } /// /// Compare x-coordinate before y-coordinate, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this V2d v0, V2d v1) { if (v0.X < v1.X) return -1; if (v0.X > v1.X) return +1; if (v0.Y < v1.Y) return -1; if (v0.Y > v1.Y) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MinElement(V2d v) => v.MinElement; /// /// Returns the maximum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MaxElement(V2d v) => v.MaxElement; #endregion #region Angle between two vectors /// /// Computes the angle between two given vectors in radians. The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double AngleBetweenFast(this V2d x, V2d y) { return Fun.AcosClamped(x.Dot(y)); } /// /// Computes the angle between two given vectors in radians using a numerically stable algorithm. /// The input vectors have to be normalized. /// // https://scicomp.stackexchange.com/a/27769 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double AngleBetween(this V2d x, V2d y) { var a = x + y; var b = x - y; return 2 * Fun.Atan2(b.Length, a.Length); } /// /// Computes the signed angle between two given vectors in radians. The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double AngleBetweenSigned(this V2d x, V2d y) { var a = x.X * y.Y - x.Y * y.X; var b = x.X * y.X + x.Y * y.Y; return Fun.Atan2(a, b); } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this V2d v, double epsilon) => v.X.IsTiny(epsilon) || v.Y.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this V2d v, double epsilon) => v.X.IsTiny(epsilon) && v.Y.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyFinite(V2d v) => v.AnyFinite; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllFinite(V2d v) => v.AllFinite; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(V2d v) => v.AnyNaN; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(V2d v) => v.AllNaN; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(V2d v) => v.AnyInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(V2d v) => v.AllInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(V2d v) => v.AnyPositiveInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(V2d v) => v.AllPositiveInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(V2d v) => v.AnyNegativeInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(V2d v) => v.AllNegativeInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(V2d v) => v.AnyTiny; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(V2d v) => v.AllTiny; #endregion #region 2D Vector Arithmetics /// /// Dot product of vector with dir rotated by 90 degrees counterclockwise. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Dot90(this V2d v, V2d dir) { return v.Y * dir.X - v.X * dir.Y; } /// /// Dot product of vector with dir rotated by 180 degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Dot180(this V2d v, V2d dir) { return -(v.X * dir.X + v.Y * dir.Y); } /// /// Dot product of vector with dir rotated by 270 degrees counterclockwise. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Dot270(this V2d v, V2d dir) { return v.X * dir.Y - v.Y * dir.X; } /// /// Returns the left value of the direction v with respect to the /// line from p0 to p1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DirLeftOfLineValue(this V2d v, V2d p0, V2d p1) { return v.X * (p0.Y - p1.Y) + v.Y * (p1.X - p0.X); } /// /// Returns the right value of the direction v with respect to the /// line from p0 to p1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DirRightOfLineValue(this V2d v, V2d p0, V2d p1) { return v.X * (p1.Y - p0.Y) + v.Y * (p0.X - p1.X); } /// /// Returns the left value of the point p with respect to the /// line from p0 to p1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double PosLeftOfLineValue(this V2d p, V2d p0, V2d p1) { return (p.X - p0.X) * (p0.Y - p1.Y) + (p.Y - p0.Y) * (p1.X - p0.X); } /// /// Returns the right value of the point p with respect to the /// line from p0 to p1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double PosRightOfLineValue(this V2d p, V2d p0, V2d p1) { return (p.X - p0.X) * (p1.Y - p0.Y) + (p.Y - p0.Y) * (p0.X - p1.X); } #endregion #region Linear Combination [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d LinCom(V2d p0, V2d p1, ref Tup2 w) { return p0 * w.E0 + p1 * w.E1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d LinCom(V2d p0, V2d p1, V2d p2, ref Tup3 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d LinCom(V2d p0, V2d p1, V2d p2, V2d p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d LinCom(V2d p0, V2d p1, V2d p2, V2d p3, V2d p4, ref Tup5 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d LinCom(V2d p0, V2d p1, V2d p2, V2d p3, V2d p4, V2d p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d LinCom(V2d p0, V2d p1, V2d p2, V2d p3, V2d p4, V2d p5, V2d p6, ref Tup7 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5 + p6 * w.E6; } #endregion #region ArrayExtensions public static int IndexOfClosestPoint(this V2d[] pointArray, V2d point) { var bestDist = DistanceSquared(point, pointArray[0]); int bestIndex = 0; int count = pointArray.Length; for (int i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this V2d[] array, int start, int count, V2d point) { var bestDist = DistanceSquared(point, array[start]); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this T[] array, int start, int count, Func pointSelector, V2d point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint(this V2d[] pointArray, V2d point) { var bestDist = DistanceSquared(point, pointArray[0]); long bestIndex = 0; long count = pointArray.LongLength; for (long i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this V2d[] array, long start, long count, V2d point) { var bestDist = DistanceSquared(point, array[start]); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this T[] array, long start, long count, Func pointSelector, V2d point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static int IndexOfMinX(this V2d[] vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static long LongIndexOfMinX(this V2d[] vectorArray, long count = 0) { var minimum = vectorArray[0].X; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static int IndexOfMaxX(this V2d[] vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static long LongIndexOfMaxX(this V2d[] vectorArray, long count = 0) { var maximum = vectorArray[0].X; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static int IndexOfMinY(this V2d[] vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static long LongIndexOfMinY(this V2d[] vectorArray, long count = 0) { var minimum = vectorArray[0].Y; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static int IndexOfMaxY(this V2d[] vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static long LongIndexOfMaxY(this V2d[] vectorArray, long count = 0) { var maximum = vectorArray[0].Y; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the list. /// public static int IndexOfMinX(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the list. /// public static int IndexOfMaxX(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the list. /// public static int IndexOfMinY(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the list. /// public static int IndexOfMaxY(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the array of the index-th coordinate of each vector. /// public static double[] CopyCoord(this V2d[] self, int index) { switch (index) { case 0: return self.Map(v => v.X); case 1: return self.Map(v => v.Y); default: throw new IndexOutOfRangeException(); } } public static V2d WeightedSum( this V2d[] vectorArray, double[] weightArray) { var r = V2d.Zero; var count = vectorArray.LongLength; for (long i = 0; i < count; i++) r += vectorArray[i] * weightArray[i]; return r; } #endregion } public static class IRandomUniformV2dExtensions { #region IRandomUniform extensions for V2d /// /// Uses UniformDouble() to generate the elements of a V2d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d UniformV2d(this IRandomUniform rnd) { return new V2d(rnd.UniformDouble(), rnd.UniformDouble()); } /// /// Uses UniformDouble() to generate the elements of a V2d /// vector within the given Box2d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d UniformV2d(this IRandomUniform rnd, Box2d box) { return new V2d(box.Min.X + rnd.UniformDouble() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformDouble() * (box.Max.Y - box.Min.Y)); } /// /// Uses UniformDoubleClosed() to generate the elements of a V2d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d UniformV2dClosed(this IRandomUniform rnd) { return new V2d(rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed()); } /// /// Uses UniformDoubleClosed() to generate the elements of a V2d /// vector within the given Box2d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d UniformV2dClosed(this IRandomUniform rnd, Box2d box) { return new V2d(box.Min.X + rnd.UniformDoubleClosed() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformDoubleClosed() * (box.Max.Y - box.Min.Y)); } /// /// Uses UniformDoubleOpen() to generate the elements of a V2d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d UniformV2dOpen(this IRandomUniform rnd) { return new V2d(rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen()); } /// /// Uses UniformDoubleOpen() to generate the elements of a V2d /// vector within the given Box2d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d UniformV2dOpen(this IRandomUniform rnd, Box2d box) { return new V2d(box.Min.X + rnd.UniformDoubleOpen() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformDoubleOpen() * (box.Max.Y - box.Min.Y)); } /// /// Uses UniformDoubleFull() to generate the elements of a V2d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d UniformV2dFull(this IRandomUniform rnd) { return new V2d(rnd.UniformDoubleFull(), rnd.UniformDoubleFull()); } /// /// Uses UniformDoubleFull() to generate the elements of a V2d /// vector within the given Box2d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d UniformV2dFull(this IRandomUniform rnd, Box2d box) { return new V2d(box.Min.X + rnd.UniformDoubleFull() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformDoubleFull() * (box.Max.Y - box.Min.Y)); } /// /// Uses UniformDoubleFullClosed() to generate the elements of a V2d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d UniformV2dFullClosed(this IRandomUniform rnd) { return new V2d(rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed()); } /// /// Uses UniformDoubleFullClosed() to generate the elements of a V2d /// vector within the given Box2d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d UniformV2dFullClosed(this IRandomUniform rnd, Box2d box) { return new V2d(box.Min.X + rnd.UniformDoubleFullClosed() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformDoubleFullClosed() * (box.Max.Y - box.Min.Y)); } /// /// Uses UniformDoubleFullOpen() to generate the elements of a V2d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d UniformV2dFullOpen(this IRandomUniform rnd) { return new V2d(rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen()); } /// /// Uses UniformDoubleFullOpen() to generate the elements of a V2d /// vector within the given Box2d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d UniformV2dFullOpen(this IRandomUniform rnd, Box2d box) { return new V2d(box.Min.X + rnd.UniformDoubleFullOpen() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformDoubleFullOpen() * (box.Max.Y - box.Min.Y)); } /// /// Returns a uniformly distributed vector (corresponds to a /// uniformly distributed point on the unit circle). Uses UniformDouble() internally. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d UniformV2dDirection(this IRandomUniform rnd) { double phi = rnd.UniformDouble() * Constant.PiTimesTwo; return new V2d(Fun.Cos(phi), Fun.Sin(phi)); } /// /// Returns a uniformly distributed vector (corresponds to a /// uniformly distributed point on the unit circle). Uses UniformDoubleFull() internally. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V2d UniformV2dFullDirection(this IRandomUniform rnd) { double phi = rnd.UniformDoubleFull() * Constant.PiTimesTwo; return new V2d(Fun.Cos(phi), Fun.Sin(phi)); } #endregion } #endregion #region V3i [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct V3i : IVector, ISize3i, IFormattable, IEquatable { [DataMember] public int X; [DataMember] public int Y; [DataMember] public int Z; #region Constructors /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(int x, int y, int z) { X = x; Y = y; Z = z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(int v) { X = v; Y = v; Z = v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(int[] a) { X = a[0]; Y = a[1]; Z = a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(int[] a, int start) { X = a[start + 0]; Y = a[start + 1]; Z = a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(int a, V2i b) { X = a; Y = b.X; Z = b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V2i a, int b) { X = a.X; Y = a.Y; Z = b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(uint x, uint y, uint z) { X = (int)x; Y = (int)y; Z = (int)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(uint v) { X = (int)v; Y = (int)v; Z = (int)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(uint[] a) { X = (int)a[0]; Y = (int)a[1]; Z = (int)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(uint[] a, int start) { X = (int)a[start + 0]; Y = (int)a[start + 1]; Z = (int)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(uint a, V2ui b) { X = (int)a; Y = (int)b.X; Z = (int)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V2ui a, uint b) { X = (int)a.X; Y = (int)a.Y; Z = (int)b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(long x, long y, long z) { X = (int)x; Y = (int)y; Z = (int)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(long v) { X = (int)v; Y = (int)v; Z = (int)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(long[] a) { X = (int)a[0]; Y = (int)a[1]; Z = (int)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(long[] a, int start) { X = (int)a[start + 0]; Y = (int)a[start + 1]; Z = (int)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(long a, V2l b) { X = (int)a; Y = (int)b.X; Z = (int)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V2l a, long b) { X = (int)a.X; Y = (int)a.Y; Z = (int)b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(float x, float y, float z) { X = (int)x; Y = (int)y; Z = (int)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(float v) { X = (int)v; Y = (int)v; Z = (int)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(float[] a) { X = (int)a[0]; Y = (int)a[1]; Z = (int)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(float[] a, int start) { X = (int)a[start + 0]; Y = (int)a[start + 1]; Z = (int)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(float a, V2f b) { X = (int)a; Y = (int)b.X; Z = (int)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V2f a, float b) { X = (int)a.X; Y = (int)a.Y; Z = (int)b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(double x, double y, double z) { X = (int)x; Y = (int)y; Z = (int)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(double v) { X = (int)v; Y = (int)v; Z = (int)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(double[] a) { X = (int)a[0]; Y = (int)a[1]; Z = (int)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(double[] a, int start) { X = (int)a[start + 0]; Y = (int)a[start + 1]; Z = (int)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(double a, V2d b) { X = (int)a; Y = (int)b.X; Z = (int)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V2d a, double b) { X = (int)a.X; Y = (int)a.Y; Z = (int)b; } /// /// Creates a vector from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(Func index_fun) { X = index_fun(0); Y = index_fun(1); Z = index_fun(2); } /// /// Creates a vector from a general vector implementing the IVector<int> interface. /// The caller has to verify that the dimension of is at least 3. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(IVector v) : this(v[0], v[1], v[2]) { } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V2i v) { X = v.X; Y = v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V2ui v) { X = (int)v.X; Y = (int)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V2l v) { X = (int)v.X; Y = (int)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V2f v) { X = (int)v.X; Y = (int)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V2d v) { X = (int)v.X; Y = (int)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V3i v) { X = v.X; Y = v.Y; Z = v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V3ui v) { X = (int)v.X; Y = (int)v.Y; Z = (int)v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V3l v) { X = (int)v.X; Y = (int)v.Y; Z = (int)v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V3f v) { X = (int)v.X; Y = (int)v.Y; Z = (int)v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V3d v) { X = (int)v.X; Y = (int)v.Y; Z = (int)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V4i v) { X = v.X; Y = v.Y; Z = v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V4ui v) { X = (int)v.X; Y = (int)v.Y; Z = (int)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V4l v) { X = (int)v.X; Y = (int)v.Y; Z = (int)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V4f v) { X = (int)v.X; Y = (int)v.Y; Z = (int)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(V4d v) { X = (int)v.X; Y = (int)v.Y; Z = (int)v.Z; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(C3b c) { X = (int)(c.R); Y = (int)(c.G); Z = (int)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(C3us c) { X = (int)(c.R); Y = (int)(c.G); Z = (int)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(C4b c) { X = (int)(c.R); Y = (int)(c.G); Z = (int)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3i(C4us c) { X = (int)(c.R); Y = (int)(c.G); Z = (int)(c.B); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(V2i v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(V2ui v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(V2l v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(V2f v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(V2d v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(V3ui v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(V3l v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(V3f v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(V3d v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(V4i v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(V4ui v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(V4l v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(V4f v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(V4d v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui ToV2ui() => (V2ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToV2l() => (V2l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f ToV2f() => (V2f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d ToV2d() => (V2d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int[](V3i v) => new int[] { v.X, v.Y, v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(int[] v) => new V3i(v[0], v[1], v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](V3i v) => new uint[] { (uint)v.X, (uint)v.Y, (uint)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(uint[] v) => new V3i((int)v[0], (int)v[1], (int)v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long[](V3i v) => new long[] { (long)v.X, (long)v.Y, (long)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(long[] v) => new V3i((int)v[0], (int)v[1], (int)v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](V3i v) => new float[] { (float)v.X, (float)v.Y, (float)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(float[] v) => new V3i((int)v[0], (int)v[1], (int)v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](V3i v) => new double[] { (double)v.X, (double)v.Y, (double)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(double[] v) => new V3i((int)v[0], (int)v[1], (int)v[2]); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(C3b v) => new V3i(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(C3us v) => new V3i(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(C4b v) => new V3i(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3i(C4us v) => new V3i(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i Copy(Func element_fun) => new V3i(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i Copy(Func element_index_fun) => new V3i(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(int[] array, int start) { array[start + 0] = X; array[start + 1] = Y; array[start + 2] = Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui Copy(Func element_fun) => new V3ui(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui Copy(Func element_index_fun) => new V3ui(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(uint[] array, int start) { array[start + 0] = (uint)X; array[start + 1] = (uint)Y; array[start + 2] = (uint)Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l Copy(Func element_fun) => new V3l(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l Copy(Func element_index_fun) => new V3l(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(long[] array, int start) { array[start + 0] = (long)X; array[start + 1] = (long)Y; array[start + 2] = (long)Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f Copy(Func element_fun) => new V3f(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f Copy(Func element_index_fun) => new V3f(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(float[] array, int start) { array[start + 0] = (float)X; array[start + 1] = (float)Y; array[start + 2] = (float)Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d Copy(Func element_fun) => new V3d(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d Copy(Func element_index_fun) => new V3d(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(double[] array, int start) { array[start + 0] = (double)X; array[start + 1] = (double)Y; array[start + 2] = (double)Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(X); array[start + 1] = element_fun(Y); array[start + 2] = element_fun(Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(X, 0); array[start + 1] = element_index_fun(Y, 1); array[start + 2] = element_index_fun(Z, 2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int[] ToArray() => new int[] { X, Y, Z }; #endregion #region Properties and Indexers /// /// Property for the field X. /// Useful when properties are required, but the field X is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public int P_X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value; } } /// /// Property for the field Y. /// Useful when properties are required, but the field Y is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public int P_Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Y = value; } } /// /// Property for the field Z. /// Useful when properties are required, but the field Z is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public int P_Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Z = value; } } /// /// Enumerates all elements of this vector. /// public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return X; yield return Y; yield return Z; } } /// /// Gets or sets element with given index. /// public unsafe int this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (int* ptr = &X) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (int* ptr = &X) { ptr[index] = value; } } } /// /// Returns the index of the largest dimension of the vector. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X >= Y ? (X >= Z ? 0 : 2) : (Y >= Z ? 1 : 2); } } /// /// Returns the index of the smallest dimension of the vector. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X <= Y ? (X <= Z ? 0 : 2) : (Y <= Z ? 1 : 2); } } /// /// Returns the minimum element of the vector. /// public readonly int MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(X, Y, Z); } /// /// Returns the maximum element of the vector. /// public readonly int MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(X, Y, Z); } #endregion #region Constants /// /// Number of elements in this vector. /// public const int Dimension = 3; /// /// All elements zero. /// public static V3i Zero { get { return new V3i(0, 0, 0); } } /// /// All elements one. /// public static V3i One { get { return new V3i(1, 1, 1); } } /// /// All elements set to maximum possible value. /// public static V3i MaxValue { get { return new V3i(Constant.ParseableMaxValue, Constant.ParseableMaxValue, Constant.ParseableMaxValue); } } /// /// All elements set to minimum possible value. /// public static V3i MinValue { get { return new V3i(Constant.ParseableMinValue, Constant.ParseableMinValue, Constant.ParseableMinValue); } } /// /// Normalized X-axis. /// public static V3i XAxis { get { return new V3i(1, 0, 0); } } /// /// Normalized Y-axis. /// public static V3i YAxis { get { return new V3i(0, 1, 0); } } /// /// Normalized Z-axis. /// public static V3i ZAxis { get { return new V3i(0, 0, 1); } } /// /// An array of accessor functions for the coordinates of the vector. /// public static readonly Func[] SelectorArray = new Func[] { v => v.X, v => v.Y, v => v.Z }; /// /// Element getter function. /// public static readonly Func Getter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref V3i v, int i, int s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; default: throw new IndexOutOfRangeException(); } }; /// /// Element getter function with long index. /// public static readonly Func LongGetter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action with long index. /// public static readonly ActionRefValVal LongSetter = (ref V3i v, long i, int s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Static factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i FromV3ui(V3ui v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i FromV3l(V3l v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i FromV3f(V3f v) => new V3i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i FromV3d(V3d v) => new V3i(v); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i FromC3b(C3b c) => new V3i(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i FromC3us(C3us c) => new V3i(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i FromC4b(C4b c) => new V3i(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i FromC4us(C4us c) => new V3i(c); #endregion #region Norms /// /// Returns the squared length of the vector. /// public readonly int LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X * X + Y * Y + Z * Z ; } } /// /// Returns the length of the vector. /// public readonly double Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z ); } } /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// public readonly int Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Abs(X) + Fun.Abs(Y) + Fun.Abs(Z); } } /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z); } } /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// public readonly int NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z)); } } /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// public readonly int NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z)); } } /// /// Returns a normalized copy of this vector. /// public readonly V3d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Length; if (s == 0) return V3d.Zero; s = 1 / s; return new V3d(X * s, Y * s, Z * s); } } #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Abs(V3i v) => v.Abs(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i LinearInterp(float t, V3i a, V3i b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i LinearInterp(V3f t, V3i a, V3i b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i LinearInterp(double t, V3i a, V3i b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i LinearInterp(V3d t, V3i a, V3i b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Min(V3i v0, V3i v1) => Fun.Min(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Min(V3i v, int x) => Fun.Min(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Max(V3i v0, V3i v1) => Fun.Max(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Max(V3i v, int x) => Fun.Max(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Saturate(V3i v) => Fun.Saturate(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i DivideByInt(V3i v, int x) => v / x; #endregion #region Operations /// /// Sets the elements of a vector to the given int elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(int x, int y, int z) { X = x; Y = y; Z = z; } /// /// Sets the elements of a vector to the given uint elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(uint x, uint y, uint z) { X = (int)x; Y = (int)y; Z = (int)z; } /// /// Sets the elements of a vector to the given long elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(long x, long y, long z) { X = (int)x; Y = (int)y; Z = (int)z; } /// /// Sets the elements of a vector to the given float elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(float x, float y, float z) { X = (int)x; Y = (int)y; Z = (int)z; } /// /// Sets the elements of a vector to the given double elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(double x, double y, double z) { X = (int)x; Y = (int)y; Z = (int)z; } /// /// Returns a negated copy of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator -(V3i v) => new V3i(-v.X, -v.Y, -v.Z); /// /// Returns the component-wise bitwise complement of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator ~(V3i v) => new V3i(~v.X, ~v.Y, ~v.Z); /// /// Returns the component-wise sum of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator +(V3i a, V3i b) => new V3i(a.X + b.X, a.Y + b.Y, a.Z + b.Z); /// /// Returns the component-wise sum of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator +(V3i v, int s) => new V3i(v.X + s, v.Y + s, v.Z + s); /// /// Returns the component-wise sum of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator +(int s, V3i v) => new V3i(s + v.X, s + v.Y, s + v.Z); /// /// Returns the component-wise difference of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator -(V3i a, V3i b) => new V3i(a.X - b.X, a.Y - b.Y, a.Z - b.Z); /// /// Returns the component-wise difference of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator -(V3i v, int s) => new V3i(v.X - s, v.Y - s, v.Z - s); /// /// Returns the component-wise difference of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator -(int s, V3i v) => new V3i(s - v.X, s - v.Y, s - v.Z); /// /// Returns the component-wise product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator *(V3i a, V3i b) => new V3i(a.X * b.X, a.Y * b.Y, a.Z * b.Z); /// /// Returns the component-wise product of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator *(V3i v, int s) => new V3i(v.X * s, v.Y * s, v.Z * s); /// /// Returns the component-wise product of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator *(int s, V3i v) => new V3i(s * v.X, s * v.Y, s * v.Z); /// /// Returns the component-wise fraction of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator /(V3i a, V3i b) => new V3i(a.X / b.X, a.Y / b.Y, a.Z / b.Z); /// /// Returns the component-wise fraction of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator /(V3i v, int s) => new V3i(v.X / s, v.Y / s, v.Z / s); /// /// Returns the component-wise fraction of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator /(int s, V3i v) => new V3i(s / v.X, s / v.Y, s / v.Z); /// /// Returns the component-wise remainder of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator %(V3i a, V3i b) => new V3i(a.X % b.X, a.Y % b.Y, a.Z % b.Z); /// /// Returns the component-wise remainder of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator %(V3i v, int s) => new V3i(v.X % s, v.Y % s, v.Z % s); /// /// Returns the component-wise remainder of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator %(int s, V3i v) => new V3i(s % v.X, s % v.Y, s % v.Z); /// /// Returns the component-wise bitwise and of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator &(V3i a, V3i b) => new V3i(a.X & b.X, a.Y & b.Y, a.Z & b.Z); /// /// Returns the component-wise bitwise and of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator &(V3i v, int s) => new V3i(v.X & s, v.Y & s, v.Z & s); /// /// Returns the component-wise bitwise and of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator &(int s, V3i v) => new V3i(s & v.X, s & v.Y, s & v.Z); /// /// Returns the component-wise bitwise or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator |(V3i a, V3i b) => new V3i(a.X | b.X, a.Y | b.Y, a.Z | b.Z); /// /// Returns the component-wise bitwise or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator |(V3i v, int s) => new V3i(v.X | s, v.Y | s, v.Z | s); /// /// Returns the component-wise bitwise or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator |(int s, V3i v) => new V3i(s | v.X, s | v.Y, s | v.Z); /// /// Returns the component-wise bitwise exclusive or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator ^(V3i a, V3i b) => new V3i(a.X ^ b.X, a.Y ^ b.Y, a.Z ^ b.Z); /// /// Returns the component-wise bitwise exclusive or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator ^(V3i v, int s) => new V3i(v.X ^ s, v.Y ^ s, v.Z ^ s); /// /// Returns the component-wise bitwise exclusive or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator ^(int s, V3i v) => new V3i(s ^ v.X, s ^ v.Y, s ^ v.Z); /// /// Returns the component-wise left bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator <<(V3i v, int s) => new V3i(v.X << s, v.Y << s, v.Z << s); /// /// Returns the component-wise right bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i operator >>(V3i v, int s) => new V3i(v.X >> s, v.Y >> s, v.Z >> s); /// Attention: NEVER implement operators <, <=, >=, >, /// since these are not defined in a Vector space. /// Use AllSmaller() and similar comparators! #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V3i a, V3i b) { return a.X == b.X && a.Y == b.Y && a.Z == b.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V3i v, int s) { return v.X == s && v.Y == s && v.Z == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(int s, V3i v) { return s == v.X && s == v.Y && s == v.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V3i a, V3i b) { return a.X != b.X || a.Y != b.Y || a.Z != b.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V3i v, int s) { return v.X != s || v.Y != s || v.Z != s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(int s, V3i v) { return s != v.X || s != v.Y || s != v.Z; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(V3i other) { return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z); } #endregion #region Overrides public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + X.ToString(format, fp) + between + Y.ToString(format, fp) + between + Z.ToString(format, fp) + end; } public override readonly int GetHashCode() { return HashCode.GetCombined(X, Y, Z); } public override readonly bool Equals(object other) => (other is V3i o) ? Equals(o) : false; public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + X.ToString(null, CultureInfo.InvariantCulture) + ", " + Y.ToString(null, CultureInfo.InvariantCulture) + ", " + Z.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Parsing public static V3i Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new V3i( int.Parse(x[0], CultureInfo.InvariantCulture), int.Parse(x[1], CultureInfo.InvariantCulture), int.Parse(x[2], CultureInfo.InvariantCulture) ); } public static V3i Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, V3i.Setter); } public static V3i Parse(Text t, int bracketLevel) { return t.NestedBracketSplit(bracketLevel, Text.Parse, V3i.Setter); } #endregion #region Swizzle Methods [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i OX => new V2i(0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i OY => new V2i(0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i OZ => new V2i(0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i IX => new V2i(1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i IY => new V2i(1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i IZ => new V2i(1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i NX => new V2i(-1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i NY => new V2i(-1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i NZ => new V2i(-1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i XO => new V2i(X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i XI => new V2i(X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i XN => new V2i(X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i XX => new V2i(X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i XY { readonly get => new V2i(X, Y); set { X = value.X; Y = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i XZ { readonly get => new V2i(X, Z); set { X = value.X; Z = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i YO => new V2i(Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i YI => new V2i(Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i YN => new V2i(Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i YX { readonly get => new V2i(Y, X); set { Y = value.X; X = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i YY => new V2i(Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i YZ { readonly get => new V2i(Y, Z); set { Y = value.X; Z = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i ZO => new V2i(Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i ZI => new V2i(Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i ZN => new V2i(Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i ZX { readonly get => new V2i(Z, X); set { Z = value.X; X = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i ZY { readonly get => new V2i(Z, Y); set { Z = value.X; Y = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i ZZ => new V2i(Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i OOO => new V3i(0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i OOI => new V3i(0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i OON => new V3i(0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OOX => new V3i(0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OOY => new V3i(0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OOZ => new V3i(0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i OIO => new V3i(0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i OII => new V3i(0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i OPN => new V3i(0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OIX => new V3i(0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OIY => new V3i(0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OIZ => new V3i(0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i ONO => new V3i(0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i ONP => new V3i(0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i ONN => new V3i(0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ONX => new V3i(0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ONY => new V3i(0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ONZ => new V3i(0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXO => new V3i(0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXI => new V3i(0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXN => new V3i(0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXX => new V3i(0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXY => new V3i(0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXZ => new V3i(0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYO => new V3i(0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYI => new V3i(0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYN => new V3i(0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYX => new V3i(0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYY => new V3i(0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYZ => new V3i(0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OZO => new V3i(0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OZI => new V3i(0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OZN => new V3i(0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OZX => new V3i(0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OZY => new V3i(0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OZZ => new V3i(0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i IOO => new V3i(1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i IOI => new V3i(1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i PON => new V3i(1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IOX => new V3i(1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IOY => new V3i(1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IOZ => new V3i(1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i IIO => new V3i(1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i III => new V3i(1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i PPN => new V3i(1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IIX => new V3i(1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IIY => new V3i(1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IIZ => new V3i(1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i PNO => new V3i(1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i PNP => new V3i(1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i PNN => new V3i(1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PNX => new V3i(1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PNY => new V3i(1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PNZ => new V3i(1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IXO => new V3i(1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IXI => new V3i(1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PXN => new V3i(1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IXX => new V3i(1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IXY => new V3i(1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IXZ => new V3i(1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IYO => new V3i(1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IYI => new V3i(1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PYN => new V3i(1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IYX => new V3i(1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IYY => new V3i(1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IYZ => new V3i(1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IZO => new V3i(1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IZI => new V3i(1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PZN => new V3i(1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IZX => new V3i(1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IZY => new V3i(1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IZZ => new V3i(1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i NOO => new V3i(-1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i NOP => new V3i(-1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i NON => new V3i(-1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NOX => new V3i(-1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NOY => new V3i(-1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NOZ => new V3i(-1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i NPO => new V3i(-1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i NPP => new V3i(-1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i NPN => new V3i(-1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NPX => new V3i(-1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NPY => new V3i(-1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NPZ => new V3i(-1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i NNO => new V3i(-1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i NNP => new V3i(-1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3i NNN => new V3i(-1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NNX => new V3i(-1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NNY => new V3i(-1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NNZ => new V3i(-1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXO => new V3i(-1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXP => new V3i(-1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXN => new V3i(-1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXX => new V3i(-1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXY => new V3i(-1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXZ => new V3i(-1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYO => new V3i(-1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYP => new V3i(-1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYN => new V3i(-1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYX => new V3i(-1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYY => new V3i(-1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYZ => new V3i(-1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NZO => new V3i(-1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NZP => new V3i(-1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NZN => new V3i(-1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NZX => new V3i(-1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NZY => new V3i(-1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NZZ => new V3i(-1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XOO => new V3i(X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XOI => new V3i(X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XON => new V3i(X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XOX => new V3i(X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XOY => new V3i(X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XOZ => new V3i(X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XIO => new V3i(X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XII => new V3i(X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XPN => new V3i(X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XIX => new V3i(X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XIY => new V3i(X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XIZ => new V3i(X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNO => new V3i(X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNP => new V3i(X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNN => new V3i(X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNX => new V3i(X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNY => new V3i(X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNZ => new V3i(X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXO => new V3i(X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXI => new V3i(X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXN => new V3i(X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXX => new V3i(X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXY => new V3i(X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXZ => new V3i(X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XYO => new V3i(X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XYI => new V3i(X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XYN => new V3i(X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XYX => new V3i(X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XYY => new V3i(X, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i XYZ { readonly get => new V3i(X, Y, Z); set { X = value.X; Y = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XZO => new V3i(X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XZI => new V3i(X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XZN => new V3i(X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XZX => new V3i(X, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i XZY { readonly get => new V3i(X, Z, Y); set { X = value.X; Z = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XZZ => new V3i(X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YOO => new V3i(Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YOI => new V3i(Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YON => new V3i(Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YOX => new V3i(Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YOY => new V3i(Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YOZ => new V3i(Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YIO => new V3i(Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YII => new V3i(Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YPN => new V3i(Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YIX => new V3i(Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YIY => new V3i(Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YIZ => new V3i(Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNO => new V3i(Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNP => new V3i(Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNN => new V3i(Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNX => new V3i(Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNY => new V3i(Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNZ => new V3i(Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YXO => new V3i(Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YXI => new V3i(Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YXN => new V3i(Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YXX => new V3i(Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YXY => new V3i(Y, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i YXZ { readonly get => new V3i(Y, X, Z); set { Y = value.X; X = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYO => new V3i(Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYI => new V3i(Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYN => new V3i(Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYX => new V3i(Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYY => new V3i(Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYZ => new V3i(Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YZO => new V3i(Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YZI => new V3i(Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YZN => new V3i(Y, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i YZX { readonly get => new V3i(Y, Z, X); set { Y = value.X; Z = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YZY => new V3i(Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YZZ => new V3i(Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZOO => new V3i(Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZOI => new V3i(Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZON => new V3i(Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZOX => new V3i(Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZOY => new V3i(Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZOZ => new V3i(Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZIO => new V3i(Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZII => new V3i(Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZPN => new V3i(Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZIX => new V3i(Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZIY => new V3i(Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZIZ => new V3i(Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZNO => new V3i(Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZNP => new V3i(Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZNN => new V3i(Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZNX => new V3i(Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZNY => new V3i(Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZNZ => new V3i(Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZXO => new V3i(Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZXI => new V3i(Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZXN => new V3i(Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZXX => new V3i(Z, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i ZXY { readonly get => new V3i(Z, X, Y); set { Z = value.X; X = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZXZ => new V3i(Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZYO => new V3i(Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZYI => new V3i(Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZYN => new V3i(Z, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i ZYX { readonly get => new V3i(Z, Y, X); set { Z = value.X; Y = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZYY => new V3i(Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZYZ => new V3i(Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZZO => new V3i(Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZZI => new V3i(Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZZN => new V3i(Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZZX => new V3i(Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZZY => new V3i(Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZZZ => new V3i(Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOOX => new V4i(0, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOOY => new V4i(0, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOOZ => new V4i(0, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOIX => new V4i(0, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOIY => new V4i(0, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOIZ => new V4i(0, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OONX => new V4i(0, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OONY => new V4i(0, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OONZ => new V4i(0, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXO => new V4i(0, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXI => new V4i(0, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXN => new V4i(0, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXX => new V4i(0, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXY => new V4i(0, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXZ => new V4i(0, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYO => new V4i(0, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYI => new V4i(0, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYN => new V4i(0, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYX => new V4i(0, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYY => new V4i(0, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYZ => new V4i(0, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOZO => new V4i(0, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOZI => new V4i(0, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOZN => new V4i(0, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOZX => new V4i(0, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOZY => new V4i(0, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOZZ => new V4i(0, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIOX => new V4i(0, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIOY => new V4i(0, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIOZ => new V4i(0, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIIX => new V4i(0, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIIY => new V4i(0, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIIZ => new V4i(0, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPNX => new V4i(0, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPNY => new V4i(0, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPNZ => new V4i(0, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIXO => new V4i(0, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIXI => new V4i(0, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPXN => new V4i(0, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIXX => new V4i(0, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIXY => new V4i(0, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIXZ => new V4i(0, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIYO => new V4i(0, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIYI => new V4i(0, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPYN => new V4i(0, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIYX => new V4i(0, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIYY => new V4i(0, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIYZ => new V4i(0, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIZO => new V4i(0, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIZI => new V4i(0, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPZN => new V4i(0, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIZX => new V4i(0, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIZY => new V4i(0, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIZZ => new V4i(0, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONOX => new V4i(0, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONOY => new V4i(0, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONOZ => new V4i(0, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONPX => new V4i(0, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONPY => new V4i(0, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONPZ => new V4i(0, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONNX => new V4i(0, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONNY => new V4i(0, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONNZ => new V4i(0, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXO => new V4i(0, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXP => new V4i(0, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXN => new V4i(0, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXX => new V4i(0, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXY => new V4i(0, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXZ => new V4i(0, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYO => new V4i(0, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYP => new V4i(0, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYN => new V4i(0, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYX => new V4i(0, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYY => new V4i(0, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYZ => new V4i(0, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONZO => new V4i(0, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONZP => new V4i(0, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONZN => new V4i(0, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONZX => new V4i(0, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONZY => new V4i(0, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONZZ => new V4i(0, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXOO => new V4i(0, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXOI => new V4i(0, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXON => new V4i(0, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXOX => new V4i(0, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXOY => new V4i(0, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXOZ => new V4i(0, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXIO => new V4i(0, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXII => new V4i(0, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXPN => new V4i(0, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXIX => new V4i(0, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXIY => new V4i(0, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXIZ => new V4i(0, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNO => new V4i(0, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNP => new V4i(0, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNN => new V4i(0, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNX => new V4i(0, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNY => new V4i(0, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNZ => new V4i(0, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXO => new V4i(0, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXI => new V4i(0, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXN => new V4i(0, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXX => new V4i(0, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXY => new V4i(0, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXZ => new V4i(0, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYO => new V4i(0, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYI => new V4i(0, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYN => new V4i(0, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYX => new V4i(0, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYY => new V4i(0, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYZ => new V4i(0, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXZO => new V4i(0, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXZI => new V4i(0, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXZN => new V4i(0, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXZX => new V4i(0, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXZY => new V4i(0, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXZZ => new V4i(0, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYOO => new V4i(0, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYOI => new V4i(0, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYON => new V4i(0, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYOX => new V4i(0, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYOY => new V4i(0, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYOZ => new V4i(0, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYIO => new V4i(0, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYII => new V4i(0, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYPN => new V4i(0, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYIX => new V4i(0, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYIY => new V4i(0, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYIZ => new V4i(0, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNO => new V4i(0, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNP => new V4i(0, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNN => new V4i(0, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNX => new V4i(0, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNY => new V4i(0, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNZ => new V4i(0, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXO => new V4i(0, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXI => new V4i(0, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXN => new V4i(0, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXX => new V4i(0, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXY => new V4i(0, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXZ => new V4i(0, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYO => new V4i(0, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYI => new V4i(0, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYN => new V4i(0, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYX => new V4i(0, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYY => new V4i(0, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYZ => new V4i(0, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYZO => new V4i(0, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYZI => new V4i(0, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYZN => new V4i(0, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYZX => new V4i(0, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYZY => new V4i(0, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYZZ => new V4i(0, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZOO => new V4i(0, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZOI => new V4i(0, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZON => new V4i(0, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZOX => new V4i(0, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZOY => new V4i(0, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZOZ => new V4i(0, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZIO => new V4i(0, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZII => new V4i(0, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZPN => new V4i(0, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZIX => new V4i(0, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZIY => new V4i(0, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZIZ => new V4i(0, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZNO => new V4i(0, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZNP => new V4i(0, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZNN => new V4i(0, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZNX => new V4i(0, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZNY => new V4i(0, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZNZ => new V4i(0, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZXO => new V4i(0, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZXI => new V4i(0, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZXN => new V4i(0, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZXX => new V4i(0, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZXY => new V4i(0, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZXZ => new V4i(0, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZYO => new V4i(0, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZYI => new V4i(0, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZYN => new V4i(0, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZYX => new V4i(0, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZYY => new V4i(0, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZYZ => new V4i(0, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZZO => new V4i(0, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZZI => new V4i(0, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZZN => new V4i(0, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZZX => new V4i(0, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZZY => new V4i(0, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZZZ => new V4i(0, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOOX => new V4i(1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOOY => new V4i(1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOOZ => new V4i(1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOIX => new V4i(1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOIY => new V4i(1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOIZ => new V4i(1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PONX => new V4i(1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PONY => new V4i(1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PONZ => new V4i(1, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOXO => new V4i(1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOXI => new V4i(1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i POXN => new V4i(1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOXX => new V4i(1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOXY => new V4i(1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOXZ => new V4i(1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOYO => new V4i(1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOYI => new V4i(1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i POYN => new V4i(1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOYX => new V4i(1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOYY => new V4i(1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOYZ => new V4i(1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOZO => new V4i(1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOZI => new V4i(1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i POZN => new V4i(1, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOZX => new V4i(1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOZY => new V4i(1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOZZ => new V4i(1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIOX => new V4i(1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIOY => new V4i(1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIOZ => new V4i(1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIIX => new V4i(1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIIY => new V4i(1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIIZ => new V4i(1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPNX => new V4i(1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPNY => new V4i(1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPNZ => new V4i(1, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIXO => new V4i(1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIXI => new V4i(1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPXN => new V4i(1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIXX => new V4i(1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIXY => new V4i(1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIXZ => new V4i(1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIYO => new V4i(1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIYI => new V4i(1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPYN => new V4i(1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIYX => new V4i(1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIYY => new V4i(1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIYZ => new V4i(1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIZO => new V4i(1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIZI => new V4i(1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPZN => new V4i(1, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIZX => new V4i(1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIZY => new V4i(1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIZZ => new V4i(1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNOX => new V4i(1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNOY => new V4i(1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNOZ => new V4i(1, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNPX => new V4i(1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNPY => new V4i(1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNPZ => new V4i(1, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNNX => new V4i(1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNNY => new V4i(1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNNZ => new V4i(1, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXO => new V4i(1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXP => new V4i(1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXN => new V4i(1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXX => new V4i(1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXY => new V4i(1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXZ => new V4i(1, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYO => new V4i(1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYP => new V4i(1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYN => new V4i(1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYX => new V4i(1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYY => new V4i(1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYZ => new V4i(1, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNZO => new V4i(1, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNZP => new V4i(1, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNZN => new V4i(1, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNZX => new V4i(1, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNZY => new V4i(1, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNZZ => new V4i(1, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXOO => new V4i(1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXOI => new V4i(1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXON => new V4i(1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXOX => new V4i(1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXOY => new V4i(1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXOZ => new V4i(1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXIO => new V4i(1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXII => new V4i(1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXPN => new V4i(1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXIX => new V4i(1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXIY => new V4i(1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXIZ => new V4i(1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNO => new V4i(1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNP => new V4i(1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNN => new V4i(1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNX => new V4i(1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNY => new V4i(1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNZ => new V4i(1, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXXO => new V4i(1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXXI => new V4i(1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXXN => new V4i(1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXXX => new V4i(1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXXY => new V4i(1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXXZ => new V4i(1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXYO => new V4i(1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXYI => new V4i(1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXYN => new V4i(1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXYX => new V4i(1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXYY => new V4i(1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXYZ => new V4i(1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXZO => new V4i(1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXZI => new V4i(1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXZN => new V4i(1, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXZX => new V4i(1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXZY => new V4i(1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXZZ => new V4i(1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYOO => new V4i(1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYOI => new V4i(1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYON => new V4i(1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYOX => new V4i(1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYOY => new V4i(1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYOZ => new V4i(1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYIO => new V4i(1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYII => new V4i(1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYPN => new V4i(1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYIX => new V4i(1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYIY => new V4i(1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYIZ => new V4i(1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNO => new V4i(1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNP => new V4i(1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNN => new V4i(1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNX => new V4i(1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNY => new V4i(1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNZ => new V4i(1, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYXO => new V4i(1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYXI => new V4i(1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYXN => new V4i(1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYXX => new V4i(1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYXY => new V4i(1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYXZ => new V4i(1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYYO => new V4i(1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYYI => new V4i(1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYYN => new V4i(1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYYX => new V4i(1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYYY => new V4i(1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYYZ => new V4i(1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYZO => new V4i(1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYZI => new V4i(1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYZN => new V4i(1, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYZX => new V4i(1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYZY => new V4i(1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYZZ => new V4i(1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZOO => new V4i(1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZOI => new V4i(1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZON => new V4i(1, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZOX => new V4i(1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZOY => new V4i(1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZOZ => new V4i(1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZIO => new V4i(1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZII => new V4i(1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZPN => new V4i(1, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZIX => new V4i(1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZIY => new V4i(1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZIZ => new V4i(1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZNO => new V4i(1, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZNP => new V4i(1, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZNN => new V4i(1, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZNX => new V4i(1, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZNY => new V4i(1, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZNZ => new V4i(1, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZXO => new V4i(1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZXI => new V4i(1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZXN => new V4i(1, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZXX => new V4i(1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZXY => new V4i(1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZXZ => new V4i(1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZYO => new V4i(1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZYI => new V4i(1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZYN => new V4i(1, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZYX => new V4i(1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZYY => new V4i(1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZYZ => new V4i(1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZZO => new V4i(1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZZI => new V4i(1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZZN => new V4i(1, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZZX => new V4i(1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZZY => new V4i(1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZZZ => new V4i(1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOOX => new V4i(-1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOOY => new V4i(-1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOOZ => new V4i(-1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOPX => new V4i(-1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOPY => new V4i(-1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOPZ => new V4i(-1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NONX => new V4i(-1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NONY => new V4i(-1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NONZ => new V4i(-1, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXO => new V4i(-1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXP => new V4i(-1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXN => new V4i(-1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXX => new V4i(-1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXY => new V4i(-1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXZ => new V4i(-1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYO => new V4i(-1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYP => new V4i(-1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYN => new V4i(-1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYX => new V4i(-1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYY => new V4i(-1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYZ => new V4i(-1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOZO => new V4i(-1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOZP => new V4i(-1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOZN => new V4i(-1, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOZX => new V4i(-1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOZY => new V4i(-1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOZZ => new V4i(-1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPOX => new V4i(-1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPOY => new V4i(-1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPOZ => new V4i(-1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPPX => new V4i(-1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPPY => new V4i(-1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPPZ => new V4i(-1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPNX => new V4i(-1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPNY => new V4i(-1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPNZ => new V4i(-1, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXO => new V4i(-1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXP => new V4i(-1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXN => new V4i(-1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXX => new V4i(-1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXY => new V4i(-1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXZ => new V4i(-1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYO => new V4i(-1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYP => new V4i(-1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYN => new V4i(-1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYX => new V4i(-1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYY => new V4i(-1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYZ => new V4i(-1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPZO => new V4i(-1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPZP => new V4i(-1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPZN => new V4i(-1, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPZX => new V4i(-1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPZY => new V4i(-1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPZZ => new V4i(-1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNOX => new V4i(-1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNOY => new V4i(-1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNOZ => new V4i(-1, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNPX => new V4i(-1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNPY => new V4i(-1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNPZ => new V4i(-1, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNNX => new V4i(-1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNNY => new V4i(-1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNNZ => new V4i(-1, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXO => new V4i(-1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXP => new V4i(-1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXN => new V4i(-1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXX => new V4i(-1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXY => new V4i(-1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXZ => new V4i(-1, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYO => new V4i(-1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYP => new V4i(-1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYN => new V4i(-1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYX => new V4i(-1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYY => new V4i(-1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYZ => new V4i(-1, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNZO => new V4i(-1, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNZP => new V4i(-1, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNZN => new V4i(-1, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNZX => new V4i(-1, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNZY => new V4i(-1, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNZZ => new V4i(-1, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXOO => new V4i(-1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXOP => new V4i(-1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXON => new V4i(-1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXOX => new V4i(-1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXOY => new V4i(-1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXOZ => new V4i(-1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPO => new V4i(-1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPP => new V4i(-1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPN => new V4i(-1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPX => new V4i(-1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPY => new V4i(-1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPZ => new V4i(-1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNO => new V4i(-1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNP => new V4i(-1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNN => new V4i(-1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNX => new V4i(-1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNY => new V4i(-1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNZ => new V4i(-1, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXO => new V4i(-1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXP => new V4i(-1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXN => new V4i(-1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXX => new V4i(-1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXY => new V4i(-1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXZ => new V4i(-1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYO => new V4i(-1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYP => new V4i(-1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYN => new V4i(-1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYX => new V4i(-1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYY => new V4i(-1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYZ => new V4i(-1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXZO => new V4i(-1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXZP => new V4i(-1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXZN => new V4i(-1, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXZX => new V4i(-1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXZY => new V4i(-1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXZZ => new V4i(-1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYOO => new V4i(-1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYOP => new V4i(-1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYON => new V4i(-1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYOX => new V4i(-1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYOY => new V4i(-1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYOZ => new V4i(-1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPO => new V4i(-1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPP => new V4i(-1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPN => new V4i(-1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPX => new V4i(-1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPY => new V4i(-1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPZ => new V4i(-1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNO => new V4i(-1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNP => new V4i(-1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNN => new V4i(-1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNX => new V4i(-1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNY => new V4i(-1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNZ => new V4i(-1, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXO => new V4i(-1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXP => new V4i(-1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXN => new V4i(-1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXX => new V4i(-1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXY => new V4i(-1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXZ => new V4i(-1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYO => new V4i(-1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYP => new V4i(-1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYN => new V4i(-1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYX => new V4i(-1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYY => new V4i(-1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYZ => new V4i(-1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYZO => new V4i(-1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYZP => new V4i(-1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYZN => new V4i(-1, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYZX => new V4i(-1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYZY => new V4i(-1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYZZ => new V4i(-1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZOO => new V4i(-1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZOP => new V4i(-1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZON => new V4i(-1, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZOX => new V4i(-1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZOY => new V4i(-1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZOZ => new V4i(-1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZPO => new V4i(-1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZPP => new V4i(-1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZPN => new V4i(-1, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZPX => new V4i(-1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZPY => new V4i(-1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZPZ => new V4i(-1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZNO => new V4i(-1, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZNP => new V4i(-1, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZNN => new V4i(-1, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZNX => new V4i(-1, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZNY => new V4i(-1, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZNZ => new V4i(-1, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZXO => new V4i(-1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZXP => new V4i(-1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZXN => new V4i(-1, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZXX => new V4i(-1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZXY => new V4i(-1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZXZ => new V4i(-1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZYO => new V4i(-1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZYP => new V4i(-1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZYN => new V4i(-1, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZYX => new V4i(-1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZYY => new V4i(-1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZYZ => new V4i(-1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZZO => new V4i(-1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZZP => new V4i(-1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZZN => new V4i(-1, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZZX => new V4i(-1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZZY => new V4i(-1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZZZ => new V4i(-1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOOO => new V4i(X, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOOI => new V4i(X, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOON => new V4i(X, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOOX => new V4i(X, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOOY => new V4i(X, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOOZ => new V4i(X, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOIO => new V4i(X, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOII => new V4i(X, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOPN => new V4i(X, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOIX => new V4i(X, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOIY => new V4i(X, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOIZ => new V4i(X, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONO => new V4i(X, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONP => new V4i(X, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONN => new V4i(X, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONX => new V4i(X, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONY => new V4i(X, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONZ => new V4i(X, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXO => new V4i(X, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXI => new V4i(X, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXN => new V4i(X, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXX => new V4i(X, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXY => new V4i(X, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXZ => new V4i(X, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYO => new V4i(X, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYI => new V4i(X, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYN => new V4i(X, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYX => new V4i(X, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYY => new V4i(X, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYZ => new V4i(X, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOZO => new V4i(X, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOZI => new V4i(X, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOZN => new V4i(X, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOZX => new V4i(X, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOZY => new V4i(X, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOZZ => new V4i(X, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIOO => new V4i(X, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIOI => new V4i(X, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPON => new V4i(X, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIOX => new V4i(X, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIOY => new V4i(X, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIOZ => new V4i(X, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIIO => new V4i(X, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIII => new V4i(X, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPPN => new V4i(X, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIIX => new V4i(X, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIIY => new V4i(X, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIIZ => new V4i(X, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNO => new V4i(X, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNP => new V4i(X, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNN => new V4i(X, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNX => new V4i(X, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNY => new V4i(X, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNZ => new V4i(X, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIXO => new V4i(X, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIXI => new V4i(X, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPXN => new V4i(X, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIXX => new V4i(X, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIXY => new V4i(X, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIXZ => new V4i(X, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIYO => new V4i(X, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIYI => new V4i(X, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPYN => new V4i(X, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIYX => new V4i(X, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIYY => new V4i(X, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIYZ => new V4i(X, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIZO => new V4i(X, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIZI => new V4i(X, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPZN => new V4i(X, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIZX => new V4i(X, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIZY => new V4i(X, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIZZ => new V4i(X, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNOO => new V4i(X, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNOP => new V4i(X, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNON => new V4i(X, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNOX => new V4i(X, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNOY => new V4i(X, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNOZ => new V4i(X, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPO => new V4i(X, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPP => new V4i(X, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPN => new V4i(X, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPX => new V4i(X, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPY => new V4i(X, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPZ => new V4i(X, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNO => new V4i(X, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNP => new V4i(X, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNN => new V4i(X, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNX => new V4i(X, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNY => new V4i(X, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNZ => new V4i(X, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXO => new V4i(X, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXP => new V4i(X, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXN => new V4i(X, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXX => new V4i(X, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXY => new V4i(X, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXZ => new V4i(X, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYO => new V4i(X, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYP => new V4i(X, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYN => new V4i(X, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYX => new V4i(X, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYY => new V4i(X, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYZ => new V4i(X, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNZO => new V4i(X, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNZP => new V4i(X, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNZN => new V4i(X, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNZX => new V4i(X, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNZY => new V4i(X, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNZZ => new V4i(X, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXOO => new V4i(X, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXOI => new V4i(X, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXON => new V4i(X, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXOX => new V4i(X, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXOY => new V4i(X, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXOZ => new V4i(X, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXIO => new V4i(X, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXII => new V4i(X, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXPN => new V4i(X, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXIX => new V4i(X, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXIY => new V4i(X, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXIZ => new V4i(X, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNO => new V4i(X, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNP => new V4i(X, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNN => new V4i(X, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNX => new V4i(X, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNY => new V4i(X, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNZ => new V4i(X, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXO => new V4i(X, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXI => new V4i(X, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXN => new V4i(X, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXX => new V4i(X, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXY => new V4i(X, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXZ => new V4i(X, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYO => new V4i(X, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYI => new V4i(X, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYN => new V4i(X, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYX => new V4i(X, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYY => new V4i(X, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYZ => new V4i(X, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXZO => new V4i(X, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXZI => new V4i(X, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXZN => new V4i(X, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXZX => new V4i(X, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXZY => new V4i(X, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXZZ => new V4i(X, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYOO => new V4i(X, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYOI => new V4i(X, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYON => new V4i(X, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYOX => new V4i(X, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYOY => new V4i(X, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYOZ => new V4i(X, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYIO => new V4i(X, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYII => new V4i(X, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYPN => new V4i(X, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYIX => new V4i(X, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYIY => new V4i(X, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYIZ => new V4i(X, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNO => new V4i(X, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNP => new V4i(X, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNN => new V4i(X, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNX => new V4i(X, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNY => new V4i(X, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNZ => new V4i(X, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXO => new V4i(X, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXI => new V4i(X, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXN => new V4i(X, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXX => new V4i(X, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXY => new V4i(X, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXZ => new V4i(X, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYO => new V4i(X, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYI => new V4i(X, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYN => new V4i(X, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYX => new V4i(X, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYY => new V4i(X, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYZ => new V4i(X, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYZO => new V4i(X, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYZI => new V4i(X, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYZN => new V4i(X, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYZX => new V4i(X, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYZY => new V4i(X, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYZZ => new V4i(X, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZOO => new V4i(X, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZOI => new V4i(X, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZON => new V4i(X, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZOX => new V4i(X, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZOY => new V4i(X, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZOZ => new V4i(X, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZIO => new V4i(X, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZII => new V4i(X, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZPN => new V4i(X, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZIX => new V4i(X, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZIY => new V4i(X, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZIZ => new V4i(X, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZNO => new V4i(X, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZNP => new V4i(X, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZNN => new V4i(X, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZNX => new V4i(X, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZNY => new V4i(X, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZNZ => new V4i(X, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZXO => new V4i(X, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZXI => new V4i(X, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZXN => new V4i(X, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZXX => new V4i(X, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZXY => new V4i(X, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZXZ => new V4i(X, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZYO => new V4i(X, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZYI => new V4i(X, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZYN => new V4i(X, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZYX => new V4i(X, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZYY => new V4i(X, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZYZ => new V4i(X, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZZO => new V4i(X, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZZI => new V4i(X, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZZN => new V4i(X, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZZX => new V4i(X, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZZY => new V4i(X, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZZZ => new V4i(X, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOOO => new V4i(Y, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOOI => new V4i(Y, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOON => new V4i(Y, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOOX => new V4i(Y, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOOY => new V4i(Y, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOOZ => new V4i(Y, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOIO => new V4i(Y, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOII => new V4i(Y, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOPN => new V4i(Y, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOIX => new V4i(Y, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOIY => new V4i(Y, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOIZ => new V4i(Y, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONO => new V4i(Y, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONP => new V4i(Y, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONN => new V4i(Y, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONX => new V4i(Y, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONY => new V4i(Y, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONZ => new V4i(Y, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXO => new V4i(Y, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXI => new V4i(Y, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXN => new V4i(Y, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXX => new V4i(Y, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXY => new V4i(Y, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXZ => new V4i(Y, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYO => new V4i(Y, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYI => new V4i(Y, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYN => new V4i(Y, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYX => new V4i(Y, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYY => new V4i(Y, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYZ => new V4i(Y, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOZO => new V4i(Y, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOZI => new V4i(Y, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOZN => new V4i(Y, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOZX => new V4i(Y, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOZY => new V4i(Y, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOZZ => new V4i(Y, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIOO => new V4i(Y, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIOI => new V4i(Y, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPON => new V4i(Y, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIOX => new V4i(Y, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIOY => new V4i(Y, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIOZ => new V4i(Y, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIIO => new V4i(Y, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIII => new V4i(Y, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPPN => new V4i(Y, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIIX => new V4i(Y, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIIY => new V4i(Y, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIIZ => new V4i(Y, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNO => new V4i(Y, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNP => new V4i(Y, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNN => new V4i(Y, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNX => new V4i(Y, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNY => new V4i(Y, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNZ => new V4i(Y, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIXO => new V4i(Y, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIXI => new V4i(Y, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPXN => new V4i(Y, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIXX => new V4i(Y, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIXY => new V4i(Y, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIXZ => new V4i(Y, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIYO => new V4i(Y, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIYI => new V4i(Y, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPYN => new V4i(Y, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIYX => new V4i(Y, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIYY => new V4i(Y, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIYZ => new V4i(Y, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIZO => new V4i(Y, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIZI => new V4i(Y, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPZN => new V4i(Y, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIZX => new V4i(Y, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIZY => new V4i(Y, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIZZ => new V4i(Y, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNOO => new V4i(Y, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNOP => new V4i(Y, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNON => new V4i(Y, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNOX => new V4i(Y, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNOY => new V4i(Y, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNOZ => new V4i(Y, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPO => new V4i(Y, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPP => new V4i(Y, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPN => new V4i(Y, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPX => new V4i(Y, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPY => new V4i(Y, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPZ => new V4i(Y, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNO => new V4i(Y, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNP => new V4i(Y, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNN => new V4i(Y, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNX => new V4i(Y, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNY => new V4i(Y, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNZ => new V4i(Y, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXO => new V4i(Y, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXP => new V4i(Y, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXN => new V4i(Y, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXX => new V4i(Y, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXY => new V4i(Y, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXZ => new V4i(Y, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYO => new V4i(Y, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYP => new V4i(Y, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYN => new V4i(Y, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYX => new V4i(Y, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYY => new V4i(Y, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYZ => new V4i(Y, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNZO => new V4i(Y, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNZP => new V4i(Y, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNZN => new V4i(Y, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNZX => new V4i(Y, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNZY => new V4i(Y, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNZZ => new V4i(Y, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXOO => new V4i(Y, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXOI => new V4i(Y, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXON => new V4i(Y, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXOX => new V4i(Y, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXOY => new V4i(Y, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXOZ => new V4i(Y, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXIO => new V4i(Y, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXII => new V4i(Y, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXPN => new V4i(Y, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXIX => new V4i(Y, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXIY => new V4i(Y, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXIZ => new V4i(Y, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNO => new V4i(Y, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNP => new V4i(Y, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNN => new V4i(Y, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNX => new V4i(Y, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNY => new V4i(Y, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNZ => new V4i(Y, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXO => new V4i(Y, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXI => new V4i(Y, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXN => new V4i(Y, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXX => new V4i(Y, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXY => new V4i(Y, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXZ => new V4i(Y, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYO => new V4i(Y, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYI => new V4i(Y, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYN => new V4i(Y, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYX => new V4i(Y, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYY => new V4i(Y, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYZ => new V4i(Y, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXZO => new V4i(Y, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXZI => new V4i(Y, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXZN => new V4i(Y, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXZX => new V4i(Y, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXZY => new V4i(Y, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXZZ => new V4i(Y, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYOO => new V4i(Y, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYOI => new V4i(Y, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYON => new V4i(Y, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYOX => new V4i(Y, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYOY => new V4i(Y, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYOZ => new V4i(Y, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYIO => new V4i(Y, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYII => new V4i(Y, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYPN => new V4i(Y, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYIX => new V4i(Y, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYIY => new V4i(Y, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYIZ => new V4i(Y, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNO => new V4i(Y, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNP => new V4i(Y, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNN => new V4i(Y, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNX => new V4i(Y, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNY => new V4i(Y, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNZ => new V4i(Y, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXO => new V4i(Y, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXI => new V4i(Y, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXN => new V4i(Y, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXX => new V4i(Y, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXY => new V4i(Y, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXZ => new V4i(Y, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYO => new V4i(Y, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYI => new V4i(Y, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYN => new V4i(Y, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYX => new V4i(Y, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYY => new V4i(Y, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYZ => new V4i(Y, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYZO => new V4i(Y, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYZI => new V4i(Y, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYZN => new V4i(Y, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYZX => new V4i(Y, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYZY => new V4i(Y, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYZZ => new V4i(Y, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZOO => new V4i(Y, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZOI => new V4i(Y, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZON => new V4i(Y, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZOX => new V4i(Y, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZOY => new V4i(Y, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZOZ => new V4i(Y, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZIO => new V4i(Y, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZII => new V4i(Y, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZPN => new V4i(Y, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZIX => new V4i(Y, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZIY => new V4i(Y, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZIZ => new V4i(Y, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZNO => new V4i(Y, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZNP => new V4i(Y, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZNN => new V4i(Y, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZNX => new V4i(Y, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZNY => new V4i(Y, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZNZ => new V4i(Y, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZXO => new V4i(Y, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZXI => new V4i(Y, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZXN => new V4i(Y, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZXX => new V4i(Y, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZXY => new V4i(Y, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZXZ => new V4i(Y, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZYO => new V4i(Y, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZYI => new V4i(Y, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZYN => new V4i(Y, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZYX => new V4i(Y, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZYY => new V4i(Y, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZYZ => new V4i(Y, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZZO => new V4i(Y, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZZI => new V4i(Y, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZZN => new V4i(Y, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZZX => new V4i(Y, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZZY => new V4i(Y, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZZZ => new V4i(Y, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOOO => new V4i(Z, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOOI => new V4i(Z, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOON => new V4i(Z, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOOX => new V4i(Z, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOOY => new V4i(Z, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOOZ => new V4i(Z, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOIO => new V4i(Z, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOII => new V4i(Z, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOPN => new V4i(Z, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOIX => new V4i(Z, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOIY => new V4i(Z, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOIZ => new V4i(Z, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZONO => new V4i(Z, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZONP => new V4i(Z, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZONN => new V4i(Z, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZONX => new V4i(Z, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZONY => new V4i(Z, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZONZ => new V4i(Z, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOXO => new V4i(Z, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOXI => new V4i(Z, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOXN => new V4i(Z, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOXX => new V4i(Z, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOXY => new V4i(Z, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOXZ => new V4i(Z, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOYO => new V4i(Z, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOYI => new V4i(Z, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOYN => new V4i(Z, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOYX => new V4i(Z, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOYY => new V4i(Z, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOYZ => new V4i(Z, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOZO => new V4i(Z, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOZI => new V4i(Z, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOZN => new V4i(Z, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOZX => new V4i(Z, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOZY => new V4i(Z, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOZZ => new V4i(Z, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIOO => new V4i(Z, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIOI => new V4i(Z, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPON => new V4i(Z, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIOX => new V4i(Z, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIOY => new V4i(Z, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIOZ => new V4i(Z, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIIO => new V4i(Z, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIII => new V4i(Z, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPPN => new V4i(Z, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIIX => new V4i(Z, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIIY => new V4i(Z, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIIZ => new V4i(Z, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPNO => new V4i(Z, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPNP => new V4i(Z, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPNN => new V4i(Z, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPNX => new V4i(Z, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPNY => new V4i(Z, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPNZ => new V4i(Z, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIXO => new V4i(Z, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIXI => new V4i(Z, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPXN => new V4i(Z, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIXX => new V4i(Z, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIXY => new V4i(Z, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIXZ => new V4i(Z, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIYO => new V4i(Z, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIYI => new V4i(Z, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPYN => new V4i(Z, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIYX => new V4i(Z, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIYY => new V4i(Z, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIYZ => new V4i(Z, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIZO => new V4i(Z, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIZI => new V4i(Z, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPZN => new V4i(Z, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIZX => new V4i(Z, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIZY => new V4i(Z, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIZZ => new V4i(Z, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNOO => new V4i(Z, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNOP => new V4i(Z, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNON => new V4i(Z, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNOX => new V4i(Z, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNOY => new V4i(Z, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNOZ => new V4i(Z, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNPO => new V4i(Z, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNPP => new V4i(Z, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNPN => new V4i(Z, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNPX => new V4i(Z, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNPY => new V4i(Z, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNPZ => new V4i(Z, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNNO => new V4i(Z, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNNP => new V4i(Z, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNNN => new V4i(Z, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNNX => new V4i(Z, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNNY => new V4i(Z, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNNZ => new V4i(Z, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNXO => new V4i(Z, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNXP => new V4i(Z, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNXN => new V4i(Z, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNXX => new V4i(Z, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNXY => new V4i(Z, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNXZ => new V4i(Z, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNYO => new V4i(Z, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNYP => new V4i(Z, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNYN => new V4i(Z, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNYX => new V4i(Z, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNYY => new V4i(Z, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNYZ => new V4i(Z, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNZO => new V4i(Z, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNZP => new V4i(Z, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNZN => new V4i(Z, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNZX => new V4i(Z, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNZY => new V4i(Z, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNZZ => new V4i(Z, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXOO => new V4i(Z, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXOI => new V4i(Z, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXON => new V4i(Z, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXOX => new V4i(Z, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXOY => new V4i(Z, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXOZ => new V4i(Z, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXIO => new V4i(Z, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXII => new V4i(Z, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXPN => new V4i(Z, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXIX => new V4i(Z, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXIY => new V4i(Z, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXIZ => new V4i(Z, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXNO => new V4i(Z, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXNP => new V4i(Z, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXNN => new V4i(Z, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXNX => new V4i(Z, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXNY => new V4i(Z, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXNZ => new V4i(Z, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXXO => new V4i(Z, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXXI => new V4i(Z, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXXN => new V4i(Z, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXXX => new V4i(Z, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXXY => new V4i(Z, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXXZ => new V4i(Z, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXYO => new V4i(Z, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXYI => new V4i(Z, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXYN => new V4i(Z, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXYX => new V4i(Z, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXYY => new V4i(Z, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXYZ => new V4i(Z, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXZO => new V4i(Z, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXZI => new V4i(Z, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXZN => new V4i(Z, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXZX => new V4i(Z, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXZY => new V4i(Z, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXZZ => new V4i(Z, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYOO => new V4i(Z, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYOI => new V4i(Z, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYON => new V4i(Z, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYOX => new V4i(Z, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYOY => new V4i(Z, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYOZ => new V4i(Z, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYIO => new V4i(Z, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYII => new V4i(Z, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYPN => new V4i(Z, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYIX => new V4i(Z, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYIY => new V4i(Z, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYIZ => new V4i(Z, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYNO => new V4i(Z, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYNP => new V4i(Z, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYNN => new V4i(Z, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYNX => new V4i(Z, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYNY => new V4i(Z, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYNZ => new V4i(Z, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYXO => new V4i(Z, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYXI => new V4i(Z, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYXN => new V4i(Z, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYXX => new V4i(Z, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYXY => new V4i(Z, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYXZ => new V4i(Z, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYYO => new V4i(Z, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYYI => new V4i(Z, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYYN => new V4i(Z, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYYX => new V4i(Z, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYYY => new V4i(Z, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYYZ => new V4i(Z, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYZO => new V4i(Z, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYZI => new V4i(Z, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYZN => new V4i(Z, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYZX => new V4i(Z, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYZY => new V4i(Z, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYZZ => new V4i(Z, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZOO => new V4i(Z, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZOI => new V4i(Z, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZON => new V4i(Z, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZOX => new V4i(Z, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZOY => new V4i(Z, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZOZ => new V4i(Z, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZIO => new V4i(Z, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZII => new V4i(Z, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZPN => new V4i(Z, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZIX => new V4i(Z, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZIY => new V4i(Z, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZIZ => new V4i(Z, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZNO => new V4i(Z, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZNP => new V4i(Z, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZNN => new V4i(Z, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZNX => new V4i(Z, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZNY => new V4i(Z, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZNZ => new V4i(Z, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZXO => new V4i(Z, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZXI => new V4i(Z, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZXN => new V4i(Z, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZXX => new V4i(Z, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZXY => new V4i(Z, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZXZ => new V4i(Z, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZYO => new V4i(Z, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZYI => new V4i(Z, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZYN => new V4i(Z, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZYX => new V4i(Z, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZYY => new V4i(Z, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZYZ => new V4i(Z, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZZO => new V4i(Z, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZZI => new V4i(Z, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZZN => new V4i(Z, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZZX => new V4i(Z, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZZY => new V4i(Z, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZZZ => new V4i(Z, Z, Z, Z); #endregion #region IVector Members /// /// By using long indices, the IVector<double> interface is /// accessed. /// public double this[long i] { readonly get { return (double)this[(int)i]; } set { this[(int)i] = (int)value; } } #endregion #region ISize3i Members public readonly V3i Size3i { get { return this; } } #endregion #region IVector public readonly long Dim { get { return 3; } } public readonly object GetValue(long index) { return (object)this[(int)index]; } public void SetValue(object value, long index) { this[(int)index] = (int)value; } #endregion } public class V3iEqualityComparer : IEqualityComparer { public static V3iEqualityComparer Default => new V3iEqualityComparer(); #region IEqualityComparer Members public bool Equals(V3i v0, V3i v1) { return v0 == v1; } public int GetHashCode(V3i v) { return v.GetHashCode(); } #endregion } public static partial class Fun { #region Min and Max /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Min(this V3i a, V3i b) { return new V3i(Min(a.X, b.X), Min(a.Y, b.Y), Min(a.Z, b.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Min(this V3i a, int b) { return new V3i(Min(a.X, b), Min(a.Y, b), Min(a.Z, b)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Min(this int a, V3i b) { return new V3i(Min(a, b.X), Min(a, b.Y), Min(a, b.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Max(this V3i a, V3i b) { return new V3i(Max(a.X, b.X), Max(a.Y, b.Y), Max(a.Z, b.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Max(this V3i a, int b) { return new V3i(Max(a.X, b), Max(a.Y, b), Max(a.Z, b)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Max(this int a, V3i b) { return new V3i(Max(a, b.X), Max(a, b.Y), Max(a, b.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Min(this V3i a, V3i b, V3i c) { return new V3i(Min(a.X, b.X, c.X), Min(a.Y, b.Y, c.Y), Min(a.Z, b.Z, c.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Max(this V3i a, V3i b, V3i c) { return new V3i(Max(a.X, b.X, c.X), Max(a.Y, b.Y, c.Y), Max(a.Z, b.Z, c.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Min(this V3i a, V3i b, V3i c, V3i d) { return new V3i(Min(a.X, b.X, c.X, d.X), Min(a.Y, b.Y, c.Y, d.Y), Min(a.Z, b.Z, c.Z, d.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Max(this V3i a, V3i b, V3i c, V3i d) { return new V3i(Max(a.X, b.X, c.X, d.X), Max(a.Y, b.Y, c.Y, d.Y), Max(a.Z, b.Z, c.Z, d.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Min(this V3i x, params V3i[] values) { return new V3i(Min(x.X, values.Map(a => a.X)), Min(x.Y, values.Map(a => a.Y)), Min(x.Z, values.Map(a => a.Z))); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Max(this V3i x, params V3i[] values) { return new V3i(Max(x.X, values.Map(a => a.X)), Max(x.Y, values.Map(a => a.Y)), Max(x.Z, values.Map(a => a.Z))); } #endregion #region Abs /// /// Applies Fun.Abs to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Abs(this V3i x) { return new V3i(Abs(x.X), Abs(x.Y), Abs(x.Z)); } #endregion #region Clamping /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Clamp(this V3i x, V3i a, V3i b) { return new V3i(Clamp(x.X, a.X, b.X), Clamp(x.Y, a.Y, b.Y), Clamp(x.Z, a.Z, b.Z)); } /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Clamp(this V3i x, int a, int b) { return new V3i(Clamp(x.X, a, b), Clamp(x.Y, a, b), Clamp(x.Z, a, b)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i ClampExcl(this V3i x, V3i a, V3i b) { return new V3i(ClampExcl(x.X, a.X, b.X), ClampExcl(x.Y, a.Y, b.Y), ClampExcl(x.Z, a.Z, b.Z)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i ClampExcl(this V3i x, int a, int b) { return new V3i(ClampExcl(x.X, a, b), ClampExcl(x.Y, a, b), ClampExcl(x.Z, a, b)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i ClampWrap(this V3i x, V3i a, V3i b) { return new V3i(ClampWrap(x.X, a.X, b.X), ClampWrap(x.Y, a.Y, b.Y), ClampWrap(x.Z, a.Z, b.Z)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i ClampWrap(this V3i x, int a, int b) { return new V3i(ClampWrap(x.X, a, b), ClampWrap(x.Y, a, b), ClampWrap(x.Z, a, b)); } /// /// Applies Fun.Saturate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Saturate(this V3i x) { return new V3i(Saturate(x.X), Saturate(x.Y), Saturate(x.Z)); } #endregion #region Sign /// /// Applies Fun.Sign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Sign(this V3i x) { return new V3i(Sign(x.X), Sign(x.Y), Sign(x.Z)); } /// /// Applies Fun.Signumi to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Signumi(this V3i x) { return new V3i(Signumi(x.X), Signumi(x.Y), Signumi(x.Z)); } /// /// Applies Fun.Signum to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Signum(this V3i x) { return new V3i(Signum(x.X), Signum(x.Y), Signum(x.Z)); } #endregion #region Multiply-Add /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i MultiplyAdd(V3i x, V3i y, V3i z) { return new V3i(MultiplyAdd(x.X, y.X, z.X), MultiplyAdd(x.Y, y.Y, z.Y), MultiplyAdd(x.Z, y.Z, z.Z)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i MultiplyAdd(V3i x, int y, V3i z) { return new V3i(MultiplyAdd(x.X, y, z.X), MultiplyAdd(x.Y, y, z.Y), MultiplyAdd(x.Z, y, z.Z)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i MultiplyAdd(int x, V3i y, V3i z) { return new V3i(MultiplyAdd(x, y.X, z.X), MultiplyAdd(x, y.Y, z.Y), MultiplyAdd(x, y.Z, z.Z)); } #endregion #region Roots /// /// Applies Fun.Sqrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Sqrt(this V3i x) { return new V3d(Sqrt(x.X), Sqrt(x.Y), Sqrt(x.Z)); } /// /// Applies Fun.Cbrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Cbrt(this V3i x) { return new V3d(Cbrt(x.X), Cbrt(x.Y), Cbrt(x.Z)); } #endregion #region Square /// /// Applies Fun.Square to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Square(this V3i x) { return new V3i(Square(x.X), Square(x.Y), Square(x.Z)); } #endregion #region Power /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Pown(this V3i x, V3i y) { return new V3i(Pown(x.X, y.X), Pown(x.Y, y.Y), Pown(x.Z, y.Z)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Pown(this V3i x, int y) { return new V3i(Pown(x.X, y), Pown(x.Y, y), Pown(x.Z, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Pown(this int x, V3i y) { return new V3i(Pown(x, y.X), Pown(x, y.Y), Pown(x, y.Z)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Pow(this V3i x, V3f y) { return new V3f(Pow(x.X, y.X), Pow(x.Y, y.Y), Pow(x.Z, y.Z)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Pow(this V3i x, float y) { return new V3f(Pow(x.X, y), Pow(x.Y, y), Pow(x.Z, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Pow(this int x, V3f y) { return new V3f(Pow(x, y.X), Pow(x, y.Y), Pow(x, y.Z)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Pow(this V3i x, V3d y) { return new V3d(Pow(x.X, y.X), Pow(x.Y, y.Y), Pow(x.Z, y.Z)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Pow(this V3i x, double y) { return new V3d(Pow(x.X, y), Pow(x.Y, y), Pow(x.Z, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Pow(this int x, V3d y) { return new V3d(Pow(x, y.X), Pow(x, y.Y), Pow(x, y.Z)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Power(this V3i x, V3f y) { return new V3f(Power(x.X, y.X), Power(x.Y, y.Y), Power(x.Z, y.Z)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Power(this V3i x, float y) { return new V3f(Power(x.X, y), Power(x.Y, y), Power(x.Z, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Power(this int x, V3f y) { return new V3f(Power(x, y.X), Power(x, y.Y), Power(x, y.Z)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Power(this V3i x, V3d y) { return new V3d(Power(x.X, y.X), Power(x.Y, y.Y), Power(x.Z, y.Z)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Power(this V3i x, double y) { return new V3d(Power(x.X, y), Power(x.Y, y), Power(x.Z, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Power(this int x, V3d y) { return new V3d(Power(x, y.X), Power(x, y.Y), Power(x, y.Z)); } #endregion #region Exp and Log /// /// Applies Fun.Exp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Exp(this V3i x) { return new V3d(Exp(x.X), Exp(x.Y), Exp(x.Z)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log(this V3i x) { return new V3d(Log(x.X), Log(x.Y), Log(x.Z)); } /// /// Applies Fun.Log2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log2(this V3i x) { return new V3d(Log2(x.X), Log2(x.Y), Log2(x.Z)); } /// /// Applies Fun.Log2Int to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Log2Int(this V3i x) { return new V3i(Log2Int(x.X), Log2Int(x.Y), Log2Int(x.Z)); } /// /// Applies Fun.Log10 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log10(this V3i x) { return new V3d(Log10(x.X), Log10(x.Y), Log10(x.Z)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log(this V3i x, double basis) { return new V3d(Log(x.X, basis), Log(x.Y, basis), Log(x.Z, basis)); } #endregion #region ModP /// /// Applies Fun.ModP to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i ModP(this V3i a, V3i b) { return new V3i(ModP(a.X, b.X), ModP(a.Y, b.Y), ModP(a.Z, b.Z)); } #endregion #region Power of Two /// /// Applies Fun.PowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l PowerOfTwo(this V3i x) { return new V3l(PowerOfTwo(x.X), PowerOfTwo(x.Y), PowerOfTwo(x.Z)); } /// /// Applies Fun.NextPowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i NextPowerOfTwo(this V3i x) { return new V3i(NextPowerOfTwo(x.X), NextPowerOfTwo(x.Y), NextPowerOfTwo(x.Z)); } /// /// Applies Fun.PrevPowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i PrevPowerOfTwo(this V3i x) { return new V3i(PrevPowerOfTwo(x.X), PrevPowerOfTwo(x.Y), PrevPowerOfTwo(x.Z)); } #endregion #region Step functions /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Step(this V3i x, V3i edge) { return new V3i(Step(x.X, edge.X), Step(x.Y, edge.Y), Step(x.Z, edge.Z)); } /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Step(this V3i x, int edge) { return new V3i(Step(x.X, edge), Step(x.Y, edge), Step(x.Z, edge)); } #endregion #region Interpolation /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Lerp(this float t, V3i a, V3i b) { return new V3i(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y), Lerp(t, a.Z, b.Z)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Lerp(this V3f t, V3i a, V3i b) { return new V3i(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y), Lerp(t.Z, a.Z, b.Z)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Lerp(this double t, V3i a, V3i b) { return new V3i(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y), Lerp(t, a.Z, b.Z)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Lerp(this V3d t, V3i a, V3i b) { return new V3i(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y), Lerp(t.Z, a.Z, b.Z)); } /// /// Applies Fun.InvLerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvLerp(this V3i y, V3i a, V3i b) { return new V3d(InvLerp(y.X, a.X, b.X), InvLerp(y.Y, a.Y, b.Y), InvLerp(y.Z, a.Z, b.Z)); } #endregion #region Common Divisor and Multiple /// /// Applies Fun.GreatestCommonDivisor to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i GreatestCommonDivisor(this V3i a, V3i b) { return new V3i(GreatestCommonDivisor(a.X, b.X), GreatestCommonDivisor(a.Y, b.Y), GreatestCommonDivisor(a.Z, b.Z)); } /// /// Applies Fun.LeastCommonMultiple to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i LeastCommonMultiple(this V3i a, V3i b) { return new V3i(LeastCommonMultiple(a.X, b.X), LeastCommonMultiple(a.Y, b.Y), LeastCommonMultiple(a.Z, b.Z)); } #endregion #region Floating point bits /// /// Applies Fun.FloatFromBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FloatFromBits(this V3i x) { return new V3f(FloatFromBits(x.X), FloatFromBits(x.Y), FloatFromBits(x.Z)); } #endregion #region ApproximateEquals /// /// Returns whether the given vectors are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V3i a, V3i b, int tolerance) { return ApproximateEquals(a.X, b.X, tolerance) && ApproximateEquals(a.Y, b.Y, tolerance) && ApproximateEquals(a.Z, b.Z, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this V3i v, int epsilon) => Vec.AllTiny(v, epsilon); #endregion } /// /// Contains static methods /// public static partial class Vec { #region Length /// /// Returns the squared length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LengthSquared(V3i v) => v.LengthSquared; /// /// Returns the length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Length(V3i v) => v.Length; #endregion #region Normalize /// /// Returns a normalized copy of this vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Normalized(V3i v) => v.Normalized; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Norm1(V3i v) => v.Norm1; /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(V3i v) => v.Norm2; /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NormMax(V3i v) => v.NormMax; /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NormMin(V3i v) => v.NormMin; /// /// Gets the p-norm. This is calculated as the p-th root of (|x|^n + |y|^n + ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this V3i v, double p) { return ( Fun.Abs(v.X).Pow(p) + Fun.Abs(v.Y).Pow(p) + Fun.Abs(v.Z).Pow(p)).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the squared distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int DistanceSquared(this V3i a, V3i b) => Fun.Square(b.X - a.X) + Fun.Square(b.Y - a.Y) + Fun.Square(b.Z - a.Z); /// /// Returns the distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V3i a, V3i b) => Fun.Sqrt(DistanceSquared(a, b)); /// /// Returns the Manhatten (or 1-) distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Distance1(this V3i a, V3i b) => Fun.Abs(b.X - a.X) + Fun.Abs(b.Y - a.Y) + Fun.Abs(b.Z - a.Z); /// /// Returns the p-distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V3i a, V3i b, double p) => (Fun.Abs(b.X - a.X).Pow(p) + Fun.Abs(b.Y - a.Y).Pow(p) + Fun.Abs(b.Z - a.Z).Pow(p)).Pow(1 / p); /// /// Returns the maximal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int DistanceMax(this V3i a, V3i b) => Fun.Max(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y), Fun.Abs(b.Z - a.Z)); /// /// Returns the minimal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int DistanceMin(this V3i a, V3i b) => Fun.Min(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y), Fun.Abs(b.Z - a.Z)); /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V3i query, V3i p0, V3i p1) { return DistanceToLine((V3d) query, (V3d) p0, (V3d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V3i query, V3i p0, V3i p1) { return DistanceToInfiniteLine((V3d) query, (V3d) p0, (V3d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V3i query, V3i p0, V3i p1, out double t) { return DistanceToLine((V3d) query, (V3d) p0, (V3d) p1, out t); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V3i query, V3i p0, V3i p1, out double t) { return DistanceToInfiniteLine((V3d) query, (V3d) p0, (V3d) p1, out t); } #endregion #region Operations /// /// Negates the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Negate(this ref V3i v) { v.X = -v.X; v.Y = -v.Y; v.Z = -v.Z; } /// /// Returns the outer product (tensor-product) of a * b^T as a 3x3 matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33i Outer(this V3i a, V3i b) { return new M33i( a.X * b.X, a.X * b.Y, a.X * b.Z, a.Y * b.X, a.Y * b.Y, a.Y * b.Z, a.Z * b.X, a.Z * b.Y, a.Z * b.Z); } /// /// Returns the dot product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Dot(this V3i a, V3i b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z; } /// /// Returns the skew-symmetric "cross" matrix (A^T = -A) of the vector v. /// public static M33i CrossMatrix(this V3i v) { return new M33i(0, -v.Z, +v.Y, +v.Z, 0, -v.X, -v.Y, +v.X, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DirFlags DirFlags(this V3i v) { DirFlags flags = Aardbase.DirFlags.None; if (v.X > 0) flags |= Aardbase.DirFlags.PositiveX; if (v.X < 0) flags |= Aardbase.DirFlags.NegativeX; if (v.Y > 0) flags |= Aardbase.DirFlags.PositiveY; if (v.Y < 0) flags |= Aardbase.DirFlags.NegativeY; if (v.Z > 0) flags |= Aardbase.DirFlags.PositiveZ; if (v.Z < 0) flags |= Aardbase.DirFlags.NegativeZ; return flags; } /// /// Returns the cross product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Cross(this V3i a, V3i b) { return new V3i( a.Y * b.Z - a.Z * b.Y, a.Z * b.X - a.X * b.Z, a.X * b.Y - a.Y * b.X ); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V3i a, V3i b) { return (a.X < b.X && a.Y < b.Y && a.Z < b.Z); } /// /// Returns whether ALL elements of v are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V3i v, int s) { return (v.X < s && v.Y < s && v.Z < s); } /// /// Returns whether a is Smaller ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(int s, V3i v) { return (s < v.X && s < v.Y && s < v.Z); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V3i a, V3i b) { return (a.X < b.X || a.Y < b.Y || a.Z < b.Z); } /// /// Returns whether AT LEAST ONE element of v is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V3i v, int s) { return (v.X < s || v.Y < s || v.Z < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(int s, V3i v) { return (s < v.X || s < v.Y || s < v.Z); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V3i a, V3i b) { return (a.X > b.X && a.Y > b.Y && a.Z > b.Z); } /// /// Returns whether ALL elements of v are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V3i v, int s) { return (v.X > s && v.Y > s && v.Z > s); } /// /// Returns whether a is Greater ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(int s, V3i v) { return (s > v.X && s > v.Y && s > v.Z); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V3i a, V3i b) { return (a.X > b.X || a.Y > b.Y || a.Z > b.Z); } /// /// Returns whether AT LEAST ONE element of v is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V3i v, int s) { return (v.X > s || v.Y > s || v.Z > s); } /// /// Returns whether a is Greater AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(int s, V3i v) { return (s > v.X || s > v.Y || s > v.Z); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V3i a, V3i b) { return (a.X <= b.X && a.Y <= b.Y && a.Z <= b.Z); } /// /// Returns whether ALL elements of v are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V3i v, int s) { return (v.X <= s && v.Y <= s && v.Z <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(int s, V3i v) { return (s <= v.X && s <= v.Y && s <= v.Z); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V3i a, V3i b) { return (a.X <= b.X || a.Y <= b.Y || a.Z <= b.Z); } /// /// Returns whether AT LEAST ONE element of v is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V3i v, int s) { return (v.X <= s || v.Y <= s || v.Z <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(int s, V3i v) { return (s <= v.X || s <= v.Y || s <= v.Z); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V3i a, V3i b) { return (a.X >= b.X && a.Y >= b.Y && a.Z >= b.Z); } /// /// Returns whether ALL elements of v are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V3i v, int s) { return (v.X >= s && v.Y >= s && v.Z >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(int s, V3i v) { return (s >= v.X && s >= v.Y && s >= v.Z); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V3i a, V3i b) { return (a.X >= b.X || a.Y >= b.Y || a.Z >= b.Z); } /// /// Returns whether AT LEAST ONE element of v is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V3i v, int s) { return (v.X >= s || v.Y >= s || v.Z >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(int s, V3i v) { return (s >= v.X || s >= v.Y || s >= v.Z); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V3i a, V3i b) { return (a.X == b.X && a.Y == b.Y && a.Z == b.Z); } /// /// Returns whether ALL elements of v are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V3i v, int s) { return (v.X == s && v.Y == s && v.Z == s); } /// /// Returns whether a is Equal ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(int s, V3i v) { return (s == v.X && s == v.Y && s == v.Z); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V3i a, V3i b) { return (a.X == b.X || a.Y == b.Y || a.Z == b.Z); } /// /// Returns whether AT LEAST ONE element of v is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V3i v, int s) { return (v.X == s || v.Y == s || v.Z == s); } /// /// Returns whether a is Equal AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(int s, V3i v) { return (s == v.X || s == v.Y || s == v.Z); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V3i a, V3i b) { return (a.X != b.X && a.Y != b.Y && a.Z != b.Z); } /// /// Returns whether ALL elements of v are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V3i v, int s) { return (v.X != s && v.Y != s && v.Z != s); } /// /// Returns whether a is Different ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(int s, V3i v) { return (s != v.X && s != v.Y && s != v.Z); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V3i a, V3i b) { return (a.X != b.X || a.Y != b.Y || a.Z != b.Z); } /// /// Returns whether AT LEAST ONE element of v is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V3i v, int s) { return (v.X != s || v.Y != s || v.Z != s); } /// /// Returns whether a is Different AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(int s, V3i v) { return (s != v.X || s != v.Y || s != v.Z); } /// /// Compare x-coordinate before y-coordinate, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this V3i v0, V3i v1) { if (v0.X < v1.X) return -1; if (v0.X > v1.X) return +1; if (v0.Y < v1.Y) return -1; if (v0.Y > v1.Y) return +1; if (v0.Z < v1.Z) return -1; if (v0.Z > v1.Z) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MinElement(V3i v) => v.MinElement; /// /// Returns the maximum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MaxElement(V3i v) => v.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this V3i v, int epsilon) => v.X.IsTiny(epsilon) || v.Y.IsTiny(epsilon) || v.Z.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this V3i v, int epsilon) => v.X.IsTiny(epsilon) && v.Y.IsTiny(epsilon) && v.Z.IsTiny(epsilon); #endregion #region ArrayExtensions public static int IndexOfClosestPoint(this V3i[] pointArray, V3i point) { var bestDist = DistanceSquared(point, pointArray[0]); int bestIndex = 0; int count = pointArray.Length; for (int i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this V3i[] array, int start, int count, V3i point) { var bestDist = DistanceSquared(point, array[start]); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this T[] array, int start, int count, Func pointSelector, V3i point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint(this V3i[] pointArray, V3i point) { var bestDist = DistanceSquared(point, pointArray[0]); long bestIndex = 0; long count = pointArray.LongLength; for (long i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this V3i[] array, long start, long count, V3i point) { var bestDist = DistanceSquared(point, array[start]); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this T[] array, long start, long count, Func pointSelector, V3i point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static int IndexOfMinX(this V3i[] vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static long LongIndexOfMinX(this V3i[] vectorArray, long count = 0) { var minimum = vectorArray[0].X; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static int IndexOfMaxX(this V3i[] vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static long LongIndexOfMaxX(this V3i[] vectorArray, long count = 0) { var maximum = vectorArray[0].X; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static int IndexOfMinY(this V3i[] vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static long LongIndexOfMinY(this V3i[] vectorArray, long count = 0) { var minimum = vectorArray[0].Y; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static int IndexOfMaxY(this V3i[] vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static long LongIndexOfMaxY(this V3i[] vectorArray, long count = 0) { var maximum = vectorArray[0].Y; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static int IndexOfMinZ(this V3i[] vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static long LongIndexOfMinZ(this V3i[] vectorArray, long count = 0) { var minimum = vectorArray[0].Z; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static int IndexOfMaxZ(this V3i[] vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static long LongIndexOfMaxZ(this V3i[] vectorArray, long count = 0) { var maximum = vectorArray[0].Z; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the list. /// public static int IndexOfMinX(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the list. /// public static int IndexOfMaxX(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the list. /// public static int IndexOfMinY(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the list. /// public static int IndexOfMaxY(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the list. /// public static int IndexOfMinZ(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the list. /// public static int IndexOfMaxZ(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the array of the index-th coordinate of each vector. /// public static int[] CopyCoord(this V3i[] self, int index) { switch (index) { case 0: return self.Map(v => v.X); case 1: return self.Map(v => v.Y); case 2: return self.Map(v => v.Z); default: throw new IndexOutOfRangeException(); } } #endregion } public static class IRandomUniformV3iExtensions { #region IRandomUniform extensions for V3i /// /// Uses UniformInt() to generate the elements of a V3i vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i UniformV3i(this IRandomUniform rnd) { return new V3i(rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt()); } /// /// Uses UniformIntNonZero() to generate the elements of a V3i vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i UniformV3iNonZero(this IRandomUniform rnd) { return new V3i(rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero()); } /// /// Uses UniformInt(int) to generate the elements of a V3i vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i UniformV3i(this IRandomUniform rnd, int size) { return new V3i(rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size)); } /// /// Uses UniformInt(int) to generate the elements of a V3i vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i UniformV3i(this IRandomUniform rnd, V3i size) { return new V3i(rnd.UniformInt(size.X), rnd.UniformInt(size.Y), rnd.UniformInt(size.Z)); } #endregion } #endregion #region V3ui [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct V3ui : IVector, ISize3ui, IFormattable, IEquatable { [DataMember] public uint X; [DataMember] public uint Y; [DataMember] public uint Z; #region Constructors /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(int x, int y, int z) { X = (uint)x; Y = (uint)y; Z = (uint)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(int v) { X = (uint)v; Y = (uint)v; Z = (uint)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(int[] a) { X = (uint)a[0]; Y = (uint)a[1]; Z = (uint)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(int[] a, int start) { X = (uint)a[start + 0]; Y = (uint)a[start + 1]; Z = (uint)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(int a, V2i b) { X = (uint)a; Y = (uint)b.X; Z = (uint)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V2i a, int b) { X = (uint)a.X; Y = (uint)a.Y; Z = (uint)b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(uint x, uint y, uint z) { X = x; Y = y; Z = z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(uint v) { X = v; Y = v; Z = v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(uint[] a) { X = a[0]; Y = a[1]; Z = a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(uint[] a, int start) { X = a[start + 0]; Y = a[start + 1]; Z = a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(uint a, V2ui b) { X = a; Y = b.X; Z = b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V2ui a, uint b) { X = a.X; Y = a.Y; Z = b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(long x, long y, long z) { X = (uint)x; Y = (uint)y; Z = (uint)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(long v) { X = (uint)v; Y = (uint)v; Z = (uint)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(long[] a) { X = (uint)a[0]; Y = (uint)a[1]; Z = (uint)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(long[] a, int start) { X = (uint)a[start + 0]; Y = (uint)a[start + 1]; Z = (uint)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(long a, V2l b) { X = (uint)a; Y = (uint)b.X; Z = (uint)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V2l a, long b) { X = (uint)a.X; Y = (uint)a.Y; Z = (uint)b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(float x, float y, float z) { X = (uint)x; Y = (uint)y; Z = (uint)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(float v) { X = (uint)v; Y = (uint)v; Z = (uint)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(float[] a) { X = (uint)a[0]; Y = (uint)a[1]; Z = (uint)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(float[] a, int start) { X = (uint)a[start + 0]; Y = (uint)a[start + 1]; Z = (uint)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(float a, V2f b) { X = (uint)a; Y = (uint)b.X; Z = (uint)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V2f a, float b) { X = (uint)a.X; Y = (uint)a.Y; Z = (uint)b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(double x, double y, double z) { X = (uint)x; Y = (uint)y; Z = (uint)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(double v) { X = (uint)v; Y = (uint)v; Z = (uint)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(double[] a) { X = (uint)a[0]; Y = (uint)a[1]; Z = (uint)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(double[] a, int start) { X = (uint)a[start + 0]; Y = (uint)a[start + 1]; Z = (uint)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(double a, V2d b) { X = (uint)a; Y = (uint)b.X; Z = (uint)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V2d a, double b) { X = (uint)a.X; Y = (uint)a.Y; Z = (uint)b; } /// /// Creates a vector from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(Func index_fun) { X = index_fun(0); Y = index_fun(1); Z = index_fun(2); } /// /// Creates a vector from a general vector implementing the IVector<uint> interface. /// The caller has to verify that the dimension of is at least 3. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(IVector v) : this(v[0], v[1], v[2]) { } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V2i v) { X = (uint)v.X; Y = (uint)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V2ui v) { X = v.X; Y = v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V2l v) { X = (uint)v.X; Y = (uint)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V2f v) { X = (uint)v.X; Y = (uint)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V2d v) { X = (uint)v.X; Y = (uint)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V3i v) { X = (uint)v.X; Y = (uint)v.Y; Z = (uint)v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V3ui v) { X = v.X; Y = v.Y; Z = v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V3l v) { X = (uint)v.X; Y = (uint)v.Y; Z = (uint)v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V3f v) { X = (uint)v.X; Y = (uint)v.Y; Z = (uint)v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V3d v) { X = (uint)v.X; Y = (uint)v.Y; Z = (uint)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V4i v) { X = (uint)v.X; Y = (uint)v.Y; Z = (uint)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V4ui v) { X = v.X; Y = v.Y; Z = v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V4l v) { X = (uint)v.X; Y = (uint)v.Y; Z = (uint)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V4f v) { X = (uint)v.X; Y = (uint)v.Y; Z = (uint)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(V4d v) { X = (uint)v.X; Y = (uint)v.Y; Z = (uint)v.Z; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(C3b c) { X = (uint)(c.R); Y = (uint)(c.G); Z = (uint)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(C3us c) { X = (uint)(c.R); Y = (uint)(c.G); Z = (uint)(c.B); } /// /// Creates a vector from a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(C3ui c) { X = (c.R); Y = (c.G); Z = (c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(C4b c) { X = (uint)(c.R); Y = (uint)(c.G); Z = (uint)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(C4us c) { X = (uint)(c.R); Y = (uint)(c.G); Z = (uint)(c.B); } /// /// Creates a vector from a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3ui(C4ui c) { X = (c.R); Y = (c.G); Z = (c.B); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(V2i v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(V2ui v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(V2l v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(V2f v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(V2d v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(V3i v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(V3l v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(V3f v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(V3d v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(V4i v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(V4ui v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(V4l v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(V4f v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(V4d v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToV2i() => (V2i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToV2l() => (V2l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f ToV2f() => (V2f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d ToV2d() => (V2d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int[](V3ui v) => new int[] { (int)v.X, (int)v.Y, (int)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(int[] v) => new V3ui((uint)v[0], (uint)v[1], (uint)v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](V3ui v) => new uint[] { v.X, v.Y, v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(uint[] v) => new V3ui(v[0], v[1], v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long[](V3ui v) => new long[] { (long)v.X, (long)v.Y, (long)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(long[] v) => new V3ui((uint)v[0], (uint)v[1], (uint)v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](V3ui v) => new float[] { (float)v.X, (float)v.Y, (float)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(float[] v) => new V3ui((uint)v[0], (uint)v[1], (uint)v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](V3ui v) => new double[] { (double)v.X, (double)v.Y, (double)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(double[] v) => new V3ui((uint)v[0], (uint)v[1], (uint)v[2]); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(C3b v) => new V3ui(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(C3us v) => new V3ui(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(C3ui v) => new V3ui(v); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(C4b v) => new V3ui(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(C4us v) => new V3ui(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3ui(C4ui v) => new V3ui(v); /// /// Converts the given vector to a color. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i Copy(Func element_fun) => new V3i(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i Copy(Func element_index_fun) => new V3i(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(int[] array, int start) { array[start + 0] = (int)X; array[start + 1] = (int)Y; array[start + 2] = (int)Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui Copy(Func element_fun) => new V3ui(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui Copy(Func element_index_fun) => new V3ui(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(uint[] array, int start) { array[start + 0] = X; array[start + 1] = Y; array[start + 2] = Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l Copy(Func element_fun) => new V3l(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l Copy(Func element_index_fun) => new V3l(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(long[] array, int start) { array[start + 0] = (long)X; array[start + 1] = (long)Y; array[start + 2] = (long)Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f Copy(Func element_fun) => new V3f(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f Copy(Func element_index_fun) => new V3f(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(float[] array, int start) { array[start + 0] = (float)X; array[start + 1] = (float)Y; array[start + 2] = (float)Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d Copy(Func element_fun) => new V3d(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d Copy(Func element_index_fun) => new V3d(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(double[] array, int start) { array[start + 0] = (double)X; array[start + 1] = (double)Y; array[start + 2] = (double)Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(X); array[start + 1] = element_fun(Y); array[start + 2] = element_fun(Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(X, 0); array[start + 1] = element_index_fun(Y, 1); array[start + 2] = element_index_fun(Z, 2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly uint[] ToArray() => new uint[] { X, Y, Z }; #endregion #region Properties and Indexers /// /// Property for the field X. /// Useful when properties are required, but the field X is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public uint P_X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value; } } /// /// Property for the field Y. /// Useful when properties are required, but the field Y is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public uint P_Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Y = value; } } /// /// Property for the field Z. /// Useful when properties are required, but the field Z is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public uint P_Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Z = value; } } /// /// Enumerates all elements of this vector. /// public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return X; yield return Y; yield return Z; } } /// /// Gets or sets element with given index. /// public unsafe uint this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (uint* ptr = &X) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (uint* ptr = &X) { ptr[index] = value; } } } /// /// Returns the index of the largest dimension of the vector. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X >= Y ? (X >= Z ? 0 : 2) : (Y >= Z ? 1 : 2); } } /// /// Returns the index of the smallest dimension of the vector. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X <= Y ? (X <= Z ? 0 : 2) : (Y <= Z ? 1 : 2); } } /// /// Returns the minimum element of the vector. /// public readonly uint MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(X, Y, Z); } /// /// Returns the maximum element of the vector. /// public readonly uint MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(X, Y, Z); } #endregion #region Constants /// /// Number of elements in this vector. /// public const int Dimension = 3; /// /// All elements zero. /// public static V3ui Zero { get { return new V3ui(0, 0, 0); } } /// /// All elements one. /// public static V3ui One { get { return new V3ui(1, 1, 1); } } /// /// All elements set to maximum possible value. /// public static V3ui MaxValue { get { return new V3ui(Constant.ParseableMaxValue, Constant.ParseableMaxValue, Constant.ParseableMaxValue); } } /// /// All elements set to minimum possible value. /// public static V3ui MinValue { get { return new V3ui(Constant.ParseableMinValue, Constant.ParseableMinValue, Constant.ParseableMinValue); } } /// /// Normalized X-axis. /// public static V3ui XAxis { get { return new V3ui(1, 0, 0); } } /// /// Normalized Y-axis. /// public static V3ui YAxis { get { return new V3ui(0, 1, 0); } } /// /// Normalized Z-axis. /// public static V3ui ZAxis { get { return new V3ui(0, 0, 1); } } /// /// An array of accessor functions for the coordinates of the vector. /// public static readonly Func[] SelectorArray = new Func[] { v => v.X, v => v.Y, v => v.Z }; /// /// Element getter function. /// public static readonly Func Getter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref V3ui v, int i, uint s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; default: throw new IndexOutOfRangeException(); } }; /// /// Element getter function with long index. /// public static readonly Func LongGetter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action with long index. /// public static readonly ActionRefValVal LongSetter = (ref V3ui v, long i, uint s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Static factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui FromV3i(V3i v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui FromV3l(V3l v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui FromV3f(V3f v) => new V3ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui FromV3d(V3d v) => new V3ui(v); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui FromC3b(C3b c) => new V3ui(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui FromC3us(C3us c) => new V3ui(c); /// /// Creates a vector from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui FromC3ui(C3ui c) => new V3ui(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui FromC4b(C4b c) => new V3ui(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui FromC4us(C4us c) => new V3ui(c); /// /// Creates a vector from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui FromC4ui(C4ui c) => new V3ui(c); #endregion #region Norms /// /// Returns the squared length of the vector. /// public readonly uint LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X * X + Y * Y + Z * Z ; } } /// /// Returns the length of the vector. /// public readonly double Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z ); } } /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// public readonly uint Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X + Y + Z; } } /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z); } } /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// public readonly uint NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(X, Y, Z); } } /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// public readonly uint NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(X, Y, Z); } } /// /// Returns a normalized copy of this vector. /// public readonly V3d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Length; if (s == 0) return V3d.Zero; s = 1 / s; return new V3d(X * s, Y * s, Z * s); } } #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui LinearInterp(float t, V3ui a, V3ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui LinearInterp(V3f t, V3ui a, V3ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui LinearInterp(double t, V3ui a, V3ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui LinearInterp(V3d t, V3ui a, V3ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Min(V3ui v0, V3ui v1) => Fun.Min(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Min(V3ui v, uint x) => Fun.Min(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Max(V3ui v0, V3ui v1) => Fun.Max(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Max(V3ui v, uint x) => Fun.Max(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Saturate(V3ui v) => Fun.Saturate(v); #endregion #region Operations /// /// Sets the elements of a vector to the given int elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(int x, int y, int z) { X = (uint)x; Y = (uint)y; Z = (uint)z; } /// /// Sets the elements of a vector to the given uint elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(uint x, uint y, uint z) { X = x; Y = y; Z = z; } /// /// Sets the elements of a vector to the given long elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(long x, long y, long z) { X = (uint)x; Y = (uint)y; Z = (uint)z; } /// /// Sets the elements of a vector to the given float elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(float x, float y, float z) { X = (uint)x; Y = (uint)y; Z = (uint)z; } /// /// Sets the elements of a vector to the given double elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(double x, double y, double z) { X = (uint)x; Y = (uint)y; Z = (uint)z; } /// /// Returns the component-wise bitwise complement of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator ~(V3ui v) => new V3ui(~v.X, ~v.Y, ~v.Z); /// /// Returns the component-wise sum of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator +(V3ui a, V3ui b) => new V3ui(a.X + b.X, a.Y + b.Y, a.Z + b.Z); /// /// Returns the component-wise sum of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator +(V3ui v, uint s) => new V3ui(v.X + s, v.Y + s, v.Z + s); /// /// Returns the component-wise sum of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator +(uint s, V3ui v) => new V3ui(s + v.X, s + v.Y, s + v.Z); /// /// Returns the component-wise difference of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator -(V3ui a, V3ui b) => new V3ui(a.X - b.X, a.Y - b.Y, a.Z - b.Z); /// /// Returns the component-wise difference of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator -(V3ui v, uint s) => new V3ui(v.X - s, v.Y - s, v.Z - s); /// /// Returns the component-wise difference of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator -(uint s, V3ui v) => new V3ui(s - v.X, s - v.Y, s - v.Z); /// /// Returns the component-wise product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator *(V3ui a, V3ui b) => new V3ui(a.X * b.X, a.Y * b.Y, a.Z * b.Z); /// /// Returns the component-wise product of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator *(V3ui v, uint s) => new V3ui(v.X * s, v.Y * s, v.Z * s); /// /// Returns the component-wise product of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator *(uint s, V3ui v) => new V3ui(s * v.X, s * v.Y, s * v.Z); /// /// Returns the component-wise fraction of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator /(V3ui a, V3ui b) => new V3ui(a.X / b.X, a.Y / b.Y, a.Z / b.Z); /// /// Returns the component-wise fraction of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator /(V3ui v, uint s) => new V3ui(v.X / s, v.Y / s, v.Z / s); /// /// Returns the component-wise fraction of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator /(uint s, V3ui v) => new V3ui(s / v.X, s / v.Y, s / v.Z); /// /// Returns the component-wise remainder of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator %(V3ui a, V3ui b) => new V3ui(a.X % b.X, a.Y % b.Y, a.Z % b.Z); /// /// Returns the component-wise remainder of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator %(V3ui v, uint s) => new V3ui(v.X % s, v.Y % s, v.Z % s); /// /// Returns the component-wise remainder of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator %(uint s, V3ui v) => new V3ui(s % v.X, s % v.Y, s % v.Z); /// /// Returns the component-wise bitwise and of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator &(V3ui a, V3ui b) => new V3ui(a.X & b.X, a.Y & b.Y, a.Z & b.Z); /// /// Returns the component-wise bitwise and of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator &(V3ui v, uint s) => new V3ui(v.X & s, v.Y & s, v.Z & s); /// /// Returns the component-wise bitwise and of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator &(uint s, V3ui v) => new V3ui(s & v.X, s & v.Y, s & v.Z); /// /// Returns the component-wise bitwise or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator |(V3ui a, V3ui b) => new V3ui(a.X | b.X, a.Y | b.Y, a.Z | b.Z); /// /// Returns the component-wise bitwise or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator |(V3ui v, uint s) => new V3ui(v.X | s, v.Y | s, v.Z | s); /// /// Returns the component-wise bitwise or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator |(uint s, V3ui v) => new V3ui(s | v.X, s | v.Y, s | v.Z); /// /// Returns the component-wise bitwise exclusive or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator ^(V3ui a, V3ui b) => new V3ui(a.X ^ b.X, a.Y ^ b.Y, a.Z ^ b.Z); /// /// Returns the component-wise bitwise exclusive or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator ^(V3ui v, uint s) => new V3ui(v.X ^ s, v.Y ^ s, v.Z ^ s); /// /// Returns the component-wise bitwise exclusive or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator ^(uint s, V3ui v) => new V3ui(s ^ v.X, s ^ v.Y, s ^ v.Z); /// /// Returns the component-wise left bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator <<(V3ui v, int s) => new V3ui(v.X << s, v.Y << s, v.Z << s); /// /// Returns the component-wise right bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui operator >>(V3ui v, int s) => new V3ui(v.X >> s, v.Y >> s, v.Z >> s); /// Attention: NEVER implement operators <, <=, >=, >, /// since these are not defined in a Vector space. /// Use AllSmaller() and similar comparators! #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V3ui a, V3ui b) { return a.X == b.X && a.Y == b.Y && a.Z == b.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V3ui v, uint s) { return v.X == s && v.Y == s && v.Z == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(uint s, V3ui v) { return s == v.X && s == v.Y && s == v.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V3ui a, V3ui b) { return a.X != b.X || a.Y != b.Y || a.Z != b.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V3ui v, uint s) { return v.X != s || v.Y != s || v.Z != s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(uint s, V3ui v) { return s != v.X || s != v.Y || s != v.Z; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(V3ui other) { return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z); } #endregion #region Overrides public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + X.ToString(format, fp) + between + Y.ToString(format, fp) + between + Z.ToString(format, fp) + end; } public override readonly int GetHashCode() { return HashCode.GetCombined(X, Y, Z); } public override readonly bool Equals(object other) => (other is V3ui o) ? Equals(o) : false; public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + X.ToString(null, CultureInfo.InvariantCulture) + ", " + Y.ToString(null, CultureInfo.InvariantCulture) + ", " + Z.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Parsing public static V3ui Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new V3ui( uint.Parse(x[0], CultureInfo.InvariantCulture), uint.Parse(x[1], CultureInfo.InvariantCulture), uint.Parse(x[2], CultureInfo.InvariantCulture) ); } public static V3ui Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, V3ui.Setter); } public static V3ui Parse(Text t, int bracketLevel) { return t.NestedBracketSplit(bracketLevel, Text.Parse, V3ui.Setter); } #endregion #region Swizzle Methods [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui OX => new V2ui(0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui OY => new V2ui(0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui OZ => new V2ui(0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui IX => new V2ui(1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui IY => new V2ui(1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui IZ => new V2ui(1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui XO => new V2ui(X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui XI => new V2ui(X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui XX => new V2ui(X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui XY { readonly get => new V2ui(X, Y); set { X = value.X; Y = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui XZ { readonly get => new V2ui(X, Z); set { X = value.X; Z = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui YO => new V2ui(Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui YI => new V2ui(Y, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui YX { readonly get => new V2ui(Y, X); set { Y = value.X; X = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui YY => new V2ui(Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui YZ { readonly get => new V2ui(Y, Z); set { Y = value.X; Z = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui ZO => new V2ui(Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui ZI => new V2ui(Z, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui ZX { readonly get => new V2ui(Z, X); set { Z = value.X; X = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui ZY { readonly get => new V2ui(Z, Y); set { Z = value.X; Y = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui ZZ => new V2ui(Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3ui OOO => new V3ui(0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3ui OOI => new V3ui(0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OOX => new V3ui(0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OOY => new V3ui(0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OOZ => new V3ui(0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3ui OIO => new V3ui(0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3ui OII => new V3ui(0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OIX => new V3ui(0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OIY => new V3ui(0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OIZ => new V3ui(0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OXO => new V3ui(0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OXI => new V3ui(0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OXX => new V3ui(0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OXY => new V3ui(0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OXZ => new V3ui(0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OYO => new V3ui(0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OYI => new V3ui(0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OYX => new V3ui(0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OYY => new V3ui(0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OYZ => new V3ui(0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OZO => new V3ui(0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OZI => new V3ui(0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OZX => new V3ui(0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OZY => new V3ui(0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OZZ => new V3ui(0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3ui IOO => new V3ui(1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3ui IOI => new V3ui(1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IOX => new V3ui(1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IOY => new V3ui(1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IOZ => new V3ui(1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3ui IIO => new V3ui(1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3ui III => new V3ui(1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IIX => new V3ui(1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IIY => new V3ui(1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IIZ => new V3ui(1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IXO => new V3ui(1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IXI => new V3ui(1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IXX => new V3ui(1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IXY => new V3ui(1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IXZ => new V3ui(1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IYO => new V3ui(1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IYI => new V3ui(1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IYX => new V3ui(1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IYY => new V3ui(1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IYZ => new V3ui(1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IZO => new V3ui(1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IZI => new V3ui(1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IZX => new V3ui(1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IZY => new V3ui(1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IZZ => new V3ui(1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XOO => new V3ui(X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XOI => new V3ui(X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XOX => new V3ui(X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XOY => new V3ui(X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XOZ => new V3ui(X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XIO => new V3ui(X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XII => new V3ui(X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XIX => new V3ui(X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XIY => new V3ui(X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XIZ => new V3ui(X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XXO => new V3ui(X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XXI => new V3ui(X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XXX => new V3ui(X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XXY => new V3ui(X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XXZ => new V3ui(X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XYO => new V3ui(X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XYI => new V3ui(X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XYX => new V3ui(X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XYY => new V3ui(X, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui XYZ { readonly get => new V3ui(X, Y, Z); set { X = value.X; Y = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XZO => new V3ui(X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XZI => new V3ui(X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XZX => new V3ui(X, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui XZY { readonly get => new V3ui(X, Z, Y); set { X = value.X; Z = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XZZ => new V3ui(X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YOO => new V3ui(Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YOI => new V3ui(Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YOX => new V3ui(Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YOY => new V3ui(Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YOZ => new V3ui(Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YIO => new V3ui(Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YII => new V3ui(Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YIX => new V3ui(Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YIY => new V3ui(Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YIZ => new V3ui(Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YXO => new V3ui(Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YXI => new V3ui(Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YXX => new V3ui(Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YXY => new V3ui(Y, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui YXZ { readonly get => new V3ui(Y, X, Z); set { Y = value.X; X = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YYO => new V3ui(Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YYI => new V3ui(Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YYX => new V3ui(Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YYY => new V3ui(Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YYZ => new V3ui(Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YZO => new V3ui(Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YZI => new V3ui(Y, Z, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui YZX { readonly get => new V3ui(Y, Z, X); set { Y = value.X; Z = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YZY => new V3ui(Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YZZ => new V3ui(Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZOO => new V3ui(Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZOI => new V3ui(Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZOX => new V3ui(Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZOY => new V3ui(Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZOZ => new V3ui(Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZIO => new V3ui(Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZII => new V3ui(Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZIX => new V3ui(Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZIY => new V3ui(Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZIZ => new V3ui(Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZXO => new V3ui(Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZXI => new V3ui(Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZXX => new V3ui(Z, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui ZXY { readonly get => new V3ui(Z, X, Y); set { Z = value.X; X = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZXZ => new V3ui(Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZYO => new V3ui(Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZYI => new V3ui(Z, Y, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui ZYX { readonly get => new V3ui(Z, Y, X); set { Z = value.X; Y = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZYY => new V3ui(Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZYZ => new V3ui(Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZZO => new V3ui(Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZZI => new V3ui(Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZZX => new V3ui(Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZZY => new V3ui(Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZZZ => new V3ui(Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOOX => new V4ui(0, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOOY => new V4ui(0, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOOZ => new V4ui(0, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOIX => new V4ui(0, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOIY => new V4ui(0, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOIZ => new V4ui(0, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOXO => new V4ui(0, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOXI => new V4ui(0, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOXX => new V4ui(0, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOXY => new V4ui(0, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOXZ => new V4ui(0, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOYO => new V4ui(0, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOYI => new V4ui(0, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOYX => new V4ui(0, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOYY => new V4ui(0, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOYZ => new V4ui(0, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOZO => new V4ui(0, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOZI => new V4ui(0, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOZX => new V4ui(0, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOZY => new V4ui(0, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOZZ => new V4ui(0, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIOX => new V4ui(0, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIOY => new V4ui(0, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIOZ => new V4ui(0, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIIX => new V4ui(0, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIIY => new V4ui(0, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIIZ => new V4ui(0, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIXO => new V4ui(0, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIXI => new V4ui(0, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIXX => new V4ui(0, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIXY => new V4ui(0, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIXZ => new V4ui(0, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIYO => new V4ui(0, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIYI => new V4ui(0, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIYX => new V4ui(0, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIYY => new V4ui(0, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIYZ => new V4ui(0, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIZO => new V4ui(0, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIZI => new V4ui(0, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIZX => new V4ui(0, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIZY => new V4ui(0, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIZZ => new V4ui(0, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXOO => new V4ui(0, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXOI => new V4ui(0, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXOX => new V4ui(0, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXOY => new V4ui(0, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXOZ => new V4ui(0, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXIO => new V4ui(0, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXII => new V4ui(0, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXIX => new V4ui(0, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXIY => new V4ui(0, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXIZ => new V4ui(0, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXXO => new V4ui(0, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXXI => new V4ui(0, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXXX => new V4ui(0, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXXY => new V4ui(0, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXXZ => new V4ui(0, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXYO => new V4ui(0, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXYI => new V4ui(0, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXYX => new V4ui(0, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXYY => new V4ui(0, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXYZ => new V4ui(0, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXZO => new V4ui(0, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXZI => new V4ui(0, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXZX => new V4ui(0, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXZY => new V4ui(0, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXZZ => new V4ui(0, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYOO => new V4ui(0, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYOI => new V4ui(0, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYOX => new V4ui(0, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYOY => new V4ui(0, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYOZ => new V4ui(0, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYIO => new V4ui(0, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYII => new V4ui(0, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYIX => new V4ui(0, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYIY => new V4ui(0, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYIZ => new V4ui(0, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYXO => new V4ui(0, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYXI => new V4ui(0, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYXX => new V4ui(0, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYXY => new V4ui(0, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYXZ => new V4ui(0, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYYO => new V4ui(0, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYYI => new V4ui(0, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYYX => new V4ui(0, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYYY => new V4ui(0, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYYZ => new V4ui(0, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYZO => new V4ui(0, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYZI => new V4ui(0, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYZX => new V4ui(0, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYZY => new V4ui(0, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYZZ => new V4ui(0, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZOO => new V4ui(0, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZOI => new V4ui(0, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZOX => new V4ui(0, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZOY => new V4ui(0, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZOZ => new V4ui(0, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZIO => new V4ui(0, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZII => new V4ui(0, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZIX => new V4ui(0, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZIY => new V4ui(0, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZIZ => new V4ui(0, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZXO => new V4ui(0, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZXI => new V4ui(0, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZXX => new V4ui(0, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZXY => new V4ui(0, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZXZ => new V4ui(0, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZYO => new V4ui(0, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZYI => new V4ui(0, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZYX => new V4ui(0, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZYY => new V4ui(0, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZYZ => new V4ui(0, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZZO => new V4ui(0, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZZI => new V4ui(0, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZZX => new V4ui(0, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZZY => new V4ui(0, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZZZ => new V4ui(0, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOOX => new V4ui(1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOOY => new V4ui(1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOOZ => new V4ui(1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOIX => new V4ui(1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOIY => new V4ui(1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOIZ => new V4ui(1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOXO => new V4ui(1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOXI => new V4ui(1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOXX => new V4ui(1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOXY => new V4ui(1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOXZ => new V4ui(1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOYO => new V4ui(1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOYI => new V4ui(1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOYX => new V4ui(1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOYY => new V4ui(1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOYZ => new V4ui(1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOZO => new V4ui(1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOZI => new V4ui(1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOZX => new V4ui(1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOZY => new V4ui(1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOZZ => new V4ui(1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIOX => new V4ui(1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIOY => new V4ui(1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIOZ => new V4ui(1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIIX => new V4ui(1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIIY => new V4ui(1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIIZ => new V4ui(1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIXO => new V4ui(1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIXI => new V4ui(1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIXX => new V4ui(1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIXY => new V4ui(1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIXZ => new V4ui(1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIYO => new V4ui(1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIYI => new V4ui(1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIYX => new V4ui(1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIYY => new V4ui(1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIYZ => new V4ui(1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIZO => new V4ui(1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIZI => new V4ui(1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIZX => new V4ui(1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIZY => new V4ui(1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIZZ => new V4ui(1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXOO => new V4ui(1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXOI => new V4ui(1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXOX => new V4ui(1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXOY => new V4ui(1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXOZ => new V4ui(1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXIO => new V4ui(1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXII => new V4ui(1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXIX => new V4ui(1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXIY => new V4ui(1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXIZ => new V4ui(1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXXO => new V4ui(1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXXI => new V4ui(1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXXX => new V4ui(1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXXY => new V4ui(1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXXZ => new V4ui(1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXYO => new V4ui(1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXYI => new V4ui(1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXYX => new V4ui(1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXYY => new V4ui(1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXYZ => new V4ui(1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXZO => new V4ui(1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXZI => new V4ui(1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXZX => new V4ui(1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXZY => new V4ui(1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXZZ => new V4ui(1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYOO => new V4ui(1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYOI => new V4ui(1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYOX => new V4ui(1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYOY => new V4ui(1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYOZ => new V4ui(1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYIO => new V4ui(1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYII => new V4ui(1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYIX => new V4ui(1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYIY => new V4ui(1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYIZ => new V4ui(1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYXO => new V4ui(1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYXI => new V4ui(1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYXX => new V4ui(1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYXY => new V4ui(1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYXZ => new V4ui(1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYYO => new V4ui(1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYYI => new V4ui(1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYYX => new V4ui(1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYYY => new V4ui(1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYYZ => new V4ui(1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYZO => new V4ui(1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYZI => new V4ui(1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYZX => new V4ui(1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYZY => new V4ui(1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYZZ => new V4ui(1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZOO => new V4ui(1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZOI => new V4ui(1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZOX => new V4ui(1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZOY => new V4ui(1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZOZ => new V4ui(1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZIO => new V4ui(1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZII => new V4ui(1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZIX => new V4ui(1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZIY => new V4ui(1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZIZ => new V4ui(1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZXO => new V4ui(1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZXI => new V4ui(1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZXX => new V4ui(1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZXY => new V4ui(1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZXZ => new V4ui(1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZYO => new V4ui(1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZYI => new V4ui(1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZYX => new V4ui(1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZYY => new V4ui(1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZYZ => new V4ui(1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZZO => new V4ui(1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZZI => new V4ui(1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZZX => new V4ui(1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZZY => new V4ui(1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZZZ => new V4ui(1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOOO => new V4ui(X, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOOI => new V4ui(X, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOOX => new V4ui(X, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOOY => new V4ui(X, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOOZ => new V4ui(X, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOIO => new V4ui(X, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOII => new V4ui(X, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOIX => new V4ui(X, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOIY => new V4ui(X, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOIZ => new V4ui(X, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOXO => new V4ui(X, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOXI => new V4ui(X, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOXX => new V4ui(X, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOXY => new V4ui(X, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOXZ => new V4ui(X, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOYO => new V4ui(X, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOYI => new V4ui(X, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOYX => new V4ui(X, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOYY => new V4ui(X, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOYZ => new V4ui(X, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOZO => new V4ui(X, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOZI => new V4ui(X, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOZX => new V4ui(X, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOZY => new V4ui(X, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOZZ => new V4ui(X, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIOO => new V4ui(X, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIOI => new V4ui(X, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIOX => new V4ui(X, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIOY => new V4ui(X, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIOZ => new V4ui(X, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIIO => new V4ui(X, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIII => new V4ui(X, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIIX => new V4ui(X, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIIY => new V4ui(X, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIIZ => new V4ui(X, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIXO => new V4ui(X, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIXI => new V4ui(X, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIXX => new V4ui(X, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIXY => new V4ui(X, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIXZ => new V4ui(X, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIYO => new V4ui(X, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIYI => new V4ui(X, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIYX => new V4ui(X, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIYY => new V4ui(X, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIYZ => new V4ui(X, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIZO => new V4ui(X, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIZI => new V4ui(X, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIZX => new V4ui(X, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIZY => new V4ui(X, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIZZ => new V4ui(X, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXOO => new V4ui(X, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXOI => new V4ui(X, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXOX => new V4ui(X, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXOY => new V4ui(X, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXOZ => new V4ui(X, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXIO => new V4ui(X, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXII => new V4ui(X, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXIX => new V4ui(X, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXIY => new V4ui(X, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXIZ => new V4ui(X, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXXO => new V4ui(X, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXXI => new V4ui(X, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXXX => new V4ui(X, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXXY => new V4ui(X, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXXZ => new V4ui(X, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXYO => new V4ui(X, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXYI => new V4ui(X, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXYX => new V4ui(X, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXYY => new V4ui(X, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXYZ => new V4ui(X, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXZO => new V4ui(X, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXZI => new V4ui(X, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXZX => new V4ui(X, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXZY => new V4ui(X, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXZZ => new V4ui(X, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYOO => new V4ui(X, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYOI => new V4ui(X, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYOX => new V4ui(X, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYOY => new V4ui(X, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYOZ => new V4ui(X, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYIO => new V4ui(X, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYII => new V4ui(X, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYIX => new V4ui(X, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYIY => new V4ui(X, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYIZ => new V4ui(X, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYXO => new V4ui(X, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYXI => new V4ui(X, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYXX => new V4ui(X, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYXY => new V4ui(X, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYXZ => new V4ui(X, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYYO => new V4ui(X, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYYI => new V4ui(X, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYYX => new V4ui(X, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYYY => new V4ui(X, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYYZ => new V4ui(X, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYZO => new V4ui(X, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYZI => new V4ui(X, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYZX => new V4ui(X, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYZY => new V4ui(X, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYZZ => new V4ui(X, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZOO => new V4ui(X, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZOI => new V4ui(X, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZOX => new V4ui(X, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZOY => new V4ui(X, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZOZ => new V4ui(X, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZIO => new V4ui(X, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZII => new V4ui(X, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZIX => new V4ui(X, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZIY => new V4ui(X, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZIZ => new V4ui(X, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZXO => new V4ui(X, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZXI => new V4ui(X, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZXX => new V4ui(X, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZXY => new V4ui(X, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZXZ => new V4ui(X, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZYO => new V4ui(X, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZYI => new V4ui(X, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZYX => new V4ui(X, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZYY => new V4ui(X, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZYZ => new V4ui(X, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZZO => new V4ui(X, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZZI => new V4ui(X, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZZX => new V4ui(X, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZZY => new V4ui(X, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZZZ => new V4ui(X, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOOO => new V4ui(Y, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOOI => new V4ui(Y, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOOX => new V4ui(Y, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOOY => new V4ui(Y, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOOZ => new V4ui(Y, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOIO => new V4ui(Y, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOII => new V4ui(Y, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOIX => new V4ui(Y, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOIY => new V4ui(Y, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOIZ => new V4ui(Y, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOXO => new V4ui(Y, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOXI => new V4ui(Y, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOXX => new V4ui(Y, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOXY => new V4ui(Y, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOXZ => new V4ui(Y, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOYO => new V4ui(Y, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOYI => new V4ui(Y, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOYX => new V4ui(Y, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOYY => new V4ui(Y, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOYZ => new V4ui(Y, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOZO => new V4ui(Y, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOZI => new V4ui(Y, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOZX => new V4ui(Y, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOZY => new V4ui(Y, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOZZ => new V4ui(Y, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIOO => new V4ui(Y, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIOI => new V4ui(Y, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIOX => new V4ui(Y, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIOY => new V4ui(Y, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIOZ => new V4ui(Y, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIIO => new V4ui(Y, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIII => new V4ui(Y, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIIX => new V4ui(Y, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIIY => new V4ui(Y, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIIZ => new V4ui(Y, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIXO => new V4ui(Y, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIXI => new V4ui(Y, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIXX => new V4ui(Y, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIXY => new V4ui(Y, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIXZ => new V4ui(Y, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIYO => new V4ui(Y, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIYI => new V4ui(Y, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIYX => new V4ui(Y, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIYY => new V4ui(Y, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIYZ => new V4ui(Y, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIZO => new V4ui(Y, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIZI => new V4ui(Y, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIZX => new V4ui(Y, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIZY => new V4ui(Y, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIZZ => new V4ui(Y, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXOO => new V4ui(Y, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXOI => new V4ui(Y, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXOX => new V4ui(Y, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXOY => new V4ui(Y, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXOZ => new V4ui(Y, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXIO => new V4ui(Y, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXII => new V4ui(Y, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXIX => new V4ui(Y, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXIY => new V4ui(Y, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXIZ => new V4ui(Y, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXXO => new V4ui(Y, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXXI => new V4ui(Y, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXXX => new V4ui(Y, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXXY => new V4ui(Y, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXXZ => new V4ui(Y, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXYO => new V4ui(Y, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXYI => new V4ui(Y, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXYX => new V4ui(Y, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXYY => new V4ui(Y, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXYZ => new V4ui(Y, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXZO => new V4ui(Y, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXZI => new V4ui(Y, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXZX => new V4ui(Y, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXZY => new V4ui(Y, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXZZ => new V4ui(Y, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYOO => new V4ui(Y, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYOI => new V4ui(Y, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYOX => new V4ui(Y, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYOY => new V4ui(Y, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYOZ => new V4ui(Y, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYIO => new V4ui(Y, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYII => new V4ui(Y, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYIX => new V4ui(Y, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYIY => new V4ui(Y, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYIZ => new V4ui(Y, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYXO => new V4ui(Y, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYXI => new V4ui(Y, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYXX => new V4ui(Y, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYXY => new V4ui(Y, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYXZ => new V4ui(Y, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYYO => new V4ui(Y, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYYI => new V4ui(Y, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYYX => new V4ui(Y, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYYY => new V4ui(Y, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYYZ => new V4ui(Y, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYZO => new V4ui(Y, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYZI => new V4ui(Y, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYZX => new V4ui(Y, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYZY => new V4ui(Y, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYZZ => new V4ui(Y, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZOO => new V4ui(Y, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZOI => new V4ui(Y, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZOX => new V4ui(Y, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZOY => new V4ui(Y, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZOZ => new V4ui(Y, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZIO => new V4ui(Y, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZII => new V4ui(Y, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZIX => new V4ui(Y, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZIY => new V4ui(Y, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZIZ => new V4ui(Y, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZXO => new V4ui(Y, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZXI => new V4ui(Y, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZXX => new V4ui(Y, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZXY => new V4ui(Y, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZXZ => new V4ui(Y, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZYO => new V4ui(Y, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZYI => new V4ui(Y, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZYX => new V4ui(Y, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZYY => new V4ui(Y, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZYZ => new V4ui(Y, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZZO => new V4ui(Y, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZZI => new V4ui(Y, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZZX => new V4ui(Y, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZZY => new V4ui(Y, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZZZ => new V4ui(Y, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOOO => new V4ui(Z, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOOI => new V4ui(Z, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOOX => new V4ui(Z, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOOY => new V4ui(Z, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOOZ => new V4ui(Z, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOIO => new V4ui(Z, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOII => new V4ui(Z, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOIX => new V4ui(Z, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOIY => new V4ui(Z, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOIZ => new V4ui(Z, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOXO => new V4ui(Z, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOXI => new V4ui(Z, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOXX => new V4ui(Z, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOXY => new V4ui(Z, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOXZ => new V4ui(Z, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOYO => new V4ui(Z, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOYI => new V4ui(Z, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOYX => new V4ui(Z, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOYY => new V4ui(Z, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOYZ => new V4ui(Z, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOZO => new V4ui(Z, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOZI => new V4ui(Z, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOZX => new V4ui(Z, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOZY => new V4ui(Z, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOZZ => new V4ui(Z, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIOO => new V4ui(Z, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIOI => new V4ui(Z, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIOX => new V4ui(Z, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIOY => new V4ui(Z, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIOZ => new V4ui(Z, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIIO => new V4ui(Z, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIII => new V4ui(Z, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIIX => new V4ui(Z, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIIY => new V4ui(Z, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIIZ => new V4ui(Z, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIXO => new V4ui(Z, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIXI => new V4ui(Z, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIXX => new V4ui(Z, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIXY => new V4ui(Z, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIXZ => new V4ui(Z, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIYO => new V4ui(Z, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIYI => new V4ui(Z, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIYX => new V4ui(Z, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIYY => new V4ui(Z, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIYZ => new V4ui(Z, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIZO => new V4ui(Z, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIZI => new V4ui(Z, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIZX => new V4ui(Z, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIZY => new V4ui(Z, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIZZ => new V4ui(Z, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXOO => new V4ui(Z, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXOI => new V4ui(Z, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXOX => new V4ui(Z, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXOY => new V4ui(Z, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXOZ => new V4ui(Z, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXIO => new V4ui(Z, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXII => new V4ui(Z, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXIX => new V4ui(Z, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXIY => new V4ui(Z, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXIZ => new V4ui(Z, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXXO => new V4ui(Z, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXXI => new V4ui(Z, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXXX => new V4ui(Z, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXXY => new V4ui(Z, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXXZ => new V4ui(Z, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXYO => new V4ui(Z, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXYI => new V4ui(Z, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXYX => new V4ui(Z, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXYY => new V4ui(Z, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXYZ => new V4ui(Z, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXZO => new V4ui(Z, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXZI => new V4ui(Z, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXZX => new V4ui(Z, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXZY => new V4ui(Z, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXZZ => new V4ui(Z, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYOO => new V4ui(Z, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYOI => new V4ui(Z, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYOX => new V4ui(Z, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYOY => new V4ui(Z, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYOZ => new V4ui(Z, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYIO => new V4ui(Z, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYII => new V4ui(Z, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYIX => new V4ui(Z, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYIY => new V4ui(Z, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYIZ => new V4ui(Z, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYXO => new V4ui(Z, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYXI => new V4ui(Z, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYXX => new V4ui(Z, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYXY => new V4ui(Z, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYXZ => new V4ui(Z, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYYO => new V4ui(Z, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYYI => new V4ui(Z, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYYX => new V4ui(Z, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYYY => new V4ui(Z, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYYZ => new V4ui(Z, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYZO => new V4ui(Z, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYZI => new V4ui(Z, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYZX => new V4ui(Z, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYZY => new V4ui(Z, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYZZ => new V4ui(Z, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZOO => new V4ui(Z, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZOI => new V4ui(Z, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZOX => new V4ui(Z, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZOY => new V4ui(Z, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZOZ => new V4ui(Z, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZIO => new V4ui(Z, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZII => new V4ui(Z, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZIX => new V4ui(Z, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZIY => new V4ui(Z, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZIZ => new V4ui(Z, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZXO => new V4ui(Z, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZXI => new V4ui(Z, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZXX => new V4ui(Z, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZXY => new V4ui(Z, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZXZ => new V4ui(Z, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZYO => new V4ui(Z, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZYI => new V4ui(Z, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZYX => new V4ui(Z, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZYY => new V4ui(Z, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZYZ => new V4ui(Z, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZZO => new V4ui(Z, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZZI => new V4ui(Z, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZZX => new V4ui(Z, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZZY => new V4ui(Z, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZZZ => new V4ui(Z, Z, Z, Z); #endregion #region IVector Members /// /// By using long indices, the IVector<double> interface is /// accessed. /// public double this[long i] { readonly get { return (double)this[(int)i]; } set { this[(int)i] = (uint)value; } } #endregion #region ISize3ui Members public readonly V3ui Size3ui { get { return this; } } #endregion #region IVector public readonly long Dim { get { return 3; } } public readonly object GetValue(long index) { return (object)this[(int)index]; } public void SetValue(object value, long index) { this[(int)index] = (uint)value; } #endregion } public class V3uiEqualityComparer : IEqualityComparer { public static V3uiEqualityComparer Default => new V3uiEqualityComparer(); #region IEqualityComparer Members public bool Equals(V3ui v0, V3ui v1) { return v0 == v1; } public int GetHashCode(V3ui v) { return v.GetHashCode(); } #endregion } public static partial class Fun { #region Min and Max /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Min(this V3ui a, V3ui b) { return new V3ui(Min(a.X, b.X), Min(a.Y, b.Y), Min(a.Z, b.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Min(this V3ui a, uint b) { return new V3ui(Min(a.X, b), Min(a.Y, b), Min(a.Z, b)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Min(this uint a, V3ui b) { return new V3ui(Min(a, b.X), Min(a, b.Y), Min(a, b.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Max(this V3ui a, V3ui b) { return new V3ui(Max(a.X, b.X), Max(a.Y, b.Y), Max(a.Z, b.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Max(this V3ui a, uint b) { return new V3ui(Max(a.X, b), Max(a.Y, b), Max(a.Z, b)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Max(this uint a, V3ui b) { return new V3ui(Max(a, b.X), Max(a, b.Y), Max(a, b.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Min(this V3ui a, V3ui b, V3ui c) { return new V3ui(Min(a.X, b.X, c.X), Min(a.Y, b.Y, c.Y), Min(a.Z, b.Z, c.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Max(this V3ui a, V3ui b, V3ui c) { return new V3ui(Max(a.X, b.X, c.X), Max(a.Y, b.Y, c.Y), Max(a.Z, b.Z, c.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Min(this V3ui a, V3ui b, V3ui c, V3ui d) { return new V3ui(Min(a.X, b.X, c.X, d.X), Min(a.Y, b.Y, c.Y, d.Y), Min(a.Z, b.Z, c.Z, d.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Max(this V3ui a, V3ui b, V3ui c, V3ui d) { return new V3ui(Max(a.X, b.X, c.X, d.X), Max(a.Y, b.Y, c.Y, d.Y), Max(a.Z, b.Z, c.Z, d.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Min(this V3ui x, params V3ui[] values) { return new V3ui(Min(x.X, values.Map(a => a.X)), Min(x.Y, values.Map(a => a.Y)), Min(x.Z, values.Map(a => a.Z))); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Max(this V3ui x, params V3ui[] values) { return new V3ui(Max(x.X, values.Map(a => a.X)), Max(x.Y, values.Map(a => a.Y)), Max(x.Z, values.Map(a => a.Z))); } #endregion #region Clamping /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Clamp(this V3ui x, V3ui a, V3ui b) { return new V3ui(Clamp(x.X, a.X, b.X), Clamp(x.Y, a.Y, b.Y), Clamp(x.Z, a.Z, b.Z)); } /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Clamp(this V3ui x, uint a, uint b) { return new V3ui(Clamp(x.X, a, b), Clamp(x.Y, a, b), Clamp(x.Z, a, b)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui ClampExcl(this V3ui x, V3ui a, V3ui b) { return new V3ui(ClampExcl(x.X, a.X, b.X), ClampExcl(x.Y, a.Y, b.Y), ClampExcl(x.Z, a.Z, b.Z)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui ClampExcl(this V3ui x, uint a, uint b) { return new V3ui(ClampExcl(x.X, a, b), ClampExcl(x.Y, a, b), ClampExcl(x.Z, a, b)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui ClampWrap(this V3ui x, V3ui a, V3ui b) { return new V3ui(ClampWrap(x.X, a.X, b.X), ClampWrap(x.Y, a.Y, b.Y), ClampWrap(x.Z, a.Z, b.Z)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui ClampWrap(this V3ui x, uint a, uint b) { return new V3ui(ClampWrap(x.X, a, b), ClampWrap(x.Y, a, b), ClampWrap(x.Z, a, b)); } /// /// Applies Fun.Saturate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Saturate(this V3ui x) { return new V3ui(Saturate(x.X), Saturate(x.Y), Saturate(x.Z)); } #endregion #region Multiply-Add /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui MultiplyAdd(V3ui x, V3ui y, V3ui z) { return new V3ui(MultiplyAdd(x.X, y.X, z.X), MultiplyAdd(x.Y, y.Y, z.Y), MultiplyAdd(x.Z, y.Z, z.Z)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui MultiplyAdd(V3ui x, uint y, V3ui z) { return new V3ui(MultiplyAdd(x.X, y, z.X), MultiplyAdd(x.Y, y, z.Y), MultiplyAdd(x.Z, y, z.Z)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui MultiplyAdd(uint x, V3ui y, V3ui z) { return new V3ui(MultiplyAdd(x, y.X, z.X), MultiplyAdd(x, y.Y, z.Y), MultiplyAdd(x, y.Z, z.Z)); } #endregion #region Roots /// /// Applies Fun.Sqrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Sqrt(this V3ui x) { return new V3d(Sqrt(x.X), Sqrt(x.Y), Sqrt(x.Z)); } /// /// Applies Fun.Cbrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Cbrt(this V3ui x) { return new V3d(Cbrt(x.X), Cbrt(x.Y), Cbrt(x.Z)); } #endregion #region Square /// /// Applies Fun.Square to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Square(this V3ui x) { return new V3ui(Square(x.X), Square(x.Y), Square(x.Z)); } #endregion #region Power /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Pown(this V3ui x, V3ui y) { return new V3ui(Pown(x.X, y.X), Pown(x.Y, y.Y), Pown(x.Z, y.Z)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Pown(this V3ui x, uint y) { return new V3ui(Pown(x.X, y), Pown(x.Y, y), Pown(x.Z, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Pown(this uint x, V3ui y) { return new V3ui(Pown(x, y.X), Pown(x, y.Y), Pown(x, y.Z)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Pown(this V3ui x, V3i y) { return new V3ui(Pown(x.X, y.X), Pown(x.Y, y.Y), Pown(x.Z, y.Z)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Pown(this V3ui x, int y) { return new V3ui(Pown(x.X, y), Pown(x.Y, y), Pown(x.Z, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Pown(this uint x, V3i y) { return new V3ui(Pown(x, y.X), Pown(x, y.Y), Pown(x, y.Z)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Pow(this V3ui x, V3f y) { return new V3f(Pow(x.X, y.X), Pow(x.Y, y.Y), Pow(x.Z, y.Z)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Pow(this V3ui x, float y) { return new V3f(Pow(x.X, y), Pow(x.Y, y), Pow(x.Z, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Pow(this uint x, V3f y) { return new V3f(Pow(x, y.X), Pow(x, y.Y), Pow(x, y.Z)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Pow(this V3ui x, V3d y) { return new V3d(Pow(x.X, y.X), Pow(x.Y, y.Y), Pow(x.Z, y.Z)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Pow(this V3ui x, double y) { return new V3d(Pow(x.X, y), Pow(x.Y, y), Pow(x.Z, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Pow(this uint x, V3d y) { return new V3d(Pow(x, y.X), Pow(x, y.Y), Pow(x, y.Z)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Power(this V3ui x, V3f y) { return new V3f(Power(x.X, y.X), Power(x.Y, y.Y), Power(x.Z, y.Z)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Power(this V3ui x, float y) { return new V3f(Power(x.X, y), Power(x.Y, y), Power(x.Z, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Power(this uint x, V3f y) { return new V3f(Power(x, y.X), Power(x, y.Y), Power(x, y.Z)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Power(this V3ui x, V3d y) { return new V3d(Power(x.X, y.X), Power(x.Y, y.Y), Power(x.Z, y.Z)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Power(this V3ui x, double y) { return new V3d(Power(x.X, y), Power(x.Y, y), Power(x.Z, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Power(this uint x, V3d y) { return new V3d(Power(x, y.X), Power(x, y.Y), Power(x, y.Z)); } #endregion #region Exp and Log /// /// Applies Fun.Exp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Exp(this V3ui x) { return new V3d(Exp(x.X), Exp(x.Y), Exp(x.Z)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log(this V3ui x) { return new V3d(Log(x.X), Log(x.Y), Log(x.Z)); } /// /// Applies Fun.Log2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log2(this V3ui x) { return new V3d(Log2(x.X), Log2(x.Y), Log2(x.Z)); } /// /// Applies Fun.Log2Int to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Log2Int(this V3ui x) { return new V3i(Log2Int(x.X), Log2Int(x.Y), Log2Int(x.Z)); } /// /// Applies Fun.Log10 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log10(this V3ui x) { return new V3d(Log10(x.X), Log10(x.Y), Log10(x.Z)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log(this V3ui x, double basis) { return new V3d(Log(x.X, basis), Log(x.Y, basis), Log(x.Z, basis)); } #endregion #region Step functions /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Step(this V3ui x, V3ui edge) { return new V3ui(Step(x.X, edge.X), Step(x.Y, edge.Y), Step(x.Z, edge.Z)); } /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Step(this V3ui x, uint edge) { return new V3ui(Step(x.X, edge), Step(x.Y, edge), Step(x.Z, edge)); } #endregion #region Interpolation /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Lerp(this float t, V3ui a, V3ui b) { return new V3ui(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y), Lerp(t, a.Z, b.Z)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Lerp(this V3f t, V3ui a, V3ui b) { return new V3ui(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y), Lerp(t.Z, a.Z, b.Z)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Lerp(this double t, V3ui a, V3ui b) { return new V3ui(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y), Lerp(t, a.Z, b.Z)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui Lerp(this V3d t, V3ui a, V3ui b) { return new V3ui(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y), Lerp(t.Z, a.Z, b.Z)); } /// /// Applies Fun.InvLerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvLerp(this V3ui y, V3ui a, V3ui b) { return new V3d(InvLerp(y.X, a.X, b.X), InvLerp(y.Y, a.Y, b.Y), InvLerp(y.Z, a.Z, b.Z)); } #endregion #region Common Divisor and Multiple /// /// Applies Fun.GreatestCommonDivisor to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui GreatestCommonDivisor(this V3ui a, V3ui b) { return new V3ui(GreatestCommonDivisor(a.X, b.X), GreatestCommonDivisor(a.Y, b.Y), GreatestCommonDivisor(a.Z, b.Z)); } /// /// Applies Fun.LeastCommonMultiple to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui LeastCommonMultiple(this V3ui a, V3ui b) { return new V3ui(LeastCommonMultiple(a.X, b.X), LeastCommonMultiple(a.Y, b.Y), LeastCommonMultiple(a.Z, b.Z)); } #endregion #region Floating point bits /// /// Applies Fun.FloatFromUnsignedBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FloatFromUnsignedBits(this V3ui x) { return new V3f(FloatFromUnsignedBits(x.X), FloatFromUnsignedBits(x.Y), FloatFromUnsignedBits(x.Z)); } #endregion #region ApproximateEquals /// /// Returns whether the given vectors are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V3ui a, V3ui b, uint tolerance) { return ApproximateEquals(a.X, b.X, tolerance) && ApproximateEquals(a.Y, b.Y, tolerance) && ApproximateEquals(a.Z, b.Z, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this V3ui v, uint epsilon) => Vec.AllTiny(v, epsilon); #endregion } /// /// Contains static methods /// public static partial class Vec { #region Length /// /// Returns the squared length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint LengthSquared(V3ui v) => v.LengthSquared; /// /// Returns the length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Length(V3ui v) => v.Length; #endregion #region Normalize /// /// Returns a normalized copy of this vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Normalized(V3ui v) => v.Normalized; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Norm1(V3ui v) => v.Norm1; /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(V3ui v) => v.Norm2; /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint NormMax(V3ui v) => v.NormMax; /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint NormMin(V3ui v) => v.NormMin; /// /// Gets the p-norm. This is calculated as the p-th root of (|x|^n + |y|^n + ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this V3ui v, double p) { return ( Fun.Abs(v.X).Pow(p) + Fun.Abs(v.Y).Pow(p) + Fun.Abs(v.Z).Pow(p)).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the squared distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint DistanceSquared(this V3ui a, V3ui b) => Fun.Square((a.X < b.X) ? (b.X - a.X) : (a.X - b.X)) + Fun.Square((a.Y < b.Y) ? (b.Y - a.Y) : (a.Y - b.Y)) + Fun.Square((a.Z < b.Z) ? (b.Z - a.Z) : (a.Z - b.Z)); /// /// Returns the distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V3ui a, V3ui b) => Fun.Sqrt(DistanceSquared(a, b)); /// /// Returns the Manhatten (or 1-) distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Distance1(this V3ui a, V3ui b) => ((a.X < b.X) ? (b.X - a.X) : (a.X - b.X)) + ((a.Y < b.Y) ? (b.Y - a.Y) : (a.Y - b.Y)) + ((a.Z < b.Z) ? (b.Z - a.Z) : (a.Z - b.Z)); /// /// Returns the p-distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V3ui a, V3ui b, double p) => (((a.X < b.X) ? (b.X - a.X) : (a.X - b.X)).Pow(p) + ((a.Y < b.Y) ? (b.Y - a.Y) : (a.Y - b.Y)).Pow(p) + ((a.Z < b.Z) ? (b.Z - a.Z) : (a.Z - b.Z)).Pow(p)).Pow(1 / p); /// /// Returns the maximal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint DistanceMax(this V3ui a, V3ui b) => Fun.Max(((a.X < b.X) ? (b.X - a.X) : (a.X - b.X)), ((a.Y < b.Y) ? (b.Y - a.Y) : (a.Y - b.Y)), ((a.Z < b.Z) ? (b.Z - a.Z) : (a.Z - b.Z))); /// /// Returns the minimal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint DistanceMin(this V3ui a, V3ui b) => Fun.Min(((a.X < b.X) ? (b.X - a.X) : (a.X - b.X)), ((a.Y < b.Y) ? (b.Y - a.Y) : (a.Y - b.Y)), ((a.Z < b.Z) ? (b.Z - a.Z) : (a.Z - b.Z))); /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V3ui query, V3ui p0, V3ui p1) { return DistanceToLine((V3d) query, (V3d) p0, (V3d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V3ui query, V3ui p0, V3ui p1) { return DistanceToInfiniteLine((V3d) query, (V3d) p0, (V3d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V3ui query, V3ui p0, V3ui p1, out double t) { return DistanceToLine((V3d) query, (V3d) p0, (V3d) p1, out t); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V3ui query, V3ui p0, V3ui p1, out double t) { return DistanceToInfiniteLine((V3d) query, (V3d) p0, (V3d) p1, out t); } #endregion #region Operations /// /// Returns the dot product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Dot(this V3ui a, V3ui b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DirFlags DirFlags(this V3ui v) { DirFlags flags = Aardbase.DirFlags.None; if (v.X > 0) flags |= Aardbase.DirFlags.PositiveX; if (v.X < 0) flags |= Aardbase.DirFlags.NegativeX; if (v.Y > 0) flags |= Aardbase.DirFlags.PositiveY; if (v.Y < 0) flags |= Aardbase.DirFlags.NegativeY; if (v.Z > 0) flags |= Aardbase.DirFlags.PositiveZ; if (v.Z < 0) flags |= Aardbase.DirFlags.NegativeZ; return flags; } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V3ui a, V3ui b) { return (a.X < b.X && a.Y < b.Y && a.Z < b.Z); } /// /// Returns whether ALL elements of v are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V3ui v, uint s) { return (v.X < s && v.Y < s && v.Z < s); } /// /// Returns whether a is Smaller ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(uint s, V3ui v) { return (s < v.X && s < v.Y && s < v.Z); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V3ui a, V3ui b) { return (a.X < b.X || a.Y < b.Y || a.Z < b.Z); } /// /// Returns whether AT LEAST ONE element of v is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V3ui v, uint s) { return (v.X < s || v.Y < s || v.Z < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(uint s, V3ui v) { return (s < v.X || s < v.Y || s < v.Z); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V3ui a, V3ui b) { return (a.X > b.X && a.Y > b.Y && a.Z > b.Z); } /// /// Returns whether ALL elements of v are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V3ui v, uint s) { return (v.X > s && v.Y > s && v.Z > s); } /// /// Returns whether a is Greater ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(uint s, V3ui v) { return (s > v.X && s > v.Y && s > v.Z); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V3ui a, V3ui b) { return (a.X > b.X || a.Y > b.Y || a.Z > b.Z); } /// /// Returns whether AT LEAST ONE element of v is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V3ui v, uint s) { return (v.X > s || v.Y > s || v.Z > s); } /// /// Returns whether a is Greater AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(uint s, V3ui v) { return (s > v.X || s > v.Y || s > v.Z); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V3ui a, V3ui b) { return (a.X <= b.X && a.Y <= b.Y && a.Z <= b.Z); } /// /// Returns whether ALL elements of v are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V3ui v, uint s) { return (v.X <= s && v.Y <= s && v.Z <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(uint s, V3ui v) { return (s <= v.X && s <= v.Y && s <= v.Z); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V3ui a, V3ui b) { return (a.X <= b.X || a.Y <= b.Y || a.Z <= b.Z); } /// /// Returns whether AT LEAST ONE element of v is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V3ui v, uint s) { return (v.X <= s || v.Y <= s || v.Z <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(uint s, V3ui v) { return (s <= v.X || s <= v.Y || s <= v.Z); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V3ui a, V3ui b) { return (a.X >= b.X && a.Y >= b.Y && a.Z >= b.Z); } /// /// Returns whether ALL elements of v are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V3ui v, uint s) { return (v.X >= s && v.Y >= s && v.Z >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(uint s, V3ui v) { return (s >= v.X && s >= v.Y && s >= v.Z); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V3ui a, V3ui b) { return (a.X >= b.X || a.Y >= b.Y || a.Z >= b.Z); } /// /// Returns whether AT LEAST ONE element of v is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V3ui v, uint s) { return (v.X >= s || v.Y >= s || v.Z >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(uint s, V3ui v) { return (s >= v.X || s >= v.Y || s >= v.Z); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V3ui a, V3ui b) { return (a.X == b.X && a.Y == b.Y && a.Z == b.Z); } /// /// Returns whether ALL elements of v are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V3ui v, uint s) { return (v.X == s && v.Y == s && v.Z == s); } /// /// Returns whether a is Equal ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(uint s, V3ui v) { return (s == v.X && s == v.Y && s == v.Z); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V3ui a, V3ui b) { return (a.X == b.X || a.Y == b.Y || a.Z == b.Z); } /// /// Returns whether AT LEAST ONE element of v is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V3ui v, uint s) { return (v.X == s || v.Y == s || v.Z == s); } /// /// Returns whether a is Equal AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(uint s, V3ui v) { return (s == v.X || s == v.Y || s == v.Z); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V3ui a, V3ui b) { return (a.X != b.X && a.Y != b.Y && a.Z != b.Z); } /// /// Returns whether ALL elements of v are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V3ui v, uint s) { return (v.X != s && v.Y != s && v.Z != s); } /// /// Returns whether a is Different ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(uint s, V3ui v) { return (s != v.X && s != v.Y && s != v.Z); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V3ui a, V3ui b) { return (a.X != b.X || a.Y != b.Y || a.Z != b.Z); } /// /// Returns whether AT LEAST ONE element of v is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V3ui v, uint s) { return (v.X != s || v.Y != s || v.Z != s); } /// /// Returns whether a is Different AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(uint s, V3ui v) { return (s != v.X || s != v.Y || s != v.Z); } /// /// Compare x-coordinate before y-coordinate, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this V3ui v0, V3ui v1) { if (v0.X < v1.X) return -1; if (v0.X > v1.X) return +1; if (v0.Y < v1.Y) return -1; if (v0.Y > v1.Y) return +1; if (v0.Z < v1.Z) return -1; if (v0.Z > v1.Z) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint MinElement(V3ui v) => v.MinElement; /// /// Returns the maximum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint MaxElement(V3ui v) => v.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this V3ui v, uint epsilon) => v.X.IsTiny(epsilon) || v.Y.IsTiny(epsilon) || v.Z.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this V3ui v, uint epsilon) => v.X.IsTiny(epsilon) && v.Y.IsTiny(epsilon) && v.Z.IsTiny(epsilon); #endregion #region ArrayExtensions public static int IndexOfClosestPoint(this V3ui[] pointArray, V3ui point) { var bestDist = DistanceSquared(point, pointArray[0]); int bestIndex = 0; int count = pointArray.Length; for (int i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this V3ui[] array, int start, int count, V3ui point) { var bestDist = DistanceSquared(point, array[start]); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this T[] array, int start, int count, Func pointSelector, V3ui point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint(this V3ui[] pointArray, V3ui point) { var bestDist = DistanceSquared(point, pointArray[0]); long bestIndex = 0; long count = pointArray.LongLength; for (long i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this V3ui[] array, long start, long count, V3ui point) { var bestDist = DistanceSquared(point, array[start]); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this T[] array, long start, long count, Func pointSelector, V3ui point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static int IndexOfMinX(this V3ui[] vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static long LongIndexOfMinX(this V3ui[] vectorArray, long count = 0) { var minimum = vectorArray[0].X; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static int IndexOfMaxX(this V3ui[] vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static long LongIndexOfMaxX(this V3ui[] vectorArray, long count = 0) { var maximum = vectorArray[0].X; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static int IndexOfMinY(this V3ui[] vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static long LongIndexOfMinY(this V3ui[] vectorArray, long count = 0) { var minimum = vectorArray[0].Y; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static int IndexOfMaxY(this V3ui[] vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static long LongIndexOfMaxY(this V3ui[] vectorArray, long count = 0) { var maximum = vectorArray[0].Y; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static int IndexOfMinZ(this V3ui[] vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static long LongIndexOfMinZ(this V3ui[] vectorArray, long count = 0) { var minimum = vectorArray[0].Z; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static int IndexOfMaxZ(this V3ui[] vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static long LongIndexOfMaxZ(this V3ui[] vectorArray, long count = 0) { var maximum = vectorArray[0].Z; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the list. /// public static int IndexOfMinX(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the list. /// public static int IndexOfMaxX(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the list. /// public static int IndexOfMinY(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the list. /// public static int IndexOfMaxY(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the list. /// public static int IndexOfMinZ(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the list. /// public static int IndexOfMaxZ(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the array of the index-th coordinate of each vector. /// public static uint[] CopyCoord(this V3ui[] self, int index) { switch (index) { case 0: return self.Map(v => v.X); case 1: return self.Map(v => v.Y); case 2: return self.Map(v => v.Z); default: throw new IndexOutOfRangeException(); } } #endregion } public static class IRandomUniformV3uiExtensions { #region IRandomUniform extensions for V3ui /// /// Uses UniformUInt() to generate the elements of a V3ui vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui UniformV3ui(this IRandomUniform rnd) { return new V3ui(rnd.UniformUInt(), rnd.UniformUInt(), rnd.UniformUInt()); } #endregion } #endregion #region V3l [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct V3l : IVector, ISize3l, IFormattable, IEquatable { [DataMember] public long X; [DataMember] public long Y; [DataMember] public long Z; #region Constructors /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(int x, int y, int z) { X = (long)x; Y = (long)y; Z = (long)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(int v) { X = (long)v; Y = (long)v; Z = (long)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(int[] a) { X = (long)a[0]; Y = (long)a[1]; Z = (long)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(int[] a, int start) { X = (long)a[start + 0]; Y = (long)a[start + 1]; Z = (long)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(int a, V2i b) { X = (long)a; Y = (long)b.X; Z = (long)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V2i a, int b) { X = (long)a.X; Y = (long)a.Y; Z = (long)b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(uint x, uint y, uint z) { X = (long)x; Y = (long)y; Z = (long)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(uint v) { X = (long)v; Y = (long)v; Z = (long)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(uint[] a) { X = (long)a[0]; Y = (long)a[1]; Z = (long)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(uint[] a, int start) { X = (long)a[start + 0]; Y = (long)a[start + 1]; Z = (long)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(uint a, V2ui b) { X = (long)a; Y = (long)b.X; Z = (long)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V2ui a, uint b) { X = (long)a.X; Y = (long)a.Y; Z = (long)b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(long x, long y, long z) { X = x; Y = y; Z = z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(long v) { X = v; Y = v; Z = v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(long[] a) { X = a[0]; Y = a[1]; Z = a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(long[] a, int start) { X = a[start + 0]; Y = a[start + 1]; Z = a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(long a, V2l b) { X = a; Y = b.X; Z = b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V2l a, long b) { X = a.X; Y = a.Y; Z = b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(float x, float y, float z) { X = (long)x; Y = (long)y; Z = (long)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(float v) { X = (long)v; Y = (long)v; Z = (long)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(float[] a) { X = (long)a[0]; Y = (long)a[1]; Z = (long)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(float[] a, int start) { X = (long)a[start + 0]; Y = (long)a[start + 1]; Z = (long)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(float a, V2f b) { X = (long)a; Y = (long)b.X; Z = (long)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V2f a, float b) { X = (long)a.X; Y = (long)a.Y; Z = (long)b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(double x, double y, double z) { X = (long)x; Y = (long)y; Z = (long)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(double v) { X = (long)v; Y = (long)v; Z = (long)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(double[] a) { X = (long)a[0]; Y = (long)a[1]; Z = (long)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(double[] a, int start) { X = (long)a[start + 0]; Y = (long)a[start + 1]; Z = (long)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(double a, V2d b) { X = (long)a; Y = (long)b.X; Z = (long)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V2d a, double b) { X = (long)a.X; Y = (long)a.Y; Z = (long)b; } /// /// Creates a vector from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(Func index_fun) { X = index_fun(0); Y = index_fun(1); Z = index_fun(2); } /// /// Creates a vector from a general vector implementing the IVector<long> interface. /// The caller has to verify that the dimension of is at least 3. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(IVector v) : this(v[0], v[1], v[2]) { } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V2i v) { X = (long)v.X; Y = (long)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V2ui v) { X = (long)v.X; Y = (long)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V2l v) { X = v.X; Y = v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V2f v) { X = (long)v.X; Y = (long)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V2d v) { X = (long)v.X; Y = (long)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V3i v) { X = (long)v.X; Y = (long)v.Y; Z = (long)v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V3ui v) { X = (long)v.X; Y = (long)v.Y; Z = (long)v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V3l v) { X = v.X; Y = v.Y; Z = v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V3f v) { X = (long)v.X; Y = (long)v.Y; Z = (long)v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V3d v) { X = (long)v.X; Y = (long)v.Y; Z = (long)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V4i v) { X = (long)v.X; Y = (long)v.Y; Z = (long)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V4ui v) { X = (long)v.X; Y = (long)v.Y; Z = (long)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V4l v) { X = v.X; Y = v.Y; Z = v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V4f v) { X = (long)v.X; Y = (long)v.Y; Z = (long)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(V4d v) { X = (long)v.X; Y = (long)v.Y; Z = (long)v.Z; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(C3b c) { X = (long)(c.R); Y = (long)(c.G); Z = (long)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(C3us c) { X = (long)(c.R); Y = (long)(c.G); Z = (long)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(C3ui c) { X = (long)(c.R); Y = (long)(c.G); Z = (long)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(C4b c) { X = (long)(c.R); Y = (long)(c.G); Z = (long)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(C4us c) { X = (long)(c.R); Y = (long)(c.G); Z = (long)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3l(C4ui c) { X = (long)(c.R); Y = (long)(c.G); Z = (long)(c.B); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(V2i v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(V2ui v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(V2l v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(V2f v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(V2d v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(V3i v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(V3ui v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(V3f v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(V3d v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(V4i v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(V4ui v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(V4l v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(V4f v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(V4d v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToV2i() => (V2i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui ToV2ui() => (V2ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f ToV2f() => (V2f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d ToV2d() => (V2d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int[](V3l v) => new int[] { (int)v.X, (int)v.Y, (int)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(int[] v) => new V3l((long)v[0], (long)v[1], (long)v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](V3l v) => new uint[] { (uint)v.X, (uint)v.Y, (uint)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(uint[] v) => new V3l((long)v[0], (long)v[1], (long)v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long[](V3l v) => new long[] { v.X, v.Y, v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(long[] v) => new V3l(v[0], v[1], v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](V3l v) => new float[] { (float)v.X, (float)v.Y, (float)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(float[] v) => new V3l((long)v[0], (long)v[1], (long)v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](V3l v) => new double[] { (double)v.X, (double)v.Y, (double)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(double[] v) => new V3l((long)v[0], (long)v[1], (long)v[2]); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(C3b v) => new V3l(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(C3us v) => new V3l(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(C3ui v) => new V3l(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(C4b v) => new V3l(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(C4us v) => new V3l(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3l(C4ui v) => new V3l(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i Copy(Func element_fun) => new V3i(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i Copy(Func element_index_fun) => new V3i(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(int[] array, int start) { array[start + 0] = (int)X; array[start + 1] = (int)Y; array[start + 2] = (int)Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui Copy(Func element_fun) => new V3ui(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui Copy(Func element_index_fun) => new V3ui(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(uint[] array, int start) { array[start + 0] = (uint)X; array[start + 1] = (uint)Y; array[start + 2] = (uint)Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l Copy(Func element_fun) => new V3l(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l Copy(Func element_index_fun) => new V3l(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(long[] array, int start) { array[start + 0] = X; array[start + 1] = Y; array[start + 2] = Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f Copy(Func element_fun) => new V3f(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f Copy(Func element_index_fun) => new V3f(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(float[] array, int start) { array[start + 0] = (float)X; array[start + 1] = (float)Y; array[start + 2] = (float)Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d Copy(Func element_fun) => new V3d(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d Copy(Func element_index_fun) => new V3d(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(double[] array, int start) { array[start + 0] = (double)X; array[start + 1] = (double)Y; array[start + 2] = (double)Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(X); array[start + 1] = element_fun(Y); array[start + 2] = element_fun(Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(X, 0); array[start + 1] = element_index_fun(Y, 1); array[start + 2] = element_index_fun(Z, 2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly long[] ToArray() => new long[] { X, Y, Z }; #endregion #region Properties and Indexers /// /// Property for the field X. /// Useful when properties are required, but the field X is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public long P_X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value; } } /// /// Property for the field Y. /// Useful when properties are required, but the field Y is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public long P_Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Y = value; } } /// /// Property for the field Z. /// Useful when properties are required, but the field Z is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public long P_Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Z = value; } } /// /// Enumerates all elements of this vector. /// public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return X; yield return Y; yield return Z; } } /// /// Gets or sets element with given index. /// public unsafe long this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (long* ptr = &X) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (long* ptr = &X) { ptr[index] = value; } } } /// /// Returns the index of the largest dimension of the vector. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X >= Y ? (X >= Z ? 0 : 2) : (Y >= Z ? 1 : 2); } } /// /// Returns the index of the smallest dimension of the vector. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X <= Y ? (X <= Z ? 0 : 2) : (Y <= Z ? 1 : 2); } } /// /// Returns the minimum element of the vector. /// public readonly long MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(X, Y, Z); } /// /// Returns the maximum element of the vector. /// public readonly long MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(X, Y, Z); } #endregion #region Constants /// /// Number of elements in this vector. /// public const int Dimension = 3; /// /// All elements zero. /// public static V3l Zero { get { return new V3l(0, 0, 0); } } /// /// All elements one. /// public static V3l One { get { return new V3l(1, 1, 1); } } /// /// All elements set to maximum possible value. /// public static V3l MaxValue { get { return new V3l(Constant.ParseableMaxValue, Constant.ParseableMaxValue, Constant.ParseableMaxValue); } } /// /// All elements set to minimum possible value. /// public static V3l MinValue { get { return new V3l(Constant.ParseableMinValue, Constant.ParseableMinValue, Constant.ParseableMinValue); } } /// /// Normalized X-axis. /// public static V3l XAxis { get { return new V3l(1, 0, 0); } } /// /// Normalized Y-axis. /// public static V3l YAxis { get { return new V3l(0, 1, 0); } } /// /// Normalized Z-axis. /// public static V3l ZAxis { get { return new V3l(0, 0, 1); } } /// /// An array of accessor functions for the coordinates of the vector. /// public static readonly Func[] SelectorArray = new Func[] { v => v.X, v => v.Y, v => v.Z }; /// /// Element getter function. /// public static readonly Func Getter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref V3l v, int i, long s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; default: throw new IndexOutOfRangeException(); } }; /// /// Element getter function with long index. /// public static readonly Func LongGetter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action with long index. /// public static readonly ActionRefValVal LongSetter = (ref V3l v, long i, long s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Static factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l FromV3i(V3i v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l FromV3ui(V3ui v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l FromV3f(V3f v) => new V3l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l FromV3d(V3d v) => new V3l(v); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l FromC3b(C3b c) => new V3l(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l FromC3us(C3us c) => new V3l(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l FromC3ui(C3ui c) => new V3l(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l FromC4b(C4b c) => new V3l(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l FromC4us(C4us c) => new V3l(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l FromC4ui(C4ui c) => new V3l(c); #endregion #region Norms /// /// Returns the squared length of the vector. /// public readonly long LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X * X + Y * Y + Z * Z ; } } /// /// Returns the length of the vector. /// public readonly double Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z ); } } /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// public readonly long Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Abs(X) + Fun.Abs(Y) + Fun.Abs(Z); } } /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z); } } /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// public readonly long NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z)); } } /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// public readonly long NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z)); } } /// /// Returns a normalized copy of this vector. /// public readonly V3d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Length; if (s == 0) return V3d.Zero; s = 1 / s; return new V3d(X * s, Y * s, Z * s); } } #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Abs(V3l v) => v.Abs(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l LinearInterp(float t, V3l a, V3l b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l LinearInterp(V3f t, V3l a, V3l b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l LinearInterp(double t, V3l a, V3l b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l LinearInterp(V3d t, V3l a, V3l b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Min(V3l v0, V3l v1) => Fun.Min(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Min(V3l v, long x) => Fun.Min(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Max(V3l v0, V3l v1) => Fun.Max(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Max(V3l v, long x) => Fun.Max(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Saturate(V3l v) => Fun.Saturate(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l DivideByInt(V3l v, int x) => v / x; #endregion #region Operations /// /// Sets the elements of a vector to the given int elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(int x, int y, int z) { X = (long)x; Y = (long)y; Z = (long)z; } /// /// Sets the elements of a vector to the given uint elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(uint x, uint y, uint z) { X = (long)x; Y = (long)y; Z = (long)z; } /// /// Sets the elements of a vector to the given long elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(long x, long y, long z) { X = x; Y = y; Z = z; } /// /// Sets the elements of a vector to the given float elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(float x, float y, float z) { X = (long)x; Y = (long)y; Z = (long)z; } /// /// Sets the elements of a vector to the given double elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(double x, double y, double z) { X = (long)x; Y = (long)y; Z = (long)z; } /// /// Returns a negated copy of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator -(V3l v) => new V3l(-v.X, -v.Y, -v.Z); /// /// Returns the component-wise bitwise complement of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator ~(V3l v) => new V3l(~v.X, ~v.Y, ~v.Z); /// /// Returns the component-wise sum of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator +(V3l a, V3l b) => new V3l(a.X + b.X, a.Y + b.Y, a.Z + b.Z); /// /// Returns the component-wise sum of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator +(V3l v, long s) => new V3l(v.X + s, v.Y + s, v.Z + s); /// /// Returns the component-wise sum of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator +(long s, V3l v) => new V3l(s + v.X, s + v.Y, s + v.Z); /// /// Returns the component-wise difference of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator -(V3l a, V3l b) => new V3l(a.X - b.X, a.Y - b.Y, a.Z - b.Z); /// /// Returns the component-wise difference of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator -(V3l v, long s) => new V3l(v.X - s, v.Y - s, v.Z - s); /// /// Returns the component-wise difference of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator -(long s, V3l v) => new V3l(s - v.X, s - v.Y, s - v.Z); /// /// Returns the component-wise product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator *(V3l a, V3l b) => new V3l(a.X * b.X, a.Y * b.Y, a.Z * b.Z); /// /// Returns the component-wise product of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator *(V3l v, long s) => new V3l(v.X * s, v.Y * s, v.Z * s); /// /// Returns the component-wise product of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator *(long s, V3l v) => new V3l(s * v.X, s * v.Y, s * v.Z); /// /// Returns the component-wise fraction of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator /(V3l a, V3l b) => new V3l(a.X / b.X, a.Y / b.Y, a.Z / b.Z); /// /// Returns the component-wise fraction of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator /(V3l v, long s) => new V3l(v.X / s, v.Y / s, v.Z / s); /// /// Returns the component-wise fraction of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator /(long s, V3l v) => new V3l(s / v.X, s / v.Y, s / v.Z); /// /// Returns the component-wise remainder of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator %(V3l a, V3l b) => new V3l(a.X % b.X, a.Y % b.Y, a.Z % b.Z); /// /// Returns the component-wise remainder of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator %(V3l v, long s) => new V3l(v.X % s, v.Y % s, v.Z % s); /// /// Returns the component-wise remainder of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator %(long s, V3l v) => new V3l(s % v.X, s % v.Y, s % v.Z); /// /// Returns the component-wise bitwise and of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator &(V3l a, V3l b) => new V3l(a.X & b.X, a.Y & b.Y, a.Z & b.Z); /// /// Returns the component-wise bitwise and of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator &(V3l v, long s) => new V3l(v.X & s, v.Y & s, v.Z & s); /// /// Returns the component-wise bitwise and of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator &(long s, V3l v) => new V3l(s & v.X, s & v.Y, s & v.Z); /// /// Returns the component-wise bitwise or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator |(V3l a, V3l b) => new V3l(a.X | b.X, a.Y | b.Y, a.Z | b.Z); /// /// Returns the component-wise bitwise or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator |(V3l v, long s) => new V3l(v.X | s, v.Y | s, v.Z | s); /// /// Returns the component-wise bitwise or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator |(long s, V3l v) => new V3l(s | v.X, s | v.Y, s | v.Z); /// /// Returns the component-wise bitwise exclusive or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator ^(V3l a, V3l b) => new V3l(a.X ^ b.X, a.Y ^ b.Y, a.Z ^ b.Z); /// /// Returns the component-wise bitwise exclusive or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator ^(V3l v, long s) => new V3l(v.X ^ s, v.Y ^ s, v.Z ^ s); /// /// Returns the component-wise bitwise exclusive or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator ^(long s, V3l v) => new V3l(s ^ v.X, s ^ v.Y, s ^ v.Z); /// /// Returns the component-wise left bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator <<(V3l v, int s) => new V3l(v.X << s, v.Y << s, v.Z << s); /// /// Returns the component-wise right bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l operator >>(V3l v, int s) => new V3l(v.X >> s, v.Y >> s, v.Z >> s); /// Attention: NEVER implement operators <, <=, >=, >, /// since these are not defined in a Vector space. /// Use AllSmaller() and similar comparators! #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V3l a, V3l b) { return a.X == b.X && a.Y == b.Y && a.Z == b.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V3l v, long s) { return v.X == s && v.Y == s && v.Z == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(long s, V3l v) { return s == v.X && s == v.Y && s == v.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V3l a, V3l b) { return a.X != b.X || a.Y != b.Y || a.Z != b.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V3l v, long s) { return v.X != s || v.Y != s || v.Z != s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(long s, V3l v) { return s != v.X || s != v.Y || s != v.Z; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(V3l other) { return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z); } #endregion #region Overrides public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + X.ToString(format, fp) + between + Y.ToString(format, fp) + between + Z.ToString(format, fp) + end; } public override readonly int GetHashCode() { return HashCode.GetCombined(X, Y, Z); } public override readonly bool Equals(object other) => (other is V3l o) ? Equals(o) : false; public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + X.ToString(null, CultureInfo.InvariantCulture) + ", " + Y.ToString(null, CultureInfo.InvariantCulture) + ", " + Z.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Parsing public static V3l Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new V3l( long.Parse(x[0], CultureInfo.InvariantCulture), long.Parse(x[1], CultureInfo.InvariantCulture), long.Parse(x[2], CultureInfo.InvariantCulture) ); } public static V3l Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, V3l.Setter); } public static V3l Parse(Text t, int bracketLevel) { return t.NestedBracketSplit(bracketLevel, Text.Parse, V3l.Setter); } #endregion #region Swizzle Methods [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l OX => new V2l(0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l OY => new V2l(0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l OZ => new V2l(0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l IX => new V2l(1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l IY => new V2l(1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l IZ => new V2l(1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l NX => new V2l(-1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l NY => new V2l(-1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l NZ => new V2l(-1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l XO => new V2l(X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l XI => new V2l(X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l XN => new V2l(X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l XX => new V2l(X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l XY { readonly get => new V2l(X, Y); set { X = value.X; Y = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l XZ { readonly get => new V2l(X, Z); set { X = value.X; Z = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l YO => new V2l(Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l YI => new V2l(Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l YN => new V2l(Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l YX { readonly get => new V2l(Y, X); set { Y = value.X; X = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l YY => new V2l(Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l YZ { readonly get => new V2l(Y, Z); set { Y = value.X; Z = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l ZO => new V2l(Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l ZI => new V2l(Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l ZN => new V2l(Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l ZX { readonly get => new V2l(Z, X); set { Z = value.X; X = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l ZY { readonly get => new V2l(Z, Y); set { Z = value.X; Y = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l ZZ => new V2l(Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l OOO => new V3l(0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l OOI => new V3l(0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l OON => new V3l(0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OOX => new V3l(0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OOY => new V3l(0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OOZ => new V3l(0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l OIO => new V3l(0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l OII => new V3l(0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l OPN => new V3l(0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OIX => new V3l(0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OIY => new V3l(0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OIZ => new V3l(0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l ONO => new V3l(0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l ONP => new V3l(0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l ONN => new V3l(0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ONX => new V3l(0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ONY => new V3l(0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ONZ => new V3l(0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXO => new V3l(0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXI => new V3l(0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXN => new V3l(0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXX => new V3l(0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXY => new V3l(0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXZ => new V3l(0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYO => new V3l(0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYI => new V3l(0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYN => new V3l(0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYX => new V3l(0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYY => new V3l(0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYZ => new V3l(0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OZO => new V3l(0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OZI => new V3l(0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OZN => new V3l(0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OZX => new V3l(0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OZY => new V3l(0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OZZ => new V3l(0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l IOO => new V3l(1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l IOI => new V3l(1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l PON => new V3l(1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IOX => new V3l(1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IOY => new V3l(1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IOZ => new V3l(1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l IIO => new V3l(1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l III => new V3l(1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l PPN => new V3l(1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IIX => new V3l(1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IIY => new V3l(1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IIZ => new V3l(1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l PNO => new V3l(1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l PNP => new V3l(1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l PNN => new V3l(1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PNX => new V3l(1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PNY => new V3l(1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PNZ => new V3l(1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IXO => new V3l(1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IXI => new V3l(1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PXN => new V3l(1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IXX => new V3l(1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IXY => new V3l(1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IXZ => new V3l(1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IYO => new V3l(1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IYI => new V3l(1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PYN => new V3l(1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IYX => new V3l(1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IYY => new V3l(1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IYZ => new V3l(1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IZO => new V3l(1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IZI => new V3l(1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PZN => new V3l(1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IZX => new V3l(1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IZY => new V3l(1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IZZ => new V3l(1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l NOO => new V3l(-1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l NOP => new V3l(-1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l NON => new V3l(-1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NOX => new V3l(-1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NOY => new V3l(-1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NOZ => new V3l(-1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l NPO => new V3l(-1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l NPP => new V3l(-1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l NPN => new V3l(-1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NPX => new V3l(-1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NPY => new V3l(-1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NPZ => new V3l(-1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l NNO => new V3l(-1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l NNP => new V3l(-1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3l NNN => new V3l(-1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NNX => new V3l(-1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NNY => new V3l(-1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NNZ => new V3l(-1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXO => new V3l(-1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXP => new V3l(-1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXN => new V3l(-1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXX => new V3l(-1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXY => new V3l(-1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXZ => new V3l(-1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYO => new V3l(-1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYP => new V3l(-1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYN => new V3l(-1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYX => new V3l(-1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYY => new V3l(-1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYZ => new V3l(-1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NZO => new V3l(-1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NZP => new V3l(-1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NZN => new V3l(-1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NZX => new V3l(-1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NZY => new V3l(-1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NZZ => new V3l(-1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XOO => new V3l(X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XOI => new V3l(X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XON => new V3l(X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XOX => new V3l(X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XOY => new V3l(X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XOZ => new V3l(X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XIO => new V3l(X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XII => new V3l(X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XPN => new V3l(X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XIX => new V3l(X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XIY => new V3l(X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XIZ => new V3l(X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNO => new V3l(X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNP => new V3l(X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNN => new V3l(X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNX => new V3l(X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNY => new V3l(X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNZ => new V3l(X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXO => new V3l(X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXI => new V3l(X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXN => new V3l(X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXX => new V3l(X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXY => new V3l(X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXZ => new V3l(X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XYO => new V3l(X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XYI => new V3l(X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XYN => new V3l(X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XYX => new V3l(X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XYY => new V3l(X, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l XYZ { readonly get => new V3l(X, Y, Z); set { X = value.X; Y = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XZO => new V3l(X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XZI => new V3l(X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XZN => new V3l(X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XZX => new V3l(X, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l XZY { readonly get => new V3l(X, Z, Y); set { X = value.X; Z = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XZZ => new V3l(X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YOO => new V3l(Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YOI => new V3l(Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YON => new V3l(Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YOX => new V3l(Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YOY => new V3l(Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YOZ => new V3l(Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YIO => new V3l(Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YII => new V3l(Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YPN => new V3l(Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YIX => new V3l(Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YIY => new V3l(Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YIZ => new V3l(Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNO => new V3l(Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNP => new V3l(Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNN => new V3l(Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNX => new V3l(Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNY => new V3l(Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNZ => new V3l(Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YXO => new V3l(Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YXI => new V3l(Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YXN => new V3l(Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YXX => new V3l(Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YXY => new V3l(Y, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l YXZ { readonly get => new V3l(Y, X, Z); set { Y = value.X; X = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYO => new V3l(Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYI => new V3l(Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYN => new V3l(Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYX => new V3l(Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYY => new V3l(Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYZ => new V3l(Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YZO => new V3l(Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YZI => new V3l(Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YZN => new V3l(Y, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l YZX { readonly get => new V3l(Y, Z, X); set { Y = value.X; Z = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YZY => new V3l(Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YZZ => new V3l(Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZOO => new V3l(Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZOI => new V3l(Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZON => new V3l(Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZOX => new V3l(Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZOY => new V3l(Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZOZ => new V3l(Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZIO => new V3l(Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZII => new V3l(Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZPN => new V3l(Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZIX => new V3l(Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZIY => new V3l(Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZIZ => new V3l(Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZNO => new V3l(Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZNP => new V3l(Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZNN => new V3l(Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZNX => new V3l(Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZNY => new V3l(Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZNZ => new V3l(Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZXO => new V3l(Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZXI => new V3l(Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZXN => new V3l(Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZXX => new V3l(Z, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l ZXY { readonly get => new V3l(Z, X, Y); set { Z = value.X; X = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZXZ => new V3l(Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZYO => new V3l(Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZYI => new V3l(Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZYN => new V3l(Z, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l ZYX { readonly get => new V3l(Z, Y, X); set { Z = value.X; Y = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZYY => new V3l(Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZYZ => new V3l(Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZZO => new V3l(Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZZI => new V3l(Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZZN => new V3l(Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZZX => new V3l(Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZZY => new V3l(Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZZZ => new V3l(Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOOX => new V4l(0, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOOY => new V4l(0, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOOZ => new V4l(0, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOIX => new V4l(0, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOIY => new V4l(0, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOIZ => new V4l(0, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OONX => new V4l(0, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OONY => new V4l(0, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OONZ => new V4l(0, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXO => new V4l(0, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXI => new V4l(0, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXN => new V4l(0, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXX => new V4l(0, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXY => new V4l(0, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXZ => new V4l(0, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYO => new V4l(0, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYI => new V4l(0, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYN => new V4l(0, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYX => new V4l(0, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYY => new V4l(0, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYZ => new V4l(0, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOZO => new V4l(0, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOZI => new V4l(0, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOZN => new V4l(0, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOZX => new V4l(0, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOZY => new V4l(0, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOZZ => new V4l(0, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIOX => new V4l(0, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIOY => new V4l(0, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIOZ => new V4l(0, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIIX => new V4l(0, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIIY => new V4l(0, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIIZ => new V4l(0, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPNX => new V4l(0, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPNY => new V4l(0, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPNZ => new V4l(0, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIXO => new V4l(0, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIXI => new V4l(0, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPXN => new V4l(0, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIXX => new V4l(0, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIXY => new V4l(0, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIXZ => new V4l(0, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIYO => new V4l(0, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIYI => new V4l(0, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPYN => new V4l(0, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIYX => new V4l(0, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIYY => new V4l(0, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIYZ => new V4l(0, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIZO => new V4l(0, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIZI => new V4l(0, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPZN => new V4l(0, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIZX => new V4l(0, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIZY => new V4l(0, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIZZ => new V4l(0, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONOX => new V4l(0, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONOY => new V4l(0, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONOZ => new V4l(0, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONPX => new V4l(0, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONPY => new V4l(0, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONPZ => new V4l(0, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONNX => new V4l(0, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONNY => new V4l(0, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONNZ => new V4l(0, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXO => new V4l(0, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXP => new V4l(0, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXN => new V4l(0, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXX => new V4l(0, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXY => new V4l(0, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXZ => new V4l(0, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYO => new V4l(0, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYP => new V4l(0, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYN => new V4l(0, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYX => new V4l(0, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYY => new V4l(0, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYZ => new V4l(0, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONZO => new V4l(0, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONZP => new V4l(0, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONZN => new V4l(0, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONZX => new V4l(0, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONZY => new V4l(0, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONZZ => new V4l(0, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXOO => new V4l(0, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXOI => new V4l(0, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXON => new V4l(0, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXOX => new V4l(0, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXOY => new V4l(0, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXOZ => new V4l(0, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXIO => new V4l(0, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXII => new V4l(0, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXPN => new V4l(0, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXIX => new V4l(0, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXIY => new V4l(0, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXIZ => new V4l(0, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNO => new V4l(0, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNP => new V4l(0, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNN => new V4l(0, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNX => new V4l(0, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNY => new V4l(0, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNZ => new V4l(0, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXO => new V4l(0, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXI => new V4l(0, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXN => new V4l(0, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXX => new V4l(0, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXY => new V4l(0, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXZ => new V4l(0, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYO => new V4l(0, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYI => new V4l(0, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYN => new V4l(0, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYX => new V4l(0, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYY => new V4l(0, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYZ => new V4l(0, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXZO => new V4l(0, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXZI => new V4l(0, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXZN => new V4l(0, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXZX => new V4l(0, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXZY => new V4l(0, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXZZ => new V4l(0, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYOO => new V4l(0, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYOI => new V4l(0, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYON => new V4l(0, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYOX => new V4l(0, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYOY => new V4l(0, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYOZ => new V4l(0, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYIO => new V4l(0, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYII => new V4l(0, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYPN => new V4l(0, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYIX => new V4l(0, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYIY => new V4l(0, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYIZ => new V4l(0, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNO => new V4l(0, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNP => new V4l(0, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNN => new V4l(0, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNX => new V4l(0, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNY => new V4l(0, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNZ => new V4l(0, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXO => new V4l(0, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXI => new V4l(0, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXN => new V4l(0, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXX => new V4l(0, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXY => new V4l(0, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXZ => new V4l(0, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYO => new V4l(0, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYI => new V4l(0, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYN => new V4l(0, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYX => new V4l(0, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYY => new V4l(0, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYZ => new V4l(0, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYZO => new V4l(0, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYZI => new V4l(0, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYZN => new V4l(0, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYZX => new V4l(0, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYZY => new V4l(0, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYZZ => new V4l(0, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZOO => new V4l(0, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZOI => new V4l(0, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZON => new V4l(0, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZOX => new V4l(0, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZOY => new V4l(0, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZOZ => new V4l(0, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZIO => new V4l(0, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZII => new V4l(0, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZPN => new V4l(0, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZIX => new V4l(0, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZIY => new V4l(0, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZIZ => new V4l(0, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZNO => new V4l(0, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZNP => new V4l(0, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZNN => new V4l(0, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZNX => new V4l(0, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZNY => new V4l(0, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZNZ => new V4l(0, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZXO => new V4l(0, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZXI => new V4l(0, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZXN => new V4l(0, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZXX => new V4l(0, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZXY => new V4l(0, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZXZ => new V4l(0, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZYO => new V4l(0, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZYI => new V4l(0, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZYN => new V4l(0, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZYX => new V4l(0, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZYY => new V4l(0, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZYZ => new V4l(0, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZZO => new V4l(0, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZZI => new V4l(0, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZZN => new V4l(0, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZZX => new V4l(0, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZZY => new V4l(0, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZZZ => new V4l(0, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOOX => new V4l(1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOOY => new V4l(1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOOZ => new V4l(1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOIX => new V4l(1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOIY => new V4l(1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOIZ => new V4l(1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PONX => new V4l(1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PONY => new V4l(1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PONZ => new V4l(1, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOXO => new V4l(1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOXI => new V4l(1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l POXN => new V4l(1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOXX => new V4l(1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOXY => new V4l(1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOXZ => new V4l(1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOYO => new V4l(1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOYI => new V4l(1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l POYN => new V4l(1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOYX => new V4l(1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOYY => new V4l(1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOYZ => new V4l(1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOZO => new V4l(1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOZI => new V4l(1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l POZN => new V4l(1, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOZX => new V4l(1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOZY => new V4l(1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOZZ => new V4l(1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIOX => new V4l(1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIOY => new V4l(1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIOZ => new V4l(1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIIX => new V4l(1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIIY => new V4l(1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIIZ => new V4l(1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPNX => new V4l(1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPNY => new V4l(1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPNZ => new V4l(1, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIXO => new V4l(1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIXI => new V4l(1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPXN => new V4l(1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIXX => new V4l(1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIXY => new V4l(1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIXZ => new V4l(1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIYO => new V4l(1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIYI => new V4l(1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPYN => new V4l(1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIYX => new V4l(1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIYY => new V4l(1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIYZ => new V4l(1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIZO => new V4l(1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIZI => new V4l(1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPZN => new V4l(1, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIZX => new V4l(1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIZY => new V4l(1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIZZ => new V4l(1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNOX => new V4l(1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNOY => new V4l(1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNOZ => new V4l(1, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNPX => new V4l(1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNPY => new V4l(1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNPZ => new V4l(1, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNNX => new V4l(1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNNY => new V4l(1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNNZ => new V4l(1, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXO => new V4l(1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXP => new V4l(1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXN => new V4l(1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXX => new V4l(1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXY => new V4l(1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXZ => new V4l(1, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYO => new V4l(1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYP => new V4l(1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYN => new V4l(1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYX => new V4l(1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYY => new V4l(1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYZ => new V4l(1, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNZO => new V4l(1, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNZP => new V4l(1, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNZN => new V4l(1, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNZX => new V4l(1, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNZY => new V4l(1, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNZZ => new V4l(1, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXOO => new V4l(1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXOI => new V4l(1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXON => new V4l(1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXOX => new V4l(1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXOY => new V4l(1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXOZ => new V4l(1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXIO => new V4l(1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXII => new V4l(1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXPN => new V4l(1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXIX => new V4l(1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXIY => new V4l(1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXIZ => new V4l(1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNO => new V4l(1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNP => new V4l(1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNN => new V4l(1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNX => new V4l(1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNY => new V4l(1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNZ => new V4l(1, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXXO => new V4l(1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXXI => new V4l(1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXXN => new V4l(1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXXX => new V4l(1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXXY => new V4l(1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXXZ => new V4l(1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXYO => new V4l(1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXYI => new V4l(1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXYN => new V4l(1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXYX => new V4l(1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXYY => new V4l(1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXYZ => new V4l(1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXZO => new V4l(1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXZI => new V4l(1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXZN => new V4l(1, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXZX => new V4l(1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXZY => new V4l(1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXZZ => new V4l(1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYOO => new V4l(1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYOI => new V4l(1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYON => new V4l(1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYOX => new V4l(1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYOY => new V4l(1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYOZ => new V4l(1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYIO => new V4l(1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYII => new V4l(1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYPN => new V4l(1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYIX => new V4l(1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYIY => new V4l(1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYIZ => new V4l(1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNO => new V4l(1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNP => new V4l(1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNN => new V4l(1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNX => new V4l(1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNY => new V4l(1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNZ => new V4l(1, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYXO => new V4l(1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYXI => new V4l(1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYXN => new V4l(1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYXX => new V4l(1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYXY => new V4l(1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYXZ => new V4l(1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYYO => new V4l(1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYYI => new V4l(1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYYN => new V4l(1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYYX => new V4l(1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYYY => new V4l(1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYYZ => new V4l(1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYZO => new V4l(1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYZI => new V4l(1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYZN => new V4l(1, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYZX => new V4l(1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYZY => new V4l(1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYZZ => new V4l(1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZOO => new V4l(1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZOI => new V4l(1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZON => new V4l(1, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZOX => new V4l(1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZOY => new V4l(1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZOZ => new V4l(1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZIO => new V4l(1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZII => new V4l(1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZPN => new V4l(1, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZIX => new V4l(1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZIY => new V4l(1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZIZ => new V4l(1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZNO => new V4l(1, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZNP => new V4l(1, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZNN => new V4l(1, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZNX => new V4l(1, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZNY => new V4l(1, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZNZ => new V4l(1, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZXO => new V4l(1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZXI => new V4l(1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZXN => new V4l(1, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZXX => new V4l(1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZXY => new V4l(1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZXZ => new V4l(1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZYO => new V4l(1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZYI => new V4l(1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZYN => new V4l(1, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZYX => new V4l(1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZYY => new V4l(1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZYZ => new V4l(1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZZO => new V4l(1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZZI => new V4l(1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZZN => new V4l(1, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZZX => new V4l(1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZZY => new V4l(1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZZZ => new V4l(1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOOX => new V4l(-1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOOY => new V4l(-1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOOZ => new V4l(-1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOPX => new V4l(-1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOPY => new V4l(-1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOPZ => new V4l(-1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NONX => new V4l(-1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NONY => new V4l(-1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NONZ => new V4l(-1, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXO => new V4l(-1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXP => new V4l(-1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXN => new V4l(-1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXX => new V4l(-1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXY => new V4l(-1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXZ => new V4l(-1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYO => new V4l(-1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYP => new V4l(-1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYN => new V4l(-1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYX => new V4l(-1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYY => new V4l(-1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYZ => new V4l(-1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOZO => new V4l(-1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOZP => new V4l(-1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOZN => new V4l(-1, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOZX => new V4l(-1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOZY => new V4l(-1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOZZ => new V4l(-1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPOX => new V4l(-1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPOY => new V4l(-1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPOZ => new V4l(-1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPPX => new V4l(-1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPPY => new V4l(-1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPPZ => new V4l(-1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPNX => new V4l(-1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPNY => new V4l(-1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPNZ => new V4l(-1, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXO => new V4l(-1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXP => new V4l(-1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXN => new V4l(-1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXX => new V4l(-1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXY => new V4l(-1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXZ => new V4l(-1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYO => new V4l(-1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYP => new V4l(-1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYN => new V4l(-1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYX => new V4l(-1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYY => new V4l(-1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYZ => new V4l(-1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPZO => new V4l(-1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPZP => new V4l(-1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPZN => new V4l(-1, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPZX => new V4l(-1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPZY => new V4l(-1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPZZ => new V4l(-1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNOX => new V4l(-1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNOY => new V4l(-1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNOZ => new V4l(-1, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNPX => new V4l(-1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNPY => new V4l(-1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNPZ => new V4l(-1, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNNX => new V4l(-1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNNY => new V4l(-1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNNZ => new V4l(-1, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXO => new V4l(-1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXP => new V4l(-1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXN => new V4l(-1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXX => new V4l(-1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXY => new V4l(-1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXZ => new V4l(-1, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYO => new V4l(-1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYP => new V4l(-1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYN => new V4l(-1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYX => new V4l(-1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYY => new V4l(-1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYZ => new V4l(-1, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNZO => new V4l(-1, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNZP => new V4l(-1, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNZN => new V4l(-1, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNZX => new V4l(-1, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNZY => new V4l(-1, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNZZ => new V4l(-1, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXOO => new V4l(-1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXOP => new V4l(-1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXON => new V4l(-1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXOX => new V4l(-1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXOY => new V4l(-1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXOZ => new V4l(-1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPO => new V4l(-1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPP => new V4l(-1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPN => new V4l(-1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPX => new V4l(-1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPY => new V4l(-1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPZ => new V4l(-1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNO => new V4l(-1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNP => new V4l(-1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNN => new V4l(-1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNX => new V4l(-1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNY => new V4l(-1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNZ => new V4l(-1, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXO => new V4l(-1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXP => new V4l(-1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXN => new V4l(-1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXX => new V4l(-1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXY => new V4l(-1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXZ => new V4l(-1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYO => new V4l(-1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYP => new V4l(-1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYN => new V4l(-1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYX => new V4l(-1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYY => new V4l(-1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYZ => new V4l(-1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXZO => new V4l(-1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXZP => new V4l(-1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXZN => new V4l(-1, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXZX => new V4l(-1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXZY => new V4l(-1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXZZ => new V4l(-1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYOO => new V4l(-1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYOP => new V4l(-1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYON => new V4l(-1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYOX => new V4l(-1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYOY => new V4l(-1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYOZ => new V4l(-1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPO => new V4l(-1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPP => new V4l(-1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPN => new V4l(-1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPX => new V4l(-1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPY => new V4l(-1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPZ => new V4l(-1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNO => new V4l(-1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNP => new V4l(-1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNN => new V4l(-1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNX => new V4l(-1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNY => new V4l(-1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNZ => new V4l(-1, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXO => new V4l(-1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXP => new V4l(-1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXN => new V4l(-1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXX => new V4l(-1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXY => new V4l(-1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXZ => new V4l(-1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYO => new V4l(-1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYP => new V4l(-1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYN => new V4l(-1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYX => new V4l(-1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYY => new V4l(-1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYZ => new V4l(-1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYZO => new V4l(-1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYZP => new V4l(-1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYZN => new V4l(-1, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYZX => new V4l(-1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYZY => new V4l(-1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYZZ => new V4l(-1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZOO => new V4l(-1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZOP => new V4l(-1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZON => new V4l(-1, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZOX => new V4l(-1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZOY => new V4l(-1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZOZ => new V4l(-1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZPO => new V4l(-1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZPP => new V4l(-1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZPN => new V4l(-1, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZPX => new V4l(-1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZPY => new V4l(-1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZPZ => new V4l(-1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZNO => new V4l(-1, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZNP => new V4l(-1, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZNN => new V4l(-1, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZNX => new V4l(-1, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZNY => new V4l(-1, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZNZ => new V4l(-1, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZXO => new V4l(-1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZXP => new V4l(-1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZXN => new V4l(-1, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZXX => new V4l(-1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZXY => new V4l(-1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZXZ => new V4l(-1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZYO => new V4l(-1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZYP => new V4l(-1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZYN => new V4l(-1, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZYX => new V4l(-1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZYY => new V4l(-1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZYZ => new V4l(-1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZZO => new V4l(-1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZZP => new V4l(-1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZZN => new V4l(-1, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZZX => new V4l(-1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZZY => new V4l(-1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZZZ => new V4l(-1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOOO => new V4l(X, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOOI => new V4l(X, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOON => new V4l(X, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOOX => new V4l(X, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOOY => new V4l(X, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOOZ => new V4l(X, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOIO => new V4l(X, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOII => new V4l(X, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOPN => new V4l(X, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOIX => new V4l(X, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOIY => new V4l(X, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOIZ => new V4l(X, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONO => new V4l(X, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONP => new V4l(X, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONN => new V4l(X, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONX => new V4l(X, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONY => new V4l(X, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONZ => new V4l(X, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXO => new V4l(X, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXI => new V4l(X, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXN => new V4l(X, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXX => new V4l(X, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXY => new V4l(X, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXZ => new V4l(X, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYO => new V4l(X, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYI => new V4l(X, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYN => new V4l(X, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYX => new V4l(X, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYY => new V4l(X, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYZ => new V4l(X, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOZO => new V4l(X, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOZI => new V4l(X, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOZN => new V4l(X, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOZX => new V4l(X, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOZY => new V4l(X, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOZZ => new V4l(X, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIOO => new V4l(X, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIOI => new V4l(X, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPON => new V4l(X, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIOX => new V4l(X, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIOY => new V4l(X, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIOZ => new V4l(X, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIIO => new V4l(X, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIII => new V4l(X, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPPN => new V4l(X, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIIX => new V4l(X, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIIY => new V4l(X, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIIZ => new V4l(X, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNO => new V4l(X, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNP => new V4l(X, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNN => new V4l(X, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNX => new V4l(X, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNY => new V4l(X, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNZ => new V4l(X, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIXO => new V4l(X, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIXI => new V4l(X, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPXN => new V4l(X, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIXX => new V4l(X, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIXY => new V4l(X, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIXZ => new V4l(X, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIYO => new V4l(X, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIYI => new V4l(X, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPYN => new V4l(X, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIYX => new V4l(X, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIYY => new V4l(X, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIYZ => new V4l(X, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIZO => new V4l(X, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIZI => new V4l(X, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPZN => new V4l(X, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIZX => new V4l(X, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIZY => new V4l(X, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIZZ => new V4l(X, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNOO => new V4l(X, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNOP => new V4l(X, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNON => new V4l(X, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNOX => new V4l(X, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNOY => new V4l(X, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNOZ => new V4l(X, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPO => new V4l(X, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPP => new V4l(X, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPN => new V4l(X, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPX => new V4l(X, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPY => new V4l(X, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPZ => new V4l(X, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNO => new V4l(X, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNP => new V4l(X, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNN => new V4l(X, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNX => new V4l(X, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNY => new V4l(X, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNZ => new V4l(X, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXO => new V4l(X, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXP => new V4l(X, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXN => new V4l(X, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXX => new V4l(X, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXY => new V4l(X, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXZ => new V4l(X, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYO => new V4l(X, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYP => new V4l(X, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYN => new V4l(X, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYX => new V4l(X, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYY => new V4l(X, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYZ => new V4l(X, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNZO => new V4l(X, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNZP => new V4l(X, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNZN => new V4l(X, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNZX => new V4l(X, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNZY => new V4l(X, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNZZ => new V4l(X, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXOO => new V4l(X, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXOI => new V4l(X, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXON => new V4l(X, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXOX => new V4l(X, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXOY => new V4l(X, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXOZ => new V4l(X, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXIO => new V4l(X, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXII => new V4l(X, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXPN => new V4l(X, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXIX => new V4l(X, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXIY => new V4l(X, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXIZ => new V4l(X, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNO => new V4l(X, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNP => new V4l(X, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNN => new V4l(X, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNX => new V4l(X, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNY => new V4l(X, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNZ => new V4l(X, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXO => new V4l(X, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXI => new V4l(X, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXN => new V4l(X, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXX => new V4l(X, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXY => new V4l(X, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXZ => new V4l(X, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYO => new V4l(X, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYI => new V4l(X, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYN => new V4l(X, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYX => new V4l(X, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYY => new V4l(X, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYZ => new V4l(X, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXZO => new V4l(X, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXZI => new V4l(X, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXZN => new V4l(X, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXZX => new V4l(X, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXZY => new V4l(X, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXZZ => new V4l(X, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYOO => new V4l(X, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYOI => new V4l(X, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYON => new V4l(X, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYOX => new V4l(X, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYOY => new V4l(X, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYOZ => new V4l(X, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYIO => new V4l(X, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYII => new V4l(X, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYPN => new V4l(X, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYIX => new V4l(X, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYIY => new V4l(X, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYIZ => new V4l(X, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNO => new V4l(X, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNP => new V4l(X, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNN => new V4l(X, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNX => new V4l(X, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNY => new V4l(X, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNZ => new V4l(X, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXO => new V4l(X, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXI => new V4l(X, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXN => new V4l(X, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXX => new V4l(X, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXY => new V4l(X, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXZ => new V4l(X, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYO => new V4l(X, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYI => new V4l(X, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYN => new V4l(X, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYX => new V4l(X, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYY => new V4l(X, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYZ => new V4l(X, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYZO => new V4l(X, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYZI => new V4l(X, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYZN => new V4l(X, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYZX => new V4l(X, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYZY => new V4l(X, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYZZ => new V4l(X, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZOO => new V4l(X, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZOI => new V4l(X, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZON => new V4l(X, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZOX => new V4l(X, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZOY => new V4l(X, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZOZ => new V4l(X, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZIO => new V4l(X, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZII => new V4l(X, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZPN => new V4l(X, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZIX => new V4l(X, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZIY => new V4l(X, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZIZ => new V4l(X, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZNO => new V4l(X, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZNP => new V4l(X, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZNN => new V4l(X, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZNX => new V4l(X, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZNY => new V4l(X, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZNZ => new V4l(X, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZXO => new V4l(X, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZXI => new V4l(X, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZXN => new V4l(X, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZXX => new V4l(X, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZXY => new V4l(X, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZXZ => new V4l(X, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZYO => new V4l(X, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZYI => new V4l(X, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZYN => new V4l(X, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZYX => new V4l(X, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZYY => new V4l(X, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZYZ => new V4l(X, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZZO => new V4l(X, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZZI => new V4l(X, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZZN => new V4l(X, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZZX => new V4l(X, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZZY => new V4l(X, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZZZ => new V4l(X, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOOO => new V4l(Y, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOOI => new V4l(Y, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOON => new V4l(Y, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOOX => new V4l(Y, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOOY => new V4l(Y, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOOZ => new V4l(Y, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOIO => new V4l(Y, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOII => new V4l(Y, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOPN => new V4l(Y, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOIX => new V4l(Y, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOIY => new V4l(Y, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOIZ => new V4l(Y, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONO => new V4l(Y, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONP => new V4l(Y, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONN => new V4l(Y, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONX => new V4l(Y, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONY => new V4l(Y, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONZ => new V4l(Y, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXO => new V4l(Y, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXI => new V4l(Y, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXN => new V4l(Y, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXX => new V4l(Y, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXY => new V4l(Y, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXZ => new V4l(Y, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYO => new V4l(Y, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYI => new V4l(Y, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYN => new V4l(Y, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYX => new V4l(Y, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYY => new V4l(Y, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYZ => new V4l(Y, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOZO => new V4l(Y, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOZI => new V4l(Y, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOZN => new V4l(Y, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOZX => new V4l(Y, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOZY => new V4l(Y, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOZZ => new V4l(Y, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIOO => new V4l(Y, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIOI => new V4l(Y, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPON => new V4l(Y, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIOX => new V4l(Y, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIOY => new V4l(Y, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIOZ => new V4l(Y, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIIO => new V4l(Y, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIII => new V4l(Y, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPPN => new V4l(Y, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIIX => new V4l(Y, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIIY => new V4l(Y, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIIZ => new V4l(Y, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNO => new V4l(Y, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNP => new V4l(Y, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNN => new V4l(Y, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNX => new V4l(Y, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNY => new V4l(Y, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNZ => new V4l(Y, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIXO => new V4l(Y, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIXI => new V4l(Y, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPXN => new V4l(Y, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIXX => new V4l(Y, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIXY => new V4l(Y, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIXZ => new V4l(Y, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIYO => new V4l(Y, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIYI => new V4l(Y, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPYN => new V4l(Y, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIYX => new V4l(Y, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIYY => new V4l(Y, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIYZ => new V4l(Y, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIZO => new V4l(Y, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIZI => new V4l(Y, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPZN => new V4l(Y, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIZX => new V4l(Y, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIZY => new V4l(Y, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIZZ => new V4l(Y, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNOO => new V4l(Y, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNOP => new V4l(Y, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNON => new V4l(Y, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNOX => new V4l(Y, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNOY => new V4l(Y, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNOZ => new V4l(Y, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPO => new V4l(Y, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPP => new V4l(Y, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPN => new V4l(Y, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPX => new V4l(Y, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPY => new V4l(Y, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPZ => new V4l(Y, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNO => new V4l(Y, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNP => new V4l(Y, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNN => new V4l(Y, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNX => new V4l(Y, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNY => new V4l(Y, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNZ => new V4l(Y, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXO => new V4l(Y, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXP => new V4l(Y, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXN => new V4l(Y, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXX => new V4l(Y, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXY => new V4l(Y, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXZ => new V4l(Y, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYO => new V4l(Y, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYP => new V4l(Y, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYN => new V4l(Y, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYX => new V4l(Y, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYY => new V4l(Y, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYZ => new V4l(Y, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNZO => new V4l(Y, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNZP => new V4l(Y, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNZN => new V4l(Y, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNZX => new V4l(Y, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNZY => new V4l(Y, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNZZ => new V4l(Y, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXOO => new V4l(Y, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXOI => new V4l(Y, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXON => new V4l(Y, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXOX => new V4l(Y, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXOY => new V4l(Y, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXOZ => new V4l(Y, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXIO => new V4l(Y, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXII => new V4l(Y, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXPN => new V4l(Y, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXIX => new V4l(Y, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXIY => new V4l(Y, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXIZ => new V4l(Y, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNO => new V4l(Y, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNP => new V4l(Y, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNN => new V4l(Y, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNX => new V4l(Y, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNY => new V4l(Y, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNZ => new V4l(Y, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXO => new V4l(Y, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXI => new V4l(Y, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXN => new V4l(Y, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXX => new V4l(Y, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXY => new V4l(Y, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXZ => new V4l(Y, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYO => new V4l(Y, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYI => new V4l(Y, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYN => new V4l(Y, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYX => new V4l(Y, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYY => new V4l(Y, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYZ => new V4l(Y, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXZO => new V4l(Y, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXZI => new V4l(Y, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXZN => new V4l(Y, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXZX => new V4l(Y, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXZY => new V4l(Y, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXZZ => new V4l(Y, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYOO => new V4l(Y, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYOI => new V4l(Y, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYON => new V4l(Y, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYOX => new V4l(Y, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYOY => new V4l(Y, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYOZ => new V4l(Y, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYIO => new V4l(Y, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYII => new V4l(Y, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYPN => new V4l(Y, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYIX => new V4l(Y, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYIY => new V4l(Y, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYIZ => new V4l(Y, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNO => new V4l(Y, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNP => new V4l(Y, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNN => new V4l(Y, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNX => new V4l(Y, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNY => new V4l(Y, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNZ => new V4l(Y, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXO => new V4l(Y, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXI => new V4l(Y, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXN => new V4l(Y, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXX => new V4l(Y, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXY => new V4l(Y, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXZ => new V4l(Y, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYO => new V4l(Y, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYI => new V4l(Y, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYN => new V4l(Y, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYX => new V4l(Y, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYY => new V4l(Y, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYZ => new V4l(Y, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYZO => new V4l(Y, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYZI => new V4l(Y, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYZN => new V4l(Y, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYZX => new V4l(Y, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYZY => new V4l(Y, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYZZ => new V4l(Y, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZOO => new V4l(Y, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZOI => new V4l(Y, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZON => new V4l(Y, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZOX => new V4l(Y, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZOY => new V4l(Y, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZOZ => new V4l(Y, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZIO => new V4l(Y, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZII => new V4l(Y, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZPN => new V4l(Y, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZIX => new V4l(Y, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZIY => new V4l(Y, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZIZ => new V4l(Y, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZNO => new V4l(Y, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZNP => new V4l(Y, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZNN => new V4l(Y, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZNX => new V4l(Y, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZNY => new V4l(Y, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZNZ => new V4l(Y, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZXO => new V4l(Y, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZXI => new V4l(Y, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZXN => new V4l(Y, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZXX => new V4l(Y, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZXY => new V4l(Y, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZXZ => new V4l(Y, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZYO => new V4l(Y, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZYI => new V4l(Y, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZYN => new V4l(Y, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZYX => new V4l(Y, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZYY => new V4l(Y, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZYZ => new V4l(Y, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZZO => new V4l(Y, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZZI => new V4l(Y, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZZN => new V4l(Y, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZZX => new V4l(Y, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZZY => new V4l(Y, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZZZ => new V4l(Y, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOOO => new V4l(Z, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOOI => new V4l(Z, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOON => new V4l(Z, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOOX => new V4l(Z, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOOY => new V4l(Z, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOOZ => new V4l(Z, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOIO => new V4l(Z, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOII => new V4l(Z, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOPN => new V4l(Z, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOIX => new V4l(Z, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOIY => new V4l(Z, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOIZ => new V4l(Z, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZONO => new V4l(Z, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZONP => new V4l(Z, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZONN => new V4l(Z, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZONX => new V4l(Z, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZONY => new V4l(Z, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZONZ => new V4l(Z, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOXO => new V4l(Z, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOXI => new V4l(Z, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOXN => new V4l(Z, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOXX => new V4l(Z, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOXY => new V4l(Z, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOXZ => new V4l(Z, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOYO => new V4l(Z, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOYI => new V4l(Z, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOYN => new V4l(Z, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOYX => new V4l(Z, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOYY => new V4l(Z, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOYZ => new V4l(Z, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOZO => new V4l(Z, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOZI => new V4l(Z, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOZN => new V4l(Z, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOZX => new V4l(Z, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOZY => new V4l(Z, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOZZ => new V4l(Z, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIOO => new V4l(Z, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIOI => new V4l(Z, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPON => new V4l(Z, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIOX => new V4l(Z, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIOY => new V4l(Z, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIOZ => new V4l(Z, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIIO => new V4l(Z, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIII => new V4l(Z, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPPN => new V4l(Z, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIIX => new V4l(Z, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIIY => new V4l(Z, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIIZ => new V4l(Z, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPNO => new V4l(Z, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPNP => new V4l(Z, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPNN => new V4l(Z, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPNX => new V4l(Z, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPNY => new V4l(Z, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPNZ => new V4l(Z, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIXO => new V4l(Z, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIXI => new V4l(Z, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPXN => new V4l(Z, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIXX => new V4l(Z, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIXY => new V4l(Z, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIXZ => new V4l(Z, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIYO => new V4l(Z, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIYI => new V4l(Z, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPYN => new V4l(Z, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIYX => new V4l(Z, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIYY => new V4l(Z, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIYZ => new V4l(Z, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIZO => new V4l(Z, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIZI => new V4l(Z, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPZN => new V4l(Z, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIZX => new V4l(Z, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIZY => new V4l(Z, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIZZ => new V4l(Z, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNOO => new V4l(Z, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNOP => new V4l(Z, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNON => new V4l(Z, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNOX => new V4l(Z, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNOY => new V4l(Z, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNOZ => new V4l(Z, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNPO => new V4l(Z, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNPP => new V4l(Z, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNPN => new V4l(Z, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNPX => new V4l(Z, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNPY => new V4l(Z, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNPZ => new V4l(Z, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNNO => new V4l(Z, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNNP => new V4l(Z, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNNN => new V4l(Z, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNNX => new V4l(Z, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNNY => new V4l(Z, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNNZ => new V4l(Z, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNXO => new V4l(Z, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNXP => new V4l(Z, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNXN => new V4l(Z, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNXX => new V4l(Z, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNXY => new V4l(Z, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNXZ => new V4l(Z, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNYO => new V4l(Z, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNYP => new V4l(Z, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNYN => new V4l(Z, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNYX => new V4l(Z, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNYY => new V4l(Z, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNYZ => new V4l(Z, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNZO => new V4l(Z, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNZP => new V4l(Z, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNZN => new V4l(Z, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNZX => new V4l(Z, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNZY => new V4l(Z, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNZZ => new V4l(Z, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXOO => new V4l(Z, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXOI => new V4l(Z, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXON => new V4l(Z, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXOX => new V4l(Z, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXOY => new V4l(Z, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXOZ => new V4l(Z, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXIO => new V4l(Z, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXII => new V4l(Z, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXPN => new V4l(Z, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXIX => new V4l(Z, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXIY => new V4l(Z, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXIZ => new V4l(Z, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXNO => new V4l(Z, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXNP => new V4l(Z, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXNN => new V4l(Z, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXNX => new V4l(Z, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXNY => new V4l(Z, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXNZ => new V4l(Z, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXXO => new V4l(Z, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXXI => new V4l(Z, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXXN => new V4l(Z, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXXX => new V4l(Z, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXXY => new V4l(Z, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXXZ => new V4l(Z, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXYO => new V4l(Z, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXYI => new V4l(Z, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXYN => new V4l(Z, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXYX => new V4l(Z, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXYY => new V4l(Z, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXYZ => new V4l(Z, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXZO => new V4l(Z, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXZI => new V4l(Z, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXZN => new V4l(Z, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXZX => new V4l(Z, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXZY => new V4l(Z, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXZZ => new V4l(Z, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYOO => new V4l(Z, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYOI => new V4l(Z, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYON => new V4l(Z, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYOX => new V4l(Z, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYOY => new V4l(Z, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYOZ => new V4l(Z, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYIO => new V4l(Z, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYII => new V4l(Z, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYPN => new V4l(Z, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYIX => new V4l(Z, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYIY => new V4l(Z, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYIZ => new V4l(Z, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYNO => new V4l(Z, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYNP => new V4l(Z, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYNN => new V4l(Z, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYNX => new V4l(Z, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYNY => new V4l(Z, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYNZ => new V4l(Z, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYXO => new V4l(Z, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYXI => new V4l(Z, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYXN => new V4l(Z, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYXX => new V4l(Z, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYXY => new V4l(Z, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYXZ => new V4l(Z, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYYO => new V4l(Z, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYYI => new V4l(Z, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYYN => new V4l(Z, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYYX => new V4l(Z, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYYY => new V4l(Z, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYYZ => new V4l(Z, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYZO => new V4l(Z, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYZI => new V4l(Z, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYZN => new V4l(Z, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYZX => new V4l(Z, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYZY => new V4l(Z, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYZZ => new V4l(Z, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZOO => new V4l(Z, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZOI => new V4l(Z, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZON => new V4l(Z, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZOX => new V4l(Z, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZOY => new V4l(Z, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZOZ => new V4l(Z, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZIO => new V4l(Z, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZII => new V4l(Z, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZPN => new V4l(Z, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZIX => new V4l(Z, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZIY => new V4l(Z, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZIZ => new V4l(Z, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZNO => new V4l(Z, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZNP => new V4l(Z, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZNN => new V4l(Z, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZNX => new V4l(Z, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZNY => new V4l(Z, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZNZ => new V4l(Z, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZXO => new V4l(Z, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZXI => new V4l(Z, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZXN => new V4l(Z, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZXX => new V4l(Z, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZXY => new V4l(Z, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZXZ => new V4l(Z, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZYO => new V4l(Z, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZYI => new V4l(Z, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZYN => new V4l(Z, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZYX => new V4l(Z, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZYY => new V4l(Z, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZYZ => new V4l(Z, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZZO => new V4l(Z, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZZI => new V4l(Z, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZZN => new V4l(Z, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZZX => new V4l(Z, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZZY => new V4l(Z, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZZZ => new V4l(Z, Z, Z, Z); #endregion #region IVector Members /// /// By using long indices, the IVector<double> interface is /// accessed. /// public double this[long i] { readonly get { return (double)this[(int)i]; } set { this[(int)i] = (long)value; } } #endregion #region ISize3l Members public readonly V3l Size3l { get { return this; } } #endregion #region IVector public readonly long Dim { get { return 3; } } public readonly object GetValue(long index) { return (object)this[(int)index]; } public void SetValue(object value, long index) { this[(int)index] = (long)value; } #endregion } public class V3lEqualityComparer : IEqualityComparer { public static V3lEqualityComparer Default => new V3lEqualityComparer(); #region IEqualityComparer Members public bool Equals(V3l v0, V3l v1) { return v0 == v1; } public int GetHashCode(V3l v) { return v.GetHashCode(); } #endregion } public static partial class Fun { #region Min and Max /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Min(this V3l a, V3l b) { return new V3l(Min(a.X, b.X), Min(a.Y, b.Y), Min(a.Z, b.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Min(this V3l a, long b) { return new V3l(Min(a.X, b), Min(a.Y, b), Min(a.Z, b)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Min(this long a, V3l b) { return new V3l(Min(a, b.X), Min(a, b.Y), Min(a, b.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Max(this V3l a, V3l b) { return new V3l(Max(a.X, b.X), Max(a.Y, b.Y), Max(a.Z, b.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Max(this V3l a, long b) { return new V3l(Max(a.X, b), Max(a.Y, b), Max(a.Z, b)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Max(this long a, V3l b) { return new V3l(Max(a, b.X), Max(a, b.Y), Max(a, b.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Min(this V3l a, V3l b, V3l c) { return new V3l(Min(a.X, b.X, c.X), Min(a.Y, b.Y, c.Y), Min(a.Z, b.Z, c.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Max(this V3l a, V3l b, V3l c) { return new V3l(Max(a.X, b.X, c.X), Max(a.Y, b.Y, c.Y), Max(a.Z, b.Z, c.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Min(this V3l a, V3l b, V3l c, V3l d) { return new V3l(Min(a.X, b.X, c.X, d.X), Min(a.Y, b.Y, c.Y, d.Y), Min(a.Z, b.Z, c.Z, d.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Max(this V3l a, V3l b, V3l c, V3l d) { return new V3l(Max(a.X, b.X, c.X, d.X), Max(a.Y, b.Y, c.Y, d.Y), Max(a.Z, b.Z, c.Z, d.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Min(this V3l x, params V3l[] values) { return new V3l(Min(x.X, values.Map(a => a.X)), Min(x.Y, values.Map(a => a.Y)), Min(x.Z, values.Map(a => a.Z))); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Max(this V3l x, params V3l[] values) { return new V3l(Max(x.X, values.Map(a => a.X)), Max(x.Y, values.Map(a => a.Y)), Max(x.Z, values.Map(a => a.Z))); } #endregion #region Abs /// /// Applies Fun.Abs to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Abs(this V3l x) { return new V3l(Abs(x.X), Abs(x.Y), Abs(x.Z)); } #endregion #region Clamping /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Clamp(this V3l x, V3l a, V3l b) { return new V3l(Clamp(x.X, a.X, b.X), Clamp(x.Y, a.Y, b.Y), Clamp(x.Z, a.Z, b.Z)); } /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Clamp(this V3l x, long a, long b) { return new V3l(Clamp(x.X, a, b), Clamp(x.Y, a, b), Clamp(x.Z, a, b)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l ClampExcl(this V3l x, V3l a, V3l b) { return new V3l(ClampExcl(x.X, a.X, b.X), ClampExcl(x.Y, a.Y, b.Y), ClampExcl(x.Z, a.Z, b.Z)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l ClampExcl(this V3l x, long a, long b) { return new V3l(ClampExcl(x.X, a, b), ClampExcl(x.Y, a, b), ClampExcl(x.Z, a, b)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l ClampWrap(this V3l x, V3l a, V3l b) { return new V3l(ClampWrap(x.X, a.X, b.X), ClampWrap(x.Y, a.Y, b.Y), ClampWrap(x.Z, a.Z, b.Z)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l ClampWrap(this V3l x, long a, long b) { return new V3l(ClampWrap(x.X, a, b), ClampWrap(x.Y, a, b), ClampWrap(x.Z, a, b)); } /// /// Applies Fun.Saturate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Saturate(this V3l x) { return new V3l(Saturate(x.X), Saturate(x.Y), Saturate(x.Z)); } #endregion #region Sign /// /// Applies Fun.Sign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Sign(this V3l x) { return new V3i(Sign(x.X), Sign(x.Y), Sign(x.Z)); } /// /// Applies Fun.Signumi to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Signumi(this V3l x) { return new V3i(Signumi(x.X), Signumi(x.Y), Signumi(x.Z)); } /// /// Applies Fun.Signum to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Signum(this V3l x) { return new V3l(Signum(x.X), Signum(x.Y), Signum(x.Z)); } #endregion #region Multiply-Add /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l MultiplyAdd(V3l x, V3l y, V3l z) { return new V3l(MultiplyAdd(x.X, y.X, z.X), MultiplyAdd(x.Y, y.Y, z.Y), MultiplyAdd(x.Z, y.Z, z.Z)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l MultiplyAdd(V3l x, long y, V3l z) { return new V3l(MultiplyAdd(x.X, y, z.X), MultiplyAdd(x.Y, y, z.Y), MultiplyAdd(x.Z, y, z.Z)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l MultiplyAdd(long x, V3l y, V3l z) { return new V3l(MultiplyAdd(x, y.X, z.X), MultiplyAdd(x, y.Y, z.Y), MultiplyAdd(x, y.Z, z.Z)); } #endregion #region Roots /// /// Applies Fun.Sqrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Sqrt(this V3l x) { return new V3d(Sqrt(x.X), Sqrt(x.Y), Sqrt(x.Z)); } /// /// Applies Fun.Cbrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Cbrt(this V3l x) { return new V3d(Cbrt(x.X), Cbrt(x.Y), Cbrt(x.Z)); } #endregion #region Square /// /// Applies Fun.Square to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Square(this V3l x) { return new V3l(Square(x.X), Square(x.Y), Square(x.Z)); } #endregion #region Power /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Pown(this V3l x, V3l y) { return new V3l(Pown(x.X, y.X), Pown(x.Y, y.Y), Pown(x.Z, y.Z)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Pown(this V3l x, long y) { return new V3l(Pown(x.X, y), Pown(x.Y, y), Pown(x.Z, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Pown(this long x, V3l y) { return new V3l(Pown(x, y.X), Pown(x, y.Y), Pown(x, y.Z)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Pown(this V3l x, V3i y) { return new V3l(Pown(x.X, y.X), Pown(x.Y, y.Y), Pown(x.Z, y.Z)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Pown(this V3l x, int y) { return new V3l(Pown(x.X, y), Pown(x.Y, y), Pown(x.Z, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Pown(this long x, V3i y) { return new V3l(Pown(x, y.X), Pown(x, y.Y), Pown(x, y.Z)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Pow(this V3l x, V3f y) { return new V3f(Pow(x.X, y.X), Pow(x.Y, y.Y), Pow(x.Z, y.Z)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Pow(this V3l x, float y) { return new V3f(Pow(x.X, y), Pow(x.Y, y), Pow(x.Z, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Pow(this long x, V3f y) { return new V3f(Pow(x, y.X), Pow(x, y.Y), Pow(x, y.Z)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Pow(this V3l x, V3d y) { return new V3d(Pow(x.X, y.X), Pow(x.Y, y.Y), Pow(x.Z, y.Z)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Pow(this V3l x, double y) { return new V3d(Pow(x.X, y), Pow(x.Y, y), Pow(x.Z, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Pow(this long x, V3d y) { return new V3d(Pow(x, y.X), Pow(x, y.Y), Pow(x, y.Z)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Power(this V3l x, V3f y) { return new V3f(Power(x.X, y.X), Power(x.Y, y.Y), Power(x.Z, y.Z)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Power(this V3l x, float y) { return new V3f(Power(x.X, y), Power(x.Y, y), Power(x.Z, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Power(this long x, V3f y) { return new V3f(Power(x, y.X), Power(x, y.Y), Power(x, y.Z)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Power(this V3l x, V3d y) { return new V3d(Power(x.X, y.X), Power(x.Y, y.Y), Power(x.Z, y.Z)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Power(this V3l x, double y) { return new V3d(Power(x.X, y), Power(x.Y, y), Power(x.Z, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Power(this long x, V3d y) { return new V3d(Power(x, y.X), Power(x, y.Y), Power(x, y.Z)); } #endregion #region Exp and Log /// /// Applies Fun.Exp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Exp(this V3l x) { return new V3d(Exp(x.X), Exp(x.Y), Exp(x.Z)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log(this V3l x) { return new V3d(Log(x.X), Log(x.Y), Log(x.Z)); } /// /// Applies Fun.Log2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log2(this V3l x) { return new V3d(Log2(x.X), Log2(x.Y), Log2(x.Z)); } /// /// Applies Fun.Log2Int to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Log2Int(this V3l x) { return new V3i(Log2Int(x.X), Log2Int(x.Y), Log2Int(x.Z)); } /// /// Applies Fun.Log10 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log10(this V3l x) { return new V3d(Log10(x.X), Log10(x.Y), Log10(x.Z)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log(this V3l x, double basis) { return new V3d(Log(x.X, basis), Log(x.Y, basis), Log(x.Z, basis)); } #endregion #region ModP /// /// Applies Fun.ModP to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l ModP(this V3l a, V3l b) { return new V3l(ModP(a.X, b.X), ModP(a.Y, b.Y), ModP(a.Z, b.Z)); } #endregion #region Power of Two /// /// Applies Fun.PowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l PowerOfTwo(this V3l x) { return new V3l(PowerOfTwo(x.X), PowerOfTwo(x.Y), PowerOfTwo(x.Z)); } /// /// Applies Fun.NextPowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l NextPowerOfTwo(this V3l x) { return new V3l(NextPowerOfTwo(x.X), NextPowerOfTwo(x.Y), NextPowerOfTwo(x.Z)); } /// /// Applies Fun.PrevPowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l PrevPowerOfTwo(this V3l x) { return new V3l(PrevPowerOfTwo(x.X), PrevPowerOfTwo(x.Y), PrevPowerOfTwo(x.Z)); } #endregion #region Step functions /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Step(this V3l x, V3l edge) { return new V3l(Step(x.X, edge.X), Step(x.Y, edge.Y), Step(x.Z, edge.Z)); } /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Step(this V3l x, long edge) { return new V3l(Step(x.X, edge), Step(x.Y, edge), Step(x.Z, edge)); } #endregion #region Interpolation /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Lerp(this float t, V3l a, V3l b) { return new V3l(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y), Lerp(t, a.Z, b.Z)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Lerp(this V3f t, V3l a, V3l b) { return new V3l(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y), Lerp(t.Z, a.Z, b.Z)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Lerp(this double t, V3l a, V3l b) { return new V3l(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y), Lerp(t, a.Z, b.Z)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Lerp(this V3d t, V3l a, V3l b) { return new V3l(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y), Lerp(t.Z, a.Z, b.Z)); } /// /// Applies Fun.InvLerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvLerp(this V3l y, V3l a, V3l b) { return new V3d(InvLerp(y.X, a.X, b.X), InvLerp(y.Y, a.Y, b.Y), InvLerp(y.Z, a.Z, b.Z)); } #endregion #region Common Divisor and Multiple /// /// Applies Fun.GreatestCommonDivisor to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l GreatestCommonDivisor(this V3l a, V3l b) { return new V3l(GreatestCommonDivisor(a.X, b.X), GreatestCommonDivisor(a.Y, b.Y), GreatestCommonDivisor(a.Z, b.Z)); } /// /// Applies Fun.LeastCommonMultiple to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l LeastCommonMultiple(this V3l a, V3l b) { return new V3l(LeastCommonMultiple(a.X, b.X), LeastCommonMultiple(a.Y, b.Y), LeastCommonMultiple(a.Z, b.Z)); } #endregion #region Floating point bits /// /// Applies Fun.FloatFromBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FloatFromBits(this V3l x) { return new V3d(FloatFromBits(x.X), FloatFromBits(x.Y), FloatFromBits(x.Z)); } #endregion #region ApproximateEquals /// /// Returns whether the given vectors are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V3l a, V3l b, long tolerance) { return ApproximateEquals(a.X, b.X, tolerance) && ApproximateEquals(a.Y, b.Y, tolerance) && ApproximateEquals(a.Z, b.Z, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this V3l v, long epsilon) => Vec.AllTiny(v, epsilon); #endregion } /// /// Contains static methods /// public static partial class Vec { #region Length /// /// Returns the squared length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long LengthSquared(V3l v) => v.LengthSquared; /// /// Returns the length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Length(V3l v) => v.Length; #endregion #region Normalize /// /// Returns a normalized copy of this vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Normalized(V3l v) => v.Normalized; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Norm1(V3l v) => v.Norm1; /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(V3l v) => v.Norm2; /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NormMax(V3l v) => v.NormMax; /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NormMin(V3l v) => v.NormMin; /// /// Gets the p-norm. This is calculated as the p-th root of (|x|^n + |y|^n + ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this V3l v, double p) { return ( Fun.Abs(v.X).Pow(p) + Fun.Abs(v.Y).Pow(p) + Fun.Abs(v.Z).Pow(p)).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the squared distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long DistanceSquared(this V3l a, V3l b) => Fun.Square(b.X - a.X) + Fun.Square(b.Y - a.Y) + Fun.Square(b.Z - a.Z); /// /// Returns the distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V3l a, V3l b) => Fun.Sqrt(DistanceSquared(a, b)); /// /// Returns the Manhatten (or 1-) distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Distance1(this V3l a, V3l b) => Fun.Abs(b.X - a.X) + Fun.Abs(b.Y - a.Y) + Fun.Abs(b.Z - a.Z); /// /// Returns the p-distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V3l a, V3l b, double p) => (Fun.Abs(b.X - a.X).Pow(p) + Fun.Abs(b.Y - a.Y).Pow(p) + Fun.Abs(b.Z - a.Z).Pow(p)).Pow(1 / p); /// /// Returns the maximal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long DistanceMax(this V3l a, V3l b) => Fun.Max(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y), Fun.Abs(b.Z - a.Z)); /// /// Returns the minimal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long DistanceMin(this V3l a, V3l b) => Fun.Min(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y), Fun.Abs(b.Z - a.Z)); /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V3l query, V3l p0, V3l p1) { return DistanceToLine((V3d) query, (V3d) p0, (V3d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V3l query, V3l p0, V3l p1) { return DistanceToInfiniteLine((V3d) query, (V3d) p0, (V3d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V3l query, V3l p0, V3l p1, out double t) { return DistanceToLine((V3d) query, (V3d) p0, (V3d) p1, out t); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V3l query, V3l p0, V3l p1, out double t) { return DistanceToInfiniteLine((V3d) query, (V3d) p0, (V3d) p1, out t); } #endregion #region Operations /// /// Negates the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Negate(this ref V3l v) { v.X = -v.X; v.Y = -v.Y; v.Z = -v.Z; } /// /// Returns the outer product (tensor-product) of a * b^T as a 3x3 matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33l Outer(this V3l a, V3l b) { return new M33l( a.X * b.X, a.X * b.Y, a.X * b.Z, a.Y * b.X, a.Y * b.Y, a.Y * b.Z, a.Z * b.X, a.Z * b.Y, a.Z * b.Z); } /// /// Returns the dot product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Dot(this V3l a, V3l b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z; } /// /// Returns the skew-symmetric "cross" matrix (A^T = -A) of the vector v. /// public static M33l CrossMatrix(this V3l v) { return new M33l(0, -v.Z, +v.Y, +v.Z, 0, -v.X, -v.Y, +v.X, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DirFlags DirFlags(this V3l v) { DirFlags flags = Aardbase.DirFlags.None; if (v.X > 0) flags |= Aardbase.DirFlags.PositiveX; if (v.X < 0) flags |= Aardbase.DirFlags.NegativeX; if (v.Y > 0) flags |= Aardbase.DirFlags.PositiveY; if (v.Y < 0) flags |= Aardbase.DirFlags.NegativeY; if (v.Z > 0) flags |= Aardbase.DirFlags.PositiveZ; if (v.Z < 0) flags |= Aardbase.DirFlags.NegativeZ; return flags; } /// /// Returns the cross product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l Cross(this V3l a, V3l b) { return new V3l( a.Y * b.Z - a.Z * b.Y, a.Z * b.X - a.X * b.Z, a.X * b.Y - a.Y * b.X ); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V3l a, V3l b) { return (a.X < b.X && a.Y < b.Y && a.Z < b.Z); } /// /// Returns whether ALL elements of v are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V3l v, long s) { return (v.X < s && v.Y < s && v.Z < s); } /// /// Returns whether a is Smaller ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(long s, V3l v) { return (s < v.X && s < v.Y && s < v.Z); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V3l a, V3l b) { return (a.X < b.X || a.Y < b.Y || a.Z < b.Z); } /// /// Returns whether AT LEAST ONE element of v is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V3l v, long s) { return (v.X < s || v.Y < s || v.Z < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(long s, V3l v) { return (s < v.X || s < v.Y || s < v.Z); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V3l a, V3l b) { return (a.X > b.X && a.Y > b.Y && a.Z > b.Z); } /// /// Returns whether ALL elements of v are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V3l v, long s) { return (v.X > s && v.Y > s && v.Z > s); } /// /// Returns whether a is Greater ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(long s, V3l v) { return (s > v.X && s > v.Y && s > v.Z); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V3l a, V3l b) { return (a.X > b.X || a.Y > b.Y || a.Z > b.Z); } /// /// Returns whether AT LEAST ONE element of v is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V3l v, long s) { return (v.X > s || v.Y > s || v.Z > s); } /// /// Returns whether a is Greater AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(long s, V3l v) { return (s > v.X || s > v.Y || s > v.Z); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V3l a, V3l b) { return (a.X <= b.X && a.Y <= b.Y && a.Z <= b.Z); } /// /// Returns whether ALL elements of v are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V3l v, long s) { return (v.X <= s && v.Y <= s && v.Z <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(long s, V3l v) { return (s <= v.X && s <= v.Y && s <= v.Z); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V3l a, V3l b) { return (a.X <= b.X || a.Y <= b.Y || a.Z <= b.Z); } /// /// Returns whether AT LEAST ONE element of v is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V3l v, long s) { return (v.X <= s || v.Y <= s || v.Z <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(long s, V3l v) { return (s <= v.X || s <= v.Y || s <= v.Z); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V3l a, V3l b) { return (a.X >= b.X && a.Y >= b.Y && a.Z >= b.Z); } /// /// Returns whether ALL elements of v are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V3l v, long s) { return (v.X >= s && v.Y >= s && v.Z >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(long s, V3l v) { return (s >= v.X && s >= v.Y && s >= v.Z); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V3l a, V3l b) { return (a.X >= b.X || a.Y >= b.Y || a.Z >= b.Z); } /// /// Returns whether AT LEAST ONE element of v is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V3l v, long s) { return (v.X >= s || v.Y >= s || v.Z >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(long s, V3l v) { return (s >= v.X || s >= v.Y || s >= v.Z); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V3l a, V3l b) { return (a.X == b.X && a.Y == b.Y && a.Z == b.Z); } /// /// Returns whether ALL elements of v are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V3l v, long s) { return (v.X == s && v.Y == s && v.Z == s); } /// /// Returns whether a is Equal ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(long s, V3l v) { return (s == v.X && s == v.Y && s == v.Z); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V3l a, V3l b) { return (a.X == b.X || a.Y == b.Y || a.Z == b.Z); } /// /// Returns whether AT LEAST ONE element of v is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V3l v, long s) { return (v.X == s || v.Y == s || v.Z == s); } /// /// Returns whether a is Equal AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(long s, V3l v) { return (s == v.X || s == v.Y || s == v.Z); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V3l a, V3l b) { return (a.X != b.X && a.Y != b.Y && a.Z != b.Z); } /// /// Returns whether ALL elements of v are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V3l v, long s) { return (v.X != s && v.Y != s && v.Z != s); } /// /// Returns whether a is Different ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(long s, V3l v) { return (s != v.X && s != v.Y && s != v.Z); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V3l a, V3l b) { return (a.X != b.X || a.Y != b.Y || a.Z != b.Z); } /// /// Returns whether AT LEAST ONE element of v is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V3l v, long s) { return (v.X != s || v.Y != s || v.Z != s); } /// /// Returns whether a is Different AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(long s, V3l v) { return (s != v.X || s != v.Y || s != v.Z); } /// /// Compare x-coordinate before y-coordinate, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this V3l v0, V3l v1) { if (v0.X < v1.X) return -1; if (v0.X > v1.X) return +1; if (v0.Y < v1.Y) return -1; if (v0.Y > v1.Y) return +1; if (v0.Z < v1.Z) return -1; if (v0.Z > v1.Z) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MinElement(V3l v) => v.MinElement; /// /// Returns the maximum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MaxElement(V3l v) => v.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this V3l v, long epsilon) => v.X.IsTiny(epsilon) || v.Y.IsTiny(epsilon) || v.Z.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this V3l v, long epsilon) => v.X.IsTiny(epsilon) && v.Y.IsTiny(epsilon) && v.Z.IsTiny(epsilon); #endregion #region ArrayExtensions public static int IndexOfClosestPoint(this V3l[] pointArray, V3l point) { var bestDist = DistanceSquared(point, pointArray[0]); int bestIndex = 0; int count = pointArray.Length; for (int i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this V3l[] array, int start, int count, V3l point) { var bestDist = DistanceSquared(point, array[start]); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this T[] array, int start, int count, Func pointSelector, V3l point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint(this V3l[] pointArray, V3l point) { var bestDist = DistanceSquared(point, pointArray[0]); long bestIndex = 0; long count = pointArray.LongLength; for (long i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this V3l[] array, long start, long count, V3l point) { var bestDist = DistanceSquared(point, array[start]); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this T[] array, long start, long count, Func pointSelector, V3l point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static int IndexOfMinX(this V3l[] vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static long LongIndexOfMinX(this V3l[] vectorArray, long count = 0) { var minimum = vectorArray[0].X; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static int IndexOfMaxX(this V3l[] vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static long LongIndexOfMaxX(this V3l[] vectorArray, long count = 0) { var maximum = vectorArray[0].X; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static int IndexOfMinY(this V3l[] vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static long LongIndexOfMinY(this V3l[] vectorArray, long count = 0) { var minimum = vectorArray[0].Y; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static int IndexOfMaxY(this V3l[] vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static long LongIndexOfMaxY(this V3l[] vectorArray, long count = 0) { var maximum = vectorArray[0].Y; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static int IndexOfMinZ(this V3l[] vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static long LongIndexOfMinZ(this V3l[] vectorArray, long count = 0) { var minimum = vectorArray[0].Z; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static int IndexOfMaxZ(this V3l[] vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static long LongIndexOfMaxZ(this V3l[] vectorArray, long count = 0) { var maximum = vectorArray[0].Z; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the list. /// public static int IndexOfMinX(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the list. /// public static int IndexOfMaxX(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the list. /// public static int IndexOfMinY(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the list. /// public static int IndexOfMaxY(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the list. /// public static int IndexOfMinZ(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the list. /// public static int IndexOfMaxZ(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the array of the index-th coordinate of each vector. /// public static long[] CopyCoord(this V3l[] self, int index) { switch (index) { case 0: return self.Map(v => v.X); case 1: return self.Map(v => v.Y); case 2: return self.Map(v => v.Z); default: throw new IndexOutOfRangeException(); } } #endregion } public static class IRandomUniformV3lExtensions { #region IRandomUniform extensions for V3l /// /// Uses UniformLong() to generate the elements of a V3l vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l UniformV3l(this IRandomUniform rnd) { return new V3l(rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong()); } /// /// Uses UniformLongNonZero() to generate the elements of a V3l vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l UniformV3lNonZero(this IRandomUniform rnd) { return new V3l(rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero()); } /// /// Uses UniformLong(long) to generate the elements of a V3l vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l UniformV3l(this IRandomUniform rnd, long size) { return new V3l(rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size)); } /// /// Uses UniformLong(long) to generate the elements of a V3l vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l UniformV3l(this IRandomUniform rnd, V3l size) { return new V3l(rnd.UniformLong(size.X), rnd.UniformLong(size.Y), rnd.UniformLong(size.Z)); } #endregion } #endregion #region V3f [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct V3f : IVector, ISize3f, IFormattable, IEquatable { [DataMember] public float X; [DataMember] public float Y; [DataMember] public float Z; #region Constructors /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(int x, int y, int z) { X = (float)x; Y = (float)y; Z = (float)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(int v) { X = (float)v; Y = (float)v; Z = (float)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(int[] a) { X = (float)a[0]; Y = (float)a[1]; Z = (float)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(int[] a, int start) { X = (float)a[start + 0]; Y = (float)a[start + 1]; Z = (float)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(int a, V2i b) { X = (float)a; Y = (float)b.X; Z = (float)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V2i a, int b) { X = (float)a.X; Y = (float)a.Y; Z = (float)b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(uint x, uint y, uint z) { X = (float)x; Y = (float)y; Z = (float)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(uint v) { X = (float)v; Y = (float)v; Z = (float)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(uint[] a) { X = (float)a[0]; Y = (float)a[1]; Z = (float)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(uint[] a, int start) { X = (float)a[start + 0]; Y = (float)a[start + 1]; Z = (float)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(uint a, V2ui b) { X = (float)a; Y = (float)b.X; Z = (float)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V2ui a, uint b) { X = (float)a.X; Y = (float)a.Y; Z = (float)b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(long x, long y, long z) { X = (float)x; Y = (float)y; Z = (float)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(long v) { X = (float)v; Y = (float)v; Z = (float)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(long[] a) { X = (float)a[0]; Y = (float)a[1]; Z = (float)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(long[] a, int start) { X = (float)a[start + 0]; Y = (float)a[start + 1]; Z = (float)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(long a, V2l b) { X = (float)a; Y = (float)b.X; Z = (float)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V2l a, long b) { X = (float)a.X; Y = (float)a.Y; Z = (float)b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(float x, float y, float z) { X = x; Y = y; Z = z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(float v) { X = v; Y = v; Z = v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(float[] a) { X = a[0]; Y = a[1]; Z = a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(float[] a, int start) { X = a[start + 0]; Y = a[start + 1]; Z = a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(float a, V2f b) { X = a; Y = b.X; Z = b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V2f a, float b) { X = a.X; Y = a.Y; Z = b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(double x, double y, double z) { X = (float)x; Y = (float)y; Z = (float)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(double v) { X = (float)v; Y = (float)v; Z = (float)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(double[] a) { X = (float)a[0]; Y = (float)a[1]; Z = (float)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(double[] a, int start) { X = (float)a[start + 0]; Y = (float)a[start + 1]; Z = (float)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(double a, V2d b) { X = (float)a; Y = (float)b.X; Z = (float)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V2d a, double b) { X = (float)a.X; Y = (float)a.Y; Z = (float)b; } /// /// Creates a vector from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(Func index_fun) { X = index_fun(0); Y = index_fun(1); Z = index_fun(2); } /// /// Creates a vector from a general vector implementing the IVector<float> interface. /// The caller has to verify that the dimension of is at least 3. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(IVector v) : this(v[0], v[1], v[2]) { } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V2i v) { X = (float)v.X; Y = (float)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V2ui v) { X = (float)v.X; Y = (float)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V2l v) { X = (float)v.X; Y = (float)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V2f v) { X = v.X; Y = v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V2d v) { X = (float)v.X; Y = (float)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V3i v) { X = (float)v.X; Y = (float)v.Y; Z = (float)v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V3ui v) { X = (float)v.X; Y = (float)v.Y; Z = (float)v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V3l v) { X = (float)v.X; Y = (float)v.Y; Z = (float)v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V3f v) { X = v.X; Y = v.Y; Z = v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V3d v) { X = (float)v.X; Y = (float)v.Y; Z = (float)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V4i v) { X = (float)v.X; Y = (float)v.Y; Z = (float)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V4ui v) { X = (float)v.X; Y = (float)v.Y; Z = (float)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V4l v) { X = (float)v.X; Y = (float)v.Y; Z = (float)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V4f v) { X = v.X; Y = v.Y; Z = v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(V4d v) { X = (float)v.X; Y = (float)v.Y; Z = (float)v.Z; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(C3b c) { X = (float)(c.R); Y = (float)(c.G); Z = (float)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(C3us c) { X = (float)(c.R); Y = (float)(c.G); Z = (float)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(C3ui c) { X = (float)(c.R); Y = (float)(c.G); Z = (float)(c.B); } /// /// Creates a vector from a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(C3f c) { X = (c.R); Y = (c.G); Z = (c.B); } /// /// Creates a vector from a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(C3d c) { X = (float)(c.R); Y = (float)(c.G); Z = (float)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(C4b c) { X = (float)(c.R); Y = (float)(c.G); Z = (float)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(C4us c) { X = (float)(c.R); Y = (float)(c.G); Z = (float)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(C4ui c) { X = (float)(c.R); Y = (float)(c.G); Z = (float)(c.B); } /// /// Creates a vector from a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(C4f c) { X = (c.R); Y = (c.G); Z = (c.B); } /// /// Creates a vector from a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3f(C4d c) { X = (float)(c.R); Y = (float)(c.G); Z = (float)(c.B); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(V2i v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(V2ui v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(V2l v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(V2f v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(V2d v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(V3i v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(V3ui v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(V3l v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(V3d v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(V4i v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(V4ui v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(V4l v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(V4f v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(V4d v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToV2i() => (V2i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui ToV2ui() => (V2ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToV2l() => (V2l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d ToV2d() => (V2d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int[](V3f v) => new int[] { (int)v.X, (int)v.Y, (int)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(int[] v) => new V3f((float)v[0], (float)v[1], (float)v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](V3f v) => new uint[] { (uint)v.X, (uint)v.Y, (uint)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(uint[] v) => new V3f((float)v[0], (float)v[1], (float)v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long[](V3f v) => new long[] { (long)v.X, (long)v.Y, (long)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(long[] v) => new V3f((float)v[0], (float)v[1], (float)v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](V3f v) => new float[] { v.X, v.Y, v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(float[] v) => new V3f(v[0], v[1], v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](V3f v) => new double[] { (double)v.X, (double)v.Y, (double)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(double[] v) => new V3f((float)v[0], (float)v[1], (float)v[2]); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(C3b v) => new V3f(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(C3us v) => new V3f(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(C3ui v) => new V3f(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(C3f v) => new V3f(v); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f ToC3f() => (C3f)this; /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(C3d v) => new V3f(v); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d ToC3d() => (C3d)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(C4b v) => new V3f(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(C4us v) => new V3f(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(C4ui v) => new V3f(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(C4f v) => new V3f(v); /// /// Converts the given vector to a color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f ToC4f() => (C4f)this; /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3f(C4d v) => new V3f(v); /// /// Converts the given vector to a color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d ToC4d() => (C4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToFloorV3i() => new V3i((int)Fun.Floor(X), (int)Fun.Floor(Y), (int)Fun.Floor(Z)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToCeilingV3i() => new V3i((int)Fun.Ceiling(X), (int)Fun.Ceiling(Y), (int)Fun.Ceiling(Z)); /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToV2iInhomo() { var div = 1 / Z; return new V2i(X * div, Y * div); } /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui ToV2uiInhomo() { var div = 1 / Z; return new V2ui(X * div, Y * div); } /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToV2lInhomo() { var div = 1 / Z; return new V2l(X * div, Y * div); } /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f ToV2fInhomo() { var div = 1 / Z; return new V2f(X * div, Y * div); } /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d ToV2dInhomo() { var div = 1 / Z; return new V2d(X * div, Y * div); } /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4iHomo() => new V4i(X, Y, Z, 1); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4uiHomo() => new V4ui(X, Y, Z, 1); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4lHomo() => new V4l(X, Y, Z, 1); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4fHomo() => new V4f(X, Y, Z, 1); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4dHomo() => new V4d(X, Y, Z, 1); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i Copy(Func element_fun) => new V3i(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i Copy(Func element_index_fun) => new V3i(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(int[] array, int start) { array[start + 0] = (int)X; array[start + 1] = (int)Y; array[start + 2] = (int)Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui Copy(Func element_fun) => new V3ui(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui Copy(Func element_index_fun) => new V3ui(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(uint[] array, int start) { array[start + 0] = (uint)X; array[start + 1] = (uint)Y; array[start + 2] = (uint)Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l Copy(Func element_fun) => new V3l(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l Copy(Func element_index_fun) => new V3l(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(long[] array, int start) { array[start + 0] = (long)X; array[start + 1] = (long)Y; array[start + 2] = (long)Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f Copy(Func element_fun) => new V3f(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f Copy(Func element_index_fun) => new V3f(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(float[] array, int start) { array[start + 0] = X; array[start + 1] = Y; array[start + 2] = Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d Copy(Func element_fun) => new V3d(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d Copy(Func element_index_fun) => new V3d(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(double[] array, int start) { array[start + 0] = (double)X; array[start + 1] = (double)Y; array[start + 2] = (double)Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(X); array[start + 1] = element_fun(Y); array[start + 2] = element_fun(Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(X, 0); array[start + 1] = element_index_fun(Y, 1); array[start + 2] = element_index_fun(Z, 2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float[] ToArray() => new float[] { X, Y, Z }; #endregion #region Properties and Indexers /// /// Property for the field X. /// Useful when properties are required, but the field X is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public float P_X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value; } } /// /// Property for the field Y. /// Useful when properties are required, but the field Y is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public float P_Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Y = value; } } /// /// Property for the field Z. /// Useful when properties are required, but the field Z is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public float P_Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Z = value; } } /// /// Enumerates all elements of this vector. /// public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return X; yield return Y; yield return Z; } } /// /// Gets or sets element with given index. /// public unsafe float this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &X) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &X) { ptr[index] = value; } } } /// /// Returns the index of the largest dimension of the vector. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X >= Y ? (X >= Z ? 0 : 2) : (Y >= Z ? 1 : 2); } } /// /// Returns the index of the smallest dimension of the vector. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X <= Y ? (X <= Z ? 0 : 2) : (Y <= Z ? 1 : 2); } } /// /// Returns the minimum element of the vector. /// public readonly float MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(X, Y, Z); } /// /// Returns the maximum element of the vector. /// public readonly float MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(X, Y, Z); } public readonly bool AnyFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsFinite(X) || Fun.IsFinite(Y) || Fun.IsFinite(Z); } public readonly bool AllFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsFinite(X) && Fun.IsFinite(Y) && Fun.IsFinite(Z); } public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNaN(X) || float.IsNaN(Y) || float.IsNaN(Z); } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNaN(X) && float.IsNaN(Y) && float.IsNaN(Z); } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsInfinity(X) || float.IsInfinity(Y) || float.IsInfinity(Z); } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsInfinity(X) && float.IsInfinity(Y) && float.IsInfinity(Z); } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsPositiveInfinity(X) || float.IsPositiveInfinity(Y) || float.IsPositiveInfinity(Z); } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsPositiveInfinity(X) && float.IsPositiveInfinity(Y) && float.IsPositiveInfinity(Z); } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNegativeInfinity(X) || float.IsNegativeInfinity(Y) || float.IsNegativeInfinity(Z); } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNegativeInfinity(X) && float.IsNegativeInfinity(Y) && float.IsNegativeInfinity(Z); } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(X) || Fun.IsTiny(Y) || Fun.IsTiny(Z); } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(X) && Fun.IsTiny(Y) && Fun.IsTiny(Z); } /// /// Returns true if the absolute value of each component of the vector is smaller than Constant<float>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any component of the vector is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any component of the vector is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any component of the vector is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any component of the vector is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all components of the vector are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Constants /// /// Number of elements in this vector. /// public const int Dimension = 3; /// /// All elements zero. /// public static V3f Zero { get { return new V3f(0, 0, 0); } } /// /// All elements half. /// public static V3f Half { get { return new V3f(0.5, 0.5, 0.5); } } /// /// All elements one. /// public static V3f One { get { return new V3f(1, 1, 1); } } /// /// All elements set to maximum possible value. /// public static V3f MaxValue { get { return new V3f(Constant.ParseableMaxValue, Constant.ParseableMaxValue, Constant.ParseableMaxValue); } } /// /// All elements set to minimum possible value. /// public static V3f MinValue { get { return new V3f(Constant.ParseableMinValue, Constant.ParseableMinValue, Constant.ParseableMinValue); } } /// /// All elements set to negative infinity. /// public static V3f NegativeInfinity { get { return new V3f(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); } } /// /// All elements set to positive infinity. /// public static V3f PositiveInfinity { get { return new V3f(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); } } /// /// All elements set to NaN. /// public static V3f NaN { get { return new V3f(float.NaN, float.NaN, float.NaN); } } /// /// Normalized X-axis. /// public static V3f XAxis { get { return new V3f(1, 0, 0); } } /// /// Normalized Y-axis. /// public static V3f YAxis { get { return new V3f(0, 1, 0); } } /// /// Normalized Z-axis. /// public static V3f ZAxis { get { return new V3f(0, 0, 1); } } /// /// An array of accessor functions for the coordinates of the vector. /// public static readonly Func[] SelectorArray = new Func[] { v => v.X, v => v.Y, v => v.Z }; /// /// Element getter function. /// public static readonly Func Getter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref V3f v, int i, float s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; default: throw new IndexOutOfRangeException(); } }; /// /// Element getter function with long index. /// public static readonly Func LongGetter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action with long index. /// public static readonly ActionRefValVal LongSetter = (ref V3f v, long i, float s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Static factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FromV3i(V3i v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FromV3ui(V3ui v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FromV3l(V3l v) => new V3f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FromV3d(V3d v) => new V3f(v); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FromC3b(C3b c) => new V3f(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FromC3us(C3us c) => new V3f(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FromC3ui(C3ui c) => new V3f(c); /// /// Creates a vector from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FromC3f(C3f c) => new V3f(c); /// /// Creates a vector from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FromC3d(C3d c) => new V3f(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FromC4b(C4b c) => new V3f(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FromC4us(C4us c) => new V3f(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FromC4ui(C4ui c) => new V3f(c); /// /// Creates a vector from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FromC4f(C4f c) => new V3f(c); /// /// Creates a vector from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FromC4d(C4d c) => new V3f(c); private static readonly V3f[] s_fromCubeCode = new V3f[] { -V3f.XAxis, -V3f.YAxis, -V3f.ZAxis, V3f.XAxis, V3f.YAxis, V3f.ZAxis }; /// /// Return the vector for the supplied cube face code. /// 0 ... -XAxis, 1 ... -YAxis, 2 ... -ZAsix, 3 ... XAxis, 4 ... YAxis, 5 ... ZAxis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FromCubeFaceCode(int i) { return s_fromCubeCode[i]; } #endregion #region Norms /// /// Returns the squared length of the vector. /// public readonly float LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X * X + Y * Y + Z * Z ; } } /// /// Returns the length of the vector. /// public readonly float Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z ); } } /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// public readonly float Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Abs(X) + Fun.Abs(Y) + Fun.Abs(Z); } } /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// public readonly float Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z); } } /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// public readonly float NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z)); } } /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// public readonly float NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z)); } } /// /// Returns a normalized copy of this vector. /// public readonly V3f Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Length; if (s == 0) return V3f.Zero; s = 1 / s; return new V3f(X * s, Y * s, Z * s); } } /// /// Returns a copy of the vector with the maximum component length of /// exactly 1. This corresponds to mapping the vector onto an origin- /// centered cube with side length 2. /// public readonly V3f CubeMapped { get { float x = Fun.Abs(X); float y = Fun.Abs(Y); float z = Fun.Abs(Z); if (x > y) { if (x > z) { double s = 1 / x; return new V3f(Fun.Sign(X), Y * s, Z * s); } else { double s = 1 / z; return new V3f(X * s, Y * s, Fun.Sign(Z)); } } else { if (y > z) { double s = 1 / y; return new V3f(X * s, Fun.Sign(Y), Z * s); } else { double s = 1 / z; return new V3f(X * s, Y * s, Fun.Sign(Z)); } } } } /// /// Returns a copy of the vector with the maximum component length of /// exactly 1. This corresponds to mapping the vector onto an origin- /// centered cube with side length 2. /// The out parameter face indicate which face the vector was mapped to: /// 0 ... -XAxis, 1 ... -YAxis, 2 ... -ZAsix, 3 ... XAxis, 4 ... YAxis, 5 ... ZAxis. /// public readonly V3f CubeMappedOnFace(out int face) { float x = Fun.Abs(X); float y = Fun.Abs(Y); float z = Fun.Abs(Z); if (x > y) { if (x > z) { double s = 1 / x; face = X < 0 ? 0 : 3; return new V3f(Fun.Sign(X), Y * s, Z * s); } else { double s = 1 / z; face = Z < 0 ? 2 : 5; return new V3f(X * s, Y * s, Fun.Sign(Z)); } } else { if (y > z) { double s = 1 / y; face = Y < 0 ? 1 : 4; return new V3f(X * s, Fun.Sign(Y), Z * s); } else { double s = 1 / z; face = Z < 0 ? 2 : 5; return new V3f(X * s, Y * s, Fun.Sign(Z)); } } } /// /// Return an index for the cube face onto which the vector points. /// 0 ... -XAxis, 1 ... -YAxis, 2 ... -ZAsix, 3 ... XAxis, 4 ... YAxis, 5 ... ZAxis. /// public readonly int CubeFaceCode { get { double x = Fun.Abs(X); double y = Fun.Abs(Y); double z = Fun.Abs(Z); int c; double v; if (x > y) { if (x > z) { c = 0; v = X; } else { c = 2; v = Z; } } else { if (y > z) { c = 1; v = Y; } else { c = 2; v = Z; } } return v < 0 ? c : c + 3; } } #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Abs(V3f v) => v.Abs(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Floor(V3f v) => v.Floor(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Ceiling(V3f v) => v.Ceiling(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Round(V3f v) => v.Round(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Truncate(V3f v) => v.Truncate(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Acos(V3f v) => Fun.Acos(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Acoshb(V3f v) => Fun.Acosh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Cos(V3f v) => Fun.Cos(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Cosh(V3f v) => Fun.Cosh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Asin(V3f v) => Fun.Asin(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Asinhb(V3f v) => Fun.Asinh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Sin(V3f v) => Fun.Sin(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Sinh(V3f v) => Fun.Sinh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Atan(V3f v) => Fun.Atan(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Atanhb(V3f v) => Fun.Atanh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Atan2(V3f a, V3f b) => Fun.Atan2(a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Tan(V3f v) => Fun.Tan(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Tanh(V3f v) => Fun.Tanh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Sqrt(V3f v) => Fun.Sqrt(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f CubeRoot(V3f v) => Fun.Cbrt(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Exp(V3f v) => Fun.Exp(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Log(V3f v) => Fun.Log(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f LogBinary(V3f v) => Fun.Log2(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Log10(V3f v) => Fun.Log10(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f CopySgn(V3f value, V3f sign) => Fun.CopySign(value, sign); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f CopySgn(V3f value, float sign) => Fun.CopySign(value, sign); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f LinearInterp(float t, V3f a, V3f b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f LinearInterp(V3f t, V3f a, V3f b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Min(V3f v0, V3f v1) => Fun.Min(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Min(V3f v, float x) => Fun.Min(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Max(V3f v0, V3f v1) => Fun.Max(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Max(V3f v, float x) => Fun.Max(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Saturate(V3f v) => Fun.Saturate(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f DivideByInt(V3f v, int x) => v / x; #endregion #region Operations /// /// Sets the elements of a vector to the given int elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(int x, int y, int z) { X = (float)x; Y = (float)y; Z = (float)z; } /// /// Sets the elements of a vector to the given uint elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(uint x, uint y, uint z) { X = (float)x; Y = (float)y; Z = (float)z; } /// /// Sets the elements of a vector to the given long elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(long x, long y, long z) { X = (float)x; Y = (float)y; Z = (float)z; } /// /// Sets the elements of a vector to the given float elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(float x, float y, float z) { X = x; Y = y; Z = z; } /// /// Sets the elements of a vector to the given double elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(double x, double y, double z) { X = (float)x; Y = (float)y; Z = (float)z; } /// /// Returns a negated copy of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator -(V3f v) => new V3f(-v.X, -v.Y, -v.Z); /// /// Gets a copy of this vector containing the reciprocal (1/x) of each element. /// public readonly V3f Reciprocal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3f(1 / X, 1 / Y, 1 / Z); } } /// /// Returns the component-wise sum of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator +(V3f a, V3f b) => new V3f(a.X + b.X, a.Y + b.Y, a.Z + b.Z); /// /// Returns the component-wise sum of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator +(V3f v, float s) => new V3f(v.X + s, v.Y + s, v.Z + s); /// /// Returns the component-wise sum of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator +(float s, V3f v) => new V3f(s + v.X, s + v.Y, s + v.Z); /// /// Returns the component-wise difference of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator -(V3f a, V3f b) => new V3f(a.X - b.X, a.Y - b.Y, a.Z - b.Z); /// /// Returns the component-wise difference of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator -(V3f v, float s) => new V3f(v.X - s, v.Y - s, v.Z - s); /// /// Returns the component-wise difference of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator -(float s, V3f v) => new V3f(s - v.X, s - v.Y, s - v.Z); /// /// Returns the component-wise product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator *(V3f a, V3f b) => new V3f(a.X * b.X, a.Y * b.Y, a.Z * b.Z); /// /// Returns the component-wise product of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator *(V3f v, float s) => new V3f(v.X * s, v.Y * s, v.Z * s); /// /// Returns the component-wise product of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator *(float s, V3f v) => new V3f(s * v.X, s * v.Y, s * v.Z); /// /// Returns the component-wise fraction of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator /(V3f a, V3f b) => new V3f(a.X / b.X, a.Y / b.Y, a.Z / b.Z); /// /// Returns the component-wise fraction of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator /(V3f v, float s) => new V3f(v.X / s, v.Y / s, v.Z / s); /// /// Returns the component-wise fraction of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator /(float s, V3f v) => new V3f(s / v.X, s / v.Y, s / v.Z); /// /// Returns the component-wise remainder of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator %(V3f a, V3f b) => new V3f(a.X % b.X, a.Y % b.Y, a.Z % b.Z); /// /// Returns the component-wise remainder of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator %(V3f v, float s) => new V3f(v.X % s, v.Y % s, v.Z % s); /// /// Returns the component-wise remainder of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f operator %(float s, V3f v) => new V3f(s % v.X, s % v.Y, s % v.Z); /// Attention: NEVER implement operators <, <=, >=, >, /// since these are not defined in a Vector space. /// Use AllSmaller() and similar comparators! #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V3f a, V3f b) { return a.X == b.X && a.Y == b.Y && a.Z == b.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V3f v, float s) { return v.X == s && v.Y == s && v.Z == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(float s, V3f v) { return s == v.X && s == v.Y && s == v.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V3f a, V3f b) { return a.X != b.X || a.Y != b.Y || a.Z != b.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V3f v, float s) { return v.X != s || v.Y != s || v.Z != s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(float s, V3f v) { return s != v.X || s != v.Y || s != v.Z; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(V3f other) { return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z); } #endregion #region Overrides public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + X.ToString(format, fp) + between + Y.ToString(format, fp) + between + Z.ToString(format, fp) + end; } public override readonly int GetHashCode() { return HashCode.GetCombined(X, Y, Z); } public override readonly bool Equals(object other) => (other is V3f o) ? Equals(o) : false; public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + X.ToString(null, CultureInfo.InvariantCulture) + ", " + Y.ToString(null, CultureInfo.InvariantCulture) + ", " + Z.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Parsing public static V3f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new V3f( float.Parse(x[0], CultureInfo.InvariantCulture), float.Parse(x[1], CultureInfo.InvariantCulture), float.Parse(x[2], CultureInfo.InvariantCulture) ); } public static V3f Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, V3f.Setter); } public static V3f Parse(Text t, int bracketLevel) { return t.NestedBracketSplit(bracketLevel, Text.Parse, V3f.Setter); } #endregion #region Swizzle Methods [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f OX => new V2f(0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f OY => new V2f(0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f OZ => new V2f(0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f IX => new V2f(1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f IY => new V2f(1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f IZ => new V2f(1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f NX => new V2f(-1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f NY => new V2f(-1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f NZ => new V2f(-1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f XO => new V2f(X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f XI => new V2f(X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f XN => new V2f(X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f XX => new V2f(X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f XY { readonly get => new V2f(X, Y); set { X = value.X; Y = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f XZ { readonly get => new V2f(X, Z); set { X = value.X; Z = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f YO => new V2f(Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f YI => new V2f(Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f YN => new V2f(Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f YX { readonly get => new V2f(Y, X); set { Y = value.X; X = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f YY => new V2f(Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f YZ { readonly get => new V2f(Y, Z); set { Y = value.X; Z = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f ZO => new V2f(Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f ZI => new V2f(Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f ZN => new V2f(Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f ZX { readonly get => new V2f(Z, X); set { Z = value.X; X = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f ZY { readonly get => new V2f(Z, Y); set { Z = value.X; Y = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f ZZ => new V2f(Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f OOO => new V3f(0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f OOI => new V3f(0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f OON => new V3f(0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OOX => new V3f(0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OOY => new V3f(0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OOZ => new V3f(0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f OIO => new V3f(0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f OII => new V3f(0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f OPN => new V3f(0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OIX => new V3f(0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OIY => new V3f(0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OIZ => new V3f(0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f ONO => new V3f(0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f ONP => new V3f(0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f ONN => new V3f(0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ONX => new V3f(0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ONY => new V3f(0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ONZ => new V3f(0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXO => new V3f(0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXI => new V3f(0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXN => new V3f(0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXX => new V3f(0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXY => new V3f(0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXZ => new V3f(0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYO => new V3f(0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYI => new V3f(0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYN => new V3f(0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYX => new V3f(0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYY => new V3f(0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYZ => new V3f(0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OZO => new V3f(0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OZI => new V3f(0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OZN => new V3f(0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OZX => new V3f(0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OZY => new V3f(0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OZZ => new V3f(0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f IOO => new V3f(1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f IOI => new V3f(1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f PON => new V3f(1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IOX => new V3f(1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IOY => new V3f(1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IOZ => new V3f(1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f IIO => new V3f(1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f III => new V3f(1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f PPN => new V3f(1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IIX => new V3f(1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IIY => new V3f(1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IIZ => new V3f(1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f PNO => new V3f(1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f PNP => new V3f(1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f PNN => new V3f(1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PNX => new V3f(1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PNY => new V3f(1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PNZ => new V3f(1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IXO => new V3f(1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IXI => new V3f(1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PXN => new V3f(1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IXX => new V3f(1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IXY => new V3f(1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IXZ => new V3f(1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IYO => new V3f(1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IYI => new V3f(1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PYN => new V3f(1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IYX => new V3f(1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IYY => new V3f(1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IYZ => new V3f(1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IZO => new V3f(1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IZI => new V3f(1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PZN => new V3f(1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IZX => new V3f(1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IZY => new V3f(1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IZZ => new V3f(1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f NOO => new V3f(-1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f NOP => new V3f(-1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f NON => new V3f(-1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NOX => new V3f(-1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NOY => new V3f(-1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NOZ => new V3f(-1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f NPO => new V3f(-1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f NPP => new V3f(-1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f NPN => new V3f(-1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NPX => new V3f(-1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NPY => new V3f(-1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NPZ => new V3f(-1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f NNO => new V3f(-1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f NNP => new V3f(-1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3f NNN => new V3f(-1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NNX => new V3f(-1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NNY => new V3f(-1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NNZ => new V3f(-1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXO => new V3f(-1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXP => new V3f(-1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXN => new V3f(-1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXX => new V3f(-1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXY => new V3f(-1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXZ => new V3f(-1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYO => new V3f(-1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYP => new V3f(-1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYN => new V3f(-1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYX => new V3f(-1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYY => new V3f(-1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYZ => new V3f(-1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NZO => new V3f(-1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NZP => new V3f(-1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NZN => new V3f(-1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NZX => new V3f(-1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NZY => new V3f(-1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NZZ => new V3f(-1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XOO => new V3f(X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XOI => new V3f(X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XON => new V3f(X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XOX => new V3f(X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XOY => new V3f(X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XOZ => new V3f(X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XIO => new V3f(X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XII => new V3f(X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XPN => new V3f(X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XIX => new V3f(X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XIY => new V3f(X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XIZ => new V3f(X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNO => new V3f(X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNP => new V3f(X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNN => new V3f(X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNX => new V3f(X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNY => new V3f(X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNZ => new V3f(X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXO => new V3f(X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXI => new V3f(X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXN => new V3f(X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXX => new V3f(X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXY => new V3f(X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXZ => new V3f(X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XYO => new V3f(X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XYI => new V3f(X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XYN => new V3f(X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XYX => new V3f(X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XYY => new V3f(X, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f XYZ { readonly get => new V3f(X, Y, Z); set { X = value.X; Y = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XZO => new V3f(X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XZI => new V3f(X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XZN => new V3f(X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XZX => new V3f(X, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f XZY { readonly get => new V3f(X, Z, Y); set { X = value.X; Z = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XZZ => new V3f(X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YOO => new V3f(Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YOI => new V3f(Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YON => new V3f(Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YOX => new V3f(Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YOY => new V3f(Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YOZ => new V3f(Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YIO => new V3f(Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YII => new V3f(Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YPN => new V3f(Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YIX => new V3f(Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YIY => new V3f(Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YIZ => new V3f(Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNO => new V3f(Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNP => new V3f(Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNN => new V3f(Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNX => new V3f(Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNY => new V3f(Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNZ => new V3f(Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YXO => new V3f(Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YXI => new V3f(Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YXN => new V3f(Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YXX => new V3f(Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YXY => new V3f(Y, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f YXZ { readonly get => new V3f(Y, X, Z); set { Y = value.X; X = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYO => new V3f(Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYI => new V3f(Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYN => new V3f(Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYX => new V3f(Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYY => new V3f(Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYZ => new V3f(Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YZO => new V3f(Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YZI => new V3f(Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YZN => new V3f(Y, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f YZX { readonly get => new V3f(Y, Z, X); set { Y = value.X; Z = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YZY => new V3f(Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YZZ => new V3f(Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZOO => new V3f(Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZOI => new V3f(Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZON => new V3f(Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZOX => new V3f(Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZOY => new V3f(Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZOZ => new V3f(Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZIO => new V3f(Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZII => new V3f(Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZPN => new V3f(Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZIX => new V3f(Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZIY => new V3f(Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZIZ => new V3f(Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZNO => new V3f(Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZNP => new V3f(Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZNN => new V3f(Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZNX => new V3f(Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZNY => new V3f(Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZNZ => new V3f(Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZXO => new V3f(Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZXI => new V3f(Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZXN => new V3f(Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZXX => new V3f(Z, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f ZXY { readonly get => new V3f(Z, X, Y); set { Z = value.X; X = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZXZ => new V3f(Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZYO => new V3f(Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZYI => new V3f(Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZYN => new V3f(Z, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f ZYX { readonly get => new V3f(Z, Y, X); set { Z = value.X; Y = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZYY => new V3f(Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZYZ => new V3f(Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZZO => new V3f(Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZZI => new V3f(Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZZN => new V3f(Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZZX => new V3f(Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZZY => new V3f(Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZZZ => new V3f(Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOOX => new V4f(0, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOOY => new V4f(0, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOOZ => new V4f(0, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOIX => new V4f(0, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOIY => new V4f(0, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOIZ => new V4f(0, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OONX => new V4f(0, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OONY => new V4f(0, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OONZ => new V4f(0, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXO => new V4f(0, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXI => new V4f(0, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXN => new V4f(0, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXX => new V4f(0, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXY => new V4f(0, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXZ => new V4f(0, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYO => new V4f(0, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYI => new V4f(0, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYN => new V4f(0, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYX => new V4f(0, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYY => new V4f(0, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYZ => new V4f(0, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOZO => new V4f(0, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOZI => new V4f(0, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOZN => new V4f(0, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOZX => new V4f(0, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOZY => new V4f(0, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOZZ => new V4f(0, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIOX => new V4f(0, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIOY => new V4f(0, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIOZ => new V4f(0, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIIX => new V4f(0, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIIY => new V4f(0, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIIZ => new V4f(0, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPNX => new V4f(0, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPNY => new V4f(0, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPNZ => new V4f(0, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIXO => new V4f(0, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIXI => new V4f(0, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPXN => new V4f(0, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIXX => new V4f(0, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIXY => new V4f(0, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIXZ => new V4f(0, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIYO => new V4f(0, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIYI => new V4f(0, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPYN => new V4f(0, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIYX => new V4f(0, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIYY => new V4f(0, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIYZ => new V4f(0, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIZO => new V4f(0, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIZI => new V4f(0, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPZN => new V4f(0, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIZX => new V4f(0, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIZY => new V4f(0, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIZZ => new V4f(0, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONOX => new V4f(0, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONOY => new V4f(0, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONOZ => new V4f(0, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONPX => new V4f(0, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONPY => new V4f(0, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONPZ => new V4f(0, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONNX => new V4f(0, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONNY => new V4f(0, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONNZ => new V4f(0, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXO => new V4f(0, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXP => new V4f(0, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXN => new V4f(0, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXX => new V4f(0, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXY => new V4f(0, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXZ => new V4f(0, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYO => new V4f(0, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYP => new V4f(0, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYN => new V4f(0, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYX => new V4f(0, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYY => new V4f(0, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYZ => new V4f(0, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONZO => new V4f(0, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONZP => new V4f(0, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONZN => new V4f(0, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONZX => new V4f(0, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONZY => new V4f(0, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONZZ => new V4f(0, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXOO => new V4f(0, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXOI => new V4f(0, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXON => new V4f(0, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXOX => new V4f(0, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXOY => new V4f(0, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXOZ => new V4f(0, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXIO => new V4f(0, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXII => new V4f(0, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXPN => new V4f(0, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXIX => new V4f(0, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXIY => new V4f(0, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXIZ => new V4f(0, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNO => new V4f(0, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNP => new V4f(0, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNN => new V4f(0, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNX => new V4f(0, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNY => new V4f(0, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNZ => new V4f(0, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXO => new V4f(0, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXI => new V4f(0, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXN => new V4f(0, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXX => new V4f(0, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXY => new V4f(0, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXZ => new V4f(0, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYO => new V4f(0, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYI => new V4f(0, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYN => new V4f(0, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYX => new V4f(0, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYY => new V4f(0, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYZ => new V4f(0, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXZO => new V4f(0, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXZI => new V4f(0, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXZN => new V4f(0, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXZX => new V4f(0, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXZY => new V4f(0, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXZZ => new V4f(0, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYOO => new V4f(0, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYOI => new V4f(0, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYON => new V4f(0, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYOX => new V4f(0, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYOY => new V4f(0, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYOZ => new V4f(0, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYIO => new V4f(0, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYII => new V4f(0, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYPN => new V4f(0, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYIX => new V4f(0, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYIY => new V4f(0, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYIZ => new V4f(0, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNO => new V4f(0, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNP => new V4f(0, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNN => new V4f(0, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNX => new V4f(0, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNY => new V4f(0, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNZ => new V4f(0, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXO => new V4f(0, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXI => new V4f(0, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXN => new V4f(0, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXX => new V4f(0, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXY => new V4f(0, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXZ => new V4f(0, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYO => new V4f(0, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYI => new V4f(0, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYN => new V4f(0, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYX => new V4f(0, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYY => new V4f(0, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYZ => new V4f(0, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYZO => new V4f(0, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYZI => new V4f(0, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYZN => new V4f(0, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYZX => new V4f(0, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYZY => new V4f(0, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYZZ => new V4f(0, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZOO => new V4f(0, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZOI => new V4f(0, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZON => new V4f(0, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZOX => new V4f(0, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZOY => new V4f(0, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZOZ => new V4f(0, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZIO => new V4f(0, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZII => new V4f(0, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZPN => new V4f(0, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZIX => new V4f(0, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZIY => new V4f(0, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZIZ => new V4f(0, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZNO => new V4f(0, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZNP => new V4f(0, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZNN => new V4f(0, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZNX => new V4f(0, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZNY => new V4f(0, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZNZ => new V4f(0, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZXO => new V4f(0, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZXI => new V4f(0, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZXN => new V4f(0, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZXX => new V4f(0, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZXY => new V4f(0, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZXZ => new V4f(0, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZYO => new V4f(0, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZYI => new V4f(0, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZYN => new V4f(0, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZYX => new V4f(0, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZYY => new V4f(0, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZYZ => new V4f(0, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZZO => new V4f(0, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZZI => new V4f(0, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZZN => new V4f(0, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZZX => new V4f(0, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZZY => new V4f(0, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZZZ => new V4f(0, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOOX => new V4f(1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOOY => new V4f(1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOOZ => new V4f(1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOIX => new V4f(1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOIY => new V4f(1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOIZ => new V4f(1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PONX => new V4f(1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PONY => new V4f(1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PONZ => new V4f(1, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOXO => new V4f(1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOXI => new V4f(1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f POXN => new V4f(1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOXX => new V4f(1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOXY => new V4f(1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOXZ => new V4f(1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOYO => new V4f(1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOYI => new V4f(1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f POYN => new V4f(1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOYX => new V4f(1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOYY => new V4f(1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOYZ => new V4f(1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOZO => new V4f(1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOZI => new V4f(1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f POZN => new V4f(1, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOZX => new V4f(1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOZY => new V4f(1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOZZ => new V4f(1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIOX => new V4f(1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIOY => new V4f(1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIOZ => new V4f(1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIIX => new V4f(1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIIY => new V4f(1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIIZ => new V4f(1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPNX => new V4f(1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPNY => new V4f(1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPNZ => new V4f(1, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIXO => new V4f(1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIXI => new V4f(1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPXN => new V4f(1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIXX => new V4f(1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIXY => new V4f(1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIXZ => new V4f(1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIYO => new V4f(1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIYI => new V4f(1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPYN => new V4f(1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIYX => new V4f(1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIYY => new V4f(1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIYZ => new V4f(1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIZO => new V4f(1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIZI => new V4f(1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPZN => new V4f(1, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIZX => new V4f(1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIZY => new V4f(1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIZZ => new V4f(1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNOX => new V4f(1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNOY => new V4f(1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNOZ => new V4f(1, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNPX => new V4f(1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNPY => new V4f(1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNPZ => new V4f(1, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNNX => new V4f(1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNNY => new V4f(1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNNZ => new V4f(1, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXO => new V4f(1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXP => new V4f(1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXN => new V4f(1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXX => new V4f(1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXY => new V4f(1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXZ => new V4f(1, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYO => new V4f(1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYP => new V4f(1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYN => new V4f(1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYX => new V4f(1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYY => new V4f(1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYZ => new V4f(1, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNZO => new V4f(1, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNZP => new V4f(1, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNZN => new V4f(1, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNZX => new V4f(1, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNZY => new V4f(1, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNZZ => new V4f(1, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXOO => new V4f(1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXOI => new V4f(1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXON => new V4f(1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXOX => new V4f(1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXOY => new V4f(1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXOZ => new V4f(1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXIO => new V4f(1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXII => new V4f(1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXPN => new V4f(1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXIX => new V4f(1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXIY => new V4f(1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXIZ => new V4f(1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNO => new V4f(1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNP => new V4f(1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNN => new V4f(1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNX => new V4f(1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNY => new V4f(1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNZ => new V4f(1, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXXO => new V4f(1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXXI => new V4f(1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXXN => new V4f(1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXXX => new V4f(1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXXY => new V4f(1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXXZ => new V4f(1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXYO => new V4f(1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXYI => new V4f(1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXYN => new V4f(1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXYX => new V4f(1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXYY => new V4f(1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXYZ => new V4f(1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXZO => new V4f(1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXZI => new V4f(1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXZN => new V4f(1, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXZX => new V4f(1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXZY => new V4f(1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXZZ => new V4f(1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYOO => new V4f(1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYOI => new V4f(1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYON => new V4f(1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYOX => new V4f(1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYOY => new V4f(1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYOZ => new V4f(1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYIO => new V4f(1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYII => new V4f(1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYPN => new V4f(1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYIX => new V4f(1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYIY => new V4f(1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYIZ => new V4f(1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNO => new V4f(1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNP => new V4f(1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNN => new V4f(1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNX => new V4f(1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNY => new V4f(1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNZ => new V4f(1, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYXO => new V4f(1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYXI => new V4f(1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYXN => new V4f(1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYXX => new V4f(1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYXY => new V4f(1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYXZ => new V4f(1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYYO => new V4f(1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYYI => new V4f(1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYYN => new V4f(1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYYX => new V4f(1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYYY => new V4f(1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYYZ => new V4f(1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYZO => new V4f(1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYZI => new V4f(1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYZN => new V4f(1, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYZX => new V4f(1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYZY => new V4f(1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYZZ => new V4f(1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZOO => new V4f(1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZOI => new V4f(1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZON => new V4f(1, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZOX => new V4f(1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZOY => new V4f(1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZOZ => new V4f(1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZIO => new V4f(1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZII => new V4f(1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZPN => new V4f(1, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZIX => new V4f(1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZIY => new V4f(1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZIZ => new V4f(1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZNO => new V4f(1, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZNP => new V4f(1, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZNN => new V4f(1, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZNX => new V4f(1, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZNY => new V4f(1, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZNZ => new V4f(1, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZXO => new V4f(1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZXI => new V4f(1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZXN => new V4f(1, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZXX => new V4f(1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZXY => new V4f(1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZXZ => new V4f(1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZYO => new V4f(1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZYI => new V4f(1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZYN => new V4f(1, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZYX => new V4f(1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZYY => new V4f(1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZYZ => new V4f(1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZZO => new V4f(1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZZI => new V4f(1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZZN => new V4f(1, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZZX => new V4f(1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZZY => new V4f(1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZZZ => new V4f(1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOOX => new V4f(-1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOOY => new V4f(-1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOOZ => new V4f(-1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOPX => new V4f(-1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOPY => new V4f(-1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOPZ => new V4f(-1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NONX => new V4f(-1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NONY => new V4f(-1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NONZ => new V4f(-1, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXO => new V4f(-1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXP => new V4f(-1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXN => new V4f(-1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXX => new V4f(-1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXY => new V4f(-1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXZ => new V4f(-1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYO => new V4f(-1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYP => new V4f(-1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYN => new V4f(-1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYX => new V4f(-1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYY => new V4f(-1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYZ => new V4f(-1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOZO => new V4f(-1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOZP => new V4f(-1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOZN => new V4f(-1, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOZX => new V4f(-1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOZY => new V4f(-1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOZZ => new V4f(-1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPOX => new V4f(-1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPOY => new V4f(-1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPOZ => new V4f(-1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPPX => new V4f(-1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPPY => new V4f(-1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPPZ => new V4f(-1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPNX => new V4f(-1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPNY => new V4f(-1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPNZ => new V4f(-1, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXO => new V4f(-1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXP => new V4f(-1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXN => new V4f(-1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXX => new V4f(-1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXY => new V4f(-1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXZ => new V4f(-1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYO => new V4f(-1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYP => new V4f(-1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYN => new V4f(-1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYX => new V4f(-1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYY => new V4f(-1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYZ => new V4f(-1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPZO => new V4f(-1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPZP => new V4f(-1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPZN => new V4f(-1, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPZX => new V4f(-1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPZY => new V4f(-1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPZZ => new V4f(-1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNOX => new V4f(-1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNOY => new V4f(-1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNOZ => new V4f(-1, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNPX => new V4f(-1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNPY => new V4f(-1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNPZ => new V4f(-1, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNNX => new V4f(-1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNNY => new V4f(-1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNNZ => new V4f(-1, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXO => new V4f(-1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXP => new V4f(-1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXN => new V4f(-1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXX => new V4f(-1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXY => new V4f(-1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXZ => new V4f(-1, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYO => new V4f(-1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYP => new V4f(-1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYN => new V4f(-1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYX => new V4f(-1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYY => new V4f(-1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYZ => new V4f(-1, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNZO => new V4f(-1, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNZP => new V4f(-1, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNZN => new V4f(-1, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNZX => new V4f(-1, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNZY => new V4f(-1, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNZZ => new V4f(-1, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXOO => new V4f(-1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXOP => new V4f(-1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXON => new V4f(-1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXOX => new V4f(-1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXOY => new V4f(-1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXOZ => new V4f(-1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPO => new V4f(-1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPP => new V4f(-1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPN => new V4f(-1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPX => new V4f(-1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPY => new V4f(-1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPZ => new V4f(-1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNO => new V4f(-1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNP => new V4f(-1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNN => new V4f(-1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNX => new V4f(-1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNY => new V4f(-1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNZ => new V4f(-1, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXO => new V4f(-1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXP => new V4f(-1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXN => new V4f(-1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXX => new V4f(-1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXY => new V4f(-1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXZ => new V4f(-1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYO => new V4f(-1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYP => new V4f(-1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYN => new V4f(-1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYX => new V4f(-1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYY => new V4f(-1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYZ => new V4f(-1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXZO => new V4f(-1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXZP => new V4f(-1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXZN => new V4f(-1, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXZX => new V4f(-1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXZY => new V4f(-1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXZZ => new V4f(-1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYOO => new V4f(-1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYOP => new V4f(-1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYON => new V4f(-1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYOX => new V4f(-1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYOY => new V4f(-1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYOZ => new V4f(-1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPO => new V4f(-1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPP => new V4f(-1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPN => new V4f(-1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPX => new V4f(-1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPY => new V4f(-1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPZ => new V4f(-1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNO => new V4f(-1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNP => new V4f(-1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNN => new V4f(-1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNX => new V4f(-1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNY => new V4f(-1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNZ => new V4f(-1, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXO => new V4f(-1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXP => new V4f(-1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXN => new V4f(-1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXX => new V4f(-1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXY => new V4f(-1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXZ => new V4f(-1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYO => new V4f(-1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYP => new V4f(-1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYN => new V4f(-1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYX => new V4f(-1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYY => new V4f(-1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYZ => new V4f(-1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYZO => new V4f(-1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYZP => new V4f(-1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYZN => new V4f(-1, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYZX => new V4f(-1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYZY => new V4f(-1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYZZ => new V4f(-1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZOO => new V4f(-1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZOP => new V4f(-1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZON => new V4f(-1, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZOX => new V4f(-1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZOY => new V4f(-1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZOZ => new V4f(-1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZPO => new V4f(-1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZPP => new V4f(-1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZPN => new V4f(-1, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZPX => new V4f(-1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZPY => new V4f(-1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZPZ => new V4f(-1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZNO => new V4f(-1, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZNP => new V4f(-1, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZNN => new V4f(-1, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZNX => new V4f(-1, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZNY => new V4f(-1, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZNZ => new V4f(-1, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZXO => new V4f(-1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZXP => new V4f(-1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZXN => new V4f(-1, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZXX => new V4f(-1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZXY => new V4f(-1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZXZ => new V4f(-1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZYO => new V4f(-1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZYP => new V4f(-1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZYN => new V4f(-1, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZYX => new V4f(-1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZYY => new V4f(-1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZYZ => new V4f(-1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZZO => new V4f(-1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZZP => new V4f(-1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZZN => new V4f(-1, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZZX => new V4f(-1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZZY => new V4f(-1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZZZ => new V4f(-1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOOO => new V4f(X, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOOI => new V4f(X, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOON => new V4f(X, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOOX => new V4f(X, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOOY => new V4f(X, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOOZ => new V4f(X, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOIO => new V4f(X, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOII => new V4f(X, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOPN => new V4f(X, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOIX => new V4f(X, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOIY => new V4f(X, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOIZ => new V4f(X, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONO => new V4f(X, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONP => new V4f(X, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONN => new V4f(X, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONX => new V4f(X, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONY => new V4f(X, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONZ => new V4f(X, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXO => new V4f(X, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXI => new V4f(X, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXN => new V4f(X, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXX => new V4f(X, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXY => new V4f(X, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXZ => new V4f(X, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYO => new V4f(X, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYI => new V4f(X, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYN => new V4f(X, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYX => new V4f(X, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYY => new V4f(X, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYZ => new V4f(X, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOZO => new V4f(X, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOZI => new V4f(X, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOZN => new V4f(X, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOZX => new V4f(X, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOZY => new V4f(X, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOZZ => new V4f(X, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIOO => new V4f(X, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIOI => new V4f(X, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPON => new V4f(X, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIOX => new V4f(X, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIOY => new V4f(X, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIOZ => new V4f(X, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIIO => new V4f(X, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIII => new V4f(X, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPPN => new V4f(X, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIIX => new V4f(X, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIIY => new V4f(X, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIIZ => new V4f(X, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNO => new V4f(X, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNP => new V4f(X, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNN => new V4f(X, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNX => new V4f(X, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNY => new V4f(X, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNZ => new V4f(X, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIXO => new V4f(X, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIXI => new V4f(X, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPXN => new V4f(X, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIXX => new V4f(X, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIXY => new V4f(X, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIXZ => new V4f(X, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIYO => new V4f(X, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIYI => new V4f(X, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPYN => new V4f(X, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIYX => new V4f(X, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIYY => new V4f(X, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIYZ => new V4f(X, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIZO => new V4f(X, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIZI => new V4f(X, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPZN => new V4f(X, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIZX => new V4f(X, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIZY => new V4f(X, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIZZ => new V4f(X, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNOO => new V4f(X, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNOP => new V4f(X, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNON => new V4f(X, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNOX => new V4f(X, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNOY => new V4f(X, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNOZ => new V4f(X, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPO => new V4f(X, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPP => new V4f(X, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPN => new V4f(X, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPX => new V4f(X, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPY => new V4f(X, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPZ => new V4f(X, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNO => new V4f(X, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNP => new V4f(X, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNN => new V4f(X, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNX => new V4f(X, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNY => new V4f(X, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNZ => new V4f(X, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXO => new V4f(X, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXP => new V4f(X, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXN => new V4f(X, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXX => new V4f(X, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXY => new V4f(X, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXZ => new V4f(X, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYO => new V4f(X, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYP => new V4f(X, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYN => new V4f(X, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYX => new V4f(X, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYY => new V4f(X, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYZ => new V4f(X, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNZO => new V4f(X, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNZP => new V4f(X, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNZN => new V4f(X, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNZX => new V4f(X, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNZY => new V4f(X, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNZZ => new V4f(X, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXOO => new V4f(X, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXOI => new V4f(X, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXON => new V4f(X, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXOX => new V4f(X, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXOY => new V4f(X, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXOZ => new V4f(X, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXIO => new V4f(X, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXII => new V4f(X, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXPN => new V4f(X, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXIX => new V4f(X, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXIY => new V4f(X, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXIZ => new V4f(X, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNO => new V4f(X, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNP => new V4f(X, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNN => new V4f(X, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNX => new V4f(X, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNY => new V4f(X, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNZ => new V4f(X, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXO => new V4f(X, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXI => new V4f(X, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXN => new V4f(X, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXX => new V4f(X, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXY => new V4f(X, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXZ => new V4f(X, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYO => new V4f(X, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYI => new V4f(X, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYN => new V4f(X, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYX => new V4f(X, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYY => new V4f(X, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYZ => new V4f(X, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXZO => new V4f(X, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXZI => new V4f(X, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXZN => new V4f(X, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXZX => new V4f(X, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXZY => new V4f(X, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXZZ => new V4f(X, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYOO => new V4f(X, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYOI => new V4f(X, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYON => new V4f(X, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYOX => new V4f(X, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYOY => new V4f(X, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYOZ => new V4f(X, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYIO => new V4f(X, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYII => new V4f(X, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYPN => new V4f(X, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYIX => new V4f(X, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYIY => new V4f(X, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYIZ => new V4f(X, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNO => new V4f(X, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNP => new V4f(X, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNN => new V4f(X, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNX => new V4f(X, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNY => new V4f(X, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNZ => new V4f(X, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXO => new V4f(X, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXI => new V4f(X, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXN => new V4f(X, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXX => new V4f(X, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXY => new V4f(X, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXZ => new V4f(X, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYO => new V4f(X, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYI => new V4f(X, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYN => new V4f(X, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYX => new V4f(X, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYY => new V4f(X, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYZ => new V4f(X, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYZO => new V4f(X, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYZI => new V4f(X, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYZN => new V4f(X, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYZX => new V4f(X, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYZY => new V4f(X, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYZZ => new V4f(X, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZOO => new V4f(X, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZOI => new V4f(X, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZON => new V4f(X, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZOX => new V4f(X, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZOY => new V4f(X, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZOZ => new V4f(X, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZIO => new V4f(X, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZII => new V4f(X, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZPN => new V4f(X, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZIX => new V4f(X, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZIY => new V4f(X, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZIZ => new V4f(X, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZNO => new V4f(X, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZNP => new V4f(X, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZNN => new V4f(X, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZNX => new V4f(X, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZNY => new V4f(X, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZNZ => new V4f(X, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZXO => new V4f(X, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZXI => new V4f(X, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZXN => new V4f(X, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZXX => new V4f(X, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZXY => new V4f(X, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZXZ => new V4f(X, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZYO => new V4f(X, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZYI => new V4f(X, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZYN => new V4f(X, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZYX => new V4f(X, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZYY => new V4f(X, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZYZ => new V4f(X, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZZO => new V4f(X, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZZI => new V4f(X, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZZN => new V4f(X, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZZX => new V4f(X, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZZY => new V4f(X, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZZZ => new V4f(X, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOOO => new V4f(Y, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOOI => new V4f(Y, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOON => new V4f(Y, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOOX => new V4f(Y, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOOY => new V4f(Y, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOOZ => new V4f(Y, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOIO => new V4f(Y, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOII => new V4f(Y, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOPN => new V4f(Y, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOIX => new V4f(Y, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOIY => new V4f(Y, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOIZ => new V4f(Y, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONO => new V4f(Y, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONP => new V4f(Y, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONN => new V4f(Y, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONX => new V4f(Y, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONY => new V4f(Y, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONZ => new V4f(Y, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXO => new V4f(Y, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXI => new V4f(Y, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXN => new V4f(Y, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXX => new V4f(Y, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXY => new V4f(Y, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXZ => new V4f(Y, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYO => new V4f(Y, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYI => new V4f(Y, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYN => new V4f(Y, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYX => new V4f(Y, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYY => new V4f(Y, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYZ => new V4f(Y, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOZO => new V4f(Y, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOZI => new V4f(Y, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOZN => new V4f(Y, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOZX => new V4f(Y, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOZY => new V4f(Y, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOZZ => new V4f(Y, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIOO => new V4f(Y, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIOI => new V4f(Y, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPON => new V4f(Y, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIOX => new V4f(Y, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIOY => new V4f(Y, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIOZ => new V4f(Y, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIIO => new V4f(Y, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIII => new V4f(Y, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPPN => new V4f(Y, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIIX => new V4f(Y, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIIY => new V4f(Y, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIIZ => new V4f(Y, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNO => new V4f(Y, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNP => new V4f(Y, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNN => new V4f(Y, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNX => new V4f(Y, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNY => new V4f(Y, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNZ => new V4f(Y, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIXO => new V4f(Y, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIXI => new V4f(Y, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPXN => new V4f(Y, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIXX => new V4f(Y, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIXY => new V4f(Y, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIXZ => new V4f(Y, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIYO => new V4f(Y, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIYI => new V4f(Y, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPYN => new V4f(Y, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIYX => new V4f(Y, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIYY => new V4f(Y, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIYZ => new V4f(Y, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIZO => new V4f(Y, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIZI => new V4f(Y, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPZN => new V4f(Y, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIZX => new V4f(Y, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIZY => new V4f(Y, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIZZ => new V4f(Y, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNOO => new V4f(Y, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNOP => new V4f(Y, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNON => new V4f(Y, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNOX => new V4f(Y, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNOY => new V4f(Y, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNOZ => new V4f(Y, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPO => new V4f(Y, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPP => new V4f(Y, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPN => new V4f(Y, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPX => new V4f(Y, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPY => new V4f(Y, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPZ => new V4f(Y, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNO => new V4f(Y, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNP => new V4f(Y, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNN => new V4f(Y, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNX => new V4f(Y, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNY => new V4f(Y, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNZ => new V4f(Y, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXO => new V4f(Y, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXP => new V4f(Y, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXN => new V4f(Y, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXX => new V4f(Y, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXY => new V4f(Y, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXZ => new V4f(Y, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYO => new V4f(Y, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYP => new V4f(Y, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYN => new V4f(Y, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYX => new V4f(Y, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYY => new V4f(Y, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYZ => new V4f(Y, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNZO => new V4f(Y, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNZP => new V4f(Y, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNZN => new V4f(Y, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNZX => new V4f(Y, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNZY => new V4f(Y, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNZZ => new V4f(Y, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXOO => new V4f(Y, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXOI => new V4f(Y, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXON => new V4f(Y, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXOX => new V4f(Y, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXOY => new V4f(Y, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXOZ => new V4f(Y, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXIO => new V4f(Y, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXII => new V4f(Y, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXPN => new V4f(Y, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXIX => new V4f(Y, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXIY => new V4f(Y, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXIZ => new V4f(Y, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNO => new V4f(Y, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNP => new V4f(Y, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNN => new V4f(Y, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNX => new V4f(Y, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNY => new V4f(Y, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNZ => new V4f(Y, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXO => new V4f(Y, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXI => new V4f(Y, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXN => new V4f(Y, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXX => new V4f(Y, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXY => new V4f(Y, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXZ => new V4f(Y, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYO => new V4f(Y, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYI => new V4f(Y, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYN => new V4f(Y, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYX => new V4f(Y, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYY => new V4f(Y, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYZ => new V4f(Y, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXZO => new V4f(Y, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXZI => new V4f(Y, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXZN => new V4f(Y, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXZX => new V4f(Y, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXZY => new V4f(Y, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXZZ => new V4f(Y, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYOO => new V4f(Y, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYOI => new V4f(Y, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYON => new V4f(Y, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYOX => new V4f(Y, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYOY => new V4f(Y, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYOZ => new V4f(Y, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYIO => new V4f(Y, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYII => new V4f(Y, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYPN => new V4f(Y, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYIX => new V4f(Y, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYIY => new V4f(Y, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYIZ => new V4f(Y, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNO => new V4f(Y, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNP => new V4f(Y, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNN => new V4f(Y, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNX => new V4f(Y, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNY => new V4f(Y, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNZ => new V4f(Y, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXO => new V4f(Y, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXI => new V4f(Y, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXN => new V4f(Y, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXX => new V4f(Y, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXY => new V4f(Y, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXZ => new V4f(Y, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYO => new V4f(Y, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYI => new V4f(Y, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYN => new V4f(Y, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYX => new V4f(Y, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYY => new V4f(Y, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYZ => new V4f(Y, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYZO => new V4f(Y, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYZI => new V4f(Y, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYZN => new V4f(Y, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYZX => new V4f(Y, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYZY => new V4f(Y, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYZZ => new V4f(Y, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZOO => new V4f(Y, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZOI => new V4f(Y, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZON => new V4f(Y, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZOX => new V4f(Y, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZOY => new V4f(Y, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZOZ => new V4f(Y, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZIO => new V4f(Y, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZII => new V4f(Y, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZPN => new V4f(Y, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZIX => new V4f(Y, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZIY => new V4f(Y, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZIZ => new V4f(Y, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZNO => new V4f(Y, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZNP => new V4f(Y, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZNN => new V4f(Y, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZNX => new V4f(Y, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZNY => new V4f(Y, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZNZ => new V4f(Y, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZXO => new V4f(Y, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZXI => new V4f(Y, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZXN => new V4f(Y, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZXX => new V4f(Y, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZXY => new V4f(Y, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZXZ => new V4f(Y, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZYO => new V4f(Y, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZYI => new V4f(Y, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZYN => new V4f(Y, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZYX => new V4f(Y, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZYY => new V4f(Y, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZYZ => new V4f(Y, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZZO => new V4f(Y, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZZI => new V4f(Y, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZZN => new V4f(Y, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZZX => new V4f(Y, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZZY => new V4f(Y, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZZZ => new V4f(Y, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOOO => new V4f(Z, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOOI => new V4f(Z, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOON => new V4f(Z, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOOX => new V4f(Z, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOOY => new V4f(Z, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOOZ => new V4f(Z, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOIO => new V4f(Z, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOII => new V4f(Z, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOPN => new V4f(Z, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOIX => new V4f(Z, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOIY => new V4f(Z, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOIZ => new V4f(Z, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZONO => new V4f(Z, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZONP => new V4f(Z, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZONN => new V4f(Z, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZONX => new V4f(Z, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZONY => new V4f(Z, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZONZ => new V4f(Z, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOXO => new V4f(Z, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOXI => new V4f(Z, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOXN => new V4f(Z, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOXX => new V4f(Z, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOXY => new V4f(Z, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOXZ => new V4f(Z, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOYO => new V4f(Z, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOYI => new V4f(Z, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOYN => new V4f(Z, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOYX => new V4f(Z, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOYY => new V4f(Z, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOYZ => new V4f(Z, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOZO => new V4f(Z, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOZI => new V4f(Z, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOZN => new V4f(Z, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOZX => new V4f(Z, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOZY => new V4f(Z, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOZZ => new V4f(Z, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIOO => new V4f(Z, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIOI => new V4f(Z, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPON => new V4f(Z, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIOX => new V4f(Z, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIOY => new V4f(Z, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIOZ => new V4f(Z, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIIO => new V4f(Z, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIII => new V4f(Z, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPPN => new V4f(Z, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIIX => new V4f(Z, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIIY => new V4f(Z, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIIZ => new V4f(Z, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPNO => new V4f(Z, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPNP => new V4f(Z, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPNN => new V4f(Z, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPNX => new V4f(Z, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPNY => new V4f(Z, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPNZ => new V4f(Z, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIXO => new V4f(Z, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIXI => new V4f(Z, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPXN => new V4f(Z, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIXX => new V4f(Z, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIXY => new V4f(Z, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIXZ => new V4f(Z, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIYO => new V4f(Z, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIYI => new V4f(Z, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPYN => new V4f(Z, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIYX => new V4f(Z, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIYY => new V4f(Z, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIYZ => new V4f(Z, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIZO => new V4f(Z, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIZI => new V4f(Z, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPZN => new V4f(Z, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIZX => new V4f(Z, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIZY => new V4f(Z, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIZZ => new V4f(Z, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNOO => new V4f(Z, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNOP => new V4f(Z, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNON => new V4f(Z, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNOX => new V4f(Z, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNOY => new V4f(Z, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNOZ => new V4f(Z, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNPO => new V4f(Z, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNPP => new V4f(Z, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNPN => new V4f(Z, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNPX => new V4f(Z, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNPY => new V4f(Z, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNPZ => new V4f(Z, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNNO => new V4f(Z, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNNP => new V4f(Z, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNNN => new V4f(Z, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNNX => new V4f(Z, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNNY => new V4f(Z, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNNZ => new V4f(Z, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNXO => new V4f(Z, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNXP => new V4f(Z, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNXN => new V4f(Z, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNXX => new V4f(Z, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNXY => new V4f(Z, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNXZ => new V4f(Z, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNYO => new V4f(Z, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNYP => new V4f(Z, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNYN => new V4f(Z, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNYX => new V4f(Z, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNYY => new V4f(Z, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNYZ => new V4f(Z, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNZO => new V4f(Z, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNZP => new V4f(Z, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNZN => new V4f(Z, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNZX => new V4f(Z, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNZY => new V4f(Z, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNZZ => new V4f(Z, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXOO => new V4f(Z, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXOI => new V4f(Z, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXON => new V4f(Z, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXOX => new V4f(Z, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXOY => new V4f(Z, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXOZ => new V4f(Z, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXIO => new V4f(Z, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXII => new V4f(Z, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXPN => new V4f(Z, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXIX => new V4f(Z, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXIY => new V4f(Z, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXIZ => new V4f(Z, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXNO => new V4f(Z, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXNP => new V4f(Z, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXNN => new V4f(Z, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXNX => new V4f(Z, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXNY => new V4f(Z, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXNZ => new V4f(Z, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXXO => new V4f(Z, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXXI => new V4f(Z, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXXN => new V4f(Z, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXXX => new V4f(Z, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXXY => new V4f(Z, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXXZ => new V4f(Z, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXYO => new V4f(Z, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXYI => new V4f(Z, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXYN => new V4f(Z, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXYX => new V4f(Z, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXYY => new V4f(Z, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXYZ => new V4f(Z, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXZO => new V4f(Z, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXZI => new V4f(Z, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXZN => new V4f(Z, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXZX => new V4f(Z, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXZY => new V4f(Z, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXZZ => new V4f(Z, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYOO => new V4f(Z, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYOI => new V4f(Z, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYON => new V4f(Z, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYOX => new V4f(Z, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYOY => new V4f(Z, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYOZ => new V4f(Z, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYIO => new V4f(Z, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYII => new V4f(Z, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYPN => new V4f(Z, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYIX => new V4f(Z, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYIY => new V4f(Z, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYIZ => new V4f(Z, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYNO => new V4f(Z, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYNP => new V4f(Z, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYNN => new V4f(Z, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYNX => new V4f(Z, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYNY => new V4f(Z, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYNZ => new V4f(Z, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYXO => new V4f(Z, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYXI => new V4f(Z, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYXN => new V4f(Z, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYXX => new V4f(Z, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYXY => new V4f(Z, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYXZ => new V4f(Z, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYYO => new V4f(Z, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYYI => new V4f(Z, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYYN => new V4f(Z, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYYX => new V4f(Z, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYYY => new V4f(Z, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYYZ => new V4f(Z, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYZO => new V4f(Z, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYZI => new V4f(Z, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYZN => new V4f(Z, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYZX => new V4f(Z, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYZY => new V4f(Z, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYZZ => new V4f(Z, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZOO => new V4f(Z, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZOI => new V4f(Z, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZON => new V4f(Z, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZOX => new V4f(Z, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZOY => new V4f(Z, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZOZ => new V4f(Z, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZIO => new V4f(Z, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZII => new V4f(Z, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZPN => new V4f(Z, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZIX => new V4f(Z, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZIY => new V4f(Z, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZIZ => new V4f(Z, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZNO => new V4f(Z, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZNP => new V4f(Z, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZNN => new V4f(Z, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZNX => new V4f(Z, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZNY => new V4f(Z, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZNZ => new V4f(Z, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZXO => new V4f(Z, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZXI => new V4f(Z, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZXN => new V4f(Z, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZXX => new V4f(Z, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZXY => new V4f(Z, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZXZ => new V4f(Z, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZYO => new V4f(Z, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZYI => new V4f(Z, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZYN => new V4f(Z, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZYX => new V4f(Z, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZYY => new V4f(Z, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZYZ => new V4f(Z, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZZO => new V4f(Z, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZZI => new V4f(Z, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZZN => new V4f(Z, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZZX => new V4f(Z, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZZY => new V4f(Z, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZZZ => new V4f(Z, Z, Z, Z); #endregion #region IVector Members /// /// By using long indices, the IVector<double> interface is /// accessed. /// public double this[long i] { readonly get { return (double)this[(int)i]; } set { this[(int)i] = (float)value; } } #endregion #region ISize3f Members public readonly V3f Size3f { get { return this; } } #endregion #region IVector public readonly long Dim { get { return 3; } } public readonly object GetValue(long index) { return (object)this[(int)index]; } public void SetValue(object value, long index) { this[(int)index] = (float)value; } #endregion } public class V3fEqualityComparer : IEqualityComparer { public static V3fEqualityComparer Default => new V3fEqualityComparer(); #region IEqualityComparer Members public bool Equals(V3f v0, V3f v1) { return v0 == v1; } public int GetHashCode(V3f v) { return v.GetHashCode(); } #endregion } public static partial class Fun { #region Min and Max /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Min(this V3f a, V3f b) { return new V3f(Min(a.X, b.X), Min(a.Y, b.Y), Min(a.Z, b.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Min(this V3f a, float b) { return new V3f(Min(a.X, b), Min(a.Y, b), Min(a.Z, b)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Min(this float a, V3f b) { return new V3f(Min(a, b.X), Min(a, b.Y), Min(a, b.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Max(this V3f a, V3f b) { return new V3f(Max(a.X, b.X), Max(a.Y, b.Y), Max(a.Z, b.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Max(this V3f a, float b) { return new V3f(Max(a.X, b), Max(a.Y, b), Max(a.Z, b)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Max(this float a, V3f b) { return new V3f(Max(a, b.X), Max(a, b.Y), Max(a, b.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Min(this V3f a, V3f b, V3f c) { return new V3f(Min(a.X, b.X, c.X), Min(a.Y, b.Y, c.Y), Min(a.Z, b.Z, c.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Max(this V3f a, V3f b, V3f c) { return new V3f(Max(a.X, b.X, c.X), Max(a.Y, b.Y, c.Y), Max(a.Z, b.Z, c.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Min(this V3f a, V3f b, V3f c, V3f d) { return new V3f(Min(a.X, b.X, c.X, d.X), Min(a.Y, b.Y, c.Y, d.Y), Min(a.Z, b.Z, c.Z, d.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Max(this V3f a, V3f b, V3f c, V3f d) { return new V3f(Max(a.X, b.X, c.X, d.X), Max(a.Y, b.Y, c.Y, d.Y), Max(a.Z, b.Z, c.Z, d.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Min(this V3f x, params V3f[] values) { return new V3f(Min(x.X, values.Map(a => a.X)), Min(x.Y, values.Map(a => a.Y)), Min(x.Z, values.Map(a => a.Z))); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Max(this V3f x, params V3f[] values) { return new V3f(Max(x.X, values.Map(a => a.X)), Max(x.Y, values.Map(a => a.Y)), Max(x.Z, values.Map(a => a.Z))); } #endregion #region Abs /// /// Applies Fun.Abs to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Abs(this V3f x) { return new V3f(Abs(x.X), Abs(x.Y), Abs(x.Z)); } #endregion #region Rounding /// /// Applies Fun.Floor to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Floor(this V3f x) { return new V3f(Floor(x.X), Floor(x.Y), Floor(x.Z)); } /// /// Applies Fun.Ceiling to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Ceiling(this V3f x) { return new V3f(Ceiling(x.X), Ceiling(x.Y), Ceiling(x.Z)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Round(this V3f x) { return new V3f(Round(x.X), Round(x.Y), Round(x.Z)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Round(this V3f x, MidpointRounding mode) { return new V3f(Round(x.X, mode), Round(x.Y, mode), Round(x.Z, mode)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Round(this V3f x, int digits) { return new V3f(Round(x.X, digits), Round(x.Y, digits), Round(x.Z, digits)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Round(this V3f x, int digits, MidpointRounding mode) { return new V3f(Round(x.X, digits, mode), Round(x.Y, digits, mode), Round(x.Z, digits, mode)); } /// /// Applies Fun.Truncate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Truncate(this V3f x) { return new V3f(Truncate(x.X), Truncate(x.Y), Truncate(x.Z)); } #endregion #region Frac /// /// Applies Fun.Frac to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Frac(this V3f x) { return new V3f(Frac(x.X), Frac(x.Y), Frac(x.Z)); } #endregion #region Clamping /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Clamp(this V3f x, V3f a, V3f b) { return new V3f(Clamp(x.X, a.X, b.X), Clamp(x.Y, a.Y, b.Y), Clamp(x.Z, a.Z, b.Z)); } /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Clamp(this V3f x, float a, float b) { return new V3f(Clamp(x.X, a, b), Clamp(x.Y, a, b), Clamp(x.Z, a, b)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f ClampWrap(this V3f x, V3f a, V3f b) { return new V3f(ClampWrap(x.X, a.X, b.X), ClampWrap(x.Y, a.Y, b.Y), ClampWrap(x.Z, a.Z, b.Z)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f ClampWrap(this V3f x, float a, float b) { return new V3f(ClampWrap(x.X, a, b), ClampWrap(x.Y, a, b), ClampWrap(x.Z, a, b)); } /// /// Applies Fun.Saturate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Saturate(this V3f x) { return new V3f(Saturate(x.X), Saturate(x.Y), Saturate(x.Z)); } #endregion #region MapToUnitInterval /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f MapToUnitInterval(this V3f t, V3f tMax, bool repeat, bool mirror) { return new V3f(MapToUnitInterval(t.X, tMax.X, repeat, mirror), MapToUnitInterval(t.Y, tMax.Y, repeat, mirror), MapToUnitInterval(t.Z, tMax.Z, repeat, mirror)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f MapToUnitInterval(this V3f t, V3f tMax, bool repeat) { return new V3f(MapToUnitInterval(t.X, tMax.X, repeat), MapToUnitInterval(t.Y, tMax.Y, repeat), MapToUnitInterval(t.Z, tMax.Z, repeat)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f MapToUnitInterval(this V3f t, V3f tMax) { return new V3f(MapToUnitInterval(t.X, tMax.X), MapToUnitInterval(t.Y, tMax.Y), MapToUnitInterval(t.Z, tMax.Z)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f MapToUnitInterval(this V3f t, V3f tMin, V3f tMax) { return new V3f(MapToUnitInterval(t.X, tMin.X, tMax.X), MapToUnitInterval(t.Y, tMin.Y, tMax.Y), MapToUnitInterval(t.Z, tMin.Z, tMax.Z)); } #endregion #region Sign /// /// Applies Fun.Sign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Sign(this V3f x) { return new V3i(Sign(x.X), Sign(x.Y), Sign(x.Z)); } /// /// Applies Fun.Signumi to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Signumi(this V3f x) { return new V3i(Signumi(x.X), Signumi(x.Y), Signumi(x.Z)); } /// /// Applies Fun.Signum to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Signum(this V3f x) { return new V3f(Signum(x.X), Signum(x.Y), Signum(x.Z)); } #endregion #region Multiply-Add /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f MultiplyAdd(V3f x, V3f y, V3f z) { return new V3f(MultiplyAdd(x.X, y.X, z.X), MultiplyAdd(x.Y, y.Y, z.Y), MultiplyAdd(x.Z, y.Z, z.Z)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f MultiplyAdd(V3f x, float y, V3f z) { return new V3f(MultiplyAdd(x.X, y, z.X), MultiplyAdd(x.Y, y, z.Y), MultiplyAdd(x.Z, y, z.Z)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f MultiplyAdd(float x, V3f y, V3f z) { return new V3f(MultiplyAdd(x, y.X, z.X), MultiplyAdd(x, y.Y, z.Y), MultiplyAdd(x, y.Z, z.Z)); } #endregion #region Copy sign /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f CopySign(V3f value, V3f sign) { return new V3f(CopySign(value.X, sign.X), CopySign(value.Y, sign.Y), CopySign(value.Z, sign.Z)); } /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f CopySign(float value, V3f sign) { return new V3f(CopySign(value, sign.X), CopySign(value, sign.Y), CopySign(value, sign.Z)); } /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f CopySign(V3f value, float sign) { return new V3f(CopySign(value.X, sign), CopySign(value.Y, sign), CopySign(value.Z, sign)); } #endregion #region Roots /// /// Applies Fun.Sqrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Sqrt(this V3f x) { return new V3f(Sqrt(x.X), Sqrt(x.Y), Sqrt(x.Z)); } /// /// Applies Fun.Cbrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Cbrt(this V3f x) { return new V3f(Cbrt(x.X), Cbrt(x.Y), Cbrt(x.Z)); } #endregion #region Square /// /// Applies Fun.Square to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Square(this V3f x) { return new V3f(Square(x.X), Square(x.Y), Square(x.Z)); } #endregion #region Power /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Pown(this V3f x, V3i y) { return new V3f(Pown(x.X, y.X), Pown(x.Y, y.Y), Pown(x.Z, y.Z)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Pown(this V3f x, int y) { return new V3f(Pown(x.X, y), Pown(x.Y, y), Pown(x.Z, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Pown(this float x, V3i y) { return new V3f(Pown(x, y.X), Pown(x, y.Y), Pown(x, y.Z)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Pow(this V3f x, V3f y) { return new V3f(Pow(x.X, y.X), Pow(x.Y, y.Y), Pow(x.Z, y.Z)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Pow(this V3f x, float y) { return new V3f(Pow(x.X, y), Pow(x.Y, y), Pow(x.Z, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Pow(this float x, V3f y) { return new V3f(Pow(x, y.X), Pow(x, y.Y), Pow(x, y.Z)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Power(this V3f x, V3f y) { return new V3f(Power(x.X, y.X), Power(x.Y, y.Y), Power(x.Z, y.Z)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Power(this V3f x, float y) { return new V3f(Power(x.X, y), Power(x.Y, y), Power(x.Z, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Power(this float x, V3f y) { return new V3f(Power(x, y.X), Power(x, y.Y), Power(x, y.Z)); } #endregion #region Exp and Log /// /// Applies Fun.Exp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Exp(this V3f x) { return new V3f(Exp(x.X), Exp(x.Y), Exp(x.Z)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Log(this V3f x) { return new V3f(Log(x.X), Log(x.Y), Log(x.Z)); } /// /// Applies Fun.Log2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Log2(this V3f x) { return new V3f(Log2(x.X), Log2(x.Y), Log2(x.Z)); } /// /// Applies Fun.Log2Int to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Log2Int(this V3f x) { return new V3i(Log2Int(x.X), Log2Int(x.Y), Log2Int(x.Z)); } /// /// Applies Fun.Log10 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Log10(this V3f x) { return new V3f(Log10(x.X), Log10(x.Y), Log10(x.Z)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Log(this V3f x, float basis) { return new V3f(Log(x.X, basis), Log(x.Y, basis), Log(x.Z, basis)); } #endregion #region ModP /// /// Applies Fun.ModP to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f ModP(this V3f a, V3f b) { return new V3f(ModP(a.X, b.X), ModP(a.Y, b.Y), ModP(a.Z, b.Z)); } #endregion #region Power of Two /// /// Applies Fun.PowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f PowerOfTwo(this V3f x) { return new V3f(PowerOfTwo(x.X), PowerOfTwo(x.Y), PowerOfTwo(x.Z)); } #endregion #region Trigonometry /// /// Applies Fun.Sin to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Sin(this V3f x) { return new V3f(Sin(x.X), Sin(x.Y), Sin(x.Z)); } /// /// Applies Fun.Cos to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Cos(this V3f x) { return new V3f(Cos(x.X), Cos(x.Y), Cos(x.Z)); } /// /// Applies Fun.Tan to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Tan(this V3f x) { return new V3f(Tan(x.X), Tan(x.Y), Tan(x.Z)); } /// /// Applies Fun.Asin to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Asin(this V3f x) { return new V3f(Asin(x.X), Asin(x.Y), Asin(x.Z)); } /// /// Applies Fun.AsinClamped to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f AsinClamped(this V3f x) { return new V3f(AsinClamped(x.X), AsinClamped(x.Y), AsinClamped(x.Z)); } /// /// Applies Fun.Acos to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Acos(this V3f x) { return new V3f(Acos(x.X), Acos(x.Y), Acos(x.Z)); } /// /// Applies Fun.AcosClamped to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f AcosClamped(this V3f x) { return new V3f(AcosClamped(x.X), AcosClamped(x.Y), AcosClamped(x.Z)); } /// /// Applies Fun.Atan to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Atan(this V3f x) { return new V3f(Atan(x.X), Atan(x.Y), Atan(x.Z)); } /// /// Applies Fun.Atan2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Atan2(V3f y, V3f x) { return new V3f(Atan2(y.X, x.X), Atan2(y.Y, x.Y), Atan2(y.Z, x.Z)); } /// /// Applies Fun.FastAtan2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f FastAtan2(V3f y, V3f x) { return new V3f(FastAtan2(y.X, x.X), FastAtan2(y.Y, x.Y), FastAtan2(y.Z, x.Z)); } /// /// Applies Fun.Sinh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Sinh(this V3f x) { return new V3f(Sinh(x.X), Sinh(x.Y), Sinh(x.Z)); } /// /// Applies Fun.Cosh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Cosh(this V3f x) { return new V3f(Cosh(x.X), Cosh(x.Y), Cosh(x.Z)); } /// /// Applies Fun.Tanh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Tanh(this V3f x) { return new V3f(Tanh(x.X), Tanh(x.Y), Tanh(x.Z)); } /// /// Applies Fun.Asinh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Asinh(this V3f x) { return new V3f(Asinh(x.X), Asinh(x.Y), Asinh(x.Z)); } /// /// Applies Fun.Acosh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Acosh(this V3f x) { return new V3f(Acosh(x.X), Acosh(x.Y), Acosh(x.Z)); } /// /// Applies Fun.Atanh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Atanh(this V3f x) { return new V3f(Atanh(x.X), Atanh(x.Y), Atanh(x.Z)); } #endregion #region Step functions /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Step(this V3f x, V3f edge) { return new V3f(Step(x.X, edge.X), Step(x.Y, edge.Y), Step(x.Z, edge.Z)); } /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Step(this V3f x, float edge) { return new V3f(Step(x.X, edge), Step(x.Y, edge), Step(x.Z, edge)); } /// /// Applies Fun.Linearstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Linearstep(this V3f x, V3f edge0, V3f edge1) { return new V3f(Linearstep(x.X, edge0.X, edge1.X), Linearstep(x.Y, edge0.Y, edge1.Y), Linearstep(x.Z, edge0.Z, edge1.Z)); } /// /// Applies Fun.Linearstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Linearstep(this V3f x, float edge0, float edge1) { return new V3f(Linearstep(x.X, edge0, edge1), Linearstep(x.Y, edge0, edge1), Linearstep(x.Z, edge0, edge1)); } /// /// Applies Fun.Smoothstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Smoothstep(this V3f x, V3f edge0, V3f edge1) { return new V3f(Smoothstep(x.X, edge0.X, edge1.X), Smoothstep(x.Y, edge0.Y, edge1.Y), Smoothstep(x.Z, edge0.Z, edge1.Z)); } /// /// Applies Fun.Smoothstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Smoothstep(this V3f x, float edge0, float edge1) { return new V3f(Smoothstep(x.X, edge0, edge1), Smoothstep(x.Y, edge0, edge1), Smoothstep(x.Z, edge0, edge1)); } #endregion #region Interpolation /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Lerp(this float t, V3f a, V3f b) { return new V3f(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y), Lerp(t, a.Z, b.Z)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Lerp(this V3f t, V3f a, V3f b) { return new V3f(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y), Lerp(t.Z, a.Z, b.Z)); } /// /// Applies Fun.InvLerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f InvLerp(this V3f y, V3f a, V3f b) { return new V3f(InvLerp(y.X, a.X, b.X), InvLerp(y.Y, a.Y, b.Y), InvLerp(y.Z, a.Z, b.Z)); } #endregion #region Floating point bits /// /// Applies Fun.FloatToBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i FloatToBits(this V3f x) { return new V3i(FloatToBits(x.X), FloatToBits(x.Y), FloatToBits(x.Z)); } /// /// Applies Fun.FloatToUnsignedBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3ui FloatToUnsignedBits(this V3f x) { return new V3ui(FloatToUnsignedBits(x.X), FloatToUnsignedBits(x.Y), FloatToUnsignedBits(x.Z)); } #endregion #region ApproximateEquals /// /// Returns whether the given vectors are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V3f a, V3f b, float tolerance) { return ApproximateEquals(a.X, b.X, tolerance) && ApproximateEquals(a.Y, b.Y, tolerance) && ApproximateEquals(a.Z, b.Z, tolerance); } /// /// Returns whether the given vectors are equal within /// Constant{float}.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V3f a, V3f b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this V3f v, float epsilon) => Vec.AllTiny(v, epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than Constant<float>.PositiveTinyValue. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(V3f v) => v.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any component of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(V3f v) => v.IsNaN; /// /// Returns whether any component of the the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(V3f v) => v.IsInfinity; /// /// Returns whether any component of the the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(V3f v) => v.IsPositiveInfinity; /// /// Returns whether any component of the the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(V3f v) => v.IsNegativeInfinity; /// /// Returns whether all components of the the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(V3f v) => v.IsFinite; #endregion } public static partial class Conversion { #region Angles (Radians, Degrees, Gons) /// /// Converts the angles given in degrees to radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f RadiansFromDegrees(this V3f degrees) => new V3f( RadiansFromDegrees(degrees.X), RadiansFromDegrees(degrees.Y), RadiansFromDegrees(degrees.Z) ); /// /// Converts the angles given in gons to radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f RadiansFromGons(this V3f gons) => new V3f( RadiansFromGons(gons.X), RadiansFromGons(gons.Y), RadiansFromGons(gons.Z) ); /// /// Converts the angles given in radians to degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f DegreesFromRadians(this V3f radians) => new V3f( DegreesFromRadians(radians.X), DegreesFromRadians(radians.Y), DegreesFromRadians(radians.Z) ); /// /// Converts the angles given in gons to degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f DegreesFromGons(this V3f gons) => new V3f( DegreesFromGons(gons.X), DegreesFromGons(gons.Y), DegreesFromGons(gons.Z) ); /// /// Converts the angles given in radians to gons. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GonsFromRadians(this V3f radians) => new V3f( GonsFromRadians(radians.X), GonsFromRadians(radians.Y), GonsFromRadians(radians.Z) ); /// /// Converts the angles given in degrees to gons. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f GonsFromDegrees(this V3f degrees) => new V3f( GonsFromDegrees(degrees.X), GonsFromDegrees(degrees.Y), GonsFromDegrees(degrees.Z) ); #endregion } /// /// Contains static methods /// public static partial class Vec { #region Length /// /// Returns the squared length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LengthSquared(V3f v) => v.LengthSquared; /// /// Returns the length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Length(V3f v) => v.Length; #endregion #region Normalize /// /// Normalizes the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref V3f v) { var s = v.Length; if (s == 0) return; s = 1 / s; v.X *= s; v.Y *= s; v.Z *= s; } /// /// Returns a normalized copy of this vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Normalized(V3f v) => v.Normalized; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm1(V3f v) => v.Norm1; /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm2(V3f v) => v.Norm2; /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormMax(V3f v) => v.NormMax; /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormMin(V3f v) => v.NormMin; /// /// Gets the p-norm. This is calculated as the p-th root of (|x|^n + |y|^n + ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm(this V3f v, float p) { return ( Fun.Abs(v.X).Pow(p) + Fun.Abs(v.Y).Pow(p) + Fun.Abs(v.Z).Pow(p)).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the squared distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceSquared(this V3f a, V3f b) => Fun.Square(b.X - a.X) + Fun.Square(b.Y - a.Y) + Fun.Square(b.Z - a.Z); /// /// Returns the distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance(this V3f a, V3f b) => Fun.Sqrt(DistanceSquared(a, b)); /// /// Returns the Manhatten (or 1-) distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance1(this V3f a, V3f b) => Fun.Abs(b.X - a.X) + Fun.Abs(b.Y - a.Y) + Fun.Abs(b.Z - a.Z); /// /// Returns the p-distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance(this V3f a, V3f b, float p) => (Fun.Abs(b.X - a.X).Pow(p) + Fun.Abs(b.Y - a.Y).Pow(p) + Fun.Abs(b.Z - a.Z).Pow(p)).Pow(1 / p); /// /// Returns the maximal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceMax(this V3f a, V3f b) => Fun.Max(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y), Fun.Abs(b.Z - a.Z)); /// /// Returns the minimal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceMin(this V3f a, V3f b) => Fun.Min(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y), Fun.Abs(b.Z - a.Z)); /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceToLine( this V3f query, V3f p0, V3f p1) { var p0p1 = p1 - p0; var p0q = query - p0; var t = Dot(p0q, p0p1); if (t <= 0) { return p0q.Length; } var denom = p0p1.LengthSquared; if (t >= denom) { return Distance(query, p1); } t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceToInfiniteLine( this V3f query, V3f p0, V3f p1) { var p0p1 = p1 - p0; var p0q = query - p0; var t = Dot(p0q, p0p1); var denom = p0p1.LengthSquared; t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceToLine( this V3f query, V3f p0, V3f p1, out float t) { var p0p1 = p1 - p0; var p0q = query - p0; t = Dot(p0q, p0p1); if (t <= 0) { t = 0; return p0q.Length; } var denom = p0p1.LengthSquared; if (t >= denom) { t = 1; return Distance(query, p1); } t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceToInfiniteLine( this V3f query, V3f p0, V3f p1, out float t) { var p0p1 = p1 - p0; var p0q = query - p0; t = Dot(p0q, p0p1); var denom = p0p1.LengthSquared; t /= denom; return (p0q - t * p0p1).Length; } #endregion #region Operations /// /// Gets a copy of the given vector containing the reciprocal (1/x) of each element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Reciprocal(V3f v) => v.Reciprocal; /// /// Negates the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Negate(this ref V3f v) { v.X = -v.X; v.Y = -v.Y; v.Z = -v.Z; } /// /// Returns the outer product (tensor-product) of a * b^T as a 3x3 matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33f Outer(this V3f a, V3f b) { return new M33f( a.X * b.X, a.X * b.Y, a.X * b.Z, a.Y * b.X, a.Y * b.Y, a.Y * b.Z, a.Z * b.X, a.Z * b.Y, a.Z * b.Z); } /// /// Returns the dot product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot(this V3f a, V3f b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z; } /// /// Returns the skew-symmetric "cross" matrix (A^T = -A) of the vector v. /// public static M33f CrossMatrix(this V3f v) { return new M33f(0, -v.Z, +v.Y, +v.Z, 0, -v.X, -v.Y, +v.X, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DirFlags DirFlags(this V3f v) { DirFlags flags = Aardbase.DirFlags.None; if (v.X > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveX; if (v.X < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeX; if (v.Y > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveY; if (v.Y < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeY; if (v.Z > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveZ; if (v.Z < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeZ; return flags; } /// /// Returns the reflection direction of the given vector v (pointing to the surface) for the given normal (should be normalized). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Reflect(this V3f v, V3f normal) { return v - 2 * v.Dot(normal) * normal; } /// /// Returns the refraction direction of the given vector v (pointing to the surface) for the given normal and ratio of refraction indices (n_out / n_in). /// Both the input vectors should be normalized. /// Returns a zero-vector in case of total internal reflection. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Refract(this V3f v, V3f normal, float eta) { var t = v.Dot(normal); var k = 1 - eta * eta * (1 - t * t); if (k < 0) { return V3f.Zero; } else { return eta * v - (eta * t + Fun.Sqrt(k)) * normal; } } /// /// Returns the cross product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f Cross(this V3f a, V3f b) { return new V3f( a.Y * b.Z - a.Z * b.Y, a.Z * b.X - a.X * b.Z, a.X * b.Y - a.Y * b.X ); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V3f a, V3f b) { return (a.X < b.X && a.Y < b.Y && a.Z < b.Z); } /// /// Returns whether ALL elements of v are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V3f v, float s) { return (v.X < s && v.Y < s && v.Z < s); } /// /// Returns whether a is Smaller ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(float s, V3f v) { return (s < v.X && s < v.Y && s < v.Z); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V3f a, V3f b) { return (a.X < b.X || a.Y < b.Y || a.Z < b.Z); } /// /// Returns whether AT LEAST ONE element of v is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V3f v, float s) { return (v.X < s || v.Y < s || v.Z < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(float s, V3f v) { return (s < v.X || s < v.Y || s < v.Z); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V3f a, V3f b) { return (a.X > b.X && a.Y > b.Y && a.Z > b.Z); } /// /// Returns whether ALL elements of v are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V3f v, float s) { return (v.X > s && v.Y > s && v.Z > s); } /// /// Returns whether a is Greater ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(float s, V3f v) { return (s > v.X && s > v.Y && s > v.Z); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V3f a, V3f b) { return (a.X > b.X || a.Y > b.Y || a.Z > b.Z); } /// /// Returns whether AT LEAST ONE element of v is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V3f v, float s) { return (v.X > s || v.Y > s || v.Z > s); } /// /// Returns whether a is Greater AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(float s, V3f v) { return (s > v.X || s > v.Y || s > v.Z); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V3f a, V3f b) { return (a.X <= b.X && a.Y <= b.Y && a.Z <= b.Z); } /// /// Returns whether ALL elements of v are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V3f v, float s) { return (v.X <= s && v.Y <= s && v.Z <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(float s, V3f v) { return (s <= v.X && s <= v.Y && s <= v.Z); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V3f a, V3f b) { return (a.X <= b.X || a.Y <= b.Y || a.Z <= b.Z); } /// /// Returns whether AT LEAST ONE element of v is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V3f v, float s) { return (v.X <= s || v.Y <= s || v.Z <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(float s, V3f v) { return (s <= v.X || s <= v.Y || s <= v.Z); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V3f a, V3f b) { return (a.X >= b.X && a.Y >= b.Y && a.Z >= b.Z); } /// /// Returns whether ALL elements of v are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V3f v, float s) { return (v.X >= s && v.Y >= s && v.Z >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(float s, V3f v) { return (s >= v.X && s >= v.Y && s >= v.Z); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V3f a, V3f b) { return (a.X >= b.X || a.Y >= b.Y || a.Z >= b.Z); } /// /// Returns whether AT LEAST ONE element of v is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V3f v, float s) { return (v.X >= s || v.Y >= s || v.Z >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(float s, V3f v) { return (s >= v.X || s >= v.Y || s >= v.Z); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V3f a, V3f b) { return (a.X == b.X && a.Y == b.Y && a.Z == b.Z); } /// /// Returns whether ALL elements of v are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V3f v, float s) { return (v.X == s && v.Y == s && v.Z == s); } /// /// Returns whether a is Equal ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(float s, V3f v) { return (s == v.X && s == v.Y && s == v.Z); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V3f a, V3f b) { return (a.X == b.X || a.Y == b.Y || a.Z == b.Z); } /// /// Returns whether AT LEAST ONE element of v is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V3f v, float s) { return (v.X == s || v.Y == s || v.Z == s); } /// /// Returns whether a is Equal AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(float s, V3f v) { return (s == v.X || s == v.Y || s == v.Z); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V3f a, V3f b) { return (a.X != b.X && a.Y != b.Y && a.Z != b.Z); } /// /// Returns whether ALL elements of v are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V3f v, float s) { return (v.X != s && v.Y != s && v.Z != s); } /// /// Returns whether a is Different ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(float s, V3f v) { return (s != v.X && s != v.Y && s != v.Z); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V3f a, V3f b) { return (a.X != b.X || a.Y != b.Y || a.Z != b.Z); } /// /// Returns whether AT LEAST ONE element of v is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V3f v, float s) { return (v.X != s || v.Y != s || v.Z != s); } /// /// Returns whether a is Different AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(float s, V3f v) { return (s != v.X || s != v.Y || s != v.Z); } /// /// Compare x-coordinate before y-coordinate, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this V3f v0, V3f v1) { if (v0.X < v1.X) return -1; if (v0.X > v1.X) return +1; if (v0.Y < v1.Y) return -1; if (v0.Y > v1.Y) return +1; if (v0.Z < v1.Z) return -1; if (v0.Z > v1.Z) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MinElement(V3f v) => v.MinElement; /// /// Returns the maximum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MaxElement(V3f v) => v.MaxElement; #endregion #region Axis aligned normal /// /// Returns an arbitrary normal vector, which /// is also normal to either the x, y or z-axis. /// public static V3f AxisAlignedNormal(this V3f v) { V3f vector; float x = v.X.Abs(); float y = v.Y.Abs(); float z = v.Z.Abs(); if (x < y) { if (x < z) vector = V3f.XAxis; else vector = V3f.ZAxis; } else { if (y < z) vector = V3f.YAxis; else vector = V3f.ZAxis; } return v.Cross(vector).Normalized; } #endregion #region Angle between two vectors /// /// Computes the angle between two given vectors in radians. The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float AngleBetweenFast(this V3f x, V3f y) { return Fun.AcosClamped(x.Dot(y)); } /// /// Computes the angle between two given vectors in radians using a numerically stable algorithm. /// The input vectors have to be normalized. /// // https://scicomp.stackexchange.com/a/27769 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float AngleBetween(this V3f x, V3f y) { var a = x + y; var b = x - y; return 2 * Fun.Atan2(b.Length, a.Length); } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this V3f v, float epsilon) => v.X.IsTiny(epsilon) || v.Y.IsTiny(epsilon) || v.Z.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this V3f v, float epsilon) => v.X.IsTiny(epsilon) && v.Y.IsTiny(epsilon) && v.Z.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyFinite(V3f v) => v.AnyFinite; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllFinite(V3f v) => v.AllFinite; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(V3f v) => v.AnyNaN; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(V3f v) => v.AllNaN; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(V3f v) => v.AnyInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(V3f v) => v.AllInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(V3f v) => v.AnyPositiveInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(V3f v) => v.AllPositiveInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(V3f v) => v.AnyNegativeInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(V3f v) => v.AllNegativeInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(V3f v) => v.AnyTiny; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(V3f v) => v.AllTiny; #endregion #region Linear Combination [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f LinCom(V3f p0, V3f p1, ref Tup2 w) { return p0 * w.E0 + p1 * w.E1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f LinCom(V3f p0, V3f p1, V3f p2, ref Tup3 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f LinCom(V3f p0, V3f p1, V3f p2, V3f p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f LinCom(V3f p0, V3f p1, V3f p2, V3f p3, V3f p4, ref Tup5 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f LinCom(V3f p0, V3f p1, V3f p2, V3f p3, V3f p4, V3f p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f LinCom(V3f p0, V3f p1, V3f p2, V3f p3, V3f p4, V3f p5, V3f p6, ref Tup7 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5 + p6 * w.E6; } #endregion #region ArrayExtensions public static int IndexOfClosestPoint(this V3f[] pointArray, V3f point) { var bestDist = DistanceSquared(point, pointArray[0]); int bestIndex = 0; int count = pointArray.Length; for (int i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this V3f[] array, int start, int count, V3f point) { var bestDist = DistanceSquared(point, array[start]); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this T[] array, int start, int count, Func pointSelector, V3f point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint(this V3f[] pointArray, V3f point) { var bestDist = DistanceSquared(point, pointArray[0]); long bestIndex = 0; long count = pointArray.LongLength; for (long i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this V3f[] array, long start, long count, V3f point) { var bestDist = DistanceSquared(point, array[start]); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this T[] array, long start, long count, Func pointSelector, V3f point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static int IndexOfMinX(this V3f[] vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static long LongIndexOfMinX(this V3f[] vectorArray, long count = 0) { var minimum = vectorArray[0].X; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static int IndexOfMaxX(this V3f[] vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static long LongIndexOfMaxX(this V3f[] vectorArray, long count = 0) { var maximum = vectorArray[0].X; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static int IndexOfMinY(this V3f[] vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static long LongIndexOfMinY(this V3f[] vectorArray, long count = 0) { var minimum = vectorArray[0].Y; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static int IndexOfMaxY(this V3f[] vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static long LongIndexOfMaxY(this V3f[] vectorArray, long count = 0) { var maximum = vectorArray[0].Y; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static int IndexOfMinZ(this V3f[] vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static long LongIndexOfMinZ(this V3f[] vectorArray, long count = 0) { var minimum = vectorArray[0].Z; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static int IndexOfMaxZ(this V3f[] vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static long LongIndexOfMaxZ(this V3f[] vectorArray, long count = 0) { var maximum = vectorArray[0].Z; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the list. /// public static int IndexOfMinX(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the list. /// public static int IndexOfMaxX(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the list. /// public static int IndexOfMinY(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the list. /// public static int IndexOfMaxY(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the list. /// public static int IndexOfMinZ(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the list. /// public static int IndexOfMaxZ(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the array of the index-th coordinate of each vector. /// public static float[] CopyCoord(this V3f[] self, int index) { switch (index) { case 0: return self.Map(v => v.X); case 1: return self.Map(v => v.Y); case 2: return self.Map(v => v.Z); default: throw new IndexOutOfRangeException(); } } public static V3f WeightedSum( this V3f[] vectorArray, float[] weightArray) { var r = V3f.Zero; var count = vectorArray.LongLength; for (long i = 0; i < count; i++) r += vectorArray[i] * weightArray[i]; return r; } #endregion } public static class IRandomUniformV3fExtensions { #region IRandomUniform extensions for V3f /// /// Uses UniformFloat() to generate the elements of a V3f vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f UniformV3f(this IRandomUniform rnd) { return new V3f(rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat()); } /// /// Uses UniformFloat() to generate the elements of a V3f /// vector within the given Box3f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f UniformV3f(this IRandomUniform rnd, Box3f box) { return new V3f(box.Min.X + rnd.UniformFloat() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformFloat() * (box.Max.Y - box.Min.Y), box.Min.Z + rnd.UniformFloat() * (box.Max.Z - box.Min.Z)); } /// /// Uses UniformFloatClosed() to generate the elements of a V3f vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f UniformV3fClosed(this IRandomUniform rnd) { return new V3f(rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed()); } /// /// Uses UniformFloatClosed() to generate the elements of a V3f /// vector within the given Box3f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f UniformV3fClosed(this IRandomUniform rnd, Box3f box) { return new V3f(box.Min.X + rnd.UniformFloatClosed() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformFloatClosed() * (box.Max.Y - box.Min.Y), box.Min.Z + rnd.UniformFloatClosed() * (box.Max.Z - box.Min.Z)); } /// /// Uses UniformFloatOpen() to generate the elements of a V3f vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f UniformV3fOpen(this IRandomUniform rnd) { return new V3f(rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen()); } /// /// Uses UniformFloatOpen() to generate the elements of a V3f /// vector within the given Box3f. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f UniformV3fOpen(this IRandomUniform rnd, Box3f box) { return new V3f(box.Min.X + rnd.UniformFloatOpen() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformFloatOpen() * (box.Max.Y - box.Min.Y), box.Min.Z + rnd.UniformFloatOpen() * (box.Max.Z - box.Min.Z)); } /// /// Returns a uniformly distributed vector (corresponds to a /// uniformly distributed point on the surface of the unit sphere). /// Note however, that the returned vector will never be equal to /// [0, 0, -1]. Uses UniformFloat() internally. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f UniformV3fDirection(this IRandomUniform rnd) { float phi = rnd.UniformFloat() * ConstantF.PiTimesTwo; float z = 1 - rnd.UniformFloat() * 2; float s = Fun.Sqrt(1 - z * z); return new V3f(Fun.Cos(phi) * s, Fun.Sin(phi) * s, z); } /// /// Uniform vector in the closed unit sphere (i.e vectors to /// the surface of the sphere may be generated). Uses UniformV3fClosed() internally. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f UniformV3fClosedSphere(this IRandomUniform rnd) { float r2; V3f p; V3f c_shift = -V3f.Half; do { p = (rnd.UniformV3fClosed() + c_shift) * 2; r2 = p.LengthSquared; } while (r2 >= 1); return p; } /// /// Uniform vector inside the open unit sphere (i.e. no vector /// ends on the surface of the sphere). Uses UniformV3fOpen() internally. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3f UniformV3fOpenSphere(this IRandomUniform rnd) { float r2; V3f p; V3f c_shift = -V3f.Half; do { p = (rnd.UniformV3fOpen() + c_shift) * 2; r2 = p.LengthSquared; } while (r2 >= 1); return p; } #endregion } #endregion #region V3d [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct V3d : IVector, ISize3d, IFormattable, IEquatable { [DataMember] public double X; [DataMember] public double Y; [DataMember] public double Z; #region Constructors /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(int x, int y, int z) { X = (double)x; Y = (double)y; Z = (double)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(int v) { X = (double)v; Y = (double)v; Z = (double)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(int[] a) { X = (double)a[0]; Y = (double)a[1]; Z = (double)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(int[] a, int start) { X = (double)a[start + 0]; Y = (double)a[start + 1]; Z = (double)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(int a, V2i b) { X = (double)a; Y = (double)b.X; Z = (double)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V2i a, int b) { X = (double)a.X; Y = (double)a.Y; Z = (double)b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(uint x, uint y, uint z) { X = (double)x; Y = (double)y; Z = (double)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(uint v) { X = (double)v; Y = (double)v; Z = (double)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(uint[] a) { X = (double)a[0]; Y = (double)a[1]; Z = (double)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(uint[] a, int start) { X = (double)a[start + 0]; Y = (double)a[start + 1]; Z = (double)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(uint a, V2ui b) { X = (double)a; Y = (double)b.X; Z = (double)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V2ui a, uint b) { X = (double)a.X; Y = (double)a.Y; Z = (double)b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(long x, long y, long z) { X = (double)x; Y = (double)y; Z = (double)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(long v) { X = (double)v; Y = (double)v; Z = (double)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(long[] a) { X = (double)a[0]; Y = (double)a[1]; Z = (double)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(long[] a, int start) { X = (double)a[start + 0]; Y = (double)a[start + 1]; Z = (double)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(long a, V2l b) { X = (double)a; Y = (double)b.X; Z = (double)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V2l a, long b) { X = (double)a.X; Y = (double)a.Y; Z = (double)b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(float x, float y, float z) { X = (double)x; Y = (double)y; Z = (double)z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(float v) { X = (double)v; Y = (double)v; Z = (double)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(float[] a) { X = (double)a[0]; Y = (double)a[1]; Z = (double)a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(float[] a, int start) { X = (double)a[start + 0]; Y = (double)a[start + 1]; Z = (double)a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(float a, V2f b) { X = (double)a; Y = (double)b.X; Z = (double)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V2f a, float b) { X = (double)a.X; Y = (double)a.Y; Z = (double)b; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(double x, double y, double z) { X = x; Y = y; Z = z; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(double v) { X = v; Y = v; Z = v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(double[] a) { X = a[0]; Y = a[1]; Z = a[2]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(double[] a, int start) { X = a[start + 0]; Y = a[start + 1]; Z = a[start + 2]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(double a, V2d b) { X = a; Y = b.X; Z = b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V2d a, double b) { X = a.X; Y = a.Y; Z = b; } /// /// Creates a vector from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(Func index_fun) { X = index_fun(0); Y = index_fun(1); Z = index_fun(2); } /// /// Creates a vector from a general vector implementing the IVector<double> interface. /// The caller has to verify that the dimension of is at least 3. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(IVector v) : this(v[0], v[1], v[2]) { } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V2i v) { X = (double)v.X; Y = (double)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V2ui v) { X = (double)v.X; Y = (double)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V2l v) { X = (double)v.X; Y = (double)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V2f v) { X = (double)v.X; Y = (double)v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// Z is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V2d v) { X = v.X; Y = v.Y; Z = 0; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V3i v) { X = (double)v.X; Y = (double)v.Y; Z = (double)v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V3ui v) { X = (double)v.X; Y = (double)v.Y; Z = (double)v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V3l v) { X = (double)v.X; Y = (double)v.Y; Z = (double)v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V3f v) { X = (double)v.X; Y = (double)v.Y; Z = (double)v.Z; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V3d v) { X = v.X; Y = v.Y; Z = v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V4i v) { X = (double)v.X; Y = (double)v.Y; Z = (double)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V4ui v) { X = (double)v.X; Y = (double)v.Y; Z = (double)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V4l v) { X = (double)v.X; Y = (double)v.Y; Z = (double)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V4f v) { X = (double)v.X; Y = (double)v.Y; Z = (double)v.Z; } /// /// Creates a vector from another vector of type . /// v.W is ignored. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(V4d v) { X = v.X; Y = v.Y; Z = v.Z; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(C3b c) { X = (double)(c.R); Y = (double)(c.G); Z = (double)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(C3us c) { X = (double)(c.R); Y = (double)(c.G); Z = (double)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(C3ui c) { X = (double)(c.R); Y = (double)(c.G); Z = (double)(c.B); } /// /// Creates a vector from a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(C3f c) { X = (double)(c.R); Y = (double)(c.G); Z = (double)(c.B); } /// /// Creates a vector from a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(C3d c) { X = (c.R); Y = (c.G); Z = (c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(C4b c) { X = (double)(c.R); Y = (double)(c.G); Z = (double)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(C4us c) { X = (double)(c.R); Y = (double)(c.G); Z = (double)(c.B); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(C4ui c) { X = (double)(c.R); Y = (double)(c.G); Z = (double)(c.B); } /// /// Creates a vector from a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(C4f c) { X = (double)(c.R); Y = (double)(c.G); Z = (double)(c.B); } /// /// Creates a vector from a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V3d(C4d c) { X = (c.R); Y = (c.G); Z = (c.B); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(V2i v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(V2ui v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(V2l v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(V2f v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(V2d v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(V3i v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(V3ui v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(V3l v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(V3f v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(V4i v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(V4ui v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(V4l v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(V4f v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(V4d v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToV2i() => (V2i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui ToV2ui() => (V2ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToV2l() => (V2l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f ToV2f() => (V2f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int[](V3d v) => new int[] { (int)v.X, (int)v.Y, (int)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(int[] v) => new V3d((double)v[0], (double)v[1], (double)v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](V3d v) => new uint[] { (uint)v.X, (uint)v.Y, (uint)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(uint[] v) => new V3d((double)v[0], (double)v[1], (double)v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long[](V3d v) => new long[] { (long)v.X, (long)v.Y, (long)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(long[] v) => new V3d((double)v[0], (double)v[1], (double)v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](V3d v) => new float[] { (float)v.X, (float)v.Y, (float)v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(float[] v) => new V3d((double)v[0], (double)v[1], (double)v[2]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](V3d v) => new double[] { v.X, v.Y, v.Z }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(double[] v) => new V3d(v[0], v[1], v[2]); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(C3b v) => new V3d(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(C3us v) => new V3d(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(C3ui v) => new V3d(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(C3f v) => new V3d(v); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f ToC3f() => (C3f)this; /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(C3d v) => new V3d(v); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d ToC3d() => (C3d)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(C4b v) => new V3d(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(C4us v) => new V3d(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(C4ui v) => new V3d(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// The alpha channel is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(C4f v) => new V3d(v); /// /// Converts the given vector to a color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f ToC4f() => (C4f)this; /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V3d(C4d v) => new V3d(v); /// /// Converts the given vector to a color. /// The alpha channel is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d ToC4d() => (C4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToFloorV3l() => new V3l((long)Fun.Floor(X), (long)Fun.Floor(Y), (long)Fun.Floor(Z)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToCeilingV3l() => new V3l((long)Fun.Ceiling(X), (long)Fun.Ceiling(Y), (long)Fun.Ceiling(Z)); /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToV2iInhomo() { var div = 1 / Z; return new V2i(X * div, Y * div); } /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui ToV2uiInhomo() { var div = 1 / Z; return new V2ui(X * div, Y * div); } /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToV2lInhomo() { var div = 1 / Z; return new V2l(X * div, Y * div); } /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f ToV2fInhomo() { var div = 1 / Z; return new V2f(X * div, Y * div); } /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d ToV2dInhomo() { var div = 1 / Z; return new V2d(X * div, Y * div); } /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4iHomo() => new V4i(X, Y, Z, 1); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4uiHomo() => new V4ui(X, Y, Z, 1); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4lHomo() => new V4l(X, Y, Z, 1); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4fHomo() => new V4f(X, Y, Z, 1); /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4dHomo() => new V4d(X, Y, Z, 1); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i Copy(Func element_fun) => new V3i(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i Copy(Func element_index_fun) => new V3i(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(int[] array, int start) { array[start + 0] = (int)X; array[start + 1] = (int)Y; array[start + 2] = (int)Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui Copy(Func element_fun) => new V3ui(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui Copy(Func element_index_fun) => new V3ui(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(uint[] array, int start) { array[start + 0] = (uint)X; array[start + 1] = (uint)Y; array[start + 2] = (uint)Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l Copy(Func element_fun) => new V3l(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l Copy(Func element_index_fun) => new V3l(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(long[] array, int start) { array[start + 0] = (long)X; array[start + 1] = (long)Y; array[start + 2] = (long)Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f Copy(Func element_fun) => new V3f(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f Copy(Func element_index_fun) => new V3f(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(float[] array, int start) { array[start + 0] = (float)X; array[start + 1] = (float)Y; array[start + 2] = (float)Z; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d Copy(Func element_fun) => new V3d(element_fun(X), element_fun(Y), element_fun(Z)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d Copy(Func element_index_fun) => new V3d(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(double[] array, int start) { array[start + 0] = X; array[start + 1] = Y; array[start + 2] = Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(X); array[start + 1] = element_fun(Y); array[start + 2] = element_fun(Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(X, 0); array[start + 1] = element_index_fun(Y, 1); array[start + 2] = element_index_fun(Z, 2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double[] ToArray() => new double[] { X, Y, Z }; #endregion #region Properties and Indexers /// /// Property for the field X. /// Useful when properties are required, but the field X is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public double P_X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value; } } /// /// Property for the field Y. /// Useful when properties are required, but the field Y is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public double P_Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Y = value; } } /// /// Property for the field Z. /// Useful when properties are required, but the field Z is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public double P_Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Z = value; } } /// /// Enumerates all elements of this vector. /// public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return X; yield return Y; yield return Z; } } /// /// Gets or sets element with given index. /// public unsafe double this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &X) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &X) { ptr[index] = value; } } } /// /// Returns the index of the largest dimension of the vector. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X >= Y ? (X >= Z ? 0 : 2) : (Y >= Z ? 1 : 2); } } /// /// Returns the index of the smallest dimension of the vector. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X <= Y ? (X <= Z ? 0 : 2) : (Y <= Z ? 1 : 2); } } /// /// Returns the minimum element of the vector. /// public readonly double MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(X, Y, Z); } /// /// Returns the maximum element of the vector. /// public readonly double MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(X, Y, Z); } public readonly bool AnyFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsFinite(X) || Fun.IsFinite(Y) || Fun.IsFinite(Z); } public readonly bool AllFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsFinite(X) && Fun.IsFinite(Y) && Fun.IsFinite(Z); } public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNaN(X) || double.IsNaN(Y) || double.IsNaN(Z); } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNaN(X) && double.IsNaN(Y) && double.IsNaN(Z); } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsInfinity(X) || double.IsInfinity(Y) || double.IsInfinity(Z); } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsInfinity(X) && double.IsInfinity(Y) && double.IsInfinity(Z); } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsPositiveInfinity(X) || double.IsPositiveInfinity(Y) || double.IsPositiveInfinity(Z); } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsPositiveInfinity(X) && double.IsPositiveInfinity(Y) && double.IsPositiveInfinity(Z); } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNegativeInfinity(X) || double.IsNegativeInfinity(Y) || double.IsNegativeInfinity(Z); } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNegativeInfinity(X) && double.IsNegativeInfinity(Y) && double.IsNegativeInfinity(Z); } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(X) || Fun.IsTiny(Y) || Fun.IsTiny(Z); } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(X) && Fun.IsTiny(Y) && Fun.IsTiny(Z); } /// /// Returns true if the absolute value of each component of the vector is smaller than Constant<double>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any component of the vector is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any component of the vector is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any component of the vector is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any component of the vector is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all components of the vector are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Constants /// /// Number of elements in this vector. /// public const int Dimension = 3; /// /// All elements zero. /// public static V3d Zero { get { return new V3d(0, 0, 0); } } /// /// All elements half. /// public static V3d Half { get { return new V3d(0.5, 0.5, 0.5); } } /// /// All elements one. /// public static V3d One { get { return new V3d(1, 1, 1); } } /// /// All elements set to maximum possible value. /// public static V3d MaxValue { get { return new V3d(Constant.ParseableMaxValue, Constant.ParseableMaxValue, Constant.ParseableMaxValue); } } /// /// All elements set to minimum possible value. /// public static V3d MinValue { get { return new V3d(Constant.ParseableMinValue, Constant.ParseableMinValue, Constant.ParseableMinValue); } } /// /// All elements set to negative infinity. /// public static V3d NegativeInfinity { get { return new V3d(double.NegativeInfinity, double.NegativeInfinity, double.NegativeInfinity); } } /// /// All elements set to positive infinity. /// public static V3d PositiveInfinity { get { return new V3d(double.PositiveInfinity, double.PositiveInfinity, double.PositiveInfinity); } } /// /// All elements set to NaN. /// public static V3d NaN { get { return new V3d(double.NaN, double.NaN, double.NaN); } } /// /// Normalized X-axis. /// public static V3d XAxis { get { return new V3d(1, 0, 0); } } /// /// Normalized Y-axis. /// public static V3d YAxis { get { return new V3d(0, 1, 0); } } /// /// Normalized Z-axis. /// public static V3d ZAxis { get { return new V3d(0, 0, 1); } } /// /// An array of accessor functions for the coordinates of the vector. /// public static readonly Func[] SelectorArray = new Func[] { v => v.X, v => v.Y, v => v.Z }; /// /// Element getter function. /// public static readonly Func Getter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref V3d v, int i, double s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; default: throw new IndexOutOfRangeException(); } }; /// /// Element getter function with long index. /// public static readonly Func LongGetter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action with long index. /// public static readonly ActionRefValVal LongSetter = (ref V3d v, long i, double s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Static factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FromV3i(V3i v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FromV3ui(V3ui v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FromV3l(V3l v) => new V3d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FromV3f(V3f v) => new V3d(v); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FromC3b(C3b c) => new V3d(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FromC3us(C3us c) => new V3d(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FromC3ui(C3ui c) => new V3d(c); /// /// Creates a vector from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FromC3f(C3f c) => new V3d(c); /// /// Creates a vector from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FromC3d(C3d c) => new V3d(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FromC4b(C4b c) => new V3d(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FromC4us(C4us c) => new V3d(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FromC4ui(C4ui c) => new V3d(c); /// /// Creates a vector from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FromC4f(C4f c) => new V3d(c); /// /// Creates a vector from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FromC4d(C4d c) => new V3d(c); private static readonly V3d[] s_fromCubeCode = new V3d[] { -V3d.XAxis, -V3d.YAxis, -V3d.ZAxis, V3d.XAxis, V3d.YAxis, V3d.ZAxis }; /// /// Return the vector for the supplied cube face code. /// 0 ... -XAxis, 1 ... -YAxis, 2 ... -ZAsix, 3 ... XAxis, 4 ... YAxis, 5 ... ZAxis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FromCubeFaceCode(int i) { return s_fromCubeCode[i]; } #endregion #region Norms /// /// Returns the squared length of the vector. /// public readonly double LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X * X + Y * Y + Z * Z ; } } /// /// Returns the length of the vector. /// public readonly double Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z ); } } /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// public readonly double Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Abs(X) + Fun.Abs(Y) + Fun.Abs(Z); } } /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z); } } /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// public readonly double NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z)); } } /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// public readonly double NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z)); } } /// /// Returns a normalized copy of this vector. /// public readonly V3d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Length; if (s == 0) return V3d.Zero; s = 1 / s; return new V3d(X * s, Y * s, Z * s); } } /// /// Returns a copy of the vector with the maximum component length of /// exactly 1. This corresponds to mapping the vector onto an origin- /// centered cube with side length 2. /// public readonly V3d CubeMapped { get { double x = Fun.Abs(X); double y = Fun.Abs(Y); double z = Fun.Abs(Z); if (x > y) { if (x > z) { double s = 1 / x; return new V3d(Fun.Sign(X), Y * s, Z * s); } else { double s = 1 / z; return new V3d(X * s, Y * s, Fun.Sign(Z)); } } else { if (y > z) { double s = 1 / y; return new V3d(X * s, Fun.Sign(Y), Z * s); } else { double s = 1 / z; return new V3d(X * s, Y * s, Fun.Sign(Z)); } } } } /// /// Returns a copy of the vector with the maximum component length of /// exactly 1. This corresponds to mapping the vector onto an origin- /// centered cube with side length 2. /// The out parameter face indicate which face the vector was mapped to: /// 0 ... -XAxis, 1 ... -YAxis, 2 ... -ZAsix, 3 ... XAxis, 4 ... YAxis, 5 ... ZAxis. /// public readonly V3d CubeMappedOnFace(out int face) { double x = Fun.Abs(X); double y = Fun.Abs(Y); double z = Fun.Abs(Z); if (x > y) { if (x > z) { double s = 1 / x; face = X < 0 ? 0 : 3; return new V3d(Fun.Sign(X), Y * s, Z * s); } else { double s = 1 / z; face = Z < 0 ? 2 : 5; return new V3d(X * s, Y * s, Fun.Sign(Z)); } } else { if (y > z) { double s = 1 / y; face = Y < 0 ? 1 : 4; return new V3d(X * s, Fun.Sign(Y), Z * s); } else { double s = 1 / z; face = Z < 0 ? 2 : 5; return new V3d(X * s, Y * s, Fun.Sign(Z)); } } } /// /// Return an index for the cube face onto which the vector points. /// 0 ... -XAxis, 1 ... -YAxis, 2 ... -ZAsix, 3 ... XAxis, 4 ... YAxis, 5 ... ZAxis. /// public readonly int CubeFaceCode { get { double x = Fun.Abs(X); double y = Fun.Abs(Y); double z = Fun.Abs(Z); int c; double v; if (x > y) { if (x > z) { c = 0; v = X; } else { c = 2; v = Z; } } else { if (y > z) { c = 1; v = Y; } else { c = 2; v = Z; } } return v < 0 ? c : c + 3; } } #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Abs(V3d v) => v.Abs(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Floor(V3d v) => v.Floor(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Ceiling(V3d v) => v.Ceiling(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Round(V3d v) => v.Round(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Truncate(V3d v) => v.Truncate(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Acos(V3d v) => Fun.Acos(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Acoshb(V3d v) => Fun.Acosh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Cos(V3d v) => Fun.Cos(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Cosh(V3d v) => Fun.Cosh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Asin(V3d v) => Fun.Asin(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Asinhb(V3d v) => Fun.Asinh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Sin(V3d v) => Fun.Sin(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Sinh(V3d v) => Fun.Sinh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Atan(V3d v) => Fun.Atan(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Atanhb(V3d v) => Fun.Atanh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Atan2(V3d a, V3d b) => Fun.Atan2(a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Tan(V3d v) => Fun.Tan(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Tanh(V3d v) => Fun.Tanh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Sqrt(V3d v) => Fun.Sqrt(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d CubeRoot(V3d v) => Fun.Cbrt(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Exp(V3d v) => Fun.Exp(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log(V3d v) => Fun.Log(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d LogBinary(V3d v) => Fun.Log2(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log10(V3d v) => Fun.Log10(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d CopySgn(V3d value, V3d sign) => Fun.CopySign(value, sign); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d CopySgn(V3d value, double sign) => Fun.CopySign(value, sign); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d LinearInterp(double t, V3d a, V3d b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d LinearInterp(V3d t, V3d a, V3d b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Min(V3d v0, V3d v1) => Fun.Min(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Min(V3d v, double x) => Fun.Min(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Max(V3d v0, V3d v1) => Fun.Max(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Max(V3d v, double x) => Fun.Max(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Saturate(V3d v) => Fun.Saturate(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d DivideByInt(V3d v, int x) => v / x; #endregion #region Operations /// /// Sets the elements of a vector to the given int elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(int x, int y, int z) { X = (double)x; Y = (double)y; Z = (double)z; } /// /// Sets the elements of a vector to the given uint elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(uint x, uint y, uint z) { X = (double)x; Y = (double)y; Z = (double)z; } /// /// Sets the elements of a vector to the given long elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(long x, long y, long z) { X = (double)x; Y = (double)y; Z = (double)z; } /// /// Sets the elements of a vector to the given float elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(float x, float y, float z) { X = (double)x; Y = (double)y; Z = (double)z; } /// /// Sets the elements of a vector to the given double elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(double x, double y, double z) { X = x; Y = y; Z = z; } /// /// Returns a negated copy of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator -(V3d v) => new V3d(-v.X, -v.Y, -v.Z); /// /// Gets a copy of this vector containing the reciprocal (1/x) of each element. /// public readonly V3d Reciprocal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V3d(1 / X, 1 / Y, 1 / Z); } } /// /// Returns the component-wise sum of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator +(V3d a, V3d b) => new V3d(a.X + b.X, a.Y + b.Y, a.Z + b.Z); /// /// Returns the component-wise sum of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator +(V3d v, double s) => new V3d(v.X + s, v.Y + s, v.Z + s); /// /// Returns the component-wise sum of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator +(double s, V3d v) => new V3d(s + v.X, s + v.Y, s + v.Z); /// /// Returns the component-wise difference of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator -(V3d a, V3d b) => new V3d(a.X - b.X, a.Y - b.Y, a.Z - b.Z); /// /// Returns the component-wise difference of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator -(V3d v, double s) => new V3d(v.X - s, v.Y - s, v.Z - s); /// /// Returns the component-wise difference of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator -(double s, V3d v) => new V3d(s - v.X, s - v.Y, s - v.Z); /// /// Returns the component-wise product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator *(V3d a, V3d b) => new V3d(a.X * b.X, a.Y * b.Y, a.Z * b.Z); /// /// Returns the component-wise product of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator *(V3d v, double s) => new V3d(v.X * s, v.Y * s, v.Z * s); /// /// Returns the component-wise product of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator *(double s, V3d v) => new V3d(s * v.X, s * v.Y, s * v.Z); /// /// Returns the component-wise fraction of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator /(V3d a, V3d b) => new V3d(a.X / b.X, a.Y / b.Y, a.Z / b.Z); /// /// Returns the component-wise fraction of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator /(V3d v, double s) => new V3d(v.X / s, v.Y / s, v.Z / s); /// /// Returns the component-wise fraction of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator /(double s, V3d v) => new V3d(s / v.X, s / v.Y, s / v.Z); /// /// Returns the component-wise remainder of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator %(V3d a, V3d b) => new V3d(a.X % b.X, a.Y % b.Y, a.Z % b.Z); /// /// Returns the component-wise remainder of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator %(V3d v, double s) => new V3d(v.X % s, v.Y % s, v.Z % s); /// /// Returns the component-wise remainder of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d operator %(double s, V3d v) => new V3d(s % v.X, s % v.Y, s % v.Z); /// Attention: NEVER implement operators <, <=, >=, >, /// since these are not defined in a Vector space. /// Use AllSmaller() and similar comparators! #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V3d a, V3d b) { return a.X == b.X && a.Y == b.Y && a.Z == b.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V3d v, double s) { return v.X == s && v.Y == s && v.Z == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(double s, V3d v) { return s == v.X && s == v.Y && s == v.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V3d a, V3d b) { return a.X != b.X || a.Y != b.Y || a.Z != b.Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V3d v, double s) { return v.X != s || v.Y != s || v.Z != s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(double s, V3d v) { return s != v.X || s != v.Y || s != v.Z; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(V3d other) { return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z); } #endregion #region Overrides public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + X.ToString(format, fp) + between + Y.ToString(format, fp) + between + Z.ToString(format, fp) + end; } public override readonly int GetHashCode() { return HashCode.GetCombined(X, Y, Z); } public override readonly bool Equals(object other) => (other is V3d o) ? Equals(o) : false; public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + X.ToString(null, CultureInfo.InvariantCulture) + ", " + Y.ToString(null, CultureInfo.InvariantCulture) + ", " + Z.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Parsing public static V3d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new V3d( double.Parse(x[0], CultureInfo.InvariantCulture), double.Parse(x[1], CultureInfo.InvariantCulture), double.Parse(x[2], CultureInfo.InvariantCulture) ); } public static V3d Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, V3d.Setter); } public static V3d Parse(Text t, int bracketLevel) { return t.NestedBracketSplit(bracketLevel, Text.Parse, V3d.Setter); } #endregion #region Swizzle Methods [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d OX => new V2d(0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d OY => new V2d(0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d OZ => new V2d(0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d IX => new V2d(1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d IY => new V2d(1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d IZ => new V2d(1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d NX => new V2d(-1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d NY => new V2d(-1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d NZ => new V2d(-1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d XO => new V2d(X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d XI => new V2d(X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d XN => new V2d(X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d XX => new V2d(X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d XY { readonly get => new V2d(X, Y); set { X = value.X; Y = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d XZ { readonly get => new V2d(X, Z); set { X = value.X; Z = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d YO => new V2d(Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d YI => new V2d(Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d YN => new V2d(Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d YX { readonly get => new V2d(Y, X); set { Y = value.X; X = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d YY => new V2d(Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d YZ { readonly get => new V2d(Y, Z); set { Y = value.X; Z = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d ZO => new V2d(Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d ZI => new V2d(Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d ZN => new V2d(Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d ZX { readonly get => new V2d(Z, X); set { Z = value.X; X = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d ZY { readonly get => new V2d(Z, Y); set { Z = value.X; Y = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d ZZ => new V2d(Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d OOO => new V3d(0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d OOI => new V3d(0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d OON => new V3d(0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OOX => new V3d(0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OOY => new V3d(0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OOZ => new V3d(0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d OIO => new V3d(0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d OII => new V3d(0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d OPN => new V3d(0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OIX => new V3d(0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OIY => new V3d(0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OIZ => new V3d(0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d ONO => new V3d(0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d ONP => new V3d(0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d ONN => new V3d(0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ONX => new V3d(0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ONY => new V3d(0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ONZ => new V3d(0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXO => new V3d(0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXI => new V3d(0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXN => new V3d(0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXX => new V3d(0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXY => new V3d(0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXZ => new V3d(0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYO => new V3d(0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYI => new V3d(0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYN => new V3d(0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYX => new V3d(0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYY => new V3d(0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYZ => new V3d(0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OZO => new V3d(0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OZI => new V3d(0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OZN => new V3d(0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OZX => new V3d(0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OZY => new V3d(0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OZZ => new V3d(0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d IOO => new V3d(1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d IOI => new V3d(1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d PON => new V3d(1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IOX => new V3d(1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IOY => new V3d(1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IOZ => new V3d(1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d IIO => new V3d(1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d III => new V3d(1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d PPN => new V3d(1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IIX => new V3d(1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IIY => new V3d(1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IIZ => new V3d(1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d PNO => new V3d(1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d PNP => new V3d(1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d PNN => new V3d(1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PNX => new V3d(1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PNY => new V3d(1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PNZ => new V3d(1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IXO => new V3d(1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IXI => new V3d(1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PXN => new V3d(1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IXX => new V3d(1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IXY => new V3d(1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IXZ => new V3d(1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IYO => new V3d(1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IYI => new V3d(1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PYN => new V3d(1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IYX => new V3d(1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IYY => new V3d(1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IYZ => new V3d(1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IZO => new V3d(1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IZI => new V3d(1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PZN => new V3d(1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IZX => new V3d(1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IZY => new V3d(1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IZZ => new V3d(1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d NOO => new V3d(-1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d NOP => new V3d(-1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d NON => new V3d(-1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NOX => new V3d(-1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NOY => new V3d(-1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NOZ => new V3d(-1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d NPO => new V3d(-1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d NPP => new V3d(-1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d NPN => new V3d(-1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NPX => new V3d(-1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NPY => new V3d(-1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NPZ => new V3d(-1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d NNO => new V3d(-1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d NNP => new V3d(-1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V3d NNN => new V3d(-1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NNX => new V3d(-1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NNY => new V3d(-1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NNZ => new V3d(-1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXO => new V3d(-1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXP => new V3d(-1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXN => new V3d(-1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXX => new V3d(-1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXY => new V3d(-1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXZ => new V3d(-1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYO => new V3d(-1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYP => new V3d(-1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYN => new V3d(-1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYX => new V3d(-1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYY => new V3d(-1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYZ => new V3d(-1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NZO => new V3d(-1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NZP => new V3d(-1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NZN => new V3d(-1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NZX => new V3d(-1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NZY => new V3d(-1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NZZ => new V3d(-1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XOO => new V3d(X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XOI => new V3d(X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XON => new V3d(X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XOX => new V3d(X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XOY => new V3d(X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XOZ => new V3d(X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XIO => new V3d(X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XII => new V3d(X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XPN => new V3d(X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XIX => new V3d(X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XIY => new V3d(X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XIZ => new V3d(X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNO => new V3d(X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNP => new V3d(X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNN => new V3d(X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNX => new V3d(X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNY => new V3d(X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNZ => new V3d(X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXO => new V3d(X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXI => new V3d(X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXN => new V3d(X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXX => new V3d(X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXY => new V3d(X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXZ => new V3d(X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XYO => new V3d(X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XYI => new V3d(X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XYN => new V3d(X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XYX => new V3d(X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XYY => new V3d(X, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d XYZ { readonly get => new V3d(X, Y, Z); set { X = value.X; Y = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XZO => new V3d(X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XZI => new V3d(X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XZN => new V3d(X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XZX => new V3d(X, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d XZY { readonly get => new V3d(X, Z, Y); set { X = value.X; Z = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XZZ => new V3d(X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YOO => new V3d(Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YOI => new V3d(Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YON => new V3d(Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YOX => new V3d(Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YOY => new V3d(Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YOZ => new V3d(Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YIO => new V3d(Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YII => new V3d(Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YPN => new V3d(Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YIX => new V3d(Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YIY => new V3d(Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YIZ => new V3d(Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNO => new V3d(Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNP => new V3d(Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNN => new V3d(Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNX => new V3d(Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNY => new V3d(Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNZ => new V3d(Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YXO => new V3d(Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YXI => new V3d(Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YXN => new V3d(Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YXX => new V3d(Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YXY => new V3d(Y, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d YXZ { readonly get => new V3d(Y, X, Z); set { Y = value.X; X = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYO => new V3d(Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYI => new V3d(Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYN => new V3d(Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYX => new V3d(Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYY => new V3d(Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYZ => new V3d(Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YZO => new V3d(Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YZI => new V3d(Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YZN => new V3d(Y, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d YZX { readonly get => new V3d(Y, Z, X); set { Y = value.X; Z = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YZY => new V3d(Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YZZ => new V3d(Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZOO => new V3d(Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZOI => new V3d(Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZON => new V3d(Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZOX => new V3d(Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZOY => new V3d(Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZOZ => new V3d(Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZIO => new V3d(Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZII => new V3d(Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZPN => new V3d(Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZIX => new V3d(Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZIY => new V3d(Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZIZ => new V3d(Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZNO => new V3d(Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZNP => new V3d(Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZNN => new V3d(Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZNX => new V3d(Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZNY => new V3d(Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZNZ => new V3d(Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZXO => new V3d(Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZXI => new V3d(Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZXN => new V3d(Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZXX => new V3d(Z, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d ZXY { readonly get => new V3d(Z, X, Y); set { Z = value.X; X = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZXZ => new V3d(Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZYO => new V3d(Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZYI => new V3d(Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZYN => new V3d(Z, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d ZYX { readonly get => new V3d(Z, Y, X); set { Z = value.X; Y = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZYY => new V3d(Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZYZ => new V3d(Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZZO => new V3d(Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZZI => new V3d(Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZZN => new V3d(Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZZX => new V3d(Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZZY => new V3d(Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZZZ => new V3d(Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOOX => new V4d(0, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOOY => new V4d(0, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOOZ => new V4d(0, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOIX => new V4d(0, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOIY => new V4d(0, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOIZ => new V4d(0, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OONX => new V4d(0, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OONY => new V4d(0, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OONZ => new V4d(0, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXO => new V4d(0, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXI => new V4d(0, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXN => new V4d(0, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXX => new V4d(0, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXY => new V4d(0, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXZ => new V4d(0, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYO => new V4d(0, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYI => new V4d(0, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYN => new V4d(0, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYX => new V4d(0, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYY => new V4d(0, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYZ => new V4d(0, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOZO => new V4d(0, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOZI => new V4d(0, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOZN => new V4d(0, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOZX => new V4d(0, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOZY => new V4d(0, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOZZ => new V4d(0, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIOX => new V4d(0, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIOY => new V4d(0, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIOZ => new V4d(0, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIIX => new V4d(0, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIIY => new V4d(0, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIIZ => new V4d(0, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPNX => new V4d(0, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPNY => new V4d(0, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPNZ => new V4d(0, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIXO => new V4d(0, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIXI => new V4d(0, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPXN => new V4d(0, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIXX => new V4d(0, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIXY => new V4d(0, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIXZ => new V4d(0, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIYO => new V4d(0, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIYI => new V4d(0, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPYN => new V4d(0, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIYX => new V4d(0, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIYY => new V4d(0, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIYZ => new V4d(0, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIZO => new V4d(0, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIZI => new V4d(0, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPZN => new V4d(0, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIZX => new V4d(0, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIZY => new V4d(0, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIZZ => new V4d(0, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONOX => new V4d(0, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONOY => new V4d(0, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONOZ => new V4d(0, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONPX => new V4d(0, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONPY => new V4d(0, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONPZ => new V4d(0, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONNX => new V4d(0, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONNY => new V4d(0, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONNZ => new V4d(0, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXO => new V4d(0, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXP => new V4d(0, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXN => new V4d(0, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXX => new V4d(0, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXY => new V4d(0, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXZ => new V4d(0, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYO => new V4d(0, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYP => new V4d(0, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYN => new V4d(0, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYX => new V4d(0, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYY => new V4d(0, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYZ => new V4d(0, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONZO => new V4d(0, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONZP => new V4d(0, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONZN => new V4d(0, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONZX => new V4d(0, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONZY => new V4d(0, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONZZ => new V4d(0, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXOO => new V4d(0, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXOI => new V4d(0, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXON => new V4d(0, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXOX => new V4d(0, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXOY => new V4d(0, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXOZ => new V4d(0, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXIO => new V4d(0, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXII => new V4d(0, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXPN => new V4d(0, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXIX => new V4d(0, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXIY => new V4d(0, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXIZ => new V4d(0, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNO => new V4d(0, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNP => new V4d(0, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNN => new V4d(0, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNX => new V4d(0, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNY => new V4d(0, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNZ => new V4d(0, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXO => new V4d(0, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXI => new V4d(0, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXN => new V4d(0, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXX => new V4d(0, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXY => new V4d(0, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXZ => new V4d(0, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYO => new V4d(0, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYI => new V4d(0, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYN => new V4d(0, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYX => new V4d(0, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYY => new V4d(0, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYZ => new V4d(0, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXZO => new V4d(0, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXZI => new V4d(0, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXZN => new V4d(0, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXZX => new V4d(0, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXZY => new V4d(0, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXZZ => new V4d(0, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYOO => new V4d(0, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYOI => new V4d(0, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYON => new V4d(0, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYOX => new V4d(0, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYOY => new V4d(0, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYOZ => new V4d(0, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYIO => new V4d(0, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYII => new V4d(0, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYPN => new V4d(0, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYIX => new V4d(0, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYIY => new V4d(0, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYIZ => new V4d(0, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNO => new V4d(0, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNP => new V4d(0, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNN => new V4d(0, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNX => new V4d(0, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNY => new V4d(0, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNZ => new V4d(0, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXO => new V4d(0, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXI => new V4d(0, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXN => new V4d(0, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXX => new V4d(0, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXY => new V4d(0, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXZ => new V4d(0, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYO => new V4d(0, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYI => new V4d(0, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYN => new V4d(0, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYX => new V4d(0, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYY => new V4d(0, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYZ => new V4d(0, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYZO => new V4d(0, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYZI => new V4d(0, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYZN => new V4d(0, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYZX => new V4d(0, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYZY => new V4d(0, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYZZ => new V4d(0, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZOO => new V4d(0, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZOI => new V4d(0, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZON => new V4d(0, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZOX => new V4d(0, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZOY => new V4d(0, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZOZ => new V4d(0, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZIO => new V4d(0, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZII => new V4d(0, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZPN => new V4d(0, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZIX => new V4d(0, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZIY => new V4d(0, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZIZ => new V4d(0, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZNO => new V4d(0, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZNP => new V4d(0, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZNN => new V4d(0, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZNX => new V4d(0, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZNY => new V4d(0, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZNZ => new V4d(0, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZXO => new V4d(0, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZXI => new V4d(0, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZXN => new V4d(0, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZXX => new V4d(0, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZXY => new V4d(0, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZXZ => new V4d(0, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZYO => new V4d(0, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZYI => new V4d(0, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZYN => new V4d(0, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZYX => new V4d(0, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZYY => new V4d(0, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZYZ => new V4d(0, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZZO => new V4d(0, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZZI => new V4d(0, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZZN => new V4d(0, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZZX => new V4d(0, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZZY => new V4d(0, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZZZ => new V4d(0, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOOX => new V4d(1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOOY => new V4d(1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOOZ => new V4d(1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOIX => new V4d(1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOIY => new V4d(1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOIZ => new V4d(1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PONX => new V4d(1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PONY => new V4d(1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PONZ => new V4d(1, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOXO => new V4d(1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOXI => new V4d(1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d POXN => new V4d(1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOXX => new V4d(1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOXY => new V4d(1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOXZ => new V4d(1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOYO => new V4d(1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOYI => new V4d(1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d POYN => new V4d(1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOYX => new V4d(1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOYY => new V4d(1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOYZ => new V4d(1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOZO => new V4d(1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOZI => new V4d(1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d POZN => new V4d(1, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOZX => new V4d(1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOZY => new V4d(1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOZZ => new V4d(1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIOX => new V4d(1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIOY => new V4d(1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIOZ => new V4d(1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIIX => new V4d(1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIIY => new V4d(1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIIZ => new V4d(1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPNX => new V4d(1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPNY => new V4d(1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPNZ => new V4d(1, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIXO => new V4d(1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIXI => new V4d(1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPXN => new V4d(1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIXX => new V4d(1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIXY => new V4d(1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIXZ => new V4d(1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIYO => new V4d(1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIYI => new V4d(1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPYN => new V4d(1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIYX => new V4d(1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIYY => new V4d(1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIYZ => new V4d(1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIZO => new V4d(1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIZI => new V4d(1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPZN => new V4d(1, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIZX => new V4d(1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIZY => new V4d(1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIZZ => new V4d(1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNOX => new V4d(1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNOY => new V4d(1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNOZ => new V4d(1, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNPX => new V4d(1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNPY => new V4d(1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNPZ => new V4d(1, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNNX => new V4d(1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNNY => new V4d(1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNNZ => new V4d(1, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXO => new V4d(1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXP => new V4d(1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXN => new V4d(1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXX => new V4d(1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXY => new V4d(1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXZ => new V4d(1, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYO => new V4d(1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYP => new V4d(1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYN => new V4d(1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYX => new V4d(1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYY => new V4d(1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYZ => new V4d(1, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNZO => new V4d(1, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNZP => new V4d(1, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNZN => new V4d(1, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNZX => new V4d(1, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNZY => new V4d(1, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNZZ => new V4d(1, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXOO => new V4d(1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXOI => new V4d(1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXON => new V4d(1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXOX => new V4d(1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXOY => new V4d(1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXOZ => new V4d(1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXIO => new V4d(1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXII => new V4d(1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXPN => new V4d(1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXIX => new V4d(1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXIY => new V4d(1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXIZ => new V4d(1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNO => new V4d(1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNP => new V4d(1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNN => new V4d(1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNX => new V4d(1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNY => new V4d(1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNZ => new V4d(1, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXXO => new V4d(1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXXI => new V4d(1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXXN => new V4d(1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXXX => new V4d(1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXXY => new V4d(1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXXZ => new V4d(1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXYO => new V4d(1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXYI => new V4d(1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXYN => new V4d(1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXYX => new V4d(1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXYY => new V4d(1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXYZ => new V4d(1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXZO => new V4d(1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXZI => new V4d(1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXZN => new V4d(1, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXZX => new V4d(1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXZY => new V4d(1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXZZ => new V4d(1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYOO => new V4d(1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYOI => new V4d(1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYON => new V4d(1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYOX => new V4d(1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYOY => new V4d(1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYOZ => new V4d(1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYIO => new V4d(1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYII => new V4d(1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYPN => new V4d(1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYIX => new V4d(1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYIY => new V4d(1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYIZ => new V4d(1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNO => new V4d(1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNP => new V4d(1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNN => new V4d(1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNX => new V4d(1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNY => new V4d(1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNZ => new V4d(1, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYXO => new V4d(1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYXI => new V4d(1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYXN => new V4d(1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYXX => new V4d(1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYXY => new V4d(1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYXZ => new V4d(1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYYO => new V4d(1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYYI => new V4d(1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYYN => new V4d(1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYYX => new V4d(1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYYY => new V4d(1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYYZ => new V4d(1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYZO => new V4d(1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYZI => new V4d(1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYZN => new V4d(1, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYZX => new V4d(1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYZY => new V4d(1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYZZ => new V4d(1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZOO => new V4d(1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZOI => new V4d(1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZON => new V4d(1, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZOX => new V4d(1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZOY => new V4d(1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZOZ => new V4d(1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZIO => new V4d(1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZII => new V4d(1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZPN => new V4d(1, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZIX => new V4d(1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZIY => new V4d(1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZIZ => new V4d(1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZNO => new V4d(1, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZNP => new V4d(1, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZNN => new V4d(1, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZNX => new V4d(1, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZNY => new V4d(1, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZNZ => new V4d(1, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZXO => new V4d(1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZXI => new V4d(1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZXN => new V4d(1, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZXX => new V4d(1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZXY => new V4d(1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZXZ => new V4d(1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZYO => new V4d(1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZYI => new V4d(1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZYN => new V4d(1, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZYX => new V4d(1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZYY => new V4d(1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZYZ => new V4d(1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZZO => new V4d(1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZZI => new V4d(1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZZN => new V4d(1, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZZX => new V4d(1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZZY => new V4d(1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZZZ => new V4d(1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOOX => new V4d(-1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOOY => new V4d(-1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOOZ => new V4d(-1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOPX => new V4d(-1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOPY => new V4d(-1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOPZ => new V4d(-1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NONX => new V4d(-1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NONY => new V4d(-1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NONZ => new V4d(-1, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXO => new V4d(-1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXP => new V4d(-1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXN => new V4d(-1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXX => new V4d(-1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXY => new V4d(-1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXZ => new V4d(-1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYO => new V4d(-1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYP => new V4d(-1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYN => new V4d(-1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYX => new V4d(-1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYY => new V4d(-1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYZ => new V4d(-1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOZO => new V4d(-1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOZP => new V4d(-1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOZN => new V4d(-1, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOZX => new V4d(-1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOZY => new V4d(-1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOZZ => new V4d(-1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPOX => new V4d(-1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPOY => new V4d(-1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPOZ => new V4d(-1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPPX => new V4d(-1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPPY => new V4d(-1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPPZ => new V4d(-1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPNX => new V4d(-1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPNY => new V4d(-1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPNZ => new V4d(-1, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXO => new V4d(-1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXP => new V4d(-1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXN => new V4d(-1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXX => new V4d(-1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXY => new V4d(-1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXZ => new V4d(-1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYO => new V4d(-1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYP => new V4d(-1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYN => new V4d(-1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYX => new V4d(-1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYY => new V4d(-1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYZ => new V4d(-1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPZO => new V4d(-1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPZP => new V4d(-1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPZN => new V4d(-1, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPZX => new V4d(-1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPZY => new V4d(-1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPZZ => new V4d(-1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNOX => new V4d(-1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNOY => new V4d(-1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNOZ => new V4d(-1, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNPX => new V4d(-1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNPY => new V4d(-1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNPZ => new V4d(-1, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNNX => new V4d(-1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNNY => new V4d(-1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNNZ => new V4d(-1, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXO => new V4d(-1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXP => new V4d(-1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXN => new V4d(-1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXX => new V4d(-1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXY => new V4d(-1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXZ => new V4d(-1, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYO => new V4d(-1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYP => new V4d(-1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYN => new V4d(-1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYX => new V4d(-1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYY => new V4d(-1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYZ => new V4d(-1, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNZO => new V4d(-1, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNZP => new V4d(-1, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNZN => new V4d(-1, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNZX => new V4d(-1, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNZY => new V4d(-1, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNZZ => new V4d(-1, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXOO => new V4d(-1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXOP => new V4d(-1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXON => new V4d(-1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXOX => new V4d(-1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXOY => new V4d(-1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXOZ => new V4d(-1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPO => new V4d(-1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPP => new V4d(-1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPN => new V4d(-1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPX => new V4d(-1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPY => new V4d(-1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPZ => new V4d(-1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNO => new V4d(-1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNP => new V4d(-1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNN => new V4d(-1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNX => new V4d(-1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNY => new V4d(-1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNZ => new V4d(-1, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXO => new V4d(-1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXP => new V4d(-1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXN => new V4d(-1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXX => new V4d(-1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXY => new V4d(-1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXZ => new V4d(-1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYO => new V4d(-1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYP => new V4d(-1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYN => new V4d(-1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYX => new V4d(-1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYY => new V4d(-1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYZ => new V4d(-1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXZO => new V4d(-1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXZP => new V4d(-1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXZN => new V4d(-1, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXZX => new V4d(-1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXZY => new V4d(-1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXZZ => new V4d(-1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYOO => new V4d(-1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYOP => new V4d(-1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYON => new V4d(-1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYOX => new V4d(-1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYOY => new V4d(-1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYOZ => new V4d(-1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPO => new V4d(-1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPP => new V4d(-1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPN => new V4d(-1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPX => new V4d(-1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPY => new V4d(-1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPZ => new V4d(-1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNO => new V4d(-1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNP => new V4d(-1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNN => new V4d(-1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNX => new V4d(-1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNY => new V4d(-1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNZ => new V4d(-1, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXO => new V4d(-1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXP => new V4d(-1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXN => new V4d(-1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXX => new V4d(-1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXY => new V4d(-1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXZ => new V4d(-1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYO => new V4d(-1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYP => new V4d(-1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYN => new V4d(-1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYX => new V4d(-1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYY => new V4d(-1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYZ => new V4d(-1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYZO => new V4d(-1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYZP => new V4d(-1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYZN => new V4d(-1, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYZX => new V4d(-1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYZY => new V4d(-1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYZZ => new V4d(-1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZOO => new V4d(-1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZOP => new V4d(-1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZON => new V4d(-1, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZOX => new V4d(-1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZOY => new V4d(-1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZOZ => new V4d(-1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZPO => new V4d(-1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZPP => new V4d(-1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZPN => new V4d(-1, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZPX => new V4d(-1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZPY => new V4d(-1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZPZ => new V4d(-1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZNO => new V4d(-1, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZNP => new V4d(-1, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZNN => new V4d(-1, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZNX => new V4d(-1, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZNY => new V4d(-1, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZNZ => new V4d(-1, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZXO => new V4d(-1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZXP => new V4d(-1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZXN => new V4d(-1, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZXX => new V4d(-1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZXY => new V4d(-1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZXZ => new V4d(-1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZYO => new V4d(-1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZYP => new V4d(-1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZYN => new V4d(-1, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZYX => new V4d(-1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZYY => new V4d(-1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZYZ => new V4d(-1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZZO => new V4d(-1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZZP => new V4d(-1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZZN => new V4d(-1, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZZX => new V4d(-1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZZY => new V4d(-1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZZZ => new V4d(-1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOOO => new V4d(X, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOOI => new V4d(X, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOON => new V4d(X, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOOX => new V4d(X, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOOY => new V4d(X, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOOZ => new V4d(X, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOIO => new V4d(X, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOII => new V4d(X, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOPN => new V4d(X, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOIX => new V4d(X, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOIY => new V4d(X, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOIZ => new V4d(X, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONO => new V4d(X, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONP => new V4d(X, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONN => new V4d(X, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONX => new V4d(X, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONY => new V4d(X, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONZ => new V4d(X, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXO => new V4d(X, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXI => new V4d(X, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXN => new V4d(X, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXX => new V4d(X, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXY => new V4d(X, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXZ => new V4d(X, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYO => new V4d(X, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYI => new V4d(X, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYN => new V4d(X, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYX => new V4d(X, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYY => new V4d(X, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYZ => new V4d(X, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOZO => new V4d(X, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOZI => new V4d(X, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOZN => new V4d(X, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOZX => new V4d(X, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOZY => new V4d(X, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOZZ => new V4d(X, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIOO => new V4d(X, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIOI => new V4d(X, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPON => new V4d(X, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIOX => new V4d(X, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIOY => new V4d(X, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIOZ => new V4d(X, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIIO => new V4d(X, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIII => new V4d(X, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPPN => new V4d(X, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIIX => new V4d(X, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIIY => new V4d(X, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIIZ => new V4d(X, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNO => new V4d(X, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNP => new V4d(X, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNN => new V4d(X, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNX => new V4d(X, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNY => new V4d(X, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNZ => new V4d(X, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIXO => new V4d(X, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIXI => new V4d(X, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPXN => new V4d(X, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIXX => new V4d(X, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIXY => new V4d(X, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIXZ => new V4d(X, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIYO => new V4d(X, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIYI => new V4d(X, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPYN => new V4d(X, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIYX => new V4d(X, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIYY => new V4d(X, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIYZ => new V4d(X, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIZO => new V4d(X, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIZI => new V4d(X, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPZN => new V4d(X, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIZX => new V4d(X, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIZY => new V4d(X, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIZZ => new V4d(X, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNOO => new V4d(X, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNOP => new V4d(X, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNON => new V4d(X, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNOX => new V4d(X, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNOY => new V4d(X, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNOZ => new V4d(X, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPO => new V4d(X, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPP => new V4d(X, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPN => new V4d(X, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPX => new V4d(X, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPY => new V4d(X, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPZ => new V4d(X, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNO => new V4d(X, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNP => new V4d(X, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNN => new V4d(X, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNX => new V4d(X, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNY => new V4d(X, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNZ => new V4d(X, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXO => new V4d(X, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXP => new V4d(X, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXN => new V4d(X, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXX => new V4d(X, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXY => new V4d(X, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXZ => new V4d(X, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYO => new V4d(X, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYP => new V4d(X, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYN => new V4d(X, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYX => new V4d(X, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYY => new V4d(X, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYZ => new V4d(X, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNZO => new V4d(X, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNZP => new V4d(X, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNZN => new V4d(X, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNZX => new V4d(X, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNZY => new V4d(X, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNZZ => new V4d(X, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXOO => new V4d(X, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXOI => new V4d(X, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXON => new V4d(X, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXOX => new V4d(X, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXOY => new V4d(X, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXOZ => new V4d(X, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXIO => new V4d(X, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXII => new V4d(X, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXPN => new V4d(X, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXIX => new V4d(X, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXIY => new V4d(X, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXIZ => new V4d(X, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNO => new V4d(X, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNP => new V4d(X, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNN => new V4d(X, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNX => new V4d(X, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNY => new V4d(X, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNZ => new V4d(X, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXO => new V4d(X, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXI => new V4d(X, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXN => new V4d(X, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXX => new V4d(X, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXY => new V4d(X, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXZ => new V4d(X, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYO => new V4d(X, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYI => new V4d(X, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYN => new V4d(X, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYX => new V4d(X, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYY => new V4d(X, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYZ => new V4d(X, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXZO => new V4d(X, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXZI => new V4d(X, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXZN => new V4d(X, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXZX => new V4d(X, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXZY => new V4d(X, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXZZ => new V4d(X, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYOO => new V4d(X, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYOI => new V4d(X, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYON => new V4d(X, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYOX => new V4d(X, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYOY => new V4d(X, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYOZ => new V4d(X, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYIO => new V4d(X, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYII => new V4d(X, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYPN => new V4d(X, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYIX => new V4d(X, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYIY => new V4d(X, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYIZ => new V4d(X, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNO => new V4d(X, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNP => new V4d(X, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNN => new V4d(X, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNX => new V4d(X, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNY => new V4d(X, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNZ => new V4d(X, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXO => new V4d(X, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXI => new V4d(X, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXN => new V4d(X, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXX => new V4d(X, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXY => new V4d(X, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXZ => new V4d(X, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYO => new V4d(X, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYI => new V4d(X, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYN => new V4d(X, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYX => new V4d(X, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYY => new V4d(X, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYZ => new V4d(X, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYZO => new V4d(X, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYZI => new V4d(X, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYZN => new V4d(X, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYZX => new V4d(X, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYZY => new V4d(X, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYZZ => new V4d(X, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZOO => new V4d(X, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZOI => new V4d(X, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZON => new V4d(X, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZOX => new V4d(X, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZOY => new V4d(X, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZOZ => new V4d(X, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZIO => new V4d(X, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZII => new V4d(X, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZPN => new V4d(X, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZIX => new V4d(X, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZIY => new V4d(X, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZIZ => new V4d(X, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZNO => new V4d(X, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZNP => new V4d(X, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZNN => new V4d(X, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZNX => new V4d(X, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZNY => new V4d(X, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZNZ => new V4d(X, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZXO => new V4d(X, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZXI => new V4d(X, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZXN => new V4d(X, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZXX => new V4d(X, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZXY => new V4d(X, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZXZ => new V4d(X, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZYO => new V4d(X, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZYI => new V4d(X, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZYN => new V4d(X, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZYX => new V4d(X, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZYY => new V4d(X, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZYZ => new V4d(X, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZZO => new V4d(X, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZZI => new V4d(X, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZZN => new V4d(X, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZZX => new V4d(X, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZZY => new V4d(X, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZZZ => new V4d(X, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOOO => new V4d(Y, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOOI => new V4d(Y, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOON => new V4d(Y, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOOX => new V4d(Y, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOOY => new V4d(Y, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOOZ => new V4d(Y, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOIO => new V4d(Y, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOII => new V4d(Y, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOPN => new V4d(Y, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOIX => new V4d(Y, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOIY => new V4d(Y, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOIZ => new V4d(Y, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONO => new V4d(Y, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONP => new V4d(Y, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONN => new V4d(Y, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONX => new V4d(Y, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONY => new V4d(Y, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONZ => new V4d(Y, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXO => new V4d(Y, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXI => new V4d(Y, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXN => new V4d(Y, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXX => new V4d(Y, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXY => new V4d(Y, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXZ => new V4d(Y, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYO => new V4d(Y, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYI => new V4d(Y, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYN => new V4d(Y, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYX => new V4d(Y, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYY => new V4d(Y, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYZ => new V4d(Y, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOZO => new V4d(Y, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOZI => new V4d(Y, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOZN => new V4d(Y, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOZX => new V4d(Y, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOZY => new V4d(Y, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOZZ => new V4d(Y, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIOO => new V4d(Y, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIOI => new V4d(Y, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPON => new V4d(Y, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIOX => new V4d(Y, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIOY => new V4d(Y, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIOZ => new V4d(Y, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIIO => new V4d(Y, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIII => new V4d(Y, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPPN => new V4d(Y, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIIX => new V4d(Y, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIIY => new V4d(Y, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIIZ => new V4d(Y, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNO => new V4d(Y, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNP => new V4d(Y, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNN => new V4d(Y, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNX => new V4d(Y, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNY => new V4d(Y, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNZ => new V4d(Y, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIXO => new V4d(Y, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIXI => new V4d(Y, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPXN => new V4d(Y, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIXX => new V4d(Y, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIXY => new V4d(Y, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIXZ => new V4d(Y, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIYO => new V4d(Y, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIYI => new V4d(Y, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPYN => new V4d(Y, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIYX => new V4d(Y, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIYY => new V4d(Y, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIYZ => new V4d(Y, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIZO => new V4d(Y, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIZI => new V4d(Y, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPZN => new V4d(Y, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIZX => new V4d(Y, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIZY => new V4d(Y, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIZZ => new V4d(Y, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNOO => new V4d(Y, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNOP => new V4d(Y, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNON => new V4d(Y, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNOX => new V4d(Y, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNOY => new V4d(Y, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNOZ => new V4d(Y, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPO => new V4d(Y, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPP => new V4d(Y, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPN => new V4d(Y, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPX => new V4d(Y, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPY => new V4d(Y, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPZ => new V4d(Y, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNO => new V4d(Y, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNP => new V4d(Y, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNN => new V4d(Y, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNX => new V4d(Y, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNY => new V4d(Y, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNZ => new V4d(Y, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXO => new V4d(Y, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXP => new V4d(Y, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXN => new V4d(Y, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXX => new V4d(Y, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXY => new V4d(Y, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXZ => new V4d(Y, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYO => new V4d(Y, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYP => new V4d(Y, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYN => new V4d(Y, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYX => new V4d(Y, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYY => new V4d(Y, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYZ => new V4d(Y, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNZO => new V4d(Y, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNZP => new V4d(Y, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNZN => new V4d(Y, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNZX => new V4d(Y, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNZY => new V4d(Y, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNZZ => new V4d(Y, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXOO => new V4d(Y, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXOI => new V4d(Y, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXON => new V4d(Y, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXOX => new V4d(Y, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXOY => new V4d(Y, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXOZ => new V4d(Y, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXIO => new V4d(Y, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXII => new V4d(Y, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXPN => new V4d(Y, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXIX => new V4d(Y, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXIY => new V4d(Y, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXIZ => new V4d(Y, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNO => new V4d(Y, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNP => new V4d(Y, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNN => new V4d(Y, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNX => new V4d(Y, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNY => new V4d(Y, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNZ => new V4d(Y, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXO => new V4d(Y, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXI => new V4d(Y, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXN => new V4d(Y, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXX => new V4d(Y, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXY => new V4d(Y, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXZ => new V4d(Y, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYO => new V4d(Y, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYI => new V4d(Y, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYN => new V4d(Y, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYX => new V4d(Y, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYY => new V4d(Y, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYZ => new V4d(Y, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXZO => new V4d(Y, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXZI => new V4d(Y, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXZN => new V4d(Y, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXZX => new V4d(Y, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXZY => new V4d(Y, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXZZ => new V4d(Y, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYOO => new V4d(Y, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYOI => new V4d(Y, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYON => new V4d(Y, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYOX => new V4d(Y, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYOY => new V4d(Y, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYOZ => new V4d(Y, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYIO => new V4d(Y, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYII => new V4d(Y, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYPN => new V4d(Y, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYIX => new V4d(Y, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYIY => new V4d(Y, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYIZ => new V4d(Y, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNO => new V4d(Y, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNP => new V4d(Y, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNN => new V4d(Y, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNX => new V4d(Y, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNY => new V4d(Y, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNZ => new V4d(Y, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXO => new V4d(Y, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXI => new V4d(Y, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXN => new V4d(Y, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXX => new V4d(Y, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXY => new V4d(Y, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXZ => new V4d(Y, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYO => new V4d(Y, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYI => new V4d(Y, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYN => new V4d(Y, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYX => new V4d(Y, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYY => new V4d(Y, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYZ => new V4d(Y, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYZO => new V4d(Y, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYZI => new V4d(Y, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYZN => new V4d(Y, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYZX => new V4d(Y, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYZY => new V4d(Y, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYZZ => new V4d(Y, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZOO => new V4d(Y, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZOI => new V4d(Y, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZON => new V4d(Y, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZOX => new V4d(Y, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZOY => new V4d(Y, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZOZ => new V4d(Y, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZIO => new V4d(Y, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZII => new V4d(Y, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZPN => new V4d(Y, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZIX => new V4d(Y, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZIY => new V4d(Y, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZIZ => new V4d(Y, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZNO => new V4d(Y, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZNP => new V4d(Y, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZNN => new V4d(Y, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZNX => new V4d(Y, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZNY => new V4d(Y, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZNZ => new V4d(Y, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZXO => new V4d(Y, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZXI => new V4d(Y, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZXN => new V4d(Y, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZXX => new V4d(Y, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZXY => new V4d(Y, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZXZ => new V4d(Y, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZYO => new V4d(Y, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZYI => new V4d(Y, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZYN => new V4d(Y, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZYX => new V4d(Y, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZYY => new V4d(Y, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZYZ => new V4d(Y, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZZO => new V4d(Y, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZZI => new V4d(Y, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZZN => new V4d(Y, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZZX => new V4d(Y, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZZY => new V4d(Y, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZZZ => new V4d(Y, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOOO => new V4d(Z, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOOI => new V4d(Z, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOON => new V4d(Z, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOOX => new V4d(Z, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOOY => new V4d(Z, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOOZ => new V4d(Z, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOIO => new V4d(Z, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOII => new V4d(Z, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOPN => new V4d(Z, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOIX => new V4d(Z, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOIY => new V4d(Z, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOIZ => new V4d(Z, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZONO => new V4d(Z, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZONP => new V4d(Z, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZONN => new V4d(Z, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZONX => new V4d(Z, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZONY => new V4d(Z, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZONZ => new V4d(Z, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOXO => new V4d(Z, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOXI => new V4d(Z, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOXN => new V4d(Z, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOXX => new V4d(Z, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOXY => new V4d(Z, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOXZ => new V4d(Z, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOYO => new V4d(Z, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOYI => new V4d(Z, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOYN => new V4d(Z, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOYX => new V4d(Z, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOYY => new V4d(Z, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOYZ => new V4d(Z, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOZO => new V4d(Z, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOZI => new V4d(Z, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOZN => new V4d(Z, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOZX => new V4d(Z, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOZY => new V4d(Z, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOZZ => new V4d(Z, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIOO => new V4d(Z, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIOI => new V4d(Z, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPON => new V4d(Z, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIOX => new V4d(Z, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIOY => new V4d(Z, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIOZ => new V4d(Z, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIIO => new V4d(Z, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIII => new V4d(Z, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPPN => new V4d(Z, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIIX => new V4d(Z, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIIY => new V4d(Z, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIIZ => new V4d(Z, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPNO => new V4d(Z, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPNP => new V4d(Z, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPNN => new V4d(Z, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPNX => new V4d(Z, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPNY => new V4d(Z, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPNZ => new V4d(Z, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIXO => new V4d(Z, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIXI => new V4d(Z, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPXN => new V4d(Z, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIXX => new V4d(Z, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIXY => new V4d(Z, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIXZ => new V4d(Z, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIYO => new V4d(Z, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIYI => new V4d(Z, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPYN => new V4d(Z, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIYX => new V4d(Z, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIYY => new V4d(Z, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIYZ => new V4d(Z, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIZO => new V4d(Z, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIZI => new V4d(Z, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPZN => new V4d(Z, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIZX => new V4d(Z, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIZY => new V4d(Z, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIZZ => new V4d(Z, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNOO => new V4d(Z, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNOP => new V4d(Z, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNON => new V4d(Z, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNOX => new V4d(Z, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNOY => new V4d(Z, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNOZ => new V4d(Z, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNPO => new V4d(Z, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNPP => new V4d(Z, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNPN => new V4d(Z, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNPX => new V4d(Z, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNPY => new V4d(Z, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNPZ => new V4d(Z, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNNO => new V4d(Z, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNNP => new V4d(Z, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNNN => new V4d(Z, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNNX => new V4d(Z, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNNY => new V4d(Z, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNNZ => new V4d(Z, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNXO => new V4d(Z, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNXP => new V4d(Z, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNXN => new V4d(Z, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNXX => new V4d(Z, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNXY => new V4d(Z, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNXZ => new V4d(Z, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNYO => new V4d(Z, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNYP => new V4d(Z, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNYN => new V4d(Z, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNYX => new V4d(Z, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNYY => new V4d(Z, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNYZ => new V4d(Z, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNZO => new V4d(Z, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNZP => new V4d(Z, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNZN => new V4d(Z, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNZX => new V4d(Z, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNZY => new V4d(Z, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNZZ => new V4d(Z, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXOO => new V4d(Z, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXOI => new V4d(Z, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXON => new V4d(Z, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXOX => new V4d(Z, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXOY => new V4d(Z, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXOZ => new V4d(Z, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXIO => new V4d(Z, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXII => new V4d(Z, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXPN => new V4d(Z, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXIX => new V4d(Z, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXIY => new V4d(Z, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXIZ => new V4d(Z, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXNO => new V4d(Z, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXNP => new V4d(Z, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXNN => new V4d(Z, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXNX => new V4d(Z, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXNY => new V4d(Z, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXNZ => new V4d(Z, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXXO => new V4d(Z, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXXI => new V4d(Z, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXXN => new V4d(Z, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXXX => new V4d(Z, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXXY => new V4d(Z, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXXZ => new V4d(Z, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXYO => new V4d(Z, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXYI => new V4d(Z, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXYN => new V4d(Z, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXYX => new V4d(Z, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXYY => new V4d(Z, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXYZ => new V4d(Z, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXZO => new V4d(Z, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXZI => new V4d(Z, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXZN => new V4d(Z, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXZX => new V4d(Z, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXZY => new V4d(Z, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXZZ => new V4d(Z, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYOO => new V4d(Z, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYOI => new V4d(Z, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYON => new V4d(Z, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYOX => new V4d(Z, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYOY => new V4d(Z, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYOZ => new V4d(Z, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYIO => new V4d(Z, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYII => new V4d(Z, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYPN => new V4d(Z, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYIX => new V4d(Z, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYIY => new V4d(Z, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYIZ => new V4d(Z, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYNO => new V4d(Z, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYNP => new V4d(Z, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYNN => new V4d(Z, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYNX => new V4d(Z, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYNY => new V4d(Z, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYNZ => new V4d(Z, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYXO => new V4d(Z, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYXI => new V4d(Z, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYXN => new V4d(Z, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYXX => new V4d(Z, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYXY => new V4d(Z, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYXZ => new V4d(Z, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYYO => new V4d(Z, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYYI => new V4d(Z, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYYN => new V4d(Z, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYYX => new V4d(Z, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYYY => new V4d(Z, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYYZ => new V4d(Z, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYZO => new V4d(Z, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYZI => new V4d(Z, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYZN => new V4d(Z, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYZX => new V4d(Z, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYZY => new V4d(Z, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYZZ => new V4d(Z, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZOO => new V4d(Z, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZOI => new V4d(Z, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZON => new V4d(Z, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZOX => new V4d(Z, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZOY => new V4d(Z, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZOZ => new V4d(Z, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZIO => new V4d(Z, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZII => new V4d(Z, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZPN => new V4d(Z, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZIX => new V4d(Z, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZIY => new V4d(Z, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZIZ => new V4d(Z, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZNO => new V4d(Z, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZNP => new V4d(Z, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZNN => new V4d(Z, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZNX => new V4d(Z, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZNY => new V4d(Z, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZNZ => new V4d(Z, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZXO => new V4d(Z, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZXI => new V4d(Z, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZXN => new V4d(Z, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZXX => new V4d(Z, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZXY => new V4d(Z, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZXZ => new V4d(Z, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZYO => new V4d(Z, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZYI => new V4d(Z, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZYN => new V4d(Z, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZYX => new V4d(Z, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZYY => new V4d(Z, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZYZ => new V4d(Z, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZZO => new V4d(Z, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZZI => new V4d(Z, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZZN => new V4d(Z, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZZX => new V4d(Z, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZZY => new V4d(Z, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZZZ => new V4d(Z, Z, Z, Z); #endregion #region IVector Members /// /// By using long indices, the IVector<double> interface is /// accessed. /// public double this[long i] { readonly get { return (double)this[(int)i]; } set { this[(int)i] = (double)value; } } #endregion #region ISize3d Members public readonly V3d Size3d { get { return this; } } #endregion #region IVector public readonly long Dim { get { return 3; } } public readonly object GetValue(long index) { return (object)this[(int)index]; } public void SetValue(object value, long index) { this[(int)index] = (double)value; } #endregion } public class V3dEqualityComparer : IEqualityComparer { public static V3dEqualityComparer Default => new V3dEqualityComparer(); #region IEqualityComparer Members public bool Equals(V3d v0, V3d v1) { return v0 == v1; } public int GetHashCode(V3d v) { return v.GetHashCode(); } #endregion } public static partial class Fun { #region Min and Max /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Min(this V3d a, V3d b) { return new V3d(Min(a.X, b.X), Min(a.Y, b.Y), Min(a.Z, b.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Min(this V3d a, double b) { return new V3d(Min(a.X, b), Min(a.Y, b), Min(a.Z, b)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Min(this double a, V3d b) { return new V3d(Min(a, b.X), Min(a, b.Y), Min(a, b.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Max(this V3d a, V3d b) { return new V3d(Max(a.X, b.X), Max(a.Y, b.Y), Max(a.Z, b.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Max(this V3d a, double b) { return new V3d(Max(a.X, b), Max(a.Y, b), Max(a.Z, b)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Max(this double a, V3d b) { return new V3d(Max(a, b.X), Max(a, b.Y), Max(a, b.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Min(this V3d a, V3d b, V3d c) { return new V3d(Min(a.X, b.X, c.X), Min(a.Y, b.Y, c.Y), Min(a.Z, b.Z, c.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Max(this V3d a, V3d b, V3d c) { return new V3d(Max(a.X, b.X, c.X), Max(a.Y, b.Y, c.Y), Max(a.Z, b.Z, c.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Min(this V3d a, V3d b, V3d c, V3d d) { return new V3d(Min(a.X, b.X, c.X, d.X), Min(a.Y, b.Y, c.Y, d.Y), Min(a.Z, b.Z, c.Z, d.Z)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Max(this V3d a, V3d b, V3d c, V3d d) { return new V3d(Max(a.X, b.X, c.X, d.X), Max(a.Y, b.Y, c.Y, d.Y), Max(a.Z, b.Z, c.Z, d.Z)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Min(this V3d x, params V3d[] values) { return new V3d(Min(x.X, values.Map(a => a.X)), Min(x.Y, values.Map(a => a.Y)), Min(x.Z, values.Map(a => a.Z))); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Max(this V3d x, params V3d[] values) { return new V3d(Max(x.X, values.Map(a => a.X)), Max(x.Y, values.Map(a => a.Y)), Max(x.Z, values.Map(a => a.Z))); } #endregion #region Abs /// /// Applies Fun.Abs to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Abs(this V3d x) { return new V3d(Abs(x.X), Abs(x.Y), Abs(x.Z)); } #endregion #region Rounding /// /// Applies Fun.Floor to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Floor(this V3d x) { return new V3d(Floor(x.X), Floor(x.Y), Floor(x.Z)); } /// /// Applies Fun.Ceiling to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Ceiling(this V3d x) { return new V3d(Ceiling(x.X), Ceiling(x.Y), Ceiling(x.Z)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Round(this V3d x) { return new V3d(Round(x.X), Round(x.Y), Round(x.Z)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Round(this V3d x, MidpointRounding mode) { return new V3d(Round(x.X, mode), Round(x.Y, mode), Round(x.Z, mode)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Round(this V3d x, int digits) { return new V3d(Round(x.X, digits), Round(x.Y, digits), Round(x.Z, digits)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Round(this V3d x, int digits, MidpointRounding mode) { return new V3d(Round(x.X, digits, mode), Round(x.Y, digits, mode), Round(x.Z, digits, mode)); } /// /// Applies Fun.Truncate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Truncate(this V3d x) { return new V3d(Truncate(x.X), Truncate(x.Y), Truncate(x.Z)); } #endregion #region Frac /// /// Applies Fun.Frac to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Frac(this V3d x) { return new V3d(Frac(x.X), Frac(x.Y), Frac(x.Z)); } #endregion #region Clamping /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Clamp(this V3d x, V3d a, V3d b) { return new V3d(Clamp(x.X, a.X, b.X), Clamp(x.Y, a.Y, b.Y), Clamp(x.Z, a.Z, b.Z)); } /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Clamp(this V3d x, double a, double b) { return new V3d(Clamp(x.X, a, b), Clamp(x.Y, a, b), Clamp(x.Z, a, b)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d ClampWrap(this V3d x, V3d a, V3d b) { return new V3d(ClampWrap(x.X, a.X, b.X), ClampWrap(x.Y, a.Y, b.Y), ClampWrap(x.Z, a.Z, b.Z)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d ClampWrap(this V3d x, double a, double b) { return new V3d(ClampWrap(x.X, a, b), ClampWrap(x.Y, a, b), ClampWrap(x.Z, a, b)); } /// /// Applies Fun.Saturate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Saturate(this V3d x) { return new V3d(Saturate(x.X), Saturate(x.Y), Saturate(x.Z)); } #endregion #region MapToUnitInterval /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d MapToUnitInterval(this V3d t, V3d tMax, bool repeat, bool mirror) { return new V3d(MapToUnitInterval(t.X, tMax.X, repeat, mirror), MapToUnitInterval(t.Y, tMax.Y, repeat, mirror), MapToUnitInterval(t.Z, tMax.Z, repeat, mirror)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d MapToUnitInterval(this V3d t, V3d tMax, bool repeat) { return new V3d(MapToUnitInterval(t.X, tMax.X, repeat), MapToUnitInterval(t.Y, tMax.Y, repeat), MapToUnitInterval(t.Z, tMax.Z, repeat)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d MapToUnitInterval(this V3d t, V3d tMax) { return new V3d(MapToUnitInterval(t.X, tMax.X), MapToUnitInterval(t.Y, tMax.Y), MapToUnitInterval(t.Z, tMax.Z)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d MapToUnitInterval(this V3d t, V3d tMin, V3d tMax) { return new V3d(MapToUnitInterval(t.X, tMin.X, tMax.X), MapToUnitInterval(t.Y, tMin.Y, tMax.Y), MapToUnitInterval(t.Z, tMin.Z, tMax.Z)); } #endregion #region Sign /// /// Applies Fun.Sign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Sign(this V3d x) { return new V3i(Sign(x.X), Sign(x.Y), Sign(x.Z)); } /// /// Applies Fun.Signumi to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Signumi(this V3d x) { return new V3i(Signumi(x.X), Signumi(x.Y), Signumi(x.Z)); } /// /// Applies Fun.Signum to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Signum(this V3d x) { return new V3d(Signum(x.X), Signum(x.Y), Signum(x.Z)); } #endregion #region Multiply-Add /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d MultiplyAdd(V3d x, V3d y, V3d z) { return new V3d(MultiplyAdd(x.X, y.X, z.X), MultiplyAdd(x.Y, y.Y, z.Y), MultiplyAdd(x.Z, y.Z, z.Z)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d MultiplyAdd(V3d x, double y, V3d z) { return new V3d(MultiplyAdd(x.X, y, z.X), MultiplyAdd(x.Y, y, z.Y), MultiplyAdd(x.Z, y, z.Z)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d MultiplyAdd(double x, V3d y, V3d z) { return new V3d(MultiplyAdd(x, y.X, z.X), MultiplyAdd(x, y.Y, z.Y), MultiplyAdd(x, y.Z, z.Z)); } #endregion #region Copy sign /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d CopySign(V3d value, V3d sign) { return new V3d(CopySign(value.X, sign.X), CopySign(value.Y, sign.Y), CopySign(value.Z, sign.Z)); } /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d CopySign(double value, V3d sign) { return new V3d(CopySign(value, sign.X), CopySign(value, sign.Y), CopySign(value, sign.Z)); } /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d CopySign(V3d value, double sign) { return new V3d(CopySign(value.X, sign), CopySign(value.Y, sign), CopySign(value.Z, sign)); } #endregion #region Roots /// /// Applies Fun.Sqrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Sqrt(this V3d x) { return new V3d(Sqrt(x.X), Sqrt(x.Y), Sqrt(x.Z)); } /// /// Applies Fun.Cbrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Cbrt(this V3d x) { return new V3d(Cbrt(x.X), Cbrt(x.Y), Cbrt(x.Z)); } #endregion #region Square /// /// Applies Fun.Square to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Square(this V3d x) { return new V3d(Square(x.X), Square(x.Y), Square(x.Z)); } #endregion #region Power /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Pown(this V3d x, V3i y) { return new V3d(Pown(x.X, y.X), Pown(x.Y, y.Y), Pown(x.Z, y.Z)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Pown(this V3d x, int y) { return new V3d(Pown(x.X, y), Pown(x.Y, y), Pown(x.Z, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Pown(this double x, V3i y) { return new V3d(Pown(x, y.X), Pown(x, y.Y), Pown(x, y.Z)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Pow(this V3d x, V3d y) { return new V3d(Pow(x.X, y.X), Pow(x.Y, y.Y), Pow(x.Z, y.Z)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Pow(this V3d x, double y) { return new V3d(Pow(x.X, y), Pow(x.Y, y), Pow(x.Z, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Pow(this double x, V3d y) { return new V3d(Pow(x, y.X), Pow(x, y.Y), Pow(x, y.Z)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Power(this V3d x, V3d y) { return new V3d(Power(x.X, y.X), Power(x.Y, y.Y), Power(x.Z, y.Z)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Power(this V3d x, double y) { return new V3d(Power(x.X, y), Power(x.Y, y), Power(x.Z, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Power(this double x, V3d y) { return new V3d(Power(x, y.X), Power(x, y.Y), Power(x, y.Z)); } #endregion #region Exp and Log /// /// Applies Fun.Exp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Exp(this V3d x) { return new V3d(Exp(x.X), Exp(x.Y), Exp(x.Z)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log(this V3d x) { return new V3d(Log(x.X), Log(x.Y), Log(x.Z)); } /// /// Applies Fun.Log2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log2(this V3d x) { return new V3d(Log2(x.X), Log2(x.Y), Log2(x.Z)); } /// /// Applies Fun.Log2Int to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3i Log2Int(this V3d x) { return new V3i(Log2Int(x.X), Log2Int(x.Y), Log2Int(x.Z)); } /// /// Applies Fun.Log10 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log10(this V3d x) { return new V3d(Log10(x.X), Log10(x.Y), Log10(x.Z)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Log(this V3d x, double basis) { return new V3d(Log(x.X, basis), Log(x.Y, basis), Log(x.Z, basis)); } #endregion #region ModP /// /// Applies Fun.ModP to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d ModP(this V3d a, V3d b) { return new V3d(ModP(a.X, b.X), ModP(a.Y, b.Y), ModP(a.Z, b.Z)); } #endregion #region Power of Two /// /// Applies Fun.PowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d PowerOfTwo(this V3d x) { return new V3d(PowerOfTwo(x.X), PowerOfTwo(x.Y), PowerOfTwo(x.Z)); } #endregion #region Trigonometry /// /// Applies Fun.Sin to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Sin(this V3d x) { return new V3d(Sin(x.X), Sin(x.Y), Sin(x.Z)); } /// /// Applies Fun.Cos to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Cos(this V3d x) { return new V3d(Cos(x.X), Cos(x.Y), Cos(x.Z)); } /// /// Applies Fun.Tan to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Tan(this V3d x) { return new V3d(Tan(x.X), Tan(x.Y), Tan(x.Z)); } /// /// Applies Fun.Asin to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Asin(this V3d x) { return new V3d(Asin(x.X), Asin(x.Y), Asin(x.Z)); } /// /// Applies Fun.AsinClamped to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d AsinClamped(this V3d x) { return new V3d(AsinClamped(x.X), AsinClamped(x.Y), AsinClamped(x.Z)); } /// /// Applies Fun.Acos to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Acos(this V3d x) { return new V3d(Acos(x.X), Acos(x.Y), Acos(x.Z)); } /// /// Applies Fun.AcosClamped to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d AcosClamped(this V3d x) { return new V3d(AcosClamped(x.X), AcosClamped(x.Y), AcosClamped(x.Z)); } /// /// Applies Fun.Atan to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Atan(this V3d x) { return new V3d(Atan(x.X), Atan(x.Y), Atan(x.Z)); } /// /// Applies Fun.Atan2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Atan2(V3d y, V3d x) { return new V3d(Atan2(y.X, x.X), Atan2(y.Y, x.Y), Atan2(y.Z, x.Z)); } /// /// Applies Fun.FastAtan2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d FastAtan2(V3d y, V3d x) { return new V3d(FastAtan2(y.X, x.X), FastAtan2(y.Y, x.Y), FastAtan2(y.Z, x.Z)); } /// /// Applies Fun.Sinh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Sinh(this V3d x) { return new V3d(Sinh(x.X), Sinh(x.Y), Sinh(x.Z)); } /// /// Applies Fun.Cosh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Cosh(this V3d x) { return new V3d(Cosh(x.X), Cosh(x.Y), Cosh(x.Z)); } /// /// Applies Fun.Tanh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Tanh(this V3d x) { return new V3d(Tanh(x.X), Tanh(x.Y), Tanh(x.Z)); } /// /// Applies Fun.Asinh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Asinh(this V3d x) { return new V3d(Asinh(x.X), Asinh(x.Y), Asinh(x.Z)); } /// /// Applies Fun.Acosh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Acosh(this V3d x) { return new V3d(Acosh(x.X), Acosh(x.Y), Acosh(x.Z)); } /// /// Applies Fun.Atanh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Atanh(this V3d x) { return new V3d(Atanh(x.X), Atanh(x.Y), Atanh(x.Z)); } #endregion #region Step functions /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Step(this V3d x, V3d edge) { return new V3d(Step(x.X, edge.X), Step(x.Y, edge.Y), Step(x.Z, edge.Z)); } /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Step(this V3d x, double edge) { return new V3d(Step(x.X, edge), Step(x.Y, edge), Step(x.Z, edge)); } /// /// Applies Fun.Linearstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Linearstep(this V3d x, V3d edge0, V3d edge1) { return new V3d(Linearstep(x.X, edge0.X, edge1.X), Linearstep(x.Y, edge0.Y, edge1.Y), Linearstep(x.Z, edge0.Z, edge1.Z)); } /// /// Applies Fun.Linearstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Linearstep(this V3d x, double edge0, double edge1) { return new V3d(Linearstep(x.X, edge0, edge1), Linearstep(x.Y, edge0, edge1), Linearstep(x.Z, edge0, edge1)); } /// /// Applies Fun.Smoothstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Smoothstep(this V3d x, V3d edge0, V3d edge1) { return new V3d(Smoothstep(x.X, edge0.X, edge1.X), Smoothstep(x.Y, edge0.Y, edge1.Y), Smoothstep(x.Z, edge0.Z, edge1.Z)); } /// /// Applies Fun.Smoothstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Smoothstep(this V3d x, double edge0, double edge1) { return new V3d(Smoothstep(x.X, edge0, edge1), Smoothstep(x.Y, edge0, edge1), Smoothstep(x.Z, edge0, edge1)); } #endregion #region Interpolation /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Lerp(this double t, V3d a, V3d b) { return new V3d(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y), Lerp(t, a.Z, b.Z)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Lerp(this V3d t, V3d a, V3d b) { return new V3d(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y), Lerp(t.Z, a.Z, b.Z)); } /// /// Applies Fun.InvLerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d InvLerp(this V3d y, V3d a, V3d b) { return new V3d(InvLerp(y.X, a.X, b.X), InvLerp(y.Y, a.Y, b.Y), InvLerp(y.Z, a.Z, b.Z)); } #endregion #region Floating point bits /// /// Applies Fun.FloatToBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3l FloatToBits(this V3d x) { return new V3l(FloatToBits(x.X), FloatToBits(x.Y), FloatToBits(x.Z)); } #endregion #region ApproximateEquals /// /// Returns whether the given vectors are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V3d a, V3d b, double tolerance) { return ApproximateEquals(a.X, b.X, tolerance) && ApproximateEquals(a.Y, b.Y, tolerance) && ApproximateEquals(a.Z, b.Z, tolerance); } /// /// Returns whether the given vectors are equal within /// Constant{double}.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V3d a, V3d b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this V3d v, double epsilon) => Vec.AllTiny(v, epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than Constant<double>.PositiveTinyValue. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(V3d v) => v.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any component of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(V3d v) => v.IsNaN; /// /// Returns whether any component of the the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(V3d v) => v.IsInfinity; /// /// Returns whether any component of the the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(V3d v) => v.IsPositiveInfinity; /// /// Returns whether any component of the the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(V3d v) => v.IsNegativeInfinity; /// /// Returns whether all components of the the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(V3d v) => v.IsFinite; #endregion } public static partial class Conversion { #region Angles (Radians, Degrees, Gons) /// /// Converts the angles given in degrees to radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d RadiansFromDegrees(this V3d degrees) => new V3d( RadiansFromDegrees(degrees.X), RadiansFromDegrees(degrees.Y), RadiansFromDegrees(degrees.Z) ); /// /// Converts the angles given in gons to radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d RadiansFromGons(this V3d gons) => new V3d( RadiansFromGons(gons.X), RadiansFromGons(gons.Y), RadiansFromGons(gons.Z) ); /// /// Converts the angles given in radians to degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d DegreesFromRadians(this V3d radians) => new V3d( DegreesFromRadians(radians.X), DegreesFromRadians(radians.Y), DegreesFromRadians(radians.Z) ); /// /// Converts the angles given in gons to degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d DegreesFromGons(this V3d gons) => new V3d( DegreesFromGons(gons.X), DegreesFromGons(gons.Y), DegreesFromGons(gons.Z) ); /// /// Converts the angles given in radians to gons. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GonsFromRadians(this V3d radians) => new V3d( GonsFromRadians(radians.X), GonsFromRadians(radians.Y), GonsFromRadians(radians.Z) ); /// /// Converts the angles given in degrees to gons. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d GonsFromDegrees(this V3d degrees) => new V3d( GonsFromDegrees(degrees.X), GonsFromDegrees(degrees.Y), GonsFromDegrees(degrees.Z) ); #endregion } /// /// Contains static methods /// public static partial class Vec { #region Length /// /// Returns the squared length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LengthSquared(V3d v) => v.LengthSquared; /// /// Returns the length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Length(V3d v) => v.Length; #endregion #region Normalize /// /// Normalizes the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref V3d v) { var s = v.Length; if (s == 0) return; s = 1 / s; v.X *= s; v.Y *= s; v.Z *= s; } /// /// Returns a normalized copy of this vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Normalized(V3d v) => v.Normalized; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm1(V3d v) => v.Norm1; /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(V3d v) => v.Norm2; /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormMax(V3d v) => v.NormMax; /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormMin(V3d v) => v.NormMin; /// /// Gets the p-norm. This is calculated as the p-th root of (|x|^n + |y|^n + ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this V3d v, double p) { return ( Fun.Abs(v.X).Pow(p) + Fun.Abs(v.Y).Pow(p) + Fun.Abs(v.Z).Pow(p)).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the squared distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceSquared(this V3d a, V3d b) => Fun.Square(b.X - a.X) + Fun.Square(b.Y - a.Y) + Fun.Square(b.Z - a.Z); /// /// Returns the distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V3d a, V3d b) => Fun.Sqrt(DistanceSquared(a, b)); /// /// Returns the Manhatten (or 1-) distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance1(this V3d a, V3d b) => Fun.Abs(b.X - a.X) + Fun.Abs(b.Y - a.Y) + Fun.Abs(b.Z - a.Z); /// /// Returns the p-distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V3d a, V3d b, double p) => (Fun.Abs(b.X - a.X).Pow(p) + Fun.Abs(b.Y - a.Y).Pow(p) + Fun.Abs(b.Z - a.Z).Pow(p)).Pow(1 / p); /// /// Returns the maximal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceMax(this V3d a, V3d b) => Fun.Max(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y), Fun.Abs(b.Z - a.Z)); /// /// Returns the minimal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceMin(this V3d a, V3d b) => Fun.Min(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y), Fun.Abs(b.Z - a.Z)); /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V3d query, V3d p0, V3d p1) { var p0p1 = p1 - p0; var p0q = query - p0; var t = Dot(p0q, p0p1); if (t <= 0) { return p0q.Length; } var denom = p0p1.LengthSquared; if (t >= denom) { return Distance(query, p1); } t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V3d query, V3d p0, V3d p1) { var p0p1 = p1 - p0; var p0q = query - p0; var t = Dot(p0q, p0p1); var denom = p0p1.LengthSquared; t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V3d query, V3d p0, V3d p1, out double t) { var p0p1 = p1 - p0; var p0q = query - p0; t = Dot(p0q, p0p1); if (t <= 0) { t = 0; return p0q.Length; } var denom = p0p1.LengthSquared; if (t >= denom) { t = 1; return Distance(query, p1); } t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V3d query, V3d p0, V3d p1, out double t) { var p0p1 = p1 - p0; var p0q = query - p0; t = Dot(p0q, p0p1); var denom = p0p1.LengthSquared; t /= denom; return (p0q - t * p0p1).Length; } #endregion #region Operations /// /// Gets a copy of the given vector containing the reciprocal (1/x) of each element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Reciprocal(V3d v) => v.Reciprocal; /// /// Negates the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Negate(this ref V3d v) { v.X = -v.X; v.Y = -v.Y; v.Z = -v.Z; } /// /// Returns the outer product (tensor-product) of a * b^T as a 3x3 matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M33d Outer(this V3d a, V3d b) { return new M33d( a.X * b.X, a.X * b.Y, a.X * b.Z, a.Y * b.X, a.Y * b.Y, a.Y * b.Z, a.Z * b.X, a.Z * b.Y, a.Z * b.Z); } /// /// Returns the dot product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Dot(this V3d a, V3d b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z; } /// /// Returns the skew-symmetric "cross" matrix (A^T = -A) of the vector v. /// public static M33d CrossMatrix(this V3d v) { return new M33d(0, -v.Z, +v.Y, +v.Z, 0, -v.X, -v.Y, +v.X, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DirFlags DirFlags(this V3d v) { DirFlags flags = Aardbase.DirFlags.None; if (v.X > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveX; if (v.X < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeX; if (v.Y > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveY; if (v.Y < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeY; if (v.Z > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveZ; if (v.Z < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeZ; return flags; } /// /// Returns the reflection direction of the given vector v (pointing to the surface) for the given normal (should be normalized). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Reflect(this V3d v, V3d normal) { return v - 2 * v.Dot(normal) * normal; } /// /// Returns the refraction direction of the given vector v (pointing to the surface) for the given normal and ratio of refraction indices (n_out / n_in). /// Both the input vectors should be normalized. /// Returns a zero-vector in case of total internal reflection. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Refract(this V3d v, V3d normal, double eta) { var t = v.Dot(normal); var k = 1 - eta * eta * (1 - t * t); if (k < 0) { return V3d.Zero; } else { return eta * v - (eta * t + Fun.Sqrt(k)) * normal; } } /// /// Returns the cross product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d Cross(this V3d a, V3d b) { return new V3d( a.Y * b.Z - a.Z * b.Y, a.Z * b.X - a.X * b.Z, a.X * b.Y - a.Y * b.X ); } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V3d a, V3d b) { return (a.X < b.X && a.Y < b.Y && a.Z < b.Z); } /// /// Returns whether ALL elements of v are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V3d v, double s) { return (v.X < s && v.Y < s && v.Z < s); } /// /// Returns whether a is Smaller ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(double s, V3d v) { return (s < v.X && s < v.Y && s < v.Z); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V3d a, V3d b) { return (a.X < b.X || a.Y < b.Y || a.Z < b.Z); } /// /// Returns whether AT LEAST ONE element of v is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V3d v, double s) { return (v.X < s || v.Y < s || v.Z < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(double s, V3d v) { return (s < v.X || s < v.Y || s < v.Z); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V3d a, V3d b) { return (a.X > b.X && a.Y > b.Y && a.Z > b.Z); } /// /// Returns whether ALL elements of v are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V3d v, double s) { return (v.X > s && v.Y > s && v.Z > s); } /// /// Returns whether a is Greater ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(double s, V3d v) { return (s > v.X && s > v.Y && s > v.Z); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V3d a, V3d b) { return (a.X > b.X || a.Y > b.Y || a.Z > b.Z); } /// /// Returns whether AT LEAST ONE element of v is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V3d v, double s) { return (v.X > s || v.Y > s || v.Z > s); } /// /// Returns whether a is Greater AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(double s, V3d v) { return (s > v.X || s > v.Y || s > v.Z); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V3d a, V3d b) { return (a.X <= b.X && a.Y <= b.Y && a.Z <= b.Z); } /// /// Returns whether ALL elements of v are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V3d v, double s) { return (v.X <= s && v.Y <= s && v.Z <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(double s, V3d v) { return (s <= v.X && s <= v.Y && s <= v.Z); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V3d a, V3d b) { return (a.X <= b.X || a.Y <= b.Y || a.Z <= b.Z); } /// /// Returns whether AT LEAST ONE element of v is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V3d v, double s) { return (v.X <= s || v.Y <= s || v.Z <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(double s, V3d v) { return (s <= v.X || s <= v.Y || s <= v.Z); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V3d a, V3d b) { return (a.X >= b.X && a.Y >= b.Y && a.Z >= b.Z); } /// /// Returns whether ALL elements of v are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V3d v, double s) { return (v.X >= s && v.Y >= s && v.Z >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(double s, V3d v) { return (s >= v.X && s >= v.Y && s >= v.Z); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V3d a, V3d b) { return (a.X >= b.X || a.Y >= b.Y || a.Z >= b.Z); } /// /// Returns whether AT LEAST ONE element of v is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V3d v, double s) { return (v.X >= s || v.Y >= s || v.Z >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(double s, V3d v) { return (s >= v.X || s >= v.Y || s >= v.Z); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V3d a, V3d b) { return (a.X == b.X && a.Y == b.Y && a.Z == b.Z); } /// /// Returns whether ALL elements of v are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V3d v, double s) { return (v.X == s && v.Y == s && v.Z == s); } /// /// Returns whether a is Equal ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(double s, V3d v) { return (s == v.X && s == v.Y && s == v.Z); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V3d a, V3d b) { return (a.X == b.X || a.Y == b.Y || a.Z == b.Z); } /// /// Returns whether AT LEAST ONE element of v is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V3d v, double s) { return (v.X == s || v.Y == s || v.Z == s); } /// /// Returns whether a is Equal AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(double s, V3d v) { return (s == v.X || s == v.Y || s == v.Z); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V3d a, V3d b) { return (a.X != b.X && a.Y != b.Y && a.Z != b.Z); } /// /// Returns whether ALL elements of v are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V3d v, double s) { return (v.X != s && v.Y != s && v.Z != s); } /// /// Returns whether a is Different ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(double s, V3d v) { return (s != v.X && s != v.Y && s != v.Z); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V3d a, V3d b) { return (a.X != b.X || a.Y != b.Y || a.Z != b.Z); } /// /// Returns whether AT LEAST ONE element of v is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V3d v, double s) { return (v.X != s || v.Y != s || v.Z != s); } /// /// Returns whether a is Different AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(double s, V3d v) { return (s != v.X || s != v.Y || s != v.Z); } /// /// Compare x-coordinate before y-coordinate, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this V3d v0, V3d v1) { if (v0.X < v1.X) return -1; if (v0.X > v1.X) return +1; if (v0.Y < v1.Y) return -1; if (v0.Y > v1.Y) return +1; if (v0.Z < v1.Z) return -1; if (v0.Z > v1.Z) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MinElement(V3d v) => v.MinElement; /// /// Returns the maximum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MaxElement(V3d v) => v.MaxElement; #endregion #region Axis aligned normal /// /// Returns an arbitrary normal vector, which /// is also normal to either the x, y or z-axis. /// public static V3d AxisAlignedNormal(this V3d v) { V3d vector; double x = v.X.Abs(); double y = v.Y.Abs(); double z = v.Z.Abs(); if (x < y) { if (x < z) vector = V3d.XAxis; else vector = V3d.ZAxis; } else { if (y < z) vector = V3d.YAxis; else vector = V3d.ZAxis; } return v.Cross(vector).Normalized; } #endregion #region Angle between two vectors /// /// Computes the angle between two given vectors in radians. The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double AngleBetweenFast(this V3d x, V3d y) { return Fun.AcosClamped(x.Dot(y)); } /// /// Computes the angle between two given vectors in radians using a numerically stable algorithm. /// The input vectors have to be normalized. /// // https://scicomp.stackexchange.com/a/27769 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double AngleBetween(this V3d x, V3d y) { var a = x + y; var b = x - y; return 2 * Fun.Atan2(b.Length, a.Length); } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this V3d v, double epsilon) => v.X.IsTiny(epsilon) || v.Y.IsTiny(epsilon) || v.Z.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this V3d v, double epsilon) => v.X.IsTiny(epsilon) && v.Y.IsTiny(epsilon) && v.Z.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyFinite(V3d v) => v.AnyFinite; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllFinite(V3d v) => v.AllFinite; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(V3d v) => v.AnyNaN; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(V3d v) => v.AllNaN; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(V3d v) => v.AnyInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(V3d v) => v.AllInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(V3d v) => v.AnyPositiveInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(V3d v) => v.AllPositiveInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(V3d v) => v.AnyNegativeInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(V3d v) => v.AllNegativeInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(V3d v) => v.AnyTiny; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(V3d v) => v.AllTiny; #endregion #region Linear Combination [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d LinCom(V3d p0, V3d p1, ref Tup2 w) { return p0 * w.E0 + p1 * w.E1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d LinCom(V3d p0, V3d p1, V3d p2, ref Tup3 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d LinCom(V3d p0, V3d p1, V3d p2, V3d p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d LinCom(V3d p0, V3d p1, V3d p2, V3d p3, V3d p4, ref Tup5 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d LinCom(V3d p0, V3d p1, V3d p2, V3d p3, V3d p4, V3d p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d LinCom(V3d p0, V3d p1, V3d p2, V3d p3, V3d p4, V3d p5, V3d p6, ref Tup7 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5 + p6 * w.E6; } #endregion #region ArrayExtensions public static int IndexOfClosestPoint(this V3d[] pointArray, V3d point) { var bestDist = DistanceSquared(point, pointArray[0]); int bestIndex = 0; int count = pointArray.Length; for (int i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this V3d[] array, int start, int count, V3d point) { var bestDist = DistanceSquared(point, array[start]); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this T[] array, int start, int count, Func pointSelector, V3d point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint(this V3d[] pointArray, V3d point) { var bestDist = DistanceSquared(point, pointArray[0]); long bestIndex = 0; long count = pointArray.LongLength; for (long i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this V3d[] array, long start, long count, V3d point) { var bestDist = DistanceSquared(point, array[start]); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this T[] array, long start, long count, Func pointSelector, V3d point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static int IndexOfMinX(this V3d[] vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static long LongIndexOfMinX(this V3d[] vectorArray, long count = 0) { var minimum = vectorArray[0].X; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static int IndexOfMaxX(this V3d[] vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static long LongIndexOfMaxX(this V3d[] vectorArray, long count = 0) { var maximum = vectorArray[0].X; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static int IndexOfMinY(this V3d[] vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static long LongIndexOfMinY(this V3d[] vectorArray, long count = 0) { var minimum = vectorArray[0].Y; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static int IndexOfMaxY(this V3d[] vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static long LongIndexOfMaxY(this V3d[] vectorArray, long count = 0) { var maximum = vectorArray[0].Y; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static int IndexOfMinZ(this V3d[] vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static long LongIndexOfMinZ(this V3d[] vectorArray, long count = 0) { var minimum = vectorArray[0].Z; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static int IndexOfMaxZ(this V3d[] vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static long LongIndexOfMaxZ(this V3d[] vectorArray, long count = 0) { var maximum = vectorArray[0].Z; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the list. /// public static int IndexOfMinX(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the list. /// public static int IndexOfMaxX(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the list. /// public static int IndexOfMinY(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the list. /// public static int IndexOfMaxY(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the list. /// public static int IndexOfMinZ(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the list. /// public static int IndexOfMaxZ(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the array of the index-th coordinate of each vector. /// public static double[] CopyCoord(this V3d[] self, int index) { switch (index) { case 0: return self.Map(v => v.X); case 1: return self.Map(v => v.Y); case 2: return self.Map(v => v.Z); default: throw new IndexOutOfRangeException(); } } public static V3d WeightedSum( this V3d[] vectorArray, double[] weightArray) { var r = V3d.Zero; var count = vectorArray.LongLength; for (long i = 0; i < count; i++) r += vectorArray[i] * weightArray[i]; return r; } #endregion } public static class IRandomUniformV3dExtensions { #region IRandomUniform extensions for V3d /// /// Uses UniformDouble() to generate the elements of a V3d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3d(this IRandomUniform rnd) { return new V3d(rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble()); } /// /// Uses UniformDouble() to generate the elements of a V3d /// vector within the given Box3d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3d(this IRandomUniform rnd, Box3d box) { return new V3d(box.Min.X + rnd.UniformDouble() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformDouble() * (box.Max.Y - box.Min.Y), box.Min.Z + rnd.UniformDouble() * (box.Max.Z - box.Min.Z)); } /// /// Uses UniformDoubleClosed() to generate the elements of a V3d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3dClosed(this IRandomUniform rnd) { return new V3d(rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed()); } /// /// Uses UniformDoubleClosed() to generate the elements of a V3d /// vector within the given Box3d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3dClosed(this IRandomUniform rnd, Box3d box) { return new V3d(box.Min.X + rnd.UniformDoubleClosed() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformDoubleClosed() * (box.Max.Y - box.Min.Y), box.Min.Z + rnd.UniformDoubleClosed() * (box.Max.Z - box.Min.Z)); } /// /// Uses UniformDoubleOpen() to generate the elements of a V3d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3dOpen(this IRandomUniform rnd) { return new V3d(rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen()); } /// /// Uses UniformDoubleOpen() to generate the elements of a V3d /// vector within the given Box3d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3dOpen(this IRandomUniform rnd, Box3d box) { return new V3d(box.Min.X + rnd.UniformDoubleOpen() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformDoubleOpen() * (box.Max.Y - box.Min.Y), box.Min.Z + rnd.UniformDoubleOpen() * (box.Max.Z - box.Min.Z)); } /// /// Uses UniformDoubleFull() to generate the elements of a V3d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3dFull(this IRandomUniform rnd) { return new V3d(rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull()); } /// /// Uses UniformDoubleFull() to generate the elements of a V3d /// vector within the given Box3d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3dFull(this IRandomUniform rnd, Box3d box) { return new V3d(box.Min.X + rnd.UniformDoubleFull() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformDoubleFull() * (box.Max.Y - box.Min.Y), box.Min.Z + rnd.UniformDoubleFull() * (box.Max.Z - box.Min.Z)); } /// /// Uses UniformDoubleFullClosed() to generate the elements of a V3d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3dFullClosed(this IRandomUniform rnd) { return new V3d(rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed()); } /// /// Uses UniformDoubleFullClosed() to generate the elements of a V3d /// vector within the given Box3d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3dFullClosed(this IRandomUniform rnd, Box3d box) { return new V3d(box.Min.X + rnd.UniformDoubleFullClosed() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformDoubleFullClosed() * (box.Max.Y - box.Min.Y), box.Min.Z + rnd.UniformDoubleFullClosed() * (box.Max.Z - box.Min.Z)); } /// /// Uses UniformDoubleFullOpen() to generate the elements of a V3d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3dFullOpen(this IRandomUniform rnd) { return new V3d(rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen()); } /// /// Uses UniformDoubleFullOpen() to generate the elements of a V3d /// vector within the given Box3d. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3dFullOpen(this IRandomUniform rnd, Box3d box) { return new V3d(box.Min.X + rnd.UniformDoubleFullOpen() * (box.Max.X - box.Min.X), box.Min.Y + rnd.UniformDoubleFullOpen() * (box.Max.Y - box.Min.Y), box.Min.Z + rnd.UniformDoubleFullOpen() * (box.Max.Z - box.Min.Z)); } /// /// Returns a uniformly distributed vector (corresponds to a /// uniformly distributed point on the surface of the unit sphere). /// Note however, that the returned vector will never be equal to /// [0, 0, -1]. Uses UniformDouble() internally. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3dDirection(this IRandomUniform rnd) { double phi = rnd.UniformDouble() * Constant.PiTimesTwo; double z = 1 - rnd.UniformDouble() * 2; double s = Fun.Sqrt(1 - z * z); return new V3d(Fun.Cos(phi) * s, Fun.Sin(phi) * s, z); } /// /// Uniform vector in the closed unit sphere (i.e vectors to /// the surface of the sphere may be generated). Uses UniformV3dClosed() internally. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3dClosedSphere(this IRandomUniform rnd) { double r2; V3d p; V3d c_shift = -V3d.Half; do { p = (rnd.UniformV3dClosed() + c_shift) * 2; r2 = p.LengthSquared; } while (r2 >= 1); return p; } /// /// Uniform vector inside the open unit sphere (i.e. no vector /// ends on the surface of the sphere). Uses UniformV3dOpen() internally. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3dOpenSphere(this IRandomUniform rnd) { double r2; V3d p; V3d c_shift = -V3d.Half; do { p = (rnd.UniformV3dOpen() + c_shift) * 2; r2 = p.LengthSquared; } while (r2 >= 1); return p; } /// /// Returns a uniformly distributed vector (corresponds to a /// uniformly distributed point on the surface of the unit sphere). /// Note however, that the returned vector will never be equal to /// [0, 0, -1]. Uses UniformDoubleFull() internally. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3dFullDirection(this IRandomUniform rnd) { double phi = rnd.UniformDoubleFull() * Constant.PiTimesTwo; double z = 1 - rnd.UniformDoubleFull() * 2; double s = Fun.Sqrt(1 - z * z); return new V3d(Fun.Cos(phi) * s, Fun.Sin(phi) * s, z); } /// /// Uniform vector in the closed unit sphere (i.e vectors to /// the surface of the sphere may be generated). Uses UniformV3dClosed() internally. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3dFullClosedSphere(this IRandomUniform rnd) { double r2; V3d p; V3d c_shift = -V3d.Half; do { p = (rnd.UniformV3dClosed() + c_shift) * 2; r2 = p.LengthSquared; } while (r2 >= 1); return p; } /// /// Uniform vector inside the open unit sphere (i.e. no vector /// ends on the surface of the sphere). Uses UniformV3dOpen() internally. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V3d UniformV3dFullOpenSphere(this IRandomUniform rnd) { double r2; V3d p; V3d c_shift = -V3d.Half; do { p = (rnd.UniformV3dOpen() + c_shift) * 2; r2 = p.LengthSquared; } while (r2 >= 1); return p; } #endregion } #endregion #region V4i [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct V4i : IVector, ISize4i, IFormattable, IEquatable { [DataMember] public int X; [DataMember] public int Y; [DataMember] public int Z; [DataMember] public int W; #region Constructors /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(int x, int y, int z, int w) { X = x; Y = y; Z = z; W = w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(int v) { X = v; Y = v; Z = v; W = v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(int[] a) { X = a[0]; Y = a[1]; Z = a[2]; W = a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(int[] a, int start) { X = a[start + 0]; Y = a[start + 1]; Z = a[start + 2]; W = a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(int a, V3i b) { X = a; Y = b.X; Z = b.Y; W = b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V2i a, V2i b) { X = a.X; Y = a.Y; Z = b.X; W = b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V3i a, int b) { X = a.X; Y = a.Y; Z = a.Z; W = b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V2i a, int b, int c) { X = a.X; Y = a.Y; Z = b; W = c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(int a, V2i b, int c) { X = a; Y = b.X; Z = b.Y; W = c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(int a, int b, V2i c) { X = a; Y = b; Z = c.X; W = c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(uint x, uint y, uint z, uint w) { X = (int)x; Y = (int)y; Z = (int)z; W = (int)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(uint v) { X = (int)v; Y = (int)v; Z = (int)v; W = (int)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(uint[] a) { X = (int)a[0]; Y = (int)a[1]; Z = (int)a[2]; W = (int)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(uint[] a, int start) { X = (int)a[start + 0]; Y = (int)a[start + 1]; Z = (int)a[start + 2]; W = (int)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(uint a, V3ui b) { X = (int)a; Y = (int)b.X; Z = (int)b.Y; W = (int)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V2ui a, V2ui b) { X = (int)a.X; Y = (int)a.Y; Z = (int)b.X; W = (int)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V3ui a, uint b) { X = (int)a.X; Y = (int)a.Y; Z = (int)a.Z; W = (int)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V2ui a, uint b, uint c) { X = (int)a.X; Y = (int)a.Y; Z = (int)b; W = (int)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(uint a, V2ui b, uint c) { X = (int)a; Y = (int)b.X; Z = (int)b.Y; W = (int)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(uint a, uint b, V2ui c) { X = (int)a; Y = (int)b; Z = (int)c.X; W = (int)c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(long x, long y, long z, long w) { X = (int)x; Y = (int)y; Z = (int)z; W = (int)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(long v) { X = (int)v; Y = (int)v; Z = (int)v; W = (int)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(long[] a) { X = (int)a[0]; Y = (int)a[1]; Z = (int)a[2]; W = (int)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(long[] a, int start) { X = (int)a[start + 0]; Y = (int)a[start + 1]; Z = (int)a[start + 2]; W = (int)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(long a, V3l b) { X = (int)a; Y = (int)b.X; Z = (int)b.Y; W = (int)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V2l a, V2l b) { X = (int)a.X; Y = (int)a.Y; Z = (int)b.X; W = (int)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V3l a, long b) { X = (int)a.X; Y = (int)a.Y; Z = (int)a.Z; W = (int)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V2l a, long b, long c) { X = (int)a.X; Y = (int)a.Y; Z = (int)b; W = (int)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(long a, V2l b, long c) { X = (int)a; Y = (int)b.X; Z = (int)b.Y; W = (int)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(long a, long b, V2l c) { X = (int)a; Y = (int)b; Z = (int)c.X; W = (int)c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(float x, float y, float z, float w) { X = (int)x; Y = (int)y; Z = (int)z; W = (int)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(float v) { X = (int)v; Y = (int)v; Z = (int)v; W = (int)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(float[] a) { X = (int)a[0]; Y = (int)a[1]; Z = (int)a[2]; W = (int)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(float[] a, int start) { X = (int)a[start + 0]; Y = (int)a[start + 1]; Z = (int)a[start + 2]; W = (int)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(float a, V3f b) { X = (int)a; Y = (int)b.X; Z = (int)b.Y; W = (int)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V2f a, V2f b) { X = (int)a.X; Y = (int)a.Y; Z = (int)b.X; W = (int)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V3f a, float b) { X = (int)a.X; Y = (int)a.Y; Z = (int)a.Z; W = (int)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V2f a, float b, float c) { X = (int)a.X; Y = (int)a.Y; Z = (int)b; W = (int)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(float a, V2f b, float c) { X = (int)a; Y = (int)b.X; Z = (int)b.Y; W = (int)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(float a, float b, V2f c) { X = (int)a; Y = (int)b; Z = (int)c.X; W = (int)c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(double x, double y, double z, double w) { X = (int)x; Y = (int)y; Z = (int)z; W = (int)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(double v) { X = (int)v; Y = (int)v; Z = (int)v; W = (int)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(double[] a) { X = (int)a[0]; Y = (int)a[1]; Z = (int)a[2]; W = (int)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(double[] a, int start) { X = (int)a[start + 0]; Y = (int)a[start + 1]; Z = (int)a[start + 2]; W = (int)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(double a, V3d b) { X = (int)a; Y = (int)b.X; Z = (int)b.Y; W = (int)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V2d a, V2d b) { X = (int)a.X; Y = (int)a.Y; Z = (int)b.X; W = (int)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V3d a, double b) { X = (int)a.X; Y = (int)a.Y; Z = (int)a.Z; W = (int)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V2d a, double b, double c) { X = (int)a.X; Y = (int)a.Y; Z = (int)b; W = (int)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(double a, V2d b, double c) { X = (int)a; Y = (int)b.X; Z = (int)b.Y; W = (int)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(double a, double b, V2d c) { X = (int)a; Y = (int)b; Z = (int)c.X; W = (int)c.Y; } /// /// Creates a vector from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(Func index_fun) { X = index_fun(0); Y = index_fun(1); Z = index_fun(2); W = index_fun(3); } /// /// Creates a vector from a general vector implementing the IVector<int> interface. /// The caller has to verify that the dimension of is at least 4. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(IVector v) : this(v[0], v[1], v[2], v[3]) { } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V2i v) { X = v.X; Y = v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V2ui v) { X = (int)v.X; Y = (int)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V2l v) { X = (int)v.X; Y = (int)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V2f v) { X = (int)v.X; Y = (int)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V2d v) { X = (int)v.X; Y = (int)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V3i v) { X = v.X; Y = v.Y; Z = v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V3ui v) { X = (int)v.X; Y = (int)v.Y; Z = (int)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V3l v) { X = (int)v.X; Y = (int)v.Y; Z = (int)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V3f v) { X = (int)v.X; Y = (int)v.Y; Z = (int)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V3d v) { X = (int)v.X; Y = (int)v.Y; Z = (int)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V4i v) { X = v.X; Y = v.Y; Z = v.Z; W = v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V4ui v) { X = (int)v.X; Y = (int)v.Y; Z = (int)v.Z; W = (int)v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V4l v) { X = (int)v.X; Y = (int)v.Y; Z = (int)v.Z; W = (int)v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V4f v) { X = (int)v.X; Y = (int)v.Y; Z = (int)v.Z; W = (int)v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(V4d v) { X = (int)v.X; Y = (int)v.Y; Z = (int)v.Z; W = (int)v.W; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(C3b c) { X = (int)(c.R); Y = (int)(c.G); Z = (int)(c.B); W = (int)255; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(C3us c) { X = (int)(c.R); Y = (int)(c.G); Z = (int)(c.B); W = (int)65535; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(C4b c) { X = (int)(c.R); Y = (int)(c.G); Z = (int)(c.B); W = (int)(c.A); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4i(C4us c) { X = (int)(c.R); Y = (int)(c.G); Z = (int)(c.B); W = (int)(c.A); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(V2i v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(V2ui v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(V2l v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(V2f v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(V2d v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(V3i v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(V3ui v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(V3l v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(V3f v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(V3d v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(V4ui v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(V4l v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(V4f v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(V4d v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui ToV2ui() => (V2ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToV2l() => (V2l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f ToV2f() => (V2f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d ToV2d() => (V2d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int[](V4i v) => new int[] { v.X, v.Y, v.Z, v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(int[] v) => new V4i(v[0], v[1], v[2], v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](V4i v) => new uint[] { (uint)v.X, (uint)v.Y, (uint)v.Z, (uint)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(uint[] v) => new V4i((int)v[0], (int)v[1], (int)v[2], (int)v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long[](V4i v) => new long[] { (long)v.X, (long)v.Y, (long)v.Z, (long)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(long[] v) => new V4i((int)v[0], (int)v[1], (int)v[2], (int)v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](V4i v) => new float[] { (float)v.X, (float)v.Y, (float)v.Z, (float)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(float[] v) => new V4i((int)v[0], (int)v[1], (int)v[2], (int)v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](V4i v) => new double[] { (double)v.X, (double)v.Y, (double)v.Z, (double)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(double[] v) => new V4i((int)v[0], (int)v[1], (int)v[2], (int)v[3]); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(C3b v) => new V4i(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(C3us v) => new V4i(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(C4b v) => new V4i(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4i(C4us v) => new V4i(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i Copy(Func element_fun) => new V4i(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i Copy(Func element_index_fun) => new V4i(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(int[] array, int start) { array[start + 0] = X; array[start + 1] = Y; array[start + 2] = Z; array[start + 3] = W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui Copy(Func element_fun) => new V4ui(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui Copy(Func element_index_fun) => new V4ui(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(uint[] array, int start) { array[start + 0] = (uint)X; array[start + 1] = (uint)Y; array[start + 2] = (uint)Z; array[start + 3] = (uint)W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l Copy(Func element_fun) => new V4l(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l Copy(Func element_index_fun) => new V4l(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(long[] array, int start) { array[start + 0] = (long)X; array[start + 1] = (long)Y; array[start + 2] = (long)Z; array[start + 3] = (long)W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f Copy(Func element_fun) => new V4f(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f Copy(Func element_index_fun) => new V4f(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(float[] array, int start) { array[start + 0] = (float)X; array[start + 1] = (float)Y; array[start + 2] = (float)Z; array[start + 3] = (float)W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d Copy(Func element_fun) => new V4d(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d Copy(Func element_index_fun) => new V4d(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(double[] array, int start) { array[start + 0] = (double)X; array[start + 1] = (double)Y; array[start + 2] = (double)Z; array[start + 3] = (double)W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(X); array[start + 1] = element_fun(Y); array[start + 2] = element_fun(Z); array[start + 3] = element_fun(W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(X, 0); array[start + 1] = element_index_fun(Y, 1); array[start + 2] = element_index_fun(Z, 2); array[start + 3] = element_index_fun(W, 3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int[] ToArray() => new int[] { X, Y, Z, W }; #endregion #region Properties and Indexers /// /// Property for the field X. /// Useful when properties are required, but the field X is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public int P_X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value; } } /// /// Property for the field Y. /// Useful when properties are required, but the field Y is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public int P_Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Y = value; } } /// /// Property for the field Z. /// Useful when properties are required, but the field Z is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public int P_Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Z = value; } } /// /// Property for the field W. /// Useful when properties are required, but the field W is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public int P_W { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { W = value; } } /// /// Enumerates all elements of this vector. /// public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return X; yield return Y; yield return Z; yield return W; } } /// /// Gets or sets element with given index. /// public unsafe int this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (int* ptr = &X) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (int* ptr = &X) { ptr[index] = value; } } } /// /// Returns the index of the largest dimension of the vector. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X >= Y ? (X >= Z ? (X >= W ? 0 : 3) : (Z >= W ? 2 : 3)) : (Y >= Z ? (Y >= W ? 1 : 3) : (Z >= W ? 2 : 3)); } } /// /// Returns the index of the smallest dimension of the vector. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X <= Y ? (X <= Z ? (X <= W ? 0 : 3) : (Z <= W ? 2 : 3)) : (Y <= Z ? (Y <= W ? 1 : 3) : (Z <= W ? 2 : 3)); } } /// /// Returns the minimum element of the vector. /// public readonly int MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(X, Y, Z, W); } /// /// Returns the maximum element of the vector. /// public readonly int MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(X, Y, Z, W); } #endregion #region Constants /// /// Number of elements in this vector. /// public const int Dimension = 4; /// /// All elements zero. /// public static V4i Zero { get { return new V4i(0, 0, 0, 0); } } /// /// All elements one. /// public static V4i One { get { return new V4i(1, 1, 1, 1); } } /// /// All elements set to maximum possible value. /// public static V4i MaxValue { get { return new V4i(Constant.ParseableMaxValue, Constant.ParseableMaxValue, Constant.ParseableMaxValue, Constant.ParseableMaxValue); } } /// /// All elements set to minimum possible value. /// public static V4i MinValue { get { return new V4i(Constant.ParseableMinValue, Constant.ParseableMinValue, Constant.ParseableMinValue, Constant.ParseableMinValue); } } /// /// Normalized X-axis. /// public static V4i XAxis { get { return new V4i(1, 0, 0, 0); } } /// /// Normalized Y-axis. /// public static V4i YAxis { get { return new V4i(0, 1, 0, 0); } } /// /// Normalized Z-axis. /// public static V4i ZAxis { get { return new V4i(0, 0, 1, 0); } } /// /// Normalized W-axis. /// public static V4i WAxis { get { return new V4i(0, 0, 0, 1); } } /// /// An array of accessor functions for the coordinates of the vector. /// public static readonly Func[] SelectorArray = new Func[] { v => v.X, v => v.Y, v => v.Z, v => v.W }; /// /// Element getter function. /// public static readonly Func Getter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; case 3: return v.W; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref V4i v, int i, int s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; case 3: v.W = s; return; default: throw new IndexOutOfRangeException(); } }; /// /// Element getter function with long index. /// public static readonly Func LongGetter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; case 3: return v.W; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action with long index. /// public static readonly ActionRefValVal LongSetter = (ref V4i v, long i, int s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; case 3: v.W = s; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Static factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i FromV4ui(V4ui v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i FromV4l(V4l v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i FromV4f(V4f v) => new V4i(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i FromV4d(V4d v) => new V4i(v); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i FromC3b(C3b c) => new V4i(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i FromC3us(C3us c) => new V4i(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i FromC4b(C4b c) => new V4i(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i FromC4us(C4us c) => new V4i(c); #endregion #region Norms /// /// Returns the squared length of the vector. /// public readonly int LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X * X + Y * Y + Z * Z + W * W ; } } /// /// Returns the length of the vector. /// public readonly double Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z + W * W ); } } /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// public readonly int Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Abs(X) + Fun.Abs(Y) + Fun.Abs(Z) + Fun.Abs(W); } } /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z + W * W); } } /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// public readonly int NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z), Fun.Abs(W)); } } /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// public readonly int NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z), Fun.Abs(W)); } } /// /// Returns a normalized copy of this vector. /// public readonly V4d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Length; if (s == 0) return V4d.Zero; s = 1 / s; return new V4d(X * s, Y * s, Z * s, W * s); } } #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Abs(V4i v) => v.Abs(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i LinearInterp(float t, V4i a, V4i b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i LinearInterp(V4f t, V4i a, V4i b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i LinearInterp(double t, V4i a, V4i b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i LinearInterp(V4d t, V4i a, V4i b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Min(V4i v0, V4i v1) => Fun.Min(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Min(V4i v, int x) => Fun.Min(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Max(V4i v0, V4i v1) => Fun.Max(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Max(V4i v, int x) => Fun.Max(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Saturate(V4i v) => Fun.Saturate(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i DivideByInt(V4i v, int x) => v / x; #endregion #region Operations /// /// Sets the elements of a vector to the given int elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(int x, int y, int z, int w) { X = x; Y = y; Z = z; W = w; } /// /// Sets the elements of a vector to the given uint elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(uint x, uint y, uint z, uint w) { X = (int)x; Y = (int)y; Z = (int)z; W = (int)w; } /// /// Sets the elements of a vector to the given long elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(long x, long y, long z, long w) { X = (int)x; Y = (int)y; Z = (int)z; W = (int)w; } /// /// Sets the elements of a vector to the given float elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(float x, float y, float z, float w) { X = (int)x; Y = (int)y; Z = (int)z; W = (int)w; } /// /// Sets the elements of a vector to the given double elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(double x, double y, double z, double w) { X = (int)x; Y = (int)y; Z = (int)z; W = (int)w; } /// /// Returns a negated copy of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator -(V4i v) => new V4i(-v.X, -v.Y, -v.Z, -v.W); /// /// Returns the component-wise bitwise complement of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator ~(V4i v) => new V4i(~v.X, ~v.Y, ~v.Z, ~v.W); /// /// Returns the component-wise sum of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator +(V4i a, V4i b) => new V4i(a.X + b.X, a.Y + b.Y, a.Z + b.Z, a.W + b.W); /// /// Returns the component-wise sum of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator +(V4i v, int s) => new V4i(v.X + s, v.Y + s, v.Z + s, v.W + s); /// /// Returns the component-wise sum of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator +(int s, V4i v) => new V4i(s + v.X, s + v.Y, s + v.Z, s + v.W); /// /// Returns the component-wise difference of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator -(V4i a, V4i b) => new V4i(a.X - b.X, a.Y - b.Y, a.Z - b.Z, a.W - b.W); /// /// Returns the component-wise difference of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator -(V4i v, int s) => new V4i(v.X - s, v.Y - s, v.Z - s, v.W - s); /// /// Returns the component-wise difference of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator -(int s, V4i v) => new V4i(s - v.X, s - v.Y, s - v.Z, s - v.W); /// /// Returns the component-wise product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator *(V4i a, V4i b) => new V4i(a.X * b.X, a.Y * b.Y, a.Z * b.Z, a.W * b.W); /// /// Returns the component-wise product of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator *(V4i v, int s) => new V4i(v.X * s, v.Y * s, v.Z * s, v.W * s); /// /// Returns the component-wise product of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator *(int s, V4i v) => new V4i(s * v.X, s * v.Y, s * v.Z, s * v.W); /// /// Returns the component-wise fraction of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator /(V4i a, V4i b) => new V4i(a.X / b.X, a.Y / b.Y, a.Z / b.Z, a.W / b.W); /// /// Returns the component-wise fraction of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator /(V4i v, int s) => new V4i(v.X / s, v.Y / s, v.Z / s, v.W / s); /// /// Returns the component-wise fraction of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator /(int s, V4i v) => new V4i(s / v.X, s / v.Y, s / v.Z, s / v.W); /// /// Returns the component-wise remainder of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator %(V4i a, V4i b) => new V4i(a.X % b.X, a.Y % b.Y, a.Z % b.Z, a.W % b.W); /// /// Returns the component-wise remainder of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator %(V4i v, int s) => new V4i(v.X % s, v.Y % s, v.Z % s, v.W % s); /// /// Returns the component-wise remainder of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator %(int s, V4i v) => new V4i(s % v.X, s % v.Y, s % v.Z, s % v.W); /// /// Returns the component-wise bitwise and of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator &(V4i a, V4i b) => new V4i(a.X & b.X, a.Y & b.Y, a.Z & b.Z, a.W & b.W); /// /// Returns the component-wise bitwise and of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator &(V4i v, int s) => new V4i(v.X & s, v.Y & s, v.Z & s, v.W & s); /// /// Returns the component-wise bitwise and of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator &(int s, V4i v) => new V4i(s & v.X, s & v.Y, s & v.Z, s & v.W); /// /// Returns the component-wise bitwise or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator |(V4i a, V4i b) => new V4i(a.X | b.X, a.Y | b.Y, a.Z | b.Z, a.W | b.W); /// /// Returns the component-wise bitwise or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator |(V4i v, int s) => new V4i(v.X | s, v.Y | s, v.Z | s, v.W | s); /// /// Returns the component-wise bitwise or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator |(int s, V4i v) => new V4i(s | v.X, s | v.Y, s | v.Z, s | v.W); /// /// Returns the component-wise bitwise exclusive or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator ^(V4i a, V4i b) => new V4i(a.X ^ b.X, a.Y ^ b.Y, a.Z ^ b.Z, a.W ^ b.W); /// /// Returns the component-wise bitwise exclusive or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator ^(V4i v, int s) => new V4i(v.X ^ s, v.Y ^ s, v.Z ^ s, v.W ^ s); /// /// Returns the component-wise bitwise exclusive or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator ^(int s, V4i v) => new V4i(s ^ v.X, s ^ v.Y, s ^ v.Z, s ^ v.W); /// /// Returns the component-wise left bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator <<(V4i v, int s) => new V4i(v.X << s, v.Y << s, v.Z << s, v.W << s); /// /// Returns the component-wise right bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i operator >>(V4i v, int s) => new V4i(v.X >> s, v.Y >> s, v.Z >> s, v.W >> s); /// Attention: NEVER implement operators <, <=, >=, >, /// since these are not defined in a Vector space. /// Use AllSmaller() and similar comparators! #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V4i a, V4i b) { return a.X == b.X && a.Y == b.Y && a.Z == b.Z && a.W == b.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V4i v, int s) { return v.X == s && v.Y == s && v.Z == s && v.W == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(int s, V4i v) { return s == v.X && s == v.Y && s == v.Z && s == v.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V4i a, V4i b) { return a.X != b.X || a.Y != b.Y || a.Z != b.Z || a.W != b.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V4i v, int s) { return v.X != s || v.Y != s || v.Z != s || v.W != s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(int s, V4i v) { return s != v.X || s != v.Y || s != v.Z || s != v.W; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(V4i other) { return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && W.Equals(other.W); } #endregion #region Overrides public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + X.ToString(format, fp) + between + Y.ToString(format, fp) + between + Z.ToString(format, fp) + between + W.ToString(format, fp) + end; } public override readonly int GetHashCode() { return HashCode.GetCombined(X, Y, Z, W); } public override readonly bool Equals(object other) => (other is V4i o) ? Equals(o) : false; public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + X.ToString(null, CultureInfo.InvariantCulture) + ", " + Y.ToString(null, CultureInfo.InvariantCulture) + ", " + Z.ToString(null, CultureInfo.InvariantCulture) + ", " + W.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Parsing public static V4i Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new V4i( int.Parse(x[0], CultureInfo.InvariantCulture), int.Parse(x[1], CultureInfo.InvariantCulture), int.Parse(x[2], CultureInfo.InvariantCulture), int.Parse(x[3], CultureInfo.InvariantCulture) ); } public static V4i Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, V4i.Setter); } public static V4i Parse(Text t, int bracketLevel) { return t.NestedBracketSplit(bracketLevel, Text.Parse, V4i.Setter); } #endregion #region Swizzle Methods [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i OX => new V2i(0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i OY => new V2i(0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i OZ => new V2i(0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i OW => new V2i(0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i IX => new V2i(1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i IY => new V2i(1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i IZ => new V2i(1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i IW => new V2i(1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i NX => new V2i(-1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i NY => new V2i(-1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i NZ => new V2i(-1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i NW => new V2i(-1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i XO => new V2i(X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i XI => new V2i(X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i XN => new V2i(X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i XX => new V2i(X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i XY { readonly get => new V2i(X, Y); set { X = value.X; Y = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i XZ { readonly get => new V2i(X, Z); set { X = value.X; Z = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i XW { readonly get => new V2i(X, W); set { X = value.X; W = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i YO => new V2i(Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i YI => new V2i(Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i YN => new V2i(Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i YX { readonly get => new V2i(Y, X); set { Y = value.X; X = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i YY => new V2i(Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i YZ { readonly get => new V2i(Y, Z); set { Y = value.X; Z = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i YW { readonly get => new V2i(Y, W); set { Y = value.X; W = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i ZO => new V2i(Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i ZI => new V2i(Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i ZN => new V2i(Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i ZX { readonly get => new V2i(Z, X); set { Z = value.X; X = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i ZY { readonly get => new V2i(Z, Y); set { Z = value.X; Y = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i ZZ => new V2i(Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i ZW { readonly get => new V2i(Z, W); set { Z = value.X; W = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i WO => new V2i(W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i WI => new V2i(W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i WN => new V2i(W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i WX { readonly get => new V2i(W, X); set { W = value.X; X = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i WY { readonly get => new V2i(W, Y); set { W = value.X; Y = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2i WZ { readonly get => new V2i(W, Z); set { W = value.X; Z = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2i WW => new V2i(W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OOX => new V3i(0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OOY => new V3i(0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OOZ => new V3i(0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OOW => new V3i(0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OIX => new V3i(0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OIY => new V3i(0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OIZ => new V3i(0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OIW => new V3i(0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ONX => new V3i(0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ONY => new V3i(0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ONZ => new V3i(0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ONW => new V3i(0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXO => new V3i(0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXI => new V3i(0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXN => new V3i(0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXX => new V3i(0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXY => new V3i(0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXZ => new V3i(0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OXW => new V3i(0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYO => new V3i(0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYI => new V3i(0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYN => new V3i(0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYX => new V3i(0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYY => new V3i(0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYZ => new V3i(0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OYW => new V3i(0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OZO => new V3i(0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OZI => new V3i(0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OZN => new V3i(0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OZX => new V3i(0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OZY => new V3i(0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OZZ => new V3i(0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OZW => new V3i(0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OWO => new V3i(0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OWI => new V3i(0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OWN => new V3i(0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OWX => new V3i(0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OWY => new V3i(0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OWZ => new V3i(0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i OWW => new V3i(0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IOX => new V3i(1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IOY => new V3i(1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IOZ => new V3i(1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IOW => new V3i(1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IIX => new V3i(1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IIY => new V3i(1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IIZ => new V3i(1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IIW => new V3i(1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PNX => new V3i(1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PNY => new V3i(1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PNZ => new V3i(1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PNW => new V3i(1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IXO => new V3i(1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IXI => new V3i(1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PXN => new V3i(1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IXX => new V3i(1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IXY => new V3i(1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IXZ => new V3i(1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IXW => new V3i(1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IYO => new V3i(1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IYI => new V3i(1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PYN => new V3i(1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IYX => new V3i(1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IYY => new V3i(1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IYZ => new V3i(1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IYW => new V3i(1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IZO => new V3i(1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IZI => new V3i(1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PZN => new V3i(1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IZX => new V3i(1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IZY => new V3i(1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IZZ => new V3i(1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IZW => new V3i(1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IWO => new V3i(1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IWI => new V3i(1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i PWN => new V3i(1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IWX => new V3i(1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IWY => new V3i(1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IWZ => new V3i(1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i IWW => new V3i(1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NOX => new V3i(-1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NOY => new V3i(-1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NOZ => new V3i(-1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NOW => new V3i(-1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NPX => new V3i(-1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NPY => new V3i(-1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NPZ => new V3i(-1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NPW => new V3i(-1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NNX => new V3i(-1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NNY => new V3i(-1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NNZ => new V3i(-1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NNW => new V3i(-1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXO => new V3i(-1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXP => new V3i(-1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXN => new V3i(-1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXX => new V3i(-1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXY => new V3i(-1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXZ => new V3i(-1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NXW => new V3i(-1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYO => new V3i(-1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYP => new V3i(-1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYN => new V3i(-1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYX => new V3i(-1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYY => new V3i(-1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYZ => new V3i(-1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NYW => new V3i(-1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NZO => new V3i(-1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NZP => new V3i(-1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NZN => new V3i(-1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NZX => new V3i(-1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NZY => new V3i(-1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NZZ => new V3i(-1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NZW => new V3i(-1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NWO => new V3i(-1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NWP => new V3i(-1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NWN => new V3i(-1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NWX => new V3i(-1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NWY => new V3i(-1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NWZ => new V3i(-1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i NWW => new V3i(-1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XOO => new V3i(X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XOI => new V3i(X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XON => new V3i(X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XOX => new V3i(X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XOY => new V3i(X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XOZ => new V3i(X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XOW => new V3i(X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XIO => new V3i(X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XII => new V3i(X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XPN => new V3i(X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XIX => new V3i(X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XIY => new V3i(X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XIZ => new V3i(X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XIW => new V3i(X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNO => new V3i(X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNP => new V3i(X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNN => new V3i(X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNX => new V3i(X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNY => new V3i(X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNZ => new V3i(X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XNW => new V3i(X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXO => new V3i(X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXI => new V3i(X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXN => new V3i(X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXX => new V3i(X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXY => new V3i(X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXZ => new V3i(X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XXW => new V3i(X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XYO => new V3i(X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XYI => new V3i(X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XYN => new V3i(X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XYX => new V3i(X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XYY => new V3i(X, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i XYZ { readonly get => new V3i(X, Y, Z); set { X = value.X; Y = value.Y; Z = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i XYW { readonly get => new V3i(X, Y, W); set { X = value.X; Y = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XZO => new V3i(X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XZI => new V3i(X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XZN => new V3i(X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XZX => new V3i(X, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i XZY { readonly get => new V3i(X, Z, Y); set { X = value.X; Z = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XZZ => new V3i(X, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i XZW { readonly get => new V3i(X, Z, W); set { X = value.X; Z = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XWO => new V3i(X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XWI => new V3i(X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XWN => new V3i(X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XWX => new V3i(X, W, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i XWY { readonly get => new V3i(X, W, Y); set { X = value.X; W = value.Y; Y = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i XWZ { readonly get => new V3i(X, W, Z); set { X = value.X; W = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i XWW => new V3i(X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YOO => new V3i(Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YOI => new V3i(Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YON => new V3i(Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YOX => new V3i(Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YOY => new V3i(Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YOZ => new V3i(Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YOW => new V3i(Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YIO => new V3i(Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YII => new V3i(Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YPN => new V3i(Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YIX => new V3i(Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YIY => new V3i(Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YIZ => new V3i(Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YIW => new V3i(Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNO => new V3i(Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNP => new V3i(Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNN => new V3i(Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNX => new V3i(Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNY => new V3i(Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNZ => new V3i(Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YNW => new V3i(Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YXO => new V3i(Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YXI => new V3i(Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YXN => new V3i(Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YXX => new V3i(Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YXY => new V3i(Y, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i YXZ { readonly get => new V3i(Y, X, Z); set { Y = value.X; X = value.Y; Z = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i YXW { readonly get => new V3i(Y, X, W); set { Y = value.X; X = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYO => new V3i(Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYI => new V3i(Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYN => new V3i(Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYX => new V3i(Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYY => new V3i(Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYZ => new V3i(Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YYW => new V3i(Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YZO => new V3i(Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YZI => new V3i(Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YZN => new V3i(Y, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i YZX { readonly get => new V3i(Y, Z, X); set { Y = value.X; Z = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YZY => new V3i(Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YZZ => new V3i(Y, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i YZW { readonly get => new V3i(Y, Z, W); set { Y = value.X; Z = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YWO => new V3i(Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YWI => new V3i(Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YWN => new V3i(Y, W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i YWX { readonly get => new V3i(Y, W, X); set { Y = value.X; W = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YWY => new V3i(Y, W, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i YWZ { readonly get => new V3i(Y, W, Z); set { Y = value.X; W = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i YWW => new V3i(Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZOO => new V3i(Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZOI => new V3i(Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZON => new V3i(Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZOX => new V3i(Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZOY => new V3i(Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZOZ => new V3i(Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZOW => new V3i(Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZIO => new V3i(Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZII => new V3i(Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZPN => new V3i(Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZIX => new V3i(Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZIY => new V3i(Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZIZ => new V3i(Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZIW => new V3i(Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZNO => new V3i(Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZNP => new V3i(Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZNN => new V3i(Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZNX => new V3i(Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZNY => new V3i(Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZNZ => new V3i(Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZNW => new V3i(Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZXO => new V3i(Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZXI => new V3i(Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZXN => new V3i(Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZXX => new V3i(Z, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i ZXY { readonly get => new V3i(Z, X, Y); set { Z = value.X; X = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZXZ => new V3i(Z, X, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i ZXW { readonly get => new V3i(Z, X, W); set { Z = value.X; X = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZYO => new V3i(Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZYI => new V3i(Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZYN => new V3i(Z, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i ZYX { readonly get => new V3i(Z, Y, X); set { Z = value.X; Y = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZYY => new V3i(Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZYZ => new V3i(Z, Y, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i ZYW { readonly get => new V3i(Z, Y, W); set { Z = value.X; Y = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZZO => new V3i(Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZZI => new V3i(Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZZN => new V3i(Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZZX => new V3i(Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZZY => new V3i(Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZZZ => new V3i(Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZZW => new V3i(Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZWO => new V3i(Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZWI => new V3i(Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZWN => new V3i(Z, W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i ZWX { readonly get => new V3i(Z, W, X); set { Z = value.X; W = value.Y; X = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i ZWY { readonly get => new V3i(Z, W, Y); set { Z = value.X; W = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZWZ => new V3i(Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i ZWW => new V3i(Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WOO => new V3i(W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WOI => new V3i(W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WON => new V3i(W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WOX => new V3i(W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WOY => new V3i(W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WOZ => new V3i(W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WOW => new V3i(W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WIO => new V3i(W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WII => new V3i(W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WPN => new V3i(W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WIX => new V3i(W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WIY => new V3i(W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WIZ => new V3i(W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WIW => new V3i(W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WNO => new V3i(W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WNP => new V3i(W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WNN => new V3i(W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WNX => new V3i(W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WNY => new V3i(W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WNZ => new V3i(W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WNW => new V3i(W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WXO => new V3i(W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WXI => new V3i(W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WXN => new V3i(W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WXX => new V3i(W, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i WXY { readonly get => new V3i(W, X, Y); set { W = value.X; X = value.Y; Y = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i WXZ { readonly get => new V3i(W, X, Z); set { W = value.X; X = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WXW => new V3i(W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WYO => new V3i(W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WYI => new V3i(W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WYN => new V3i(W, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i WYX { readonly get => new V3i(W, Y, X); set { W = value.X; Y = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WYY => new V3i(W, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i WYZ { readonly get => new V3i(W, Y, Z); set { W = value.X; Y = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WYW => new V3i(W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WZO => new V3i(W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WZI => new V3i(W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WZN => new V3i(W, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i WZX { readonly get => new V3i(W, Z, X); set { W = value.X; Z = value.Y; X = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3i WZY { readonly get => new V3i(W, Z, Y); set { W = value.X; Z = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WZZ => new V3i(W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WZW => new V3i(W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WWO => new V3i(W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WWI => new V3i(W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WWN => new V3i(W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WWX => new V3i(W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WWY => new V3i(W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WWZ => new V3i(W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3i WWW => new V3i(W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OOOO => new V4i(0, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OOOI => new V4i(0, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OOON => new V4i(0, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOOX => new V4i(0, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOOY => new V4i(0, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOOZ => new V4i(0, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOOW => new V4i(0, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OOIO => new V4i(0, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OOII => new V4i(0, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OOPN => new V4i(0, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOIX => new V4i(0, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOIY => new V4i(0, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOIZ => new V4i(0, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOIW => new V4i(0, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OONO => new V4i(0, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OONP => new V4i(0, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OONN => new V4i(0, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OONX => new V4i(0, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OONY => new V4i(0, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OONZ => new V4i(0, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OONW => new V4i(0, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXO => new V4i(0, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXI => new V4i(0, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXN => new V4i(0, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXX => new V4i(0, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXY => new V4i(0, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXZ => new V4i(0, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOXW => new V4i(0, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYO => new V4i(0, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYI => new V4i(0, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYN => new V4i(0, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYX => new V4i(0, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYY => new V4i(0, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYZ => new V4i(0, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOYW => new V4i(0, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOZO => new V4i(0, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOZI => new V4i(0, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOZN => new V4i(0, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOZX => new V4i(0, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOZY => new V4i(0, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOZZ => new V4i(0, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOZW => new V4i(0, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOWO => new V4i(0, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOWI => new V4i(0, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOWN => new V4i(0, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOWX => new V4i(0, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOWY => new V4i(0, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOWZ => new V4i(0, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OOWW => new V4i(0, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OIOO => new V4i(0, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OIOI => new V4i(0, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OPON => new V4i(0, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIOX => new V4i(0, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIOY => new V4i(0, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIOZ => new V4i(0, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIOW => new V4i(0, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OIIO => new V4i(0, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OIII => new V4i(0, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OPPN => new V4i(0, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIIX => new V4i(0, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIIY => new V4i(0, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIIZ => new V4i(0, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIIW => new V4i(0, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OPNO => new V4i(0, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OPNP => new V4i(0, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i OPNN => new V4i(0, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPNX => new V4i(0, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPNY => new V4i(0, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPNZ => new V4i(0, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPNW => new V4i(0, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIXO => new V4i(0, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIXI => new V4i(0, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPXN => new V4i(0, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIXX => new V4i(0, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIXY => new V4i(0, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIXZ => new V4i(0, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIXW => new V4i(0, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIYO => new V4i(0, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIYI => new V4i(0, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPYN => new V4i(0, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIYX => new V4i(0, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIYY => new V4i(0, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIYZ => new V4i(0, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIYW => new V4i(0, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIZO => new V4i(0, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIZI => new V4i(0, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPZN => new V4i(0, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIZX => new V4i(0, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIZY => new V4i(0, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIZZ => new V4i(0, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIZW => new V4i(0, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIWO => new V4i(0, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIWI => new V4i(0, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OPWN => new V4i(0, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIWX => new V4i(0, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIWY => new V4i(0, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIWZ => new V4i(0, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OIWW => new V4i(0, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i ONOO => new V4i(0, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i ONOP => new V4i(0, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i ONON => new V4i(0, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONOX => new V4i(0, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONOY => new V4i(0, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONOZ => new V4i(0, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONOW => new V4i(0, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i ONPO => new V4i(0, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i ONPP => new V4i(0, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i ONPN => new V4i(0, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONPX => new V4i(0, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONPY => new V4i(0, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONPZ => new V4i(0, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONPW => new V4i(0, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i ONNO => new V4i(0, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i ONNP => new V4i(0, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i ONNN => new V4i(0, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONNX => new V4i(0, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONNY => new V4i(0, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONNZ => new V4i(0, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONNW => new V4i(0, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXO => new V4i(0, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXP => new V4i(0, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXN => new V4i(0, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXX => new V4i(0, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXY => new V4i(0, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXZ => new V4i(0, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONXW => new V4i(0, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYO => new V4i(0, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYP => new V4i(0, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYN => new V4i(0, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYX => new V4i(0, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYY => new V4i(0, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYZ => new V4i(0, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONYW => new V4i(0, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONZO => new V4i(0, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONZP => new V4i(0, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONZN => new V4i(0, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONZX => new V4i(0, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONZY => new V4i(0, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONZZ => new V4i(0, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONZW => new V4i(0, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONWO => new V4i(0, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONWP => new V4i(0, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONWN => new V4i(0, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONWX => new V4i(0, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONWY => new V4i(0, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONWZ => new V4i(0, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ONWW => new V4i(0, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXOO => new V4i(0, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXOI => new V4i(0, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXON => new V4i(0, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXOX => new V4i(0, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXOY => new V4i(0, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXOZ => new V4i(0, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXOW => new V4i(0, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXIO => new V4i(0, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXII => new V4i(0, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXPN => new V4i(0, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXIX => new V4i(0, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXIY => new V4i(0, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXIZ => new V4i(0, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXIW => new V4i(0, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNO => new V4i(0, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNP => new V4i(0, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNN => new V4i(0, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNX => new V4i(0, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNY => new V4i(0, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNZ => new V4i(0, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXNW => new V4i(0, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXO => new V4i(0, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXI => new V4i(0, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXN => new V4i(0, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXX => new V4i(0, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXY => new V4i(0, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXZ => new V4i(0, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXXW => new V4i(0, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYO => new V4i(0, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYI => new V4i(0, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYN => new V4i(0, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYX => new V4i(0, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYY => new V4i(0, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYZ => new V4i(0, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXYW => new V4i(0, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXZO => new V4i(0, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXZI => new V4i(0, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXZN => new V4i(0, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXZX => new V4i(0, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXZY => new V4i(0, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXZZ => new V4i(0, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXZW => new V4i(0, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXWO => new V4i(0, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXWI => new V4i(0, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXWN => new V4i(0, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXWX => new V4i(0, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXWY => new V4i(0, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXWZ => new V4i(0, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OXWW => new V4i(0, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYOO => new V4i(0, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYOI => new V4i(0, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYON => new V4i(0, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYOX => new V4i(0, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYOY => new V4i(0, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYOZ => new V4i(0, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYOW => new V4i(0, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYIO => new V4i(0, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYII => new V4i(0, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYPN => new V4i(0, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYIX => new V4i(0, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYIY => new V4i(0, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYIZ => new V4i(0, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYIW => new V4i(0, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNO => new V4i(0, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNP => new V4i(0, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNN => new V4i(0, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNX => new V4i(0, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNY => new V4i(0, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNZ => new V4i(0, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYNW => new V4i(0, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXO => new V4i(0, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXI => new V4i(0, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXN => new V4i(0, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXX => new V4i(0, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXY => new V4i(0, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXZ => new V4i(0, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYXW => new V4i(0, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYO => new V4i(0, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYI => new V4i(0, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYN => new V4i(0, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYX => new V4i(0, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYY => new V4i(0, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYZ => new V4i(0, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYYW => new V4i(0, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYZO => new V4i(0, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYZI => new V4i(0, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYZN => new V4i(0, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYZX => new V4i(0, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYZY => new V4i(0, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYZZ => new V4i(0, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYZW => new V4i(0, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYWO => new V4i(0, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYWI => new V4i(0, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYWN => new V4i(0, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYWX => new V4i(0, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYWY => new V4i(0, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYWZ => new V4i(0, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OYWW => new V4i(0, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZOO => new V4i(0, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZOI => new V4i(0, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZON => new V4i(0, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZOX => new V4i(0, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZOY => new V4i(0, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZOZ => new V4i(0, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZOW => new V4i(0, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZIO => new V4i(0, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZII => new V4i(0, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZPN => new V4i(0, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZIX => new V4i(0, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZIY => new V4i(0, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZIZ => new V4i(0, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZIW => new V4i(0, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZNO => new V4i(0, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZNP => new V4i(0, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZNN => new V4i(0, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZNX => new V4i(0, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZNY => new V4i(0, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZNZ => new V4i(0, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZNW => new V4i(0, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZXO => new V4i(0, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZXI => new V4i(0, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZXN => new V4i(0, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZXX => new V4i(0, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZXY => new V4i(0, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZXZ => new V4i(0, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZXW => new V4i(0, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZYO => new V4i(0, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZYI => new V4i(0, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZYN => new V4i(0, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZYX => new V4i(0, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZYY => new V4i(0, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZYZ => new V4i(0, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZYW => new V4i(0, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZZO => new V4i(0, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZZI => new V4i(0, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZZN => new V4i(0, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZZX => new V4i(0, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZZY => new V4i(0, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZZZ => new V4i(0, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZZW => new V4i(0, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZWO => new V4i(0, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZWI => new V4i(0, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZWN => new V4i(0, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZWX => new V4i(0, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZWY => new V4i(0, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZWZ => new V4i(0, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OZWW => new V4i(0, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWOO => new V4i(0, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWOI => new V4i(0, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWON => new V4i(0, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWOX => new V4i(0, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWOY => new V4i(0, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWOZ => new V4i(0, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWOW => new V4i(0, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWIO => new V4i(0, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWII => new V4i(0, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWPN => new V4i(0, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWIX => new V4i(0, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWIY => new V4i(0, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWIZ => new V4i(0, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWIW => new V4i(0, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWNO => new V4i(0, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWNP => new V4i(0, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWNN => new V4i(0, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWNX => new V4i(0, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWNY => new V4i(0, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWNZ => new V4i(0, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWNW => new V4i(0, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWXO => new V4i(0, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWXI => new V4i(0, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWXN => new V4i(0, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWXX => new V4i(0, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWXY => new V4i(0, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWXZ => new V4i(0, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWXW => new V4i(0, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWYO => new V4i(0, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWYI => new V4i(0, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWYN => new V4i(0, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWYX => new V4i(0, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWYY => new V4i(0, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWYZ => new V4i(0, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWYW => new V4i(0, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWZO => new V4i(0, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWZI => new V4i(0, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWZN => new V4i(0, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWZX => new V4i(0, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWZY => new V4i(0, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWZZ => new V4i(0, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWZW => new V4i(0, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWWO => new V4i(0, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWWI => new V4i(0, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWWN => new V4i(0, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWWX => new V4i(0, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWWY => new V4i(0, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWWZ => new V4i(0, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i OWWW => new V4i(0, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i IOOO => new V4i(1, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i IOOI => new V4i(1, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i POON => new V4i(1, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOOX => new V4i(1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOOY => new V4i(1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOOZ => new V4i(1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOOW => new V4i(1, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i IOIO => new V4i(1, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i IOII => new V4i(1, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i POPN => new V4i(1, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOIX => new V4i(1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOIY => new V4i(1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOIZ => new V4i(1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOIW => new V4i(1, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PONO => new V4i(1, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PONP => new V4i(1, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PONN => new V4i(1, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PONX => new V4i(1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PONY => new V4i(1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PONZ => new V4i(1, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PONW => new V4i(1, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOXO => new V4i(1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOXI => new V4i(1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i POXN => new V4i(1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOXX => new V4i(1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOXY => new V4i(1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOXZ => new V4i(1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOXW => new V4i(1, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOYO => new V4i(1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOYI => new V4i(1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i POYN => new V4i(1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOYX => new V4i(1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOYY => new V4i(1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOYZ => new V4i(1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOYW => new V4i(1, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOZO => new V4i(1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOZI => new V4i(1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i POZN => new V4i(1, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOZX => new V4i(1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOZY => new V4i(1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOZZ => new V4i(1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOZW => new V4i(1, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOWO => new V4i(1, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOWI => new V4i(1, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i POWN => new V4i(1, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOWX => new V4i(1, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOWY => new V4i(1, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOWZ => new V4i(1, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IOWW => new V4i(1, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i IIOO => new V4i(1, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i IIOI => new V4i(1, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PPON => new V4i(1, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIOX => new V4i(1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIOY => new V4i(1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIOZ => new V4i(1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIOW => new V4i(1, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i IIIO => new V4i(1, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i IIII => new V4i(1, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PPPN => new V4i(1, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIIX => new V4i(1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIIY => new V4i(1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIIZ => new V4i(1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIIW => new V4i(1, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PPNO => new V4i(1, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PPNP => new V4i(1, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PPNN => new V4i(1, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPNX => new V4i(1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPNY => new V4i(1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPNZ => new V4i(1, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPNW => new V4i(1, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIXO => new V4i(1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIXI => new V4i(1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPXN => new V4i(1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIXX => new V4i(1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIXY => new V4i(1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIXZ => new V4i(1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIXW => new V4i(1, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIYO => new V4i(1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIYI => new V4i(1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPYN => new V4i(1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIYX => new V4i(1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIYY => new V4i(1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIYZ => new V4i(1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIYW => new V4i(1, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIZO => new V4i(1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIZI => new V4i(1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPZN => new V4i(1, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIZX => new V4i(1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIZY => new V4i(1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIZZ => new V4i(1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIZW => new V4i(1, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIWO => new V4i(1, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIWI => new V4i(1, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PPWN => new V4i(1, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIWX => new V4i(1, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIWY => new V4i(1, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIWZ => new V4i(1, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IIWW => new V4i(1, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PNOO => new V4i(1, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PNOP => new V4i(1, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PNON => new V4i(1, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNOX => new V4i(1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNOY => new V4i(1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNOZ => new V4i(1, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNOW => new V4i(1, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PNPO => new V4i(1, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PNPP => new V4i(1, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PNPN => new V4i(1, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNPX => new V4i(1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNPY => new V4i(1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNPZ => new V4i(1, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNPW => new V4i(1, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PNNO => new V4i(1, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PNNP => new V4i(1, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i PNNN => new V4i(1, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNNX => new V4i(1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNNY => new V4i(1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNNZ => new V4i(1, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNNW => new V4i(1, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXO => new V4i(1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXP => new V4i(1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXN => new V4i(1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXX => new V4i(1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXY => new V4i(1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXZ => new V4i(1, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNXW => new V4i(1, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYO => new V4i(1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYP => new V4i(1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYN => new V4i(1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYX => new V4i(1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYY => new V4i(1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYZ => new V4i(1, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNYW => new V4i(1, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNZO => new V4i(1, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNZP => new V4i(1, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNZN => new V4i(1, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNZX => new V4i(1, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNZY => new V4i(1, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNZZ => new V4i(1, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNZW => new V4i(1, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNWO => new V4i(1, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNWP => new V4i(1, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNWN => new V4i(1, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNWX => new V4i(1, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNWY => new V4i(1, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNWZ => new V4i(1, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PNWW => new V4i(1, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXOO => new V4i(1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXOI => new V4i(1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXON => new V4i(1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXOX => new V4i(1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXOY => new V4i(1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXOZ => new V4i(1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXOW => new V4i(1, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXIO => new V4i(1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXII => new V4i(1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXPN => new V4i(1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXIX => new V4i(1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXIY => new V4i(1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXIZ => new V4i(1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXIW => new V4i(1, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNO => new V4i(1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNP => new V4i(1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNN => new V4i(1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNX => new V4i(1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNY => new V4i(1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNZ => new V4i(1, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXNW => new V4i(1, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXXO => new V4i(1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXXI => new V4i(1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXXN => new V4i(1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXXX => new V4i(1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXXY => new V4i(1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXXZ => new V4i(1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXXW => new V4i(1, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXYO => new V4i(1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXYI => new V4i(1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXYN => new V4i(1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXYX => new V4i(1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXYY => new V4i(1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXYZ => new V4i(1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXYW => new V4i(1, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXZO => new V4i(1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXZI => new V4i(1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXZN => new V4i(1, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXZX => new V4i(1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXZY => new V4i(1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXZZ => new V4i(1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXZW => new V4i(1, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXWO => new V4i(1, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXWI => new V4i(1, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PXWN => new V4i(1, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXWX => new V4i(1, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXWY => new V4i(1, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXWZ => new V4i(1, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IXWW => new V4i(1, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYOO => new V4i(1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYOI => new V4i(1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYON => new V4i(1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYOX => new V4i(1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYOY => new V4i(1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYOZ => new V4i(1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYOW => new V4i(1, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYIO => new V4i(1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYII => new V4i(1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYPN => new V4i(1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYIX => new V4i(1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYIY => new V4i(1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYIZ => new V4i(1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYIW => new V4i(1, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNO => new V4i(1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNP => new V4i(1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNN => new V4i(1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNX => new V4i(1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNY => new V4i(1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNZ => new V4i(1, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYNW => new V4i(1, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYXO => new V4i(1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYXI => new V4i(1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYXN => new V4i(1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYXX => new V4i(1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYXY => new V4i(1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYXZ => new V4i(1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYXW => new V4i(1, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYYO => new V4i(1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYYI => new V4i(1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYYN => new V4i(1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYYX => new V4i(1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYYY => new V4i(1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYYZ => new V4i(1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYYW => new V4i(1, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYZO => new V4i(1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYZI => new V4i(1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYZN => new V4i(1, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYZX => new V4i(1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYZY => new V4i(1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYZZ => new V4i(1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYZW => new V4i(1, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYWO => new V4i(1, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYWI => new V4i(1, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PYWN => new V4i(1, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYWX => new V4i(1, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYWY => new V4i(1, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYWZ => new V4i(1, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IYWW => new V4i(1, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZOO => new V4i(1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZOI => new V4i(1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZON => new V4i(1, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZOX => new V4i(1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZOY => new V4i(1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZOZ => new V4i(1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZOW => new V4i(1, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZIO => new V4i(1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZII => new V4i(1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZPN => new V4i(1, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZIX => new V4i(1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZIY => new V4i(1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZIZ => new V4i(1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZIW => new V4i(1, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZNO => new V4i(1, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZNP => new V4i(1, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZNN => new V4i(1, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZNX => new V4i(1, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZNY => new V4i(1, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZNZ => new V4i(1, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZNW => new V4i(1, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZXO => new V4i(1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZXI => new V4i(1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZXN => new V4i(1, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZXX => new V4i(1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZXY => new V4i(1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZXZ => new V4i(1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZXW => new V4i(1, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZYO => new V4i(1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZYI => new V4i(1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZYN => new V4i(1, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZYX => new V4i(1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZYY => new V4i(1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZYZ => new V4i(1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZYW => new V4i(1, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZZO => new V4i(1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZZI => new V4i(1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZZN => new V4i(1, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZZX => new V4i(1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZZY => new V4i(1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZZZ => new V4i(1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZZW => new V4i(1, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZWO => new V4i(1, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZWI => new V4i(1, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PZWN => new V4i(1, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZWX => new V4i(1, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZWY => new V4i(1, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZWZ => new V4i(1, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IZWW => new V4i(1, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWOO => new V4i(1, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWOI => new V4i(1, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PWON => new V4i(1, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWOX => new V4i(1, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWOY => new V4i(1, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWOZ => new V4i(1, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWOW => new V4i(1, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWIO => new V4i(1, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWII => new V4i(1, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PWPN => new V4i(1, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWIX => new V4i(1, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWIY => new V4i(1, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWIZ => new V4i(1, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWIW => new V4i(1, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PWNO => new V4i(1, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PWNP => new V4i(1, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PWNN => new V4i(1, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PWNX => new V4i(1, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PWNY => new V4i(1, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PWNZ => new V4i(1, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PWNW => new V4i(1, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWXO => new V4i(1, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWXI => new V4i(1, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PWXN => new V4i(1, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWXX => new V4i(1, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWXY => new V4i(1, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWXZ => new V4i(1, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWXW => new V4i(1, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWYO => new V4i(1, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWYI => new V4i(1, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PWYN => new V4i(1, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWYX => new V4i(1, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWYY => new V4i(1, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWYZ => new V4i(1, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWYW => new V4i(1, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWZO => new V4i(1, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWZI => new V4i(1, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PWZN => new V4i(1, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWZX => new V4i(1, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWZY => new V4i(1, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWZZ => new V4i(1, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWZW => new V4i(1, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWWO => new V4i(1, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWWI => new V4i(1, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i PWWN => new V4i(1, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWWX => new V4i(1, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWWY => new V4i(1, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWWZ => new V4i(1, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i IWWW => new V4i(1, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NOOO => new V4i(-1, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NOOP => new V4i(-1, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NOON => new V4i(-1, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOOX => new V4i(-1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOOY => new V4i(-1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOOZ => new V4i(-1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOOW => new V4i(-1, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NOPO => new V4i(-1, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NOPP => new V4i(-1, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NOPN => new V4i(-1, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOPX => new V4i(-1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOPY => new V4i(-1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOPZ => new V4i(-1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOPW => new V4i(-1, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NONO => new V4i(-1, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NONP => new V4i(-1, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NONN => new V4i(-1, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NONX => new V4i(-1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NONY => new V4i(-1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NONZ => new V4i(-1, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NONW => new V4i(-1, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXO => new V4i(-1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXP => new V4i(-1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXN => new V4i(-1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXX => new V4i(-1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXY => new V4i(-1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXZ => new V4i(-1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOXW => new V4i(-1, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYO => new V4i(-1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYP => new V4i(-1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYN => new V4i(-1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYX => new V4i(-1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYY => new V4i(-1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYZ => new V4i(-1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOYW => new V4i(-1, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOZO => new V4i(-1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOZP => new V4i(-1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOZN => new V4i(-1, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOZX => new V4i(-1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOZY => new V4i(-1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOZZ => new V4i(-1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOZW => new V4i(-1, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOWO => new V4i(-1, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOWP => new V4i(-1, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOWN => new V4i(-1, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOWX => new V4i(-1, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOWY => new V4i(-1, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOWZ => new V4i(-1, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NOWW => new V4i(-1, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NPOO => new V4i(-1, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NPOP => new V4i(-1, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NPON => new V4i(-1, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPOX => new V4i(-1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPOY => new V4i(-1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPOZ => new V4i(-1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPOW => new V4i(-1, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NPPO => new V4i(-1, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NPPP => new V4i(-1, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NPPN => new V4i(-1, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPPX => new V4i(-1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPPY => new V4i(-1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPPZ => new V4i(-1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPPW => new V4i(-1, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NPNO => new V4i(-1, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NPNP => new V4i(-1, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NPNN => new V4i(-1, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPNX => new V4i(-1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPNY => new V4i(-1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPNZ => new V4i(-1, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPNW => new V4i(-1, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXO => new V4i(-1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXP => new V4i(-1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXN => new V4i(-1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXX => new V4i(-1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXY => new V4i(-1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXZ => new V4i(-1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPXW => new V4i(-1, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYO => new V4i(-1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYP => new V4i(-1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYN => new V4i(-1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYX => new V4i(-1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYY => new V4i(-1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYZ => new V4i(-1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPYW => new V4i(-1, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPZO => new V4i(-1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPZP => new V4i(-1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPZN => new V4i(-1, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPZX => new V4i(-1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPZY => new V4i(-1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPZZ => new V4i(-1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPZW => new V4i(-1, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPWO => new V4i(-1, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPWP => new V4i(-1, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPWN => new V4i(-1, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPWX => new V4i(-1, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPWY => new V4i(-1, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPWZ => new V4i(-1, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NPWW => new V4i(-1, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NNOO => new V4i(-1, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NNOP => new V4i(-1, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NNON => new V4i(-1, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNOX => new V4i(-1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNOY => new V4i(-1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNOZ => new V4i(-1, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNOW => new V4i(-1, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NNPO => new V4i(-1, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NNPP => new V4i(-1, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NNPN => new V4i(-1, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNPX => new V4i(-1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNPY => new V4i(-1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNPZ => new V4i(-1, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNPW => new V4i(-1, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NNNO => new V4i(-1, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NNNP => new V4i(-1, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4i NNNN => new V4i(-1, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNNX => new V4i(-1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNNY => new V4i(-1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNNZ => new V4i(-1, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNNW => new V4i(-1, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXO => new V4i(-1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXP => new V4i(-1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXN => new V4i(-1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXX => new V4i(-1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXY => new V4i(-1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXZ => new V4i(-1, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNXW => new V4i(-1, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYO => new V4i(-1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYP => new V4i(-1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYN => new V4i(-1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYX => new V4i(-1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYY => new V4i(-1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYZ => new V4i(-1, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNYW => new V4i(-1, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNZO => new V4i(-1, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNZP => new V4i(-1, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNZN => new V4i(-1, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNZX => new V4i(-1, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNZY => new V4i(-1, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNZZ => new V4i(-1, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNZW => new V4i(-1, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNWO => new V4i(-1, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNWP => new V4i(-1, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNWN => new V4i(-1, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNWX => new V4i(-1, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNWY => new V4i(-1, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNWZ => new V4i(-1, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NNWW => new V4i(-1, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXOO => new V4i(-1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXOP => new V4i(-1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXON => new V4i(-1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXOX => new V4i(-1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXOY => new V4i(-1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXOZ => new V4i(-1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXOW => new V4i(-1, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPO => new V4i(-1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPP => new V4i(-1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPN => new V4i(-1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPX => new V4i(-1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPY => new V4i(-1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPZ => new V4i(-1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXPW => new V4i(-1, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNO => new V4i(-1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNP => new V4i(-1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNN => new V4i(-1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNX => new V4i(-1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNY => new V4i(-1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNZ => new V4i(-1, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXNW => new V4i(-1, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXO => new V4i(-1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXP => new V4i(-1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXN => new V4i(-1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXX => new V4i(-1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXY => new V4i(-1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXZ => new V4i(-1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXXW => new V4i(-1, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYO => new V4i(-1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYP => new V4i(-1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYN => new V4i(-1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYX => new V4i(-1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYY => new V4i(-1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYZ => new V4i(-1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXYW => new V4i(-1, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXZO => new V4i(-1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXZP => new V4i(-1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXZN => new V4i(-1, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXZX => new V4i(-1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXZY => new V4i(-1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXZZ => new V4i(-1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXZW => new V4i(-1, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXWO => new V4i(-1, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXWP => new V4i(-1, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXWN => new V4i(-1, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXWX => new V4i(-1, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXWY => new V4i(-1, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXWZ => new V4i(-1, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NXWW => new V4i(-1, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYOO => new V4i(-1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYOP => new V4i(-1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYON => new V4i(-1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYOX => new V4i(-1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYOY => new V4i(-1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYOZ => new V4i(-1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYOW => new V4i(-1, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPO => new V4i(-1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPP => new V4i(-1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPN => new V4i(-1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPX => new V4i(-1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPY => new V4i(-1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPZ => new V4i(-1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYPW => new V4i(-1, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNO => new V4i(-1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNP => new V4i(-1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNN => new V4i(-1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNX => new V4i(-1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNY => new V4i(-1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNZ => new V4i(-1, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYNW => new V4i(-1, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXO => new V4i(-1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXP => new V4i(-1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXN => new V4i(-1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXX => new V4i(-1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXY => new V4i(-1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXZ => new V4i(-1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYXW => new V4i(-1, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYO => new V4i(-1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYP => new V4i(-1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYN => new V4i(-1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYX => new V4i(-1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYY => new V4i(-1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYZ => new V4i(-1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYYW => new V4i(-1, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYZO => new V4i(-1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYZP => new V4i(-1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYZN => new V4i(-1, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYZX => new V4i(-1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYZY => new V4i(-1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYZZ => new V4i(-1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYZW => new V4i(-1, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYWO => new V4i(-1, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYWP => new V4i(-1, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYWN => new V4i(-1, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYWX => new V4i(-1, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYWY => new V4i(-1, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYWZ => new V4i(-1, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NYWW => new V4i(-1, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZOO => new V4i(-1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZOP => new V4i(-1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZON => new V4i(-1, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZOX => new V4i(-1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZOY => new V4i(-1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZOZ => new V4i(-1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZOW => new V4i(-1, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZPO => new V4i(-1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZPP => new V4i(-1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZPN => new V4i(-1, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZPX => new V4i(-1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZPY => new V4i(-1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZPZ => new V4i(-1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZPW => new V4i(-1, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZNO => new V4i(-1, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZNP => new V4i(-1, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZNN => new V4i(-1, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZNX => new V4i(-1, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZNY => new V4i(-1, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZNZ => new V4i(-1, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZNW => new V4i(-1, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZXO => new V4i(-1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZXP => new V4i(-1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZXN => new V4i(-1, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZXX => new V4i(-1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZXY => new V4i(-1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZXZ => new V4i(-1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZXW => new V4i(-1, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZYO => new V4i(-1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZYP => new V4i(-1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZYN => new V4i(-1, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZYX => new V4i(-1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZYY => new V4i(-1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZYZ => new V4i(-1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZYW => new V4i(-1, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZZO => new V4i(-1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZZP => new V4i(-1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZZN => new V4i(-1, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZZX => new V4i(-1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZZY => new V4i(-1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZZZ => new V4i(-1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZZW => new V4i(-1, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZWO => new V4i(-1, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZWP => new V4i(-1, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZWN => new V4i(-1, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZWX => new V4i(-1, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZWY => new V4i(-1, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZWZ => new V4i(-1, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NZWW => new V4i(-1, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWOO => new V4i(-1, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWOP => new V4i(-1, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWON => new V4i(-1, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWOX => new V4i(-1, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWOY => new V4i(-1, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWOZ => new V4i(-1, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWOW => new V4i(-1, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWPO => new V4i(-1, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWPP => new V4i(-1, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWPN => new V4i(-1, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWPX => new V4i(-1, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWPY => new V4i(-1, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWPZ => new V4i(-1, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWPW => new V4i(-1, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWNO => new V4i(-1, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWNP => new V4i(-1, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWNN => new V4i(-1, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWNX => new V4i(-1, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWNY => new V4i(-1, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWNZ => new V4i(-1, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWNW => new V4i(-1, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWXO => new V4i(-1, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWXP => new V4i(-1, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWXN => new V4i(-1, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWXX => new V4i(-1, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWXY => new V4i(-1, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWXZ => new V4i(-1, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWXW => new V4i(-1, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWYO => new V4i(-1, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWYP => new V4i(-1, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWYN => new V4i(-1, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWYX => new V4i(-1, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWYY => new V4i(-1, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWYZ => new V4i(-1, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWYW => new V4i(-1, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWZO => new V4i(-1, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWZP => new V4i(-1, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWZN => new V4i(-1, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWZX => new V4i(-1, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWZY => new V4i(-1, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWZZ => new V4i(-1, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWZW => new V4i(-1, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWWO => new V4i(-1, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWWP => new V4i(-1, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWWN => new V4i(-1, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWWX => new V4i(-1, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWWY => new V4i(-1, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWWZ => new V4i(-1, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i NWWW => new V4i(-1, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOOO => new V4i(X, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOOI => new V4i(X, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOON => new V4i(X, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOOX => new V4i(X, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOOY => new V4i(X, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOOZ => new V4i(X, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOOW => new V4i(X, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOIO => new V4i(X, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOII => new V4i(X, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOPN => new V4i(X, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOIX => new V4i(X, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOIY => new V4i(X, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOIZ => new V4i(X, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOIW => new V4i(X, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONO => new V4i(X, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONP => new V4i(X, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONN => new V4i(X, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONX => new V4i(X, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONY => new V4i(X, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONZ => new V4i(X, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XONW => new V4i(X, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXO => new V4i(X, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXI => new V4i(X, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXN => new V4i(X, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXX => new V4i(X, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXY => new V4i(X, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXZ => new V4i(X, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOXW => new V4i(X, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYO => new V4i(X, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYI => new V4i(X, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYN => new V4i(X, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYX => new V4i(X, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYY => new V4i(X, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYZ => new V4i(X, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOYW => new V4i(X, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOZO => new V4i(X, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOZI => new V4i(X, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOZN => new V4i(X, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOZX => new V4i(X, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOZY => new V4i(X, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOZZ => new V4i(X, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOZW => new V4i(X, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOWO => new V4i(X, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOWI => new V4i(X, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOWN => new V4i(X, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOWX => new V4i(X, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOWY => new V4i(X, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOWZ => new V4i(X, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XOWW => new V4i(X, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIOO => new V4i(X, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIOI => new V4i(X, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPON => new V4i(X, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIOX => new V4i(X, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIOY => new V4i(X, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIOZ => new V4i(X, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIOW => new V4i(X, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIIO => new V4i(X, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIII => new V4i(X, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPPN => new V4i(X, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIIX => new V4i(X, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIIY => new V4i(X, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIIZ => new V4i(X, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIIW => new V4i(X, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNO => new V4i(X, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNP => new V4i(X, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNN => new V4i(X, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNX => new V4i(X, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNY => new V4i(X, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNZ => new V4i(X, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPNW => new V4i(X, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIXO => new V4i(X, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIXI => new V4i(X, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPXN => new V4i(X, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIXX => new V4i(X, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIXY => new V4i(X, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIXZ => new V4i(X, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIXW => new V4i(X, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIYO => new V4i(X, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIYI => new V4i(X, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPYN => new V4i(X, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIYX => new V4i(X, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIYY => new V4i(X, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIYZ => new V4i(X, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIYW => new V4i(X, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIZO => new V4i(X, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIZI => new V4i(X, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPZN => new V4i(X, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIZX => new V4i(X, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIZY => new V4i(X, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIZZ => new V4i(X, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIZW => new V4i(X, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIWO => new V4i(X, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIWI => new V4i(X, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XPWN => new V4i(X, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIWX => new V4i(X, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIWY => new V4i(X, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIWZ => new V4i(X, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XIWW => new V4i(X, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNOO => new V4i(X, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNOP => new V4i(X, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNON => new V4i(X, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNOX => new V4i(X, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNOY => new V4i(X, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNOZ => new V4i(X, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNOW => new V4i(X, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPO => new V4i(X, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPP => new V4i(X, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPN => new V4i(X, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPX => new V4i(X, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPY => new V4i(X, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPZ => new V4i(X, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNPW => new V4i(X, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNO => new V4i(X, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNP => new V4i(X, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNN => new V4i(X, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNX => new V4i(X, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNY => new V4i(X, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNZ => new V4i(X, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNNW => new V4i(X, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXO => new V4i(X, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXP => new V4i(X, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXN => new V4i(X, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXX => new V4i(X, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXY => new V4i(X, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXZ => new V4i(X, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNXW => new V4i(X, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYO => new V4i(X, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYP => new V4i(X, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYN => new V4i(X, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYX => new V4i(X, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYY => new V4i(X, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYZ => new V4i(X, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNYW => new V4i(X, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNZO => new V4i(X, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNZP => new V4i(X, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNZN => new V4i(X, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNZX => new V4i(X, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNZY => new V4i(X, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNZZ => new V4i(X, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNZW => new V4i(X, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNWO => new V4i(X, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNWP => new V4i(X, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNWN => new V4i(X, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNWX => new V4i(X, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNWY => new V4i(X, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNWZ => new V4i(X, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XNWW => new V4i(X, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXOO => new V4i(X, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXOI => new V4i(X, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXON => new V4i(X, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXOX => new V4i(X, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXOY => new V4i(X, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXOZ => new V4i(X, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXOW => new V4i(X, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXIO => new V4i(X, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXII => new V4i(X, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXPN => new V4i(X, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXIX => new V4i(X, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXIY => new V4i(X, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXIZ => new V4i(X, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXIW => new V4i(X, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNO => new V4i(X, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNP => new V4i(X, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNN => new V4i(X, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNX => new V4i(X, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNY => new V4i(X, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNZ => new V4i(X, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXNW => new V4i(X, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXO => new V4i(X, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXI => new V4i(X, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXN => new V4i(X, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXX => new V4i(X, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXY => new V4i(X, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXZ => new V4i(X, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXXW => new V4i(X, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYO => new V4i(X, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYI => new V4i(X, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYN => new V4i(X, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYX => new V4i(X, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYY => new V4i(X, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYZ => new V4i(X, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXYW => new V4i(X, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXZO => new V4i(X, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXZI => new V4i(X, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXZN => new V4i(X, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXZX => new V4i(X, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXZY => new V4i(X, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXZZ => new V4i(X, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXZW => new V4i(X, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXWO => new V4i(X, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXWI => new V4i(X, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXWN => new V4i(X, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXWX => new V4i(X, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXWY => new V4i(X, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXWZ => new V4i(X, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XXWW => new V4i(X, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYOO => new V4i(X, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYOI => new V4i(X, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYON => new V4i(X, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYOX => new V4i(X, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYOY => new V4i(X, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYOZ => new V4i(X, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYOW => new V4i(X, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYIO => new V4i(X, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYII => new V4i(X, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYPN => new V4i(X, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYIX => new V4i(X, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYIY => new V4i(X, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYIZ => new V4i(X, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYIW => new V4i(X, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNO => new V4i(X, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNP => new V4i(X, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNN => new V4i(X, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNX => new V4i(X, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNY => new V4i(X, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNZ => new V4i(X, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYNW => new V4i(X, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXO => new V4i(X, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXI => new V4i(X, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXN => new V4i(X, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXX => new V4i(X, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXY => new V4i(X, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXZ => new V4i(X, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYXW => new V4i(X, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYO => new V4i(X, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYI => new V4i(X, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYN => new V4i(X, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYX => new V4i(X, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYY => new V4i(X, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYZ => new V4i(X, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYYW => new V4i(X, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYZO => new V4i(X, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYZI => new V4i(X, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYZN => new V4i(X, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYZX => new V4i(X, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYZY => new V4i(X, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYZZ => new V4i(X, Y, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i XYZW { readonly get => new V4i(X, Y, Z, W); set { X = value.X; Y = value.Y; Z = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYWO => new V4i(X, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYWI => new V4i(X, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYWN => new V4i(X, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYWX => new V4i(X, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYWY => new V4i(X, Y, W, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i XYWZ { readonly get => new V4i(X, Y, W, Z); set { X = value.X; Y = value.Y; W = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XYWW => new V4i(X, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZOO => new V4i(X, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZOI => new V4i(X, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZON => new V4i(X, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZOX => new V4i(X, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZOY => new V4i(X, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZOZ => new V4i(X, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZOW => new V4i(X, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZIO => new V4i(X, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZII => new V4i(X, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZPN => new V4i(X, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZIX => new V4i(X, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZIY => new V4i(X, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZIZ => new V4i(X, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZIW => new V4i(X, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZNO => new V4i(X, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZNP => new V4i(X, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZNN => new V4i(X, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZNX => new V4i(X, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZNY => new V4i(X, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZNZ => new V4i(X, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZNW => new V4i(X, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZXO => new V4i(X, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZXI => new V4i(X, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZXN => new V4i(X, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZXX => new V4i(X, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZXY => new V4i(X, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZXZ => new V4i(X, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZXW => new V4i(X, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZYO => new V4i(X, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZYI => new V4i(X, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZYN => new V4i(X, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZYX => new V4i(X, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZYY => new V4i(X, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZYZ => new V4i(X, Z, Y, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i XZYW { readonly get => new V4i(X, Z, Y, W); set { X = value.X; Z = value.Y; Y = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZZO => new V4i(X, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZZI => new V4i(X, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZZN => new V4i(X, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZZX => new V4i(X, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZZY => new V4i(X, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZZZ => new V4i(X, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZZW => new V4i(X, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZWO => new V4i(X, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZWI => new V4i(X, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZWN => new V4i(X, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZWX => new V4i(X, Z, W, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i XZWY { readonly get => new V4i(X, Z, W, Y); set { X = value.X; Z = value.Y; W = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZWZ => new V4i(X, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XZWW => new V4i(X, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWOO => new V4i(X, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWOI => new V4i(X, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWON => new V4i(X, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWOX => new V4i(X, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWOY => new V4i(X, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWOZ => new V4i(X, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWOW => new V4i(X, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWIO => new V4i(X, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWII => new V4i(X, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWPN => new V4i(X, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWIX => new V4i(X, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWIY => new V4i(X, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWIZ => new V4i(X, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWIW => new V4i(X, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWNO => new V4i(X, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWNP => new V4i(X, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWNN => new V4i(X, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWNX => new V4i(X, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWNY => new V4i(X, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWNZ => new V4i(X, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWNW => new V4i(X, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWXO => new V4i(X, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWXI => new V4i(X, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWXN => new V4i(X, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWXX => new V4i(X, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWXY => new V4i(X, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWXZ => new V4i(X, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWXW => new V4i(X, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWYO => new V4i(X, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWYI => new V4i(X, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWYN => new V4i(X, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWYX => new V4i(X, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWYY => new V4i(X, W, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i XWYZ { readonly get => new V4i(X, W, Y, Z); set { X = value.X; W = value.Y; Y = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWYW => new V4i(X, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWZO => new V4i(X, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWZI => new V4i(X, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWZN => new V4i(X, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWZX => new V4i(X, W, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i XWZY { readonly get => new V4i(X, W, Z, Y); set { X = value.X; W = value.Y; Z = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWZZ => new V4i(X, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWZW => new V4i(X, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWWO => new V4i(X, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWWI => new V4i(X, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWWN => new V4i(X, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWWX => new V4i(X, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWWY => new V4i(X, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWWZ => new V4i(X, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i XWWW => new V4i(X, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOOO => new V4i(Y, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOOI => new V4i(Y, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOON => new V4i(Y, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOOX => new V4i(Y, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOOY => new V4i(Y, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOOZ => new V4i(Y, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOOW => new V4i(Y, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOIO => new V4i(Y, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOII => new V4i(Y, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOPN => new V4i(Y, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOIX => new V4i(Y, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOIY => new V4i(Y, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOIZ => new V4i(Y, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOIW => new V4i(Y, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONO => new V4i(Y, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONP => new V4i(Y, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONN => new V4i(Y, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONX => new V4i(Y, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONY => new V4i(Y, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONZ => new V4i(Y, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YONW => new V4i(Y, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXO => new V4i(Y, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXI => new V4i(Y, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXN => new V4i(Y, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXX => new V4i(Y, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXY => new V4i(Y, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXZ => new V4i(Y, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOXW => new V4i(Y, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYO => new V4i(Y, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYI => new V4i(Y, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYN => new V4i(Y, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYX => new V4i(Y, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYY => new V4i(Y, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYZ => new V4i(Y, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOYW => new V4i(Y, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOZO => new V4i(Y, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOZI => new V4i(Y, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOZN => new V4i(Y, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOZX => new V4i(Y, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOZY => new V4i(Y, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOZZ => new V4i(Y, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOZW => new V4i(Y, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOWO => new V4i(Y, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOWI => new V4i(Y, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOWN => new V4i(Y, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOWX => new V4i(Y, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOWY => new V4i(Y, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOWZ => new V4i(Y, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YOWW => new V4i(Y, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIOO => new V4i(Y, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIOI => new V4i(Y, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPON => new V4i(Y, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIOX => new V4i(Y, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIOY => new V4i(Y, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIOZ => new V4i(Y, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIOW => new V4i(Y, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIIO => new V4i(Y, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIII => new V4i(Y, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPPN => new V4i(Y, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIIX => new V4i(Y, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIIY => new V4i(Y, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIIZ => new V4i(Y, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIIW => new V4i(Y, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNO => new V4i(Y, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNP => new V4i(Y, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNN => new V4i(Y, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNX => new V4i(Y, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNY => new V4i(Y, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNZ => new V4i(Y, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPNW => new V4i(Y, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIXO => new V4i(Y, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIXI => new V4i(Y, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPXN => new V4i(Y, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIXX => new V4i(Y, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIXY => new V4i(Y, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIXZ => new V4i(Y, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIXW => new V4i(Y, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIYO => new V4i(Y, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIYI => new V4i(Y, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPYN => new V4i(Y, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIYX => new V4i(Y, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIYY => new V4i(Y, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIYZ => new V4i(Y, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIYW => new V4i(Y, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIZO => new V4i(Y, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIZI => new V4i(Y, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPZN => new V4i(Y, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIZX => new V4i(Y, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIZY => new V4i(Y, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIZZ => new V4i(Y, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIZW => new V4i(Y, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIWO => new V4i(Y, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIWI => new V4i(Y, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YPWN => new V4i(Y, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIWX => new V4i(Y, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIWY => new V4i(Y, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIWZ => new V4i(Y, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YIWW => new V4i(Y, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNOO => new V4i(Y, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNOP => new V4i(Y, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNON => new V4i(Y, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNOX => new V4i(Y, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNOY => new V4i(Y, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNOZ => new V4i(Y, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNOW => new V4i(Y, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPO => new V4i(Y, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPP => new V4i(Y, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPN => new V4i(Y, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPX => new V4i(Y, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPY => new V4i(Y, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPZ => new V4i(Y, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNPW => new V4i(Y, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNO => new V4i(Y, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNP => new V4i(Y, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNN => new V4i(Y, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNX => new V4i(Y, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNY => new V4i(Y, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNZ => new V4i(Y, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNNW => new V4i(Y, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXO => new V4i(Y, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXP => new V4i(Y, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXN => new V4i(Y, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXX => new V4i(Y, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXY => new V4i(Y, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXZ => new V4i(Y, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNXW => new V4i(Y, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYO => new V4i(Y, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYP => new V4i(Y, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYN => new V4i(Y, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYX => new V4i(Y, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYY => new V4i(Y, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYZ => new V4i(Y, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNYW => new V4i(Y, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNZO => new V4i(Y, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNZP => new V4i(Y, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNZN => new V4i(Y, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNZX => new V4i(Y, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNZY => new V4i(Y, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNZZ => new V4i(Y, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNZW => new V4i(Y, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNWO => new V4i(Y, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNWP => new V4i(Y, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNWN => new V4i(Y, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNWX => new V4i(Y, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNWY => new V4i(Y, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNWZ => new V4i(Y, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YNWW => new V4i(Y, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXOO => new V4i(Y, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXOI => new V4i(Y, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXON => new V4i(Y, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXOX => new V4i(Y, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXOY => new V4i(Y, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXOZ => new V4i(Y, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXOW => new V4i(Y, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXIO => new V4i(Y, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXII => new V4i(Y, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXPN => new V4i(Y, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXIX => new V4i(Y, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXIY => new V4i(Y, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXIZ => new V4i(Y, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXIW => new V4i(Y, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNO => new V4i(Y, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNP => new V4i(Y, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNN => new V4i(Y, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNX => new V4i(Y, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNY => new V4i(Y, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNZ => new V4i(Y, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXNW => new V4i(Y, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXO => new V4i(Y, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXI => new V4i(Y, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXN => new V4i(Y, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXX => new V4i(Y, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXY => new V4i(Y, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXZ => new V4i(Y, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXXW => new V4i(Y, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYO => new V4i(Y, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYI => new V4i(Y, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYN => new V4i(Y, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYX => new V4i(Y, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYY => new V4i(Y, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYZ => new V4i(Y, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXYW => new V4i(Y, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXZO => new V4i(Y, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXZI => new V4i(Y, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXZN => new V4i(Y, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXZX => new V4i(Y, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXZY => new V4i(Y, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXZZ => new V4i(Y, X, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i YXZW { readonly get => new V4i(Y, X, Z, W); set { Y = value.X; X = value.Y; Z = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXWO => new V4i(Y, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXWI => new V4i(Y, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXWN => new V4i(Y, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXWX => new V4i(Y, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXWY => new V4i(Y, X, W, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i YXWZ { readonly get => new V4i(Y, X, W, Z); set { Y = value.X; X = value.Y; W = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YXWW => new V4i(Y, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYOO => new V4i(Y, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYOI => new V4i(Y, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYON => new V4i(Y, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYOX => new V4i(Y, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYOY => new V4i(Y, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYOZ => new V4i(Y, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYOW => new V4i(Y, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYIO => new V4i(Y, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYII => new V4i(Y, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYPN => new V4i(Y, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYIX => new V4i(Y, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYIY => new V4i(Y, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYIZ => new V4i(Y, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYIW => new V4i(Y, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNO => new V4i(Y, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNP => new V4i(Y, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNN => new V4i(Y, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNX => new V4i(Y, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNY => new V4i(Y, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNZ => new V4i(Y, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYNW => new V4i(Y, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXO => new V4i(Y, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXI => new V4i(Y, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXN => new V4i(Y, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXX => new V4i(Y, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXY => new V4i(Y, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXZ => new V4i(Y, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYXW => new V4i(Y, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYO => new V4i(Y, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYI => new V4i(Y, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYN => new V4i(Y, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYX => new V4i(Y, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYY => new V4i(Y, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYZ => new V4i(Y, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYYW => new V4i(Y, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYZO => new V4i(Y, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYZI => new V4i(Y, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYZN => new V4i(Y, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYZX => new V4i(Y, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYZY => new V4i(Y, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYZZ => new V4i(Y, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYZW => new V4i(Y, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYWO => new V4i(Y, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYWI => new V4i(Y, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYWN => new V4i(Y, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYWX => new V4i(Y, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYWY => new V4i(Y, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYWZ => new V4i(Y, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YYWW => new V4i(Y, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZOO => new V4i(Y, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZOI => new V4i(Y, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZON => new V4i(Y, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZOX => new V4i(Y, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZOY => new V4i(Y, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZOZ => new V4i(Y, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZOW => new V4i(Y, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZIO => new V4i(Y, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZII => new V4i(Y, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZPN => new V4i(Y, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZIX => new V4i(Y, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZIY => new V4i(Y, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZIZ => new V4i(Y, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZIW => new V4i(Y, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZNO => new V4i(Y, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZNP => new V4i(Y, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZNN => new V4i(Y, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZNX => new V4i(Y, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZNY => new V4i(Y, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZNZ => new V4i(Y, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZNW => new V4i(Y, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZXO => new V4i(Y, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZXI => new V4i(Y, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZXN => new V4i(Y, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZXX => new V4i(Y, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZXY => new V4i(Y, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZXZ => new V4i(Y, Z, X, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i YZXW { readonly get => new V4i(Y, Z, X, W); set { Y = value.X; Z = value.Y; X = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZYO => new V4i(Y, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZYI => new V4i(Y, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZYN => new V4i(Y, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZYX => new V4i(Y, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZYY => new V4i(Y, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZYZ => new V4i(Y, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZYW => new V4i(Y, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZZO => new V4i(Y, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZZI => new V4i(Y, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZZN => new V4i(Y, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZZX => new V4i(Y, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZZY => new V4i(Y, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZZZ => new V4i(Y, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZZW => new V4i(Y, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZWO => new V4i(Y, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZWI => new V4i(Y, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZWN => new V4i(Y, Z, W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i YZWX { readonly get => new V4i(Y, Z, W, X); set { Y = value.X; Z = value.Y; W = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZWY => new V4i(Y, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZWZ => new V4i(Y, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YZWW => new V4i(Y, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWOO => new V4i(Y, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWOI => new V4i(Y, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWON => new V4i(Y, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWOX => new V4i(Y, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWOY => new V4i(Y, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWOZ => new V4i(Y, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWOW => new V4i(Y, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWIO => new V4i(Y, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWII => new V4i(Y, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWPN => new V4i(Y, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWIX => new V4i(Y, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWIY => new V4i(Y, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWIZ => new V4i(Y, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWIW => new V4i(Y, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWNO => new V4i(Y, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWNP => new V4i(Y, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWNN => new V4i(Y, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWNX => new V4i(Y, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWNY => new V4i(Y, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWNZ => new V4i(Y, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWNW => new V4i(Y, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWXO => new V4i(Y, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWXI => new V4i(Y, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWXN => new V4i(Y, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWXX => new V4i(Y, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWXY => new V4i(Y, W, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i YWXZ { readonly get => new V4i(Y, W, X, Z); set { Y = value.X; W = value.Y; X = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWXW => new V4i(Y, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWYO => new V4i(Y, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWYI => new V4i(Y, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWYN => new V4i(Y, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWYX => new V4i(Y, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWYY => new V4i(Y, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWYZ => new V4i(Y, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWYW => new V4i(Y, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWZO => new V4i(Y, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWZI => new V4i(Y, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWZN => new V4i(Y, W, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i YWZX { readonly get => new V4i(Y, W, Z, X); set { Y = value.X; W = value.Y; Z = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWZY => new V4i(Y, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWZZ => new V4i(Y, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWZW => new V4i(Y, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWWO => new V4i(Y, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWWI => new V4i(Y, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWWN => new V4i(Y, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWWX => new V4i(Y, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWWY => new V4i(Y, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWWZ => new V4i(Y, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i YWWW => new V4i(Y, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOOO => new V4i(Z, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOOI => new V4i(Z, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOON => new V4i(Z, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOOX => new V4i(Z, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOOY => new V4i(Z, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOOZ => new V4i(Z, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOOW => new V4i(Z, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOIO => new V4i(Z, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOII => new V4i(Z, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOPN => new V4i(Z, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOIX => new V4i(Z, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOIY => new V4i(Z, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOIZ => new V4i(Z, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOIW => new V4i(Z, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZONO => new V4i(Z, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZONP => new V4i(Z, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZONN => new V4i(Z, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZONX => new V4i(Z, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZONY => new V4i(Z, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZONZ => new V4i(Z, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZONW => new V4i(Z, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOXO => new V4i(Z, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOXI => new V4i(Z, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOXN => new V4i(Z, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOXX => new V4i(Z, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOXY => new V4i(Z, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOXZ => new V4i(Z, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOXW => new V4i(Z, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOYO => new V4i(Z, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOYI => new V4i(Z, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOYN => new V4i(Z, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOYX => new V4i(Z, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOYY => new V4i(Z, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOYZ => new V4i(Z, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOYW => new V4i(Z, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOZO => new V4i(Z, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOZI => new V4i(Z, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOZN => new V4i(Z, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOZX => new V4i(Z, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOZY => new V4i(Z, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOZZ => new V4i(Z, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOZW => new V4i(Z, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOWO => new V4i(Z, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOWI => new V4i(Z, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOWN => new V4i(Z, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOWX => new V4i(Z, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOWY => new V4i(Z, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOWZ => new V4i(Z, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZOWW => new V4i(Z, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIOO => new V4i(Z, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIOI => new V4i(Z, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPON => new V4i(Z, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIOX => new V4i(Z, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIOY => new V4i(Z, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIOZ => new V4i(Z, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIOW => new V4i(Z, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIIO => new V4i(Z, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIII => new V4i(Z, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPPN => new V4i(Z, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIIX => new V4i(Z, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIIY => new V4i(Z, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIIZ => new V4i(Z, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIIW => new V4i(Z, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPNO => new V4i(Z, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPNP => new V4i(Z, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPNN => new V4i(Z, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPNX => new V4i(Z, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPNY => new V4i(Z, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPNZ => new V4i(Z, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPNW => new V4i(Z, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIXO => new V4i(Z, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIXI => new V4i(Z, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPXN => new V4i(Z, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIXX => new V4i(Z, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIXY => new V4i(Z, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIXZ => new V4i(Z, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIXW => new V4i(Z, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIYO => new V4i(Z, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIYI => new V4i(Z, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPYN => new V4i(Z, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIYX => new V4i(Z, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIYY => new V4i(Z, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIYZ => new V4i(Z, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIYW => new V4i(Z, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIZO => new V4i(Z, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIZI => new V4i(Z, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPZN => new V4i(Z, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIZX => new V4i(Z, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIZY => new V4i(Z, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIZZ => new V4i(Z, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIZW => new V4i(Z, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIWO => new V4i(Z, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIWI => new V4i(Z, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZPWN => new V4i(Z, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIWX => new V4i(Z, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIWY => new V4i(Z, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIWZ => new V4i(Z, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZIWW => new V4i(Z, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNOO => new V4i(Z, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNOP => new V4i(Z, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNON => new V4i(Z, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNOX => new V4i(Z, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNOY => new V4i(Z, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNOZ => new V4i(Z, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNOW => new V4i(Z, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNPO => new V4i(Z, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNPP => new V4i(Z, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNPN => new V4i(Z, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNPX => new V4i(Z, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNPY => new V4i(Z, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNPZ => new V4i(Z, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNPW => new V4i(Z, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNNO => new V4i(Z, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNNP => new V4i(Z, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNNN => new V4i(Z, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNNX => new V4i(Z, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNNY => new V4i(Z, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNNZ => new V4i(Z, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNNW => new V4i(Z, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNXO => new V4i(Z, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNXP => new V4i(Z, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNXN => new V4i(Z, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNXX => new V4i(Z, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNXY => new V4i(Z, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNXZ => new V4i(Z, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNXW => new V4i(Z, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNYO => new V4i(Z, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNYP => new V4i(Z, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNYN => new V4i(Z, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNYX => new V4i(Z, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNYY => new V4i(Z, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNYZ => new V4i(Z, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNYW => new V4i(Z, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNZO => new V4i(Z, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNZP => new V4i(Z, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNZN => new V4i(Z, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNZX => new V4i(Z, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNZY => new V4i(Z, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNZZ => new V4i(Z, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNZW => new V4i(Z, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNWO => new V4i(Z, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNWP => new V4i(Z, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNWN => new V4i(Z, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNWX => new V4i(Z, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNWY => new V4i(Z, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNWZ => new V4i(Z, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZNWW => new V4i(Z, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXOO => new V4i(Z, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXOI => new V4i(Z, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXON => new V4i(Z, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXOX => new V4i(Z, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXOY => new V4i(Z, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXOZ => new V4i(Z, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXOW => new V4i(Z, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXIO => new V4i(Z, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXII => new V4i(Z, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXPN => new V4i(Z, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXIX => new V4i(Z, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXIY => new V4i(Z, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXIZ => new V4i(Z, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXIW => new V4i(Z, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXNO => new V4i(Z, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXNP => new V4i(Z, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXNN => new V4i(Z, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXNX => new V4i(Z, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXNY => new V4i(Z, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXNZ => new V4i(Z, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXNW => new V4i(Z, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXXO => new V4i(Z, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXXI => new V4i(Z, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXXN => new V4i(Z, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXXX => new V4i(Z, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXXY => new V4i(Z, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXXZ => new V4i(Z, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXXW => new V4i(Z, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXYO => new V4i(Z, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXYI => new V4i(Z, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXYN => new V4i(Z, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXYX => new V4i(Z, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXYY => new V4i(Z, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXYZ => new V4i(Z, X, Y, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i ZXYW { readonly get => new V4i(Z, X, Y, W); set { Z = value.X; X = value.Y; Y = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXZO => new V4i(Z, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXZI => new V4i(Z, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXZN => new V4i(Z, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXZX => new V4i(Z, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXZY => new V4i(Z, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXZZ => new V4i(Z, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXZW => new V4i(Z, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXWO => new V4i(Z, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXWI => new V4i(Z, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXWN => new V4i(Z, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXWX => new V4i(Z, X, W, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i ZXWY { readonly get => new V4i(Z, X, W, Y); set { Z = value.X; X = value.Y; W = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXWZ => new V4i(Z, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZXWW => new V4i(Z, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYOO => new V4i(Z, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYOI => new V4i(Z, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYON => new V4i(Z, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYOX => new V4i(Z, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYOY => new V4i(Z, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYOZ => new V4i(Z, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYOW => new V4i(Z, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYIO => new V4i(Z, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYII => new V4i(Z, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYPN => new V4i(Z, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYIX => new V4i(Z, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYIY => new V4i(Z, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYIZ => new V4i(Z, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYIW => new V4i(Z, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYNO => new V4i(Z, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYNP => new V4i(Z, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYNN => new V4i(Z, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYNX => new V4i(Z, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYNY => new V4i(Z, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYNZ => new V4i(Z, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYNW => new V4i(Z, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYXO => new V4i(Z, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYXI => new V4i(Z, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYXN => new V4i(Z, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYXX => new V4i(Z, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYXY => new V4i(Z, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYXZ => new V4i(Z, Y, X, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i ZYXW { readonly get => new V4i(Z, Y, X, W); set { Z = value.X; Y = value.Y; X = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYYO => new V4i(Z, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYYI => new V4i(Z, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYYN => new V4i(Z, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYYX => new V4i(Z, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYYY => new V4i(Z, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYYZ => new V4i(Z, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYYW => new V4i(Z, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYZO => new V4i(Z, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYZI => new V4i(Z, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYZN => new V4i(Z, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYZX => new V4i(Z, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYZY => new V4i(Z, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYZZ => new V4i(Z, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYZW => new V4i(Z, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYWO => new V4i(Z, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYWI => new V4i(Z, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYWN => new V4i(Z, Y, W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i ZYWX { readonly get => new V4i(Z, Y, W, X); set { Z = value.X; Y = value.Y; W = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYWY => new V4i(Z, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYWZ => new V4i(Z, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZYWW => new V4i(Z, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZOO => new V4i(Z, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZOI => new V4i(Z, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZON => new V4i(Z, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZOX => new V4i(Z, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZOY => new V4i(Z, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZOZ => new V4i(Z, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZOW => new V4i(Z, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZIO => new V4i(Z, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZII => new V4i(Z, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZPN => new V4i(Z, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZIX => new V4i(Z, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZIY => new V4i(Z, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZIZ => new V4i(Z, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZIW => new V4i(Z, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZNO => new V4i(Z, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZNP => new V4i(Z, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZNN => new V4i(Z, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZNX => new V4i(Z, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZNY => new V4i(Z, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZNZ => new V4i(Z, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZNW => new V4i(Z, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZXO => new V4i(Z, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZXI => new V4i(Z, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZXN => new V4i(Z, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZXX => new V4i(Z, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZXY => new V4i(Z, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZXZ => new V4i(Z, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZXW => new V4i(Z, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZYO => new V4i(Z, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZYI => new V4i(Z, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZYN => new V4i(Z, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZYX => new V4i(Z, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZYY => new V4i(Z, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZYZ => new V4i(Z, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZYW => new V4i(Z, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZZO => new V4i(Z, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZZI => new V4i(Z, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZZN => new V4i(Z, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZZX => new V4i(Z, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZZY => new V4i(Z, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZZZ => new V4i(Z, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZZW => new V4i(Z, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZWO => new V4i(Z, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZWI => new V4i(Z, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZWN => new V4i(Z, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZWX => new V4i(Z, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZWY => new V4i(Z, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZWZ => new V4i(Z, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZZWW => new V4i(Z, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWOO => new V4i(Z, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWOI => new V4i(Z, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWON => new V4i(Z, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWOX => new V4i(Z, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWOY => new V4i(Z, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWOZ => new V4i(Z, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWOW => new V4i(Z, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWIO => new V4i(Z, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWII => new V4i(Z, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWPN => new V4i(Z, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWIX => new V4i(Z, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWIY => new V4i(Z, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWIZ => new V4i(Z, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWIW => new V4i(Z, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWNO => new V4i(Z, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWNP => new V4i(Z, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWNN => new V4i(Z, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWNX => new V4i(Z, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWNY => new V4i(Z, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWNZ => new V4i(Z, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWNW => new V4i(Z, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWXO => new V4i(Z, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWXI => new V4i(Z, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWXN => new V4i(Z, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWXX => new V4i(Z, W, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i ZWXY { readonly get => new V4i(Z, W, X, Y); set { Z = value.X; W = value.Y; X = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWXZ => new V4i(Z, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWXW => new V4i(Z, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWYO => new V4i(Z, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWYI => new V4i(Z, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWYN => new V4i(Z, W, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i ZWYX { readonly get => new V4i(Z, W, Y, X); set { Z = value.X; W = value.Y; Y = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWYY => new V4i(Z, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWYZ => new V4i(Z, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWYW => new V4i(Z, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWZO => new V4i(Z, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWZI => new V4i(Z, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWZN => new V4i(Z, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWZX => new V4i(Z, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWZY => new V4i(Z, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWZZ => new V4i(Z, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWZW => new V4i(Z, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWWO => new V4i(Z, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWWI => new V4i(Z, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWWN => new V4i(Z, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWWX => new V4i(Z, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWWY => new V4i(Z, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWWZ => new V4i(Z, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i ZWWW => new V4i(Z, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOOO => new V4i(W, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOOI => new V4i(W, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOON => new V4i(W, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOOX => new V4i(W, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOOY => new V4i(W, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOOZ => new V4i(W, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOOW => new V4i(W, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOIO => new V4i(W, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOII => new V4i(W, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOPN => new V4i(W, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOIX => new V4i(W, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOIY => new V4i(W, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOIZ => new V4i(W, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOIW => new V4i(W, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WONO => new V4i(W, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WONP => new V4i(W, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WONN => new V4i(W, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WONX => new V4i(W, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WONY => new V4i(W, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WONZ => new V4i(W, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WONW => new V4i(W, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOXO => new V4i(W, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOXI => new V4i(W, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOXN => new V4i(W, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOXX => new V4i(W, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOXY => new V4i(W, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOXZ => new V4i(W, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOXW => new V4i(W, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOYO => new V4i(W, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOYI => new V4i(W, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOYN => new V4i(W, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOYX => new V4i(W, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOYY => new V4i(W, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOYZ => new V4i(W, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOYW => new V4i(W, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOZO => new V4i(W, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOZI => new V4i(W, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOZN => new V4i(W, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOZX => new V4i(W, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOZY => new V4i(W, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOZZ => new V4i(W, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOZW => new V4i(W, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOWO => new V4i(W, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOWI => new V4i(W, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOWN => new V4i(W, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOWX => new V4i(W, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOWY => new V4i(W, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOWZ => new V4i(W, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WOWW => new V4i(W, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIOO => new V4i(W, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIOI => new V4i(W, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WPON => new V4i(W, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIOX => new V4i(W, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIOY => new V4i(W, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIOZ => new V4i(W, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIOW => new V4i(W, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIIO => new V4i(W, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIII => new V4i(W, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WPPN => new V4i(W, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIIX => new V4i(W, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIIY => new V4i(W, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIIZ => new V4i(W, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIIW => new V4i(W, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WPNO => new V4i(W, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WPNP => new V4i(W, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WPNN => new V4i(W, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WPNX => new V4i(W, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WPNY => new V4i(W, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WPNZ => new V4i(W, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WPNW => new V4i(W, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIXO => new V4i(W, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIXI => new V4i(W, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WPXN => new V4i(W, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIXX => new V4i(W, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIXY => new V4i(W, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIXZ => new V4i(W, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIXW => new V4i(W, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIYO => new V4i(W, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIYI => new V4i(W, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WPYN => new V4i(W, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIYX => new V4i(W, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIYY => new V4i(W, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIYZ => new V4i(W, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIYW => new V4i(W, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIZO => new V4i(W, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIZI => new V4i(W, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WPZN => new V4i(W, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIZX => new V4i(W, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIZY => new V4i(W, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIZZ => new V4i(W, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIZW => new V4i(W, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIWO => new V4i(W, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIWI => new V4i(W, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WPWN => new V4i(W, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIWX => new V4i(W, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIWY => new V4i(W, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIWZ => new V4i(W, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WIWW => new V4i(W, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNOO => new V4i(W, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNOP => new V4i(W, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNON => new V4i(W, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNOX => new V4i(W, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNOY => new V4i(W, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNOZ => new V4i(W, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNOW => new V4i(W, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNPO => new V4i(W, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNPP => new V4i(W, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNPN => new V4i(W, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNPX => new V4i(W, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNPY => new V4i(W, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNPZ => new V4i(W, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNPW => new V4i(W, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNNO => new V4i(W, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNNP => new V4i(W, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNNN => new V4i(W, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNNX => new V4i(W, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNNY => new V4i(W, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNNZ => new V4i(W, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNNW => new V4i(W, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNXO => new V4i(W, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNXP => new V4i(W, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNXN => new V4i(W, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNXX => new V4i(W, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNXY => new V4i(W, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNXZ => new V4i(W, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNXW => new V4i(W, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNYO => new V4i(W, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNYP => new V4i(W, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNYN => new V4i(W, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNYX => new V4i(W, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNYY => new V4i(W, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNYZ => new V4i(W, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNYW => new V4i(W, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNZO => new V4i(W, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNZP => new V4i(W, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNZN => new V4i(W, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNZX => new V4i(W, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNZY => new V4i(W, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNZZ => new V4i(W, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNZW => new V4i(W, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNWO => new V4i(W, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNWP => new V4i(W, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNWN => new V4i(W, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNWX => new V4i(W, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNWY => new V4i(W, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNWZ => new V4i(W, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WNWW => new V4i(W, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXOO => new V4i(W, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXOI => new V4i(W, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXON => new V4i(W, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXOX => new V4i(W, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXOY => new V4i(W, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXOZ => new V4i(W, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXOW => new V4i(W, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXIO => new V4i(W, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXII => new V4i(W, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXPN => new V4i(W, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXIX => new V4i(W, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXIY => new V4i(W, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXIZ => new V4i(W, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXIW => new V4i(W, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXNO => new V4i(W, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXNP => new V4i(W, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXNN => new V4i(W, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXNX => new V4i(W, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXNY => new V4i(W, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXNZ => new V4i(W, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXNW => new V4i(W, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXXO => new V4i(W, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXXI => new V4i(W, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXXN => new V4i(W, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXXX => new V4i(W, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXXY => new V4i(W, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXXZ => new V4i(W, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXXW => new V4i(W, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXYO => new V4i(W, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXYI => new V4i(W, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXYN => new V4i(W, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXYX => new V4i(W, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXYY => new V4i(W, X, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i WXYZ { readonly get => new V4i(W, X, Y, Z); set { W = value.X; X = value.Y; Y = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXYW => new V4i(W, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXZO => new V4i(W, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXZI => new V4i(W, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXZN => new V4i(W, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXZX => new V4i(W, X, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i WXZY { readonly get => new V4i(W, X, Z, Y); set { W = value.X; X = value.Y; Z = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXZZ => new V4i(W, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXZW => new V4i(W, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXWO => new V4i(W, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXWI => new V4i(W, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXWN => new V4i(W, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXWX => new V4i(W, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXWY => new V4i(W, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXWZ => new V4i(W, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WXWW => new V4i(W, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYOO => new V4i(W, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYOI => new V4i(W, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYON => new V4i(W, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYOX => new V4i(W, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYOY => new V4i(W, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYOZ => new V4i(W, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYOW => new V4i(W, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYIO => new V4i(W, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYII => new V4i(W, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYPN => new V4i(W, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYIX => new V4i(W, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYIY => new V4i(W, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYIZ => new V4i(W, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYIW => new V4i(W, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYNO => new V4i(W, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYNP => new V4i(W, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYNN => new V4i(W, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYNX => new V4i(W, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYNY => new V4i(W, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYNZ => new V4i(W, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYNW => new V4i(W, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYXO => new V4i(W, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYXI => new V4i(W, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYXN => new V4i(W, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYXX => new V4i(W, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYXY => new V4i(W, Y, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i WYXZ { readonly get => new V4i(W, Y, X, Z); set { W = value.X; Y = value.Y; X = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYXW => new V4i(W, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYYO => new V4i(W, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYYI => new V4i(W, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYYN => new V4i(W, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYYX => new V4i(W, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYYY => new V4i(W, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYYZ => new V4i(W, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYYW => new V4i(W, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYZO => new V4i(W, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYZI => new V4i(W, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYZN => new V4i(W, Y, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i WYZX { readonly get => new V4i(W, Y, Z, X); set { W = value.X; Y = value.Y; Z = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYZY => new V4i(W, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYZZ => new V4i(W, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYZW => new V4i(W, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYWO => new V4i(W, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYWI => new V4i(W, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYWN => new V4i(W, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYWX => new V4i(W, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYWY => new V4i(W, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYWZ => new V4i(W, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WYWW => new V4i(W, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZOO => new V4i(W, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZOI => new V4i(W, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZON => new V4i(W, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZOX => new V4i(W, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZOY => new V4i(W, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZOZ => new V4i(W, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZOW => new V4i(W, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZIO => new V4i(W, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZII => new V4i(W, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZPN => new V4i(W, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZIX => new V4i(W, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZIY => new V4i(W, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZIZ => new V4i(W, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZIW => new V4i(W, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZNO => new V4i(W, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZNP => new V4i(W, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZNN => new V4i(W, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZNX => new V4i(W, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZNY => new V4i(W, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZNZ => new V4i(W, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZNW => new V4i(W, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZXO => new V4i(W, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZXI => new V4i(W, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZXN => new V4i(W, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZXX => new V4i(W, Z, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i WZXY { readonly get => new V4i(W, Z, X, Y); set { W = value.X; Z = value.Y; X = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZXZ => new V4i(W, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZXW => new V4i(W, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZYO => new V4i(W, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZYI => new V4i(W, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZYN => new V4i(W, Z, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4i WZYX { readonly get => new V4i(W, Z, Y, X); set { W = value.X; Z = value.Y; Y = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZYY => new V4i(W, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZYZ => new V4i(W, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZYW => new V4i(W, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZZO => new V4i(W, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZZI => new V4i(W, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZZN => new V4i(W, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZZX => new V4i(W, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZZY => new V4i(W, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZZZ => new V4i(W, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZZW => new V4i(W, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZWO => new V4i(W, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZWI => new V4i(W, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZWN => new V4i(W, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZWX => new V4i(W, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZWY => new V4i(W, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZWZ => new V4i(W, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WZWW => new V4i(W, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWOO => new V4i(W, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWOI => new V4i(W, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWON => new V4i(W, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWOX => new V4i(W, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWOY => new V4i(W, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWOZ => new V4i(W, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWOW => new V4i(W, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWIO => new V4i(W, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWII => new V4i(W, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWPN => new V4i(W, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWIX => new V4i(W, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWIY => new V4i(W, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWIZ => new V4i(W, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWIW => new V4i(W, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWNO => new V4i(W, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWNP => new V4i(W, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWNN => new V4i(W, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWNX => new V4i(W, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWNY => new V4i(W, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWNZ => new V4i(W, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWNW => new V4i(W, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWXO => new V4i(W, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWXI => new V4i(W, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWXN => new V4i(W, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWXX => new V4i(W, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWXY => new V4i(W, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWXZ => new V4i(W, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWXW => new V4i(W, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWYO => new V4i(W, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWYI => new V4i(W, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWYN => new V4i(W, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWYX => new V4i(W, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWYY => new V4i(W, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWYZ => new V4i(W, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWYW => new V4i(W, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWZO => new V4i(W, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWZI => new V4i(W, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWZN => new V4i(W, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWZX => new V4i(W, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWZY => new V4i(W, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWZZ => new V4i(W, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWZW => new V4i(W, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWWO => new V4i(W, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWWI => new V4i(W, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWWN => new V4i(W, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWWX => new V4i(W, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWWY => new V4i(W, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWWZ => new V4i(W, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4i WWWW => new V4i(W, W, W, W); #endregion #region IVector Members /// /// By using long indices, the IVector<double> interface is /// accessed. /// public double this[long i] { readonly get { return (double)this[(int)i]; } set { this[(int)i] = (int)value; } } #endregion #region ISize4i Members public readonly V4i Size4i { get { return this; } } #endregion #region IVector public readonly long Dim { get { return 4; } } public readonly object GetValue(long index) { return (object)this[(int)index]; } public void SetValue(object value, long index) { this[(int)index] = (int)value; } #endregion } public class V4iEqualityComparer : IEqualityComparer { public static V4iEqualityComparer Default => new V4iEqualityComparer(); #region IEqualityComparer Members public bool Equals(V4i v0, V4i v1) { return v0 == v1; } public int GetHashCode(V4i v) { return v.GetHashCode(); } #endregion } public static partial class Fun { #region Min and Max /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Min(this V4i a, V4i b) { return new V4i(Min(a.X, b.X), Min(a.Y, b.Y), Min(a.Z, b.Z), Min(a.W, b.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Min(this V4i a, int b) { return new V4i(Min(a.X, b), Min(a.Y, b), Min(a.Z, b), Min(a.W, b)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Min(this int a, V4i b) { return new V4i(Min(a, b.X), Min(a, b.Y), Min(a, b.Z), Min(a, b.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Max(this V4i a, V4i b) { return new V4i(Max(a.X, b.X), Max(a.Y, b.Y), Max(a.Z, b.Z), Max(a.W, b.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Max(this V4i a, int b) { return new V4i(Max(a.X, b), Max(a.Y, b), Max(a.Z, b), Max(a.W, b)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Max(this int a, V4i b) { return new V4i(Max(a, b.X), Max(a, b.Y), Max(a, b.Z), Max(a, b.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Min(this V4i a, V4i b, V4i c) { return new V4i(Min(a.X, b.X, c.X), Min(a.Y, b.Y, c.Y), Min(a.Z, b.Z, c.Z), Min(a.W, b.W, c.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Max(this V4i a, V4i b, V4i c) { return new V4i(Max(a.X, b.X, c.X), Max(a.Y, b.Y, c.Y), Max(a.Z, b.Z, c.Z), Max(a.W, b.W, c.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Min(this V4i a, V4i b, V4i c, V4i d) { return new V4i(Min(a.X, b.X, c.X, d.X), Min(a.Y, b.Y, c.Y, d.Y), Min(a.Z, b.Z, c.Z, d.Z), Min(a.W, b.W, c.W, d.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Max(this V4i a, V4i b, V4i c, V4i d) { return new V4i(Max(a.X, b.X, c.X, d.X), Max(a.Y, b.Y, c.Y, d.Y), Max(a.Z, b.Z, c.Z, d.Z), Max(a.W, b.W, c.W, d.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Min(this V4i x, params V4i[] values) { return new V4i(Min(x.X, values.Map(a => a.X)), Min(x.Y, values.Map(a => a.Y)), Min(x.Z, values.Map(a => a.Z)), Min(x.W, values.Map(a => a.W))); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Max(this V4i x, params V4i[] values) { return new V4i(Max(x.X, values.Map(a => a.X)), Max(x.Y, values.Map(a => a.Y)), Max(x.Z, values.Map(a => a.Z)), Max(x.W, values.Map(a => a.W))); } #endregion #region Abs /// /// Applies Fun.Abs to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Abs(this V4i x) { return new V4i(Abs(x.X), Abs(x.Y), Abs(x.Z), Abs(x.W)); } #endregion #region Clamping /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Clamp(this V4i x, V4i a, V4i b) { return new V4i(Clamp(x.X, a.X, b.X), Clamp(x.Y, a.Y, b.Y), Clamp(x.Z, a.Z, b.Z), Clamp(x.W, a.W, b.W)); } /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Clamp(this V4i x, int a, int b) { return new V4i(Clamp(x.X, a, b), Clamp(x.Y, a, b), Clamp(x.Z, a, b), Clamp(x.W, a, b)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i ClampExcl(this V4i x, V4i a, V4i b) { return new V4i(ClampExcl(x.X, a.X, b.X), ClampExcl(x.Y, a.Y, b.Y), ClampExcl(x.Z, a.Z, b.Z), ClampExcl(x.W, a.W, b.W)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i ClampExcl(this V4i x, int a, int b) { return new V4i(ClampExcl(x.X, a, b), ClampExcl(x.Y, a, b), ClampExcl(x.Z, a, b), ClampExcl(x.W, a, b)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i ClampWrap(this V4i x, V4i a, V4i b) { return new V4i(ClampWrap(x.X, a.X, b.X), ClampWrap(x.Y, a.Y, b.Y), ClampWrap(x.Z, a.Z, b.Z), ClampWrap(x.W, a.W, b.W)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i ClampWrap(this V4i x, int a, int b) { return new V4i(ClampWrap(x.X, a, b), ClampWrap(x.Y, a, b), ClampWrap(x.Z, a, b), ClampWrap(x.W, a, b)); } /// /// Applies Fun.Saturate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Saturate(this V4i x) { return new V4i(Saturate(x.X), Saturate(x.Y), Saturate(x.Z), Saturate(x.W)); } #endregion #region Sign /// /// Applies Fun.Sign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Sign(this V4i x) { return new V4i(Sign(x.X), Sign(x.Y), Sign(x.Z), Sign(x.W)); } /// /// Applies Fun.Signumi to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Signumi(this V4i x) { return new V4i(Signumi(x.X), Signumi(x.Y), Signumi(x.Z), Signumi(x.W)); } /// /// Applies Fun.Signum to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Signum(this V4i x) { return new V4i(Signum(x.X), Signum(x.Y), Signum(x.Z), Signum(x.W)); } #endregion #region Multiply-Add /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i MultiplyAdd(V4i x, V4i y, V4i z) { return new V4i(MultiplyAdd(x.X, y.X, z.X), MultiplyAdd(x.Y, y.Y, z.Y), MultiplyAdd(x.Z, y.Z, z.Z), MultiplyAdd(x.W, y.W, z.W)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i MultiplyAdd(V4i x, int y, V4i z) { return new V4i(MultiplyAdd(x.X, y, z.X), MultiplyAdd(x.Y, y, z.Y), MultiplyAdd(x.Z, y, z.Z), MultiplyAdd(x.W, y, z.W)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i MultiplyAdd(int x, V4i y, V4i z) { return new V4i(MultiplyAdd(x, y.X, z.X), MultiplyAdd(x, y.Y, z.Y), MultiplyAdd(x, y.Z, z.Z), MultiplyAdd(x, y.W, z.W)); } #endregion #region Roots /// /// Applies Fun.Sqrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Sqrt(this V4i x) { return new V4d(Sqrt(x.X), Sqrt(x.Y), Sqrt(x.Z), Sqrt(x.W)); } /// /// Applies Fun.Cbrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Cbrt(this V4i x) { return new V4d(Cbrt(x.X), Cbrt(x.Y), Cbrt(x.Z), Cbrt(x.W)); } #endregion #region Square /// /// Applies Fun.Square to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Square(this V4i x) { return new V4i(Square(x.X), Square(x.Y), Square(x.Z), Square(x.W)); } #endregion #region Power /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Pown(this V4i x, V4i y) { return new V4i(Pown(x.X, y.X), Pown(x.Y, y.Y), Pown(x.Z, y.Z), Pown(x.W, y.W)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Pown(this V4i x, int y) { return new V4i(Pown(x.X, y), Pown(x.Y, y), Pown(x.Z, y), Pown(x.W, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Pown(this int x, V4i y) { return new V4i(Pown(x, y.X), Pown(x, y.Y), Pown(x, y.Z), Pown(x, y.W)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Pow(this V4i x, V4f y) { return new V4f(Pow(x.X, y.X), Pow(x.Y, y.Y), Pow(x.Z, y.Z), Pow(x.W, y.W)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Pow(this V4i x, float y) { return new V4f(Pow(x.X, y), Pow(x.Y, y), Pow(x.Z, y), Pow(x.W, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Pow(this int x, V4f y) { return new V4f(Pow(x, y.X), Pow(x, y.Y), Pow(x, y.Z), Pow(x, y.W)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Pow(this V4i x, V4d y) { return new V4d(Pow(x.X, y.X), Pow(x.Y, y.Y), Pow(x.Z, y.Z), Pow(x.W, y.W)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Pow(this V4i x, double y) { return new V4d(Pow(x.X, y), Pow(x.Y, y), Pow(x.Z, y), Pow(x.W, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Pow(this int x, V4d y) { return new V4d(Pow(x, y.X), Pow(x, y.Y), Pow(x, y.Z), Pow(x, y.W)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Power(this V4i x, V4f y) { return new V4f(Power(x.X, y.X), Power(x.Y, y.Y), Power(x.Z, y.Z), Power(x.W, y.W)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Power(this V4i x, float y) { return new V4f(Power(x.X, y), Power(x.Y, y), Power(x.Z, y), Power(x.W, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Power(this int x, V4f y) { return new V4f(Power(x, y.X), Power(x, y.Y), Power(x, y.Z), Power(x, y.W)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Power(this V4i x, V4d y) { return new V4d(Power(x.X, y.X), Power(x.Y, y.Y), Power(x.Z, y.Z), Power(x.W, y.W)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Power(this V4i x, double y) { return new V4d(Power(x.X, y), Power(x.Y, y), Power(x.Z, y), Power(x.W, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Power(this int x, V4d y) { return new V4d(Power(x, y.X), Power(x, y.Y), Power(x, y.Z), Power(x, y.W)); } #endregion #region Exp and Log /// /// Applies Fun.Exp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Exp(this V4i x) { return new V4d(Exp(x.X), Exp(x.Y), Exp(x.Z), Exp(x.W)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log(this V4i x) { return new V4d(Log(x.X), Log(x.Y), Log(x.Z), Log(x.W)); } /// /// Applies Fun.Log2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log2(this V4i x) { return new V4d(Log2(x.X), Log2(x.Y), Log2(x.Z), Log2(x.W)); } /// /// Applies Fun.Log2Int to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Log2Int(this V4i x) { return new V4i(Log2Int(x.X), Log2Int(x.Y), Log2Int(x.Z), Log2Int(x.W)); } /// /// Applies Fun.Log10 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log10(this V4i x) { return new V4d(Log10(x.X), Log10(x.Y), Log10(x.Z), Log10(x.W)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log(this V4i x, double basis) { return new V4d(Log(x.X, basis), Log(x.Y, basis), Log(x.Z, basis), Log(x.W, basis)); } #endregion #region ModP /// /// Applies Fun.ModP to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i ModP(this V4i a, V4i b) { return new V4i(ModP(a.X, b.X), ModP(a.Y, b.Y), ModP(a.Z, b.Z), ModP(a.W, b.W)); } #endregion #region Power of Two /// /// Applies Fun.PowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l PowerOfTwo(this V4i x) { return new V4l(PowerOfTwo(x.X), PowerOfTwo(x.Y), PowerOfTwo(x.Z), PowerOfTwo(x.W)); } /// /// Applies Fun.NextPowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i NextPowerOfTwo(this V4i x) { return new V4i(NextPowerOfTwo(x.X), NextPowerOfTwo(x.Y), NextPowerOfTwo(x.Z), NextPowerOfTwo(x.W)); } /// /// Applies Fun.PrevPowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i PrevPowerOfTwo(this V4i x) { return new V4i(PrevPowerOfTwo(x.X), PrevPowerOfTwo(x.Y), PrevPowerOfTwo(x.Z), PrevPowerOfTwo(x.W)); } #endregion #region Step functions /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Step(this V4i x, V4i edge) { return new V4i(Step(x.X, edge.X), Step(x.Y, edge.Y), Step(x.Z, edge.Z), Step(x.W, edge.W)); } /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Step(this V4i x, int edge) { return new V4i(Step(x.X, edge), Step(x.Y, edge), Step(x.Z, edge), Step(x.W, edge)); } #endregion #region Interpolation /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Lerp(this float t, V4i a, V4i b) { return new V4i(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y), Lerp(t, a.Z, b.Z), Lerp(t, a.W, b.W)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Lerp(this V4f t, V4i a, V4i b) { return new V4i(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y), Lerp(t.Z, a.Z, b.Z), Lerp(t.W, a.W, b.W)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Lerp(this double t, V4i a, V4i b) { return new V4i(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y), Lerp(t, a.Z, b.Z), Lerp(t, a.W, b.W)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Lerp(this V4d t, V4i a, V4i b) { return new V4i(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y), Lerp(t.Z, a.Z, b.Z), Lerp(t.W, a.W, b.W)); } /// /// Applies Fun.InvLerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d InvLerp(this V4i y, V4i a, V4i b) { return new V4d(InvLerp(y.X, a.X, b.X), InvLerp(y.Y, a.Y, b.Y), InvLerp(y.Z, a.Z, b.Z), InvLerp(y.W, a.W, b.W)); } #endregion #region Common Divisor and Multiple /// /// Applies Fun.GreatestCommonDivisor to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i GreatestCommonDivisor(this V4i a, V4i b) { return new V4i(GreatestCommonDivisor(a.X, b.X), GreatestCommonDivisor(a.Y, b.Y), GreatestCommonDivisor(a.Z, b.Z), GreatestCommonDivisor(a.W, b.W)); } /// /// Applies Fun.LeastCommonMultiple to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i LeastCommonMultiple(this V4i a, V4i b) { return new V4i(LeastCommonMultiple(a.X, b.X), LeastCommonMultiple(a.Y, b.Y), LeastCommonMultiple(a.Z, b.Z), LeastCommonMultiple(a.W, b.W)); } #endregion #region Floating point bits /// /// Applies Fun.FloatFromBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FloatFromBits(this V4i x) { return new V4f(FloatFromBits(x.X), FloatFromBits(x.Y), FloatFromBits(x.Z), FloatFromBits(x.W)); } #endregion #region ApproximateEquals /// /// Returns whether the given vectors are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V4i a, V4i b, int tolerance) { return ApproximateEquals(a.X, b.X, tolerance) && ApproximateEquals(a.Y, b.Y, tolerance) && ApproximateEquals(a.Z, b.Z, tolerance) && ApproximateEquals(a.W, b.W, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this V4i v, int epsilon) => Vec.AllTiny(v, epsilon); #endregion } /// /// Contains static methods /// public static partial class Vec { #region Length /// /// Returns the squared length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LengthSquared(V4i v) => v.LengthSquared; /// /// Returns the length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Length(V4i v) => v.Length; #endregion #region Normalize /// /// Returns a normalized copy of this vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Normalized(V4i v) => v.Normalized; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Norm1(V4i v) => v.Norm1; /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(V4i v) => v.Norm2; /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NormMax(V4i v) => v.NormMax; /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NormMin(V4i v) => v.NormMin; /// /// Gets the p-norm. This is calculated as the p-th root of (|x|^n + |y|^n + ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this V4i v, double p) { return ( Fun.Abs(v.X).Pow(p) + Fun.Abs(v.Y).Pow(p) + Fun.Abs(v.Z).Pow(p) + Fun.Abs(v.W).Pow(p)).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the squared distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int DistanceSquared(this V4i a, V4i b) => Fun.Square(b.X - a.X) + Fun.Square(b.Y - a.Y) + Fun.Square(b.Z - a.Z) + Fun.Square(b.W - a.W); /// /// Returns the distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V4i a, V4i b) => Fun.Sqrt(DistanceSquared(a, b)); /// /// Returns the Manhatten (or 1-) distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Distance1(this V4i a, V4i b) => Fun.Abs(b.X - a.X) + Fun.Abs(b.Y - a.Y) + Fun.Abs(b.Z - a.Z) + Fun.Abs(b.W - a.W); /// /// Returns the p-distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V4i a, V4i b, double p) => (Fun.Abs(b.X - a.X).Pow(p) + Fun.Abs(b.Y - a.Y).Pow(p) + Fun.Abs(b.Z - a.Z).Pow(p) + Fun.Abs(b.W - a.W).Pow(p)).Pow(1 / p); /// /// Returns the maximal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int DistanceMax(this V4i a, V4i b) => Fun.Max(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y), Fun.Abs(b.Z - a.Z), Fun.Abs(b.W - a.W)); /// /// Returns the minimal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int DistanceMin(this V4i a, V4i b) => Fun.Min(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y), Fun.Abs(b.Z - a.Z), Fun.Abs(b.W - a.W)); /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V4i query, V4i p0, V4i p1) { return DistanceToLine((V4d) query, (V4d) p0, (V4d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V4i query, V4i p0, V4i p1) { return DistanceToInfiniteLine((V4d) query, (V4d) p0, (V4d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V4i query, V4i p0, V4i p1, out double t) { return DistanceToLine((V4d) query, (V4d) p0, (V4d) p1, out t); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V4i query, V4i p0, V4i p1, out double t) { return DistanceToInfiniteLine((V4d) query, (V4d) p0, (V4d) p1, out t); } #endregion #region Operations /// /// Negates the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Negate(this ref V4i v) { v.X = -v.X; v.Y = -v.Y; v.Z = -v.Z; v.W = -v.W; } /// /// Returns the outer product (tensor-product) of a * b^T as a 4x4 matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44i Outer(this V4i a, V4i b) { return new M44i( a.X * b.X, a.X * b.Y, a.X * b.Z, a.X * b.W, a.Y * b.X, a.Y * b.Y, a.Y * b.Z, a.Y * b.W, a.Z * b.X, a.Z * b.Y, a.Z * b.Z, a.Z * b.W, a.W * b.X, a.W * b.Y, a.W * b.Z, a.W * b.W); } /// /// Returns the dot product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Dot(this V4i a, V4i b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z + a.W * b.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DirFlags DirFlags(this V4i v) { DirFlags flags = Aardbase.DirFlags.None; if (v.X > 0) flags |= Aardbase.DirFlags.PositiveX; if (v.X < 0) flags |= Aardbase.DirFlags.NegativeX; if (v.Y > 0) flags |= Aardbase.DirFlags.PositiveY; if (v.Y < 0) flags |= Aardbase.DirFlags.NegativeY; if (v.Z > 0) flags |= Aardbase.DirFlags.PositiveZ; if (v.Z < 0) flags |= Aardbase.DirFlags.NegativeZ; if (v.W > 0) flags |= Aardbase.DirFlags.PositiveW; if (v.W < 0) flags |= Aardbase.DirFlags.NegativeW; return flags; } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V4i a, V4i b) { return (a.X < b.X && a.Y < b.Y && a.Z < b.Z && a.W < b.W); } /// /// Returns whether ALL elements of v are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V4i v, int s) { return (v.X < s && v.Y < s && v.Z < s && v.W < s); } /// /// Returns whether a is Smaller ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(int s, V4i v) { return (s < v.X && s < v.Y && s < v.Z && s < v.W); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V4i a, V4i b) { return (a.X < b.X || a.Y < b.Y || a.Z < b.Z || a.W < b.W); } /// /// Returns whether AT LEAST ONE element of v is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V4i v, int s) { return (v.X < s || v.Y < s || v.Z < s || v.W < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(int s, V4i v) { return (s < v.X || s < v.Y || s < v.Z || s < v.W); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V4i a, V4i b) { return (a.X > b.X && a.Y > b.Y && a.Z > b.Z && a.W > b.W); } /// /// Returns whether ALL elements of v are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V4i v, int s) { return (v.X > s && v.Y > s && v.Z > s && v.W > s); } /// /// Returns whether a is Greater ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(int s, V4i v) { return (s > v.X && s > v.Y && s > v.Z && s > v.W); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V4i a, V4i b) { return (a.X > b.X || a.Y > b.Y || a.Z > b.Z || a.W > b.W); } /// /// Returns whether AT LEAST ONE element of v is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V4i v, int s) { return (v.X > s || v.Y > s || v.Z > s || v.W > s); } /// /// Returns whether a is Greater AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(int s, V4i v) { return (s > v.X || s > v.Y || s > v.Z || s > v.W); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V4i a, V4i b) { return (a.X <= b.X && a.Y <= b.Y && a.Z <= b.Z && a.W <= b.W); } /// /// Returns whether ALL elements of v are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V4i v, int s) { return (v.X <= s && v.Y <= s && v.Z <= s && v.W <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(int s, V4i v) { return (s <= v.X && s <= v.Y && s <= v.Z && s <= v.W); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V4i a, V4i b) { return (a.X <= b.X || a.Y <= b.Y || a.Z <= b.Z || a.W <= b.W); } /// /// Returns whether AT LEAST ONE element of v is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V4i v, int s) { return (v.X <= s || v.Y <= s || v.Z <= s || v.W <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(int s, V4i v) { return (s <= v.X || s <= v.Y || s <= v.Z || s <= v.W); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V4i a, V4i b) { return (a.X >= b.X && a.Y >= b.Y && a.Z >= b.Z && a.W >= b.W); } /// /// Returns whether ALL elements of v are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V4i v, int s) { return (v.X >= s && v.Y >= s && v.Z >= s && v.W >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(int s, V4i v) { return (s >= v.X && s >= v.Y && s >= v.Z && s >= v.W); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V4i a, V4i b) { return (a.X >= b.X || a.Y >= b.Y || a.Z >= b.Z || a.W >= b.W); } /// /// Returns whether AT LEAST ONE element of v is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V4i v, int s) { return (v.X >= s || v.Y >= s || v.Z >= s || v.W >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(int s, V4i v) { return (s >= v.X || s >= v.Y || s >= v.Z || s >= v.W); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V4i a, V4i b) { return (a.X == b.X && a.Y == b.Y && a.Z == b.Z && a.W == b.W); } /// /// Returns whether ALL elements of v are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V4i v, int s) { return (v.X == s && v.Y == s && v.Z == s && v.W == s); } /// /// Returns whether a is Equal ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(int s, V4i v) { return (s == v.X && s == v.Y && s == v.Z && s == v.W); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V4i a, V4i b) { return (a.X == b.X || a.Y == b.Y || a.Z == b.Z || a.W == b.W); } /// /// Returns whether AT LEAST ONE element of v is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V4i v, int s) { return (v.X == s || v.Y == s || v.Z == s || v.W == s); } /// /// Returns whether a is Equal AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(int s, V4i v) { return (s == v.X || s == v.Y || s == v.Z || s == v.W); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V4i a, V4i b) { return (a.X != b.X && a.Y != b.Y && a.Z != b.Z && a.W != b.W); } /// /// Returns whether ALL elements of v are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V4i v, int s) { return (v.X != s && v.Y != s && v.Z != s && v.W != s); } /// /// Returns whether a is Different ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(int s, V4i v) { return (s != v.X && s != v.Y && s != v.Z && s != v.W); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V4i a, V4i b) { return (a.X != b.X || a.Y != b.Y || a.Z != b.Z || a.W != b.W); } /// /// Returns whether AT LEAST ONE element of v is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V4i v, int s) { return (v.X != s || v.Y != s || v.Z != s || v.W != s); } /// /// Returns whether a is Different AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(int s, V4i v) { return (s != v.X || s != v.Y || s != v.Z || s != v.W); } /// /// Compare x-coordinate before y-coordinate, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this V4i v0, V4i v1) { if (v0.X < v1.X) return -1; if (v0.X > v1.X) return +1; if (v0.Y < v1.Y) return -1; if (v0.Y > v1.Y) return +1; if (v0.Z < v1.Z) return -1; if (v0.Z > v1.Z) return +1; if (v0.W < v1.W) return -1; if (v0.W > v1.W) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MinElement(V4i v) => v.MinElement; /// /// Returns the maximum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int MaxElement(V4i v) => v.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this V4i v, int epsilon) => v.X.IsTiny(epsilon) || v.Y.IsTiny(epsilon) || v.Z.IsTiny(epsilon) || v.W.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this V4i v, int epsilon) => v.X.IsTiny(epsilon) && v.Y.IsTiny(epsilon) && v.Z.IsTiny(epsilon) && v.W.IsTiny(epsilon); #endregion #region ArrayExtensions public static int IndexOfClosestPoint(this V4i[] pointArray, V4i point) { var bestDist = DistanceSquared(point, pointArray[0]); int bestIndex = 0; int count = pointArray.Length; for (int i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this V4i[] array, int start, int count, V4i point) { var bestDist = DistanceSquared(point, array[start]); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this T[] array, int start, int count, Func pointSelector, V4i point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint(this V4i[] pointArray, V4i point) { var bestDist = DistanceSquared(point, pointArray[0]); long bestIndex = 0; long count = pointArray.LongLength; for (long i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this V4i[] array, long start, long count, V4i point) { var bestDist = DistanceSquared(point, array[start]); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this T[] array, long start, long count, Func pointSelector, V4i point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static int IndexOfMinX(this V4i[] vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static long LongIndexOfMinX(this V4i[] vectorArray, long count = 0) { var minimum = vectorArray[0].X; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static int IndexOfMaxX(this V4i[] vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static long LongIndexOfMaxX(this V4i[] vectorArray, long count = 0) { var maximum = vectorArray[0].X; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static int IndexOfMinY(this V4i[] vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static long LongIndexOfMinY(this V4i[] vectorArray, long count = 0) { var minimum = vectorArray[0].Y; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static int IndexOfMaxY(this V4i[] vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static long LongIndexOfMaxY(this V4i[] vectorArray, long count = 0) { var maximum = vectorArray[0].Y; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static int IndexOfMinZ(this V4i[] vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static long LongIndexOfMinZ(this V4i[] vectorArray, long count = 0) { var minimum = vectorArray[0].Z; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static int IndexOfMaxZ(this V4i[] vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static long LongIndexOfMaxZ(this V4i[] vectorArray, long count = 0) { var maximum = vectorArray[0].Z; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal W coordinate /// within the array. /// public static int IndexOfMinW(this V4i[] vectorArray, int count = 0) { var minimum = vectorArray[0].W; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal W coordinate /// within the array. /// public static long LongIndexOfMinW(this V4i[] vectorArray, long count = 0) { var minimum = vectorArray[0].W; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].W; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal W coordinate /// within the array. /// public static int IndexOfMaxW(this V4i[] vectorArray, int count = 0) { var maximum = vectorArray[0].W; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal W coordinate /// within the array. /// public static long LongIndexOfMaxW(this V4i[] vectorArray, long count = 0) { var maximum = vectorArray[0].W; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].W; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the list. /// public static int IndexOfMinX(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the list. /// public static int IndexOfMaxX(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the list. /// public static int IndexOfMinY(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the list. /// public static int IndexOfMaxY(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the list. /// public static int IndexOfMinZ(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the list. /// public static int IndexOfMaxZ(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal W coordinate /// within the list. /// public static int IndexOfMinW(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].W; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal W coordinate /// within the list. /// public static int IndexOfMaxW(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].W; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the array of the index-th coordinate of each vector. /// public static int[] CopyCoord(this V4i[] self, int index) { switch (index) { case 0: return self.Map(v => v.X); case 1: return self.Map(v => v.Y); case 2: return self.Map(v => v.Z); case 3: return self.Map(v => v.W); default: throw new IndexOutOfRangeException(); } } #endregion } public static class IRandomUniformV4iExtensions { #region IRandomUniform extensions for V4i /// /// Uses UniformInt() to generate the elements of a V4i vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i UniformV4i(this IRandomUniform rnd) { return new V4i(rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt(), rnd.UniformInt()); } /// /// Uses UniformIntNonZero() to generate the elements of a V4i vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i UniformV4iNonZero(this IRandomUniform rnd) { return new V4i(rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero(), rnd.UniformIntNonZero()); } /// /// Uses UniformInt(int) to generate the elements of a V4i vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i UniformV4i(this IRandomUniform rnd, int size) { return new V4i(rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size), rnd.UniformInt(size)); } /// /// Uses UniformInt(int) to generate the elements of a V4i vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i UniformV4i(this IRandomUniform rnd, V4i size) { return new V4i(rnd.UniformInt(size.X), rnd.UniformInt(size.Y), rnd.UniformInt(size.Z), rnd.UniformInt(size.W)); } #endregion } #endregion #region V4ui [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct V4ui : IVector, ISize4ui, IFormattable, IEquatable { [DataMember] public uint X; [DataMember] public uint Y; [DataMember] public uint Z; [DataMember] public uint W; #region Constructors /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(int x, int y, int z, int w) { X = (uint)x; Y = (uint)y; Z = (uint)z; W = (uint)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(int v) { X = (uint)v; Y = (uint)v; Z = (uint)v; W = (uint)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(int[] a) { X = (uint)a[0]; Y = (uint)a[1]; Z = (uint)a[2]; W = (uint)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(int[] a, int start) { X = (uint)a[start + 0]; Y = (uint)a[start + 1]; Z = (uint)a[start + 2]; W = (uint)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(int a, V3i b) { X = (uint)a; Y = (uint)b.X; Z = (uint)b.Y; W = (uint)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V2i a, V2i b) { X = (uint)a.X; Y = (uint)a.Y; Z = (uint)b.X; W = (uint)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V3i a, int b) { X = (uint)a.X; Y = (uint)a.Y; Z = (uint)a.Z; W = (uint)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V2i a, int b, int c) { X = (uint)a.X; Y = (uint)a.Y; Z = (uint)b; W = (uint)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(int a, V2i b, int c) { X = (uint)a; Y = (uint)b.X; Z = (uint)b.Y; W = (uint)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(int a, int b, V2i c) { X = (uint)a; Y = (uint)b; Z = (uint)c.X; W = (uint)c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(uint x, uint y, uint z, uint w) { X = x; Y = y; Z = z; W = w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(uint v) { X = v; Y = v; Z = v; W = v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(uint[] a) { X = a[0]; Y = a[1]; Z = a[2]; W = a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(uint[] a, int start) { X = a[start + 0]; Y = a[start + 1]; Z = a[start + 2]; W = a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(uint a, V3ui b) { X = a; Y = b.X; Z = b.Y; W = b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V2ui a, V2ui b) { X = a.X; Y = a.Y; Z = b.X; W = b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V3ui a, uint b) { X = a.X; Y = a.Y; Z = a.Z; W = b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V2ui a, uint b, uint c) { X = a.X; Y = a.Y; Z = b; W = c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(uint a, V2ui b, uint c) { X = a; Y = b.X; Z = b.Y; W = c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(uint a, uint b, V2ui c) { X = a; Y = b; Z = c.X; W = c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(long x, long y, long z, long w) { X = (uint)x; Y = (uint)y; Z = (uint)z; W = (uint)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(long v) { X = (uint)v; Y = (uint)v; Z = (uint)v; W = (uint)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(long[] a) { X = (uint)a[0]; Y = (uint)a[1]; Z = (uint)a[2]; W = (uint)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(long[] a, int start) { X = (uint)a[start + 0]; Y = (uint)a[start + 1]; Z = (uint)a[start + 2]; W = (uint)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(long a, V3l b) { X = (uint)a; Y = (uint)b.X; Z = (uint)b.Y; W = (uint)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V2l a, V2l b) { X = (uint)a.X; Y = (uint)a.Y; Z = (uint)b.X; W = (uint)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V3l a, long b) { X = (uint)a.X; Y = (uint)a.Y; Z = (uint)a.Z; W = (uint)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V2l a, long b, long c) { X = (uint)a.X; Y = (uint)a.Y; Z = (uint)b; W = (uint)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(long a, V2l b, long c) { X = (uint)a; Y = (uint)b.X; Z = (uint)b.Y; W = (uint)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(long a, long b, V2l c) { X = (uint)a; Y = (uint)b; Z = (uint)c.X; W = (uint)c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(float x, float y, float z, float w) { X = (uint)x; Y = (uint)y; Z = (uint)z; W = (uint)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(float v) { X = (uint)v; Y = (uint)v; Z = (uint)v; W = (uint)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(float[] a) { X = (uint)a[0]; Y = (uint)a[1]; Z = (uint)a[2]; W = (uint)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(float[] a, int start) { X = (uint)a[start + 0]; Y = (uint)a[start + 1]; Z = (uint)a[start + 2]; W = (uint)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(float a, V3f b) { X = (uint)a; Y = (uint)b.X; Z = (uint)b.Y; W = (uint)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V2f a, V2f b) { X = (uint)a.X; Y = (uint)a.Y; Z = (uint)b.X; W = (uint)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V3f a, float b) { X = (uint)a.X; Y = (uint)a.Y; Z = (uint)a.Z; W = (uint)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V2f a, float b, float c) { X = (uint)a.X; Y = (uint)a.Y; Z = (uint)b; W = (uint)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(float a, V2f b, float c) { X = (uint)a; Y = (uint)b.X; Z = (uint)b.Y; W = (uint)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(float a, float b, V2f c) { X = (uint)a; Y = (uint)b; Z = (uint)c.X; W = (uint)c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(double x, double y, double z, double w) { X = (uint)x; Y = (uint)y; Z = (uint)z; W = (uint)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(double v) { X = (uint)v; Y = (uint)v; Z = (uint)v; W = (uint)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(double[] a) { X = (uint)a[0]; Y = (uint)a[1]; Z = (uint)a[2]; W = (uint)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(double[] a, int start) { X = (uint)a[start + 0]; Y = (uint)a[start + 1]; Z = (uint)a[start + 2]; W = (uint)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(double a, V3d b) { X = (uint)a; Y = (uint)b.X; Z = (uint)b.Y; W = (uint)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V2d a, V2d b) { X = (uint)a.X; Y = (uint)a.Y; Z = (uint)b.X; W = (uint)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V3d a, double b) { X = (uint)a.X; Y = (uint)a.Y; Z = (uint)a.Z; W = (uint)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V2d a, double b, double c) { X = (uint)a.X; Y = (uint)a.Y; Z = (uint)b; W = (uint)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(double a, V2d b, double c) { X = (uint)a; Y = (uint)b.X; Z = (uint)b.Y; W = (uint)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(double a, double b, V2d c) { X = (uint)a; Y = (uint)b; Z = (uint)c.X; W = (uint)c.Y; } /// /// Creates a vector from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(Func index_fun) { X = index_fun(0); Y = index_fun(1); Z = index_fun(2); W = index_fun(3); } /// /// Creates a vector from a general vector implementing the IVector<uint> interface. /// The caller has to verify that the dimension of is at least 4. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(IVector v) : this(v[0], v[1], v[2], v[3]) { } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V2i v) { X = (uint)v.X; Y = (uint)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V2ui v) { X = v.X; Y = v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V2l v) { X = (uint)v.X; Y = (uint)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V2f v) { X = (uint)v.X; Y = (uint)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V2d v) { X = (uint)v.X; Y = (uint)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V3i v) { X = (uint)v.X; Y = (uint)v.Y; Z = (uint)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V3ui v) { X = v.X; Y = v.Y; Z = v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V3l v) { X = (uint)v.X; Y = (uint)v.Y; Z = (uint)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V3f v) { X = (uint)v.X; Y = (uint)v.Y; Z = (uint)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V3d v) { X = (uint)v.X; Y = (uint)v.Y; Z = (uint)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V4i v) { X = (uint)v.X; Y = (uint)v.Y; Z = (uint)v.Z; W = (uint)v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V4ui v) { X = v.X; Y = v.Y; Z = v.Z; W = v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V4l v) { X = (uint)v.X; Y = (uint)v.Y; Z = (uint)v.Z; W = (uint)v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V4f v) { X = (uint)v.X; Y = (uint)v.Y; Z = (uint)v.Z; W = (uint)v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(V4d v) { X = (uint)v.X; Y = (uint)v.Y; Z = (uint)v.Z; W = (uint)v.W; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(C3b c) { X = (uint)(c.R); Y = (uint)(c.G); Z = (uint)(c.B); W = (uint)255; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(C3us c) { X = (uint)(c.R); Y = (uint)(c.G); Z = (uint)(c.B); W = (uint)65535; } /// /// Creates a vector from a color. /// W is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(C3ui c) { X = (c.R); Y = (c.G); Z = (c.B); W = UInt32.MaxValue; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(C4b c) { X = (uint)(c.R); Y = (uint)(c.G); Z = (uint)(c.B); W = (uint)(c.A); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(C4us c) { X = (uint)(c.R); Y = (uint)(c.G); Z = (uint)(c.B); W = (uint)(c.A); } /// /// Creates a vector from a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4ui(C4ui c) { X = (c.R); Y = (c.G); Z = (c.B); W = (c.A); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(V2i v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(V2ui v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(V2l v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(V2f v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(V2d v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(V3i v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(V3ui v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(V3l v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(V3f v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(V3d v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(V4i v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(V4l v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(V4f v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(V4d v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToV2i() => (V2i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToV2l() => (V2l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f ToV2f() => (V2f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d ToV2d() => (V2d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int[](V4ui v) => new int[] { (int)v.X, (int)v.Y, (int)v.Z, (int)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(int[] v) => new V4ui((uint)v[0], (uint)v[1], (uint)v[2], (uint)v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](V4ui v) => new uint[] { v.X, v.Y, v.Z, v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(uint[] v) => new V4ui(v[0], v[1], v[2], v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long[](V4ui v) => new long[] { (long)v.X, (long)v.Y, (long)v.Z, (long)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(long[] v) => new V4ui((uint)v[0], (uint)v[1], (uint)v[2], (uint)v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](V4ui v) => new float[] { (float)v.X, (float)v.Y, (float)v.Z, (float)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(float[] v) => new V4ui((uint)v[0], (uint)v[1], (uint)v[2], (uint)v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](V4ui v) => new double[] { (double)v.X, (double)v.Y, (double)v.Z, (double)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(double[] v) => new V4ui((uint)v[0], (uint)v[1], (uint)v[2], (uint)v[3]); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(C3b v) => new V4ui(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(C3us v) => new V4ui(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Converts the given color to a vector. /// W is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(C3ui v) => new V4ui(v); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(C4b v) => new V4ui(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(C4us v) => new V4ui(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4ui(C4ui v) => new V4ui(v); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i Copy(Func element_fun) => new V4i(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i Copy(Func element_index_fun) => new V4i(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(int[] array, int start) { array[start + 0] = (int)X; array[start + 1] = (int)Y; array[start + 2] = (int)Z; array[start + 3] = (int)W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui Copy(Func element_fun) => new V4ui(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui Copy(Func element_index_fun) => new V4ui(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(uint[] array, int start) { array[start + 0] = X; array[start + 1] = Y; array[start + 2] = Z; array[start + 3] = W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l Copy(Func element_fun) => new V4l(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l Copy(Func element_index_fun) => new V4l(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(long[] array, int start) { array[start + 0] = (long)X; array[start + 1] = (long)Y; array[start + 2] = (long)Z; array[start + 3] = (long)W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f Copy(Func element_fun) => new V4f(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f Copy(Func element_index_fun) => new V4f(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(float[] array, int start) { array[start + 0] = (float)X; array[start + 1] = (float)Y; array[start + 2] = (float)Z; array[start + 3] = (float)W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d Copy(Func element_fun) => new V4d(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d Copy(Func element_index_fun) => new V4d(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(double[] array, int start) { array[start + 0] = (double)X; array[start + 1] = (double)Y; array[start + 2] = (double)Z; array[start + 3] = (double)W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(X); array[start + 1] = element_fun(Y); array[start + 2] = element_fun(Z); array[start + 3] = element_fun(W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(X, 0); array[start + 1] = element_index_fun(Y, 1); array[start + 2] = element_index_fun(Z, 2); array[start + 3] = element_index_fun(W, 3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly uint[] ToArray() => new uint[] { X, Y, Z, W }; #endregion #region Properties and Indexers /// /// Property for the field X. /// Useful when properties are required, but the field X is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public uint P_X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value; } } /// /// Property for the field Y. /// Useful when properties are required, but the field Y is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public uint P_Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Y = value; } } /// /// Property for the field Z. /// Useful when properties are required, but the field Z is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public uint P_Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Z = value; } } /// /// Property for the field W. /// Useful when properties are required, but the field W is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public uint P_W { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { W = value; } } /// /// Enumerates all elements of this vector. /// public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return X; yield return Y; yield return Z; yield return W; } } /// /// Gets or sets element with given index. /// public unsafe uint this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (uint* ptr = &X) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (uint* ptr = &X) { ptr[index] = value; } } } /// /// Returns the index of the largest dimension of the vector. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X >= Y ? (X >= Z ? (X >= W ? 0 : 3) : (Z >= W ? 2 : 3)) : (Y >= Z ? (Y >= W ? 1 : 3) : (Z >= W ? 2 : 3)); } } /// /// Returns the index of the smallest dimension of the vector. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X <= Y ? (X <= Z ? (X <= W ? 0 : 3) : (Z <= W ? 2 : 3)) : (Y <= Z ? (Y <= W ? 1 : 3) : (Z <= W ? 2 : 3)); } } /// /// Returns the minimum element of the vector. /// public readonly uint MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(X, Y, Z, W); } /// /// Returns the maximum element of the vector. /// public readonly uint MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(X, Y, Z, W); } #endregion #region Constants /// /// Number of elements in this vector. /// public const int Dimension = 4; /// /// All elements zero. /// public static V4ui Zero { get { return new V4ui(0, 0, 0, 0); } } /// /// All elements one. /// public static V4ui One { get { return new V4ui(1, 1, 1, 1); } } /// /// All elements set to maximum possible value. /// public static V4ui MaxValue { get { return new V4ui(Constant.ParseableMaxValue, Constant.ParseableMaxValue, Constant.ParseableMaxValue, Constant.ParseableMaxValue); } } /// /// All elements set to minimum possible value. /// public static V4ui MinValue { get { return new V4ui(Constant.ParseableMinValue, Constant.ParseableMinValue, Constant.ParseableMinValue, Constant.ParseableMinValue); } } /// /// Normalized X-axis. /// public static V4ui XAxis { get { return new V4ui(1, 0, 0, 0); } } /// /// Normalized Y-axis. /// public static V4ui YAxis { get { return new V4ui(0, 1, 0, 0); } } /// /// Normalized Z-axis. /// public static V4ui ZAxis { get { return new V4ui(0, 0, 1, 0); } } /// /// Normalized W-axis. /// public static V4ui WAxis { get { return new V4ui(0, 0, 0, 1); } } /// /// An array of accessor functions for the coordinates of the vector. /// public static readonly Func[] SelectorArray = new Func[] { v => v.X, v => v.Y, v => v.Z, v => v.W }; /// /// Element getter function. /// public static readonly Func Getter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; case 3: return v.W; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref V4ui v, int i, uint s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; case 3: v.W = s; return; default: throw new IndexOutOfRangeException(); } }; /// /// Element getter function with long index. /// public static readonly Func LongGetter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; case 3: return v.W; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action with long index. /// public static readonly ActionRefValVal LongSetter = (ref V4ui v, long i, uint s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; case 3: v.W = s; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Static factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui FromV4i(V4i v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui FromV4l(V4l v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui FromV4f(V4f v) => new V4ui(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui FromV4d(V4d v) => new V4ui(v); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui FromC3b(C3b c) => new V4ui(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui FromC3us(C3us c) => new V4ui(c); /// /// Creates a vector from the given color. /// W is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui FromC3ui(C3ui c) => new V4ui(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui FromC4b(C4b c) => new V4ui(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui FromC4us(C4us c) => new V4ui(c); /// /// Creates a vector from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui FromC4ui(C4ui c) => new V4ui(c); #endregion #region Norms /// /// Returns the squared length of the vector. /// public readonly uint LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X * X + Y * Y + Z * Z + W * W ; } } /// /// Returns the length of the vector. /// public readonly double Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z + W * W ); } } /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// public readonly uint Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X + Y + Z + W; } } /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z + W * W); } } /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// public readonly uint NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(X, Y, Z, W); } } /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// public readonly uint NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(X, Y, Z, W); } } /// /// Returns a normalized copy of this vector. /// public readonly V4d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Length; if (s == 0) return V4d.Zero; s = 1 / s; return new V4d(X * s, Y * s, Z * s, W * s); } } #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui LinearInterp(float t, V4ui a, V4ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui LinearInterp(V4f t, V4ui a, V4ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui LinearInterp(double t, V4ui a, V4ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui LinearInterp(V4d t, V4ui a, V4ui b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Min(V4ui v0, V4ui v1) => Fun.Min(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Min(V4ui v, uint x) => Fun.Min(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Max(V4ui v0, V4ui v1) => Fun.Max(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Max(V4ui v, uint x) => Fun.Max(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Saturate(V4ui v) => Fun.Saturate(v); #endregion #region Operations /// /// Sets the elements of a vector to the given int elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(int x, int y, int z, int w) { X = (uint)x; Y = (uint)y; Z = (uint)z; W = (uint)w; } /// /// Sets the elements of a vector to the given uint elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(uint x, uint y, uint z, uint w) { X = x; Y = y; Z = z; W = w; } /// /// Sets the elements of a vector to the given long elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(long x, long y, long z, long w) { X = (uint)x; Y = (uint)y; Z = (uint)z; W = (uint)w; } /// /// Sets the elements of a vector to the given float elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(float x, float y, float z, float w) { X = (uint)x; Y = (uint)y; Z = (uint)z; W = (uint)w; } /// /// Sets the elements of a vector to the given double elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(double x, double y, double z, double w) { X = (uint)x; Y = (uint)y; Z = (uint)z; W = (uint)w; } /// /// Returns the component-wise bitwise complement of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator ~(V4ui v) => new V4ui(~v.X, ~v.Y, ~v.Z, ~v.W); /// /// Returns the component-wise sum of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator +(V4ui a, V4ui b) => new V4ui(a.X + b.X, a.Y + b.Y, a.Z + b.Z, a.W + b.W); /// /// Returns the component-wise sum of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator +(V4ui v, uint s) => new V4ui(v.X + s, v.Y + s, v.Z + s, v.W + s); /// /// Returns the component-wise sum of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator +(uint s, V4ui v) => new V4ui(s + v.X, s + v.Y, s + v.Z, s + v.W); /// /// Returns the component-wise difference of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator -(V4ui a, V4ui b) => new V4ui(a.X - b.X, a.Y - b.Y, a.Z - b.Z, a.W - b.W); /// /// Returns the component-wise difference of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator -(V4ui v, uint s) => new V4ui(v.X - s, v.Y - s, v.Z - s, v.W - s); /// /// Returns the component-wise difference of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator -(uint s, V4ui v) => new V4ui(s - v.X, s - v.Y, s - v.Z, s - v.W); /// /// Returns the component-wise product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator *(V4ui a, V4ui b) => new V4ui(a.X * b.X, a.Y * b.Y, a.Z * b.Z, a.W * b.W); /// /// Returns the component-wise product of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator *(V4ui v, uint s) => new V4ui(v.X * s, v.Y * s, v.Z * s, v.W * s); /// /// Returns the component-wise product of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator *(uint s, V4ui v) => new V4ui(s * v.X, s * v.Y, s * v.Z, s * v.W); /// /// Returns the component-wise fraction of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator /(V4ui a, V4ui b) => new V4ui(a.X / b.X, a.Y / b.Y, a.Z / b.Z, a.W / b.W); /// /// Returns the component-wise fraction of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator /(V4ui v, uint s) => new V4ui(v.X / s, v.Y / s, v.Z / s, v.W / s); /// /// Returns the component-wise fraction of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator /(uint s, V4ui v) => new V4ui(s / v.X, s / v.Y, s / v.Z, s / v.W); /// /// Returns the component-wise remainder of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator %(V4ui a, V4ui b) => new V4ui(a.X % b.X, a.Y % b.Y, a.Z % b.Z, a.W % b.W); /// /// Returns the component-wise remainder of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator %(V4ui v, uint s) => new V4ui(v.X % s, v.Y % s, v.Z % s, v.W % s); /// /// Returns the component-wise remainder of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator %(uint s, V4ui v) => new V4ui(s % v.X, s % v.Y, s % v.Z, s % v.W); /// /// Returns the component-wise bitwise and of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator &(V4ui a, V4ui b) => new V4ui(a.X & b.X, a.Y & b.Y, a.Z & b.Z, a.W & b.W); /// /// Returns the component-wise bitwise and of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator &(V4ui v, uint s) => new V4ui(v.X & s, v.Y & s, v.Z & s, v.W & s); /// /// Returns the component-wise bitwise and of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator &(uint s, V4ui v) => new V4ui(s & v.X, s & v.Y, s & v.Z, s & v.W); /// /// Returns the component-wise bitwise or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator |(V4ui a, V4ui b) => new V4ui(a.X | b.X, a.Y | b.Y, a.Z | b.Z, a.W | b.W); /// /// Returns the component-wise bitwise or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator |(V4ui v, uint s) => new V4ui(v.X | s, v.Y | s, v.Z | s, v.W | s); /// /// Returns the component-wise bitwise or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator |(uint s, V4ui v) => new V4ui(s | v.X, s | v.Y, s | v.Z, s | v.W); /// /// Returns the component-wise bitwise exclusive or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator ^(V4ui a, V4ui b) => new V4ui(a.X ^ b.X, a.Y ^ b.Y, a.Z ^ b.Z, a.W ^ b.W); /// /// Returns the component-wise bitwise exclusive or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator ^(V4ui v, uint s) => new V4ui(v.X ^ s, v.Y ^ s, v.Z ^ s, v.W ^ s); /// /// Returns the component-wise bitwise exclusive or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator ^(uint s, V4ui v) => new V4ui(s ^ v.X, s ^ v.Y, s ^ v.Z, s ^ v.W); /// /// Returns the component-wise left bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator <<(V4ui v, int s) => new V4ui(v.X << s, v.Y << s, v.Z << s, v.W << s); /// /// Returns the component-wise right bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui operator >>(V4ui v, int s) => new V4ui(v.X >> s, v.Y >> s, v.Z >> s, v.W >> s); /// Attention: NEVER implement operators <, <=, >=, >, /// since these are not defined in a Vector space. /// Use AllSmaller() and similar comparators! #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V4ui a, V4ui b) { return a.X == b.X && a.Y == b.Y && a.Z == b.Z && a.W == b.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V4ui v, uint s) { return v.X == s && v.Y == s && v.Z == s && v.W == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(uint s, V4ui v) { return s == v.X && s == v.Y && s == v.Z && s == v.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V4ui a, V4ui b) { return a.X != b.X || a.Y != b.Y || a.Z != b.Z || a.W != b.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V4ui v, uint s) { return v.X != s || v.Y != s || v.Z != s || v.W != s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(uint s, V4ui v) { return s != v.X || s != v.Y || s != v.Z || s != v.W; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(V4ui other) { return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && W.Equals(other.W); } #endregion #region Overrides public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + X.ToString(format, fp) + between + Y.ToString(format, fp) + between + Z.ToString(format, fp) + between + W.ToString(format, fp) + end; } public override readonly int GetHashCode() { return HashCode.GetCombined(X, Y, Z, W); } public override readonly bool Equals(object other) => (other is V4ui o) ? Equals(o) : false; public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + X.ToString(null, CultureInfo.InvariantCulture) + ", " + Y.ToString(null, CultureInfo.InvariantCulture) + ", " + Z.ToString(null, CultureInfo.InvariantCulture) + ", " + W.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Parsing public static V4ui Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new V4ui( uint.Parse(x[0], CultureInfo.InvariantCulture), uint.Parse(x[1], CultureInfo.InvariantCulture), uint.Parse(x[2], CultureInfo.InvariantCulture), uint.Parse(x[3], CultureInfo.InvariantCulture) ); } public static V4ui Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, V4ui.Setter); } public static V4ui Parse(Text t, int bracketLevel) { return t.NestedBracketSplit(bracketLevel, Text.Parse, V4ui.Setter); } #endregion #region Swizzle Methods [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui OX => new V2ui(0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui OY => new V2ui(0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui OZ => new V2ui(0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui OW => new V2ui(0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui IX => new V2ui(1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui IY => new V2ui(1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui IZ => new V2ui(1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui IW => new V2ui(1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui XO => new V2ui(X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui XI => new V2ui(X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui XX => new V2ui(X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui XY { readonly get => new V2ui(X, Y); set { X = value.X; Y = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui XZ { readonly get => new V2ui(X, Z); set { X = value.X; Z = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui XW { readonly get => new V2ui(X, W); set { X = value.X; W = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui YO => new V2ui(Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui YI => new V2ui(Y, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui YX { readonly get => new V2ui(Y, X); set { Y = value.X; X = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui YY => new V2ui(Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui YZ { readonly get => new V2ui(Y, Z); set { Y = value.X; Z = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui YW { readonly get => new V2ui(Y, W); set { Y = value.X; W = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui ZO => new V2ui(Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui ZI => new V2ui(Z, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui ZX { readonly get => new V2ui(Z, X); set { Z = value.X; X = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui ZY { readonly get => new V2ui(Z, Y); set { Z = value.X; Y = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui ZZ => new V2ui(Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui ZW { readonly get => new V2ui(Z, W); set { Z = value.X; W = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui WO => new V2ui(W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui WI => new V2ui(W, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui WX { readonly get => new V2ui(W, X); set { W = value.X; X = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui WY { readonly get => new V2ui(W, Y); set { W = value.X; Y = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2ui WZ { readonly get => new V2ui(W, Z); set { W = value.X; Z = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2ui WW => new V2ui(W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OOX => new V3ui(0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OOY => new V3ui(0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OOZ => new V3ui(0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OOW => new V3ui(0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OIX => new V3ui(0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OIY => new V3ui(0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OIZ => new V3ui(0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OIW => new V3ui(0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OXO => new V3ui(0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OXI => new V3ui(0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OXX => new V3ui(0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OXY => new V3ui(0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OXZ => new V3ui(0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OXW => new V3ui(0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OYO => new V3ui(0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OYI => new V3ui(0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OYX => new V3ui(0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OYY => new V3ui(0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OYZ => new V3ui(0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OYW => new V3ui(0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OZO => new V3ui(0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OZI => new V3ui(0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OZX => new V3ui(0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OZY => new V3ui(0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OZZ => new V3ui(0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OZW => new V3ui(0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OWO => new V3ui(0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OWI => new V3ui(0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OWX => new V3ui(0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OWY => new V3ui(0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OWZ => new V3ui(0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui OWW => new V3ui(0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IOX => new V3ui(1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IOY => new V3ui(1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IOZ => new V3ui(1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IOW => new V3ui(1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IIX => new V3ui(1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IIY => new V3ui(1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IIZ => new V3ui(1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IIW => new V3ui(1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IXO => new V3ui(1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IXI => new V3ui(1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IXX => new V3ui(1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IXY => new V3ui(1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IXZ => new V3ui(1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IXW => new V3ui(1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IYO => new V3ui(1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IYI => new V3ui(1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IYX => new V3ui(1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IYY => new V3ui(1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IYZ => new V3ui(1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IYW => new V3ui(1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IZO => new V3ui(1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IZI => new V3ui(1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IZX => new V3ui(1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IZY => new V3ui(1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IZZ => new V3ui(1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IZW => new V3ui(1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IWO => new V3ui(1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IWI => new V3ui(1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IWX => new V3ui(1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IWY => new V3ui(1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IWZ => new V3ui(1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui IWW => new V3ui(1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XOO => new V3ui(X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XOI => new V3ui(X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XOX => new V3ui(X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XOY => new V3ui(X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XOZ => new V3ui(X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XOW => new V3ui(X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XIO => new V3ui(X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XII => new V3ui(X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XIX => new V3ui(X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XIY => new V3ui(X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XIZ => new V3ui(X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XIW => new V3ui(X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XXO => new V3ui(X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XXI => new V3ui(X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XXX => new V3ui(X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XXY => new V3ui(X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XXZ => new V3ui(X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XXW => new V3ui(X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XYO => new V3ui(X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XYI => new V3ui(X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XYX => new V3ui(X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XYY => new V3ui(X, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui XYZ { readonly get => new V3ui(X, Y, Z); set { X = value.X; Y = value.Y; Z = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui XYW { readonly get => new V3ui(X, Y, W); set { X = value.X; Y = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XZO => new V3ui(X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XZI => new V3ui(X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XZX => new V3ui(X, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui XZY { readonly get => new V3ui(X, Z, Y); set { X = value.X; Z = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XZZ => new V3ui(X, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui XZW { readonly get => new V3ui(X, Z, W); set { X = value.X; Z = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XWO => new V3ui(X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XWI => new V3ui(X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XWX => new V3ui(X, W, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui XWY { readonly get => new V3ui(X, W, Y); set { X = value.X; W = value.Y; Y = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui XWZ { readonly get => new V3ui(X, W, Z); set { X = value.X; W = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui XWW => new V3ui(X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YOO => new V3ui(Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YOI => new V3ui(Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YOX => new V3ui(Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YOY => new V3ui(Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YOZ => new V3ui(Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YOW => new V3ui(Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YIO => new V3ui(Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YII => new V3ui(Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YIX => new V3ui(Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YIY => new V3ui(Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YIZ => new V3ui(Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YIW => new V3ui(Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YXO => new V3ui(Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YXI => new V3ui(Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YXX => new V3ui(Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YXY => new V3ui(Y, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui YXZ { readonly get => new V3ui(Y, X, Z); set { Y = value.X; X = value.Y; Z = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui YXW { readonly get => new V3ui(Y, X, W); set { Y = value.X; X = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YYO => new V3ui(Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YYI => new V3ui(Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YYX => new V3ui(Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YYY => new V3ui(Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YYZ => new V3ui(Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YYW => new V3ui(Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YZO => new V3ui(Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YZI => new V3ui(Y, Z, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui YZX { readonly get => new V3ui(Y, Z, X); set { Y = value.X; Z = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YZY => new V3ui(Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YZZ => new V3ui(Y, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui YZW { readonly get => new V3ui(Y, Z, W); set { Y = value.X; Z = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YWO => new V3ui(Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YWI => new V3ui(Y, W, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui YWX { readonly get => new V3ui(Y, W, X); set { Y = value.X; W = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YWY => new V3ui(Y, W, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui YWZ { readonly get => new V3ui(Y, W, Z); set { Y = value.X; W = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui YWW => new V3ui(Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZOO => new V3ui(Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZOI => new V3ui(Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZOX => new V3ui(Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZOY => new V3ui(Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZOZ => new V3ui(Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZOW => new V3ui(Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZIO => new V3ui(Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZII => new V3ui(Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZIX => new V3ui(Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZIY => new V3ui(Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZIZ => new V3ui(Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZIW => new V3ui(Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZXO => new V3ui(Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZXI => new V3ui(Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZXX => new V3ui(Z, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui ZXY { readonly get => new V3ui(Z, X, Y); set { Z = value.X; X = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZXZ => new V3ui(Z, X, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui ZXW { readonly get => new V3ui(Z, X, W); set { Z = value.X; X = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZYO => new V3ui(Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZYI => new V3ui(Z, Y, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui ZYX { readonly get => new V3ui(Z, Y, X); set { Z = value.X; Y = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZYY => new V3ui(Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZYZ => new V3ui(Z, Y, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui ZYW { readonly get => new V3ui(Z, Y, W); set { Z = value.X; Y = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZZO => new V3ui(Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZZI => new V3ui(Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZZX => new V3ui(Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZZY => new V3ui(Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZZZ => new V3ui(Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZZW => new V3ui(Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZWO => new V3ui(Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZWI => new V3ui(Z, W, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui ZWX { readonly get => new V3ui(Z, W, X); set { Z = value.X; W = value.Y; X = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui ZWY { readonly get => new V3ui(Z, W, Y); set { Z = value.X; W = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZWZ => new V3ui(Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui ZWW => new V3ui(Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WOO => new V3ui(W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WOI => new V3ui(W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WOX => new V3ui(W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WOY => new V3ui(W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WOZ => new V3ui(W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WOW => new V3ui(W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WIO => new V3ui(W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WII => new V3ui(W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WIX => new V3ui(W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WIY => new V3ui(W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WIZ => new V3ui(W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WIW => new V3ui(W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WXO => new V3ui(W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WXI => new V3ui(W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WXX => new V3ui(W, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui WXY { readonly get => new V3ui(W, X, Y); set { W = value.X; X = value.Y; Y = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui WXZ { readonly get => new V3ui(W, X, Z); set { W = value.X; X = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WXW => new V3ui(W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WYO => new V3ui(W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WYI => new V3ui(W, Y, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui WYX { readonly get => new V3ui(W, Y, X); set { W = value.X; Y = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WYY => new V3ui(W, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui WYZ { readonly get => new V3ui(W, Y, Z); set { W = value.X; Y = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WYW => new V3ui(W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WZO => new V3ui(W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WZI => new V3ui(W, Z, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui WZX { readonly get => new V3ui(W, Z, X); set { W = value.X; Z = value.Y; X = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3ui WZY { readonly get => new V3ui(W, Z, Y); set { W = value.X; Z = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WZZ => new V3ui(W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WZW => new V3ui(W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WWO => new V3ui(W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WWI => new V3ui(W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WWX => new V3ui(W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WWY => new V3ui(W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WWZ => new V3ui(W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3ui WWW => new V3ui(W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4ui OOOO => new V4ui(0, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4ui OOOI => new V4ui(0, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOOX => new V4ui(0, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOOY => new V4ui(0, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOOZ => new V4ui(0, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOOW => new V4ui(0, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4ui OOIO => new V4ui(0, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4ui OOII => new V4ui(0, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOIX => new V4ui(0, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOIY => new V4ui(0, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOIZ => new V4ui(0, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOIW => new V4ui(0, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOXO => new V4ui(0, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOXI => new V4ui(0, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOXX => new V4ui(0, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOXY => new V4ui(0, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOXZ => new V4ui(0, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOXW => new V4ui(0, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOYO => new V4ui(0, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOYI => new V4ui(0, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOYX => new V4ui(0, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOYY => new V4ui(0, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOYZ => new V4ui(0, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOYW => new V4ui(0, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOZO => new V4ui(0, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOZI => new V4ui(0, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOZX => new V4ui(0, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOZY => new V4ui(0, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOZZ => new V4ui(0, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOZW => new V4ui(0, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOWO => new V4ui(0, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOWI => new V4ui(0, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOWX => new V4ui(0, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOWY => new V4ui(0, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOWZ => new V4ui(0, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OOWW => new V4ui(0, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4ui OIOO => new V4ui(0, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4ui OIOI => new V4ui(0, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIOX => new V4ui(0, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIOY => new V4ui(0, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIOZ => new V4ui(0, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIOW => new V4ui(0, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4ui OIIO => new V4ui(0, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4ui OIII => new V4ui(0, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIIX => new V4ui(0, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIIY => new V4ui(0, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIIZ => new V4ui(0, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIIW => new V4ui(0, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIXO => new V4ui(0, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIXI => new V4ui(0, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIXX => new V4ui(0, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIXY => new V4ui(0, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIXZ => new V4ui(0, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIXW => new V4ui(0, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIYO => new V4ui(0, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIYI => new V4ui(0, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIYX => new V4ui(0, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIYY => new V4ui(0, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIYZ => new V4ui(0, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIYW => new V4ui(0, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIZO => new V4ui(0, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIZI => new V4ui(0, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIZX => new V4ui(0, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIZY => new V4ui(0, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIZZ => new V4ui(0, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIZW => new V4ui(0, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIWO => new V4ui(0, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIWI => new V4ui(0, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIWX => new V4ui(0, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIWY => new V4ui(0, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIWZ => new V4ui(0, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OIWW => new V4ui(0, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXOO => new V4ui(0, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXOI => new V4ui(0, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXOX => new V4ui(0, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXOY => new V4ui(0, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXOZ => new V4ui(0, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXOW => new V4ui(0, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXIO => new V4ui(0, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXII => new V4ui(0, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXIX => new V4ui(0, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXIY => new V4ui(0, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXIZ => new V4ui(0, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXIW => new V4ui(0, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXXO => new V4ui(0, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXXI => new V4ui(0, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXXX => new V4ui(0, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXXY => new V4ui(0, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXXZ => new V4ui(0, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXXW => new V4ui(0, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXYO => new V4ui(0, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXYI => new V4ui(0, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXYX => new V4ui(0, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXYY => new V4ui(0, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXYZ => new V4ui(0, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXYW => new V4ui(0, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXZO => new V4ui(0, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXZI => new V4ui(0, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXZX => new V4ui(0, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXZY => new V4ui(0, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXZZ => new V4ui(0, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXZW => new V4ui(0, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXWO => new V4ui(0, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXWI => new V4ui(0, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXWX => new V4ui(0, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXWY => new V4ui(0, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXWZ => new V4ui(0, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OXWW => new V4ui(0, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYOO => new V4ui(0, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYOI => new V4ui(0, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYOX => new V4ui(0, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYOY => new V4ui(0, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYOZ => new V4ui(0, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYOW => new V4ui(0, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYIO => new V4ui(0, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYII => new V4ui(0, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYIX => new V4ui(0, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYIY => new V4ui(0, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYIZ => new V4ui(0, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYIW => new V4ui(0, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYXO => new V4ui(0, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYXI => new V4ui(0, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYXX => new V4ui(0, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYXY => new V4ui(0, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYXZ => new V4ui(0, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYXW => new V4ui(0, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYYO => new V4ui(0, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYYI => new V4ui(0, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYYX => new V4ui(0, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYYY => new V4ui(0, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYYZ => new V4ui(0, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYYW => new V4ui(0, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYZO => new V4ui(0, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYZI => new V4ui(0, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYZX => new V4ui(0, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYZY => new V4ui(0, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYZZ => new V4ui(0, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYZW => new V4ui(0, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYWO => new V4ui(0, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYWI => new V4ui(0, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYWX => new V4ui(0, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYWY => new V4ui(0, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYWZ => new V4ui(0, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OYWW => new V4ui(0, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZOO => new V4ui(0, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZOI => new V4ui(0, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZOX => new V4ui(0, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZOY => new V4ui(0, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZOZ => new V4ui(0, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZOW => new V4ui(0, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZIO => new V4ui(0, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZII => new V4ui(0, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZIX => new V4ui(0, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZIY => new V4ui(0, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZIZ => new V4ui(0, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZIW => new V4ui(0, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZXO => new V4ui(0, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZXI => new V4ui(0, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZXX => new V4ui(0, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZXY => new V4ui(0, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZXZ => new V4ui(0, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZXW => new V4ui(0, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZYO => new V4ui(0, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZYI => new V4ui(0, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZYX => new V4ui(0, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZYY => new V4ui(0, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZYZ => new V4ui(0, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZYW => new V4ui(0, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZZO => new V4ui(0, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZZI => new V4ui(0, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZZX => new V4ui(0, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZZY => new V4ui(0, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZZZ => new V4ui(0, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZZW => new V4ui(0, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZWO => new V4ui(0, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZWI => new V4ui(0, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZWX => new V4ui(0, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZWY => new V4ui(0, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZWZ => new V4ui(0, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OZWW => new V4ui(0, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWOO => new V4ui(0, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWOI => new V4ui(0, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWOX => new V4ui(0, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWOY => new V4ui(0, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWOZ => new V4ui(0, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWOW => new V4ui(0, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWIO => new V4ui(0, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWII => new V4ui(0, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWIX => new V4ui(0, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWIY => new V4ui(0, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWIZ => new V4ui(0, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWIW => new V4ui(0, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWXO => new V4ui(0, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWXI => new V4ui(0, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWXX => new V4ui(0, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWXY => new V4ui(0, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWXZ => new V4ui(0, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWXW => new V4ui(0, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWYO => new V4ui(0, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWYI => new V4ui(0, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWYX => new V4ui(0, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWYY => new V4ui(0, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWYZ => new V4ui(0, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWYW => new V4ui(0, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWZO => new V4ui(0, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWZI => new V4ui(0, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWZX => new V4ui(0, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWZY => new V4ui(0, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWZZ => new V4ui(0, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWZW => new V4ui(0, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWWO => new V4ui(0, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWWI => new V4ui(0, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWWX => new V4ui(0, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWWY => new V4ui(0, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWWZ => new V4ui(0, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui OWWW => new V4ui(0, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4ui IOOO => new V4ui(1, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4ui IOOI => new V4ui(1, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOOX => new V4ui(1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOOY => new V4ui(1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOOZ => new V4ui(1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOOW => new V4ui(1, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4ui IOIO => new V4ui(1, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4ui IOII => new V4ui(1, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOIX => new V4ui(1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOIY => new V4ui(1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOIZ => new V4ui(1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOIW => new V4ui(1, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOXO => new V4ui(1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOXI => new V4ui(1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOXX => new V4ui(1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOXY => new V4ui(1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOXZ => new V4ui(1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOXW => new V4ui(1, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOYO => new V4ui(1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOYI => new V4ui(1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOYX => new V4ui(1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOYY => new V4ui(1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOYZ => new V4ui(1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOYW => new V4ui(1, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOZO => new V4ui(1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOZI => new V4ui(1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOZX => new V4ui(1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOZY => new V4ui(1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOZZ => new V4ui(1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOZW => new V4ui(1, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOWO => new V4ui(1, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOWI => new V4ui(1, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOWX => new V4ui(1, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOWY => new V4ui(1, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOWZ => new V4ui(1, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IOWW => new V4ui(1, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4ui IIOO => new V4ui(1, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4ui IIOI => new V4ui(1, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIOX => new V4ui(1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIOY => new V4ui(1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIOZ => new V4ui(1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIOW => new V4ui(1, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4ui IIIO => new V4ui(1, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4ui IIII => new V4ui(1, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIIX => new V4ui(1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIIY => new V4ui(1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIIZ => new V4ui(1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIIW => new V4ui(1, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIXO => new V4ui(1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIXI => new V4ui(1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIXX => new V4ui(1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIXY => new V4ui(1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIXZ => new V4ui(1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIXW => new V4ui(1, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIYO => new V4ui(1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIYI => new V4ui(1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIYX => new V4ui(1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIYY => new V4ui(1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIYZ => new V4ui(1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIYW => new V4ui(1, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIZO => new V4ui(1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIZI => new V4ui(1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIZX => new V4ui(1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIZY => new V4ui(1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIZZ => new V4ui(1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIZW => new V4ui(1, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIWO => new V4ui(1, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIWI => new V4ui(1, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIWX => new V4ui(1, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIWY => new V4ui(1, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIWZ => new V4ui(1, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IIWW => new V4ui(1, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXOO => new V4ui(1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXOI => new V4ui(1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXOX => new V4ui(1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXOY => new V4ui(1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXOZ => new V4ui(1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXOW => new V4ui(1, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXIO => new V4ui(1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXII => new V4ui(1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXIX => new V4ui(1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXIY => new V4ui(1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXIZ => new V4ui(1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXIW => new V4ui(1, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXXO => new V4ui(1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXXI => new V4ui(1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXXX => new V4ui(1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXXY => new V4ui(1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXXZ => new V4ui(1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXXW => new V4ui(1, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXYO => new V4ui(1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXYI => new V4ui(1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXYX => new V4ui(1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXYY => new V4ui(1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXYZ => new V4ui(1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXYW => new V4ui(1, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXZO => new V4ui(1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXZI => new V4ui(1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXZX => new V4ui(1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXZY => new V4ui(1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXZZ => new V4ui(1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXZW => new V4ui(1, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXWO => new V4ui(1, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXWI => new V4ui(1, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXWX => new V4ui(1, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXWY => new V4ui(1, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXWZ => new V4ui(1, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IXWW => new V4ui(1, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYOO => new V4ui(1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYOI => new V4ui(1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYOX => new V4ui(1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYOY => new V4ui(1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYOZ => new V4ui(1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYOW => new V4ui(1, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYIO => new V4ui(1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYII => new V4ui(1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYIX => new V4ui(1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYIY => new V4ui(1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYIZ => new V4ui(1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYIW => new V4ui(1, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYXO => new V4ui(1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYXI => new V4ui(1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYXX => new V4ui(1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYXY => new V4ui(1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYXZ => new V4ui(1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYXW => new V4ui(1, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYYO => new V4ui(1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYYI => new V4ui(1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYYX => new V4ui(1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYYY => new V4ui(1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYYZ => new V4ui(1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYYW => new V4ui(1, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYZO => new V4ui(1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYZI => new V4ui(1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYZX => new V4ui(1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYZY => new V4ui(1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYZZ => new V4ui(1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYZW => new V4ui(1, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYWO => new V4ui(1, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYWI => new V4ui(1, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYWX => new V4ui(1, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYWY => new V4ui(1, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYWZ => new V4ui(1, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IYWW => new V4ui(1, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZOO => new V4ui(1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZOI => new V4ui(1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZOX => new V4ui(1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZOY => new V4ui(1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZOZ => new V4ui(1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZOW => new V4ui(1, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZIO => new V4ui(1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZII => new V4ui(1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZIX => new V4ui(1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZIY => new V4ui(1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZIZ => new V4ui(1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZIW => new V4ui(1, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZXO => new V4ui(1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZXI => new V4ui(1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZXX => new V4ui(1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZXY => new V4ui(1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZXZ => new V4ui(1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZXW => new V4ui(1, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZYO => new V4ui(1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZYI => new V4ui(1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZYX => new V4ui(1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZYY => new V4ui(1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZYZ => new V4ui(1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZYW => new V4ui(1, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZZO => new V4ui(1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZZI => new V4ui(1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZZX => new V4ui(1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZZY => new V4ui(1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZZZ => new V4ui(1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZZW => new V4ui(1, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZWO => new V4ui(1, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZWI => new V4ui(1, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZWX => new V4ui(1, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZWY => new V4ui(1, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZWZ => new V4ui(1, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IZWW => new V4ui(1, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWOO => new V4ui(1, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWOI => new V4ui(1, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWOX => new V4ui(1, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWOY => new V4ui(1, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWOZ => new V4ui(1, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWOW => new V4ui(1, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWIO => new V4ui(1, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWII => new V4ui(1, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWIX => new V4ui(1, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWIY => new V4ui(1, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWIZ => new V4ui(1, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWIW => new V4ui(1, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWXO => new V4ui(1, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWXI => new V4ui(1, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWXX => new V4ui(1, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWXY => new V4ui(1, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWXZ => new V4ui(1, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWXW => new V4ui(1, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWYO => new V4ui(1, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWYI => new V4ui(1, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWYX => new V4ui(1, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWYY => new V4ui(1, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWYZ => new V4ui(1, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWYW => new V4ui(1, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWZO => new V4ui(1, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWZI => new V4ui(1, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWZX => new V4ui(1, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWZY => new V4ui(1, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWZZ => new V4ui(1, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWZW => new V4ui(1, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWWO => new V4ui(1, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWWI => new V4ui(1, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWWX => new V4ui(1, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWWY => new V4ui(1, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWWZ => new V4ui(1, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui IWWW => new V4ui(1, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOOO => new V4ui(X, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOOI => new V4ui(X, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOOX => new V4ui(X, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOOY => new V4ui(X, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOOZ => new V4ui(X, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOOW => new V4ui(X, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOIO => new V4ui(X, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOII => new V4ui(X, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOIX => new V4ui(X, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOIY => new V4ui(X, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOIZ => new V4ui(X, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOIW => new V4ui(X, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOXO => new V4ui(X, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOXI => new V4ui(X, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOXX => new V4ui(X, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOXY => new V4ui(X, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOXZ => new V4ui(X, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOXW => new V4ui(X, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOYO => new V4ui(X, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOYI => new V4ui(X, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOYX => new V4ui(X, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOYY => new V4ui(X, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOYZ => new V4ui(X, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOYW => new V4ui(X, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOZO => new V4ui(X, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOZI => new V4ui(X, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOZX => new V4ui(X, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOZY => new V4ui(X, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOZZ => new V4ui(X, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOZW => new V4ui(X, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOWO => new V4ui(X, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOWI => new V4ui(X, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOWX => new V4ui(X, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOWY => new V4ui(X, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOWZ => new V4ui(X, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XOWW => new V4ui(X, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIOO => new V4ui(X, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIOI => new V4ui(X, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIOX => new V4ui(X, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIOY => new V4ui(X, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIOZ => new V4ui(X, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIOW => new V4ui(X, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIIO => new V4ui(X, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIII => new V4ui(X, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIIX => new V4ui(X, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIIY => new V4ui(X, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIIZ => new V4ui(X, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIIW => new V4ui(X, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIXO => new V4ui(X, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIXI => new V4ui(X, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIXX => new V4ui(X, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIXY => new V4ui(X, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIXZ => new V4ui(X, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIXW => new V4ui(X, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIYO => new V4ui(X, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIYI => new V4ui(X, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIYX => new V4ui(X, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIYY => new V4ui(X, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIYZ => new V4ui(X, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIYW => new V4ui(X, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIZO => new V4ui(X, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIZI => new V4ui(X, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIZX => new V4ui(X, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIZY => new V4ui(X, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIZZ => new V4ui(X, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIZW => new V4ui(X, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIWO => new V4ui(X, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIWI => new V4ui(X, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIWX => new V4ui(X, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIWY => new V4ui(X, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIWZ => new V4ui(X, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XIWW => new V4ui(X, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXOO => new V4ui(X, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXOI => new V4ui(X, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXOX => new V4ui(X, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXOY => new V4ui(X, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXOZ => new V4ui(X, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXOW => new V4ui(X, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXIO => new V4ui(X, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXII => new V4ui(X, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXIX => new V4ui(X, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXIY => new V4ui(X, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXIZ => new V4ui(X, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXIW => new V4ui(X, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXXO => new V4ui(X, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXXI => new V4ui(X, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXXX => new V4ui(X, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXXY => new V4ui(X, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXXZ => new V4ui(X, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXXW => new V4ui(X, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXYO => new V4ui(X, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXYI => new V4ui(X, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXYX => new V4ui(X, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXYY => new V4ui(X, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXYZ => new V4ui(X, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXYW => new V4ui(X, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXZO => new V4ui(X, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXZI => new V4ui(X, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXZX => new V4ui(X, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXZY => new V4ui(X, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXZZ => new V4ui(X, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXZW => new V4ui(X, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXWO => new V4ui(X, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXWI => new V4ui(X, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXWX => new V4ui(X, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXWY => new V4ui(X, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXWZ => new V4ui(X, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XXWW => new V4ui(X, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYOO => new V4ui(X, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYOI => new V4ui(X, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYOX => new V4ui(X, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYOY => new V4ui(X, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYOZ => new V4ui(X, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYOW => new V4ui(X, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYIO => new V4ui(X, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYII => new V4ui(X, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYIX => new V4ui(X, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYIY => new V4ui(X, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYIZ => new V4ui(X, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYIW => new V4ui(X, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYXO => new V4ui(X, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYXI => new V4ui(X, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYXX => new V4ui(X, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYXY => new V4ui(X, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYXZ => new V4ui(X, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYXW => new V4ui(X, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYYO => new V4ui(X, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYYI => new V4ui(X, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYYX => new V4ui(X, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYYY => new V4ui(X, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYYZ => new V4ui(X, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYYW => new V4ui(X, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYZO => new V4ui(X, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYZI => new V4ui(X, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYZX => new V4ui(X, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYZY => new V4ui(X, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYZZ => new V4ui(X, Y, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui XYZW { readonly get => new V4ui(X, Y, Z, W); set { X = value.X; Y = value.Y; Z = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYWO => new V4ui(X, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYWI => new V4ui(X, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYWX => new V4ui(X, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYWY => new V4ui(X, Y, W, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui XYWZ { readonly get => new V4ui(X, Y, W, Z); set { X = value.X; Y = value.Y; W = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XYWW => new V4ui(X, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZOO => new V4ui(X, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZOI => new V4ui(X, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZOX => new V4ui(X, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZOY => new V4ui(X, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZOZ => new V4ui(X, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZOW => new V4ui(X, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZIO => new V4ui(X, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZII => new V4ui(X, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZIX => new V4ui(X, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZIY => new V4ui(X, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZIZ => new V4ui(X, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZIW => new V4ui(X, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZXO => new V4ui(X, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZXI => new V4ui(X, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZXX => new V4ui(X, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZXY => new V4ui(X, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZXZ => new V4ui(X, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZXW => new V4ui(X, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZYO => new V4ui(X, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZYI => new V4ui(X, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZYX => new V4ui(X, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZYY => new V4ui(X, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZYZ => new V4ui(X, Z, Y, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui XZYW { readonly get => new V4ui(X, Z, Y, W); set { X = value.X; Z = value.Y; Y = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZZO => new V4ui(X, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZZI => new V4ui(X, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZZX => new V4ui(X, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZZY => new V4ui(X, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZZZ => new V4ui(X, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZZW => new V4ui(X, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZWO => new V4ui(X, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZWI => new V4ui(X, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZWX => new V4ui(X, Z, W, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui XZWY { readonly get => new V4ui(X, Z, W, Y); set { X = value.X; Z = value.Y; W = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZWZ => new V4ui(X, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XZWW => new V4ui(X, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWOO => new V4ui(X, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWOI => new V4ui(X, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWOX => new V4ui(X, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWOY => new V4ui(X, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWOZ => new V4ui(X, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWOW => new V4ui(X, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWIO => new V4ui(X, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWII => new V4ui(X, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWIX => new V4ui(X, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWIY => new V4ui(X, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWIZ => new V4ui(X, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWIW => new V4ui(X, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWXO => new V4ui(X, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWXI => new V4ui(X, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWXX => new V4ui(X, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWXY => new V4ui(X, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWXZ => new V4ui(X, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWXW => new V4ui(X, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWYO => new V4ui(X, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWYI => new V4ui(X, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWYX => new V4ui(X, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWYY => new V4ui(X, W, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui XWYZ { readonly get => new V4ui(X, W, Y, Z); set { X = value.X; W = value.Y; Y = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWYW => new V4ui(X, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWZO => new V4ui(X, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWZI => new V4ui(X, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWZX => new V4ui(X, W, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui XWZY { readonly get => new V4ui(X, W, Z, Y); set { X = value.X; W = value.Y; Z = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWZZ => new V4ui(X, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWZW => new V4ui(X, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWWO => new V4ui(X, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWWI => new V4ui(X, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWWX => new V4ui(X, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWWY => new V4ui(X, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWWZ => new V4ui(X, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui XWWW => new V4ui(X, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOOO => new V4ui(Y, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOOI => new V4ui(Y, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOOX => new V4ui(Y, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOOY => new V4ui(Y, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOOZ => new V4ui(Y, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOOW => new V4ui(Y, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOIO => new V4ui(Y, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOII => new V4ui(Y, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOIX => new V4ui(Y, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOIY => new V4ui(Y, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOIZ => new V4ui(Y, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOIW => new V4ui(Y, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOXO => new V4ui(Y, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOXI => new V4ui(Y, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOXX => new V4ui(Y, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOXY => new V4ui(Y, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOXZ => new V4ui(Y, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOXW => new V4ui(Y, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOYO => new V4ui(Y, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOYI => new V4ui(Y, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOYX => new V4ui(Y, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOYY => new V4ui(Y, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOYZ => new V4ui(Y, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOYW => new V4ui(Y, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOZO => new V4ui(Y, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOZI => new V4ui(Y, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOZX => new V4ui(Y, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOZY => new V4ui(Y, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOZZ => new V4ui(Y, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOZW => new V4ui(Y, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOWO => new V4ui(Y, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOWI => new V4ui(Y, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOWX => new V4ui(Y, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOWY => new V4ui(Y, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOWZ => new V4ui(Y, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YOWW => new V4ui(Y, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIOO => new V4ui(Y, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIOI => new V4ui(Y, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIOX => new V4ui(Y, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIOY => new V4ui(Y, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIOZ => new V4ui(Y, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIOW => new V4ui(Y, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIIO => new V4ui(Y, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIII => new V4ui(Y, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIIX => new V4ui(Y, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIIY => new V4ui(Y, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIIZ => new V4ui(Y, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIIW => new V4ui(Y, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIXO => new V4ui(Y, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIXI => new V4ui(Y, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIXX => new V4ui(Y, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIXY => new V4ui(Y, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIXZ => new V4ui(Y, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIXW => new V4ui(Y, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIYO => new V4ui(Y, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIYI => new V4ui(Y, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIYX => new V4ui(Y, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIYY => new V4ui(Y, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIYZ => new V4ui(Y, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIYW => new V4ui(Y, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIZO => new V4ui(Y, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIZI => new V4ui(Y, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIZX => new V4ui(Y, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIZY => new V4ui(Y, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIZZ => new V4ui(Y, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIZW => new V4ui(Y, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIWO => new V4ui(Y, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIWI => new V4ui(Y, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIWX => new V4ui(Y, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIWY => new V4ui(Y, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIWZ => new V4ui(Y, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YIWW => new V4ui(Y, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXOO => new V4ui(Y, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXOI => new V4ui(Y, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXOX => new V4ui(Y, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXOY => new V4ui(Y, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXOZ => new V4ui(Y, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXOW => new V4ui(Y, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXIO => new V4ui(Y, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXII => new V4ui(Y, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXIX => new V4ui(Y, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXIY => new V4ui(Y, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXIZ => new V4ui(Y, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXIW => new V4ui(Y, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXXO => new V4ui(Y, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXXI => new V4ui(Y, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXXX => new V4ui(Y, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXXY => new V4ui(Y, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXXZ => new V4ui(Y, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXXW => new V4ui(Y, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXYO => new V4ui(Y, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXYI => new V4ui(Y, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXYX => new V4ui(Y, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXYY => new V4ui(Y, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXYZ => new V4ui(Y, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXYW => new V4ui(Y, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXZO => new V4ui(Y, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXZI => new V4ui(Y, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXZX => new V4ui(Y, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXZY => new V4ui(Y, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXZZ => new V4ui(Y, X, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui YXZW { readonly get => new V4ui(Y, X, Z, W); set { Y = value.X; X = value.Y; Z = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXWO => new V4ui(Y, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXWI => new V4ui(Y, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXWX => new V4ui(Y, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXWY => new V4ui(Y, X, W, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui YXWZ { readonly get => new V4ui(Y, X, W, Z); set { Y = value.X; X = value.Y; W = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YXWW => new V4ui(Y, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYOO => new V4ui(Y, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYOI => new V4ui(Y, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYOX => new V4ui(Y, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYOY => new V4ui(Y, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYOZ => new V4ui(Y, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYOW => new V4ui(Y, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYIO => new V4ui(Y, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYII => new V4ui(Y, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYIX => new V4ui(Y, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYIY => new V4ui(Y, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYIZ => new V4ui(Y, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYIW => new V4ui(Y, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYXO => new V4ui(Y, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYXI => new V4ui(Y, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYXX => new V4ui(Y, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYXY => new V4ui(Y, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYXZ => new V4ui(Y, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYXW => new V4ui(Y, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYYO => new V4ui(Y, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYYI => new V4ui(Y, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYYX => new V4ui(Y, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYYY => new V4ui(Y, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYYZ => new V4ui(Y, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYYW => new V4ui(Y, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYZO => new V4ui(Y, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYZI => new V4ui(Y, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYZX => new V4ui(Y, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYZY => new V4ui(Y, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYZZ => new V4ui(Y, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYZW => new V4ui(Y, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYWO => new V4ui(Y, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYWI => new V4ui(Y, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYWX => new V4ui(Y, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYWY => new V4ui(Y, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYWZ => new V4ui(Y, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YYWW => new V4ui(Y, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZOO => new V4ui(Y, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZOI => new V4ui(Y, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZOX => new V4ui(Y, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZOY => new V4ui(Y, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZOZ => new V4ui(Y, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZOW => new V4ui(Y, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZIO => new V4ui(Y, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZII => new V4ui(Y, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZIX => new V4ui(Y, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZIY => new V4ui(Y, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZIZ => new V4ui(Y, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZIW => new V4ui(Y, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZXO => new V4ui(Y, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZXI => new V4ui(Y, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZXX => new V4ui(Y, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZXY => new V4ui(Y, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZXZ => new V4ui(Y, Z, X, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui YZXW { readonly get => new V4ui(Y, Z, X, W); set { Y = value.X; Z = value.Y; X = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZYO => new V4ui(Y, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZYI => new V4ui(Y, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZYX => new V4ui(Y, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZYY => new V4ui(Y, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZYZ => new V4ui(Y, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZYW => new V4ui(Y, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZZO => new V4ui(Y, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZZI => new V4ui(Y, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZZX => new V4ui(Y, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZZY => new V4ui(Y, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZZZ => new V4ui(Y, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZZW => new V4ui(Y, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZWO => new V4ui(Y, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZWI => new V4ui(Y, Z, W, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui YZWX { readonly get => new V4ui(Y, Z, W, X); set { Y = value.X; Z = value.Y; W = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZWY => new V4ui(Y, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZWZ => new V4ui(Y, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YZWW => new V4ui(Y, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWOO => new V4ui(Y, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWOI => new V4ui(Y, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWOX => new V4ui(Y, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWOY => new V4ui(Y, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWOZ => new V4ui(Y, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWOW => new V4ui(Y, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWIO => new V4ui(Y, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWII => new V4ui(Y, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWIX => new V4ui(Y, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWIY => new V4ui(Y, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWIZ => new V4ui(Y, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWIW => new V4ui(Y, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWXO => new V4ui(Y, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWXI => new V4ui(Y, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWXX => new V4ui(Y, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWXY => new V4ui(Y, W, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui YWXZ { readonly get => new V4ui(Y, W, X, Z); set { Y = value.X; W = value.Y; X = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWXW => new V4ui(Y, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWYO => new V4ui(Y, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWYI => new V4ui(Y, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWYX => new V4ui(Y, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWYY => new V4ui(Y, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWYZ => new V4ui(Y, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWYW => new V4ui(Y, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWZO => new V4ui(Y, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWZI => new V4ui(Y, W, Z, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui YWZX { readonly get => new V4ui(Y, W, Z, X); set { Y = value.X; W = value.Y; Z = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWZY => new V4ui(Y, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWZZ => new V4ui(Y, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWZW => new V4ui(Y, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWWO => new V4ui(Y, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWWI => new V4ui(Y, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWWX => new V4ui(Y, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWWY => new V4ui(Y, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWWZ => new V4ui(Y, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui YWWW => new V4ui(Y, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOOO => new V4ui(Z, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOOI => new V4ui(Z, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOOX => new V4ui(Z, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOOY => new V4ui(Z, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOOZ => new V4ui(Z, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOOW => new V4ui(Z, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOIO => new V4ui(Z, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOII => new V4ui(Z, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOIX => new V4ui(Z, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOIY => new V4ui(Z, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOIZ => new V4ui(Z, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOIW => new V4ui(Z, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOXO => new V4ui(Z, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOXI => new V4ui(Z, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOXX => new V4ui(Z, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOXY => new V4ui(Z, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOXZ => new V4ui(Z, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOXW => new V4ui(Z, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOYO => new V4ui(Z, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOYI => new V4ui(Z, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOYX => new V4ui(Z, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOYY => new V4ui(Z, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOYZ => new V4ui(Z, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOYW => new V4ui(Z, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOZO => new V4ui(Z, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOZI => new V4ui(Z, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOZX => new V4ui(Z, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOZY => new V4ui(Z, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOZZ => new V4ui(Z, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOZW => new V4ui(Z, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOWO => new V4ui(Z, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOWI => new V4ui(Z, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOWX => new V4ui(Z, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOWY => new V4ui(Z, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOWZ => new V4ui(Z, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZOWW => new V4ui(Z, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIOO => new V4ui(Z, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIOI => new V4ui(Z, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIOX => new V4ui(Z, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIOY => new V4ui(Z, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIOZ => new V4ui(Z, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIOW => new V4ui(Z, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIIO => new V4ui(Z, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIII => new V4ui(Z, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIIX => new V4ui(Z, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIIY => new V4ui(Z, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIIZ => new V4ui(Z, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIIW => new V4ui(Z, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIXO => new V4ui(Z, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIXI => new V4ui(Z, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIXX => new V4ui(Z, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIXY => new V4ui(Z, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIXZ => new V4ui(Z, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIXW => new V4ui(Z, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIYO => new V4ui(Z, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIYI => new V4ui(Z, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIYX => new V4ui(Z, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIYY => new V4ui(Z, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIYZ => new V4ui(Z, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIYW => new V4ui(Z, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIZO => new V4ui(Z, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIZI => new V4ui(Z, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIZX => new V4ui(Z, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIZY => new V4ui(Z, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIZZ => new V4ui(Z, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIZW => new V4ui(Z, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIWO => new V4ui(Z, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIWI => new V4ui(Z, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIWX => new V4ui(Z, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIWY => new V4ui(Z, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIWZ => new V4ui(Z, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZIWW => new V4ui(Z, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXOO => new V4ui(Z, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXOI => new V4ui(Z, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXOX => new V4ui(Z, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXOY => new V4ui(Z, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXOZ => new V4ui(Z, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXOW => new V4ui(Z, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXIO => new V4ui(Z, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXII => new V4ui(Z, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXIX => new V4ui(Z, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXIY => new V4ui(Z, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXIZ => new V4ui(Z, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXIW => new V4ui(Z, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXXO => new V4ui(Z, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXXI => new V4ui(Z, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXXX => new V4ui(Z, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXXY => new V4ui(Z, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXXZ => new V4ui(Z, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXXW => new V4ui(Z, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXYO => new V4ui(Z, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXYI => new V4ui(Z, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXYX => new V4ui(Z, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXYY => new V4ui(Z, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXYZ => new V4ui(Z, X, Y, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui ZXYW { readonly get => new V4ui(Z, X, Y, W); set { Z = value.X; X = value.Y; Y = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXZO => new V4ui(Z, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXZI => new V4ui(Z, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXZX => new V4ui(Z, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXZY => new V4ui(Z, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXZZ => new V4ui(Z, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXZW => new V4ui(Z, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXWO => new V4ui(Z, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXWI => new V4ui(Z, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXWX => new V4ui(Z, X, W, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui ZXWY { readonly get => new V4ui(Z, X, W, Y); set { Z = value.X; X = value.Y; W = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXWZ => new V4ui(Z, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZXWW => new V4ui(Z, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYOO => new V4ui(Z, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYOI => new V4ui(Z, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYOX => new V4ui(Z, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYOY => new V4ui(Z, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYOZ => new V4ui(Z, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYOW => new V4ui(Z, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYIO => new V4ui(Z, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYII => new V4ui(Z, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYIX => new V4ui(Z, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYIY => new V4ui(Z, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYIZ => new V4ui(Z, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYIW => new V4ui(Z, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYXO => new V4ui(Z, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYXI => new V4ui(Z, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYXX => new V4ui(Z, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYXY => new V4ui(Z, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYXZ => new V4ui(Z, Y, X, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui ZYXW { readonly get => new V4ui(Z, Y, X, W); set { Z = value.X; Y = value.Y; X = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYYO => new V4ui(Z, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYYI => new V4ui(Z, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYYX => new V4ui(Z, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYYY => new V4ui(Z, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYYZ => new V4ui(Z, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYYW => new V4ui(Z, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYZO => new V4ui(Z, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYZI => new V4ui(Z, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYZX => new V4ui(Z, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYZY => new V4ui(Z, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYZZ => new V4ui(Z, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYZW => new V4ui(Z, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYWO => new V4ui(Z, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYWI => new V4ui(Z, Y, W, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui ZYWX { readonly get => new V4ui(Z, Y, W, X); set { Z = value.X; Y = value.Y; W = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYWY => new V4ui(Z, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYWZ => new V4ui(Z, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZYWW => new V4ui(Z, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZOO => new V4ui(Z, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZOI => new V4ui(Z, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZOX => new V4ui(Z, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZOY => new V4ui(Z, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZOZ => new V4ui(Z, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZOW => new V4ui(Z, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZIO => new V4ui(Z, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZII => new V4ui(Z, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZIX => new V4ui(Z, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZIY => new V4ui(Z, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZIZ => new V4ui(Z, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZIW => new V4ui(Z, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZXO => new V4ui(Z, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZXI => new V4ui(Z, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZXX => new V4ui(Z, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZXY => new V4ui(Z, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZXZ => new V4ui(Z, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZXW => new V4ui(Z, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZYO => new V4ui(Z, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZYI => new V4ui(Z, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZYX => new V4ui(Z, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZYY => new V4ui(Z, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZYZ => new V4ui(Z, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZYW => new V4ui(Z, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZZO => new V4ui(Z, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZZI => new V4ui(Z, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZZX => new V4ui(Z, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZZY => new V4ui(Z, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZZZ => new V4ui(Z, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZZW => new V4ui(Z, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZWO => new V4ui(Z, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZWI => new V4ui(Z, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZWX => new V4ui(Z, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZWY => new V4ui(Z, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZWZ => new V4ui(Z, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZZWW => new V4ui(Z, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWOO => new V4ui(Z, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWOI => new V4ui(Z, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWOX => new V4ui(Z, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWOY => new V4ui(Z, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWOZ => new V4ui(Z, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWOW => new V4ui(Z, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWIO => new V4ui(Z, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWII => new V4ui(Z, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWIX => new V4ui(Z, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWIY => new V4ui(Z, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWIZ => new V4ui(Z, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWIW => new V4ui(Z, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWXO => new V4ui(Z, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWXI => new V4ui(Z, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWXX => new V4ui(Z, W, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui ZWXY { readonly get => new V4ui(Z, W, X, Y); set { Z = value.X; W = value.Y; X = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWXZ => new V4ui(Z, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWXW => new V4ui(Z, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWYO => new V4ui(Z, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWYI => new V4ui(Z, W, Y, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui ZWYX { readonly get => new V4ui(Z, W, Y, X); set { Z = value.X; W = value.Y; Y = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWYY => new V4ui(Z, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWYZ => new V4ui(Z, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWYW => new V4ui(Z, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWZO => new V4ui(Z, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWZI => new V4ui(Z, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWZX => new V4ui(Z, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWZY => new V4ui(Z, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWZZ => new V4ui(Z, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWZW => new V4ui(Z, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWWO => new V4ui(Z, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWWI => new V4ui(Z, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWWX => new V4ui(Z, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWWY => new V4ui(Z, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWWZ => new V4ui(Z, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui ZWWW => new V4ui(Z, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOOO => new V4ui(W, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOOI => new V4ui(W, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOOX => new V4ui(W, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOOY => new V4ui(W, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOOZ => new V4ui(W, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOOW => new V4ui(W, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOIO => new V4ui(W, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOII => new V4ui(W, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOIX => new V4ui(W, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOIY => new V4ui(W, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOIZ => new V4ui(W, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOIW => new V4ui(W, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOXO => new V4ui(W, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOXI => new V4ui(W, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOXX => new V4ui(W, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOXY => new V4ui(W, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOXZ => new V4ui(W, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOXW => new V4ui(W, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOYO => new V4ui(W, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOYI => new V4ui(W, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOYX => new V4ui(W, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOYY => new V4ui(W, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOYZ => new V4ui(W, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOYW => new V4ui(W, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOZO => new V4ui(W, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOZI => new V4ui(W, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOZX => new V4ui(W, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOZY => new V4ui(W, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOZZ => new V4ui(W, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOZW => new V4ui(W, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOWO => new V4ui(W, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOWI => new V4ui(W, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOWX => new V4ui(W, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOWY => new V4ui(W, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOWZ => new V4ui(W, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WOWW => new V4ui(W, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIOO => new V4ui(W, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIOI => new V4ui(W, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIOX => new V4ui(W, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIOY => new V4ui(W, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIOZ => new V4ui(W, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIOW => new V4ui(W, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIIO => new V4ui(W, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIII => new V4ui(W, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIIX => new V4ui(W, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIIY => new V4ui(W, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIIZ => new V4ui(W, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIIW => new V4ui(W, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIXO => new V4ui(W, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIXI => new V4ui(W, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIXX => new V4ui(W, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIXY => new V4ui(W, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIXZ => new V4ui(W, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIXW => new V4ui(W, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIYO => new V4ui(W, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIYI => new V4ui(W, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIYX => new V4ui(W, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIYY => new V4ui(W, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIYZ => new V4ui(W, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIYW => new V4ui(W, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIZO => new V4ui(W, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIZI => new V4ui(W, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIZX => new V4ui(W, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIZY => new V4ui(W, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIZZ => new V4ui(W, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIZW => new V4ui(W, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIWO => new V4ui(W, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIWI => new V4ui(W, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIWX => new V4ui(W, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIWY => new V4ui(W, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIWZ => new V4ui(W, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WIWW => new V4ui(W, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXOO => new V4ui(W, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXOI => new V4ui(W, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXOX => new V4ui(W, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXOY => new V4ui(W, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXOZ => new V4ui(W, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXOW => new V4ui(W, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXIO => new V4ui(W, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXII => new V4ui(W, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXIX => new V4ui(W, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXIY => new V4ui(W, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXIZ => new V4ui(W, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXIW => new V4ui(W, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXXO => new V4ui(W, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXXI => new V4ui(W, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXXX => new V4ui(W, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXXY => new V4ui(W, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXXZ => new V4ui(W, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXXW => new V4ui(W, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXYO => new V4ui(W, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXYI => new V4ui(W, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXYX => new V4ui(W, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXYY => new V4ui(W, X, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui WXYZ { readonly get => new V4ui(W, X, Y, Z); set { W = value.X; X = value.Y; Y = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXYW => new V4ui(W, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXZO => new V4ui(W, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXZI => new V4ui(W, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXZX => new V4ui(W, X, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui WXZY { readonly get => new V4ui(W, X, Z, Y); set { W = value.X; X = value.Y; Z = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXZZ => new V4ui(W, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXZW => new V4ui(W, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXWO => new V4ui(W, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXWI => new V4ui(W, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXWX => new V4ui(W, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXWY => new V4ui(W, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXWZ => new V4ui(W, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WXWW => new V4ui(W, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYOO => new V4ui(W, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYOI => new V4ui(W, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYOX => new V4ui(W, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYOY => new V4ui(W, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYOZ => new V4ui(W, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYOW => new V4ui(W, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYIO => new V4ui(W, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYII => new V4ui(W, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYIX => new V4ui(W, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYIY => new V4ui(W, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYIZ => new V4ui(W, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYIW => new V4ui(W, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYXO => new V4ui(W, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYXI => new V4ui(W, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYXX => new V4ui(W, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYXY => new V4ui(W, Y, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui WYXZ { readonly get => new V4ui(W, Y, X, Z); set { W = value.X; Y = value.Y; X = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYXW => new V4ui(W, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYYO => new V4ui(W, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYYI => new V4ui(W, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYYX => new V4ui(W, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYYY => new V4ui(W, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYYZ => new V4ui(W, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYYW => new V4ui(W, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYZO => new V4ui(W, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYZI => new V4ui(W, Y, Z, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui WYZX { readonly get => new V4ui(W, Y, Z, X); set { W = value.X; Y = value.Y; Z = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYZY => new V4ui(W, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYZZ => new V4ui(W, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYZW => new V4ui(W, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYWO => new V4ui(W, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYWI => new V4ui(W, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYWX => new V4ui(W, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYWY => new V4ui(W, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYWZ => new V4ui(W, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WYWW => new V4ui(W, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZOO => new V4ui(W, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZOI => new V4ui(W, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZOX => new V4ui(W, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZOY => new V4ui(W, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZOZ => new V4ui(W, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZOW => new V4ui(W, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZIO => new V4ui(W, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZII => new V4ui(W, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZIX => new V4ui(W, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZIY => new V4ui(W, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZIZ => new V4ui(W, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZIW => new V4ui(W, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZXO => new V4ui(W, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZXI => new V4ui(W, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZXX => new V4ui(W, Z, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui WZXY { readonly get => new V4ui(W, Z, X, Y); set { W = value.X; Z = value.Y; X = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZXZ => new V4ui(W, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZXW => new V4ui(W, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZYO => new V4ui(W, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZYI => new V4ui(W, Z, Y, 1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4ui WZYX { readonly get => new V4ui(W, Z, Y, X); set { W = value.X; Z = value.Y; Y = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZYY => new V4ui(W, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZYZ => new V4ui(W, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZYW => new V4ui(W, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZZO => new V4ui(W, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZZI => new V4ui(W, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZZX => new V4ui(W, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZZY => new V4ui(W, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZZZ => new V4ui(W, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZZW => new V4ui(W, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZWO => new V4ui(W, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZWI => new V4ui(W, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZWX => new V4ui(W, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZWY => new V4ui(W, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZWZ => new V4ui(W, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WZWW => new V4ui(W, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWOO => new V4ui(W, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWOI => new V4ui(W, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWOX => new V4ui(W, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWOY => new V4ui(W, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWOZ => new V4ui(W, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWOW => new V4ui(W, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWIO => new V4ui(W, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWII => new V4ui(W, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWIX => new V4ui(W, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWIY => new V4ui(W, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWIZ => new V4ui(W, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWIW => new V4ui(W, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWXO => new V4ui(W, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWXI => new V4ui(W, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWXX => new V4ui(W, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWXY => new V4ui(W, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWXZ => new V4ui(W, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWXW => new V4ui(W, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWYO => new V4ui(W, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWYI => new V4ui(W, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWYX => new V4ui(W, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWYY => new V4ui(W, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWYZ => new V4ui(W, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWYW => new V4ui(W, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWZO => new V4ui(W, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWZI => new V4ui(W, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWZX => new V4ui(W, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWZY => new V4ui(W, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWZZ => new V4ui(W, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWZW => new V4ui(W, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWWO => new V4ui(W, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWWI => new V4ui(W, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWWX => new V4ui(W, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWWY => new V4ui(W, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWWZ => new V4ui(W, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4ui WWWW => new V4ui(W, W, W, W); #endregion #region IVector Members /// /// By using long indices, the IVector<double> interface is /// accessed. /// public double this[long i] { readonly get { return (double)this[(int)i]; } set { this[(int)i] = (uint)value; } } #endregion #region ISize4ui Members public readonly V4ui Size4ui { get { return this; } } #endregion #region IVector public readonly long Dim { get { return 4; } } public readonly object GetValue(long index) { return (object)this[(int)index]; } public void SetValue(object value, long index) { this[(int)index] = (uint)value; } #endregion } public class V4uiEqualityComparer : IEqualityComparer { public static V4uiEqualityComparer Default => new V4uiEqualityComparer(); #region IEqualityComparer Members public bool Equals(V4ui v0, V4ui v1) { return v0 == v1; } public int GetHashCode(V4ui v) { return v.GetHashCode(); } #endregion } public static partial class Fun { #region Min and Max /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Min(this V4ui a, V4ui b) { return new V4ui(Min(a.X, b.X), Min(a.Y, b.Y), Min(a.Z, b.Z), Min(a.W, b.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Min(this V4ui a, uint b) { return new V4ui(Min(a.X, b), Min(a.Y, b), Min(a.Z, b), Min(a.W, b)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Min(this uint a, V4ui b) { return new V4ui(Min(a, b.X), Min(a, b.Y), Min(a, b.Z), Min(a, b.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Max(this V4ui a, V4ui b) { return new V4ui(Max(a.X, b.X), Max(a.Y, b.Y), Max(a.Z, b.Z), Max(a.W, b.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Max(this V4ui a, uint b) { return new V4ui(Max(a.X, b), Max(a.Y, b), Max(a.Z, b), Max(a.W, b)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Max(this uint a, V4ui b) { return new V4ui(Max(a, b.X), Max(a, b.Y), Max(a, b.Z), Max(a, b.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Min(this V4ui a, V4ui b, V4ui c) { return new V4ui(Min(a.X, b.X, c.X), Min(a.Y, b.Y, c.Y), Min(a.Z, b.Z, c.Z), Min(a.W, b.W, c.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Max(this V4ui a, V4ui b, V4ui c) { return new V4ui(Max(a.X, b.X, c.X), Max(a.Y, b.Y, c.Y), Max(a.Z, b.Z, c.Z), Max(a.W, b.W, c.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Min(this V4ui a, V4ui b, V4ui c, V4ui d) { return new V4ui(Min(a.X, b.X, c.X, d.X), Min(a.Y, b.Y, c.Y, d.Y), Min(a.Z, b.Z, c.Z, d.Z), Min(a.W, b.W, c.W, d.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Max(this V4ui a, V4ui b, V4ui c, V4ui d) { return new V4ui(Max(a.X, b.X, c.X, d.X), Max(a.Y, b.Y, c.Y, d.Y), Max(a.Z, b.Z, c.Z, d.Z), Max(a.W, b.W, c.W, d.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Min(this V4ui x, params V4ui[] values) { return new V4ui(Min(x.X, values.Map(a => a.X)), Min(x.Y, values.Map(a => a.Y)), Min(x.Z, values.Map(a => a.Z)), Min(x.W, values.Map(a => a.W))); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Max(this V4ui x, params V4ui[] values) { return new V4ui(Max(x.X, values.Map(a => a.X)), Max(x.Y, values.Map(a => a.Y)), Max(x.Z, values.Map(a => a.Z)), Max(x.W, values.Map(a => a.W))); } #endregion #region Clamping /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Clamp(this V4ui x, V4ui a, V4ui b) { return new V4ui(Clamp(x.X, a.X, b.X), Clamp(x.Y, a.Y, b.Y), Clamp(x.Z, a.Z, b.Z), Clamp(x.W, a.W, b.W)); } /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Clamp(this V4ui x, uint a, uint b) { return new V4ui(Clamp(x.X, a, b), Clamp(x.Y, a, b), Clamp(x.Z, a, b), Clamp(x.W, a, b)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui ClampExcl(this V4ui x, V4ui a, V4ui b) { return new V4ui(ClampExcl(x.X, a.X, b.X), ClampExcl(x.Y, a.Y, b.Y), ClampExcl(x.Z, a.Z, b.Z), ClampExcl(x.W, a.W, b.W)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui ClampExcl(this V4ui x, uint a, uint b) { return new V4ui(ClampExcl(x.X, a, b), ClampExcl(x.Y, a, b), ClampExcl(x.Z, a, b), ClampExcl(x.W, a, b)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui ClampWrap(this V4ui x, V4ui a, V4ui b) { return new V4ui(ClampWrap(x.X, a.X, b.X), ClampWrap(x.Y, a.Y, b.Y), ClampWrap(x.Z, a.Z, b.Z), ClampWrap(x.W, a.W, b.W)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui ClampWrap(this V4ui x, uint a, uint b) { return new V4ui(ClampWrap(x.X, a, b), ClampWrap(x.Y, a, b), ClampWrap(x.Z, a, b), ClampWrap(x.W, a, b)); } /// /// Applies Fun.Saturate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Saturate(this V4ui x) { return new V4ui(Saturate(x.X), Saturate(x.Y), Saturate(x.Z), Saturate(x.W)); } #endregion #region Multiply-Add /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui MultiplyAdd(V4ui x, V4ui y, V4ui z) { return new V4ui(MultiplyAdd(x.X, y.X, z.X), MultiplyAdd(x.Y, y.Y, z.Y), MultiplyAdd(x.Z, y.Z, z.Z), MultiplyAdd(x.W, y.W, z.W)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui MultiplyAdd(V4ui x, uint y, V4ui z) { return new V4ui(MultiplyAdd(x.X, y, z.X), MultiplyAdd(x.Y, y, z.Y), MultiplyAdd(x.Z, y, z.Z), MultiplyAdd(x.W, y, z.W)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui MultiplyAdd(uint x, V4ui y, V4ui z) { return new V4ui(MultiplyAdd(x, y.X, z.X), MultiplyAdd(x, y.Y, z.Y), MultiplyAdd(x, y.Z, z.Z), MultiplyAdd(x, y.W, z.W)); } #endregion #region Roots /// /// Applies Fun.Sqrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Sqrt(this V4ui x) { return new V4d(Sqrt(x.X), Sqrt(x.Y), Sqrt(x.Z), Sqrt(x.W)); } /// /// Applies Fun.Cbrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Cbrt(this V4ui x) { return new V4d(Cbrt(x.X), Cbrt(x.Y), Cbrt(x.Z), Cbrt(x.W)); } #endregion #region Square /// /// Applies Fun.Square to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Square(this V4ui x) { return new V4ui(Square(x.X), Square(x.Y), Square(x.Z), Square(x.W)); } #endregion #region Power /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Pown(this V4ui x, V4ui y) { return new V4ui(Pown(x.X, y.X), Pown(x.Y, y.Y), Pown(x.Z, y.Z), Pown(x.W, y.W)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Pown(this V4ui x, uint y) { return new V4ui(Pown(x.X, y), Pown(x.Y, y), Pown(x.Z, y), Pown(x.W, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Pown(this uint x, V4ui y) { return new V4ui(Pown(x, y.X), Pown(x, y.Y), Pown(x, y.Z), Pown(x, y.W)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Pown(this V4ui x, V4i y) { return new V4ui(Pown(x.X, y.X), Pown(x.Y, y.Y), Pown(x.Z, y.Z), Pown(x.W, y.W)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Pown(this V4ui x, int y) { return new V4ui(Pown(x.X, y), Pown(x.Y, y), Pown(x.Z, y), Pown(x.W, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Pown(this uint x, V4i y) { return new V4ui(Pown(x, y.X), Pown(x, y.Y), Pown(x, y.Z), Pown(x, y.W)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Pow(this V4ui x, V4f y) { return new V4f(Pow(x.X, y.X), Pow(x.Y, y.Y), Pow(x.Z, y.Z), Pow(x.W, y.W)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Pow(this V4ui x, float y) { return new V4f(Pow(x.X, y), Pow(x.Y, y), Pow(x.Z, y), Pow(x.W, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Pow(this uint x, V4f y) { return new V4f(Pow(x, y.X), Pow(x, y.Y), Pow(x, y.Z), Pow(x, y.W)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Pow(this V4ui x, V4d y) { return new V4d(Pow(x.X, y.X), Pow(x.Y, y.Y), Pow(x.Z, y.Z), Pow(x.W, y.W)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Pow(this V4ui x, double y) { return new V4d(Pow(x.X, y), Pow(x.Y, y), Pow(x.Z, y), Pow(x.W, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Pow(this uint x, V4d y) { return new V4d(Pow(x, y.X), Pow(x, y.Y), Pow(x, y.Z), Pow(x, y.W)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Power(this V4ui x, V4f y) { return new V4f(Power(x.X, y.X), Power(x.Y, y.Y), Power(x.Z, y.Z), Power(x.W, y.W)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Power(this V4ui x, float y) { return new V4f(Power(x.X, y), Power(x.Y, y), Power(x.Z, y), Power(x.W, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Power(this uint x, V4f y) { return new V4f(Power(x, y.X), Power(x, y.Y), Power(x, y.Z), Power(x, y.W)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Power(this V4ui x, V4d y) { return new V4d(Power(x.X, y.X), Power(x.Y, y.Y), Power(x.Z, y.Z), Power(x.W, y.W)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Power(this V4ui x, double y) { return new V4d(Power(x.X, y), Power(x.Y, y), Power(x.Z, y), Power(x.W, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Power(this uint x, V4d y) { return new V4d(Power(x, y.X), Power(x, y.Y), Power(x, y.Z), Power(x, y.W)); } #endregion #region Exp and Log /// /// Applies Fun.Exp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Exp(this V4ui x) { return new V4d(Exp(x.X), Exp(x.Y), Exp(x.Z), Exp(x.W)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log(this V4ui x) { return new V4d(Log(x.X), Log(x.Y), Log(x.Z), Log(x.W)); } /// /// Applies Fun.Log2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log2(this V4ui x) { return new V4d(Log2(x.X), Log2(x.Y), Log2(x.Z), Log2(x.W)); } /// /// Applies Fun.Log2Int to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Log2Int(this V4ui x) { return new V4i(Log2Int(x.X), Log2Int(x.Y), Log2Int(x.Z), Log2Int(x.W)); } /// /// Applies Fun.Log10 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log10(this V4ui x) { return new V4d(Log10(x.X), Log10(x.Y), Log10(x.Z), Log10(x.W)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log(this V4ui x, double basis) { return new V4d(Log(x.X, basis), Log(x.Y, basis), Log(x.Z, basis), Log(x.W, basis)); } #endregion #region Step functions /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Step(this V4ui x, V4ui edge) { return new V4ui(Step(x.X, edge.X), Step(x.Y, edge.Y), Step(x.Z, edge.Z), Step(x.W, edge.W)); } /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Step(this V4ui x, uint edge) { return new V4ui(Step(x.X, edge), Step(x.Y, edge), Step(x.Z, edge), Step(x.W, edge)); } #endregion #region Interpolation /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Lerp(this float t, V4ui a, V4ui b) { return new V4ui(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y), Lerp(t, a.Z, b.Z), Lerp(t, a.W, b.W)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Lerp(this V4f t, V4ui a, V4ui b) { return new V4ui(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y), Lerp(t.Z, a.Z, b.Z), Lerp(t.W, a.W, b.W)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Lerp(this double t, V4ui a, V4ui b) { return new V4ui(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y), Lerp(t, a.Z, b.Z), Lerp(t, a.W, b.W)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui Lerp(this V4d t, V4ui a, V4ui b) { return new V4ui(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y), Lerp(t.Z, a.Z, b.Z), Lerp(t.W, a.W, b.W)); } /// /// Applies Fun.InvLerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d InvLerp(this V4ui y, V4ui a, V4ui b) { return new V4d(InvLerp(y.X, a.X, b.X), InvLerp(y.Y, a.Y, b.Y), InvLerp(y.Z, a.Z, b.Z), InvLerp(y.W, a.W, b.W)); } #endregion #region Common Divisor and Multiple /// /// Applies Fun.GreatestCommonDivisor to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui GreatestCommonDivisor(this V4ui a, V4ui b) { return new V4ui(GreatestCommonDivisor(a.X, b.X), GreatestCommonDivisor(a.Y, b.Y), GreatestCommonDivisor(a.Z, b.Z), GreatestCommonDivisor(a.W, b.W)); } /// /// Applies Fun.LeastCommonMultiple to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui LeastCommonMultiple(this V4ui a, V4ui b) { return new V4ui(LeastCommonMultiple(a.X, b.X), LeastCommonMultiple(a.Y, b.Y), LeastCommonMultiple(a.Z, b.Z), LeastCommonMultiple(a.W, b.W)); } #endregion #region Floating point bits /// /// Applies Fun.FloatFromUnsignedBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FloatFromUnsignedBits(this V4ui x) { return new V4f(FloatFromUnsignedBits(x.X), FloatFromUnsignedBits(x.Y), FloatFromUnsignedBits(x.Z), FloatFromUnsignedBits(x.W)); } #endregion #region ApproximateEquals /// /// Returns whether the given vectors are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V4ui a, V4ui b, uint tolerance) { return ApproximateEquals(a.X, b.X, tolerance) && ApproximateEquals(a.Y, b.Y, tolerance) && ApproximateEquals(a.Z, b.Z, tolerance) && ApproximateEquals(a.W, b.W, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this V4ui v, uint epsilon) => Vec.AllTiny(v, epsilon); #endregion } /// /// Contains static methods /// public static partial class Vec { #region Length /// /// Returns the squared length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint LengthSquared(V4ui v) => v.LengthSquared; /// /// Returns the length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Length(V4ui v) => v.Length; #endregion #region Normalize /// /// Returns a normalized copy of this vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Normalized(V4ui v) => v.Normalized; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Norm1(V4ui v) => v.Norm1; /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(V4ui v) => v.Norm2; /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint NormMax(V4ui v) => v.NormMax; /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint NormMin(V4ui v) => v.NormMin; /// /// Gets the p-norm. This is calculated as the p-th root of (|x|^n + |y|^n + ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this V4ui v, double p) { return ( Fun.Abs(v.X).Pow(p) + Fun.Abs(v.Y).Pow(p) + Fun.Abs(v.Z).Pow(p) + Fun.Abs(v.W).Pow(p)).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the squared distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint DistanceSquared(this V4ui a, V4ui b) => Fun.Square((a.X < b.X) ? (b.X - a.X) : (a.X - b.X)) + Fun.Square((a.Y < b.Y) ? (b.Y - a.Y) : (a.Y - b.Y)) + Fun.Square((a.Z < b.Z) ? (b.Z - a.Z) : (a.Z - b.Z)) + Fun.Square((a.W < b.W) ? (b.W - a.W) : (a.W - b.W)); /// /// Returns the distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V4ui a, V4ui b) => Fun.Sqrt(DistanceSquared(a, b)); /// /// Returns the Manhatten (or 1-) distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Distance1(this V4ui a, V4ui b) => ((a.X < b.X) ? (b.X - a.X) : (a.X - b.X)) + ((a.Y < b.Y) ? (b.Y - a.Y) : (a.Y - b.Y)) + ((a.Z < b.Z) ? (b.Z - a.Z) : (a.Z - b.Z)) + ((a.W < b.W) ? (b.W - a.W) : (a.W - b.W)); /// /// Returns the p-distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V4ui a, V4ui b, double p) => (((a.X < b.X) ? (b.X - a.X) : (a.X - b.X)).Pow(p) + ((a.Y < b.Y) ? (b.Y - a.Y) : (a.Y - b.Y)).Pow(p) + ((a.Z < b.Z) ? (b.Z - a.Z) : (a.Z - b.Z)).Pow(p) + ((a.W < b.W) ? (b.W - a.W) : (a.W - b.W)).Pow(p)).Pow(1 / p); /// /// Returns the maximal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint DistanceMax(this V4ui a, V4ui b) => Fun.Max(((a.X < b.X) ? (b.X - a.X) : (a.X - b.X)), ((a.Y < b.Y) ? (b.Y - a.Y) : (a.Y - b.Y)), ((a.Z < b.Z) ? (b.Z - a.Z) : (a.Z - b.Z)), ((a.W < b.W) ? (b.W - a.W) : (a.W - b.W))); /// /// Returns the minimal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint DistanceMin(this V4ui a, V4ui b) => Fun.Min(((a.X < b.X) ? (b.X - a.X) : (a.X - b.X)), ((a.Y < b.Y) ? (b.Y - a.Y) : (a.Y - b.Y)), ((a.Z < b.Z) ? (b.Z - a.Z) : (a.Z - b.Z)), ((a.W < b.W) ? (b.W - a.W) : (a.W - b.W))); /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V4ui query, V4ui p0, V4ui p1) { return DistanceToLine((V4d) query, (V4d) p0, (V4d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V4ui query, V4ui p0, V4ui p1) { return DistanceToInfiniteLine((V4d) query, (V4d) p0, (V4d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V4ui query, V4ui p0, V4ui p1, out double t) { return DistanceToLine((V4d) query, (V4d) p0, (V4d) p1, out t); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V4ui query, V4ui p0, V4ui p1, out double t) { return DistanceToInfiniteLine((V4d) query, (V4d) p0, (V4d) p1, out t); } #endregion #region Operations /// /// Returns the dot product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Dot(this V4ui a, V4ui b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z + a.W * b.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DirFlags DirFlags(this V4ui v) { DirFlags flags = Aardbase.DirFlags.None; if (v.X > 0) flags |= Aardbase.DirFlags.PositiveX; if (v.X < 0) flags |= Aardbase.DirFlags.NegativeX; if (v.Y > 0) flags |= Aardbase.DirFlags.PositiveY; if (v.Y < 0) flags |= Aardbase.DirFlags.NegativeY; if (v.Z > 0) flags |= Aardbase.DirFlags.PositiveZ; if (v.Z < 0) flags |= Aardbase.DirFlags.NegativeZ; if (v.W > 0) flags |= Aardbase.DirFlags.PositiveW; if (v.W < 0) flags |= Aardbase.DirFlags.NegativeW; return flags; } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V4ui a, V4ui b) { return (a.X < b.X && a.Y < b.Y && a.Z < b.Z && a.W < b.W); } /// /// Returns whether ALL elements of v are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V4ui v, uint s) { return (v.X < s && v.Y < s && v.Z < s && v.W < s); } /// /// Returns whether a is Smaller ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(uint s, V4ui v) { return (s < v.X && s < v.Y && s < v.Z && s < v.W); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V4ui a, V4ui b) { return (a.X < b.X || a.Y < b.Y || a.Z < b.Z || a.W < b.W); } /// /// Returns whether AT LEAST ONE element of v is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V4ui v, uint s) { return (v.X < s || v.Y < s || v.Z < s || v.W < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(uint s, V4ui v) { return (s < v.X || s < v.Y || s < v.Z || s < v.W); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V4ui a, V4ui b) { return (a.X > b.X && a.Y > b.Y && a.Z > b.Z && a.W > b.W); } /// /// Returns whether ALL elements of v are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V4ui v, uint s) { return (v.X > s && v.Y > s && v.Z > s && v.W > s); } /// /// Returns whether a is Greater ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(uint s, V4ui v) { return (s > v.X && s > v.Y && s > v.Z && s > v.W); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V4ui a, V4ui b) { return (a.X > b.X || a.Y > b.Y || a.Z > b.Z || a.W > b.W); } /// /// Returns whether AT LEAST ONE element of v is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V4ui v, uint s) { return (v.X > s || v.Y > s || v.Z > s || v.W > s); } /// /// Returns whether a is Greater AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(uint s, V4ui v) { return (s > v.X || s > v.Y || s > v.Z || s > v.W); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V4ui a, V4ui b) { return (a.X <= b.X && a.Y <= b.Y && a.Z <= b.Z && a.W <= b.W); } /// /// Returns whether ALL elements of v are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V4ui v, uint s) { return (v.X <= s && v.Y <= s && v.Z <= s && v.W <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(uint s, V4ui v) { return (s <= v.X && s <= v.Y && s <= v.Z && s <= v.W); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V4ui a, V4ui b) { return (a.X <= b.X || a.Y <= b.Y || a.Z <= b.Z || a.W <= b.W); } /// /// Returns whether AT LEAST ONE element of v is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V4ui v, uint s) { return (v.X <= s || v.Y <= s || v.Z <= s || v.W <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(uint s, V4ui v) { return (s <= v.X || s <= v.Y || s <= v.Z || s <= v.W); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V4ui a, V4ui b) { return (a.X >= b.X && a.Y >= b.Y && a.Z >= b.Z && a.W >= b.W); } /// /// Returns whether ALL elements of v are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V4ui v, uint s) { return (v.X >= s && v.Y >= s && v.Z >= s && v.W >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(uint s, V4ui v) { return (s >= v.X && s >= v.Y && s >= v.Z && s >= v.W); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V4ui a, V4ui b) { return (a.X >= b.X || a.Y >= b.Y || a.Z >= b.Z || a.W >= b.W); } /// /// Returns whether AT LEAST ONE element of v is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V4ui v, uint s) { return (v.X >= s || v.Y >= s || v.Z >= s || v.W >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(uint s, V4ui v) { return (s >= v.X || s >= v.Y || s >= v.Z || s >= v.W); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V4ui a, V4ui b) { return (a.X == b.X && a.Y == b.Y && a.Z == b.Z && a.W == b.W); } /// /// Returns whether ALL elements of v are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V4ui v, uint s) { return (v.X == s && v.Y == s && v.Z == s && v.W == s); } /// /// Returns whether a is Equal ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(uint s, V4ui v) { return (s == v.X && s == v.Y && s == v.Z && s == v.W); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V4ui a, V4ui b) { return (a.X == b.X || a.Y == b.Y || a.Z == b.Z || a.W == b.W); } /// /// Returns whether AT LEAST ONE element of v is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V4ui v, uint s) { return (v.X == s || v.Y == s || v.Z == s || v.W == s); } /// /// Returns whether a is Equal AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(uint s, V4ui v) { return (s == v.X || s == v.Y || s == v.Z || s == v.W); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V4ui a, V4ui b) { return (a.X != b.X && a.Y != b.Y && a.Z != b.Z && a.W != b.W); } /// /// Returns whether ALL elements of v are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V4ui v, uint s) { return (v.X != s && v.Y != s && v.Z != s && v.W != s); } /// /// Returns whether a is Different ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(uint s, V4ui v) { return (s != v.X && s != v.Y && s != v.Z && s != v.W); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V4ui a, V4ui b) { return (a.X != b.X || a.Y != b.Y || a.Z != b.Z || a.W != b.W); } /// /// Returns whether AT LEAST ONE element of v is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V4ui v, uint s) { return (v.X != s || v.Y != s || v.Z != s || v.W != s); } /// /// Returns whether a is Different AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(uint s, V4ui v) { return (s != v.X || s != v.Y || s != v.Z || s != v.W); } /// /// Compare x-coordinate before y-coordinate, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this V4ui v0, V4ui v1) { if (v0.X < v1.X) return -1; if (v0.X > v1.X) return +1; if (v0.Y < v1.Y) return -1; if (v0.Y > v1.Y) return +1; if (v0.Z < v1.Z) return -1; if (v0.Z > v1.Z) return +1; if (v0.W < v1.W) return -1; if (v0.W > v1.W) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint MinElement(V4ui v) => v.MinElement; /// /// Returns the maximum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint MaxElement(V4ui v) => v.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this V4ui v, uint epsilon) => v.X.IsTiny(epsilon) || v.Y.IsTiny(epsilon) || v.Z.IsTiny(epsilon) || v.W.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this V4ui v, uint epsilon) => v.X.IsTiny(epsilon) && v.Y.IsTiny(epsilon) && v.Z.IsTiny(epsilon) && v.W.IsTiny(epsilon); #endregion #region ArrayExtensions public static int IndexOfClosestPoint(this V4ui[] pointArray, V4ui point) { var bestDist = DistanceSquared(point, pointArray[0]); int bestIndex = 0; int count = pointArray.Length; for (int i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this V4ui[] array, int start, int count, V4ui point) { var bestDist = DistanceSquared(point, array[start]); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this T[] array, int start, int count, Func pointSelector, V4ui point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint(this V4ui[] pointArray, V4ui point) { var bestDist = DistanceSquared(point, pointArray[0]); long bestIndex = 0; long count = pointArray.LongLength; for (long i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this V4ui[] array, long start, long count, V4ui point) { var bestDist = DistanceSquared(point, array[start]); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this T[] array, long start, long count, Func pointSelector, V4ui point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static int IndexOfMinX(this V4ui[] vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static long LongIndexOfMinX(this V4ui[] vectorArray, long count = 0) { var minimum = vectorArray[0].X; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static int IndexOfMaxX(this V4ui[] vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static long LongIndexOfMaxX(this V4ui[] vectorArray, long count = 0) { var maximum = vectorArray[0].X; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static int IndexOfMinY(this V4ui[] vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static long LongIndexOfMinY(this V4ui[] vectorArray, long count = 0) { var minimum = vectorArray[0].Y; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static int IndexOfMaxY(this V4ui[] vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static long LongIndexOfMaxY(this V4ui[] vectorArray, long count = 0) { var maximum = vectorArray[0].Y; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static int IndexOfMinZ(this V4ui[] vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static long LongIndexOfMinZ(this V4ui[] vectorArray, long count = 0) { var minimum = vectorArray[0].Z; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static int IndexOfMaxZ(this V4ui[] vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static long LongIndexOfMaxZ(this V4ui[] vectorArray, long count = 0) { var maximum = vectorArray[0].Z; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal W coordinate /// within the array. /// public static int IndexOfMinW(this V4ui[] vectorArray, int count = 0) { var minimum = vectorArray[0].W; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal W coordinate /// within the array. /// public static long LongIndexOfMinW(this V4ui[] vectorArray, long count = 0) { var minimum = vectorArray[0].W; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].W; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal W coordinate /// within the array. /// public static int IndexOfMaxW(this V4ui[] vectorArray, int count = 0) { var maximum = vectorArray[0].W; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal W coordinate /// within the array. /// public static long LongIndexOfMaxW(this V4ui[] vectorArray, long count = 0) { var maximum = vectorArray[0].W; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].W; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the list. /// public static int IndexOfMinX(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the list. /// public static int IndexOfMaxX(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the list. /// public static int IndexOfMinY(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the list. /// public static int IndexOfMaxY(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the list. /// public static int IndexOfMinZ(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the list. /// public static int IndexOfMaxZ(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal W coordinate /// within the list. /// public static int IndexOfMinW(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].W; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal W coordinate /// within the list. /// public static int IndexOfMaxW(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].W; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the array of the index-th coordinate of each vector. /// public static uint[] CopyCoord(this V4ui[] self, int index) { switch (index) { case 0: return self.Map(v => v.X); case 1: return self.Map(v => v.Y); case 2: return self.Map(v => v.Z); case 3: return self.Map(v => v.W); default: throw new IndexOutOfRangeException(); } } #endregion } public static class IRandomUniformV4uiExtensions { #region IRandomUniform extensions for V4ui /// /// Uses UniformUInt() to generate the elements of a V4ui vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui UniformV4ui(this IRandomUniform rnd) { return new V4ui(rnd.UniformUInt(), rnd.UniformUInt(), rnd.UniformUInt(), rnd.UniformUInt()); } #endregion } #endregion #region V4l [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct V4l : IVector, ISize4l, IFormattable, IEquatable { [DataMember] public long X; [DataMember] public long Y; [DataMember] public long Z; [DataMember] public long W; #region Constructors /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(int x, int y, int z, int w) { X = (long)x; Y = (long)y; Z = (long)z; W = (long)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(int v) { X = (long)v; Y = (long)v; Z = (long)v; W = (long)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(int[] a) { X = (long)a[0]; Y = (long)a[1]; Z = (long)a[2]; W = (long)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(int[] a, int start) { X = (long)a[start + 0]; Y = (long)a[start + 1]; Z = (long)a[start + 2]; W = (long)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(int a, V3i b) { X = (long)a; Y = (long)b.X; Z = (long)b.Y; W = (long)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V2i a, V2i b) { X = (long)a.X; Y = (long)a.Y; Z = (long)b.X; W = (long)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V3i a, int b) { X = (long)a.X; Y = (long)a.Y; Z = (long)a.Z; W = (long)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V2i a, int b, int c) { X = (long)a.X; Y = (long)a.Y; Z = (long)b; W = (long)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(int a, V2i b, int c) { X = (long)a; Y = (long)b.X; Z = (long)b.Y; W = (long)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(int a, int b, V2i c) { X = (long)a; Y = (long)b; Z = (long)c.X; W = (long)c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(uint x, uint y, uint z, uint w) { X = (long)x; Y = (long)y; Z = (long)z; W = (long)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(uint v) { X = (long)v; Y = (long)v; Z = (long)v; W = (long)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(uint[] a) { X = (long)a[0]; Y = (long)a[1]; Z = (long)a[2]; W = (long)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(uint[] a, int start) { X = (long)a[start + 0]; Y = (long)a[start + 1]; Z = (long)a[start + 2]; W = (long)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(uint a, V3ui b) { X = (long)a; Y = (long)b.X; Z = (long)b.Y; W = (long)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V2ui a, V2ui b) { X = (long)a.X; Y = (long)a.Y; Z = (long)b.X; W = (long)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V3ui a, uint b) { X = (long)a.X; Y = (long)a.Y; Z = (long)a.Z; W = (long)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V2ui a, uint b, uint c) { X = (long)a.X; Y = (long)a.Y; Z = (long)b; W = (long)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(uint a, V2ui b, uint c) { X = (long)a; Y = (long)b.X; Z = (long)b.Y; W = (long)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(uint a, uint b, V2ui c) { X = (long)a; Y = (long)b; Z = (long)c.X; W = (long)c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(long x, long y, long z, long w) { X = x; Y = y; Z = z; W = w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(long v) { X = v; Y = v; Z = v; W = v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(long[] a) { X = a[0]; Y = a[1]; Z = a[2]; W = a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(long[] a, int start) { X = a[start + 0]; Y = a[start + 1]; Z = a[start + 2]; W = a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(long a, V3l b) { X = a; Y = b.X; Z = b.Y; W = b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V2l a, V2l b) { X = a.X; Y = a.Y; Z = b.X; W = b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V3l a, long b) { X = a.X; Y = a.Y; Z = a.Z; W = b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V2l a, long b, long c) { X = a.X; Y = a.Y; Z = b; W = c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(long a, V2l b, long c) { X = a; Y = b.X; Z = b.Y; W = c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(long a, long b, V2l c) { X = a; Y = b; Z = c.X; W = c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(float x, float y, float z, float w) { X = (long)x; Y = (long)y; Z = (long)z; W = (long)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(float v) { X = (long)v; Y = (long)v; Z = (long)v; W = (long)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(float[] a) { X = (long)a[0]; Y = (long)a[1]; Z = (long)a[2]; W = (long)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(float[] a, int start) { X = (long)a[start + 0]; Y = (long)a[start + 1]; Z = (long)a[start + 2]; W = (long)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(float a, V3f b) { X = (long)a; Y = (long)b.X; Z = (long)b.Y; W = (long)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V2f a, V2f b) { X = (long)a.X; Y = (long)a.Y; Z = (long)b.X; W = (long)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V3f a, float b) { X = (long)a.X; Y = (long)a.Y; Z = (long)a.Z; W = (long)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V2f a, float b, float c) { X = (long)a.X; Y = (long)a.Y; Z = (long)b; W = (long)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(float a, V2f b, float c) { X = (long)a; Y = (long)b.X; Z = (long)b.Y; W = (long)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(float a, float b, V2f c) { X = (long)a; Y = (long)b; Z = (long)c.X; W = (long)c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(double x, double y, double z, double w) { X = (long)x; Y = (long)y; Z = (long)z; W = (long)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(double v) { X = (long)v; Y = (long)v; Z = (long)v; W = (long)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(double[] a) { X = (long)a[0]; Y = (long)a[1]; Z = (long)a[2]; W = (long)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(double[] a, int start) { X = (long)a[start + 0]; Y = (long)a[start + 1]; Z = (long)a[start + 2]; W = (long)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(double a, V3d b) { X = (long)a; Y = (long)b.X; Z = (long)b.Y; W = (long)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V2d a, V2d b) { X = (long)a.X; Y = (long)a.Y; Z = (long)b.X; W = (long)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V3d a, double b) { X = (long)a.X; Y = (long)a.Y; Z = (long)a.Z; W = (long)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V2d a, double b, double c) { X = (long)a.X; Y = (long)a.Y; Z = (long)b; W = (long)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(double a, V2d b, double c) { X = (long)a; Y = (long)b.X; Z = (long)b.Y; W = (long)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(double a, double b, V2d c) { X = (long)a; Y = (long)b; Z = (long)c.X; W = (long)c.Y; } /// /// Creates a vector from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(Func index_fun) { X = index_fun(0); Y = index_fun(1); Z = index_fun(2); W = index_fun(3); } /// /// Creates a vector from a general vector implementing the IVector<long> interface. /// The caller has to verify that the dimension of is at least 4. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(IVector v) : this(v[0], v[1], v[2], v[3]) { } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V2i v) { X = (long)v.X; Y = (long)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V2ui v) { X = (long)v.X; Y = (long)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V2l v) { X = v.X; Y = v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V2f v) { X = (long)v.X; Y = (long)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V2d v) { X = (long)v.X; Y = (long)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V3i v) { X = (long)v.X; Y = (long)v.Y; Z = (long)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V3ui v) { X = (long)v.X; Y = (long)v.Y; Z = (long)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V3l v) { X = v.X; Y = v.Y; Z = v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V3f v) { X = (long)v.X; Y = (long)v.Y; Z = (long)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V3d v) { X = (long)v.X; Y = (long)v.Y; Z = (long)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V4i v) { X = (long)v.X; Y = (long)v.Y; Z = (long)v.Z; W = (long)v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V4ui v) { X = (long)v.X; Y = (long)v.Y; Z = (long)v.Z; W = (long)v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V4l v) { X = v.X; Y = v.Y; Z = v.Z; W = v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V4f v) { X = (long)v.X; Y = (long)v.Y; Z = (long)v.Z; W = (long)v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(V4d v) { X = (long)v.X; Y = (long)v.Y; Z = (long)v.Z; W = (long)v.W; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(C3b c) { X = (long)(c.R); Y = (long)(c.G); Z = (long)(c.B); W = (long)255; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(C3us c) { X = (long)(c.R); Y = (long)(c.G); Z = (long)(c.B); W = (long)65535; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// W is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(C3ui c) { X = (long)(c.R); Y = (long)(c.G); Z = (long)(c.B); W = (long)UInt32.MaxValue; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(C4b c) { X = (long)(c.R); Y = (long)(c.G); Z = (long)(c.B); W = (long)(c.A); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(C4us c) { X = (long)(c.R); Y = (long)(c.G); Z = (long)(c.B); W = (long)(c.A); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4l(C4ui c) { X = (long)(c.R); Y = (long)(c.G); Z = (long)(c.B); W = (long)(c.A); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(V2i v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(V2ui v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(V2l v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(V2f v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(V2d v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(V3i v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(V3ui v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(V3l v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(V3f v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(V3d v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(V4i v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(V4ui v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(V4f v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(V4d v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToV2i() => (V2i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui ToV2ui() => (V2ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f ToV2f() => (V2f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d ToV2d() => (V2d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int[](V4l v) => new int[] { (int)v.X, (int)v.Y, (int)v.Z, (int)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(int[] v) => new V4l((long)v[0], (long)v[1], (long)v[2], (long)v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](V4l v) => new uint[] { (uint)v.X, (uint)v.Y, (uint)v.Z, (uint)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(uint[] v) => new V4l((long)v[0], (long)v[1], (long)v[2], (long)v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long[](V4l v) => new long[] { v.X, v.Y, v.Z, v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(long[] v) => new V4l(v[0], v[1], v[2], v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](V4l v) => new float[] { (float)v.X, (float)v.Y, (float)v.Z, (float)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(float[] v) => new V4l((long)v[0], (long)v[1], (long)v[2], (long)v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](V4l v) => new double[] { (double)v.X, (double)v.Y, (double)v.Z, (double)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(double[] v) => new V4l((long)v[0], (long)v[1], (long)v[2], (long)v[3]); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(C3b v) => new V4l(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(C3us v) => new V4l(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(C3ui v) => new V4l(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(C4b v) => new V4l(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(C4us v) => new V4l(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4l(C4ui v) => new V4l(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i Copy(Func element_fun) => new V4i(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i Copy(Func element_index_fun) => new V4i(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(int[] array, int start) { array[start + 0] = (int)X; array[start + 1] = (int)Y; array[start + 2] = (int)Z; array[start + 3] = (int)W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui Copy(Func element_fun) => new V4ui(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui Copy(Func element_index_fun) => new V4ui(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(uint[] array, int start) { array[start + 0] = (uint)X; array[start + 1] = (uint)Y; array[start + 2] = (uint)Z; array[start + 3] = (uint)W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l Copy(Func element_fun) => new V4l(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l Copy(Func element_index_fun) => new V4l(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(long[] array, int start) { array[start + 0] = X; array[start + 1] = Y; array[start + 2] = Z; array[start + 3] = W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f Copy(Func element_fun) => new V4f(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f Copy(Func element_index_fun) => new V4f(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(float[] array, int start) { array[start + 0] = (float)X; array[start + 1] = (float)Y; array[start + 2] = (float)Z; array[start + 3] = (float)W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d Copy(Func element_fun) => new V4d(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d Copy(Func element_index_fun) => new V4d(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(double[] array, int start) { array[start + 0] = (double)X; array[start + 1] = (double)Y; array[start + 2] = (double)Z; array[start + 3] = (double)W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(X); array[start + 1] = element_fun(Y); array[start + 2] = element_fun(Z); array[start + 3] = element_fun(W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(X, 0); array[start + 1] = element_index_fun(Y, 1); array[start + 2] = element_index_fun(Z, 2); array[start + 3] = element_index_fun(W, 3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly long[] ToArray() => new long[] { X, Y, Z, W }; #endregion #region Properties and Indexers /// /// Property for the field X. /// Useful when properties are required, but the field X is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public long P_X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value; } } /// /// Property for the field Y. /// Useful when properties are required, but the field Y is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public long P_Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Y = value; } } /// /// Property for the field Z. /// Useful when properties are required, but the field Z is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public long P_Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Z = value; } } /// /// Property for the field W. /// Useful when properties are required, but the field W is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public long P_W { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { W = value; } } /// /// Enumerates all elements of this vector. /// public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return X; yield return Y; yield return Z; yield return W; } } /// /// Gets or sets element with given index. /// public unsafe long this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (long* ptr = &X) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (long* ptr = &X) { ptr[index] = value; } } } /// /// Returns the index of the largest dimension of the vector. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X >= Y ? (X >= Z ? (X >= W ? 0 : 3) : (Z >= W ? 2 : 3)) : (Y >= Z ? (Y >= W ? 1 : 3) : (Z >= W ? 2 : 3)); } } /// /// Returns the index of the smallest dimension of the vector. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X <= Y ? (X <= Z ? (X <= W ? 0 : 3) : (Z <= W ? 2 : 3)) : (Y <= Z ? (Y <= W ? 1 : 3) : (Z <= W ? 2 : 3)); } } /// /// Returns the minimum element of the vector. /// public readonly long MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(X, Y, Z, W); } /// /// Returns the maximum element of the vector. /// public readonly long MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(X, Y, Z, W); } #endregion #region Constants /// /// Number of elements in this vector. /// public const int Dimension = 4; /// /// All elements zero. /// public static V4l Zero { get { return new V4l(0, 0, 0, 0); } } /// /// All elements one. /// public static V4l One { get { return new V4l(1, 1, 1, 1); } } /// /// All elements set to maximum possible value. /// public static V4l MaxValue { get { return new V4l(Constant.ParseableMaxValue, Constant.ParseableMaxValue, Constant.ParseableMaxValue, Constant.ParseableMaxValue); } } /// /// All elements set to minimum possible value. /// public static V4l MinValue { get { return new V4l(Constant.ParseableMinValue, Constant.ParseableMinValue, Constant.ParseableMinValue, Constant.ParseableMinValue); } } /// /// Normalized X-axis. /// public static V4l XAxis { get { return new V4l(1, 0, 0, 0); } } /// /// Normalized Y-axis. /// public static V4l YAxis { get { return new V4l(0, 1, 0, 0); } } /// /// Normalized Z-axis. /// public static V4l ZAxis { get { return new V4l(0, 0, 1, 0); } } /// /// Normalized W-axis. /// public static V4l WAxis { get { return new V4l(0, 0, 0, 1); } } /// /// An array of accessor functions for the coordinates of the vector. /// public static readonly Func[] SelectorArray = new Func[] { v => v.X, v => v.Y, v => v.Z, v => v.W }; /// /// Element getter function. /// public static readonly Func Getter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; case 3: return v.W; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref V4l v, int i, long s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; case 3: v.W = s; return; default: throw new IndexOutOfRangeException(); } }; /// /// Element getter function with long index. /// public static readonly Func LongGetter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; case 3: return v.W; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action with long index. /// public static readonly ActionRefValVal LongSetter = (ref V4l v, long i, long s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; case 3: v.W = s; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Static factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l FromV4i(V4i v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l FromV4ui(V4ui v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l FromV4f(V4f v) => new V4l(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l FromV4d(V4d v) => new V4l(v); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l FromC3b(C3b c) => new V4l(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l FromC3us(C3us c) => new V4l(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// W is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l FromC3ui(C3ui c) => new V4l(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l FromC4b(C4b c) => new V4l(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l FromC4us(C4us c) => new V4l(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l FromC4ui(C4ui c) => new V4l(c); #endregion #region Norms /// /// Returns the squared length of the vector. /// public readonly long LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X * X + Y * Y + Z * Z + W * W ; } } /// /// Returns the length of the vector. /// public readonly double Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z + W * W ); } } /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// public readonly long Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Abs(X) + Fun.Abs(Y) + Fun.Abs(Z) + Fun.Abs(W); } } /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z + W * W); } } /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// public readonly long NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z), Fun.Abs(W)); } } /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// public readonly long NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z), Fun.Abs(W)); } } /// /// Returns a normalized copy of this vector. /// public readonly V4d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Length; if (s == 0) return V4d.Zero; s = 1 / s; return new V4d(X * s, Y * s, Z * s, W * s); } } #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Abs(V4l v) => v.Abs(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l LinearInterp(float t, V4l a, V4l b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l LinearInterp(V4f t, V4l a, V4l b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l LinearInterp(double t, V4l a, V4l b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l LinearInterp(V4d t, V4l a, V4l b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Min(V4l v0, V4l v1) => Fun.Min(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Min(V4l v, long x) => Fun.Min(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Max(V4l v0, V4l v1) => Fun.Max(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Max(V4l v, long x) => Fun.Max(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Saturate(V4l v) => Fun.Saturate(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l DivideByInt(V4l v, int x) => v / x; #endregion #region Operations /// /// Sets the elements of a vector to the given int elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(int x, int y, int z, int w) { X = (long)x; Y = (long)y; Z = (long)z; W = (long)w; } /// /// Sets the elements of a vector to the given uint elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(uint x, uint y, uint z, uint w) { X = (long)x; Y = (long)y; Z = (long)z; W = (long)w; } /// /// Sets the elements of a vector to the given long elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(long x, long y, long z, long w) { X = x; Y = y; Z = z; W = w; } /// /// Sets the elements of a vector to the given float elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(float x, float y, float z, float w) { X = (long)x; Y = (long)y; Z = (long)z; W = (long)w; } /// /// Sets the elements of a vector to the given double elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(double x, double y, double z, double w) { X = (long)x; Y = (long)y; Z = (long)z; W = (long)w; } /// /// Returns a negated copy of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator -(V4l v) => new V4l(-v.X, -v.Y, -v.Z, -v.W); /// /// Returns the component-wise bitwise complement of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator ~(V4l v) => new V4l(~v.X, ~v.Y, ~v.Z, ~v.W); /// /// Returns the component-wise sum of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator +(V4l a, V4l b) => new V4l(a.X + b.X, a.Y + b.Y, a.Z + b.Z, a.W + b.W); /// /// Returns the component-wise sum of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator +(V4l v, long s) => new V4l(v.X + s, v.Y + s, v.Z + s, v.W + s); /// /// Returns the component-wise sum of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator +(long s, V4l v) => new V4l(s + v.X, s + v.Y, s + v.Z, s + v.W); /// /// Returns the component-wise difference of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator -(V4l a, V4l b) => new V4l(a.X - b.X, a.Y - b.Y, a.Z - b.Z, a.W - b.W); /// /// Returns the component-wise difference of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator -(V4l v, long s) => new V4l(v.X - s, v.Y - s, v.Z - s, v.W - s); /// /// Returns the component-wise difference of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator -(long s, V4l v) => new V4l(s - v.X, s - v.Y, s - v.Z, s - v.W); /// /// Returns the component-wise product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator *(V4l a, V4l b) => new V4l(a.X * b.X, a.Y * b.Y, a.Z * b.Z, a.W * b.W); /// /// Returns the component-wise product of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator *(V4l v, long s) => new V4l(v.X * s, v.Y * s, v.Z * s, v.W * s); /// /// Returns the component-wise product of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator *(long s, V4l v) => new V4l(s * v.X, s * v.Y, s * v.Z, s * v.W); /// /// Returns the component-wise fraction of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator /(V4l a, V4l b) => new V4l(a.X / b.X, a.Y / b.Y, a.Z / b.Z, a.W / b.W); /// /// Returns the component-wise fraction of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator /(V4l v, long s) => new V4l(v.X / s, v.Y / s, v.Z / s, v.W / s); /// /// Returns the component-wise fraction of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator /(long s, V4l v) => new V4l(s / v.X, s / v.Y, s / v.Z, s / v.W); /// /// Returns the component-wise remainder of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator %(V4l a, V4l b) => new V4l(a.X % b.X, a.Y % b.Y, a.Z % b.Z, a.W % b.W); /// /// Returns the component-wise remainder of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator %(V4l v, long s) => new V4l(v.X % s, v.Y % s, v.Z % s, v.W % s); /// /// Returns the component-wise remainder of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator %(long s, V4l v) => new V4l(s % v.X, s % v.Y, s % v.Z, s % v.W); /// /// Returns the component-wise bitwise and of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator &(V4l a, V4l b) => new V4l(a.X & b.X, a.Y & b.Y, a.Z & b.Z, a.W & b.W); /// /// Returns the component-wise bitwise and of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator &(V4l v, long s) => new V4l(v.X & s, v.Y & s, v.Z & s, v.W & s); /// /// Returns the component-wise bitwise and of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator &(long s, V4l v) => new V4l(s & v.X, s & v.Y, s & v.Z, s & v.W); /// /// Returns the component-wise bitwise or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator |(V4l a, V4l b) => new V4l(a.X | b.X, a.Y | b.Y, a.Z | b.Z, a.W | b.W); /// /// Returns the component-wise bitwise or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator |(V4l v, long s) => new V4l(v.X | s, v.Y | s, v.Z | s, v.W | s); /// /// Returns the component-wise bitwise or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator |(long s, V4l v) => new V4l(s | v.X, s | v.Y, s | v.Z, s | v.W); /// /// Returns the component-wise bitwise exclusive or of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator ^(V4l a, V4l b) => new V4l(a.X ^ b.X, a.Y ^ b.Y, a.Z ^ b.Z, a.W ^ b.W); /// /// Returns the component-wise bitwise exclusive or of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator ^(V4l v, long s) => new V4l(v.X ^ s, v.Y ^ s, v.Z ^ s, v.W ^ s); /// /// Returns the component-wise bitwise exclusive or of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator ^(long s, V4l v) => new V4l(s ^ v.X, s ^ v.Y, s ^ v.Z, s ^ v.W); /// /// Returns the component-wise left bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator <<(V4l v, int s) => new V4l(v.X << s, v.Y << s, v.Z << s, v.W << s); /// /// Returns the component-wise right bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l operator >>(V4l v, int s) => new V4l(v.X >> s, v.Y >> s, v.Z >> s, v.W >> s); /// Attention: NEVER implement operators <, <=, >=, >, /// since these are not defined in a Vector space. /// Use AllSmaller() and similar comparators! #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V4l a, V4l b) { return a.X == b.X && a.Y == b.Y && a.Z == b.Z && a.W == b.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V4l v, long s) { return v.X == s && v.Y == s && v.Z == s && v.W == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(long s, V4l v) { return s == v.X && s == v.Y && s == v.Z && s == v.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V4l a, V4l b) { return a.X != b.X || a.Y != b.Y || a.Z != b.Z || a.W != b.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V4l v, long s) { return v.X != s || v.Y != s || v.Z != s || v.W != s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(long s, V4l v) { return s != v.X || s != v.Y || s != v.Z || s != v.W; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(V4l other) { return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && W.Equals(other.W); } #endregion #region Overrides public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + X.ToString(format, fp) + between + Y.ToString(format, fp) + between + Z.ToString(format, fp) + between + W.ToString(format, fp) + end; } public override readonly int GetHashCode() { return HashCode.GetCombined(X, Y, Z, W); } public override readonly bool Equals(object other) => (other is V4l o) ? Equals(o) : false; public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + X.ToString(null, CultureInfo.InvariantCulture) + ", " + Y.ToString(null, CultureInfo.InvariantCulture) + ", " + Z.ToString(null, CultureInfo.InvariantCulture) + ", " + W.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Parsing public static V4l Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new V4l( long.Parse(x[0], CultureInfo.InvariantCulture), long.Parse(x[1], CultureInfo.InvariantCulture), long.Parse(x[2], CultureInfo.InvariantCulture), long.Parse(x[3], CultureInfo.InvariantCulture) ); } public static V4l Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, V4l.Setter); } public static V4l Parse(Text t, int bracketLevel) { return t.NestedBracketSplit(bracketLevel, Text.Parse, V4l.Setter); } #endregion #region Swizzle Methods [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l OX => new V2l(0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l OY => new V2l(0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l OZ => new V2l(0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l OW => new V2l(0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l IX => new V2l(1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l IY => new V2l(1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l IZ => new V2l(1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l IW => new V2l(1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l NX => new V2l(-1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l NY => new V2l(-1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l NZ => new V2l(-1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l NW => new V2l(-1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l XO => new V2l(X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l XI => new V2l(X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l XN => new V2l(X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l XX => new V2l(X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l XY { readonly get => new V2l(X, Y); set { X = value.X; Y = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l XZ { readonly get => new V2l(X, Z); set { X = value.X; Z = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l XW { readonly get => new V2l(X, W); set { X = value.X; W = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l YO => new V2l(Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l YI => new V2l(Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l YN => new V2l(Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l YX { readonly get => new V2l(Y, X); set { Y = value.X; X = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l YY => new V2l(Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l YZ { readonly get => new V2l(Y, Z); set { Y = value.X; Z = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l YW { readonly get => new V2l(Y, W); set { Y = value.X; W = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l ZO => new V2l(Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l ZI => new V2l(Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l ZN => new V2l(Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l ZX { readonly get => new V2l(Z, X); set { Z = value.X; X = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l ZY { readonly get => new V2l(Z, Y); set { Z = value.X; Y = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l ZZ => new V2l(Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l ZW { readonly get => new V2l(Z, W); set { Z = value.X; W = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l WO => new V2l(W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l WI => new V2l(W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l WN => new V2l(W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l WX { readonly get => new V2l(W, X); set { W = value.X; X = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l WY { readonly get => new V2l(W, Y); set { W = value.X; Y = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2l WZ { readonly get => new V2l(W, Z); set { W = value.X; Z = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2l WW => new V2l(W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OOX => new V3l(0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OOY => new V3l(0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OOZ => new V3l(0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OOW => new V3l(0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OIX => new V3l(0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OIY => new V3l(0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OIZ => new V3l(0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OIW => new V3l(0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ONX => new V3l(0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ONY => new V3l(0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ONZ => new V3l(0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ONW => new V3l(0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXO => new V3l(0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXI => new V3l(0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXN => new V3l(0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXX => new V3l(0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXY => new V3l(0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXZ => new V3l(0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OXW => new V3l(0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYO => new V3l(0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYI => new V3l(0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYN => new V3l(0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYX => new V3l(0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYY => new V3l(0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYZ => new V3l(0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OYW => new V3l(0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OZO => new V3l(0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OZI => new V3l(0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OZN => new V3l(0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OZX => new V3l(0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OZY => new V3l(0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OZZ => new V3l(0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OZW => new V3l(0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OWO => new V3l(0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OWI => new V3l(0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OWN => new V3l(0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OWX => new V3l(0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OWY => new V3l(0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OWZ => new V3l(0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l OWW => new V3l(0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IOX => new V3l(1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IOY => new V3l(1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IOZ => new V3l(1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IOW => new V3l(1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IIX => new V3l(1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IIY => new V3l(1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IIZ => new V3l(1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IIW => new V3l(1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PNX => new V3l(1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PNY => new V3l(1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PNZ => new V3l(1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PNW => new V3l(1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IXO => new V3l(1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IXI => new V3l(1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PXN => new V3l(1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IXX => new V3l(1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IXY => new V3l(1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IXZ => new V3l(1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IXW => new V3l(1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IYO => new V3l(1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IYI => new V3l(1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PYN => new V3l(1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IYX => new V3l(1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IYY => new V3l(1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IYZ => new V3l(1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IYW => new V3l(1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IZO => new V3l(1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IZI => new V3l(1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PZN => new V3l(1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IZX => new V3l(1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IZY => new V3l(1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IZZ => new V3l(1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IZW => new V3l(1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IWO => new V3l(1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IWI => new V3l(1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l PWN => new V3l(1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IWX => new V3l(1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IWY => new V3l(1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IWZ => new V3l(1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l IWW => new V3l(1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NOX => new V3l(-1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NOY => new V3l(-1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NOZ => new V3l(-1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NOW => new V3l(-1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NPX => new V3l(-1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NPY => new V3l(-1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NPZ => new V3l(-1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NPW => new V3l(-1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NNX => new V3l(-1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NNY => new V3l(-1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NNZ => new V3l(-1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NNW => new V3l(-1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXO => new V3l(-1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXP => new V3l(-1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXN => new V3l(-1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXX => new V3l(-1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXY => new V3l(-1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXZ => new V3l(-1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NXW => new V3l(-1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYO => new V3l(-1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYP => new V3l(-1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYN => new V3l(-1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYX => new V3l(-1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYY => new V3l(-1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYZ => new V3l(-1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NYW => new V3l(-1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NZO => new V3l(-1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NZP => new V3l(-1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NZN => new V3l(-1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NZX => new V3l(-1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NZY => new V3l(-1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NZZ => new V3l(-1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NZW => new V3l(-1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NWO => new V3l(-1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NWP => new V3l(-1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NWN => new V3l(-1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NWX => new V3l(-1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NWY => new V3l(-1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NWZ => new V3l(-1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l NWW => new V3l(-1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XOO => new V3l(X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XOI => new V3l(X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XON => new V3l(X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XOX => new V3l(X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XOY => new V3l(X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XOZ => new V3l(X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XOW => new V3l(X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XIO => new V3l(X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XII => new V3l(X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XPN => new V3l(X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XIX => new V3l(X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XIY => new V3l(X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XIZ => new V3l(X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XIW => new V3l(X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNO => new V3l(X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNP => new V3l(X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNN => new V3l(X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNX => new V3l(X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNY => new V3l(X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNZ => new V3l(X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XNW => new V3l(X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXO => new V3l(X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXI => new V3l(X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXN => new V3l(X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXX => new V3l(X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXY => new V3l(X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXZ => new V3l(X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XXW => new V3l(X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XYO => new V3l(X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XYI => new V3l(X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XYN => new V3l(X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XYX => new V3l(X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XYY => new V3l(X, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l XYZ { readonly get => new V3l(X, Y, Z); set { X = value.X; Y = value.Y; Z = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l XYW { readonly get => new V3l(X, Y, W); set { X = value.X; Y = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XZO => new V3l(X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XZI => new V3l(X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XZN => new V3l(X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XZX => new V3l(X, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l XZY { readonly get => new V3l(X, Z, Y); set { X = value.X; Z = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XZZ => new V3l(X, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l XZW { readonly get => new V3l(X, Z, W); set { X = value.X; Z = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XWO => new V3l(X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XWI => new V3l(X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XWN => new V3l(X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XWX => new V3l(X, W, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l XWY { readonly get => new V3l(X, W, Y); set { X = value.X; W = value.Y; Y = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l XWZ { readonly get => new V3l(X, W, Z); set { X = value.X; W = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l XWW => new V3l(X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YOO => new V3l(Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YOI => new V3l(Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YON => new V3l(Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YOX => new V3l(Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YOY => new V3l(Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YOZ => new V3l(Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YOW => new V3l(Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YIO => new V3l(Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YII => new V3l(Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YPN => new V3l(Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YIX => new V3l(Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YIY => new V3l(Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YIZ => new V3l(Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YIW => new V3l(Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNO => new V3l(Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNP => new V3l(Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNN => new V3l(Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNX => new V3l(Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNY => new V3l(Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNZ => new V3l(Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YNW => new V3l(Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YXO => new V3l(Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YXI => new V3l(Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YXN => new V3l(Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YXX => new V3l(Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YXY => new V3l(Y, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l YXZ { readonly get => new V3l(Y, X, Z); set { Y = value.X; X = value.Y; Z = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l YXW { readonly get => new V3l(Y, X, W); set { Y = value.X; X = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYO => new V3l(Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYI => new V3l(Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYN => new V3l(Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYX => new V3l(Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYY => new V3l(Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYZ => new V3l(Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YYW => new V3l(Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YZO => new V3l(Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YZI => new V3l(Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YZN => new V3l(Y, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l YZX { readonly get => new V3l(Y, Z, X); set { Y = value.X; Z = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YZY => new V3l(Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YZZ => new V3l(Y, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l YZW { readonly get => new V3l(Y, Z, W); set { Y = value.X; Z = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YWO => new V3l(Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YWI => new V3l(Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YWN => new V3l(Y, W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l YWX { readonly get => new V3l(Y, W, X); set { Y = value.X; W = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YWY => new V3l(Y, W, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l YWZ { readonly get => new V3l(Y, W, Z); set { Y = value.X; W = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l YWW => new V3l(Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZOO => new V3l(Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZOI => new V3l(Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZON => new V3l(Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZOX => new V3l(Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZOY => new V3l(Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZOZ => new V3l(Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZOW => new V3l(Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZIO => new V3l(Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZII => new V3l(Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZPN => new V3l(Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZIX => new V3l(Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZIY => new V3l(Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZIZ => new V3l(Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZIW => new V3l(Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZNO => new V3l(Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZNP => new V3l(Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZNN => new V3l(Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZNX => new V3l(Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZNY => new V3l(Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZNZ => new V3l(Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZNW => new V3l(Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZXO => new V3l(Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZXI => new V3l(Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZXN => new V3l(Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZXX => new V3l(Z, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l ZXY { readonly get => new V3l(Z, X, Y); set { Z = value.X; X = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZXZ => new V3l(Z, X, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l ZXW { readonly get => new V3l(Z, X, W); set { Z = value.X; X = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZYO => new V3l(Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZYI => new V3l(Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZYN => new V3l(Z, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l ZYX { readonly get => new V3l(Z, Y, X); set { Z = value.X; Y = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZYY => new V3l(Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZYZ => new V3l(Z, Y, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l ZYW { readonly get => new V3l(Z, Y, W); set { Z = value.X; Y = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZZO => new V3l(Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZZI => new V3l(Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZZN => new V3l(Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZZX => new V3l(Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZZY => new V3l(Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZZZ => new V3l(Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZZW => new V3l(Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZWO => new V3l(Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZWI => new V3l(Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZWN => new V3l(Z, W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l ZWX { readonly get => new V3l(Z, W, X); set { Z = value.X; W = value.Y; X = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l ZWY { readonly get => new V3l(Z, W, Y); set { Z = value.X; W = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZWZ => new V3l(Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l ZWW => new V3l(Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WOO => new V3l(W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WOI => new V3l(W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WON => new V3l(W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WOX => new V3l(W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WOY => new V3l(W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WOZ => new V3l(W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WOW => new V3l(W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WIO => new V3l(W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WII => new V3l(W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WPN => new V3l(W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WIX => new V3l(W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WIY => new V3l(W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WIZ => new V3l(W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WIW => new V3l(W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WNO => new V3l(W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WNP => new V3l(W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WNN => new V3l(W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WNX => new V3l(W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WNY => new V3l(W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WNZ => new V3l(W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WNW => new V3l(W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WXO => new V3l(W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WXI => new V3l(W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WXN => new V3l(W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WXX => new V3l(W, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l WXY { readonly get => new V3l(W, X, Y); set { W = value.X; X = value.Y; Y = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l WXZ { readonly get => new V3l(W, X, Z); set { W = value.X; X = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WXW => new V3l(W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WYO => new V3l(W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WYI => new V3l(W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WYN => new V3l(W, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l WYX { readonly get => new V3l(W, Y, X); set { W = value.X; Y = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WYY => new V3l(W, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l WYZ { readonly get => new V3l(W, Y, Z); set { W = value.X; Y = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WYW => new V3l(W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WZO => new V3l(W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WZI => new V3l(W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WZN => new V3l(W, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l WZX { readonly get => new V3l(W, Z, X); set { W = value.X; Z = value.Y; X = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3l WZY { readonly get => new V3l(W, Z, Y); set { W = value.X; Z = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WZZ => new V3l(W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WZW => new V3l(W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WWO => new V3l(W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WWI => new V3l(W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WWN => new V3l(W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WWX => new V3l(W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WWY => new V3l(W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WWZ => new V3l(W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3l WWW => new V3l(W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OOOO => new V4l(0, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OOOI => new V4l(0, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OOON => new V4l(0, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOOX => new V4l(0, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOOY => new V4l(0, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOOZ => new V4l(0, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOOW => new V4l(0, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OOIO => new V4l(0, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OOII => new V4l(0, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OOPN => new V4l(0, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOIX => new V4l(0, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOIY => new V4l(0, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOIZ => new V4l(0, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOIW => new V4l(0, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OONO => new V4l(0, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OONP => new V4l(0, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OONN => new V4l(0, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OONX => new V4l(0, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OONY => new V4l(0, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OONZ => new V4l(0, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OONW => new V4l(0, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXO => new V4l(0, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXI => new V4l(0, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXN => new V4l(0, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXX => new V4l(0, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXY => new V4l(0, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXZ => new V4l(0, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOXW => new V4l(0, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYO => new V4l(0, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYI => new V4l(0, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYN => new V4l(0, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYX => new V4l(0, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYY => new V4l(0, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYZ => new V4l(0, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOYW => new V4l(0, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOZO => new V4l(0, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOZI => new V4l(0, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOZN => new V4l(0, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOZX => new V4l(0, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOZY => new V4l(0, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOZZ => new V4l(0, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOZW => new V4l(0, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOWO => new V4l(0, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOWI => new V4l(0, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOWN => new V4l(0, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOWX => new V4l(0, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOWY => new V4l(0, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOWZ => new V4l(0, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OOWW => new V4l(0, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OIOO => new V4l(0, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OIOI => new V4l(0, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OPON => new V4l(0, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIOX => new V4l(0, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIOY => new V4l(0, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIOZ => new V4l(0, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIOW => new V4l(0, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OIIO => new V4l(0, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OIII => new V4l(0, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OPPN => new V4l(0, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIIX => new V4l(0, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIIY => new V4l(0, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIIZ => new V4l(0, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIIW => new V4l(0, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OPNO => new V4l(0, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OPNP => new V4l(0, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l OPNN => new V4l(0, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPNX => new V4l(0, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPNY => new V4l(0, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPNZ => new V4l(0, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPNW => new V4l(0, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIXO => new V4l(0, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIXI => new V4l(0, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPXN => new V4l(0, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIXX => new V4l(0, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIXY => new V4l(0, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIXZ => new V4l(0, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIXW => new V4l(0, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIYO => new V4l(0, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIYI => new V4l(0, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPYN => new V4l(0, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIYX => new V4l(0, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIYY => new V4l(0, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIYZ => new V4l(0, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIYW => new V4l(0, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIZO => new V4l(0, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIZI => new V4l(0, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPZN => new V4l(0, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIZX => new V4l(0, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIZY => new V4l(0, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIZZ => new V4l(0, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIZW => new V4l(0, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIWO => new V4l(0, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIWI => new V4l(0, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OPWN => new V4l(0, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIWX => new V4l(0, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIWY => new V4l(0, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIWZ => new V4l(0, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OIWW => new V4l(0, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l ONOO => new V4l(0, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l ONOP => new V4l(0, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l ONON => new V4l(0, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONOX => new V4l(0, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONOY => new V4l(0, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONOZ => new V4l(0, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONOW => new V4l(0, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l ONPO => new V4l(0, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l ONPP => new V4l(0, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l ONPN => new V4l(0, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONPX => new V4l(0, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONPY => new V4l(0, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONPZ => new V4l(0, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONPW => new V4l(0, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l ONNO => new V4l(0, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l ONNP => new V4l(0, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l ONNN => new V4l(0, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONNX => new V4l(0, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONNY => new V4l(0, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONNZ => new V4l(0, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONNW => new V4l(0, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXO => new V4l(0, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXP => new V4l(0, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXN => new V4l(0, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXX => new V4l(0, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXY => new V4l(0, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXZ => new V4l(0, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONXW => new V4l(0, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYO => new V4l(0, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYP => new V4l(0, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYN => new V4l(0, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYX => new V4l(0, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYY => new V4l(0, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYZ => new V4l(0, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONYW => new V4l(0, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONZO => new V4l(0, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONZP => new V4l(0, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONZN => new V4l(0, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONZX => new V4l(0, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONZY => new V4l(0, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONZZ => new V4l(0, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONZW => new V4l(0, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONWO => new V4l(0, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONWP => new V4l(0, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONWN => new V4l(0, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONWX => new V4l(0, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONWY => new V4l(0, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONWZ => new V4l(0, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ONWW => new V4l(0, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXOO => new V4l(0, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXOI => new V4l(0, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXON => new V4l(0, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXOX => new V4l(0, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXOY => new V4l(0, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXOZ => new V4l(0, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXOW => new V4l(0, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXIO => new V4l(0, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXII => new V4l(0, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXPN => new V4l(0, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXIX => new V4l(0, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXIY => new V4l(0, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXIZ => new V4l(0, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXIW => new V4l(0, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNO => new V4l(0, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNP => new V4l(0, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNN => new V4l(0, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNX => new V4l(0, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNY => new V4l(0, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNZ => new V4l(0, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXNW => new V4l(0, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXO => new V4l(0, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXI => new V4l(0, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXN => new V4l(0, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXX => new V4l(0, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXY => new V4l(0, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXZ => new V4l(0, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXXW => new V4l(0, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYO => new V4l(0, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYI => new V4l(0, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYN => new V4l(0, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYX => new V4l(0, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYY => new V4l(0, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYZ => new V4l(0, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXYW => new V4l(0, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXZO => new V4l(0, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXZI => new V4l(0, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXZN => new V4l(0, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXZX => new V4l(0, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXZY => new V4l(0, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXZZ => new V4l(0, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXZW => new V4l(0, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXWO => new V4l(0, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXWI => new V4l(0, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXWN => new V4l(0, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXWX => new V4l(0, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXWY => new V4l(0, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXWZ => new V4l(0, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OXWW => new V4l(0, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYOO => new V4l(0, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYOI => new V4l(0, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYON => new V4l(0, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYOX => new V4l(0, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYOY => new V4l(0, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYOZ => new V4l(0, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYOW => new V4l(0, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYIO => new V4l(0, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYII => new V4l(0, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYPN => new V4l(0, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYIX => new V4l(0, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYIY => new V4l(0, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYIZ => new V4l(0, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYIW => new V4l(0, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNO => new V4l(0, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNP => new V4l(0, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNN => new V4l(0, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNX => new V4l(0, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNY => new V4l(0, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNZ => new V4l(0, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYNW => new V4l(0, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXO => new V4l(0, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXI => new V4l(0, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXN => new V4l(0, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXX => new V4l(0, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXY => new V4l(0, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXZ => new V4l(0, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYXW => new V4l(0, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYO => new V4l(0, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYI => new V4l(0, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYN => new V4l(0, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYX => new V4l(0, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYY => new V4l(0, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYZ => new V4l(0, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYYW => new V4l(0, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYZO => new V4l(0, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYZI => new V4l(0, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYZN => new V4l(0, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYZX => new V4l(0, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYZY => new V4l(0, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYZZ => new V4l(0, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYZW => new V4l(0, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYWO => new V4l(0, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYWI => new V4l(0, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYWN => new V4l(0, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYWX => new V4l(0, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYWY => new V4l(0, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYWZ => new V4l(0, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OYWW => new V4l(0, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZOO => new V4l(0, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZOI => new V4l(0, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZON => new V4l(0, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZOX => new V4l(0, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZOY => new V4l(0, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZOZ => new V4l(0, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZOW => new V4l(0, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZIO => new V4l(0, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZII => new V4l(0, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZPN => new V4l(0, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZIX => new V4l(0, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZIY => new V4l(0, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZIZ => new V4l(0, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZIW => new V4l(0, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZNO => new V4l(0, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZNP => new V4l(0, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZNN => new V4l(0, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZNX => new V4l(0, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZNY => new V4l(0, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZNZ => new V4l(0, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZNW => new V4l(0, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZXO => new V4l(0, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZXI => new V4l(0, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZXN => new V4l(0, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZXX => new V4l(0, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZXY => new V4l(0, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZXZ => new V4l(0, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZXW => new V4l(0, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZYO => new V4l(0, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZYI => new V4l(0, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZYN => new V4l(0, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZYX => new V4l(0, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZYY => new V4l(0, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZYZ => new V4l(0, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZYW => new V4l(0, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZZO => new V4l(0, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZZI => new V4l(0, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZZN => new V4l(0, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZZX => new V4l(0, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZZY => new V4l(0, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZZZ => new V4l(0, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZZW => new V4l(0, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZWO => new V4l(0, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZWI => new V4l(0, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZWN => new V4l(0, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZWX => new V4l(0, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZWY => new V4l(0, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZWZ => new V4l(0, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OZWW => new V4l(0, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWOO => new V4l(0, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWOI => new V4l(0, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWON => new V4l(0, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWOX => new V4l(0, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWOY => new V4l(0, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWOZ => new V4l(0, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWOW => new V4l(0, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWIO => new V4l(0, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWII => new V4l(0, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWPN => new V4l(0, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWIX => new V4l(0, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWIY => new V4l(0, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWIZ => new V4l(0, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWIW => new V4l(0, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWNO => new V4l(0, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWNP => new V4l(0, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWNN => new V4l(0, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWNX => new V4l(0, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWNY => new V4l(0, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWNZ => new V4l(0, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWNW => new V4l(0, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWXO => new V4l(0, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWXI => new V4l(0, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWXN => new V4l(0, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWXX => new V4l(0, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWXY => new V4l(0, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWXZ => new V4l(0, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWXW => new V4l(0, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWYO => new V4l(0, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWYI => new V4l(0, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWYN => new V4l(0, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWYX => new V4l(0, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWYY => new V4l(0, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWYZ => new V4l(0, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWYW => new V4l(0, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWZO => new V4l(0, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWZI => new V4l(0, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWZN => new V4l(0, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWZX => new V4l(0, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWZY => new V4l(0, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWZZ => new V4l(0, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWZW => new V4l(0, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWWO => new V4l(0, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWWI => new V4l(0, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWWN => new V4l(0, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWWX => new V4l(0, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWWY => new V4l(0, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWWZ => new V4l(0, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l OWWW => new V4l(0, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l IOOO => new V4l(1, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l IOOI => new V4l(1, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l POON => new V4l(1, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOOX => new V4l(1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOOY => new V4l(1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOOZ => new V4l(1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOOW => new V4l(1, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l IOIO => new V4l(1, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l IOII => new V4l(1, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l POPN => new V4l(1, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOIX => new V4l(1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOIY => new V4l(1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOIZ => new V4l(1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOIW => new V4l(1, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PONO => new V4l(1, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PONP => new V4l(1, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PONN => new V4l(1, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PONX => new V4l(1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PONY => new V4l(1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PONZ => new V4l(1, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PONW => new V4l(1, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOXO => new V4l(1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOXI => new V4l(1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l POXN => new V4l(1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOXX => new V4l(1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOXY => new V4l(1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOXZ => new V4l(1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOXW => new V4l(1, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOYO => new V4l(1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOYI => new V4l(1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l POYN => new V4l(1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOYX => new V4l(1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOYY => new V4l(1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOYZ => new V4l(1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOYW => new V4l(1, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOZO => new V4l(1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOZI => new V4l(1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l POZN => new V4l(1, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOZX => new V4l(1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOZY => new V4l(1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOZZ => new V4l(1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOZW => new V4l(1, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOWO => new V4l(1, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOWI => new V4l(1, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l POWN => new V4l(1, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOWX => new V4l(1, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOWY => new V4l(1, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOWZ => new V4l(1, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IOWW => new V4l(1, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l IIOO => new V4l(1, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l IIOI => new V4l(1, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PPON => new V4l(1, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIOX => new V4l(1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIOY => new V4l(1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIOZ => new V4l(1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIOW => new V4l(1, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l IIIO => new V4l(1, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l IIII => new V4l(1, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PPPN => new V4l(1, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIIX => new V4l(1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIIY => new V4l(1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIIZ => new V4l(1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIIW => new V4l(1, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PPNO => new V4l(1, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PPNP => new V4l(1, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PPNN => new V4l(1, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPNX => new V4l(1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPNY => new V4l(1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPNZ => new V4l(1, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPNW => new V4l(1, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIXO => new V4l(1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIXI => new V4l(1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPXN => new V4l(1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIXX => new V4l(1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIXY => new V4l(1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIXZ => new V4l(1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIXW => new V4l(1, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIYO => new V4l(1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIYI => new V4l(1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPYN => new V4l(1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIYX => new V4l(1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIYY => new V4l(1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIYZ => new V4l(1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIYW => new V4l(1, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIZO => new V4l(1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIZI => new V4l(1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPZN => new V4l(1, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIZX => new V4l(1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIZY => new V4l(1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIZZ => new V4l(1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIZW => new V4l(1, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIWO => new V4l(1, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIWI => new V4l(1, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PPWN => new V4l(1, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIWX => new V4l(1, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIWY => new V4l(1, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIWZ => new V4l(1, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IIWW => new V4l(1, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PNOO => new V4l(1, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PNOP => new V4l(1, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PNON => new V4l(1, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNOX => new V4l(1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNOY => new V4l(1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNOZ => new V4l(1, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNOW => new V4l(1, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PNPO => new V4l(1, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PNPP => new V4l(1, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PNPN => new V4l(1, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNPX => new V4l(1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNPY => new V4l(1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNPZ => new V4l(1, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNPW => new V4l(1, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PNNO => new V4l(1, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PNNP => new V4l(1, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l PNNN => new V4l(1, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNNX => new V4l(1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNNY => new V4l(1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNNZ => new V4l(1, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNNW => new V4l(1, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXO => new V4l(1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXP => new V4l(1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXN => new V4l(1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXX => new V4l(1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXY => new V4l(1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXZ => new V4l(1, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNXW => new V4l(1, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYO => new V4l(1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYP => new V4l(1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYN => new V4l(1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYX => new V4l(1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYY => new V4l(1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYZ => new V4l(1, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNYW => new V4l(1, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNZO => new V4l(1, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNZP => new V4l(1, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNZN => new V4l(1, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNZX => new V4l(1, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNZY => new V4l(1, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNZZ => new V4l(1, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNZW => new V4l(1, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNWO => new V4l(1, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNWP => new V4l(1, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNWN => new V4l(1, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNWX => new V4l(1, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNWY => new V4l(1, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNWZ => new V4l(1, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PNWW => new V4l(1, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXOO => new V4l(1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXOI => new V4l(1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXON => new V4l(1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXOX => new V4l(1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXOY => new V4l(1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXOZ => new V4l(1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXOW => new V4l(1, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXIO => new V4l(1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXII => new V4l(1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXPN => new V4l(1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXIX => new V4l(1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXIY => new V4l(1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXIZ => new V4l(1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXIW => new V4l(1, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNO => new V4l(1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNP => new V4l(1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNN => new V4l(1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNX => new V4l(1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNY => new V4l(1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNZ => new V4l(1, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXNW => new V4l(1, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXXO => new V4l(1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXXI => new V4l(1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXXN => new V4l(1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXXX => new V4l(1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXXY => new V4l(1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXXZ => new V4l(1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXXW => new V4l(1, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXYO => new V4l(1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXYI => new V4l(1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXYN => new V4l(1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXYX => new V4l(1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXYY => new V4l(1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXYZ => new V4l(1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXYW => new V4l(1, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXZO => new V4l(1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXZI => new V4l(1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXZN => new V4l(1, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXZX => new V4l(1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXZY => new V4l(1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXZZ => new V4l(1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXZW => new V4l(1, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXWO => new V4l(1, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXWI => new V4l(1, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PXWN => new V4l(1, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXWX => new V4l(1, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXWY => new V4l(1, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXWZ => new V4l(1, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IXWW => new V4l(1, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYOO => new V4l(1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYOI => new V4l(1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYON => new V4l(1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYOX => new V4l(1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYOY => new V4l(1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYOZ => new V4l(1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYOW => new V4l(1, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYIO => new V4l(1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYII => new V4l(1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYPN => new V4l(1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYIX => new V4l(1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYIY => new V4l(1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYIZ => new V4l(1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYIW => new V4l(1, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNO => new V4l(1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNP => new V4l(1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNN => new V4l(1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNX => new V4l(1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNY => new V4l(1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNZ => new V4l(1, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYNW => new V4l(1, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYXO => new V4l(1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYXI => new V4l(1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYXN => new V4l(1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYXX => new V4l(1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYXY => new V4l(1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYXZ => new V4l(1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYXW => new V4l(1, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYYO => new V4l(1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYYI => new V4l(1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYYN => new V4l(1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYYX => new V4l(1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYYY => new V4l(1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYYZ => new V4l(1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYYW => new V4l(1, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYZO => new V4l(1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYZI => new V4l(1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYZN => new V4l(1, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYZX => new V4l(1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYZY => new V4l(1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYZZ => new V4l(1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYZW => new V4l(1, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYWO => new V4l(1, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYWI => new V4l(1, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PYWN => new V4l(1, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYWX => new V4l(1, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYWY => new V4l(1, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYWZ => new V4l(1, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IYWW => new V4l(1, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZOO => new V4l(1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZOI => new V4l(1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZON => new V4l(1, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZOX => new V4l(1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZOY => new V4l(1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZOZ => new V4l(1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZOW => new V4l(1, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZIO => new V4l(1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZII => new V4l(1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZPN => new V4l(1, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZIX => new V4l(1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZIY => new V4l(1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZIZ => new V4l(1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZIW => new V4l(1, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZNO => new V4l(1, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZNP => new V4l(1, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZNN => new V4l(1, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZNX => new V4l(1, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZNY => new V4l(1, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZNZ => new V4l(1, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZNW => new V4l(1, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZXO => new V4l(1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZXI => new V4l(1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZXN => new V4l(1, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZXX => new V4l(1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZXY => new V4l(1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZXZ => new V4l(1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZXW => new V4l(1, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZYO => new V4l(1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZYI => new V4l(1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZYN => new V4l(1, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZYX => new V4l(1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZYY => new V4l(1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZYZ => new V4l(1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZYW => new V4l(1, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZZO => new V4l(1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZZI => new V4l(1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZZN => new V4l(1, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZZX => new V4l(1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZZY => new V4l(1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZZZ => new V4l(1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZZW => new V4l(1, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZWO => new V4l(1, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZWI => new V4l(1, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PZWN => new V4l(1, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZWX => new V4l(1, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZWY => new V4l(1, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZWZ => new V4l(1, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IZWW => new V4l(1, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWOO => new V4l(1, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWOI => new V4l(1, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PWON => new V4l(1, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWOX => new V4l(1, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWOY => new V4l(1, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWOZ => new V4l(1, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWOW => new V4l(1, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWIO => new V4l(1, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWII => new V4l(1, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PWPN => new V4l(1, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWIX => new V4l(1, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWIY => new V4l(1, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWIZ => new V4l(1, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWIW => new V4l(1, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PWNO => new V4l(1, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PWNP => new V4l(1, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PWNN => new V4l(1, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PWNX => new V4l(1, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PWNY => new V4l(1, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PWNZ => new V4l(1, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PWNW => new V4l(1, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWXO => new V4l(1, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWXI => new V4l(1, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PWXN => new V4l(1, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWXX => new V4l(1, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWXY => new V4l(1, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWXZ => new V4l(1, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWXW => new V4l(1, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWYO => new V4l(1, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWYI => new V4l(1, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PWYN => new V4l(1, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWYX => new V4l(1, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWYY => new V4l(1, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWYZ => new V4l(1, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWYW => new V4l(1, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWZO => new V4l(1, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWZI => new V4l(1, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PWZN => new V4l(1, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWZX => new V4l(1, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWZY => new V4l(1, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWZZ => new V4l(1, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWZW => new V4l(1, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWWO => new V4l(1, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWWI => new V4l(1, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l PWWN => new V4l(1, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWWX => new V4l(1, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWWY => new V4l(1, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWWZ => new V4l(1, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l IWWW => new V4l(1, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NOOO => new V4l(-1, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NOOP => new V4l(-1, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NOON => new V4l(-1, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOOX => new V4l(-1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOOY => new V4l(-1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOOZ => new V4l(-1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOOW => new V4l(-1, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NOPO => new V4l(-1, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NOPP => new V4l(-1, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NOPN => new V4l(-1, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOPX => new V4l(-1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOPY => new V4l(-1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOPZ => new V4l(-1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOPW => new V4l(-1, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NONO => new V4l(-1, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NONP => new V4l(-1, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NONN => new V4l(-1, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NONX => new V4l(-1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NONY => new V4l(-1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NONZ => new V4l(-1, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NONW => new V4l(-1, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXO => new V4l(-1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXP => new V4l(-1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXN => new V4l(-1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXX => new V4l(-1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXY => new V4l(-1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXZ => new V4l(-1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOXW => new V4l(-1, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYO => new V4l(-1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYP => new V4l(-1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYN => new V4l(-1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYX => new V4l(-1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYY => new V4l(-1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYZ => new V4l(-1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOYW => new V4l(-1, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOZO => new V4l(-1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOZP => new V4l(-1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOZN => new V4l(-1, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOZX => new V4l(-1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOZY => new V4l(-1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOZZ => new V4l(-1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOZW => new V4l(-1, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOWO => new V4l(-1, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOWP => new V4l(-1, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOWN => new V4l(-1, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOWX => new V4l(-1, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOWY => new V4l(-1, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOWZ => new V4l(-1, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NOWW => new V4l(-1, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NPOO => new V4l(-1, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NPOP => new V4l(-1, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NPON => new V4l(-1, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPOX => new V4l(-1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPOY => new V4l(-1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPOZ => new V4l(-1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPOW => new V4l(-1, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NPPO => new V4l(-1, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NPPP => new V4l(-1, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NPPN => new V4l(-1, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPPX => new V4l(-1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPPY => new V4l(-1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPPZ => new V4l(-1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPPW => new V4l(-1, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NPNO => new V4l(-1, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NPNP => new V4l(-1, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NPNN => new V4l(-1, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPNX => new V4l(-1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPNY => new V4l(-1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPNZ => new V4l(-1, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPNW => new V4l(-1, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXO => new V4l(-1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXP => new V4l(-1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXN => new V4l(-1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXX => new V4l(-1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXY => new V4l(-1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXZ => new V4l(-1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPXW => new V4l(-1, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYO => new V4l(-1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYP => new V4l(-1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYN => new V4l(-1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYX => new V4l(-1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYY => new V4l(-1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYZ => new V4l(-1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPYW => new V4l(-1, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPZO => new V4l(-1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPZP => new V4l(-1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPZN => new V4l(-1, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPZX => new V4l(-1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPZY => new V4l(-1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPZZ => new V4l(-1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPZW => new V4l(-1, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPWO => new V4l(-1, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPWP => new V4l(-1, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPWN => new V4l(-1, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPWX => new V4l(-1, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPWY => new V4l(-1, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPWZ => new V4l(-1, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NPWW => new V4l(-1, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NNOO => new V4l(-1, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NNOP => new V4l(-1, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NNON => new V4l(-1, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNOX => new V4l(-1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNOY => new V4l(-1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNOZ => new V4l(-1, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNOW => new V4l(-1, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NNPO => new V4l(-1, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NNPP => new V4l(-1, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NNPN => new V4l(-1, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNPX => new V4l(-1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNPY => new V4l(-1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNPZ => new V4l(-1, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNPW => new V4l(-1, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NNNO => new V4l(-1, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NNNP => new V4l(-1, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4l NNNN => new V4l(-1, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNNX => new V4l(-1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNNY => new V4l(-1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNNZ => new V4l(-1, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNNW => new V4l(-1, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXO => new V4l(-1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXP => new V4l(-1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXN => new V4l(-1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXX => new V4l(-1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXY => new V4l(-1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXZ => new V4l(-1, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNXW => new V4l(-1, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYO => new V4l(-1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYP => new V4l(-1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYN => new V4l(-1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYX => new V4l(-1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYY => new V4l(-1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYZ => new V4l(-1, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNYW => new V4l(-1, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNZO => new V4l(-1, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNZP => new V4l(-1, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNZN => new V4l(-1, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNZX => new V4l(-1, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNZY => new V4l(-1, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNZZ => new V4l(-1, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNZW => new V4l(-1, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNWO => new V4l(-1, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNWP => new V4l(-1, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNWN => new V4l(-1, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNWX => new V4l(-1, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNWY => new V4l(-1, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNWZ => new V4l(-1, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NNWW => new V4l(-1, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXOO => new V4l(-1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXOP => new V4l(-1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXON => new V4l(-1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXOX => new V4l(-1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXOY => new V4l(-1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXOZ => new V4l(-1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXOW => new V4l(-1, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPO => new V4l(-1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPP => new V4l(-1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPN => new V4l(-1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPX => new V4l(-1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPY => new V4l(-1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPZ => new V4l(-1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXPW => new V4l(-1, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNO => new V4l(-1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNP => new V4l(-1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNN => new V4l(-1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNX => new V4l(-1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNY => new V4l(-1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNZ => new V4l(-1, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXNW => new V4l(-1, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXO => new V4l(-1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXP => new V4l(-1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXN => new V4l(-1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXX => new V4l(-1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXY => new V4l(-1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXZ => new V4l(-1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXXW => new V4l(-1, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYO => new V4l(-1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYP => new V4l(-1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYN => new V4l(-1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYX => new V4l(-1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYY => new V4l(-1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYZ => new V4l(-1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXYW => new V4l(-1, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXZO => new V4l(-1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXZP => new V4l(-1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXZN => new V4l(-1, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXZX => new V4l(-1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXZY => new V4l(-1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXZZ => new V4l(-1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXZW => new V4l(-1, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXWO => new V4l(-1, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXWP => new V4l(-1, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXWN => new V4l(-1, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXWX => new V4l(-1, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXWY => new V4l(-1, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXWZ => new V4l(-1, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NXWW => new V4l(-1, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYOO => new V4l(-1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYOP => new V4l(-1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYON => new V4l(-1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYOX => new V4l(-1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYOY => new V4l(-1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYOZ => new V4l(-1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYOW => new V4l(-1, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPO => new V4l(-1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPP => new V4l(-1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPN => new V4l(-1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPX => new V4l(-1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPY => new V4l(-1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPZ => new V4l(-1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYPW => new V4l(-1, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNO => new V4l(-1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNP => new V4l(-1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNN => new V4l(-1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNX => new V4l(-1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNY => new V4l(-1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNZ => new V4l(-1, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYNW => new V4l(-1, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXO => new V4l(-1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXP => new V4l(-1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXN => new V4l(-1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXX => new V4l(-1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXY => new V4l(-1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXZ => new V4l(-1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYXW => new V4l(-1, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYO => new V4l(-1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYP => new V4l(-1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYN => new V4l(-1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYX => new V4l(-1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYY => new V4l(-1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYZ => new V4l(-1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYYW => new V4l(-1, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYZO => new V4l(-1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYZP => new V4l(-1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYZN => new V4l(-1, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYZX => new V4l(-1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYZY => new V4l(-1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYZZ => new V4l(-1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYZW => new V4l(-1, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYWO => new V4l(-1, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYWP => new V4l(-1, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYWN => new V4l(-1, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYWX => new V4l(-1, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYWY => new V4l(-1, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYWZ => new V4l(-1, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NYWW => new V4l(-1, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZOO => new V4l(-1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZOP => new V4l(-1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZON => new V4l(-1, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZOX => new V4l(-1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZOY => new V4l(-1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZOZ => new V4l(-1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZOW => new V4l(-1, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZPO => new V4l(-1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZPP => new V4l(-1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZPN => new V4l(-1, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZPX => new V4l(-1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZPY => new V4l(-1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZPZ => new V4l(-1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZPW => new V4l(-1, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZNO => new V4l(-1, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZNP => new V4l(-1, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZNN => new V4l(-1, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZNX => new V4l(-1, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZNY => new V4l(-1, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZNZ => new V4l(-1, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZNW => new V4l(-1, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZXO => new V4l(-1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZXP => new V4l(-1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZXN => new V4l(-1, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZXX => new V4l(-1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZXY => new V4l(-1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZXZ => new V4l(-1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZXW => new V4l(-1, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZYO => new V4l(-1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZYP => new V4l(-1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZYN => new V4l(-1, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZYX => new V4l(-1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZYY => new V4l(-1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZYZ => new V4l(-1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZYW => new V4l(-1, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZZO => new V4l(-1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZZP => new V4l(-1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZZN => new V4l(-1, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZZX => new V4l(-1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZZY => new V4l(-1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZZZ => new V4l(-1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZZW => new V4l(-1, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZWO => new V4l(-1, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZWP => new V4l(-1, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZWN => new V4l(-1, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZWX => new V4l(-1, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZWY => new V4l(-1, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZWZ => new V4l(-1, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NZWW => new V4l(-1, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWOO => new V4l(-1, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWOP => new V4l(-1, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWON => new V4l(-1, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWOX => new V4l(-1, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWOY => new V4l(-1, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWOZ => new V4l(-1, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWOW => new V4l(-1, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWPO => new V4l(-1, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWPP => new V4l(-1, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWPN => new V4l(-1, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWPX => new V4l(-1, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWPY => new V4l(-1, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWPZ => new V4l(-1, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWPW => new V4l(-1, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWNO => new V4l(-1, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWNP => new V4l(-1, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWNN => new V4l(-1, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWNX => new V4l(-1, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWNY => new V4l(-1, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWNZ => new V4l(-1, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWNW => new V4l(-1, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWXO => new V4l(-1, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWXP => new V4l(-1, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWXN => new V4l(-1, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWXX => new V4l(-1, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWXY => new V4l(-1, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWXZ => new V4l(-1, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWXW => new V4l(-1, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWYO => new V4l(-1, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWYP => new V4l(-1, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWYN => new V4l(-1, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWYX => new V4l(-1, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWYY => new V4l(-1, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWYZ => new V4l(-1, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWYW => new V4l(-1, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWZO => new V4l(-1, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWZP => new V4l(-1, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWZN => new V4l(-1, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWZX => new V4l(-1, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWZY => new V4l(-1, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWZZ => new V4l(-1, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWZW => new V4l(-1, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWWO => new V4l(-1, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWWP => new V4l(-1, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWWN => new V4l(-1, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWWX => new V4l(-1, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWWY => new V4l(-1, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWWZ => new V4l(-1, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l NWWW => new V4l(-1, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOOO => new V4l(X, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOOI => new V4l(X, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOON => new V4l(X, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOOX => new V4l(X, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOOY => new V4l(X, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOOZ => new V4l(X, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOOW => new V4l(X, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOIO => new V4l(X, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOII => new V4l(X, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOPN => new V4l(X, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOIX => new V4l(X, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOIY => new V4l(X, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOIZ => new V4l(X, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOIW => new V4l(X, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONO => new V4l(X, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONP => new V4l(X, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONN => new V4l(X, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONX => new V4l(X, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONY => new V4l(X, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONZ => new V4l(X, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XONW => new V4l(X, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXO => new V4l(X, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXI => new V4l(X, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXN => new V4l(X, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXX => new V4l(X, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXY => new V4l(X, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXZ => new V4l(X, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOXW => new V4l(X, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYO => new V4l(X, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYI => new V4l(X, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYN => new V4l(X, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYX => new V4l(X, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYY => new V4l(X, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYZ => new V4l(X, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOYW => new V4l(X, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOZO => new V4l(X, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOZI => new V4l(X, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOZN => new V4l(X, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOZX => new V4l(X, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOZY => new V4l(X, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOZZ => new V4l(X, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOZW => new V4l(X, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOWO => new V4l(X, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOWI => new V4l(X, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOWN => new V4l(X, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOWX => new V4l(X, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOWY => new V4l(X, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOWZ => new V4l(X, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XOWW => new V4l(X, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIOO => new V4l(X, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIOI => new V4l(X, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPON => new V4l(X, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIOX => new V4l(X, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIOY => new V4l(X, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIOZ => new V4l(X, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIOW => new V4l(X, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIIO => new V4l(X, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIII => new V4l(X, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPPN => new V4l(X, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIIX => new V4l(X, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIIY => new V4l(X, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIIZ => new V4l(X, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIIW => new V4l(X, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNO => new V4l(X, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNP => new V4l(X, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNN => new V4l(X, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNX => new V4l(X, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNY => new V4l(X, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNZ => new V4l(X, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPNW => new V4l(X, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIXO => new V4l(X, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIXI => new V4l(X, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPXN => new V4l(X, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIXX => new V4l(X, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIXY => new V4l(X, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIXZ => new V4l(X, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIXW => new V4l(X, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIYO => new V4l(X, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIYI => new V4l(X, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPYN => new V4l(X, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIYX => new V4l(X, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIYY => new V4l(X, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIYZ => new V4l(X, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIYW => new V4l(X, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIZO => new V4l(X, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIZI => new V4l(X, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPZN => new V4l(X, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIZX => new V4l(X, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIZY => new V4l(X, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIZZ => new V4l(X, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIZW => new V4l(X, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIWO => new V4l(X, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIWI => new V4l(X, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XPWN => new V4l(X, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIWX => new V4l(X, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIWY => new V4l(X, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIWZ => new V4l(X, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XIWW => new V4l(X, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNOO => new V4l(X, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNOP => new V4l(X, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNON => new V4l(X, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNOX => new V4l(X, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNOY => new V4l(X, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNOZ => new V4l(X, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNOW => new V4l(X, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPO => new V4l(X, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPP => new V4l(X, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPN => new V4l(X, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPX => new V4l(X, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPY => new V4l(X, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPZ => new V4l(X, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNPW => new V4l(X, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNO => new V4l(X, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNP => new V4l(X, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNN => new V4l(X, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNX => new V4l(X, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNY => new V4l(X, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNZ => new V4l(X, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNNW => new V4l(X, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXO => new V4l(X, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXP => new V4l(X, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXN => new V4l(X, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXX => new V4l(X, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXY => new V4l(X, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXZ => new V4l(X, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNXW => new V4l(X, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYO => new V4l(X, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYP => new V4l(X, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYN => new V4l(X, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYX => new V4l(X, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYY => new V4l(X, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYZ => new V4l(X, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNYW => new V4l(X, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNZO => new V4l(X, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNZP => new V4l(X, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNZN => new V4l(X, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNZX => new V4l(X, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNZY => new V4l(X, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNZZ => new V4l(X, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNZW => new V4l(X, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNWO => new V4l(X, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNWP => new V4l(X, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNWN => new V4l(X, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNWX => new V4l(X, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNWY => new V4l(X, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNWZ => new V4l(X, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XNWW => new V4l(X, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXOO => new V4l(X, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXOI => new V4l(X, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXON => new V4l(X, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXOX => new V4l(X, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXOY => new V4l(X, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXOZ => new V4l(X, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXOW => new V4l(X, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXIO => new V4l(X, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXII => new V4l(X, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXPN => new V4l(X, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXIX => new V4l(X, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXIY => new V4l(X, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXIZ => new V4l(X, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXIW => new V4l(X, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNO => new V4l(X, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNP => new V4l(X, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNN => new V4l(X, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNX => new V4l(X, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNY => new V4l(X, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNZ => new V4l(X, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXNW => new V4l(X, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXO => new V4l(X, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXI => new V4l(X, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXN => new V4l(X, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXX => new V4l(X, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXY => new V4l(X, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXZ => new V4l(X, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXXW => new V4l(X, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYO => new V4l(X, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYI => new V4l(X, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYN => new V4l(X, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYX => new V4l(X, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYY => new V4l(X, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYZ => new V4l(X, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXYW => new V4l(X, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXZO => new V4l(X, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXZI => new V4l(X, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXZN => new V4l(X, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXZX => new V4l(X, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXZY => new V4l(X, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXZZ => new V4l(X, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXZW => new V4l(X, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXWO => new V4l(X, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXWI => new V4l(X, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXWN => new V4l(X, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXWX => new V4l(X, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXWY => new V4l(X, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXWZ => new V4l(X, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XXWW => new V4l(X, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYOO => new V4l(X, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYOI => new V4l(X, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYON => new V4l(X, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYOX => new V4l(X, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYOY => new V4l(X, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYOZ => new V4l(X, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYOW => new V4l(X, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYIO => new V4l(X, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYII => new V4l(X, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYPN => new V4l(X, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYIX => new V4l(X, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYIY => new V4l(X, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYIZ => new V4l(X, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYIW => new V4l(X, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNO => new V4l(X, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNP => new V4l(X, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNN => new V4l(X, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNX => new V4l(X, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNY => new V4l(X, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNZ => new V4l(X, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYNW => new V4l(X, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXO => new V4l(X, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXI => new V4l(X, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXN => new V4l(X, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXX => new V4l(X, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXY => new V4l(X, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXZ => new V4l(X, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYXW => new V4l(X, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYO => new V4l(X, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYI => new V4l(X, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYN => new V4l(X, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYX => new V4l(X, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYY => new V4l(X, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYZ => new V4l(X, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYYW => new V4l(X, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYZO => new V4l(X, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYZI => new V4l(X, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYZN => new V4l(X, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYZX => new V4l(X, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYZY => new V4l(X, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYZZ => new V4l(X, Y, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l XYZW { readonly get => new V4l(X, Y, Z, W); set { X = value.X; Y = value.Y; Z = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYWO => new V4l(X, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYWI => new V4l(X, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYWN => new V4l(X, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYWX => new V4l(X, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYWY => new V4l(X, Y, W, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l XYWZ { readonly get => new V4l(X, Y, W, Z); set { X = value.X; Y = value.Y; W = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XYWW => new V4l(X, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZOO => new V4l(X, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZOI => new V4l(X, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZON => new V4l(X, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZOX => new V4l(X, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZOY => new V4l(X, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZOZ => new V4l(X, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZOW => new V4l(X, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZIO => new V4l(X, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZII => new V4l(X, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZPN => new V4l(X, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZIX => new V4l(X, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZIY => new V4l(X, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZIZ => new V4l(X, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZIW => new V4l(X, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZNO => new V4l(X, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZNP => new V4l(X, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZNN => new V4l(X, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZNX => new V4l(X, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZNY => new V4l(X, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZNZ => new V4l(X, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZNW => new V4l(X, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZXO => new V4l(X, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZXI => new V4l(X, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZXN => new V4l(X, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZXX => new V4l(X, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZXY => new V4l(X, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZXZ => new V4l(X, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZXW => new V4l(X, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZYO => new V4l(X, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZYI => new V4l(X, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZYN => new V4l(X, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZYX => new V4l(X, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZYY => new V4l(X, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZYZ => new V4l(X, Z, Y, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l XZYW { readonly get => new V4l(X, Z, Y, W); set { X = value.X; Z = value.Y; Y = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZZO => new V4l(X, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZZI => new V4l(X, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZZN => new V4l(X, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZZX => new V4l(X, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZZY => new V4l(X, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZZZ => new V4l(X, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZZW => new V4l(X, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZWO => new V4l(X, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZWI => new V4l(X, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZWN => new V4l(X, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZWX => new V4l(X, Z, W, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l XZWY { readonly get => new V4l(X, Z, W, Y); set { X = value.X; Z = value.Y; W = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZWZ => new V4l(X, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XZWW => new V4l(X, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWOO => new V4l(X, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWOI => new V4l(X, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWON => new V4l(X, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWOX => new V4l(X, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWOY => new V4l(X, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWOZ => new V4l(X, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWOW => new V4l(X, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWIO => new V4l(X, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWII => new V4l(X, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWPN => new V4l(X, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWIX => new V4l(X, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWIY => new V4l(X, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWIZ => new V4l(X, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWIW => new V4l(X, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWNO => new V4l(X, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWNP => new V4l(X, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWNN => new V4l(X, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWNX => new V4l(X, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWNY => new V4l(X, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWNZ => new V4l(X, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWNW => new V4l(X, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWXO => new V4l(X, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWXI => new V4l(X, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWXN => new V4l(X, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWXX => new V4l(X, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWXY => new V4l(X, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWXZ => new V4l(X, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWXW => new V4l(X, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWYO => new V4l(X, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWYI => new V4l(X, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWYN => new V4l(X, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWYX => new V4l(X, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWYY => new V4l(X, W, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l XWYZ { readonly get => new V4l(X, W, Y, Z); set { X = value.X; W = value.Y; Y = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWYW => new V4l(X, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWZO => new V4l(X, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWZI => new V4l(X, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWZN => new V4l(X, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWZX => new V4l(X, W, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l XWZY { readonly get => new V4l(X, W, Z, Y); set { X = value.X; W = value.Y; Z = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWZZ => new V4l(X, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWZW => new V4l(X, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWWO => new V4l(X, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWWI => new V4l(X, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWWN => new V4l(X, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWWX => new V4l(X, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWWY => new V4l(X, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWWZ => new V4l(X, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l XWWW => new V4l(X, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOOO => new V4l(Y, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOOI => new V4l(Y, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOON => new V4l(Y, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOOX => new V4l(Y, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOOY => new V4l(Y, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOOZ => new V4l(Y, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOOW => new V4l(Y, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOIO => new V4l(Y, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOII => new V4l(Y, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOPN => new V4l(Y, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOIX => new V4l(Y, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOIY => new V4l(Y, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOIZ => new V4l(Y, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOIW => new V4l(Y, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONO => new V4l(Y, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONP => new V4l(Y, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONN => new V4l(Y, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONX => new V4l(Y, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONY => new V4l(Y, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONZ => new V4l(Y, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YONW => new V4l(Y, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXO => new V4l(Y, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXI => new V4l(Y, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXN => new V4l(Y, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXX => new V4l(Y, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXY => new V4l(Y, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXZ => new V4l(Y, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOXW => new V4l(Y, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYO => new V4l(Y, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYI => new V4l(Y, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYN => new V4l(Y, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYX => new V4l(Y, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYY => new V4l(Y, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYZ => new V4l(Y, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOYW => new V4l(Y, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOZO => new V4l(Y, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOZI => new V4l(Y, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOZN => new V4l(Y, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOZX => new V4l(Y, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOZY => new V4l(Y, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOZZ => new V4l(Y, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOZW => new V4l(Y, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOWO => new V4l(Y, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOWI => new V4l(Y, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOWN => new V4l(Y, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOWX => new V4l(Y, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOWY => new V4l(Y, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOWZ => new V4l(Y, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YOWW => new V4l(Y, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIOO => new V4l(Y, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIOI => new V4l(Y, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPON => new V4l(Y, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIOX => new V4l(Y, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIOY => new V4l(Y, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIOZ => new V4l(Y, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIOW => new V4l(Y, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIIO => new V4l(Y, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIII => new V4l(Y, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPPN => new V4l(Y, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIIX => new V4l(Y, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIIY => new V4l(Y, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIIZ => new V4l(Y, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIIW => new V4l(Y, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNO => new V4l(Y, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNP => new V4l(Y, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNN => new V4l(Y, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNX => new V4l(Y, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNY => new V4l(Y, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNZ => new V4l(Y, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPNW => new V4l(Y, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIXO => new V4l(Y, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIXI => new V4l(Y, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPXN => new V4l(Y, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIXX => new V4l(Y, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIXY => new V4l(Y, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIXZ => new V4l(Y, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIXW => new V4l(Y, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIYO => new V4l(Y, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIYI => new V4l(Y, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPYN => new V4l(Y, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIYX => new V4l(Y, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIYY => new V4l(Y, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIYZ => new V4l(Y, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIYW => new V4l(Y, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIZO => new V4l(Y, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIZI => new V4l(Y, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPZN => new V4l(Y, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIZX => new V4l(Y, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIZY => new V4l(Y, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIZZ => new V4l(Y, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIZW => new V4l(Y, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIWO => new V4l(Y, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIWI => new V4l(Y, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YPWN => new V4l(Y, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIWX => new V4l(Y, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIWY => new V4l(Y, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIWZ => new V4l(Y, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YIWW => new V4l(Y, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNOO => new V4l(Y, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNOP => new V4l(Y, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNON => new V4l(Y, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNOX => new V4l(Y, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNOY => new V4l(Y, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNOZ => new V4l(Y, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNOW => new V4l(Y, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPO => new V4l(Y, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPP => new V4l(Y, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPN => new V4l(Y, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPX => new V4l(Y, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPY => new V4l(Y, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPZ => new V4l(Y, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNPW => new V4l(Y, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNO => new V4l(Y, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNP => new V4l(Y, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNN => new V4l(Y, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNX => new V4l(Y, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNY => new V4l(Y, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNZ => new V4l(Y, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNNW => new V4l(Y, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXO => new V4l(Y, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXP => new V4l(Y, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXN => new V4l(Y, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXX => new V4l(Y, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXY => new V4l(Y, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXZ => new V4l(Y, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNXW => new V4l(Y, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYO => new V4l(Y, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYP => new V4l(Y, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYN => new V4l(Y, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYX => new V4l(Y, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYY => new V4l(Y, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYZ => new V4l(Y, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNYW => new V4l(Y, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNZO => new V4l(Y, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNZP => new V4l(Y, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNZN => new V4l(Y, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNZX => new V4l(Y, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNZY => new V4l(Y, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNZZ => new V4l(Y, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNZW => new V4l(Y, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNWO => new V4l(Y, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNWP => new V4l(Y, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNWN => new V4l(Y, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNWX => new V4l(Y, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNWY => new V4l(Y, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNWZ => new V4l(Y, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YNWW => new V4l(Y, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXOO => new V4l(Y, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXOI => new V4l(Y, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXON => new V4l(Y, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXOX => new V4l(Y, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXOY => new V4l(Y, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXOZ => new V4l(Y, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXOW => new V4l(Y, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXIO => new V4l(Y, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXII => new V4l(Y, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXPN => new V4l(Y, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXIX => new V4l(Y, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXIY => new V4l(Y, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXIZ => new V4l(Y, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXIW => new V4l(Y, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNO => new V4l(Y, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNP => new V4l(Y, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNN => new V4l(Y, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNX => new V4l(Y, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNY => new V4l(Y, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNZ => new V4l(Y, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXNW => new V4l(Y, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXO => new V4l(Y, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXI => new V4l(Y, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXN => new V4l(Y, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXX => new V4l(Y, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXY => new V4l(Y, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXZ => new V4l(Y, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXXW => new V4l(Y, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYO => new V4l(Y, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYI => new V4l(Y, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYN => new V4l(Y, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYX => new V4l(Y, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYY => new V4l(Y, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYZ => new V4l(Y, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXYW => new V4l(Y, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXZO => new V4l(Y, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXZI => new V4l(Y, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXZN => new V4l(Y, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXZX => new V4l(Y, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXZY => new V4l(Y, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXZZ => new V4l(Y, X, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l YXZW { readonly get => new V4l(Y, X, Z, W); set { Y = value.X; X = value.Y; Z = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXWO => new V4l(Y, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXWI => new V4l(Y, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXWN => new V4l(Y, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXWX => new V4l(Y, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXWY => new V4l(Y, X, W, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l YXWZ { readonly get => new V4l(Y, X, W, Z); set { Y = value.X; X = value.Y; W = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YXWW => new V4l(Y, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYOO => new V4l(Y, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYOI => new V4l(Y, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYON => new V4l(Y, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYOX => new V4l(Y, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYOY => new V4l(Y, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYOZ => new V4l(Y, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYOW => new V4l(Y, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYIO => new V4l(Y, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYII => new V4l(Y, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYPN => new V4l(Y, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYIX => new V4l(Y, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYIY => new V4l(Y, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYIZ => new V4l(Y, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYIW => new V4l(Y, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNO => new V4l(Y, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNP => new V4l(Y, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNN => new V4l(Y, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNX => new V4l(Y, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNY => new V4l(Y, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNZ => new V4l(Y, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYNW => new V4l(Y, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXO => new V4l(Y, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXI => new V4l(Y, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXN => new V4l(Y, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXX => new V4l(Y, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXY => new V4l(Y, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXZ => new V4l(Y, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYXW => new V4l(Y, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYO => new V4l(Y, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYI => new V4l(Y, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYN => new V4l(Y, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYX => new V4l(Y, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYY => new V4l(Y, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYZ => new V4l(Y, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYYW => new V4l(Y, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYZO => new V4l(Y, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYZI => new V4l(Y, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYZN => new V4l(Y, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYZX => new V4l(Y, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYZY => new V4l(Y, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYZZ => new V4l(Y, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYZW => new V4l(Y, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYWO => new V4l(Y, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYWI => new V4l(Y, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYWN => new V4l(Y, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYWX => new V4l(Y, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYWY => new V4l(Y, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYWZ => new V4l(Y, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YYWW => new V4l(Y, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZOO => new V4l(Y, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZOI => new V4l(Y, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZON => new V4l(Y, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZOX => new V4l(Y, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZOY => new V4l(Y, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZOZ => new V4l(Y, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZOW => new V4l(Y, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZIO => new V4l(Y, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZII => new V4l(Y, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZPN => new V4l(Y, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZIX => new V4l(Y, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZIY => new V4l(Y, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZIZ => new V4l(Y, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZIW => new V4l(Y, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZNO => new V4l(Y, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZNP => new V4l(Y, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZNN => new V4l(Y, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZNX => new V4l(Y, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZNY => new V4l(Y, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZNZ => new V4l(Y, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZNW => new V4l(Y, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZXO => new V4l(Y, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZXI => new V4l(Y, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZXN => new V4l(Y, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZXX => new V4l(Y, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZXY => new V4l(Y, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZXZ => new V4l(Y, Z, X, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l YZXW { readonly get => new V4l(Y, Z, X, W); set { Y = value.X; Z = value.Y; X = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZYO => new V4l(Y, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZYI => new V4l(Y, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZYN => new V4l(Y, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZYX => new V4l(Y, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZYY => new V4l(Y, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZYZ => new V4l(Y, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZYW => new V4l(Y, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZZO => new V4l(Y, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZZI => new V4l(Y, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZZN => new V4l(Y, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZZX => new V4l(Y, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZZY => new V4l(Y, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZZZ => new V4l(Y, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZZW => new V4l(Y, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZWO => new V4l(Y, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZWI => new V4l(Y, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZWN => new V4l(Y, Z, W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l YZWX { readonly get => new V4l(Y, Z, W, X); set { Y = value.X; Z = value.Y; W = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZWY => new V4l(Y, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZWZ => new V4l(Y, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YZWW => new V4l(Y, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWOO => new V4l(Y, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWOI => new V4l(Y, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWON => new V4l(Y, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWOX => new V4l(Y, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWOY => new V4l(Y, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWOZ => new V4l(Y, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWOW => new V4l(Y, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWIO => new V4l(Y, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWII => new V4l(Y, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWPN => new V4l(Y, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWIX => new V4l(Y, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWIY => new V4l(Y, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWIZ => new V4l(Y, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWIW => new V4l(Y, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWNO => new V4l(Y, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWNP => new V4l(Y, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWNN => new V4l(Y, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWNX => new V4l(Y, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWNY => new V4l(Y, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWNZ => new V4l(Y, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWNW => new V4l(Y, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWXO => new V4l(Y, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWXI => new V4l(Y, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWXN => new V4l(Y, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWXX => new V4l(Y, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWXY => new V4l(Y, W, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l YWXZ { readonly get => new V4l(Y, W, X, Z); set { Y = value.X; W = value.Y; X = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWXW => new V4l(Y, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWYO => new V4l(Y, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWYI => new V4l(Y, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWYN => new V4l(Y, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWYX => new V4l(Y, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWYY => new V4l(Y, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWYZ => new V4l(Y, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWYW => new V4l(Y, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWZO => new V4l(Y, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWZI => new V4l(Y, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWZN => new V4l(Y, W, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l YWZX { readonly get => new V4l(Y, W, Z, X); set { Y = value.X; W = value.Y; Z = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWZY => new V4l(Y, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWZZ => new V4l(Y, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWZW => new V4l(Y, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWWO => new V4l(Y, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWWI => new V4l(Y, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWWN => new V4l(Y, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWWX => new V4l(Y, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWWY => new V4l(Y, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWWZ => new V4l(Y, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l YWWW => new V4l(Y, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOOO => new V4l(Z, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOOI => new V4l(Z, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOON => new V4l(Z, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOOX => new V4l(Z, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOOY => new V4l(Z, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOOZ => new V4l(Z, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOOW => new V4l(Z, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOIO => new V4l(Z, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOII => new V4l(Z, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOPN => new V4l(Z, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOIX => new V4l(Z, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOIY => new V4l(Z, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOIZ => new V4l(Z, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOIW => new V4l(Z, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZONO => new V4l(Z, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZONP => new V4l(Z, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZONN => new V4l(Z, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZONX => new V4l(Z, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZONY => new V4l(Z, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZONZ => new V4l(Z, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZONW => new V4l(Z, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOXO => new V4l(Z, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOXI => new V4l(Z, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOXN => new V4l(Z, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOXX => new V4l(Z, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOXY => new V4l(Z, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOXZ => new V4l(Z, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOXW => new V4l(Z, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOYO => new V4l(Z, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOYI => new V4l(Z, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOYN => new V4l(Z, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOYX => new V4l(Z, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOYY => new V4l(Z, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOYZ => new V4l(Z, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOYW => new V4l(Z, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOZO => new V4l(Z, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOZI => new V4l(Z, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOZN => new V4l(Z, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOZX => new V4l(Z, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOZY => new V4l(Z, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOZZ => new V4l(Z, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOZW => new V4l(Z, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOWO => new V4l(Z, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOWI => new V4l(Z, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOWN => new V4l(Z, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOWX => new V4l(Z, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOWY => new V4l(Z, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOWZ => new V4l(Z, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZOWW => new V4l(Z, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIOO => new V4l(Z, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIOI => new V4l(Z, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPON => new V4l(Z, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIOX => new V4l(Z, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIOY => new V4l(Z, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIOZ => new V4l(Z, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIOW => new V4l(Z, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIIO => new V4l(Z, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIII => new V4l(Z, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPPN => new V4l(Z, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIIX => new V4l(Z, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIIY => new V4l(Z, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIIZ => new V4l(Z, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIIW => new V4l(Z, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPNO => new V4l(Z, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPNP => new V4l(Z, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPNN => new V4l(Z, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPNX => new V4l(Z, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPNY => new V4l(Z, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPNZ => new V4l(Z, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPNW => new V4l(Z, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIXO => new V4l(Z, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIXI => new V4l(Z, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPXN => new V4l(Z, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIXX => new V4l(Z, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIXY => new V4l(Z, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIXZ => new V4l(Z, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIXW => new V4l(Z, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIYO => new V4l(Z, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIYI => new V4l(Z, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPYN => new V4l(Z, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIYX => new V4l(Z, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIYY => new V4l(Z, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIYZ => new V4l(Z, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIYW => new V4l(Z, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIZO => new V4l(Z, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIZI => new V4l(Z, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPZN => new V4l(Z, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIZX => new V4l(Z, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIZY => new V4l(Z, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIZZ => new V4l(Z, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIZW => new V4l(Z, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIWO => new V4l(Z, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIWI => new V4l(Z, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZPWN => new V4l(Z, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIWX => new V4l(Z, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIWY => new V4l(Z, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIWZ => new V4l(Z, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZIWW => new V4l(Z, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNOO => new V4l(Z, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNOP => new V4l(Z, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNON => new V4l(Z, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNOX => new V4l(Z, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNOY => new V4l(Z, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNOZ => new V4l(Z, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNOW => new V4l(Z, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNPO => new V4l(Z, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNPP => new V4l(Z, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNPN => new V4l(Z, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNPX => new V4l(Z, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNPY => new V4l(Z, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNPZ => new V4l(Z, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNPW => new V4l(Z, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNNO => new V4l(Z, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNNP => new V4l(Z, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNNN => new V4l(Z, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNNX => new V4l(Z, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNNY => new V4l(Z, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNNZ => new V4l(Z, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNNW => new V4l(Z, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNXO => new V4l(Z, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNXP => new V4l(Z, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNXN => new V4l(Z, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNXX => new V4l(Z, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNXY => new V4l(Z, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNXZ => new V4l(Z, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNXW => new V4l(Z, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNYO => new V4l(Z, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNYP => new V4l(Z, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNYN => new V4l(Z, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNYX => new V4l(Z, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNYY => new V4l(Z, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNYZ => new V4l(Z, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNYW => new V4l(Z, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNZO => new V4l(Z, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNZP => new V4l(Z, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNZN => new V4l(Z, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNZX => new V4l(Z, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNZY => new V4l(Z, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNZZ => new V4l(Z, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNZW => new V4l(Z, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNWO => new V4l(Z, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNWP => new V4l(Z, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNWN => new V4l(Z, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNWX => new V4l(Z, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNWY => new V4l(Z, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNWZ => new V4l(Z, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZNWW => new V4l(Z, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXOO => new V4l(Z, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXOI => new V4l(Z, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXON => new V4l(Z, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXOX => new V4l(Z, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXOY => new V4l(Z, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXOZ => new V4l(Z, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXOW => new V4l(Z, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXIO => new V4l(Z, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXII => new V4l(Z, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXPN => new V4l(Z, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXIX => new V4l(Z, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXIY => new V4l(Z, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXIZ => new V4l(Z, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXIW => new V4l(Z, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXNO => new V4l(Z, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXNP => new V4l(Z, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXNN => new V4l(Z, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXNX => new V4l(Z, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXNY => new V4l(Z, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXNZ => new V4l(Z, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXNW => new V4l(Z, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXXO => new V4l(Z, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXXI => new V4l(Z, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXXN => new V4l(Z, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXXX => new V4l(Z, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXXY => new V4l(Z, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXXZ => new V4l(Z, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXXW => new V4l(Z, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXYO => new V4l(Z, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXYI => new V4l(Z, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXYN => new V4l(Z, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXYX => new V4l(Z, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXYY => new V4l(Z, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXYZ => new V4l(Z, X, Y, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l ZXYW { readonly get => new V4l(Z, X, Y, W); set { Z = value.X; X = value.Y; Y = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXZO => new V4l(Z, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXZI => new V4l(Z, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXZN => new V4l(Z, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXZX => new V4l(Z, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXZY => new V4l(Z, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXZZ => new V4l(Z, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXZW => new V4l(Z, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXWO => new V4l(Z, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXWI => new V4l(Z, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXWN => new V4l(Z, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXWX => new V4l(Z, X, W, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l ZXWY { readonly get => new V4l(Z, X, W, Y); set { Z = value.X; X = value.Y; W = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXWZ => new V4l(Z, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZXWW => new V4l(Z, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYOO => new V4l(Z, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYOI => new V4l(Z, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYON => new V4l(Z, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYOX => new V4l(Z, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYOY => new V4l(Z, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYOZ => new V4l(Z, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYOW => new V4l(Z, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYIO => new V4l(Z, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYII => new V4l(Z, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYPN => new V4l(Z, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYIX => new V4l(Z, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYIY => new V4l(Z, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYIZ => new V4l(Z, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYIW => new V4l(Z, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYNO => new V4l(Z, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYNP => new V4l(Z, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYNN => new V4l(Z, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYNX => new V4l(Z, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYNY => new V4l(Z, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYNZ => new V4l(Z, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYNW => new V4l(Z, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYXO => new V4l(Z, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYXI => new V4l(Z, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYXN => new V4l(Z, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYXX => new V4l(Z, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYXY => new V4l(Z, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYXZ => new V4l(Z, Y, X, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l ZYXW { readonly get => new V4l(Z, Y, X, W); set { Z = value.X; Y = value.Y; X = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYYO => new V4l(Z, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYYI => new V4l(Z, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYYN => new V4l(Z, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYYX => new V4l(Z, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYYY => new V4l(Z, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYYZ => new V4l(Z, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYYW => new V4l(Z, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYZO => new V4l(Z, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYZI => new V4l(Z, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYZN => new V4l(Z, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYZX => new V4l(Z, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYZY => new V4l(Z, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYZZ => new V4l(Z, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYZW => new V4l(Z, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYWO => new V4l(Z, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYWI => new V4l(Z, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYWN => new V4l(Z, Y, W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l ZYWX { readonly get => new V4l(Z, Y, W, X); set { Z = value.X; Y = value.Y; W = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYWY => new V4l(Z, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYWZ => new V4l(Z, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZYWW => new V4l(Z, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZOO => new V4l(Z, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZOI => new V4l(Z, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZON => new V4l(Z, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZOX => new V4l(Z, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZOY => new V4l(Z, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZOZ => new V4l(Z, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZOW => new V4l(Z, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZIO => new V4l(Z, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZII => new V4l(Z, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZPN => new V4l(Z, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZIX => new V4l(Z, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZIY => new V4l(Z, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZIZ => new V4l(Z, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZIW => new V4l(Z, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZNO => new V4l(Z, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZNP => new V4l(Z, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZNN => new V4l(Z, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZNX => new V4l(Z, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZNY => new V4l(Z, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZNZ => new V4l(Z, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZNW => new V4l(Z, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZXO => new V4l(Z, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZXI => new V4l(Z, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZXN => new V4l(Z, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZXX => new V4l(Z, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZXY => new V4l(Z, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZXZ => new V4l(Z, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZXW => new V4l(Z, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZYO => new V4l(Z, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZYI => new V4l(Z, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZYN => new V4l(Z, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZYX => new V4l(Z, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZYY => new V4l(Z, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZYZ => new V4l(Z, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZYW => new V4l(Z, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZZO => new V4l(Z, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZZI => new V4l(Z, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZZN => new V4l(Z, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZZX => new V4l(Z, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZZY => new V4l(Z, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZZZ => new V4l(Z, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZZW => new V4l(Z, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZWO => new V4l(Z, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZWI => new V4l(Z, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZWN => new V4l(Z, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZWX => new V4l(Z, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZWY => new V4l(Z, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZWZ => new V4l(Z, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZZWW => new V4l(Z, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWOO => new V4l(Z, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWOI => new V4l(Z, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWON => new V4l(Z, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWOX => new V4l(Z, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWOY => new V4l(Z, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWOZ => new V4l(Z, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWOW => new V4l(Z, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWIO => new V4l(Z, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWII => new V4l(Z, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWPN => new V4l(Z, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWIX => new V4l(Z, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWIY => new V4l(Z, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWIZ => new V4l(Z, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWIW => new V4l(Z, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWNO => new V4l(Z, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWNP => new V4l(Z, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWNN => new V4l(Z, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWNX => new V4l(Z, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWNY => new V4l(Z, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWNZ => new V4l(Z, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWNW => new V4l(Z, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWXO => new V4l(Z, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWXI => new V4l(Z, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWXN => new V4l(Z, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWXX => new V4l(Z, W, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l ZWXY { readonly get => new V4l(Z, W, X, Y); set { Z = value.X; W = value.Y; X = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWXZ => new V4l(Z, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWXW => new V4l(Z, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWYO => new V4l(Z, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWYI => new V4l(Z, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWYN => new V4l(Z, W, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l ZWYX { readonly get => new V4l(Z, W, Y, X); set { Z = value.X; W = value.Y; Y = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWYY => new V4l(Z, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWYZ => new V4l(Z, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWYW => new V4l(Z, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWZO => new V4l(Z, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWZI => new V4l(Z, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWZN => new V4l(Z, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWZX => new V4l(Z, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWZY => new V4l(Z, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWZZ => new V4l(Z, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWZW => new V4l(Z, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWWO => new V4l(Z, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWWI => new V4l(Z, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWWN => new V4l(Z, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWWX => new V4l(Z, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWWY => new V4l(Z, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWWZ => new V4l(Z, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l ZWWW => new V4l(Z, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOOO => new V4l(W, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOOI => new V4l(W, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOON => new V4l(W, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOOX => new V4l(W, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOOY => new V4l(W, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOOZ => new V4l(W, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOOW => new V4l(W, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOIO => new V4l(W, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOII => new V4l(W, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOPN => new V4l(W, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOIX => new V4l(W, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOIY => new V4l(W, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOIZ => new V4l(W, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOIW => new V4l(W, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WONO => new V4l(W, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WONP => new V4l(W, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WONN => new V4l(W, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WONX => new V4l(W, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WONY => new V4l(W, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WONZ => new V4l(W, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WONW => new V4l(W, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOXO => new V4l(W, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOXI => new V4l(W, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOXN => new V4l(W, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOXX => new V4l(W, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOXY => new V4l(W, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOXZ => new V4l(W, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOXW => new V4l(W, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOYO => new V4l(W, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOYI => new V4l(W, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOYN => new V4l(W, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOYX => new V4l(W, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOYY => new V4l(W, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOYZ => new V4l(W, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOYW => new V4l(W, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOZO => new V4l(W, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOZI => new V4l(W, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOZN => new V4l(W, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOZX => new V4l(W, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOZY => new V4l(W, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOZZ => new V4l(W, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOZW => new V4l(W, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOWO => new V4l(W, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOWI => new V4l(W, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOWN => new V4l(W, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOWX => new V4l(W, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOWY => new V4l(W, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOWZ => new V4l(W, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WOWW => new V4l(W, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIOO => new V4l(W, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIOI => new V4l(W, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WPON => new V4l(W, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIOX => new V4l(W, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIOY => new V4l(W, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIOZ => new V4l(W, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIOW => new V4l(W, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIIO => new V4l(W, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIII => new V4l(W, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WPPN => new V4l(W, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIIX => new V4l(W, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIIY => new V4l(W, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIIZ => new V4l(W, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIIW => new V4l(W, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WPNO => new V4l(W, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WPNP => new V4l(W, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WPNN => new V4l(W, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WPNX => new V4l(W, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WPNY => new V4l(W, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WPNZ => new V4l(W, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WPNW => new V4l(W, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIXO => new V4l(W, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIXI => new V4l(W, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WPXN => new V4l(W, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIXX => new V4l(W, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIXY => new V4l(W, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIXZ => new V4l(W, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIXW => new V4l(W, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIYO => new V4l(W, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIYI => new V4l(W, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WPYN => new V4l(W, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIYX => new V4l(W, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIYY => new V4l(W, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIYZ => new V4l(W, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIYW => new V4l(W, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIZO => new V4l(W, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIZI => new V4l(W, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WPZN => new V4l(W, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIZX => new V4l(W, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIZY => new V4l(W, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIZZ => new V4l(W, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIZW => new V4l(W, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIWO => new V4l(W, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIWI => new V4l(W, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WPWN => new V4l(W, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIWX => new V4l(W, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIWY => new V4l(W, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIWZ => new V4l(W, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WIWW => new V4l(W, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNOO => new V4l(W, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNOP => new V4l(W, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNON => new V4l(W, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNOX => new V4l(W, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNOY => new V4l(W, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNOZ => new V4l(W, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNOW => new V4l(W, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNPO => new V4l(W, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNPP => new V4l(W, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNPN => new V4l(W, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNPX => new V4l(W, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNPY => new V4l(W, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNPZ => new V4l(W, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNPW => new V4l(W, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNNO => new V4l(W, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNNP => new V4l(W, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNNN => new V4l(W, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNNX => new V4l(W, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNNY => new V4l(W, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNNZ => new V4l(W, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNNW => new V4l(W, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNXO => new V4l(W, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNXP => new V4l(W, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNXN => new V4l(W, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNXX => new V4l(W, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNXY => new V4l(W, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNXZ => new V4l(W, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNXW => new V4l(W, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNYO => new V4l(W, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNYP => new V4l(W, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNYN => new V4l(W, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNYX => new V4l(W, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNYY => new V4l(W, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNYZ => new V4l(W, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNYW => new V4l(W, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNZO => new V4l(W, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNZP => new V4l(W, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNZN => new V4l(W, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNZX => new V4l(W, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNZY => new V4l(W, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNZZ => new V4l(W, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNZW => new V4l(W, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNWO => new V4l(W, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNWP => new V4l(W, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNWN => new V4l(W, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNWX => new V4l(W, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNWY => new V4l(W, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNWZ => new V4l(W, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WNWW => new V4l(W, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXOO => new V4l(W, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXOI => new V4l(W, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXON => new V4l(W, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXOX => new V4l(W, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXOY => new V4l(W, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXOZ => new V4l(W, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXOW => new V4l(W, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXIO => new V4l(W, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXII => new V4l(W, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXPN => new V4l(W, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXIX => new V4l(W, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXIY => new V4l(W, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXIZ => new V4l(W, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXIW => new V4l(W, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXNO => new V4l(W, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXNP => new V4l(W, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXNN => new V4l(W, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXNX => new V4l(W, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXNY => new V4l(W, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXNZ => new V4l(W, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXNW => new V4l(W, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXXO => new V4l(W, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXXI => new V4l(W, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXXN => new V4l(W, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXXX => new V4l(W, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXXY => new V4l(W, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXXZ => new V4l(W, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXXW => new V4l(W, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXYO => new V4l(W, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXYI => new V4l(W, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXYN => new V4l(W, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXYX => new V4l(W, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXYY => new V4l(W, X, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l WXYZ { readonly get => new V4l(W, X, Y, Z); set { W = value.X; X = value.Y; Y = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXYW => new V4l(W, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXZO => new V4l(W, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXZI => new V4l(W, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXZN => new V4l(W, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXZX => new V4l(W, X, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l WXZY { readonly get => new V4l(W, X, Z, Y); set { W = value.X; X = value.Y; Z = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXZZ => new V4l(W, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXZW => new V4l(W, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXWO => new V4l(W, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXWI => new V4l(W, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXWN => new V4l(W, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXWX => new V4l(W, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXWY => new V4l(W, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXWZ => new V4l(W, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WXWW => new V4l(W, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYOO => new V4l(W, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYOI => new V4l(W, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYON => new V4l(W, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYOX => new V4l(W, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYOY => new V4l(W, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYOZ => new V4l(W, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYOW => new V4l(W, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYIO => new V4l(W, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYII => new V4l(W, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYPN => new V4l(W, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYIX => new V4l(W, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYIY => new V4l(W, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYIZ => new V4l(W, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYIW => new V4l(W, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYNO => new V4l(W, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYNP => new V4l(W, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYNN => new V4l(W, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYNX => new V4l(W, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYNY => new V4l(W, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYNZ => new V4l(W, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYNW => new V4l(W, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYXO => new V4l(W, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYXI => new V4l(W, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYXN => new V4l(W, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYXX => new V4l(W, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYXY => new V4l(W, Y, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l WYXZ { readonly get => new V4l(W, Y, X, Z); set { W = value.X; Y = value.Y; X = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYXW => new V4l(W, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYYO => new V4l(W, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYYI => new V4l(W, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYYN => new V4l(W, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYYX => new V4l(W, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYYY => new V4l(W, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYYZ => new V4l(W, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYYW => new V4l(W, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYZO => new V4l(W, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYZI => new V4l(W, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYZN => new V4l(W, Y, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l WYZX { readonly get => new V4l(W, Y, Z, X); set { W = value.X; Y = value.Y; Z = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYZY => new V4l(W, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYZZ => new V4l(W, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYZW => new V4l(W, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYWO => new V4l(W, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYWI => new V4l(W, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYWN => new V4l(W, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYWX => new V4l(W, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYWY => new V4l(W, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYWZ => new V4l(W, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WYWW => new V4l(W, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZOO => new V4l(W, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZOI => new V4l(W, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZON => new V4l(W, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZOX => new V4l(W, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZOY => new V4l(W, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZOZ => new V4l(W, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZOW => new V4l(W, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZIO => new V4l(W, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZII => new V4l(W, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZPN => new V4l(W, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZIX => new V4l(W, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZIY => new V4l(W, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZIZ => new V4l(W, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZIW => new V4l(W, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZNO => new V4l(W, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZNP => new V4l(W, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZNN => new V4l(W, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZNX => new V4l(W, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZNY => new V4l(W, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZNZ => new V4l(W, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZNW => new V4l(W, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZXO => new V4l(W, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZXI => new V4l(W, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZXN => new V4l(W, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZXX => new V4l(W, Z, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l WZXY { readonly get => new V4l(W, Z, X, Y); set { W = value.X; Z = value.Y; X = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZXZ => new V4l(W, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZXW => new V4l(W, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZYO => new V4l(W, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZYI => new V4l(W, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZYN => new V4l(W, Z, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4l WZYX { readonly get => new V4l(W, Z, Y, X); set { W = value.X; Z = value.Y; Y = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZYY => new V4l(W, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZYZ => new V4l(W, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZYW => new V4l(W, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZZO => new V4l(W, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZZI => new V4l(W, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZZN => new V4l(W, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZZX => new V4l(W, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZZY => new V4l(W, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZZZ => new V4l(W, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZZW => new V4l(W, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZWO => new V4l(W, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZWI => new V4l(W, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZWN => new V4l(W, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZWX => new V4l(W, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZWY => new V4l(W, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZWZ => new V4l(W, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WZWW => new V4l(W, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWOO => new V4l(W, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWOI => new V4l(W, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWON => new V4l(W, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWOX => new V4l(W, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWOY => new V4l(W, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWOZ => new V4l(W, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWOW => new V4l(W, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWIO => new V4l(W, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWII => new V4l(W, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWPN => new V4l(W, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWIX => new V4l(W, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWIY => new V4l(W, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWIZ => new V4l(W, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWIW => new V4l(W, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWNO => new V4l(W, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWNP => new V4l(W, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWNN => new V4l(W, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWNX => new V4l(W, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWNY => new V4l(W, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWNZ => new V4l(W, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWNW => new V4l(W, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWXO => new V4l(W, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWXI => new V4l(W, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWXN => new V4l(W, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWXX => new V4l(W, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWXY => new V4l(W, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWXZ => new V4l(W, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWXW => new V4l(W, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWYO => new V4l(W, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWYI => new V4l(W, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWYN => new V4l(W, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWYX => new V4l(W, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWYY => new V4l(W, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWYZ => new V4l(W, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWYW => new V4l(W, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWZO => new V4l(W, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWZI => new V4l(W, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWZN => new V4l(W, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWZX => new V4l(W, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWZY => new V4l(W, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWZZ => new V4l(W, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWZW => new V4l(W, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWWO => new V4l(W, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWWI => new V4l(W, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWWN => new V4l(W, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWWX => new V4l(W, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWWY => new V4l(W, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWWZ => new V4l(W, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4l WWWW => new V4l(W, W, W, W); #endregion #region IVector Members /// /// By using long indices, the IVector<double> interface is /// accessed. /// public double this[long i] { readonly get { return (double)this[(int)i]; } set { this[(int)i] = (long)value; } } #endregion #region ISize4l Members public readonly V4l Size4l { get { return this; } } #endregion #region IVector public readonly long Dim { get { return 4; } } public readonly object GetValue(long index) { return (object)this[(int)index]; } public void SetValue(object value, long index) { this[(int)index] = (long)value; } #endregion } public class V4lEqualityComparer : IEqualityComparer { public static V4lEqualityComparer Default => new V4lEqualityComparer(); #region IEqualityComparer Members public bool Equals(V4l v0, V4l v1) { return v0 == v1; } public int GetHashCode(V4l v) { return v.GetHashCode(); } #endregion } public static partial class Fun { #region Min and Max /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Min(this V4l a, V4l b) { return new V4l(Min(a.X, b.X), Min(a.Y, b.Y), Min(a.Z, b.Z), Min(a.W, b.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Min(this V4l a, long b) { return new V4l(Min(a.X, b), Min(a.Y, b), Min(a.Z, b), Min(a.W, b)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Min(this long a, V4l b) { return new V4l(Min(a, b.X), Min(a, b.Y), Min(a, b.Z), Min(a, b.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Max(this V4l a, V4l b) { return new V4l(Max(a.X, b.X), Max(a.Y, b.Y), Max(a.Z, b.Z), Max(a.W, b.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Max(this V4l a, long b) { return new V4l(Max(a.X, b), Max(a.Y, b), Max(a.Z, b), Max(a.W, b)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Max(this long a, V4l b) { return new V4l(Max(a, b.X), Max(a, b.Y), Max(a, b.Z), Max(a, b.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Min(this V4l a, V4l b, V4l c) { return new V4l(Min(a.X, b.X, c.X), Min(a.Y, b.Y, c.Y), Min(a.Z, b.Z, c.Z), Min(a.W, b.W, c.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Max(this V4l a, V4l b, V4l c) { return new V4l(Max(a.X, b.X, c.X), Max(a.Y, b.Y, c.Y), Max(a.Z, b.Z, c.Z), Max(a.W, b.W, c.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Min(this V4l a, V4l b, V4l c, V4l d) { return new V4l(Min(a.X, b.X, c.X, d.X), Min(a.Y, b.Y, c.Y, d.Y), Min(a.Z, b.Z, c.Z, d.Z), Min(a.W, b.W, c.W, d.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Max(this V4l a, V4l b, V4l c, V4l d) { return new V4l(Max(a.X, b.X, c.X, d.X), Max(a.Y, b.Y, c.Y, d.Y), Max(a.Z, b.Z, c.Z, d.Z), Max(a.W, b.W, c.W, d.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Min(this V4l x, params V4l[] values) { return new V4l(Min(x.X, values.Map(a => a.X)), Min(x.Y, values.Map(a => a.Y)), Min(x.Z, values.Map(a => a.Z)), Min(x.W, values.Map(a => a.W))); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Max(this V4l x, params V4l[] values) { return new V4l(Max(x.X, values.Map(a => a.X)), Max(x.Y, values.Map(a => a.Y)), Max(x.Z, values.Map(a => a.Z)), Max(x.W, values.Map(a => a.W))); } #endregion #region Abs /// /// Applies Fun.Abs to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Abs(this V4l x) { return new V4l(Abs(x.X), Abs(x.Y), Abs(x.Z), Abs(x.W)); } #endregion #region Clamping /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Clamp(this V4l x, V4l a, V4l b) { return new V4l(Clamp(x.X, a.X, b.X), Clamp(x.Y, a.Y, b.Y), Clamp(x.Z, a.Z, b.Z), Clamp(x.W, a.W, b.W)); } /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Clamp(this V4l x, long a, long b) { return new V4l(Clamp(x.X, a, b), Clamp(x.Y, a, b), Clamp(x.Z, a, b), Clamp(x.W, a, b)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l ClampExcl(this V4l x, V4l a, V4l b) { return new V4l(ClampExcl(x.X, a.X, b.X), ClampExcl(x.Y, a.Y, b.Y), ClampExcl(x.Z, a.Z, b.Z), ClampExcl(x.W, a.W, b.W)); } /// /// Applies Fun.ClampExcl to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l ClampExcl(this V4l x, long a, long b) { return new V4l(ClampExcl(x.X, a, b), ClampExcl(x.Y, a, b), ClampExcl(x.Z, a, b), ClampExcl(x.W, a, b)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l ClampWrap(this V4l x, V4l a, V4l b) { return new V4l(ClampWrap(x.X, a.X, b.X), ClampWrap(x.Y, a.Y, b.Y), ClampWrap(x.Z, a.Z, b.Z), ClampWrap(x.W, a.W, b.W)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l ClampWrap(this V4l x, long a, long b) { return new V4l(ClampWrap(x.X, a, b), ClampWrap(x.Y, a, b), ClampWrap(x.Z, a, b), ClampWrap(x.W, a, b)); } /// /// Applies Fun.Saturate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Saturate(this V4l x) { return new V4l(Saturate(x.X), Saturate(x.Y), Saturate(x.Z), Saturate(x.W)); } #endregion #region Sign /// /// Applies Fun.Sign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Sign(this V4l x) { return new V4i(Sign(x.X), Sign(x.Y), Sign(x.Z), Sign(x.W)); } /// /// Applies Fun.Signumi to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Signumi(this V4l x) { return new V4i(Signumi(x.X), Signumi(x.Y), Signumi(x.Z), Signumi(x.W)); } /// /// Applies Fun.Signum to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Signum(this V4l x) { return new V4l(Signum(x.X), Signum(x.Y), Signum(x.Z), Signum(x.W)); } #endregion #region Multiply-Add /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l MultiplyAdd(V4l x, V4l y, V4l z) { return new V4l(MultiplyAdd(x.X, y.X, z.X), MultiplyAdd(x.Y, y.Y, z.Y), MultiplyAdd(x.Z, y.Z, z.Z), MultiplyAdd(x.W, y.W, z.W)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l MultiplyAdd(V4l x, long y, V4l z) { return new V4l(MultiplyAdd(x.X, y, z.X), MultiplyAdd(x.Y, y, z.Y), MultiplyAdd(x.Z, y, z.Z), MultiplyAdd(x.W, y, z.W)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l MultiplyAdd(long x, V4l y, V4l z) { return new V4l(MultiplyAdd(x, y.X, z.X), MultiplyAdd(x, y.Y, z.Y), MultiplyAdd(x, y.Z, z.Z), MultiplyAdd(x, y.W, z.W)); } #endregion #region Roots /// /// Applies Fun.Sqrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Sqrt(this V4l x) { return new V4d(Sqrt(x.X), Sqrt(x.Y), Sqrt(x.Z), Sqrt(x.W)); } /// /// Applies Fun.Cbrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Cbrt(this V4l x) { return new V4d(Cbrt(x.X), Cbrt(x.Y), Cbrt(x.Z), Cbrt(x.W)); } #endregion #region Square /// /// Applies Fun.Square to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Square(this V4l x) { return new V4l(Square(x.X), Square(x.Y), Square(x.Z), Square(x.W)); } #endregion #region Power /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Pown(this V4l x, V4l y) { return new V4l(Pown(x.X, y.X), Pown(x.Y, y.Y), Pown(x.Z, y.Z), Pown(x.W, y.W)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Pown(this V4l x, long y) { return new V4l(Pown(x.X, y), Pown(x.Y, y), Pown(x.Z, y), Pown(x.W, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Pown(this long x, V4l y) { return new V4l(Pown(x, y.X), Pown(x, y.Y), Pown(x, y.Z), Pown(x, y.W)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Pown(this V4l x, V4i y) { return new V4l(Pown(x.X, y.X), Pown(x.Y, y.Y), Pown(x.Z, y.Z), Pown(x.W, y.W)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Pown(this V4l x, int y) { return new V4l(Pown(x.X, y), Pown(x.Y, y), Pown(x.Z, y), Pown(x.W, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Pown(this long x, V4i y) { return new V4l(Pown(x, y.X), Pown(x, y.Y), Pown(x, y.Z), Pown(x, y.W)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Pow(this V4l x, V4f y) { return new V4f(Pow(x.X, y.X), Pow(x.Y, y.Y), Pow(x.Z, y.Z), Pow(x.W, y.W)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Pow(this V4l x, float y) { return new V4f(Pow(x.X, y), Pow(x.Y, y), Pow(x.Z, y), Pow(x.W, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Pow(this long x, V4f y) { return new V4f(Pow(x, y.X), Pow(x, y.Y), Pow(x, y.Z), Pow(x, y.W)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Pow(this V4l x, V4d y) { return new V4d(Pow(x.X, y.X), Pow(x.Y, y.Y), Pow(x.Z, y.Z), Pow(x.W, y.W)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Pow(this V4l x, double y) { return new V4d(Pow(x.X, y), Pow(x.Y, y), Pow(x.Z, y), Pow(x.W, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Pow(this long x, V4d y) { return new V4d(Pow(x, y.X), Pow(x, y.Y), Pow(x, y.Z), Pow(x, y.W)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Power(this V4l x, V4f y) { return new V4f(Power(x.X, y.X), Power(x.Y, y.Y), Power(x.Z, y.Z), Power(x.W, y.W)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Power(this V4l x, float y) { return new V4f(Power(x.X, y), Power(x.Y, y), Power(x.Z, y), Power(x.W, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Power(this long x, V4f y) { return new V4f(Power(x, y.X), Power(x, y.Y), Power(x, y.Z), Power(x, y.W)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Power(this V4l x, V4d y) { return new V4d(Power(x.X, y.X), Power(x.Y, y.Y), Power(x.Z, y.Z), Power(x.W, y.W)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Power(this V4l x, double y) { return new V4d(Power(x.X, y), Power(x.Y, y), Power(x.Z, y), Power(x.W, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Power(this long x, V4d y) { return new V4d(Power(x, y.X), Power(x, y.Y), Power(x, y.Z), Power(x, y.W)); } #endregion #region Exp and Log /// /// Applies Fun.Exp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Exp(this V4l x) { return new V4d(Exp(x.X), Exp(x.Y), Exp(x.Z), Exp(x.W)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log(this V4l x) { return new V4d(Log(x.X), Log(x.Y), Log(x.Z), Log(x.W)); } /// /// Applies Fun.Log2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log2(this V4l x) { return new V4d(Log2(x.X), Log2(x.Y), Log2(x.Z), Log2(x.W)); } /// /// Applies Fun.Log2Int to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Log2Int(this V4l x) { return new V4i(Log2Int(x.X), Log2Int(x.Y), Log2Int(x.Z), Log2Int(x.W)); } /// /// Applies Fun.Log10 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log10(this V4l x) { return new V4d(Log10(x.X), Log10(x.Y), Log10(x.Z), Log10(x.W)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log(this V4l x, double basis) { return new V4d(Log(x.X, basis), Log(x.Y, basis), Log(x.Z, basis), Log(x.W, basis)); } #endregion #region ModP /// /// Applies Fun.ModP to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l ModP(this V4l a, V4l b) { return new V4l(ModP(a.X, b.X), ModP(a.Y, b.Y), ModP(a.Z, b.Z), ModP(a.W, b.W)); } #endregion #region Power of Two /// /// Applies Fun.PowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l PowerOfTwo(this V4l x) { return new V4l(PowerOfTwo(x.X), PowerOfTwo(x.Y), PowerOfTwo(x.Z), PowerOfTwo(x.W)); } /// /// Applies Fun.NextPowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l NextPowerOfTwo(this V4l x) { return new V4l(NextPowerOfTwo(x.X), NextPowerOfTwo(x.Y), NextPowerOfTwo(x.Z), NextPowerOfTwo(x.W)); } /// /// Applies Fun.PrevPowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l PrevPowerOfTwo(this V4l x) { return new V4l(PrevPowerOfTwo(x.X), PrevPowerOfTwo(x.Y), PrevPowerOfTwo(x.Z), PrevPowerOfTwo(x.W)); } #endregion #region Step functions /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Step(this V4l x, V4l edge) { return new V4l(Step(x.X, edge.X), Step(x.Y, edge.Y), Step(x.Z, edge.Z), Step(x.W, edge.W)); } /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Step(this V4l x, long edge) { return new V4l(Step(x.X, edge), Step(x.Y, edge), Step(x.Z, edge), Step(x.W, edge)); } #endregion #region Interpolation /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Lerp(this float t, V4l a, V4l b) { return new V4l(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y), Lerp(t, a.Z, b.Z), Lerp(t, a.W, b.W)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Lerp(this V4f t, V4l a, V4l b) { return new V4l(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y), Lerp(t.Z, a.Z, b.Z), Lerp(t.W, a.W, b.W)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Lerp(this double t, V4l a, V4l b) { return new V4l(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y), Lerp(t, a.Z, b.Z), Lerp(t, a.W, b.W)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l Lerp(this V4d t, V4l a, V4l b) { return new V4l(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y), Lerp(t.Z, a.Z, b.Z), Lerp(t.W, a.W, b.W)); } /// /// Applies Fun.InvLerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d InvLerp(this V4l y, V4l a, V4l b) { return new V4d(InvLerp(y.X, a.X, b.X), InvLerp(y.Y, a.Y, b.Y), InvLerp(y.Z, a.Z, b.Z), InvLerp(y.W, a.W, b.W)); } #endregion #region Common Divisor and Multiple /// /// Applies Fun.GreatestCommonDivisor to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l GreatestCommonDivisor(this V4l a, V4l b) { return new V4l(GreatestCommonDivisor(a.X, b.X), GreatestCommonDivisor(a.Y, b.Y), GreatestCommonDivisor(a.Z, b.Z), GreatestCommonDivisor(a.W, b.W)); } /// /// Applies Fun.LeastCommonMultiple to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l LeastCommonMultiple(this V4l a, V4l b) { return new V4l(LeastCommonMultiple(a.X, b.X), LeastCommonMultiple(a.Y, b.Y), LeastCommonMultiple(a.Z, b.Z), LeastCommonMultiple(a.W, b.W)); } #endregion #region Floating point bits /// /// Applies Fun.FloatFromBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d FloatFromBits(this V4l x) { return new V4d(FloatFromBits(x.X), FloatFromBits(x.Y), FloatFromBits(x.Z), FloatFromBits(x.W)); } #endregion #region ApproximateEquals /// /// Returns whether the given vectors are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V4l a, V4l b, long tolerance) { return ApproximateEquals(a.X, b.X, tolerance) && ApproximateEquals(a.Y, b.Y, tolerance) && ApproximateEquals(a.Z, b.Z, tolerance) && ApproximateEquals(a.W, b.W, tolerance); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this V4l v, long epsilon) => Vec.AllTiny(v, epsilon); #endregion } /// /// Contains static methods /// public static partial class Vec { #region Length /// /// Returns the squared length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long LengthSquared(V4l v) => v.LengthSquared; /// /// Returns the length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Length(V4l v) => v.Length; #endregion #region Normalize /// /// Returns a normalized copy of this vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Normalized(V4l v) => v.Normalized; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Norm1(V4l v) => v.Norm1; /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(V4l v) => v.Norm2; /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NormMax(V4l v) => v.NormMax; /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NormMin(V4l v) => v.NormMin; /// /// Gets the p-norm. This is calculated as the p-th root of (|x|^n + |y|^n + ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this V4l v, double p) { return ( Fun.Abs(v.X).Pow(p) + Fun.Abs(v.Y).Pow(p) + Fun.Abs(v.Z).Pow(p) + Fun.Abs(v.W).Pow(p)).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the squared distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long DistanceSquared(this V4l a, V4l b) => Fun.Square(b.X - a.X) + Fun.Square(b.Y - a.Y) + Fun.Square(b.Z - a.Z) + Fun.Square(b.W - a.W); /// /// Returns the distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V4l a, V4l b) => Fun.Sqrt(DistanceSquared(a, b)); /// /// Returns the Manhatten (or 1-) distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Distance1(this V4l a, V4l b) => Fun.Abs(b.X - a.X) + Fun.Abs(b.Y - a.Y) + Fun.Abs(b.Z - a.Z) + Fun.Abs(b.W - a.W); /// /// Returns the p-distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V4l a, V4l b, double p) => (Fun.Abs(b.X - a.X).Pow(p) + Fun.Abs(b.Y - a.Y).Pow(p) + Fun.Abs(b.Z - a.Z).Pow(p) + Fun.Abs(b.W - a.W).Pow(p)).Pow(1 / p); /// /// Returns the maximal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long DistanceMax(this V4l a, V4l b) => Fun.Max(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y), Fun.Abs(b.Z - a.Z), Fun.Abs(b.W - a.W)); /// /// Returns the minimal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long DistanceMin(this V4l a, V4l b) => Fun.Min(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y), Fun.Abs(b.Z - a.Z), Fun.Abs(b.W - a.W)); /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V4l query, V4l p0, V4l p1) { return DistanceToLine((V4d) query, (V4d) p0, (V4d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V4l query, V4l p0, V4l p1) { return DistanceToInfiniteLine((V4d) query, (V4d) p0, (V4d) p1); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V4l query, V4l p0, V4l p1, out double t) { return DistanceToLine((V4d) query, (V4d) p0, (V4d) p1, out t); } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V4l query, V4l p0, V4l p1, out double t) { return DistanceToInfiniteLine((V4d) query, (V4d) p0, (V4d) p1, out t); } #endregion #region Operations /// /// Negates the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Negate(this ref V4l v) { v.X = -v.X; v.Y = -v.Y; v.Z = -v.Z; v.W = -v.W; } /// /// Returns the outer product (tensor-product) of a * b^T as a 4x4 matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44l Outer(this V4l a, V4l b) { return new M44l( a.X * b.X, a.X * b.Y, a.X * b.Z, a.X * b.W, a.Y * b.X, a.Y * b.Y, a.Y * b.Z, a.Y * b.W, a.Z * b.X, a.Z * b.Y, a.Z * b.Z, a.Z * b.W, a.W * b.X, a.W * b.Y, a.W * b.Z, a.W * b.W); } /// /// Returns the dot product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Dot(this V4l a, V4l b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z + a.W * b.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DirFlags DirFlags(this V4l v) { DirFlags flags = Aardbase.DirFlags.None; if (v.X > 0) flags |= Aardbase.DirFlags.PositiveX; if (v.X < 0) flags |= Aardbase.DirFlags.NegativeX; if (v.Y > 0) flags |= Aardbase.DirFlags.PositiveY; if (v.Y < 0) flags |= Aardbase.DirFlags.NegativeY; if (v.Z > 0) flags |= Aardbase.DirFlags.PositiveZ; if (v.Z < 0) flags |= Aardbase.DirFlags.NegativeZ; if (v.W > 0) flags |= Aardbase.DirFlags.PositiveW; if (v.W < 0) flags |= Aardbase.DirFlags.NegativeW; return flags; } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V4l a, V4l b) { return (a.X < b.X && a.Y < b.Y && a.Z < b.Z && a.W < b.W); } /// /// Returns whether ALL elements of v are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V4l v, long s) { return (v.X < s && v.Y < s && v.Z < s && v.W < s); } /// /// Returns whether a is Smaller ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(long s, V4l v) { return (s < v.X && s < v.Y && s < v.Z && s < v.W); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V4l a, V4l b) { return (a.X < b.X || a.Y < b.Y || a.Z < b.Z || a.W < b.W); } /// /// Returns whether AT LEAST ONE element of v is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V4l v, long s) { return (v.X < s || v.Y < s || v.Z < s || v.W < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(long s, V4l v) { return (s < v.X || s < v.Y || s < v.Z || s < v.W); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V4l a, V4l b) { return (a.X > b.X && a.Y > b.Y && a.Z > b.Z && a.W > b.W); } /// /// Returns whether ALL elements of v are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V4l v, long s) { return (v.X > s && v.Y > s && v.Z > s && v.W > s); } /// /// Returns whether a is Greater ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(long s, V4l v) { return (s > v.X && s > v.Y && s > v.Z && s > v.W); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V4l a, V4l b) { return (a.X > b.X || a.Y > b.Y || a.Z > b.Z || a.W > b.W); } /// /// Returns whether AT LEAST ONE element of v is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V4l v, long s) { return (v.X > s || v.Y > s || v.Z > s || v.W > s); } /// /// Returns whether a is Greater AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(long s, V4l v) { return (s > v.X || s > v.Y || s > v.Z || s > v.W); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V4l a, V4l b) { return (a.X <= b.X && a.Y <= b.Y && a.Z <= b.Z && a.W <= b.W); } /// /// Returns whether ALL elements of v are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V4l v, long s) { return (v.X <= s && v.Y <= s && v.Z <= s && v.W <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(long s, V4l v) { return (s <= v.X && s <= v.Y && s <= v.Z && s <= v.W); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V4l a, V4l b) { return (a.X <= b.X || a.Y <= b.Y || a.Z <= b.Z || a.W <= b.W); } /// /// Returns whether AT LEAST ONE element of v is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V4l v, long s) { return (v.X <= s || v.Y <= s || v.Z <= s || v.W <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(long s, V4l v) { return (s <= v.X || s <= v.Y || s <= v.Z || s <= v.W); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V4l a, V4l b) { return (a.X >= b.X && a.Y >= b.Y && a.Z >= b.Z && a.W >= b.W); } /// /// Returns whether ALL elements of v are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V4l v, long s) { return (v.X >= s && v.Y >= s && v.Z >= s && v.W >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(long s, V4l v) { return (s >= v.X && s >= v.Y && s >= v.Z && s >= v.W); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V4l a, V4l b) { return (a.X >= b.X || a.Y >= b.Y || a.Z >= b.Z || a.W >= b.W); } /// /// Returns whether AT LEAST ONE element of v is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V4l v, long s) { return (v.X >= s || v.Y >= s || v.Z >= s || v.W >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(long s, V4l v) { return (s >= v.X || s >= v.Y || s >= v.Z || s >= v.W); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V4l a, V4l b) { return (a.X == b.X && a.Y == b.Y && a.Z == b.Z && a.W == b.W); } /// /// Returns whether ALL elements of v are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V4l v, long s) { return (v.X == s && v.Y == s && v.Z == s && v.W == s); } /// /// Returns whether a is Equal ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(long s, V4l v) { return (s == v.X && s == v.Y && s == v.Z && s == v.W); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V4l a, V4l b) { return (a.X == b.X || a.Y == b.Y || a.Z == b.Z || a.W == b.W); } /// /// Returns whether AT LEAST ONE element of v is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V4l v, long s) { return (v.X == s || v.Y == s || v.Z == s || v.W == s); } /// /// Returns whether a is Equal AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(long s, V4l v) { return (s == v.X || s == v.Y || s == v.Z || s == v.W); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V4l a, V4l b) { return (a.X != b.X && a.Y != b.Y && a.Z != b.Z && a.W != b.W); } /// /// Returns whether ALL elements of v are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V4l v, long s) { return (v.X != s && v.Y != s && v.Z != s && v.W != s); } /// /// Returns whether a is Different ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(long s, V4l v) { return (s != v.X && s != v.Y && s != v.Z && s != v.W); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V4l a, V4l b) { return (a.X != b.X || a.Y != b.Y || a.Z != b.Z || a.W != b.W); } /// /// Returns whether AT LEAST ONE element of v is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V4l v, long s) { return (v.X != s || v.Y != s || v.Z != s || v.W != s); } /// /// Returns whether a is Different AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(long s, V4l v) { return (s != v.X || s != v.Y || s != v.Z || s != v.W); } /// /// Compare x-coordinate before y-coordinate, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this V4l v0, V4l v1) { if (v0.X < v1.X) return -1; if (v0.X > v1.X) return +1; if (v0.Y < v1.Y) return -1; if (v0.Y > v1.Y) return +1; if (v0.Z < v1.Z) return -1; if (v0.Z > v1.Z) return +1; if (v0.W < v1.W) return -1; if (v0.W > v1.W) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MinElement(V4l v) => v.MinElement; /// /// Returns the maximum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long MaxElement(V4l v) => v.MaxElement; #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this V4l v, long epsilon) => v.X.IsTiny(epsilon) || v.Y.IsTiny(epsilon) || v.Z.IsTiny(epsilon) || v.W.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this V4l v, long epsilon) => v.X.IsTiny(epsilon) && v.Y.IsTiny(epsilon) && v.Z.IsTiny(epsilon) && v.W.IsTiny(epsilon); #endregion #region ArrayExtensions public static int IndexOfClosestPoint(this V4l[] pointArray, V4l point) { var bestDist = DistanceSquared(point, pointArray[0]); int bestIndex = 0; int count = pointArray.Length; for (int i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this V4l[] array, int start, int count, V4l point) { var bestDist = DistanceSquared(point, array[start]); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this T[] array, int start, int count, Func pointSelector, V4l point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint(this V4l[] pointArray, V4l point) { var bestDist = DistanceSquared(point, pointArray[0]); long bestIndex = 0; long count = pointArray.LongLength; for (long i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this V4l[] array, long start, long count, V4l point) { var bestDist = DistanceSquared(point, array[start]); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this T[] array, long start, long count, Func pointSelector, V4l point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static int IndexOfMinX(this V4l[] vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static long LongIndexOfMinX(this V4l[] vectorArray, long count = 0) { var minimum = vectorArray[0].X; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static int IndexOfMaxX(this V4l[] vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static long LongIndexOfMaxX(this V4l[] vectorArray, long count = 0) { var maximum = vectorArray[0].X; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static int IndexOfMinY(this V4l[] vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static long LongIndexOfMinY(this V4l[] vectorArray, long count = 0) { var minimum = vectorArray[0].Y; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static int IndexOfMaxY(this V4l[] vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static long LongIndexOfMaxY(this V4l[] vectorArray, long count = 0) { var maximum = vectorArray[0].Y; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static int IndexOfMinZ(this V4l[] vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static long LongIndexOfMinZ(this V4l[] vectorArray, long count = 0) { var minimum = vectorArray[0].Z; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static int IndexOfMaxZ(this V4l[] vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static long LongIndexOfMaxZ(this V4l[] vectorArray, long count = 0) { var maximum = vectorArray[0].Z; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal W coordinate /// within the array. /// public static int IndexOfMinW(this V4l[] vectorArray, int count = 0) { var minimum = vectorArray[0].W; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal W coordinate /// within the array. /// public static long LongIndexOfMinW(this V4l[] vectorArray, long count = 0) { var minimum = vectorArray[0].W; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].W; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal W coordinate /// within the array. /// public static int IndexOfMaxW(this V4l[] vectorArray, int count = 0) { var maximum = vectorArray[0].W; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal W coordinate /// within the array. /// public static long LongIndexOfMaxW(this V4l[] vectorArray, long count = 0) { var maximum = vectorArray[0].W; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].W; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the list. /// public static int IndexOfMinX(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the list. /// public static int IndexOfMaxX(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the list. /// public static int IndexOfMinY(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the list. /// public static int IndexOfMaxY(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the list. /// public static int IndexOfMinZ(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the list. /// public static int IndexOfMaxZ(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal W coordinate /// within the list. /// public static int IndexOfMinW(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].W; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal W coordinate /// within the list. /// public static int IndexOfMaxW(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].W; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the array of the index-th coordinate of each vector. /// public static long[] CopyCoord(this V4l[] self, int index) { switch (index) { case 0: return self.Map(v => v.X); case 1: return self.Map(v => v.Y); case 2: return self.Map(v => v.Z); case 3: return self.Map(v => v.W); default: throw new IndexOutOfRangeException(); } } #endregion } public static class IRandomUniformV4lExtensions { #region IRandomUniform extensions for V4l /// /// Uses UniformLong() to generate the elements of a V4l vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l UniformV4l(this IRandomUniform rnd) { return new V4l(rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong(), rnd.UniformLong()); } /// /// Uses UniformLongNonZero() to generate the elements of a V4l vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l UniformV4lNonZero(this IRandomUniform rnd) { return new V4l(rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero(), rnd.UniformLongNonZero()); } /// /// Uses UniformLong(long) to generate the elements of a V4l vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l UniformV4l(this IRandomUniform rnd, long size) { return new V4l(rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size), rnd.UniformLong(size)); } /// /// Uses UniformLong(long) to generate the elements of a V4l vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l UniformV4l(this IRandomUniform rnd, V4l size) { return new V4l(rnd.UniformLong(size.X), rnd.UniformLong(size.Y), rnd.UniformLong(size.Z), rnd.UniformLong(size.W)); } #endregion } #endregion #region V4f [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct V4f : IVector, ISize4f, IFormattable, IEquatable { [DataMember] public float X; [DataMember] public float Y; [DataMember] public float Z; [DataMember] public float W; #region Constructors /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(int x, int y, int z, int w) { X = (float)x; Y = (float)y; Z = (float)z; W = (float)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(int v) { X = (float)v; Y = (float)v; Z = (float)v; W = (float)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(int[] a) { X = (float)a[0]; Y = (float)a[1]; Z = (float)a[2]; W = (float)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(int[] a, int start) { X = (float)a[start + 0]; Y = (float)a[start + 1]; Z = (float)a[start + 2]; W = (float)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(int a, V3i b) { X = (float)a; Y = (float)b.X; Z = (float)b.Y; W = (float)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V2i a, V2i b) { X = (float)a.X; Y = (float)a.Y; Z = (float)b.X; W = (float)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V3i a, int b) { X = (float)a.X; Y = (float)a.Y; Z = (float)a.Z; W = (float)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V2i a, int b, int c) { X = (float)a.X; Y = (float)a.Y; Z = (float)b; W = (float)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(int a, V2i b, int c) { X = (float)a; Y = (float)b.X; Z = (float)b.Y; W = (float)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(int a, int b, V2i c) { X = (float)a; Y = (float)b; Z = (float)c.X; W = (float)c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(uint x, uint y, uint z, uint w) { X = (float)x; Y = (float)y; Z = (float)z; W = (float)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(uint v) { X = (float)v; Y = (float)v; Z = (float)v; W = (float)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(uint[] a) { X = (float)a[0]; Y = (float)a[1]; Z = (float)a[2]; W = (float)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(uint[] a, int start) { X = (float)a[start + 0]; Y = (float)a[start + 1]; Z = (float)a[start + 2]; W = (float)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(uint a, V3ui b) { X = (float)a; Y = (float)b.X; Z = (float)b.Y; W = (float)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V2ui a, V2ui b) { X = (float)a.X; Y = (float)a.Y; Z = (float)b.X; W = (float)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V3ui a, uint b) { X = (float)a.X; Y = (float)a.Y; Z = (float)a.Z; W = (float)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V2ui a, uint b, uint c) { X = (float)a.X; Y = (float)a.Y; Z = (float)b; W = (float)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(uint a, V2ui b, uint c) { X = (float)a; Y = (float)b.X; Z = (float)b.Y; W = (float)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(uint a, uint b, V2ui c) { X = (float)a; Y = (float)b; Z = (float)c.X; W = (float)c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(long x, long y, long z, long w) { X = (float)x; Y = (float)y; Z = (float)z; W = (float)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(long v) { X = (float)v; Y = (float)v; Z = (float)v; W = (float)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(long[] a) { X = (float)a[0]; Y = (float)a[1]; Z = (float)a[2]; W = (float)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(long[] a, int start) { X = (float)a[start + 0]; Y = (float)a[start + 1]; Z = (float)a[start + 2]; W = (float)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(long a, V3l b) { X = (float)a; Y = (float)b.X; Z = (float)b.Y; W = (float)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V2l a, V2l b) { X = (float)a.X; Y = (float)a.Y; Z = (float)b.X; W = (float)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V3l a, long b) { X = (float)a.X; Y = (float)a.Y; Z = (float)a.Z; W = (float)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V2l a, long b, long c) { X = (float)a.X; Y = (float)a.Y; Z = (float)b; W = (float)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(long a, V2l b, long c) { X = (float)a; Y = (float)b.X; Z = (float)b.Y; W = (float)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(long a, long b, V2l c) { X = (float)a; Y = (float)b; Z = (float)c.X; W = (float)c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(float x, float y, float z, float w) { X = x; Y = y; Z = z; W = w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(float v) { X = v; Y = v; Z = v; W = v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(float[] a) { X = a[0]; Y = a[1]; Z = a[2]; W = a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(float[] a, int start) { X = a[start + 0]; Y = a[start + 1]; Z = a[start + 2]; W = a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(float a, V3f b) { X = a; Y = b.X; Z = b.Y; W = b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V2f a, V2f b) { X = a.X; Y = a.Y; Z = b.X; W = b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V3f a, float b) { X = a.X; Y = a.Y; Z = a.Z; W = b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V2f a, float b, float c) { X = a.X; Y = a.Y; Z = b; W = c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(float a, V2f b, float c) { X = a; Y = b.X; Z = b.Y; W = c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(float a, float b, V2f c) { X = a; Y = b; Z = c.X; W = c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(double x, double y, double z, double w) { X = (float)x; Y = (float)y; Z = (float)z; W = (float)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(double v) { X = (float)v; Y = (float)v; Z = (float)v; W = (float)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(double[] a) { X = (float)a[0]; Y = (float)a[1]; Z = (float)a[2]; W = (float)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(double[] a, int start) { X = (float)a[start + 0]; Y = (float)a[start + 1]; Z = (float)a[start + 2]; W = (float)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(double a, V3d b) { X = (float)a; Y = (float)b.X; Z = (float)b.Y; W = (float)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V2d a, V2d b) { X = (float)a.X; Y = (float)a.Y; Z = (float)b.X; W = (float)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V3d a, double b) { X = (float)a.X; Y = (float)a.Y; Z = (float)a.Z; W = (float)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V2d a, double b, double c) { X = (float)a.X; Y = (float)a.Y; Z = (float)b; W = (float)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(double a, V2d b, double c) { X = (float)a; Y = (float)b.X; Z = (float)b.Y; W = (float)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(double a, double b, V2d c) { X = (float)a; Y = (float)b; Z = (float)c.X; W = (float)c.Y; } /// /// Creates a vector from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(Func index_fun) { X = index_fun(0); Y = index_fun(1); Z = index_fun(2); W = index_fun(3); } /// /// Creates a vector from a general vector implementing the IVector<float> interface. /// The caller has to verify that the dimension of is at least 4. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(IVector v) : this(v[0], v[1], v[2], v[3]) { } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V2i v) { X = (float)v.X; Y = (float)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V2ui v) { X = (float)v.X; Y = (float)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V2l v) { X = (float)v.X; Y = (float)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V2f v) { X = v.X; Y = v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V2d v) { X = (float)v.X; Y = (float)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V3i v) { X = (float)v.X; Y = (float)v.Y; Z = (float)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V3ui v) { X = (float)v.X; Y = (float)v.Y; Z = (float)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V3l v) { X = (float)v.X; Y = (float)v.Y; Z = (float)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V3f v) { X = v.X; Y = v.Y; Z = v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V3d v) { X = (float)v.X; Y = (float)v.Y; Z = (float)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V4i v) { X = (float)v.X; Y = (float)v.Y; Z = (float)v.Z; W = (float)v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V4ui v) { X = (float)v.X; Y = (float)v.Y; Z = (float)v.Z; W = (float)v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V4l v) { X = (float)v.X; Y = (float)v.Y; Z = (float)v.Z; W = (float)v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V4f v) { X = v.X; Y = v.Y; Z = v.Z; W = v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(V4d v) { X = (float)v.X; Y = (float)v.Y; Z = (float)v.Z; W = (float)v.W; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(C3b c) { X = (float)(c.R); Y = (float)(c.G); Z = (float)(c.B); W = (float)255; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(C3us c) { X = (float)(c.R); Y = (float)(c.G); Z = (float)(c.B); W = (float)65535; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// W is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(C3ui c) { X = (float)(c.R); Y = (float)(c.G); Z = (float)(c.B); W = (float)UInt32.MaxValue; } /// /// Creates a vector from a color. /// W is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(C3f c) { X = (c.R); Y = (c.G); Z = (c.B); W = 1.0f; } /// /// Creates a vector from a color. /// W is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(C3d c) { X = (float)(c.R); Y = (float)(c.G); Z = (float)(c.B); W = (float)1.0; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(C4b c) { X = (float)(c.R); Y = (float)(c.G); Z = (float)(c.B); W = (float)(c.A); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(C4us c) { X = (float)(c.R); Y = (float)(c.G); Z = (float)(c.B); W = (float)(c.A); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(C4ui c) { X = (float)(c.R); Y = (float)(c.G); Z = (float)(c.B); W = (float)(c.A); } /// /// Creates a vector from a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(C4f c) { X = (c.R); Y = (c.G); Z = (c.B); W = (c.A); } /// /// Creates a vector from a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4f(C4d c) { X = (float)(c.R); Y = (float)(c.G); Z = (float)(c.B); W = (float)(c.A); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(V2i v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(V2ui v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(V2l v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(V2f v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(V2d v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(V3i v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(V3ui v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(V3l v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(V3f v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(V3d v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(V4i v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(V4ui v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(V4l v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(V4d v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToV2i() => (V2i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui ToV2ui() => (V2ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToV2l() => (V2l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2d ToV2d() => (V2d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3d() => (V3d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d ToV4d() => (V4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int[](V4f v) => new int[] { (int)v.X, (int)v.Y, (int)v.Z, (int)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(int[] v) => new V4f((float)v[0], (float)v[1], (float)v[2], (float)v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](V4f v) => new uint[] { (uint)v.X, (uint)v.Y, (uint)v.Z, (uint)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(uint[] v) => new V4f((float)v[0], (float)v[1], (float)v[2], (float)v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long[](V4f v) => new long[] { (long)v.X, (long)v.Y, (long)v.Z, (long)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(long[] v) => new V4f((float)v[0], (float)v[1], (float)v[2], (float)v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](V4f v) => new float[] { v.X, v.Y, v.Z, v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(float[] v) => new V4f(v[0], v[1], v[2], v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](V4f v) => new double[] { (double)v.X, (double)v.Y, (double)v.Z, (double)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(double[] v) => new V4f((float)v[0], (float)v[1], (float)v[2], (float)v[3]); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(C3b v) => new V4f(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(C3us v) => new V4f(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(C3ui v) => new V4f(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Converts the given color to a vector. /// W is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(C3f v) => new V4f(v); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f ToC3f() => (C3f)this; /// /// Converts the given color to a vector. /// W is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(C3d v) => new V4f(v); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d ToC3d() => (C3d)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(C4b v) => new V4f(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(C4us v) => new V4f(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(C4ui v) => new V4f(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(C4f v) => new V4f(v); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f ToC4f() => (C4f)this; /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4f(C4d v) => new V4f(v); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d ToC4d() => (C4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToFloorV4i() => new V4i((int)Fun.Floor(X), (int)Fun.Floor(Y), (int)Fun.Floor(Z), (int)Fun.Floor(W)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToCeilingV4i() => new V4i((int)Fun.Ceiling(X), (int)Fun.Ceiling(Y), (int)Fun.Ceiling(Z), (int)Fun.Ceiling(W)); /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3iInhomo() { var div = 1 / W; return new V3i(X * div, Y * div, Z * div); } /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3uiInhomo() { var div = 1 / W; return new V3ui(X * div, Y * div, Z * div); } /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3lInhomo() { var div = 1 / W; return new V3l(X * div, Y * div, Z * div); } /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3fInhomo() { var div = 1 / W; return new V3f(X * div, Y * div, Z * div); } /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3dInhomo() { var div = 1 / W; return new V3d(X * div, Y * div, Z * div); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i Copy(Func element_fun) => new V4i(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i Copy(Func element_index_fun) => new V4i(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(int[] array, int start) { array[start + 0] = (int)X; array[start + 1] = (int)Y; array[start + 2] = (int)Z; array[start + 3] = (int)W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui Copy(Func element_fun) => new V4ui(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui Copy(Func element_index_fun) => new V4ui(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(uint[] array, int start) { array[start + 0] = (uint)X; array[start + 1] = (uint)Y; array[start + 2] = (uint)Z; array[start + 3] = (uint)W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l Copy(Func element_fun) => new V4l(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l Copy(Func element_index_fun) => new V4l(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(long[] array, int start) { array[start + 0] = (long)X; array[start + 1] = (long)Y; array[start + 2] = (long)Z; array[start + 3] = (long)W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f Copy(Func element_fun) => new V4f(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f Copy(Func element_index_fun) => new V4f(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(float[] array, int start) { array[start + 0] = X; array[start + 1] = Y; array[start + 2] = Z; array[start + 3] = W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d Copy(Func element_fun) => new V4d(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d Copy(Func element_index_fun) => new V4d(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(double[] array, int start) { array[start + 0] = (double)X; array[start + 1] = (double)Y; array[start + 2] = (double)Z; array[start + 3] = (double)W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(X); array[start + 1] = element_fun(Y); array[start + 2] = element_fun(Z); array[start + 3] = element_fun(W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(X, 0); array[start + 1] = element_index_fun(Y, 1); array[start + 2] = element_index_fun(Z, 2); array[start + 3] = element_index_fun(W, 3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float[] ToArray() => new float[] { X, Y, Z, W }; #endregion #region Properties and Indexers /// /// Property for the field X. /// Useful when properties are required, but the field X is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public float P_X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value; } } /// /// Property for the field Y. /// Useful when properties are required, but the field Y is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public float P_Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Y = value; } } /// /// Property for the field Z. /// Useful when properties are required, but the field Z is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public float P_Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Z = value; } } /// /// Property for the field W. /// Useful when properties are required, but the field W is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public float P_W { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { W = value; } } /// /// Enumerates all elements of this vector. /// public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return X; yield return Y; yield return Z; yield return W; } } /// /// Gets or sets element with given index. /// public unsafe float this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (float* ptr = &X) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (float* ptr = &X) { ptr[index] = value; } } } /// /// Returns the index of the largest dimension of the vector. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X >= Y ? (X >= Z ? (X >= W ? 0 : 3) : (Z >= W ? 2 : 3)) : (Y >= Z ? (Y >= W ? 1 : 3) : (Z >= W ? 2 : 3)); } } /// /// Returns the index of the smallest dimension of the vector. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X <= Y ? (X <= Z ? (X <= W ? 0 : 3) : (Z <= W ? 2 : 3)) : (Y <= Z ? (Y <= W ? 1 : 3) : (Z <= W ? 2 : 3)); } } /// /// Returns the minimum element of the vector. /// public readonly float MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(X, Y, Z, W); } /// /// Returns the maximum element of the vector. /// public readonly float MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(X, Y, Z, W); } public readonly bool AnyFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsFinite(X) || Fun.IsFinite(Y) || Fun.IsFinite(Z) || Fun.IsFinite(W); } public readonly bool AllFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsFinite(X) && Fun.IsFinite(Y) && Fun.IsFinite(Z) && Fun.IsFinite(W); } public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNaN(X) || float.IsNaN(Y) || float.IsNaN(Z) || float.IsNaN(W); } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNaN(X) && float.IsNaN(Y) && float.IsNaN(Z) && float.IsNaN(W); } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsInfinity(X) || float.IsInfinity(Y) || float.IsInfinity(Z) || float.IsInfinity(W); } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsInfinity(X) && float.IsInfinity(Y) && float.IsInfinity(Z) && float.IsInfinity(W); } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsPositiveInfinity(X) || float.IsPositiveInfinity(Y) || float.IsPositiveInfinity(Z) || float.IsPositiveInfinity(W); } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsPositiveInfinity(X) && float.IsPositiveInfinity(Y) && float.IsPositiveInfinity(Z) && float.IsPositiveInfinity(W); } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNegativeInfinity(X) || float.IsNegativeInfinity(Y) || float.IsNegativeInfinity(Z) || float.IsNegativeInfinity(W); } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => float.IsNegativeInfinity(X) && float.IsNegativeInfinity(Y) && float.IsNegativeInfinity(Z) && float.IsNegativeInfinity(W); } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(X) || Fun.IsTiny(Y) || Fun.IsTiny(Z) || Fun.IsTiny(W); } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(X) && Fun.IsTiny(Y) && Fun.IsTiny(Z) && Fun.IsTiny(W); } /// /// Returns true if the absolute value of each component of the vector is smaller than Constant<float>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any component of the vector is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any component of the vector is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any component of the vector is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any component of the vector is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all components of the vector are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Constants /// /// Number of elements in this vector. /// public const int Dimension = 4; /// /// All elements zero. /// public static V4f Zero { get { return new V4f(0, 0, 0, 0); } } /// /// All elements half. /// public static V4f Half { get { return new V4f(0.5, 0.5, 0.5, 0.5); } } /// /// All elements one. /// public static V4f One { get { return new V4f(1, 1, 1, 1); } } /// /// All elements set to maximum possible value. /// public static V4f MaxValue { get { return new V4f(Constant.ParseableMaxValue, Constant.ParseableMaxValue, Constant.ParseableMaxValue, Constant.ParseableMaxValue); } } /// /// All elements set to minimum possible value. /// public static V4f MinValue { get { return new V4f(Constant.ParseableMinValue, Constant.ParseableMinValue, Constant.ParseableMinValue, Constant.ParseableMinValue); } } /// /// All elements set to negative infinity. /// public static V4f NegativeInfinity { get { return new V4f(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); } } /// /// All elements set to positive infinity. /// public static V4f PositiveInfinity { get { return new V4f(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); } } /// /// All elements set to NaN. /// public static V4f NaN { get { return new V4f(float.NaN, float.NaN, float.NaN, float.NaN); } } /// /// Normalized X-axis. /// public static V4f XAxis { get { return new V4f(1, 0, 0, 0); } } /// /// Normalized Y-axis. /// public static V4f YAxis { get { return new V4f(0, 1, 0, 0); } } /// /// Normalized Z-axis. /// public static V4f ZAxis { get { return new V4f(0, 0, 1, 0); } } /// /// Normalized W-axis. /// public static V4f WAxis { get { return new V4f(0, 0, 0, 1); } } /// /// An array of accessor functions for the coordinates of the vector. /// public static readonly Func[] SelectorArray = new Func[] { v => v.X, v => v.Y, v => v.Z, v => v.W }; /// /// Element getter function. /// public static readonly Func Getter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; case 3: return v.W; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref V4f v, int i, float s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; case 3: v.W = s; return; default: throw new IndexOutOfRangeException(); } }; /// /// Element getter function with long index. /// public static readonly Func LongGetter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; case 3: return v.W; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action with long index. /// public static readonly ActionRefValVal LongSetter = (ref V4f v, long i, float s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; case 3: v.W = s; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Static factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FromV4i(V4i v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FromV4ui(V4ui v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FromV4l(V4l v) => new V4f(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FromV4d(V4d v) => new V4f(v); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FromC3b(C3b c) => new V4f(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FromC3us(C3us c) => new V4f(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// W is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FromC3ui(C3ui c) => new V4f(c); /// /// Creates a vector from the given color. /// W is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FromC3f(C3f c) => new V4f(c); /// /// Creates a vector from the given color. /// W is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FromC3d(C3d c) => new V4f(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FromC4b(C4b c) => new V4f(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FromC4us(C4us c) => new V4f(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FromC4ui(C4ui c) => new V4f(c); /// /// Creates a vector from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FromC4f(C4f c) => new V4f(c); /// /// Creates a vector from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FromC4d(C4d c) => new V4f(c); #endregion #region Norms /// /// Returns the squared length of the vector. /// public readonly float LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X * X + Y * Y + Z * Z + W * W ; } } #if NETCOREAPP3_1_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] static float Length_Sse41(V4f vec) { unsafe { var x = (float*)&vec; var vv = Sse.LoadVector128(x); vv = Sse41.DotProduct(vv, vv, 0xF1); var l2 = vv.GetElement(0); return MathF.Sqrt(l2); } } #endif /// /// Returns the length of the vector. /// public readonly float Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { #if NETCOREAPP3_1_OR_GREATER if (Sse41.IsSupported) return Length_Sse41(this); #endif return Fun.Sqrt(X * X + Y * Y + Z * Z + W * W ); } } /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// public readonly float Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Abs(X) + Fun.Abs(Y) + Fun.Abs(Z) + Fun.Abs(W); } } /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// public readonly float Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z + W * W); } } /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// public readonly float NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z), Fun.Abs(W)); } } /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// public readonly float NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z), Fun.Abs(W)); } } /// /// Returns a normalized copy of this vector. /// public readonly V4f Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Length; if (s == 0) return V4f.Zero; s = 1 / s; return new V4f(X * s, Y * s, Z * s, W * s); } } /// /// Returns a copy of the vector with the maximum component length of /// exactly 1. This corresponds to mapping the vector onto an origin- /// centered cube with side length 2. /// public readonly V4f CubeMapped { get { var s = 1 / Fun.Max(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z), Fun.Abs(W)); return new V4f(X * s, Y * s, Z * s, W * s); } } #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Abs(V4f v) => v.Abs(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Floor(V4f v) => v.Floor(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Ceiling(V4f v) => v.Ceiling(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Round(V4f v) => v.Round(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Truncate(V4f v) => v.Truncate(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Acos(V4f v) => Fun.Acos(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Acoshb(V4f v) => Fun.Acosh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Cos(V4f v) => Fun.Cos(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Cosh(V4f v) => Fun.Cosh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Asin(V4f v) => Fun.Asin(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Asinhb(V4f v) => Fun.Asinh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Sin(V4f v) => Fun.Sin(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Sinh(V4f v) => Fun.Sinh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Atan(V4f v) => Fun.Atan(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Atanhb(V4f v) => Fun.Atanh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Atan2(V4f a, V4f b) => Fun.Atan2(a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Tan(V4f v) => Fun.Tan(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Tanh(V4f v) => Fun.Tanh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Sqrt(V4f v) => Fun.Sqrt(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f CubeRoot(V4f v) => Fun.Cbrt(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Exp(V4f v) => Fun.Exp(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Log(V4f v) => Fun.Log(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f LogBinary(V4f v) => Fun.Log2(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Log10(V4f v) => Fun.Log10(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f CopySgn(V4f value, V4f sign) => Fun.CopySign(value, sign); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f CopySgn(V4f value, float sign) => Fun.CopySign(value, sign); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f LinearInterp(float t, V4f a, V4f b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f LinearInterp(V4f t, V4f a, V4f b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Min(V4f v0, V4f v1) => Fun.Min(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Min(V4f v, float x) => Fun.Min(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Max(V4f v0, V4f v1) => Fun.Max(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Max(V4f v, float x) => Fun.Max(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Saturate(V4f v) => Fun.Saturate(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f DivideByInt(V4f v, int x) => v / x; #endregion #region Operations /// /// Sets the elements of a vector to the given int elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(int x, int y, int z, int w) { X = (float)x; Y = (float)y; Z = (float)z; W = (float)w; } /// /// Sets the elements of a vector to the given uint elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(uint x, uint y, uint z, uint w) { X = (float)x; Y = (float)y; Z = (float)z; W = (float)w; } /// /// Sets the elements of a vector to the given long elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(long x, long y, long z, long w) { X = (float)x; Y = (float)y; Z = (float)z; W = (float)w; } /// /// Sets the elements of a vector to the given float elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(float x, float y, float z, float w) { X = x; Y = y; Z = z; W = w; } /// /// Sets the elements of a vector to the given double elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(double x, double y, double z, double w) { X = (float)x; Y = (float)y; Z = (float)z; W = (float)w; } /// /// Returns a negated copy of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator -(V4f v) => new V4f(-v.X, -v.Y, -v.Z, -v.W); /// /// Gets a copy of this vector containing the reciprocal (1/x) of each element. /// public readonly V4f Reciprocal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V4f(1 / X, 1 / Y, 1 / Z, 1 / W); } } /// /// Returns the component-wise sum of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator +(V4f a, V4f b) => new V4f(a.X + b.X, a.Y + b.Y, a.Z + b.Z, a.W + b.W); /// /// Returns the component-wise sum of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator +(V4f v, float s) => new V4f(v.X + s, v.Y + s, v.Z + s, v.W + s); /// /// Returns the component-wise sum of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator +(float s, V4f v) => new V4f(s + v.X, s + v.Y, s + v.Z, s + v.W); /// /// Returns the component-wise difference of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator -(V4f a, V4f b) => new V4f(a.X - b.X, a.Y - b.Y, a.Z - b.Z, a.W - b.W); /// /// Returns the component-wise difference of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator -(V4f v, float s) => new V4f(v.X - s, v.Y - s, v.Z - s, v.W - s); /// /// Returns the component-wise difference of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator -(float s, V4f v) => new V4f(s - v.X, s - v.Y, s - v.Z, s - v.W); /// /// Returns the component-wise product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator *(V4f a, V4f b) => new V4f(a.X * b.X, a.Y * b.Y, a.Z * b.Z, a.W * b.W); /// /// Returns the component-wise product of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator *(V4f v, float s) => new V4f(v.X * s, v.Y * s, v.Z * s, v.W * s); /// /// Returns the component-wise product of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator *(float s, V4f v) => new V4f(s * v.X, s * v.Y, s * v.Z, s * v.W); /// /// Returns the component-wise fraction of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator /(V4f a, V4f b) => new V4f(a.X / b.X, a.Y / b.Y, a.Z / b.Z, a.W / b.W); /// /// Returns the component-wise fraction of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator /(V4f v, float s) => new V4f(v.X / s, v.Y / s, v.Z / s, v.W / s); /// /// Returns the component-wise fraction of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator /(float s, V4f v) => new V4f(s / v.X, s / v.Y, s / v.Z, s / v.W); /// /// Returns the component-wise remainder of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator %(V4f a, V4f b) => new V4f(a.X % b.X, a.Y % b.Y, a.Z % b.Z, a.W % b.W); /// /// Returns the component-wise remainder of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator %(V4f v, float s) => new V4f(v.X % s, v.Y % s, v.Z % s, v.W % s); /// /// Returns the component-wise remainder of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f operator %(float s, V4f v) => new V4f(s % v.X, s % v.Y, s % v.Z, s % v.W); /// Attention: NEVER implement operators <, <=, >=, >, /// since these are not defined in a Vector space. /// Use AllSmaller() and similar comparators! #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V4f a, V4f b) { return a.X == b.X && a.Y == b.Y && a.Z == b.Z && a.W == b.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V4f v, float s) { return v.X == s && v.Y == s && v.Z == s && v.W == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(float s, V4f v) { return s == v.X && s == v.Y && s == v.Z && s == v.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V4f a, V4f b) { return a.X != b.X || a.Y != b.Y || a.Z != b.Z || a.W != b.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V4f v, float s) { return v.X != s || v.Y != s || v.Z != s || v.W != s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(float s, V4f v) { return s != v.X || s != v.Y || s != v.Z || s != v.W; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(V4f other) { return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && W.Equals(other.W); } #endregion #region Overrides public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + X.ToString(format, fp) + between + Y.ToString(format, fp) + between + Z.ToString(format, fp) + between + W.ToString(format, fp) + end; } public override readonly int GetHashCode() { return HashCode.GetCombined(X, Y, Z, W); } public override readonly bool Equals(object other) => (other is V4f o) ? Equals(o) : false; public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + X.ToString(null, CultureInfo.InvariantCulture) + ", " + Y.ToString(null, CultureInfo.InvariantCulture) + ", " + Z.ToString(null, CultureInfo.InvariantCulture) + ", " + W.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Parsing public static V4f Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new V4f( float.Parse(x[0], CultureInfo.InvariantCulture), float.Parse(x[1], CultureInfo.InvariantCulture), float.Parse(x[2], CultureInfo.InvariantCulture), float.Parse(x[3], CultureInfo.InvariantCulture) ); } public static V4f Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, V4f.Setter); } public static V4f Parse(Text t, int bracketLevel) { return t.NestedBracketSplit(bracketLevel, Text.Parse, V4f.Setter); } #endregion #region Swizzle Methods [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f OX => new V2f(0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f OY => new V2f(0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f OZ => new V2f(0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f OW => new V2f(0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f IX => new V2f(1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f IY => new V2f(1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f IZ => new V2f(1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f IW => new V2f(1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f NX => new V2f(-1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f NY => new V2f(-1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f NZ => new V2f(-1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f NW => new V2f(-1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f XO => new V2f(X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f XI => new V2f(X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f XN => new V2f(X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f XX => new V2f(X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f XY { readonly get => new V2f(X, Y); set { X = value.X; Y = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f XZ { readonly get => new V2f(X, Z); set { X = value.X; Z = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f XW { readonly get => new V2f(X, W); set { X = value.X; W = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f YO => new V2f(Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f YI => new V2f(Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f YN => new V2f(Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f YX { readonly get => new V2f(Y, X); set { Y = value.X; X = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f YY => new V2f(Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f YZ { readonly get => new V2f(Y, Z); set { Y = value.X; Z = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f YW { readonly get => new V2f(Y, W); set { Y = value.X; W = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f ZO => new V2f(Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f ZI => new V2f(Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f ZN => new V2f(Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f ZX { readonly get => new V2f(Z, X); set { Z = value.X; X = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f ZY { readonly get => new V2f(Z, Y); set { Z = value.X; Y = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f ZZ => new V2f(Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f ZW { readonly get => new V2f(Z, W); set { Z = value.X; W = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f WO => new V2f(W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f WI => new V2f(W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f WN => new V2f(W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f WX { readonly get => new V2f(W, X); set { W = value.X; X = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f WY { readonly get => new V2f(W, Y); set { W = value.X; Y = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2f WZ { readonly get => new V2f(W, Z); set { W = value.X; Z = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2f WW => new V2f(W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OOX => new V3f(0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OOY => new V3f(0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OOZ => new V3f(0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OOW => new V3f(0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OIX => new V3f(0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OIY => new V3f(0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OIZ => new V3f(0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OIW => new V3f(0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ONX => new V3f(0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ONY => new V3f(0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ONZ => new V3f(0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ONW => new V3f(0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXO => new V3f(0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXI => new V3f(0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXN => new V3f(0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXX => new V3f(0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXY => new V3f(0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXZ => new V3f(0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OXW => new V3f(0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYO => new V3f(0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYI => new V3f(0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYN => new V3f(0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYX => new V3f(0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYY => new V3f(0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYZ => new V3f(0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OYW => new V3f(0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OZO => new V3f(0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OZI => new V3f(0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OZN => new V3f(0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OZX => new V3f(0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OZY => new V3f(0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OZZ => new V3f(0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OZW => new V3f(0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OWO => new V3f(0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OWI => new V3f(0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OWN => new V3f(0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OWX => new V3f(0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OWY => new V3f(0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OWZ => new V3f(0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f OWW => new V3f(0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IOX => new V3f(1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IOY => new V3f(1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IOZ => new V3f(1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IOW => new V3f(1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IIX => new V3f(1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IIY => new V3f(1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IIZ => new V3f(1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IIW => new V3f(1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PNX => new V3f(1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PNY => new V3f(1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PNZ => new V3f(1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PNW => new V3f(1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IXO => new V3f(1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IXI => new V3f(1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PXN => new V3f(1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IXX => new V3f(1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IXY => new V3f(1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IXZ => new V3f(1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IXW => new V3f(1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IYO => new V3f(1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IYI => new V3f(1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PYN => new V3f(1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IYX => new V3f(1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IYY => new V3f(1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IYZ => new V3f(1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IYW => new V3f(1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IZO => new V3f(1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IZI => new V3f(1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PZN => new V3f(1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IZX => new V3f(1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IZY => new V3f(1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IZZ => new V3f(1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IZW => new V3f(1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IWO => new V3f(1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IWI => new V3f(1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f PWN => new V3f(1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IWX => new V3f(1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IWY => new V3f(1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IWZ => new V3f(1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f IWW => new V3f(1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NOX => new V3f(-1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NOY => new V3f(-1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NOZ => new V3f(-1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NOW => new V3f(-1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NPX => new V3f(-1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NPY => new V3f(-1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NPZ => new V3f(-1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NPW => new V3f(-1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NNX => new V3f(-1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NNY => new V3f(-1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NNZ => new V3f(-1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NNW => new V3f(-1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXO => new V3f(-1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXP => new V3f(-1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXN => new V3f(-1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXX => new V3f(-1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXY => new V3f(-1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXZ => new V3f(-1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NXW => new V3f(-1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYO => new V3f(-1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYP => new V3f(-1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYN => new V3f(-1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYX => new V3f(-1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYY => new V3f(-1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYZ => new V3f(-1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NYW => new V3f(-1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NZO => new V3f(-1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NZP => new V3f(-1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NZN => new V3f(-1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NZX => new V3f(-1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NZY => new V3f(-1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NZZ => new V3f(-1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NZW => new V3f(-1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NWO => new V3f(-1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NWP => new V3f(-1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NWN => new V3f(-1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NWX => new V3f(-1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NWY => new V3f(-1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NWZ => new V3f(-1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f NWW => new V3f(-1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XOO => new V3f(X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XOI => new V3f(X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XON => new V3f(X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XOX => new V3f(X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XOY => new V3f(X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XOZ => new V3f(X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XOW => new V3f(X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XIO => new V3f(X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XII => new V3f(X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XPN => new V3f(X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XIX => new V3f(X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XIY => new V3f(X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XIZ => new V3f(X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XIW => new V3f(X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNO => new V3f(X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNP => new V3f(X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNN => new V3f(X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNX => new V3f(X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNY => new V3f(X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNZ => new V3f(X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XNW => new V3f(X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXO => new V3f(X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXI => new V3f(X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXN => new V3f(X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXX => new V3f(X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXY => new V3f(X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXZ => new V3f(X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XXW => new V3f(X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XYO => new V3f(X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XYI => new V3f(X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XYN => new V3f(X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XYX => new V3f(X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XYY => new V3f(X, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f XYZ { readonly get => new V3f(X, Y, Z); set { X = value.X; Y = value.Y; Z = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f XYW { readonly get => new V3f(X, Y, W); set { X = value.X; Y = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XZO => new V3f(X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XZI => new V3f(X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XZN => new V3f(X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XZX => new V3f(X, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f XZY { readonly get => new V3f(X, Z, Y); set { X = value.X; Z = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XZZ => new V3f(X, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f XZW { readonly get => new V3f(X, Z, W); set { X = value.X; Z = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XWO => new V3f(X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XWI => new V3f(X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XWN => new V3f(X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XWX => new V3f(X, W, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f XWY { readonly get => new V3f(X, W, Y); set { X = value.X; W = value.Y; Y = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f XWZ { readonly get => new V3f(X, W, Z); set { X = value.X; W = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f XWW => new V3f(X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YOO => new V3f(Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YOI => new V3f(Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YON => new V3f(Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YOX => new V3f(Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YOY => new V3f(Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YOZ => new V3f(Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YOW => new V3f(Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YIO => new V3f(Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YII => new V3f(Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YPN => new V3f(Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YIX => new V3f(Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YIY => new V3f(Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YIZ => new V3f(Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YIW => new V3f(Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNO => new V3f(Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNP => new V3f(Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNN => new V3f(Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNX => new V3f(Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNY => new V3f(Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNZ => new V3f(Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YNW => new V3f(Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YXO => new V3f(Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YXI => new V3f(Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YXN => new V3f(Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YXX => new V3f(Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YXY => new V3f(Y, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f YXZ { readonly get => new V3f(Y, X, Z); set { Y = value.X; X = value.Y; Z = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f YXW { readonly get => new V3f(Y, X, W); set { Y = value.X; X = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYO => new V3f(Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYI => new V3f(Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYN => new V3f(Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYX => new V3f(Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYY => new V3f(Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYZ => new V3f(Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YYW => new V3f(Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YZO => new V3f(Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YZI => new V3f(Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YZN => new V3f(Y, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f YZX { readonly get => new V3f(Y, Z, X); set { Y = value.X; Z = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YZY => new V3f(Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YZZ => new V3f(Y, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f YZW { readonly get => new V3f(Y, Z, W); set { Y = value.X; Z = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YWO => new V3f(Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YWI => new V3f(Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YWN => new V3f(Y, W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f YWX { readonly get => new V3f(Y, W, X); set { Y = value.X; W = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YWY => new V3f(Y, W, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f YWZ { readonly get => new V3f(Y, W, Z); set { Y = value.X; W = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f YWW => new V3f(Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZOO => new V3f(Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZOI => new V3f(Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZON => new V3f(Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZOX => new V3f(Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZOY => new V3f(Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZOZ => new V3f(Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZOW => new V3f(Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZIO => new V3f(Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZII => new V3f(Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZPN => new V3f(Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZIX => new V3f(Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZIY => new V3f(Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZIZ => new V3f(Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZIW => new V3f(Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZNO => new V3f(Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZNP => new V3f(Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZNN => new V3f(Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZNX => new V3f(Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZNY => new V3f(Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZNZ => new V3f(Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZNW => new V3f(Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZXO => new V3f(Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZXI => new V3f(Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZXN => new V3f(Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZXX => new V3f(Z, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f ZXY { readonly get => new V3f(Z, X, Y); set { Z = value.X; X = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZXZ => new V3f(Z, X, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f ZXW { readonly get => new V3f(Z, X, W); set { Z = value.X; X = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZYO => new V3f(Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZYI => new V3f(Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZYN => new V3f(Z, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f ZYX { readonly get => new V3f(Z, Y, X); set { Z = value.X; Y = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZYY => new V3f(Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZYZ => new V3f(Z, Y, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f ZYW { readonly get => new V3f(Z, Y, W); set { Z = value.X; Y = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZZO => new V3f(Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZZI => new V3f(Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZZN => new V3f(Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZZX => new V3f(Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZZY => new V3f(Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZZZ => new V3f(Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZZW => new V3f(Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZWO => new V3f(Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZWI => new V3f(Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZWN => new V3f(Z, W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f ZWX { readonly get => new V3f(Z, W, X); set { Z = value.X; W = value.Y; X = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f ZWY { readonly get => new V3f(Z, W, Y); set { Z = value.X; W = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZWZ => new V3f(Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f ZWW => new V3f(Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WOO => new V3f(W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WOI => new V3f(W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WON => new V3f(W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WOX => new V3f(W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WOY => new V3f(W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WOZ => new V3f(W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WOW => new V3f(W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WIO => new V3f(W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WII => new V3f(W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WPN => new V3f(W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WIX => new V3f(W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WIY => new V3f(W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WIZ => new V3f(W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WIW => new V3f(W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WNO => new V3f(W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WNP => new V3f(W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WNN => new V3f(W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WNX => new V3f(W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WNY => new V3f(W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WNZ => new V3f(W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WNW => new V3f(W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WXO => new V3f(W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WXI => new V3f(W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WXN => new V3f(W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WXX => new V3f(W, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f WXY { readonly get => new V3f(W, X, Y); set { W = value.X; X = value.Y; Y = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f WXZ { readonly get => new V3f(W, X, Z); set { W = value.X; X = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WXW => new V3f(W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WYO => new V3f(W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WYI => new V3f(W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WYN => new V3f(W, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f WYX { readonly get => new V3f(W, Y, X); set { W = value.X; Y = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WYY => new V3f(W, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f WYZ { readonly get => new V3f(W, Y, Z); set { W = value.X; Y = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WYW => new V3f(W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WZO => new V3f(W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WZI => new V3f(W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WZN => new V3f(W, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f WZX { readonly get => new V3f(W, Z, X); set { W = value.X; Z = value.Y; X = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3f WZY { readonly get => new V3f(W, Z, Y); set { W = value.X; Z = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WZZ => new V3f(W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WZW => new V3f(W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WWO => new V3f(W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WWI => new V3f(W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WWN => new V3f(W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WWX => new V3f(W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WWY => new V3f(W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WWZ => new V3f(W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3f WWW => new V3f(W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OOOO => new V4f(0, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OOOI => new V4f(0, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OOON => new V4f(0, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOOX => new V4f(0, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOOY => new V4f(0, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOOZ => new V4f(0, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOOW => new V4f(0, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OOIO => new V4f(0, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OOII => new V4f(0, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OOPN => new V4f(0, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOIX => new V4f(0, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOIY => new V4f(0, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOIZ => new V4f(0, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOIW => new V4f(0, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OONO => new V4f(0, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OONP => new V4f(0, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OONN => new V4f(0, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OONX => new V4f(0, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OONY => new V4f(0, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OONZ => new V4f(0, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OONW => new V4f(0, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXO => new V4f(0, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXI => new V4f(0, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXN => new V4f(0, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXX => new V4f(0, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXY => new V4f(0, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXZ => new V4f(0, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOXW => new V4f(0, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYO => new V4f(0, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYI => new V4f(0, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYN => new V4f(0, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYX => new V4f(0, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYY => new V4f(0, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYZ => new V4f(0, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOYW => new V4f(0, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOZO => new V4f(0, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOZI => new V4f(0, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOZN => new V4f(0, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOZX => new V4f(0, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOZY => new V4f(0, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOZZ => new V4f(0, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOZW => new V4f(0, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOWO => new V4f(0, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOWI => new V4f(0, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOWN => new V4f(0, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOWX => new V4f(0, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOWY => new V4f(0, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOWZ => new V4f(0, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OOWW => new V4f(0, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OIOO => new V4f(0, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OIOI => new V4f(0, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OPON => new V4f(0, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIOX => new V4f(0, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIOY => new V4f(0, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIOZ => new V4f(0, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIOW => new V4f(0, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OIIO => new V4f(0, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OIII => new V4f(0, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OPPN => new V4f(0, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIIX => new V4f(0, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIIY => new V4f(0, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIIZ => new V4f(0, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIIW => new V4f(0, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OPNO => new V4f(0, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OPNP => new V4f(0, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f OPNN => new V4f(0, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPNX => new V4f(0, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPNY => new V4f(0, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPNZ => new V4f(0, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPNW => new V4f(0, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIXO => new V4f(0, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIXI => new V4f(0, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPXN => new V4f(0, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIXX => new V4f(0, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIXY => new V4f(0, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIXZ => new V4f(0, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIXW => new V4f(0, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIYO => new V4f(0, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIYI => new V4f(0, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPYN => new V4f(0, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIYX => new V4f(0, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIYY => new V4f(0, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIYZ => new V4f(0, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIYW => new V4f(0, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIZO => new V4f(0, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIZI => new V4f(0, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPZN => new V4f(0, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIZX => new V4f(0, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIZY => new V4f(0, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIZZ => new V4f(0, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIZW => new V4f(0, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIWO => new V4f(0, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIWI => new V4f(0, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OPWN => new V4f(0, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIWX => new V4f(0, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIWY => new V4f(0, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIWZ => new V4f(0, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OIWW => new V4f(0, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f ONOO => new V4f(0, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f ONOP => new V4f(0, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f ONON => new V4f(0, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONOX => new V4f(0, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONOY => new V4f(0, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONOZ => new V4f(0, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONOW => new V4f(0, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f ONPO => new V4f(0, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f ONPP => new V4f(0, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f ONPN => new V4f(0, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONPX => new V4f(0, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONPY => new V4f(0, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONPZ => new V4f(0, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONPW => new V4f(0, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f ONNO => new V4f(0, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f ONNP => new V4f(0, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f ONNN => new V4f(0, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONNX => new V4f(0, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONNY => new V4f(0, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONNZ => new V4f(0, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONNW => new V4f(0, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXO => new V4f(0, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXP => new V4f(0, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXN => new V4f(0, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXX => new V4f(0, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXY => new V4f(0, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXZ => new V4f(0, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONXW => new V4f(0, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYO => new V4f(0, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYP => new V4f(0, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYN => new V4f(0, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYX => new V4f(0, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYY => new V4f(0, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYZ => new V4f(0, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONYW => new V4f(0, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONZO => new V4f(0, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONZP => new V4f(0, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONZN => new V4f(0, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONZX => new V4f(0, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONZY => new V4f(0, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONZZ => new V4f(0, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONZW => new V4f(0, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONWO => new V4f(0, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONWP => new V4f(0, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONWN => new V4f(0, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONWX => new V4f(0, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONWY => new V4f(0, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONWZ => new V4f(0, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ONWW => new V4f(0, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXOO => new V4f(0, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXOI => new V4f(0, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXON => new V4f(0, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXOX => new V4f(0, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXOY => new V4f(0, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXOZ => new V4f(0, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXOW => new V4f(0, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXIO => new V4f(0, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXII => new V4f(0, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXPN => new V4f(0, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXIX => new V4f(0, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXIY => new V4f(0, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXIZ => new V4f(0, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXIW => new V4f(0, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNO => new V4f(0, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNP => new V4f(0, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNN => new V4f(0, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNX => new V4f(0, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNY => new V4f(0, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNZ => new V4f(0, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXNW => new V4f(0, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXO => new V4f(0, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXI => new V4f(0, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXN => new V4f(0, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXX => new V4f(0, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXY => new V4f(0, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXZ => new V4f(0, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXXW => new V4f(0, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYO => new V4f(0, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYI => new V4f(0, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYN => new V4f(0, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYX => new V4f(0, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYY => new V4f(0, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYZ => new V4f(0, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXYW => new V4f(0, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXZO => new V4f(0, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXZI => new V4f(0, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXZN => new V4f(0, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXZX => new V4f(0, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXZY => new V4f(0, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXZZ => new V4f(0, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXZW => new V4f(0, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXWO => new V4f(0, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXWI => new V4f(0, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXWN => new V4f(0, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXWX => new V4f(0, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXWY => new V4f(0, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXWZ => new V4f(0, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OXWW => new V4f(0, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYOO => new V4f(0, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYOI => new V4f(0, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYON => new V4f(0, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYOX => new V4f(0, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYOY => new V4f(0, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYOZ => new V4f(0, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYOW => new V4f(0, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYIO => new V4f(0, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYII => new V4f(0, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYPN => new V4f(0, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYIX => new V4f(0, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYIY => new V4f(0, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYIZ => new V4f(0, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYIW => new V4f(0, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNO => new V4f(0, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNP => new V4f(0, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNN => new V4f(0, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNX => new V4f(0, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNY => new V4f(0, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNZ => new V4f(0, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYNW => new V4f(0, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXO => new V4f(0, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXI => new V4f(0, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXN => new V4f(0, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXX => new V4f(0, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXY => new V4f(0, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXZ => new V4f(0, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYXW => new V4f(0, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYO => new V4f(0, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYI => new V4f(0, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYN => new V4f(0, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYX => new V4f(0, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYY => new V4f(0, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYZ => new V4f(0, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYYW => new V4f(0, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYZO => new V4f(0, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYZI => new V4f(0, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYZN => new V4f(0, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYZX => new V4f(0, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYZY => new V4f(0, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYZZ => new V4f(0, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYZW => new V4f(0, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYWO => new V4f(0, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYWI => new V4f(0, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYWN => new V4f(0, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYWX => new V4f(0, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYWY => new V4f(0, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYWZ => new V4f(0, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OYWW => new V4f(0, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZOO => new V4f(0, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZOI => new V4f(0, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZON => new V4f(0, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZOX => new V4f(0, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZOY => new V4f(0, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZOZ => new V4f(0, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZOW => new V4f(0, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZIO => new V4f(0, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZII => new V4f(0, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZPN => new V4f(0, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZIX => new V4f(0, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZIY => new V4f(0, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZIZ => new V4f(0, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZIW => new V4f(0, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZNO => new V4f(0, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZNP => new V4f(0, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZNN => new V4f(0, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZNX => new V4f(0, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZNY => new V4f(0, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZNZ => new V4f(0, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZNW => new V4f(0, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZXO => new V4f(0, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZXI => new V4f(0, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZXN => new V4f(0, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZXX => new V4f(0, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZXY => new V4f(0, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZXZ => new V4f(0, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZXW => new V4f(0, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZYO => new V4f(0, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZYI => new V4f(0, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZYN => new V4f(0, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZYX => new V4f(0, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZYY => new V4f(0, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZYZ => new V4f(0, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZYW => new V4f(0, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZZO => new V4f(0, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZZI => new V4f(0, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZZN => new V4f(0, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZZX => new V4f(0, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZZY => new V4f(0, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZZZ => new V4f(0, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZZW => new V4f(0, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZWO => new V4f(0, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZWI => new V4f(0, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZWN => new V4f(0, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZWX => new V4f(0, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZWY => new V4f(0, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZWZ => new V4f(0, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OZWW => new V4f(0, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWOO => new V4f(0, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWOI => new V4f(0, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWON => new V4f(0, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWOX => new V4f(0, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWOY => new V4f(0, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWOZ => new V4f(0, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWOW => new V4f(0, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWIO => new V4f(0, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWII => new V4f(0, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWPN => new V4f(0, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWIX => new V4f(0, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWIY => new V4f(0, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWIZ => new V4f(0, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWIW => new V4f(0, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWNO => new V4f(0, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWNP => new V4f(0, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWNN => new V4f(0, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWNX => new V4f(0, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWNY => new V4f(0, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWNZ => new V4f(0, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWNW => new V4f(0, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWXO => new V4f(0, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWXI => new V4f(0, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWXN => new V4f(0, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWXX => new V4f(0, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWXY => new V4f(0, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWXZ => new V4f(0, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWXW => new V4f(0, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWYO => new V4f(0, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWYI => new V4f(0, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWYN => new V4f(0, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWYX => new V4f(0, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWYY => new V4f(0, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWYZ => new V4f(0, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWYW => new V4f(0, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWZO => new V4f(0, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWZI => new V4f(0, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWZN => new V4f(0, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWZX => new V4f(0, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWZY => new V4f(0, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWZZ => new V4f(0, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWZW => new V4f(0, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWWO => new V4f(0, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWWI => new V4f(0, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWWN => new V4f(0, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWWX => new V4f(0, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWWY => new V4f(0, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWWZ => new V4f(0, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f OWWW => new V4f(0, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f IOOO => new V4f(1, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f IOOI => new V4f(1, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f POON => new V4f(1, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOOX => new V4f(1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOOY => new V4f(1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOOZ => new V4f(1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOOW => new V4f(1, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f IOIO => new V4f(1, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f IOII => new V4f(1, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f POPN => new V4f(1, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOIX => new V4f(1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOIY => new V4f(1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOIZ => new V4f(1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOIW => new V4f(1, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PONO => new V4f(1, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PONP => new V4f(1, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PONN => new V4f(1, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PONX => new V4f(1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PONY => new V4f(1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PONZ => new V4f(1, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PONW => new V4f(1, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOXO => new V4f(1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOXI => new V4f(1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f POXN => new V4f(1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOXX => new V4f(1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOXY => new V4f(1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOXZ => new V4f(1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOXW => new V4f(1, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOYO => new V4f(1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOYI => new V4f(1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f POYN => new V4f(1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOYX => new V4f(1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOYY => new V4f(1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOYZ => new V4f(1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOYW => new V4f(1, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOZO => new V4f(1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOZI => new V4f(1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f POZN => new V4f(1, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOZX => new V4f(1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOZY => new V4f(1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOZZ => new V4f(1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOZW => new V4f(1, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOWO => new V4f(1, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOWI => new V4f(1, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f POWN => new V4f(1, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOWX => new V4f(1, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOWY => new V4f(1, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOWZ => new V4f(1, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IOWW => new V4f(1, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f IIOO => new V4f(1, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f IIOI => new V4f(1, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PPON => new V4f(1, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIOX => new V4f(1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIOY => new V4f(1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIOZ => new V4f(1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIOW => new V4f(1, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f IIIO => new V4f(1, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f IIII => new V4f(1, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PPPN => new V4f(1, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIIX => new V4f(1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIIY => new V4f(1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIIZ => new V4f(1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIIW => new V4f(1, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PPNO => new V4f(1, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PPNP => new V4f(1, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PPNN => new V4f(1, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPNX => new V4f(1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPNY => new V4f(1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPNZ => new V4f(1, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPNW => new V4f(1, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIXO => new V4f(1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIXI => new V4f(1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPXN => new V4f(1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIXX => new V4f(1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIXY => new V4f(1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIXZ => new V4f(1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIXW => new V4f(1, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIYO => new V4f(1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIYI => new V4f(1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPYN => new V4f(1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIYX => new V4f(1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIYY => new V4f(1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIYZ => new V4f(1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIYW => new V4f(1, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIZO => new V4f(1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIZI => new V4f(1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPZN => new V4f(1, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIZX => new V4f(1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIZY => new V4f(1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIZZ => new V4f(1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIZW => new V4f(1, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIWO => new V4f(1, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIWI => new V4f(1, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PPWN => new V4f(1, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIWX => new V4f(1, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIWY => new V4f(1, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIWZ => new V4f(1, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IIWW => new V4f(1, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PNOO => new V4f(1, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PNOP => new V4f(1, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PNON => new V4f(1, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNOX => new V4f(1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNOY => new V4f(1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNOZ => new V4f(1, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNOW => new V4f(1, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PNPO => new V4f(1, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PNPP => new V4f(1, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PNPN => new V4f(1, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNPX => new V4f(1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNPY => new V4f(1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNPZ => new V4f(1, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNPW => new V4f(1, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PNNO => new V4f(1, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PNNP => new V4f(1, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f PNNN => new V4f(1, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNNX => new V4f(1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNNY => new V4f(1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNNZ => new V4f(1, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNNW => new V4f(1, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXO => new V4f(1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXP => new V4f(1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXN => new V4f(1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXX => new V4f(1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXY => new V4f(1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXZ => new V4f(1, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNXW => new V4f(1, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYO => new V4f(1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYP => new V4f(1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYN => new V4f(1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYX => new V4f(1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYY => new V4f(1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYZ => new V4f(1, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNYW => new V4f(1, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNZO => new V4f(1, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNZP => new V4f(1, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNZN => new V4f(1, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNZX => new V4f(1, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNZY => new V4f(1, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNZZ => new V4f(1, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNZW => new V4f(1, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNWO => new V4f(1, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNWP => new V4f(1, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNWN => new V4f(1, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNWX => new V4f(1, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNWY => new V4f(1, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNWZ => new V4f(1, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PNWW => new V4f(1, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXOO => new V4f(1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXOI => new V4f(1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXON => new V4f(1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXOX => new V4f(1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXOY => new V4f(1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXOZ => new V4f(1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXOW => new V4f(1, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXIO => new V4f(1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXII => new V4f(1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXPN => new V4f(1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXIX => new V4f(1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXIY => new V4f(1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXIZ => new V4f(1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXIW => new V4f(1, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNO => new V4f(1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNP => new V4f(1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNN => new V4f(1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNX => new V4f(1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNY => new V4f(1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNZ => new V4f(1, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXNW => new V4f(1, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXXO => new V4f(1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXXI => new V4f(1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXXN => new V4f(1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXXX => new V4f(1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXXY => new V4f(1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXXZ => new V4f(1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXXW => new V4f(1, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXYO => new V4f(1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXYI => new V4f(1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXYN => new V4f(1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXYX => new V4f(1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXYY => new V4f(1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXYZ => new V4f(1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXYW => new V4f(1, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXZO => new V4f(1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXZI => new V4f(1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXZN => new V4f(1, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXZX => new V4f(1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXZY => new V4f(1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXZZ => new V4f(1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXZW => new V4f(1, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXWO => new V4f(1, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXWI => new V4f(1, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PXWN => new V4f(1, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXWX => new V4f(1, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXWY => new V4f(1, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXWZ => new V4f(1, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IXWW => new V4f(1, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYOO => new V4f(1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYOI => new V4f(1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYON => new V4f(1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYOX => new V4f(1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYOY => new V4f(1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYOZ => new V4f(1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYOW => new V4f(1, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYIO => new V4f(1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYII => new V4f(1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYPN => new V4f(1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYIX => new V4f(1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYIY => new V4f(1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYIZ => new V4f(1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYIW => new V4f(1, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNO => new V4f(1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNP => new V4f(1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNN => new V4f(1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNX => new V4f(1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNY => new V4f(1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNZ => new V4f(1, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYNW => new V4f(1, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYXO => new V4f(1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYXI => new V4f(1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYXN => new V4f(1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYXX => new V4f(1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYXY => new V4f(1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYXZ => new V4f(1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYXW => new V4f(1, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYYO => new V4f(1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYYI => new V4f(1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYYN => new V4f(1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYYX => new V4f(1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYYY => new V4f(1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYYZ => new V4f(1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYYW => new V4f(1, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYZO => new V4f(1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYZI => new V4f(1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYZN => new V4f(1, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYZX => new V4f(1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYZY => new V4f(1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYZZ => new V4f(1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYZW => new V4f(1, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYWO => new V4f(1, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYWI => new V4f(1, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PYWN => new V4f(1, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYWX => new V4f(1, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYWY => new V4f(1, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYWZ => new V4f(1, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IYWW => new V4f(1, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZOO => new V4f(1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZOI => new V4f(1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZON => new V4f(1, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZOX => new V4f(1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZOY => new V4f(1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZOZ => new V4f(1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZOW => new V4f(1, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZIO => new V4f(1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZII => new V4f(1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZPN => new V4f(1, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZIX => new V4f(1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZIY => new V4f(1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZIZ => new V4f(1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZIW => new V4f(1, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZNO => new V4f(1, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZNP => new V4f(1, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZNN => new V4f(1, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZNX => new V4f(1, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZNY => new V4f(1, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZNZ => new V4f(1, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZNW => new V4f(1, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZXO => new V4f(1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZXI => new V4f(1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZXN => new V4f(1, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZXX => new V4f(1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZXY => new V4f(1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZXZ => new V4f(1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZXW => new V4f(1, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZYO => new V4f(1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZYI => new V4f(1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZYN => new V4f(1, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZYX => new V4f(1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZYY => new V4f(1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZYZ => new V4f(1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZYW => new V4f(1, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZZO => new V4f(1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZZI => new V4f(1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZZN => new V4f(1, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZZX => new V4f(1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZZY => new V4f(1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZZZ => new V4f(1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZZW => new V4f(1, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZWO => new V4f(1, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZWI => new V4f(1, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PZWN => new V4f(1, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZWX => new V4f(1, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZWY => new V4f(1, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZWZ => new V4f(1, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IZWW => new V4f(1, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWOO => new V4f(1, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWOI => new V4f(1, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PWON => new V4f(1, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWOX => new V4f(1, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWOY => new V4f(1, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWOZ => new V4f(1, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWOW => new V4f(1, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWIO => new V4f(1, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWII => new V4f(1, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PWPN => new V4f(1, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWIX => new V4f(1, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWIY => new V4f(1, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWIZ => new V4f(1, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWIW => new V4f(1, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PWNO => new V4f(1, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PWNP => new V4f(1, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PWNN => new V4f(1, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PWNX => new V4f(1, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PWNY => new V4f(1, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PWNZ => new V4f(1, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PWNW => new V4f(1, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWXO => new V4f(1, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWXI => new V4f(1, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PWXN => new V4f(1, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWXX => new V4f(1, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWXY => new V4f(1, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWXZ => new V4f(1, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWXW => new V4f(1, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWYO => new V4f(1, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWYI => new V4f(1, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PWYN => new V4f(1, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWYX => new V4f(1, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWYY => new V4f(1, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWYZ => new V4f(1, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWYW => new V4f(1, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWZO => new V4f(1, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWZI => new V4f(1, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PWZN => new V4f(1, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWZX => new V4f(1, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWZY => new V4f(1, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWZZ => new V4f(1, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWZW => new V4f(1, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWWO => new V4f(1, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWWI => new V4f(1, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f PWWN => new V4f(1, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWWX => new V4f(1, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWWY => new V4f(1, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWWZ => new V4f(1, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f IWWW => new V4f(1, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NOOO => new V4f(-1, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NOOP => new V4f(-1, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NOON => new V4f(-1, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOOX => new V4f(-1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOOY => new V4f(-1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOOZ => new V4f(-1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOOW => new V4f(-1, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NOPO => new V4f(-1, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NOPP => new V4f(-1, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NOPN => new V4f(-1, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOPX => new V4f(-1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOPY => new V4f(-1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOPZ => new V4f(-1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOPW => new V4f(-1, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NONO => new V4f(-1, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NONP => new V4f(-1, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NONN => new V4f(-1, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NONX => new V4f(-1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NONY => new V4f(-1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NONZ => new V4f(-1, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NONW => new V4f(-1, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXO => new V4f(-1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXP => new V4f(-1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXN => new V4f(-1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXX => new V4f(-1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXY => new V4f(-1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXZ => new V4f(-1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOXW => new V4f(-1, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYO => new V4f(-1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYP => new V4f(-1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYN => new V4f(-1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYX => new V4f(-1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYY => new V4f(-1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYZ => new V4f(-1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOYW => new V4f(-1, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOZO => new V4f(-1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOZP => new V4f(-1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOZN => new V4f(-1, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOZX => new V4f(-1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOZY => new V4f(-1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOZZ => new V4f(-1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOZW => new V4f(-1, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOWO => new V4f(-1, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOWP => new V4f(-1, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOWN => new V4f(-1, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOWX => new V4f(-1, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOWY => new V4f(-1, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOWZ => new V4f(-1, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NOWW => new V4f(-1, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NPOO => new V4f(-1, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NPOP => new V4f(-1, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NPON => new V4f(-1, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPOX => new V4f(-1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPOY => new V4f(-1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPOZ => new V4f(-1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPOW => new V4f(-1, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NPPO => new V4f(-1, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NPPP => new V4f(-1, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NPPN => new V4f(-1, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPPX => new V4f(-1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPPY => new V4f(-1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPPZ => new V4f(-1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPPW => new V4f(-1, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NPNO => new V4f(-1, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NPNP => new V4f(-1, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NPNN => new V4f(-1, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPNX => new V4f(-1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPNY => new V4f(-1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPNZ => new V4f(-1, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPNW => new V4f(-1, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXO => new V4f(-1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXP => new V4f(-1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXN => new V4f(-1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXX => new V4f(-1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXY => new V4f(-1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXZ => new V4f(-1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPXW => new V4f(-1, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYO => new V4f(-1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYP => new V4f(-1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYN => new V4f(-1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYX => new V4f(-1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYY => new V4f(-1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYZ => new V4f(-1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPYW => new V4f(-1, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPZO => new V4f(-1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPZP => new V4f(-1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPZN => new V4f(-1, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPZX => new V4f(-1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPZY => new V4f(-1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPZZ => new V4f(-1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPZW => new V4f(-1, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPWO => new V4f(-1, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPWP => new V4f(-1, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPWN => new V4f(-1, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPWX => new V4f(-1, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPWY => new V4f(-1, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPWZ => new V4f(-1, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NPWW => new V4f(-1, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NNOO => new V4f(-1, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NNOP => new V4f(-1, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NNON => new V4f(-1, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNOX => new V4f(-1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNOY => new V4f(-1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNOZ => new V4f(-1, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNOW => new V4f(-1, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NNPO => new V4f(-1, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NNPP => new V4f(-1, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NNPN => new V4f(-1, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNPX => new V4f(-1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNPY => new V4f(-1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNPZ => new V4f(-1, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNPW => new V4f(-1, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NNNO => new V4f(-1, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NNNP => new V4f(-1, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4f NNNN => new V4f(-1, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNNX => new V4f(-1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNNY => new V4f(-1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNNZ => new V4f(-1, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNNW => new V4f(-1, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXO => new V4f(-1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXP => new V4f(-1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXN => new V4f(-1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXX => new V4f(-1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXY => new V4f(-1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXZ => new V4f(-1, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNXW => new V4f(-1, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYO => new V4f(-1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYP => new V4f(-1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYN => new V4f(-1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYX => new V4f(-1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYY => new V4f(-1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYZ => new V4f(-1, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNYW => new V4f(-1, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNZO => new V4f(-1, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNZP => new V4f(-1, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNZN => new V4f(-1, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNZX => new V4f(-1, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNZY => new V4f(-1, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNZZ => new V4f(-1, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNZW => new V4f(-1, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNWO => new V4f(-1, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNWP => new V4f(-1, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNWN => new V4f(-1, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNWX => new V4f(-1, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNWY => new V4f(-1, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNWZ => new V4f(-1, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NNWW => new V4f(-1, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXOO => new V4f(-1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXOP => new V4f(-1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXON => new V4f(-1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXOX => new V4f(-1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXOY => new V4f(-1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXOZ => new V4f(-1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXOW => new V4f(-1, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPO => new V4f(-1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPP => new V4f(-1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPN => new V4f(-1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPX => new V4f(-1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPY => new V4f(-1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPZ => new V4f(-1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXPW => new V4f(-1, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNO => new V4f(-1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNP => new V4f(-1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNN => new V4f(-1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNX => new V4f(-1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNY => new V4f(-1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNZ => new V4f(-1, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXNW => new V4f(-1, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXO => new V4f(-1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXP => new V4f(-1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXN => new V4f(-1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXX => new V4f(-1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXY => new V4f(-1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXZ => new V4f(-1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXXW => new V4f(-1, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYO => new V4f(-1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYP => new V4f(-1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYN => new V4f(-1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYX => new V4f(-1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYY => new V4f(-1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYZ => new V4f(-1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXYW => new V4f(-1, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXZO => new V4f(-1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXZP => new V4f(-1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXZN => new V4f(-1, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXZX => new V4f(-1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXZY => new V4f(-1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXZZ => new V4f(-1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXZW => new V4f(-1, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXWO => new V4f(-1, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXWP => new V4f(-1, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXWN => new V4f(-1, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXWX => new V4f(-1, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXWY => new V4f(-1, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXWZ => new V4f(-1, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NXWW => new V4f(-1, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYOO => new V4f(-1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYOP => new V4f(-1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYON => new V4f(-1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYOX => new V4f(-1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYOY => new V4f(-1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYOZ => new V4f(-1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYOW => new V4f(-1, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPO => new V4f(-1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPP => new V4f(-1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPN => new V4f(-1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPX => new V4f(-1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPY => new V4f(-1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPZ => new V4f(-1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYPW => new V4f(-1, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNO => new V4f(-1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNP => new V4f(-1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNN => new V4f(-1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNX => new V4f(-1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNY => new V4f(-1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNZ => new V4f(-1, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYNW => new V4f(-1, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXO => new V4f(-1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXP => new V4f(-1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXN => new V4f(-1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXX => new V4f(-1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXY => new V4f(-1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXZ => new V4f(-1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYXW => new V4f(-1, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYO => new V4f(-1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYP => new V4f(-1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYN => new V4f(-1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYX => new V4f(-1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYY => new V4f(-1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYZ => new V4f(-1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYYW => new V4f(-1, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYZO => new V4f(-1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYZP => new V4f(-1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYZN => new V4f(-1, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYZX => new V4f(-1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYZY => new V4f(-1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYZZ => new V4f(-1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYZW => new V4f(-1, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYWO => new V4f(-1, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYWP => new V4f(-1, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYWN => new V4f(-1, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYWX => new V4f(-1, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYWY => new V4f(-1, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYWZ => new V4f(-1, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NYWW => new V4f(-1, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZOO => new V4f(-1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZOP => new V4f(-1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZON => new V4f(-1, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZOX => new V4f(-1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZOY => new V4f(-1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZOZ => new V4f(-1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZOW => new V4f(-1, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZPO => new V4f(-1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZPP => new V4f(-1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZPN => new V4f(-1, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZPX => new V4f(-1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZPY => new V4f(-1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZPZ => new V4f(-1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZPW => new V4f(-1, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZNO => new V4f(-1, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZNP => new V4f(-1, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZNN => new V4f(-1, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZNX => new V4f(-1, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZNY => new V4f(-1, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZNZ => new V4f(-1, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZNW => new V4f(-1, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZXO => new V4f(-1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZXP => new V4f(-1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZXN => new V4f(-1, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZXX => new V4f(-1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZXY => new V4f(-1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZXZ => new V4f(-1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZXW => new V4f(-1, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZYO => new V4f(-1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZYP => new V4f(-1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZYN => new V4f(-1, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZYX => new V4f(-1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZYY => new V4f(-1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZYZ => new V4f(-1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZYW => new V4f(-1, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZZO => new V4f(-1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZZP => new V4f(-1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZZN => new V4f(-1, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZZX => new V4f(-1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZZY => new V4f(-1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZZZ => new V4f(-1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZZW => new V4f(-1, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZWO => new V4f(-1, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZWP => new V4f(-1, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZWN => new V4f(-1, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZWX => new V4f(-1, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZWY => new V4f(-1, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZWZ => new V4f(-1, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NZWW => new V4f(-1, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWOO => new V4f(-1, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWOP => new V4f(-1, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWON => new V4f(-1, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWOX => new V4f(-1, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWOY => new V4f(-1, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWOZ => new V4f(-1, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWOW => new V4f(-1, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWPO => new V4f(-1, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWPP => new V4f(-1, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWPN => new V4f(-1, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWPX => new V4f(-1, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWPY => new V4f(-1, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWPZ => new V4f(-1, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWPW => new V4f(-1, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWNO => new V4f(-1, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWNP => new V4f(-1, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWNN => new V4f(-1, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWNX => new V4f(-1, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWNY => new V4f(-1, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWNZ => new V4f(-1, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWNW => new V4f(-1, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWXO => new V4f(-1, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWXP => new V4f(-1, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWXN => new V4f(-1, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWXX => new V4f(-1, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWXY => new V4f(-1, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWXZ => new V4f(-1, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWXW => new V4f(-1, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWYO => new V4f(-1, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWYP => new V4f(-1, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWYN => new V4f(-1, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWYX => new V4f(-1, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWYY => new V4f(-1, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWYZ => new V4f(-1, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWYW => new V4f(-1, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWZO => new V4f(-1, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWZP => new V4f(-1, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWZN => new V4f(-1, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWZX => new V4f(-1, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWZY => new V4f(-1, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWZZ => new V4f(-1, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWZW => new V4f(-1, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWWO => new V4f(-1, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWWP => new V4f(-1, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWWN => new V4f(-1, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWWX => new V4f(-1, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWWY => new V4f(-1, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWWZ => new V4f(-1, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f NWWW => new V4f(-1, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOOO => new V4f(X, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOOI => new V4f(X, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOON => new V4f(X, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOOX => new V4f(X, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOOY => new V4f(X, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOOZ => new V4f(X, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOOW => new V4f(X, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOIO => new V4f(X, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOII => new V4f(X, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOPN => new V4f(X, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOIX => new V4f(X, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOIY => new V4f(X, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOIZ => new V4f(X, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOIW => new V4f(X, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONO => new V4f(X, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONP => new V4f(X, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONN => new V4f(X, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONX => new V4f(X, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONY => new V4f(X, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONZ => new V4f(X, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XONW => new V4f(X, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXO => new V4f(X, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXI => new V4f(X, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXN => new V4f(X, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXX => new V4f(X, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXY => new V4f(X, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXZ => new V4f(X, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOXW => new V4f(X, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYO => new V4f(X, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYI => new V4f(X, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYN => new V4f(X, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYX => new V4f(X, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYY => new V4f(X, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYZ => new V4f(X, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOYW => new V4f(X, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOZO => new V4f(X, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOZI => new V4f(X, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOZN => new V4f(X, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOZX => new V4f(X, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOZY => new V4f(X, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOZZ => new V4f(X, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOZW => new V4f(X, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOWO => new V4f(X, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOWI => new V4f(X, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOWN => new V4f(X, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOWX => new V4f(X, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOWY => new V4f(X, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOWZ => new V4f(X, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XOWW => new V4f(X, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIOO => new V4f(X, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIOI => new V4f(X, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPON => new V4f(X, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIOX => new V4f(X, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIOY => new V4f(X, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIOZ => new V4f(X, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIOW => new V4f(X, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIIO => new V4f(X, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIII => new V4f(X, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPPN => new V4f(X, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIIX => new V4f(X, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIIY => new V4f(X, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIIZ => new V4f(X, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIIW => new V4f(X, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNO => new V4f(X, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNP => new V4f(X, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNN => new V4f(X, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNX => new V4f(X, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNY => new V4f(X, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNZ => new V4f(X, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPNW => new V4f(X, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIXO => new V4f(X, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIXI => new V4f(X, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPXN => new V4f(X, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIXX => new V4f(X, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIXY => new V4f(X, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIXZ => new V4f(X, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIXW => new V4f(X, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIYO => new V4f(X, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIYI => new V4f(X, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPYN => new V4f(X, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIYX => new V4f(X, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIYY => new V4f(X, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIYZ => new V4f(X, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIYW => new V4f(X, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIZO => new V4f(X, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIZI => new V4f(X, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPZN => new V4f(X, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIZX => new V4f(X, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIZY => new V4f(X, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIZZ => new V4f(X, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIZW => new V4f(X, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIWO => new V4f(X, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIWI => new V4f(X, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XPWN => new V4f(X, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIWX => new V4f(X, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIWY => new V4f(X, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIWZ => new V4f(X, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XIWW => new V4f(X, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNOO => new V4f(X, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNOP => new V4f(X, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNON => new V4f(X, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNOX => new V4f(X, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNOY => new V4f(X, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNOZ => new V4f(X, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNOW => new V4f(X, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPO => new V4f(X, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPP => new V4f(X, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPN => new V4f(X, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPX => new V4f(X, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPY => new V4f(X, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPZ => new V4f(X, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNPW => new V4f(X, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNO => new V4f(X, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNP => new V4f(X, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNN => new V4f(X, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNX => new V4f(X, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNY => new V4f(X, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNZ => new V4f(X, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNNW => new V4f(X, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXO => new V4f(X, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXP => new V4f(X, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXN => new V4f(X, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXX => new V4f(X, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXY => new V4f(X, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXZ => new V4f(X, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNXW => new V4f(X, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYO => new V4f(X, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYP => new V4f(X, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYN => new V4f(X, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYX => new V4f(X, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYY => new V4f(X, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYZ => new V4f(X, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNYW => new V4f(X, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNZO => new V4f(X, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNZP => new V4f(X, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNZN => new V4f(X, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNZX => new V4f(X, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNZY => new V4f(X, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNZZ => new V4f(X, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNZW => new V4f(X, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNWO => new V4f(X, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNWP => new V4f(X, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNWN => new V4f(X, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNWX => new V4f(X, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNWY => new V4f(X, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNWZ => new V4f(X, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XNWW => new V4f(X, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXOO => new V4f(X, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXOI => new V4f(X, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXON => new V4f(X, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXOX => new V4f(X, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXOY => new V4f(X, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXOZ => new V4f(X, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXOW => new V4f(X, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXIO => new V4f(X, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXII => new V4f(X, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXPN => new V4f(X, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXIX => new V4f(X, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXIY => new V4f(X, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXIZ => new V4f(X, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXIW => new V4f(X, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNO => new V4f(X, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNP => new V4f(X, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNN => new V4f(X, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNX => new V4f(X, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNY => new V4f(X, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNZ => new V4f(X, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXNW => new V4f(X, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXO => new V4f(X, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXI => new V4f(X, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXN => new V4f(X, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXX => new V4f(X, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXY => new V4f(X, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXZ => new V4f(X, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXXW => new V4f(X, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYO => new V4f(X, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYI => new V4f(X, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYN => new V4f(X, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYX => new V4f(X, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYY => new V4f(X, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYZ => new V4f(X, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXYW => new V4f(X, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXZO => new V4f(X, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXZI => new V4f(X, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXZN => new V4f(X, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXZX => new V4f(X, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXZY => new V4f(X, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXZZ => new V4f(X, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXZW => new V4f(X, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXWO => new V4f(X, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXWI => new V4f(X, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXWN => new V4f(X, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXWX => new V4f(X, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXWY => new V4f(X, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXWZ => new V4f(X, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XXWW => new V4f(X, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYOO => new V4f(X, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYOI => new V4f(X, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYON => new V4f(X, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYOX => new V4f(X, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYOY => new V4f(X, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYOZ => new V4f(X, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYOW => new V4f(X, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYIO => new V4f(X, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYII => new V4f(X, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYPN => new V4f(X, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYIX => new V4f(X, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYIY => new V4f(X, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYIZ => new V4f(X, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYIW => new V4f(X, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNO => new V4f(X, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNP => new V4f(X, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNN => new V4f(X, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNX => new V4f(X, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNY => new V4f(X, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNZ => new V4f(X, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYNW => new V4f(X, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXO => new V4f(X, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXI => new V4f(X, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXN => new V4f(X, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXX => new V4f(X, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXY => new V4f(X, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXZ => new V4f(X, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYXW => new V4f(X, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYO => new V4f(X, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYI => new V4f(X, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYN => new V4f(X, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYX => new V4f(X, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYY => new V4f(X, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYZ => new V4f(X, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYYW => new V4f(X, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYZO => new V4f(X, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYZI => new V4f(X, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYZN => new V4f(X, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYZX => new V4f(X, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYZY => new V4f(X, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYZZ => new V4f(X, Y, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f XYZW { readonly get => new V4f(X, Y, Z, W); set { X = value.X; Y = value.Y; Z = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYWO => new V4f(X, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYWI => new V4f(X, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYWN => new V4f(X, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYWX => new V4f(X, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYWY => new V4f(X, Y, W, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f XYWZ { readonly get => new V4f(X, Y, W, Z); set { X = value.X; Y = value.Y; W = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XYWW => new V4f(X, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZOO => new V4f(X, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZOI => new V4f(X, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZON => new V4f(X, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZOX => new V4f(X, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZOY => new V4f(X, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZOZ => new V4f(X, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZOW => new V4f(X, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZIO => new V4f(X, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZII => new V4f(X, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZPN => new V4f(X, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZIX => new V4f(X, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZIY => new V4f(X, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZIZ => new V4f(X, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZIW => new V4f(X, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZNO => new V4f(X, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZNP => new V4f(X, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZNN => new V4f(X, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZNX => new V4f(X, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZNY => new V4f(X, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZNZ => new V4f(X, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZNW => new V4f(X, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZXO => new V4f(X, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZXI => new V4f(X, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZXN => new V4f(X, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZXX => new V4f(X, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZXY => new V4f(X, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZXZ => new V4f(X, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZXW => new V4f(X, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZYO => new V4f(X, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZYI => new V4f(X, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZYN => new V4f(X, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZYX => new V4f(X, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZYY => new V4f(X, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZYZ => new V4f(X, Z, Y, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f XZYW { readonly get => new V4f(X, Z, Y, W); set { X = value.X; Z = value.Y; Y = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZZO => new V4f(X, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZZI => new V4f(X, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZZN => new V4f(X, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZZX => new V4f(X, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZZY => new V4f(X, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZZZ => new V4f(X, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZZW => new V4f(X, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZWO => new V4f(X, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZWI => new V4f(X, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZWN => new V4f(X, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZWX => new V4f(X, Z, W, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f XZWY { readonly get => new V4f(X, Z, W, Y); set { X = value.X; Z = value.Y; W = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZWZ => new V4f(X, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XZWW => new V4f(X, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWOO => new V4f(X, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWOI => new V4f(X, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWON => new V4f(X, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWOX => new V4f(X, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWOY => new V4f(X, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWOZ => new V4f(X, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWOW => new V4f(X, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWIO => new V4f(X, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWII => new V4f(X, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWPN => new V4f(X, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWIX => new V4f(X, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWIY => new V4f(X, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWIZ => new V4f(X, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWIW => new V4f(X, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWNO => new V4f(X, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWNP => new V4f(X, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWNN => new V4f(X, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWNX => new V4f(X, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWNY => new V4f(X, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWNZ => new V4f(X, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWNW => new V4f(X, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWXO => new V4f(X, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWXI => new V4f(X, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWXN => new V4f(X, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWXX => new V4f(X, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWXY => new V4f(X, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWXZ => new V4f(X, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWXW => new V4f(X, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWYO => new V4f(X, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWYI => new V4f(X, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWYN => new V4f(X, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWYX => new V4f(X, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWYY => new V4f(X, W, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f XWYZ { readonly get => new V4f(X, W, Y, Z); set { X = value.X; W = value.Y; Y = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWYW => new V4f(X, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWZO => new V4f(X, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWZI => new V4f(X, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWZN => new V4f(X, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWZX => new V4f(X, W, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f XWZY { readonly get => new V4f(X, W, Z, Y); set { X = value.X; W = value.Y; Z = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWZZ => new V4f(X, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWZW => new V4f(X, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWWO => new V4f(X, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWWI => new V4f(X, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWWN => new V4f(X, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWWX => new V4f(X, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWWY => new V4f(X, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWWZ => new V4f(X, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f XWWW => new V4f(X, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOOO => new V4f(Y, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOOI => new V4f(Y, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOON => new V4f(Y, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOOX => new V4f(Y, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOOY => new V4f(Y, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOOZ => new V4f(Y, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOOW => new V4f(Y, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOIO => new V4f(Y, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOII => new V4f(Y, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOPN => new V4f(Y, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOIX => new V4f(Y, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOIY => new V4f(Y, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOIZ => new V4f(Y, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOIW => new V4f(Y, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONO => new V4f(Y, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONP => new V4f(Y, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONN => new V4f(Y, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONX => new V4f(Y, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONY => new V4f(Y, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONZ => new V4f(Y, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YONW => new V4f(Y, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXO => new V4f(Y, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXI => new V4f(Y, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXN => new V4f(Y, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXX => new V4f(Y, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXY => new V4f(Y, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXZ => new V4f(Y, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOXW => new V4f(Y, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYO => new V4f(Y, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYI => new V4f(Y, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYN => new V4f(Y, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYX => new V4f(Y, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYY => new V4f(Y, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYZ => new V4f(Y, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOYW => new V4f(Y, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOZO => new V4f(Y, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOZI => new V4f(Y, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOZN => new V4f(Y, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOZX => new V4f(Y, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOZY => new V4f(Y, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOZZ => new V4f(Y, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOZW => new V4f(Y, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOWO => new V4f(Y, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOWI => new V4f(Y, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOWN => new V4f(Y, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOWX => new V4f(Y, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOWY => new V4f(Y, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOWZ => new V4f(Y, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YOWW => new V4f(Y, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIOO => new V4f(Y, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIOI => new V4f(Y, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPON => new V4f(Y, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIOX => new V4f(Y, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIOY => new V4f(Y, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIOZ => new V4f(Y, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIOW => new V4f(Y, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIIO => new V4f(Y, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIII => new V4f(Y, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPPN => new V4f(Y, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIIX => new V4f(Y, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIIY => new V4f(Y, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIIZ => new V4f(Y, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIIW => new V4f(Y, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNO => new V4f(Y, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNP => new V4f(Y, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNN => new V4f(Y, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNX => new V4f(Y, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNY => new V4f(Y, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNZ => new V4f(Y, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPNW => new V4f(Y, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIXO => new V4f(Y, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIXI => new V4f(Y, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPXN => new V4f(Y, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIXX => new V4f(Y, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIXY => new V4f(Y, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIXZ => new V4f(Y, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIXW => new V4f(Y, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIYO => new V4f(Y, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIYI => new V4f(Y, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPYN => new V4f(Y, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIYX => new V4f(Y, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIYY => new V4f(Y, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIYZ => new V4f(Y, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIYW => new V4f(Y, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIZO => new V4f(Y, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIZI => new V4f(Y, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPZN => new V4f(Y, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIZX => new V4f(Y, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIZY => new V4f(Y, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIZZ => new V4f(Y, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIZW => new V4f(Y, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIWO => new V4f(Y, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIWI => new V4f(Y, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YPWN => new V4f(Y, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIWX => new V4f(Y, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIWY => new V4f(Y, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIWZ => new V4f(Y, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YIWW => new V4f(Y, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNOO => new V4f(Y, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNOP => new V4f(Y, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNON => new V4f(Y, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNOX => new V4f(Y, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNOY => new V4f(Y, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNOZ => new V4f(Y, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNOW => new V4f(Y, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPO => new V4f(Y, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPP => new V4f(Y, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPN => new V4f(Y, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPX => new V4f(Y, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPY => new V4f(Y, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPZ => new V4f(Y, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNPW => new V4f(Y, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNO => new V4f(Y, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNP => new V4f(Y, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNN => new V4f(Y, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNX => new V4f(Y, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNY => new V4f(Y, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNZ => new V4f(Y, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNNW => new V4f(Y, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXO => new V4f(Y, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXP => new V4f(Y, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXN => new V4f(Y, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXX => new V4f(Y, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXY => new V4f(Y, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXZ => new V4f(Y, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNXW => new V4f(Y, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYO => new V4f(Y, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYP => new V4f(Y, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYN => new V4f(Y, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYX => new V4f(Y, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYY => new V4f(Y, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYZ => new V4f(Y, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNYW => new V4f(Y, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNZO => new V4f(Y, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNZP => new V4f(Y, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNZN => new V4f(Y, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNZX => new V4f(Y, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNZY => new V4f(Y, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNZZ => new V4f(Y, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNZW => new V4f(Y, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNWO => new V4f(Y, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNWP => new V4f(Y, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNWN => new V4f(Y, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNWX => new V4f(Y, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNWY => new V4f(Y, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNWZ => new V4f(Y, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YNWW => new V4f(Y, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXOO => new V4f(Y, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXOI => new V4f(Y, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXON => new V4f(Y, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXOX => new V4f(Y, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXOY => new V4f(Y, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXOZ => new V4f(Y, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXOW => new V4f(Y, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXIO => new V4f(Y, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXII => new V4f(Y, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXPN => new V4f(Y, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXIX => new V4f(Y, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXIY => new V4f(Y, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXIZ => new V4f(Y, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXIW => new V4f(Y, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNO => new V4f(Y, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNP => new V4f(Y, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNN => new V4f(Y, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNX => new V4f(Y, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNY => new V4f(Y, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNZ => new V4f(Y, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXNW => new V4f(Y, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXO => new V4f(Y, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXI => new V4f(Y, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXN => new V4f(Y, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXX => new V4f(Y, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXY => new V4f(Y, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXZ => new V4f(Y, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXXW => new V4f(Y, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYO => new V4f(Y, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYI => new V4f(Y, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYN => new V4f(Y, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYX => new V4f(Y, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYY => new V4f(Y, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYZ => new V4f(Y, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXYW => new V4f(Y, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXZO => new V4f(Y, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXZI => new V4f(Y, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXZN => new V4f(Y, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXZX => new V4f(Y, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXZY => new V4f(Y, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXZZ => new V4f(Y, X, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f YXZW { readonly get => new V4f(Y, X, Z, W); set { Y = value.X; X = value.Y; Z = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXWO => new V4f(Y, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXWI => new V4f(Y, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXWN => new V4f(Y, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXWX => new V4f(Y, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXWY => new V4f(Y, X, W, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f YXWZ { readonly get => new V4f(Y, X, W, Z); set { Y = value.X; X = value.Y; W = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YXWW => new V4f(Y, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYOO => new V4f(Y, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYOI => new V4f(Y, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYON => new V4f(Y, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYOX => new V4f(Y, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYOY => new V4f(Y, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYOZ => new V4f(Y, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYOW => new V4f(Y, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYIO => new V4f(Y, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYII => new V4f(Y, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYPN => new V4f(Y, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYIX => new V4f(Y, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYIY => new V4f(Y, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYIZ => new V4f(Y, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYIW => new V4f(Y, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNO => new V4f(Y, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNP => new V4f(Y, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNN => new V4f(Y, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNX => new V4f(Y, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNY => new V4f(Y, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNZ => new V4f(Y, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYNW => new V4f(Y, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXO => new V4f(Y, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXI => new V4f(Y, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXN => new V4f(Y, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXX => new V4f(Y, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXY => new V4f(Y, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXZ => new V4f(Y, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYXW => new V4f(Y, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYO => new V4f(Y, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYI => new V4f(Y, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYN => new V4f(Y, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYX => new V4f(Y, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYY => new V4f(Y, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYZ => new V4f(Y, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYYW => new V4f(Y, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYZO => new V4f(Y, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYZI => new V4f(Y, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYZN => new V4f(Y, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYZX => new V4f(Y, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYZY => new V4f(Y, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYZZ => new V4f(Y, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYZW => new V4f(Y, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYWO => new V4f(Y, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYWI => new V4f(Y, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYWN => new V4f(Y, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYWX => new V4f(Y, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYWY => new V4f(Y, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYWZ => new V4f(Y, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YYWW => new V4f(Y, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZOO => new V4f(Y, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZOI => new V4f(Y, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZON => new V4f(Y, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZOX => new V4f(Y, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZOY => new V4f(Y, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZOZ => new V4f(Y, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZOW => new V4f(Y, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZIO => new V4f(Y, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZII => new V4f(Y, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZPN => new V4f(Y, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZIX => new V4f(Y, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZIY => new V4f(Y, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZIZ => new V4f(Y, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZIW => new V4f(Y, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZNO => new V4f(Y, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZNP => new V4f(Y, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZNN => new V4f(Y, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZNX => new V4f(Y, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZNY => new V4f(Y, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZNZ => new V4f(Y, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZNW => new V4f(Y, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZXO => new V4f(Y, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZXI => new V4f(Y, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZXN => new V4f(Y, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZXX => new V4f(Y, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZXY => new V4f(Y, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZXZ => new V4f(Y, Z, X, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f YZXW { readonly get => new V4f(Y, Z, X, W); set { Y = value.X; Z = value.Y; X = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZYO => new V4f(Y, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZYI => new V4f(Y, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZYN => new V4f(Y, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZYX => new V4f(Y, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZYY => new V4f(Y, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZYZ => new V4f(Y, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZYW => new V4f(Y, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZZO => new V4f(Y, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZZI => new V4f(Y, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZZN => new V4f(Y, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZZX => new V4f(Y, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZZY => new V4f(Y, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZZZ => new V4f(Y, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZZW => new V4f(Y, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZWO => new V4f(Y, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZWI => new V4f(Y, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZWN => new V4f(Y, Z, W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f YZWX { readonly get => new V4f(Y, Z, W, X); set { Y = value.X; Z = value.Y; W = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZWY => new V4f(Y, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZWZ => new V4f(Y, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YZWW => new V4f(Y, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWOO => new V4f(Y, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWOI => new V4f(Y, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWON => new V4f(Y, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWOX => new V4f(Y, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWOY => new V4f(Y, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWOZ => new V4f(Y, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWOW => new V4f(Y, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWIO => new V4f(Y, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWII => new V4f(Y, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWPN => new V4f(Y, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWIX => new V4f(Y, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWIY => new V4f(Y, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWIZ => new V4f(Y, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWIW => new V4f(Y, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWNO => new V4f(Y, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWNP => new V4f(Y, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWNN => new V4f(Y, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWNX => new V4f(Y, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWNY => new V4f(Y, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWNZ => new V4f(Y, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWNW => new V4f(Y, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWXO => new V4f(Y, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWXI => new V4f(Y, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWXN => new V4f(Y, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWXX => new V4f(Y, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWXY => new V4f(Y, W, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f YWXZ { readonly get => new V4f(Y, W, X, Z); set { Y = value.X; W = value.Y; X = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWXW => new V4f(Y, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWYO => new V4f(Y, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWYI => new V4f(Y, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWYN => new V4f(Y, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWYX => new V4f(Y, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWYY => new V4f(Y, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWYZ => new V4f(Y, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWYW => new V4f(Y, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWZO => new V4f(Y, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWZI => new V4f(Y, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWZN => new V4f(Y, W, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f YWZX { readonly get => new V4f(Y, W, Z, X); set { Y = value.X; W = value.Y; Z = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWZY => new V4f(Y, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWZZ => new V4f(Y, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWZW => new V4f(Y, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWWO => new V4f(Y, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWWI => new V4f(Y, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWWN => new V4f(Y, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWWX => new V4f(Y, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWWY => new V4f(Y, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWWZ => new V4f(Y, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f YWWW => new V4f(Y, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOOO => new V4f(Z, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOOI => new V4f(Z, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOON => new V4f(Z, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOOX => new V4f(Z, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOOY => new V4f(Z, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOOZ => new V4f(Z, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOOW => new V4f(Z, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOIO => new V4f(Z, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOII => new V4f(Z, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOPN => new V4f(Z, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOIX => new V4f(Z, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOIY => new V4f(Z, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOIZ => new V4f(Z, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOIW => new V4f(Z, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZONO => new V4f(Z, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZONP => new V4f(Z, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZONN => new V4f(Z, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZONX => new V4f(Z, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZONY => new V4f(Z, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZONZ => new V4f(Z, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZONW => new V4f(Z, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOXO => new V4f(Z, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOXI => new V4f(Z, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOXN => new V4f(Z, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOXX => new V4f(Z, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOXY => new V4f(Z, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOXZ => new V4f(Z, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOXW => new V4f(Z, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOYO => new V4f(Z, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOYI => new V4f(Z, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOYN => new V4f(Z, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOYX => new V4f(Z, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOYY => new V4f(Z, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOYZ => new V4f(Z, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOYW => new V4f(Z, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOZO => new V4f(Z, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOZI => new V4f(Z, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOZN => new V4f(Z, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOZX => new V4f(Z, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOZY => new V4f(Z, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOZZ => new V4f(Z, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOZW => new V4f(Z, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOWO => new V4f(Z, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOWI => new V4f(Z, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOWN => new V4f(Z, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOWX => new V4f(Z, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOWY => new V4f(Z, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOWZ => new V4f(Z, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZOWW => new V4f(Z, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIOO => new V4f(Z, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIOI => new V4f(Z, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPON => new V4f(Z, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIOX => new V4f(Z, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIOY => new V4f(Z, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIOZ => new V4f(Z, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIOW => new V4f(Z, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIIO => new V4f(Z, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIII => new V4f(Z, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPPN => new V4f(Z, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIIX => new V4f(Z, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIIY => new V4f(Z, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIIZ => new V4f(Z, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIIW => new V4f(Z, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPNO => new V4f(Z, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPNP => new V4f(Z, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPNN => new V4f(Z, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPNX => new V4f(Z, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPNY => new V4f(Z, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPNZ => new V4f(Z, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPNW => new V4f(Z, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIXO => new V4f(Z, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIXI => new V4f(Z, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPXN => new V4f(Z, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIXX => new V4f(Z, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIXY => new V4f(Z, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIXZ => new V4f(Z, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIXW => new V4f(Z, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIYO => new V4f(Z, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIYI => new V4f(Z, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPYN => new V4f(Z, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIYX => new V4f(Z, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIYY => new V4f(Z, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIYZ => new V4f(Z, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIYW => new V4f(Z, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIZO => new V4f(Z, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIZI => new V4f(Z, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPZN => new V4f(Z, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIZX => new V4f(Z, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIZY => new V4f(Z, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIZZ => new V4f(Z, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIZW => new V4f(Z, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIWO => new V4f(Z, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIWI => new V4f(Z, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZPWN => new V4f(Z, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIWX => new V4f(Z, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIWY => new V4f(Z, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIWZ => new V4f(Z, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZIWW => new V4f(Z, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNOO => new V4f(Z, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNOP => new V4f(Z, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNON => new V4f(Z, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNOX => new V4f(Z, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNOY => new V4f(Z, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNOZ => new V4f(Z, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNOW => new V4f(Z, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNPO => new V4f(Z, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNPP => new V4f(Z, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNPN => new V4f(Z, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNPX => new V4f(Z, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNPY => new V4f(Z, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNPZ => new V4f(Z, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNPW => new V4f(Z, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNNO => new V4f(Z, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNNP => new V4f(Z, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNNN => new V4f(Z, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNNX => new V4f(Z, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNNY => new V4f(Z, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNNZ => new V4f(Z, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNNW => new V4f(Z, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNXO => new V4f(Z, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNXP => new V4f(Z, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNXN => new V4f(Z, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNXX => new V4f(Z, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNXY => new V4f(Z, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNXZ => new V4f(Z, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNXW => new V4f(Z, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNYO => new V4f(Z, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNYP => new V4f(Z, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNYN => new V4f(Z, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNYX => new V4f(Z, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNYY => new V4f(Z, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNYZ => new V4f(Z, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNYW => new V4f(Z, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNZO => new V4f(Z, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNZP => new V4f(Z, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNZN => new V4f(Z, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNZX => new V4f(Z, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNZY => new V4f(Z, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNZZ => new V4f(Z, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNZW => new V4f(Z, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNWO => new V4f(Z, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNWP => new V4f(Z, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNWN => new V4f(Z, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNWX => new V4f(Z, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNWY => new V4f(Z, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNWZ => new V4f(Z, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZNWW => new V4f(Z, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXOO => new V4f(Z, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXOI => new V4f(Z, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXON => new V4f(Z, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXOX => new V4f(Z, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXOY => new V4f(Z, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXOZ => new V4f(Z, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXOW => new V4f(Z, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXIO => new V4f(Z, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXII => new V4f(Z, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXPN => new V4f(Z, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXIX => new V4f(Z, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXIY => new V4f(Z, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXIZ => new V4f(Z, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXIW => new V4f(Z, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXNO => new V4f(Z, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXNP => new V4f(Z, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXNN => new V4f(Z, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXNX => new V4f(Z, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXNY => new V4f(Z, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXNZ => new V4f(Z, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXNW => new V4f(Z, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXXO => new V4f(Z, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXXI => new V4f(Z, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXXN => new V4f(Z, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXXX => new V4f(Z, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXXY => new V4f(Z, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXXZ => new V4f(Z, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXXW => new V4f(Z, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXYO => new V4f(Z, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXYI => new V4f(Z, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXYN => new V4f(Z, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXYX => new V4f(Z, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXYY => new V4f(Z, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXYZ => new V4f(Z, X, Y, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f ZXYW { readonly get => new V4f(Z, X, Y, W); set { Z = value.X; X = value.Y; Y = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXZO => new V4f(Z, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXZI => new V4f(Z, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXZN => new V4f(Z, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXZX => new V4f(Z, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXZY => new V4f(Z, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXZZ => new V4f(Z, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXZW => new V4f(Z, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXWO => new V4f(Z, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXWI => new V4f(Z, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXWN => new V4f(Z, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXWX => new V4f(Z, X, W, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f ZXWY { readonly get => new V4f(Z, X, W, Y); set { Z = value.X; X = value.Y; W = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXWZ => new V4f(Z, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZXWW => new V4f(Z, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYOO => new V4f(Z, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYOI => new V4f(Z, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYON => new V4f(Z, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYOX => new V4f(Z, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYOY => new V4f(Z, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYOZ => new V4f(Z, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYOW => new V4f(Z, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYIO => new V4f(Z, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYII => new V4f(Z, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYPN => new V4f(Z, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYIX => new V4f(Z, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYIY => new V4f(Z, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYIZ => new V4f(Z, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYIW => new V4f(Z, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYNO => new V4f(Z, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYNP => new V4f(Z, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYNN => new V4f(Z, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYNX => new V4f(Z, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYNY => new V4f(Z, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYNZ => new V4f(Z, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYNW => new V4f(Z, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYXO => new V4f(Z, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYXI => new V4f(Z, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYXN => new V4f(Z, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYXX => new V4f(Z, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYXY => new V4f(Z, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYXZ => new V4f(Z, Y, X, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f ZYXW { readonly get => new V4f(Z, Y, X, W); set { Z = value.X; Y = value.Y; X = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYYO => new V4f(Z, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYYI => new V4f(Z, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYYN => new V4f(Z, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYYX => new V4f(Z, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYYY => new V4f(Z, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYYZ => new V4f(Z, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYYW => new V4f(Z, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYZO => new V4f(Z, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYZI => new V4f(Z, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYZN => new V4f(Z, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYZX => new V4f(Z, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYZY => new V4f(Z, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYZZ => new V4f(Z, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYZW => new V4f(Z, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYWO => new V4f(Z, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYWI => new V4f(Z, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYWN => new V4f(Z, Y, W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f ZYWX { readonly get => new V4f(Z, Y, W, X); set { Z = value.X; Y = value.Y; W = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYWY => new V4f(Z, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYWZ => new V4f(Z, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZYWW => new V4f(Z, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZOO => new V4f(Z, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZOI => new V4f(Z, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZON => new V4f(Z, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZOX => new V4f(Z, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZOY => new V4f(Z, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZOZ => new V4f(Z, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZOW => new V4f(Z, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZIO => new V4f(Z, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZII => new V4f(Z, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZPN => new V4f(Z, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZIX => new V4f(Z, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZIY => new V4f(Z, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZIZ => new V4f(Z, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZIW => new V4f(Z, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZNO => new V4f(Z, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZNP => new V4f(Z, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZNN => new V4f(Z, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZNX => new V4f(Z, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZNY => new V4f(Z, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZNZ => new V4f(Z, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZNW => new V4f(Z, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZXO => new V4f(Z, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZXI => new V4f(Z, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZXN => new V4f(Z, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZXX => new V4f(Z, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZXY => new V4f(Z, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZXZ => new V4f(Z, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZXW => new V4f(Z, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZYO => new V4f(Z, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZYI => new V4f(Z, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZYN => new V4f(Z, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZYX => new V4f(Z, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZYY => new V4f(Z, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZYZ => new V4f(Z, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZYW => new V4f(Z, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZZO => new V4f(Z, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZZI => new V4f(Z, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZZN => new V4f(Z, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZZX => new V4f(Z, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZZY => new V4f(Z, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZZZ => new V4f(Z, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZZW => new V4f(Z, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZWO => new V4f(Z, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZWI => new V4f(Z, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZWN => new V4f(Z, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZWX => new V4f(Z, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZWY => new V4f(Z, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZWZ => new V4f(Z, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZZWW => new V4f(Z, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWOO => new V4f(Z, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWOI => new V4f(Z, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWON => new V4f(Z, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWOX => new V4f(Z, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWOY => new V4f(Z, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWOZ => new V4f(Z, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWOW => new V4f(Z, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWIO => new V4f(Z, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWII => new V4f(Z, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWPN => new V4f(Z, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWIX => new V4f(Z, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWIY => new V4f(Z, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWIZ => new V4f(Z, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWIW => new V4f(Z, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWNO => new V4f(Z, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWNP => new V4f(Z, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWNN => new V4f(Z, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWNX => new V4f(Z, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWNY => new V4f(Z, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWNZ => new V4f(Z, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWNW => new V4f(Z, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWXO => new V4f(Z, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWXI => new V4f(Z, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWXN => new V4f(Z, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWXX => new V4f(Z, W, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f ZWXY { readonly get => new V4f(Z, W, X, Y); set { Z = value.X; W = value.Y; X = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWXZ => new V4f(Z, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWXW => new V4f(Z, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWYO => new V4f(Z, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWYI => new V4f(Z, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWYN => new V4f(Z, W, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f ZWYX { readonly get => new V4f(Z, W, Y, X); set { Z = value.X; W = value.Y; Y = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWYY => new V4f(Z, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWYZ => new V4f(Z, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWYW => new V4f(Z, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWZO => new V4f(Z, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWZI => new V4f(Z, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWZN => new V4f(Z, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWZX => new V4f(Z, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWZY => new V4f(Z, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWZZ => new V4f(Z, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWZW => new V4f(Z, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWWO => new V4f(Z, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWWI => new V4f(Z, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWWN => new V4f(Z, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWWX => new V4f(Z, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWWY => new V4f(Z, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWWZ => new V4f(Z, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f ZWWW => new V4f(Z, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOOO => new V4f(W, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOOI => new V4f(W, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOON => new V4f(W, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOOX => new V4f(W, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOOY => new V4f(W, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOOZ => new V4f(W, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOOW => new V4f(W, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOIO => new V4f(W, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOII => new V4f(W, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOPN => new V4f(W, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOIX => new V4f(W, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOIY => new V4f(W, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOIZ => new V4f(W, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOIW => new V4f(W, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WONO => new V4f(W, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WONP => new V4f(W, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WONN => new V4f(W, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WONX => new V4f(W, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WONY => new V4f(W, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WONZ => new V4f(W, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WONW => new V4f(W, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOXO => new V4f(W, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOXI => new V4f(W, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOXN => new V4f(W, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOXX => new V4f(W, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOXY => new V4f(W, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOXZ => new V4f(W, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOXW => new V4f(W, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOYO => new V4f(W, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOYI => new V4f(W, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOYN => new V4f(W, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOYX => new V4f(W, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOYY => new V4f(W, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOYZ => new V4f(W, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOYW => new V4f(W, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOZO => new V4f(W, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOZI => new V4f(W, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOZN => new V4f(W, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOZX => new V4f(W, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOZY => new V4f(W, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOZZ => new V4f(W, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOZW => new V4f(W, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOWO => new V4f(W, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOWI => new V4f(W, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOWN => new V4f(W, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOWX => new V4f(W, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOWY => new V4f(W, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOWZ => new V4f(W, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WOWW => new V4f(W, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIOO => new V4f(W, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIOI => new V4f(W, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WPON => new V4f(W, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIOX => new V4f(W, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIOY => new V4f(W, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIOZ => new V4f(W, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIOW => new V4f(W, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIIO => new V4f(W, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIII => new V4f(W, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WPPN => new V4f(W, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIIX => new V4f(W, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIIY => new V4f(W, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIIZ => new V4f(W, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIIW => new V4f(W, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WPNO => new V4f(W, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WPNP => new V4f(W, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WPNN => new V4f(W, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WPNX => new V4f(W, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WPNY => new V4f(W, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WPNZ => new V4f(W, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WPNW => new V4f(W, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIXO => new V4f(W, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIXI => new V4f(W, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WPXN => new V4f(W, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIXX => new V4f(W, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIXY => new V4f(W, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIXZ => new V4f(W, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIXW => new V4f(W, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIYO => new V4f(W, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIYI => new V4f(W, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WPYN => new V4f(W, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIYX => new V4f(W, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIYY => new V4f(W, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIYZ => new V4f(W, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIYW => new V4f(W, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIZO => new V4f(W, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIZI => new V4f(W, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WPZN => new V4f(W, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIZX => new V4f(W, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIZY => new V4f(W, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIZZ => new V4f(W, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIZW => new V4f(W, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIWO => new V4f(W, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIWI => new V4f(W, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WPWN => new V4f(W, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIWX => new V4f(W, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIWY => new V4f(W, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIWZ => new V4f(W, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WIWW => new V4f(W, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNOO => new V4f(W, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNOP => new V4f(W, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNON => new V4f(W, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNOX => new V4f(W, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNOY => new V4f(W, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNOZ => new V4f(W, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNOW => new V4f(W, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNPO => new V4f(W, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNPP => new V4f(W, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNPN => new V4f(W, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNPX => new V4f(W, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNPY => new V4f(W, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNPZ => new V4f(W, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNPW => new V4f(W, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNNO => new V4f(W, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNNP => new V4f(W, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNNN => new V4f(W, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNNX => new V4f(W, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNNY => new V4f(W, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNNZ => new V4f(W, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNNW => new V4f(W, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNXO => new V4f(W, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNXP => new V4f(W, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNXN => new V4f(W, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNXX => new V4f(W, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNXY => new V4f(W, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNXZ => new V4f(W, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNXW => new V4f(W, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNYO => new V4f(W, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNYP => new V4f(W, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNYN => new V4f(W, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNYX => new V4f(W, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNYY => new V4f(W, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNYZ => new V4f(W, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNYW => new V4f(W, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNZO => new V4f(W, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNZP => new V4f(W, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNZN => new V4f(W, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNZX => new V4f(W, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNZY => new V4f(W, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNZZ => new V4f(W, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNZW => new V4f(W, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNWO => new V4f(W, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNWP => new V4f(W, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNWN => new V4f(W, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNWX => new V4f(W, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNWY => new V4f(W, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNWZ => new V4f(W, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WNWW => new V4f(W, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXOO => new V4f(W, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXOI => new V4f(W, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXON => new V4f(W, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXOX => new V4f(W, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXOY => new V4f(W, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXOZ => new V4f(W, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXOW => new V4f(W, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXIO => new V4f(W, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXII => new V4f(W, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXPN => new V4f(W, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXIX => new V4f(W, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXIY => new V4f(W, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXIZ => new V4f(W, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXIW => new V4f(W, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXNO => new V4f(W, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXNP => new V4f(W, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXNN => new V4f(W, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXNX => new V4f(W, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXNY => new V4f(W, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXNZ => new V4f(W, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXNW => new V4f(W, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXXO => new V4f(W, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXXI => new V4f(W, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXXN => new V4f(W, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXXX => new V4f(W, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXXY => new V4f(W, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXXZ => new V4f(W, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXXW => new V4f(W, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXYO => new V4f(W, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXYI => new V4f(W, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXYN => new V4f(W, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXYX => new V4f(W, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXYY => new V4f(W, X, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f WXYZ { readonly get => new V4f(W, X, Y, Z); set { W = value.X; X = value.Y; Y = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXYW => new V4f(W, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXZO => new V4f(W, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXZI => new V4f(W, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXZN => new V4f(W, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXZX => new V4f(W, X, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f WXZY { readonly get => new V4f(W, X, Z, Y); set { W = value.X; X = value.Y; Z = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXZZ => new V4f(W, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXZW => new V4f(W, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXWO => new V4f(W, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXWI => new V4f(W, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXWN => new V4f(W, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXWX => new V4f(W, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXWY => new V4f(W, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXWZ => new V4f(W, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WXWW => new V4f(W, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYOO => new V4f(W, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYOI => new V4f(W, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYON => new V4f(W, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYOX => new V4f(W, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYOY => new V4f(W, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYOZ => new V4f(W, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYOW => new V4f(W, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYIO => new V4f(W, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYII => new V4f(W, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYPN => new V4f(W, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYIX => new V4f(W, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYIY => new V4f(W, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYIZ => new V4f(W, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYIW => new V4f(W, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYNO => new V4f(W, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYNP => new V4f(W, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYNN => new V4f(W, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYNX => new V4f(W, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYNY => new V4f(W, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYNZ => new V4f(W, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYNW => new V4f(W, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYXO => new V4f(W, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYXI => new V4f(W, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYXN => new V4f(W, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYXX => new V4f(W, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYXY => new V4f(W, Y, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f WYXZ { readonly get => new V4f(W, Y, X, Z); set { W = value.X; Y = value.Y; X = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYXW => new V4f(W, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYYO => new V4f(W, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYYI => new V4f(W, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYYN => new V4f(W, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYYX => new V4f(W, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYYY => new V4f(W, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYYZ => new V4f(W, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYYW => new V4f(W, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYZO => new V4f(W, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYZI => new V4f(W, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYZN => new V4f(W, Y, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f WYZX { readonly get => new V4f(W, Y, Z, X); set { W = value.X; Y = value.Y; Z = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYZY => new V4f(W, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYZZ => new V4f(W, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYZW => new V4f(W, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYWO => new V4f(W, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYWI => new V4f(W, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYWN => new V4f(W, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYWX => new V4f(W, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYWY => new V4f(W, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYWZ => new V4f(W, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WYWW => new V4f(W, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZOO => new V4f(W, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZOI => new V4f(W, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZON => new V4f(W, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZOX => new V4f(W, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZOY => new V4f(W, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZOZ => new V4f(W, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZOW => new V4f(W, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZIO => new V4f(W, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZII => new V4f(W, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZPN => new V4f(W, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZIX => new V4f(W, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZIY => new V4f(W, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZIZ => new V4f(W, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZIW => new V4f(W, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZNO => new V4f(W, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZNP => new V4f(W, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZNN => new V4f(W, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZNX => new V4f(W, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZNY => new V4f(W, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZNZ => new V4f(W, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZNW => new V4f(W, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZXO => new V4f(W, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZXI => new V4f(W, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZXN => new V4f(W, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZXX => new V4f(W, Z, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f WZXY { readonly get => new V4f(W, Z, X, Y); set { W = value.X; Z = value.Y; X = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZXZ => new V4f(W, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZXW => new V4f(W, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZYO => new V4f(W, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZYI => new V4f(W, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZYN => new V4f(W, Z, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4f WZYX { readonly get => new V4f(W, Z, Y, X); set { W = value.X; Z = value.Y; Y = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZYY => new V4f(W, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZYZ => new V4f(W, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZYW => new V4f(W, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZZO => new V4f(W, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZZI => new V4f(W, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZZN => new V4f(W, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZZX => new V4f(W, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZZY => new V4f(W, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZZZ => new V4f(W, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZZW => new V4f(W, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZWO => new V4f(W, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZWI => new V4f(W, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZWN => new V4f(W, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZWX => new V4f(W, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZWY => new V4f(W, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZWZ => new V4f(W, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WZWW => new V4f(W, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWOO => new V4f(W, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWOI => new V4f(W, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWON => new V4f(W, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWOX => new V4f(W, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWOY => new V4f(W, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWOZ => new V4f(W, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWOW => new V4f(W, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWIO => new V4f(W, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWII => new V4f(W, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWPN => new V4f(W, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWIX => new V4f(W, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWIY => new V4f(W, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWIZ => new V4f(W, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWIW => new V4f(W, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWNO => new V4f(W, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWNP => new V4f(W, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWNN => new V4f(W, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWNX => new V4f(W, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWNY => new V4f(W, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWNZ => new V4f(W, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWNW => new V4f(W, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWXO => new V4f(W, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWXI => new V4f(W, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWXN => new V4f(W, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWXX => new V4f(W, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWXY => new V4f(W, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWXZ => new V4f(W, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWXW => new V4f(W, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWYO => new V4f(W, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWYI => new V4f(W, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWYN => new V4f(W, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWYX => new V4f(W, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWYY => new V4f(W, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWYZ => new V4f(W, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWYW => new V4f(W, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWZO => new V4f(W, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWZI => new V4f(W, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWZN => new V4f(W, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWZX => new V4f(W, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWZY => new V4f(W, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWZZ => new V4f(W, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWZW => new V4f(W, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWWO => new V4f(W, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWWI => new V4f(W, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWWN => new V4f(W, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWWX => new V4f(W, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWWY => new V4f(W, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWWZ => new V4f(W, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4f WWWW => new V4f(W, W, W, W); #endregion #region IVector Members /// /// By using long indices, the IVector<double> interface is /// accessed. /// public double this[long i] { readonly get { return (double)this[(int)i]; } set { this[(int)i] = (float)value; } } #endregion #region ISize4f Members public readonly V4f Size4f { get { return this; } } #endregion #region IVector public readonly long Dim { get { return 4; } } public readonly object GetValue(long index) { return (object)this[(int)index]; } public void SetValue(object value, long index) { this[(int)index] = (float)value; } #endregion } public class V4fEqualityComparer : IEqualityComparer { public static V4fEqualityComparer Default => new V4fEqualityComparer(); #region IEqualityComparer Members public bool Equals(V4f v0, V4f v1) { return v0 == v1; } public int GetHashCode(V4f v) { return v.GetHashCode(); } #endregion } public static partial class Fun { #region Min and Max /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Min(this V4f a, V4f b) { return new V4f(Min(a.X, b.X), Min(a.Y, b.Y), Min(a.Z, b.Z), Min(a.W, b.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Min(this V4f a, float b) { return new V4f(Min(a.X, b), Min(a.Y, b), Min(a.Z, b), Min(a.W, b)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Min(this float a, V4f b) { return new V4f(Min(a, b.X), Min(a, b.Y), Min(a, b.Z), Min(a, b.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Max(this V4f a, V4f b) { return new V4f(Max(a.X, b.X), Max(a.Y, b.Y), Max(a.Z, b.Z), Max(a.W, b.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Max(this V4f a, float b) { return new V4f(Max(a.X, b), Max(a.Y, b), Max(a.Z, b), Max(a.W, b)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Max(this float a, V4f b) { return new V4f(Max(a, b.X), Max(a, b.Y), Max(a, b.Z), Max(a, b.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Min(this V4f a, V4f b, V4f c) { return new V4f(Min(a.X, b.X, c.X), Min(a.Y, b.Y, c.Y), Min(a.Z, b.Z, c.Z), Min(a.W, b.W, c.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Max(this V4f a, V4f b, V4f c) { return new V4f(Max(a.X, b.X, c.X), Max(a.Y, b.Y, c.Y), Max(a.Z, b.Z, c.Z), Max(a.W, b.W, c.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Min(this V4f a, V4f b, V4f c, V4f d) { return new V4f(Min(a.X, b.X, c.X, d.X), Min(a.Y, b.Y, c.Y, d.Y), Min(a.Z, b.Z, c.Z, d.Z), Min(a.W, b.W, c.W, d.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Max(this V4f a, V4f b, V4f c, V4f d) { return new V4f(Max(a.X, b.X, c.X, d.X), Max(a.Y, b.Y, c.Y, d.Y), Max(a.Z, b.Z, c.Z, d.Z), Max(a.W, b.W, c.W, d.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Min(this V4f x, params V4f[] values) { return new V4f(Min(x.X, values.Map(a => a.X)), Min(x.Y, values.Map(a => a.Y)), Min(x.Z, values.Map(a => a.Z)), Min(x.W, values.Map(a => a.W))); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Max(this V4f x, params V4f[] values) { return new V4f(Max(x.X, values.Map(a => a.X)), Max(x.Y, values.Map(a => a.Y)), Max(x.Z, values.Map(a => a.Z)), Max(x.W, values.Map(a => a.W))); } #endregion #region Abs /// /// Applies Fun.Abs to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Abs(this V4f x) { return new V4f(Abs(x.X), Abs(x.Y), Abs(x.Z), Abs(x.W)); } #endregion #region Rounding /// /// Applies Fun.Floor to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Floor(this V4f x) { return new V4f(Floor(x.X), Floor(x.Y), Floor(x.Z), Floor(x.W)); } /// /// Applies Fun.Ceiling to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Ceiling(this V4f x) { return new V4f(Ceiling(x.X), Ceiling(x.Y), Ceiling(x.Z), Ceiling(x.W)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Round(this V4f x) { return new V4f(Round(x.X), Round(x.Y), Round(x.Z), Round(x.W)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Round(this V4f x, MidpointRounding mode) { return new V4f(Round(x.X, mode), Round(x.Y, mode), Round(x.Z, mode), Round(x.W, mode)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Round(this V4f x, int digits) { return new V4f(Round(x.X, digits), Round(x.Y, digits), Round(x.Z, digits), Round(x.W, digits)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Round(this V4f x, int digits, MidpointRounding mode) { return new V4f(Round(x.X, digits, mode), Round(x.Y, digits, mode), Round(x.Z, digits, mode), Round(x.W, digits, mode)); } /// /// Applies Fun.Truncate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Truncate(this V4f x) { return new V4f(Truncate(x.X), Truncate(x.Y), Truncate(x.Z), Truncate(x.W)); } #endregion #region Frac /// /// Applies Fun.Frac to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Frac(this V4f x) { return new V4f(Frac(x.X), Frac(x.Y), Frac(x.Z), Frac(x.W)); } #endregion #region Clamping /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Clamp(this V4f x, V4f a, V4f b) { return new V4f(Clamp(x.X, a.X, b.X), Clamp(x.Y, a.Y, b.Y), Clamp(x.Z, a.Z, b.Z), Clamp(x.W, a.W, b.W)); } /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Clamp(this V4f x, float a, float b) { return new V4f(Clamp(x.X, a, b), Clamp(x.Y, a, b), Clamp(x.Z, a, b), Clamp(x.W, a, b)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f ClampWrap(this V4f x, V4f a, V4f b) { return new V4f(ClampWrap(x.X, a.X, b.X), ClampWrap(x.Y, a.Y, b.Y), ClampWrap(x.Z, a.Z, b.Z), ClampWrap(x.W, a.W, b.W)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f ClampWrap(this V4f x, float a, float b) { return new V4f(ClampWrap(x.X, a, b), ClampWrap(x.Y, a, b), ClampWrap(x.Z, a, b), ClampWrap(x.W, a, b)); } /// /// Applies Fun.Saturate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Saturate(this V4f x) { return new V4f(Saturate(x.X), Saturate(x.Y), Saturate(x.Z), Saturate(x.W)); } #endregion #region MapToUnitInterval /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f MapToUnitInterval(this V4f t, V4f tMax, bool repeat, bool mirror) { return new V4f(MapToUnitInterval(t.X, tMax.X, repeat, mirror), MapToUnitInterval(t.Y, tMax.Y, repeat, mirror), MapToUnitInterval(t.Z, tMax.Z, repeat, mirror), MapToUnitInterval(t.W, tMax.W, repeat, mirror)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f MapToUnitInterval(this V4f t, V4f tMax, bool repeat) { return new V4f(MapToUnitInterval(t.X, tMax.X, repeat), MapToUnitInterval(t.Y, tMax.Y, repeat), MapToUnitInterval(t.Z, tMax.Z, repeat), MapToUnitInterval(t.W, tMax.W, repeat)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f MapToUnitInterval(this V4f t, V4f tMax) { return new V4f(MapToUnitInterval(t.X, tMax.X), MapToUnitInterval(t.Y, tMax.Y), MapToUnitInterval(t.Z, tMax.Z), MapToUnitInterval(t.W, tMax.W)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f MapToUnitInterval(this V4f t, V4f tMin, V4f tMax) { return new V4f(MapToUnitInterval(t.X, tMin.X, tMax.X), MapToUnitInterval(t.Y, tMin.Y, tMax.Y), MapToUnitInterval(t.Z, tMin.Z, tMax.Z), MapToUnitInterval(t.W, tMin.W, tMax.W)); } #endregion #region Sign /// /// Applies Fun.Sign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Sign(this V4f x) { return new V4i(Sign(x.X), Sign(x.Y), Sign(x.Z), Sign(x.W)); } /// /// Applies Fun.Signumi to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Signumi(this V4f x) { return new V4i(Signumi(x.X), Signumi(x.Y), Signumi(x.Z), Signumi(x.W)); } /// /// Applies Fun.Signum to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Signum(this V4f x) { return new V4f(Signum(x.X), Signum(x.Y), Signum(x.Z), Signum(x.W)); } #endregion #region Multiply-Add /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f MultiplyAdd(V4f x, V4f y, V4f z) { return new V4f(MultiplyAdd(x.X, y.X, z.X), MultiplyAdd(x.Y, y.Y, z.Y), MultiplyAdd(x.Z, y.Z, z.Z), MultiplyAdd(x.W, y.W, z.W)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f MultiplyAdd(V4f x, float y, V4f z) { return new V4f(MultiplyAdd(x.X, y, z.X), MultiplyAdd(x.Y, y, z.Y), MultiplyAdd(x.Z, y, z.Z), MultiplyAdd(x.W, y, z.W)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f MultiplyAdd(float x, V4f y, V4f z) { return new V4f(MultiplyAdd(x, y.X, z.X), MultiplyAdd(x, y.Y, z.Y), MultiplyAdd(x, y.Z, z.Z), MultiplyAdd(x, y.W, z.W)); } #endregion #region Copy sign /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f CopySign(V4f value, V4f sign) { return new V4f(CopySign(value.X, sign.X), CopySign(value.Y, sign.Y), CopySign(value.Z, sign.Z), CopySign(value.W, sign.W)); } /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f CopySign(float value, V4f sign) { return new V4f(CopySign(value, sign.X), CopySign(value, sign.Y), CopySign(value, sign.Z), CopySign(value, sign.W)); } /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f CopySign(V4f value, float sign) { return new V4f(CopySign(value.X, sign), CopySign(value.Y, sign), CopySign(value.Z, sign), CopySign(value.W, sign)); } #endregion #region Roots /// /// Applies Fun.Sqrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Sqrt(this V4f x) { return new V4f(Sqrt(x.X), Sqrt(x.Y), Sqrt(x.Z), Sqrt(x.W)); } /// /// Applies Fun.Cbrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Cbrt(this V4f x) { return new V4f(Cbrt(x.X), Cbrt(x.Y), Cbrt(x.Z), Cbrt(x.W)); } #endregion #region Square /// /// Applies Fun.Square to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Square(this V4f x) { return new V4f(Square(x.X), Square(x.Y), Square(x.Z), Square(x.W)); } #endregion #region Power /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Pown(this V4f x, V4i y) { return new V4f(Pown(x.X, y.X), Pown(x.Y, y.Y), Pown(x.Z, y.Z), Pown(x.W, y.W)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Pown(this V4f x, int y) { return new V4f(Pown(x.X, y), Pown(x.Y, y), Pown(x.Z, y), Pown(x.W, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Pown(this float x, V4i y) { return new V4f(Pown(x, y.X), Pown(x, y.Y), Pown(x, y.Z), Pown(x, y.W)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Pow(this V4f x, V4f y) { return new V4f(Pow(x.X, y.X), Pow(x.Y, y.Y), Pow(x.Z, y.Z), Pow(x.W, y.W)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Pow(this V4f x, float y) { return new V4f(Pow(x.X, y), Pow(x.Y, y), Pow(x.Z, y), Pow(x.W, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Pow(this float x, V4f y) { return new V4f(Pow(x, y.X), Pow(x, y.Y), Pow(x, y.Z), Pow(x, y.W)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Power(this V4f x, V4f y) { return new V4f(Power(x.X, y.X), Power(x.Y, y.Y), Power(x.Z, y.Z), Power(x.W, y.W)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Power(this V4f x, float y) { return new V4f(Power(x.X, y), Power(x.Y, y), Power(x.Z, y), Power(x.W, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Power(this float x, V4f y) { return new V4f(Power(x, y.X), Power(x, y.Y), Power(x, y.Z), Power(x, y.W)); } #endregion #region Exp and Log /// /// Applies Fun.Exp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Exp(this V4f x) { return new V4f(Exp(x.X), Exp(x.Y), Exp(x.Z), Exp(x.W)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Log(this V4f x) { return new V4f(Log(x.X), Log(x.Y), Log(x.Z), Log(x.W)); } /// /// Applies Fun.Log2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Log2(this V4f x) { return new V4f(Log2(x.X), Log2(x.Y), Log2(x.Z), Log2(x.W)); } /// /// Applies Fun.Log2Int to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Log2Int(this V4f x) { return new V4i(Log2Int(x.X), Log2Int(x.Y), Log2Int(x.Z), Log2Int(x.W)); } /// /// Applies Fun.Log10 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Log10(this V4f x) { return new V4f(Log10(x.X), Log10(x.Y), Log10(x.Z), Log10(x.W)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Log(this V4f x, float basis) { return new V4f(Log(x.X, basis), Log(x.Y, basis), Log(x.Z, basis), Log(x.W, basis)); } #endregion #region ModP /// /// Applies Fun.ModP to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f ModP(this V4f a, V4f b) { return new V4f(ModP(a.X, b.X), ModP(a.Y, b.Y), ModP(a.Z, b.Z), ModP(a.W, b.W)); } #endregion #region Power of Two /// /// Applies Fun.PowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f PowerOfTwo(this V4f x) { return new V4f(PowerOfTwo(x.X), PowerOfTwo(x.Y), PowerOfTwo(x.Z), PowerOfTwo(x.W)); } #endregion #region Trigonometry /// /// Applies Fun.Sin to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Sin(this V4f x) { return new V4f(Sin(x.X), Sin(x.Y), Sin(x.Z), Sin(x.W)); } /// /// Applies Fun.Cos to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Cos(this V4f x) { return new V4f(Cos(x.X), Cos(x.Y), Cos(x.Z), Cos(x.W)); } /// /// Applies Fun.Tan to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Tan(this V4f x) { return new V4f(Tan(x.X), Tan(x.Y), Tan(x.Z), Tan(x.W)); } /// /// Applies Fun.Asin to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Asin(this V4f x) { return new V4f(Asin(x.X), Asin(x.Y), Asin(x.Z), Asin(x.W)); } /// /// Applies Fun.AsinClamped to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f AsinClamped(this V4f x) { return new V4f(AsinClamped(x.X), AsinClamped(x.Y), AsinClamped(x.Z), AsinClamped(x.W)); } /// /// Applies Fun.Acos to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Acos(this V4f x) { return new V4f(Acos(x.X), Acos(x.Y), Acos(x.Z), Acos(x.W)); } /// /// Applies Fun.AcosClamped to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f AcosClamped(this V4f x) { return new V4f(AcosClamped(x.X), AcosClamped(x.Y), AcosClamped(x.Z), AcosClamped(x.W)); } /// /// Applies Fun.Atan to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Atan(this V4f x) { return new V4f(Atan(x.X), Atan(x.Y), Atan(x.Z), Atan(x.W)); } /// /// Applies Fun.Atan2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Atan2(V4f y, V4f x) { return new V4f(Atan2(y.X, x.X), Atan2(y.Y, x.Y), Atan2(y.Z, x.Z), Atan2(y.W, x.W)); } /// /// Applies Fun.FastAtan2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f FastAtan2(V4f y, V4f x) { return new V4f(FastAtan2(y.X, x.X), FastAtan2(y.Y, x.Y), FastAtan2(y.Z, x.Z), FastAtan2(y.W, x.W)); } /// /// Applies Fun.Sinh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Sinh(this V4f x) { return new V4f(Sinh(x.X), Sinh(x.Y), Sinh(x.Z), Sinh(x.W)); } /// /// Applies Fun.Cosh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Cosh(this V4f x) { return new V4f(Cosh(x.X), Cosh(x.Y), Cosh(x.Z), Cosh(x.W)); } /// /// Applies Fun.Tanh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Tanh(this V4f x) { return new V4f(Tanh(x.X), Tanh(x.Y), Tanh(x.Z), Tanh(x.W)); } /// /// Applies Fun.Asinh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Asinh(this V4f x) { return new V4f(Asinh(x.X), Asinh(x.Y), Asinh(x.Z), Asinh(x.W)); } /// /// Applies Fun.Acosh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Acosh(this V4f x) { return new V4f(Acosh(x.X), Acosh(x.Y), Acosh(x.Z), Acosh(x.W)); } /// /// Applies Fun.Atanh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Atanh(this V4f x) { return new V4f(Atanh(x.X), Atanh(x.Y), Atanh(x.Z), Atanh(x.W)); } #endregion #region Step functions /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Step(this V4f x, V4f edge) { return new V4f(Step(x.X, edge.X), Step(x.Y, edge.Y), Step(x.Z, edge.Z), Step(x.W, edge.W)); } /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Step(this V4f x, float edge) { return new V4f(Step(x.X, edge), Step(x.Y, edge), Step(x.Z, edge), Step(x.W, edge)); } /// /// Applies Fun.Linearstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Linearstep(this V4f x, V4f edge0, V4f edge1) { return new V4f(Linearstep(x.X, edge0.X, edge1.X), Linearstep(x.Y, edge0.Y, edge1.Y), Linearstep(x.Z, edge0.Z, edge1.Z), Linearstep(x.W, edge0.W, edge1.W)); } /// /// Applies Fun.Linearstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Linearstep(this V4f x, float edge0, float edge1) { return new V4f(Linearstep(x.X, edge0, edge1), Linearstep(x.Y, edge0, edge1), Linearstep(x.Z, edge0, edge1), Linearstep(x.W, edge0, edge1)); } /// /// Applies Fun.Smoothstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Smoothstep(this V4f x, V4f edge0, V4f edge1) { return new V4f(Smoothstep(x.X, edge0.X, edge1.X), Smoothstep(x.Y, edge0.Y, edge1.Y), Smoothstep(x.Z, edge0.Z, edge1.Z), Smoothstep(x.W, edge0.W, edge1.W)); } /// /// Applies Fun.Smoothstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Smoothstep(this V4f x, float edge0, float edge1) { return new V4f(Smoothstep(x.X, edge0, edge1), Smoothstep(x.Y, edge0, edge1), Smoothstep(x.Z, edge0, edge1), Smoothstep(x.W, edge0, edge1)); } #endregion #region Interpolation /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Lerp(this float t, V4f a, V4f b) { return new V4f(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y), Lerp(t, a.Z, b.Z), Lerp(t, a.W, b.W)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Lerp(this V4f t, V4f a, V4f b) { return new V4f(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y), Lerp(t.Z, a.Z, b.Z), Lerp(t.W, a.W, b.W)); } /// /// Applies Fun.InvLerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f InvLerp(this V4f y, V4f a, V4f b) { return new V4f(InvLerp(y.X, a.X, b.X), InvLerp(y.Y, a.Y, b.Y), InvLerp(y.Z, a.Z, b.Z), InvLerp(y.W, a.W, b.W)); } #endregion #region Floating point bits /// /// Applies Fun.FloatToBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i FloatToBits(this V4f x) { return new V4i(FloatToBits(x.X), FloatToBits(x.Y), FloatToBits(x.Z), FloatToBits(x.W)); } /// /// Applies Fun.FloatToUnsignedBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4ui FloatToUnsignedBits(this V4f x) { return new V4ui(FloatToUnsignedBits(x.X), FloatToUnsignedBits(x.Y), FloatToUnsignedBits(x.Z), FloatToUnsignedBits(x.W)); } #endregion #region ApproximateEquals /// /// Returns whether the given vectors are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V4f a, V4f b, float tolerance) { return ApproximateEquals(a.X, b.X, tolerance) && ApproximateEquals(a.Y, b.Y, tolerance) && ApproximateEquals(a.Z, b.Z, tolerance) && ApproximateEquals(a.W, b.W, tolerance); } /// /// Returns whether the given vectors are equal within /// Constant{float}.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V4f a, V4f b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this V4f v, float epsilon) => Vec.AllTiny(v, epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than Constant<float>.PositiveTinyValue. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(V4f v) => v.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any component of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(V4f v) => v.IsNaN; /// /// Returns whether any component of the the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(V4f v) => v.IsInfinity; /// /// Returns whether any component of the the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(V4f v) => v.IsPositiveInfinity; /// /// Returns whether any component of the the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(V4f v) => v.IsNegativeInfinity; /// /// Returns whether all components of the the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(V4f v) => v.IsFinite; #endregion } public static partial class Conversion { #region Angles (Radians, Degrees, Gons) /// /// Converts the angles given in degrees to radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f RadiansFromDegrees(this V4f degrees) => new V4f( RadiansFromDegrees(degrees.X), RadiansFromDegrees(degrees.Y), RadiansFromDegrees(degrees.Z), RadiansFromDegrees(degrees.W) ); /// /// Converts the angles given in gons to radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f RadiansFromGons(this V4f gons) => new V4f( RadiansFromGons(gons.X), RadiansFromGons(gons.Y), RadiansFromGons(gons.Z), RadiansFromGons(gons.W) ); /// /// Converts the angles given in radians to degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f DegreesFromRadians(this V4f radians) => new V4f( DegreesFromRadians(radians.X), DegreesFromRadians(radians.Y), DegreesFromRadians(radians.Z), DegreesFromRadians(radians.W) ); /// /// Converts the angles given in gons to degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f DegreesFromGons(this V4f gons) => new V4f( DegreesFromGons(gons.X), DegreesFromGons(gons.Y), DegreesFromGons(gons.Z), DegreesFromGons(gons.W) ); /// /// Converts the angles given in radians to gons. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f GonsFromRadians(this V4f radians) => new V4f( GonsFromRadians(radians.X), GonsFromRadians(radians.Y), GonsFromRadians(radians.Z), GonsFromRadians(radians.W) ); /// /// Converts the angles given in degrees to gons. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f GonsFromDegrees(this V4f degrees) => new V4f( GonsFromDegrees(degrees.X), GonsFromDegrees(degrees.Y), GonsFromDegrees(degrees.Z), GonsFromDegrees(degrees.W) ); #endregion } /// /// Contains static methods /// public static partial class Vec { #region Length /// /// Returns the squared length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LengthSquared(V4f v) => v.LengthSquared; /// /// Returns the length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Length(V4f v) => v.Length; #endregion #region Normalize /// /// Normalizes the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref V4f v) { var s = v.Length; if (s == 0) return; s = 1 / s; v.X *= s; v.Y *= s; v.Z *= s; v.W *= s; } /// /// Returns a normalized copy of this vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Normalized(V4f v) => v.Normalized; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm1(V4f v) => v.Norm1; /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm2(V4f v) => v.Norm2; /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormMax(V4f v) => v.NormMax; /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float NormMin(V4f v) => v.NormMin; /// /// Gets the p-norm. This is calculated as the p-th root of (|x|^n + |y|^n + ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Norm(this V4f v, float p) { return ( Fun.Abs(v.X).Pow(p) + Fun.Abs(v.Y).Pow(p) + Fun.Abs(v.Z).Pow(p) + Fun.Abs(v.W).Pow(p)).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the squared distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceSquared(this V4f a, V4f b) => Fun.Square(b.X - a.X) + Fun.Square(b.Y - a.Y) + Fun.Square(b.Z - a.Z) + Fun.Square(b.W - a.W); /// /// Returns the distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance(this V4f a, V4f b) => Fun.Sqrt(DistanceSquared(a, b)); /// /// Returns the Manhatten (or 1-) distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance1(this V4f a, V4f b) => Fun.Abs(b.X - a.X) + Fun.Abs(b.Y - a.Y) + Fun.Abs(b.Z - a.Z) + Fun.Abs(b.W - a.W); /// /// Returns the p-distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance(this V4f a, V4f b, float p) => (Fun.Abs(b.X - a.X).Pow(p) + Fun.Abs(b.Y - a.Y).Pow(p) + Fun.Abs(b.Z - a.Z).Pow(p) + Fun.Abs(b.W - a.W).Pow(p)).Pow(1 / p); /// /// Returns the maximal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceMax(this V4f a, V4f b) => Fun.Max(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y), Fun.Abs(b.Z - a.Z), Fun.Abs(b.W - a.W)); /// /// Returns the minimal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceMin(this V4f a, V4f b) => Fun.Min(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y), Fun.Abs(b.Z - a.Z), Fun.Abs(b.W - a.W)); /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceToLine( this V4f query, V4f p0, V4f p1) { var p0p1 = p1 - p0; var p0q = query - p0; var t = Dot(p0q, p0p1); if (t <= 0) { return p0q.Length; } var denom = p0p1.LengthSquared; if (t >= denom) { return Distance(query, p1); } t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceToInfiniteLine( this V4f query, V4f p0, V4f p1) { var p0p1 = p1 - p0; var p0q = query - p0; var t = Dot(p0q, p0p1); var denom = p0p1.LengthSquared; t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceToLine( this V4f query, V4f p0, V4f p1, out float t) { var p0p1 = p1 - p0; var p0q = query - p0; t = Dot(p0q, p0p1); if (t <= 0) { t = 0; return p0q.Length; } var denom = p0p1.LengthSquared; if (t >= denom) { t = 1; return Distance(query, p1); } t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceToInfiniteLine( this V4f query, V4f p0, V4f p1, out float t) { var p0p1 = p1 - p0; var p0q = query - p0; t = Dot(p0q, p0p1); var denom = p0p1.LengthSquared; t /= denom; return (p0q - t * p0p1).Length; } #endregion #region Operations /// /// Gets a copy of the given vector containing the reciprocal (1/x) of each element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Reciprocal(V4f v) => v.Reciprocal; /// /// Negates the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Negate(this ref V4f v) { v.X = -v.X; v.Y = -v.Y; v.Z = -v.Z; v.W = -v.W; } /// /// Returns the outer product (tensor-product) of a * b^T as a 4x4 matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44f Outer(this V4f a, V4f b) { return new M44f( a.X * b.X, a.X * b.Y, a.X * b.Z, a.X * b.W, a.Y * b.X, a.Y * b.Y, a.Y * b.Z, a.Y * b.W, a.Z * b.X, a.Z * b.Y, a.Z * b.Z, a.Z * b.W, a.W * b.X, a.W * b.Y, a.W * b.Z, a.W * b.W); } /// /// Returns the dot product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot(this V4f a, V4f b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z + a.W * b.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DirFlags DirFlags(this V4f v) { DirFlags flags = Aardbase.DirFlags.None; if (v.X > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveX; if (v.X < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeX; if (v.Y > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveY; if (v.Y < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeY; if (v.Z > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveZ; if (v.Z < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeZ; if (v.W > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveW; if (v.W < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeW; return flags; } /// /// Returns the reflection direction of the given vector v (pointing to the surface) for the given normal (should be normalized). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Reflect(this V4f v, V4f normal) { return v - 2 * v.Dot(normal) * normal; } /// /// Returns the refraction direction of the given vector v (pointing to the surface) for the given normal and ratio of refraction indices (n_out / n_in). /// Both the input vectors should be normalized. /// Returns a zero-vector in case of total internal reflection. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f Refract(this V4f v, V4f normal, float eta) { var t = v.Dot(normal); var k = 1 - eta * eta * (1 - t * t); if (k < 0) { return V4f.Zero; } else { return eta * v - (eta * t + Fun.Sqrt(k)) * normal; } } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V4f a, V4f b) { return (a.X < b.X && a.Y < b.Y && a.Z < b.Z && a.W < b.W); } /// /// Returns whether ALL elements of v are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V4f v, float s) { return (v.X < s && v.Y < s && v.Z < s && v.W < s); } /// /// Returns whether a is Smaller ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(float s, V4f v) { return (s < v.X && s < v.Y && s < v.Z && s < v.W); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V4f a, V4f b) { return (a.X < b.X || a.Y < b.Y || a.Z < b.Z || a.W < b.W); } /// /// Returns whether AT LEAST ONE element of v is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V4f v, float s) { return (v.X < s || v.Y < s || v.Z < s || v.W < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(float s, V4f v) { return (s < v.X || s < v.Y || s < v.Z || s < v.W); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V4f a, V4f b) { return (a.X > b.X && a.Y > b.Y && a.Z > b.Z && a.W > b.W); } /// /// Returns whether ALL elements of v are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V4f v, float s) { return (v.X > s && v.Y > s && v.Z > s && v.W > s); } /// /// Returns whether a is Greater ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(float s, V4f v) { return (s > v.X && s > v.Y && s > v.Z && s > v.W); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V4f a, V4f b) { return (a.X > b.X || a.Y > b.Y || a.Z > b.Z || a.W > b.W); } /// /// Returns whether AT LEAST ONE element of v is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V4f v, float s) { return (v.X > s || v.Y > s || v.Z > s || v.W > s); } /// /// Returns whether a is Greater AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(float s, V4f v) { return (s > v.X || s > v.Y || s > v.Z || s > v.W); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V4f a, V4f b) { return (a.X <= b.X && a.Y <= b.Y && a.Z <= b.Z && a.W <= b.W); } /// /// Returns whether ALL elements of v are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V4f v, float s) { return (v.X <= s && v.Y <= s && v.Z <= s && v.W <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(float s, V4f v) { return (s <= v.X && s <= v.Y && s <= v.Z && s <= v.W); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V4f a, V4f b) { return (a.X <= b.X || a.Y <= b.Y || a.Z <= b.Z || a.W <= b.W); } /// /// Returns whether AT LEAST ONE element of v is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V4f v, float s) { return (v.X <= s || v.Y <= s || v.Z <= s || v.W <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(float s, V4f v) { return (s <= v.X || s <= v.Y || s <= v.Z || s <= v.W); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V4f a, V4f b) { return (a.X >= b.X && a.Y >= b.Y && a.Z >= b.Z && a.W >= b.W); } /// /// Returns whether ALL elements of v are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V4f v, float s) { return (v.X >= s && v.Y >= s && v.Z >= s && v.W >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(float s, V4f v) { return (s >= v.X && s >= v.Y && s >= v.Z && s >= v.W); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V4f a, V4f b) { return (a.X >= b.X || a.Y >= b.Y || a.Z >= b.Z || a.W >= b.W); } /// /// Returns whether AT LEAST ONE element of v is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V4f v, float s) { return (v.X >= s || v.Y >= s || v.Z >= s || v.W >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(float s, V4f v) { return (s >= v.X || s >= v.Y || s >= v.Z || s >= v.W); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V4f a, V4f b) { return (a.X == b.X && a.Y == b.Y && a.Z == b.Z && a.W == b.W); } /// /// Returns whether ALL elements of v are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V4f v, float s) { return (v.X == s && v.Y == s && v.Z == s && v.W == s); } /// /// Returns whether a is Equal ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(float s, V4f v) { return (s == v.X && s == v.Y && s == v.Z && s == v.W); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V4f a, V4f b) { return (a.X == b.X || a.Y == b.Y || a.Z == b.Z || a.W == b.W); } /// /// Returns whether AT LEAST ONE element of v is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V4f v, float s) { return (v.X == s || v.Y == s || v.Z == s || v.W == s); } /// /// Returns whether a is Equal AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(float s, V4f v) { return (s == v.X || s == v.Y || s == v.Z || s == v.W); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V4f a, V4f b) { return (a.X != b.X && a.Y != b.Y && a.Z != b.Z && a.W != b.W); } /// /// Returns whether ALL elements of v are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V4f v, float s) { return (v.X != s && v.Y != s && v.Z != s && v.W != s); } /// /// Returns whether a is Different ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(float s, V4f v) { return (s != v.X && s != v.Y && s != v.Z && s != v.W); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V4f a, V4f b) { return (a.X != b.X || a.Y != b.Y || a.Z != b.Z || a.W != b.W); } /// /// Returns whether AT LEAST ONE element of v is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V4f v, float s) { return (v.X != s || v.Y != s || v.Z != s || v.W != s); } /// /// Returns whether a is Different AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(float s, V4f v) { return (s != v.X || s != v.Y || s != v.Z || s != v.W); } /// /// Compare x-coordinate before y-coordinate, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this V4f v0, V4f v1) { if (v0.X < v1.X) return -1; if (v0.X > v1.X) return +1; if (v0.Y < v1.Y) return -1; if (v0.Y > v1.Y) return +1; if (v0.Z < v1.Z) return -1; if (v0.Z > v1.Z) return +1; if (v0.W < v1.W) return -1; if (v0.W > v1.W) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MinElement(V4f v) => v.MinElement; /// /// Returns the maximum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float MaxElement(V4f v) => v.MaxElement; #endregion #region Angle between two vectors /// /// Computes the angle between two given vectors in radians. The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float AngleBetweenFast(this V4f x, V4f y) { return Fun.AcosClamped(x.Dot(y)); } /// /// Computes the angle between two given vectors in radians using a numerically stable algorithm. /// The input vectors have to be normalized. /// // https://scicomp.stackexchange.com/a/27769 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float AngleBetween(this V4f x, V4f y) { var a = x + y; var b = x - y; return 2 * Fun.Atan2(b.Length, a.Length); } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this V4f v, float epsilon) => v.X.IsTiny(epsilon) || v.Y.IsTiny(epsilon) || v.Z.IsTiny(epsilon) || v.W.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this V4f v, float epsilon) => v.X.IsTiny(epsilon) && v.Y.IsTiny(epsilon) && v.Z.IsTiny(epsilon) && v.W.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyFinite(V4f v) => v.AnyFinite; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllFinite(V4f v) => v.AllFinite; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(V4f v) => v.AnyNaN; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(V4f v) => v.AllNaN; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(V4f v) => v.AnyInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(V4f v) => v.AllInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(V4f v) => v.AnyPositiveInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(V4f v) => v.AllPositiveInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(V4f v) => v.AnyNegativeInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(V4f v) => v.AllNegativeInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(V4f v) => v.AnyTiny; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(V4f v) => v.AllTiny; #endregion #region Linear Combination [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f LinCom(V4f p0, V4f p1, ref Tup2 w) { return p0 * w.E0 + p1 * w.E1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f LinCom(V4f p0, V4f p1, V4f p2, ref Tup3 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f LinCom(V4f p0, V4f p1, V4f p2, V4f p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f LinCom(V4f p0, V4f p1, V4f p2, V4f p3, V4f p4, ref Tup5 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f LinCom(V4f p0, V4f p1, V4f p2, V4f p3, V4f p4, V4f p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f LinCom(V4f p0, V4f p1, V4f p2, V4f p3, V4f p4, V4f p5, V4f p6, ref Tup7 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5 + p6 * w.E6; } #endregion #region ArrayExtensions public static int IndexOfClosestPoint(this V4f[] pointArray, V4f point) { var bestDist = DistanceSquared(point, pointArray[0]); int bestIndex = 0; int count = pointArray.Length; for (int i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this V4f[] array, int start, int count, V4f point) { var bestDist = DistanceSquared(point, array[start]); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this T[] array, int start, int count, Func pointSelector, V4f point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint(this V4f[] pointArray, V4f point) { var bestDist = DistanceSquared(point, pointArray[0]); long bestIndex = 0; long count = pointArray.LongLength; for (long i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this V4f[] array, long start, long count, V4f point) { var bestDist = DistanceSquared(point, array[start]); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this T[] array, long start, long count, Func pointSelector, V4f point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static int IndexOfMinX(this V4f[] vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static long LongIndexOfMinX(this V4f[] vectorArray, long count = 0) { var minimum = vectorArray[0].X; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static int IndexOfMaxX(this V4f[] vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static long LongIndexOfMaxX(this V4f[] vectorArray, long count = 0) { var maximum = vectorArray[0].X; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static int IndexOfMinY(this V4f[] vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static long LongIndexOfMinY(this V4f[] vectorArray, long count = 0) { var minimum = vectorArray[0].Y; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static int IndexOfMaxY(this V4f[] vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static long LongIndexOfMaxY(this V4f[] vectorArray, long count = 0) { var maximum = vectorArray[0].Y; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static int IndexOfMinZ(this V4f[] vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static long LongIndexOfMinZ(this V4f[] vectorArray, long count = 0) { var minimum = vectorArray[0].Z; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static int IndexOfMaxZ(this V4f[] vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static long LongIndexOfMaxZ(this V4f[] vectorArray, long count = 0) { var maximum = vectorArray[0].Z; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal W coordinate /// within the array. /// public static int IndexOfMinW(this V4f[] vectorArray, int count = 0) { var minimum = vectorArray[0].W; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal W coordinate /// within the array. /// public static long LongIndexOfMinW(this V4f[] vectorArray, long count = 0) { var minimum = vectorArray[0].W; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].W; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal W coordinate /// within the array. /// public static int IndexOfMaxW(this V4f[] vectorArray, int count = 0) { var maximum = vectorArray[0].W; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal W coordinate /// within the array. /// public static long LongIndexOfMaxW(this V4f[] vectorArray, long count = 0) { var maximum = vectorArray[0].W; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].W; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the list. /// public static int IndexOfMinX(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the list. /// public static int IndexOfMaxX(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the list. /// public static int IndexOfMinY(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the list. /// public static int IndexOfMaxY(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the list. /// public static int IndexOfMinZ(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the list. /// public static int IndexOfMaxZ(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal W coordinate /// within the list. /// public static int IndexOfMinW(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].W; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal W coordinate /// within the list. /// public static int IndexOfMaxW(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].W; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the array of the index-th coordinate of each vector. /// public static float[] CopyCoord(this V4f[] self, int index) { switch (index) { case 0: return self.Map(v => v.X); case 1: return self.Map(v => v.Y); case 2: return self.Map(v => v.Z); case 3: return self.Map(v => v.W); default: throw new IndexOutOfRangeException(); } } public static V4f WeightedSum( this V4f[] vectorArray, float[] weightArray) { var r = V4f.Zero; var count = vectorArray.LongLength; for (long i = 0; i < count; i++) r += vectorArray[i] * weightArray[i]; return r; } #endregion } public static class IRandomUniformV4fExtensions { #region IRandomUniform extensions for V4f /// /// Uses UniformFloat() to generate the elements of a V4f vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f UniformV4f(this IRandomUniform rnd) { return new V4f(rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat(), rnd.UniformFloat()); } /// /// Uses UniformFloatClosed() to generate the elements of a V4f vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f UniformV4fClosed(this IRandomUniform rnd) { return new V4f(rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed(), rnd.UniformFloatClosed()); } /// /// Uses UniformFloatOpen() to generate the elements of a V4f vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4f UniformV4fOpen(this IRandomUniform rnd) { return new V4f(rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen(), rnd.UniformFloatOpen()); } #endregion } #endregion #region V4d [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct V4d : IVector, ISize4d, IFormattable, IEquatable { [DataMember] public double X; [DataMember] public double Y; [DataMember] public double Z; [DataMember] public double W; #region Constructors /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(int x, int y, int z, int w) { X = (double)x; Y = (double)y; Z = (double)z; W = (double)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(int v) { X = (double)v; Y = (double)v; Z = (double)v; W = (double)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(int[] a) { X = (double)a[0]; Y = (double)a[1]; Z = (double)a[2]; W = (double)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(int[] a, int start) { X = (double)a[start + 0]; Y = (double)a[start + 1]; Z = (double)a[start + 2]; W = (double)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(int a, V3i b) { X = (double)a; Y = (double)b.X; Z = (double)b.Y; W = (double)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V2i a, V2i b) { X = (double)a.X; Y = (double)a.Y; Z = (double)b.X; W = (double)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V3i a, int b) { X = (double)a.X; Y = (double)a.Y; Z = (double)a.Z; W = (double)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V2i a, int b, int c) { X = (double)a.X; Y = (double)a.Y; Z = (double)b; W = (double)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(int a, V2i b, int c) { X = (double)a; Y = (double)b.X; Z = (double)b.Y; W = (double)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(int a, int b, V2i c) { X = (double)a; Y = (double)b; Z = (double)c.X; W = (double)c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(uint x, uint y, uint z, uint w) { X = (double)x; Y = (double)y; Z = (double)z; W = (double)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(uint v) { X = (double)v; Y = (double)v; Z = (double)v; W = (double)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(uint[] a) { X = (double)a[0]; Y = (double)a[1]; Z = (double)a[2]; W = (double)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(uint[] a, int start) { X = (double)a[start + 0]; Y = (double)a[start + 1]; Z = (double)a[start + 2]; W = (double)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(uint a, V3ui b) { X = (double)a; Y = (double)b.X; Z = (double)b.Y; W = (double)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V2ui a, V2ui b) { X = (double)a.X; Y = (double)a.Y; Z = (double)b.X; W = (double)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V3ui a, uint b) { X = (double)a.X; Y = (double)a.Y; Z = (double)a.Z; W = (double)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V2ui a, uint b, uint c) { X = (double)a.X; Y = (double)a.Y; Z = (double)b; W = (double)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(uint a, V2ui b, uint c) { X = (double)a; Y = (double)b.X; Z = (double)b.Y; W = (double)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(uint a, uint b, V2ui c) { X = (double)a; Y = (double)b; Z = (double)c.X; W = (double)c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(long x, long y, long z, long w) { X = (double)x; Y = (double)y; Z = (double)z; W = (double)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(long v) { X = (double)v; Y = (double)v; Z = (double)v; W = (double)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(long[] a) { X = (double)a[0]; Y = (double)a[1]; Z = (double)a[2]; W = (double)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(long[] a, int start) { X = (double)a[start + 0]; Y = (double)a[start + 1]; Z = (double)a[start + 2]; W = (double)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(long a, V3l b) { X = (double)a; Y = (double)b.X; Z = (double)b.Y; W = (double)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V2l a, V2l b) { X = (double)a.X; Y = (double)a.Y; Z = (double)b.X; W = (double)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V3l a, long b) { X = (double)a.X; Y = (double)a.Y; Z = (double)a.Z; W = (double)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V2l a, long b, long c) { X = (double)a.X; Y = (double)a.Y; Z = (double)b; W = (double)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(long a, V2l b, long c) { X = (double)a; Y = (double)b.X; Z = (double)b.Y; W = (double)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(long a, long b, V2l c) { X = (double)a; Y = (double)b; Z = (double)c.X; W = (double)c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(float x, float y, float z, float w) { X = (double)x; Y = (double)y; Z = (double)z; W = (double)w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(float v) { X = (double)v; Y = (double)v; Z = (double)v; W = (double)v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(float[] a) { X = (double)a[0]; Y = (double)a[1]; Z = (double)a[2]; W = (double)a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(float[] a, int start) { X = (double)a[start + 0]; Y = (double)a[start + 1]; Z = (double)a[start + 2]; W = (double)a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(float a, V3f b) { X = (double)a; Y = (double)b.X; Z = (double)b.Y; W = (double)b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V2f a, V2f b) { X = (double)a.X; Y = (double)a.Y; Z = (double)b.X; W = (double)b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V3f a, float b) { X = (double)a.X; Y = (double)a.Y; Z = (double)a.Z; W = (double)b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V2f a, float b, float c) { X = (double)a.X; Y = (double)a.Y; Z = (double)b; W = (double)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(float a, V2f b, float c) { X = (double)a; Y = (double)b.X; Z = (double)b.Y; W = (double)c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(float a, float b, V2f c) { X = (double)a; Y = (double)b; Z = (double)c.X; W = (double)c.Y; } /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(double x, double y, double z, double w) { X = x; Y = y; Z = z; W = w; } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(double v) { X = v; Y = v; Z = v; W = v; } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(double[] a) { X = a[0]; Y = a[1]; Z = a[2]; W = a[3]; } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(double[] a, int start) { X = a[start + 0]; Y = a[start + 1]; Z = a[start + 2]; W = a[start + 3]; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(double a, V3d b) { X = a; Y = b.X; Z = b.Y; W = b.Z; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V2d a, V2d b) { X = a.X; Y = a.Y; Z = b.X; W = b.Y; } /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V3d a, double b) { X = a.X; Y = a.Y; Z = a.Z; W = b; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V2d a, double b, double c) { X = a.X; Y = a.Y; Z = b; W = c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(double a, V2d b, double c) { X = a; Y = b.X; Z = b.Y; W = c; } /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(double a, double b, V2d c) { X = a; Y = b; Z = c.X; W = c.Y; } /// /// Creates a vector from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(Func index_fun) { X = index_fun(0); Y = index_fun(1); Z = index_fun(2); W = index_fun(3); } /// /// Creates a vector from a general vector implementing the IVector<double> interface. /// The caller has to verify that the dimension of is at least 4. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(IVector v) : this(v[0], v[1], v[2], v[3]) { } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V2i v) { X = (double)v.X; Y = (double)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V2ui v) { X = (double)v.X; Y = (double)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V2l v) { X = (double)v.X; Y = (double)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V2f v) { X = (double)v.X; Y = (double)v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// Z, W are set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V2d v) { X = v.X; Y = v.Y; Z = 0; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V3i v) { X = (double)v.X; Y = (double)v.Y; Z = (double)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V3ui v) { X = (double)v.X; Y = (double)v.Y; Z = (double)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V3l v) { X = (double)v.X; Y = (double)v.Y; Z = (double)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V3f v) { X = (double)v.X; Y = (double)v.Y; Z = (double)v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// W is set to zero. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V3d v) { X = v.X; Y = v.Y; Z = v.Z; W = 0; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V4i v) { X = (double)v.X; Y = (double)v.Y; Z = (double)v.Z; W = (double)v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V4ui v) { X = (double)v.X; Y = (double)v.Y; Z = (double)v.Z; W = (double)v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V4l v) { X = (double)v.X; Y = (double)v.Y; Z = (double)v.Z; W = (double)v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V4f v) { X = (double)v.X; Y = (double)v.Y; Z = (double)v.Z; W = (double)v.W; } /// /// Creates a vector from another vector of type . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(V4d v) { X = v.X; Y = v.Y; Z = v.Z; W = v.W; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(C3b c) { X = (double)(c.R); Y = (double)(c.G); Z = (double)(c.B); W = (double)255; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(C3us c) { X = (double)(c.R); Y = (double)(c.G); Z = (double)(c.B); W = (double)65535; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// W is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(C3ui c) { X = (double)(c.R); Y = (double)(c.G); Z = (double)(c.B); W = (double)UInt32.MaxValue; } /// /// Creates a vector from a color. /// W is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(C3f c) { X = (double)(c.R); Y = (double)(c.G); Z = (double)(c.B); W = (double)1.0f; } /// /// Creates a vector from a color. /// W is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(C3d c) { X = (c.R); Y = (c.G); Z = (c.B); W = 1.0; } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(C4b c) { X = (double)(c.R); Y = (double)(c.G); Z = (double)(c.B); W = (double)(c.A); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(C4us c) { X = (double)(c.R); Y = (double)(c.G); Z = (double)(c.B); W = (double)(c.A); } /// /// Creates a vector from a color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(C4ui c) { X = (double)(c.R); Y = (double)(c.G); Z = (double)(c.B); W = (double)(c.A); } /// /// Creates a vector from a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(C4f c) { X = (double)(c.R); Y = (double)(c.G); Z = (double)(c.B); W = (double)(c.A); } /// /// Creates a vector from a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public V4d(C4d c) { X = (c.R); Y = (c.G); Z = (c.B); W = (c.A); } #endregion #region Conversions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(V2i v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(V2ui v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(V2l v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(V2f v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(V2d v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(V3i v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(V3ui v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(V3l v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(V3f v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(V3d v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(V4i v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(V4ui v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(V4l v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(V4f v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2i ToV2i() => (V2i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2ui ToV2ui() => (V2ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2l ToV2l() => (V2l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V2f ToV2f() => (V2f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3i() => (V3i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3ui() => (V3ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3l() => (V3l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3f() => (V3f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i ToV4i() => (V4i)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui ToV4ui() => (V4ui)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToV4l() => (V4l)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f ToV4f() => (V4f)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator int[](V4d v) => new int[] { (int)v.X, (int)v.Y, (int)v.Z, (int)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(int[] v) => new V4d((double)v[0], (double)v[1], (double)v[2], (double)v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator uint[](V4d v) => new uint[] { (uint)v.X, (uint)v.Y, (uint)v.Z, (uint)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(uint[] v) => new V4d((double)v[0], (double)v[1], (double)v[2], (double)v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long[](V4d v) => new long[] { (long)v.X, (long)v.Y, (long)v.Z, (long)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(long[] v) => new V4d((double)v[0], (double)v[1], (double)v[2], (double)v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator float[](V4d v) => new float[] { (float)v.X, (float)v.Y, (float)v.Z, (float)v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(float[] v) => new V4d((double)v[0], (double)v[1], (double)v[2], (double)v[3]); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator double[](V4d v) => new double[] { v.X, v.Y, v.Z, v.W }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(double[] v) => new V4d(v[0], v[1], v[2], v[3]); /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(C3b v) => new V4d(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3b ToC3b() => (C3b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(C3us v) => new V4d(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3us ToC3us() => (C3us)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// W is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(C3ui v) => new V4d(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3ui ToC3ui() => (C3ui)this; /// /// Converts the given color to a vector. /// W is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(C3f v) => new V4d(v); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3f ToC3f() => (C3f)this; /// /// Converts the given color to a vector. /// W is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(C3d v) => new V4d(v); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C3d ToC3d() => (C3d)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(C4b v) => new V4d(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4b ToC4b() => (C4b)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(C4us v) => new V4d(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4us ToC4us() => (C4us)this; /// /// Converts the given color to a vector. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(C4ui v) => new V4d(v); /// /// Converts the given vector to a color. /// The values are not mapped to the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4ui ToC4ui() => (C4ui)this; /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(C4f v) => new V4d(v); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4f ToC4f() => (C4f)this; /// /// Converts the given color to a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator V4d(C4d v) => new V4d(v); /// /// Converts the given vector to a color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly C4d ToC4d() => (C4d)this; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToFloorV4l() => new V4l((long)Fun.Floor(X), (long)Fun.Floor(Y), (long)Fun.Floor(Z), (long)Fun.Floor(W)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l ToCeilingV4l() => new V4l((long)Fun.Ceiling(X), (long)Fun.Ceiling(Y), (long)Fun.Ceiling(Z), (long)Fun.Ceiling(W)); /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3i ToV3iInhomo() { var div = 1 / W; return new V3i(X * div, Y * div, Z * div); } /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3ui ToV3uiInhomo() { var div = 1 / W; return new V3ui(X * div, Y * div, Z * div); } /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3l ToV3lInhomo() { var div = 1 / W; return new V3l(X * div, Y * div, Z * div); } /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3f ToV3fInhomo() { var div = 1 / W; return new V3f(X * div, Y * div, Z * div); } /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V3d ToV3dInhomo() { var div = 1 / W; return new V3d(X * div, Y * div, Z * div); } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i Copy(Func element_fun) => new V4i(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4i Copy(Func element_index_fun) => new V4i(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(int[] array, int start) { array[start + 0] = (int)X; array[start + 1] = (int)Y; array[start + 2] = (int)Z; array[start + 3] = (int)W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui Copy(Func element_fun) => new V4ui(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4ui Copy(Func element_index_fun) => new V4ui(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(uint[] array, int start) { array[start + 0] = (uint)X; array[start + 1] = (uint)Y; array[start + 2] = (uint)Z; array[start + 3] = (uint)W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l Copy(Func element_fun) => new V4l(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4l Copy(Func element_index_fun) => new V4l(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(long[] array, int start) { array[start + 0] = (long)X; array[start + 1] = (long)Y; array[start + 2] = (long)Z; array[start + 3] = (long)W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f Copy(Func element_fun) => new V4f(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4f Copy(Func element_index_fun) => new V4f(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(float[] array, int start) { array[start + 0] = (float)X; array[start + 1] = (float)Y; array[start + 2] = (float)Z; array[start + 3] = (float)W; } /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d Copy(Func element_fun) => new V4d(element_fun(X), element_fun(Y), element_fun(Z), element_fun(W)); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V4d Copy(Func element_index_fun) => new V4d(element_index_fun(X, 0), element_index_fun(Y, 1), element_index_fun(Z, 2), element_index_fun(W, 3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(double[] array, int start) { array[start + 0] = X; array[start + 1] = Y; array[start + 2] = Z; array[start + 3] = W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_fun) { array[start + 0] = element_fun(X); array[start + 1] = element_fun(Y); array[start + 2] = element_fun(Z); array[start + 3] = element_fun(W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func element_index_fun) { array[start + 0] = element_index_fun(X, 0); array[start + 1] = element_index_fun(Y, 1); array[start + 2] = element_index_fun(Z, 2); array[start + 3] = element_index_fun(W, 3); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double[] ToArray() => new double[] { X, Y, Z, W }; #endregion #region Properties and Indexers /// /// Property for the field X. /// Useful when properties are required, but the field X is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public double P_X { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return X; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value; } } /// /// Property for the field Y. /// Useful when properties are required, but the field Y is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public double P_Y { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Y; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Y = value; } } /// /// Property for the field Z. /// Useful when properties are required, but the field Z is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public double P_Z { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return Z; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Z = value; } } /// /// Property for the field W. /// Useful when properties are required, but the field W is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public double P_W { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { W = value; } } /// /// Enumerates all elements of this vector. /// public readonly IEnumerable Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { yield return X; yield return Y; yield return Z; yield return W; } } /// /// Gets or sets element with given index. /// public unsafe double this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (double* ptr = &X) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (double* ptr = &X) { ptr[index] = value; } } } /// /// Returns the index of the largest dimension of the vector. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X >= Y ? (X >= Z ? (X >= W ? 0 : 3) : (Z >= W ? 2 : 3)) : (Y >= Z ? (Y >= W ? 1 : 3) : (Z >= W ? 2 : 3)); } } /// /// Returns the index of the smallest dimension of the vector. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X <= Y ? (X <= Z ? (X <= W ? 0 : 3) : (Z <= W ? 2 : 3)) : (Y <= Z ? (Y <= W ? 1 : 3) : (Z <= W ? 2 : 3)); } } /// /// Returns the minimum element of the vector. /// public readonly double MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(X, Y, Z, W); } /// /// Returns the maximum element of the vector. /// public readonly double MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(X, Y, Z, W); } public readonly bool AnyFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsFinite(X) || Fun.IsFinite(Y) || Fun.IsFinite(Z) || Fun.IsFinite(W); } public readonly bool AllFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsFinite(X) && Fun.IsFinite(Y) && Fun.IsFinite(Z) && Fun.IsFinite(W); } public readonly bool AnyNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNaN(X) || double.IsNaN(Y) || double.IsNaN(Z) || double.IsNaN(W); } public readonly bool AllNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNaN(X) && double.IsNaN(Y) && double.IsNaN(Z) && double.IsNaN(W); } public readonly bool AnyInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsInfinity(X) || double.IsInfinity(Y) || double.IsInfinity(Z) || double.IsInfinity(W); } public readonly bool AllInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsInfinity(X) && double.IsInfinity(Y) && double.IsInfinity(Z) && double.IsInfinity(W); } public readonly bool AnyPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsPositiveInfinity(X) || double.IsPositiveInfinity(Y) || double.IsPositiveInfinity(Z) || double.IsPositiveInfinity(W); } public readonly bool AllPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsPositiveInfinity(X) && double.IsPositiveInfinity(Y) && double.IsPositiveInfinity(Z) && double.IsPositiveInfinity(W); } public readonly bool AnyNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNegativeInfinity(X) || double.IsNegativeInfinity(Y) || double.IsNegativeInfinity(Z) || double.IsNegativeInfinity(W); } public readonly bool AllNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => double.IsNegativeInfinity(X) && double.IsNegativeInfinity(Y) && double.IsNegativeInfinity(Z) && double.IsNegativeInfinity(W); } public readonly bool AnyTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(X) || Fun.IsTiny(Y) || Fun.IsTiny(Z) || Fun.IsTiny(W); } public readonly bool AllTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.IsTiny(X) && Fun.IsTiny(Y) && Fun.IsTiny(Z) && Fun.IsTiny(W); } /// /// Returns true if the absolute value of each component of the vector is smaller than Constant<double>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any component of the vector is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any component of the vector is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any component of the vector is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any component of the vector is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all components of the vector are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } #endregion #region Constants /// /// Number of elements in this vector. /// public const int Dimension = 4; /// /// All elements zero. /// public static V4d Zero { get { return new V4d(0, 0, 0, 0); } } /// /// All elements half. /// public static V4d Half { get { return new V4d(0.5, 0.5, 0.5, 0.5); } } /// /// All elements one. /// public static V4d One { get { return new V4d(1, 1, 1, 1); } } /// /// All elements set to maximum possible value. /// public static V4d MaxValue { get { return new V4d(Constant.ParseableMaxValue, Constant.ParseableMaxValue, Constant.ParseableMaxValue, Constant.ParseableMaxValue); } } /// /// All elements set to minimum possible value. /// public static V4d MinValue { get { return new V4d(Constant.ParseableMinValue, Constant.ParseableMinValue, Constant.ParseableMinValue, Constant.ParseableMinValue); } } /// /// All elements set to negative infinity. /// public static V4d NegativeInfinity { get { return new V4d(double.NegativeInfinity, double.NegativeInfinity, double.NegativeInfinity, double.NegativeInfinity); } } /// /// All elements set to positive infinity. /// public static V4d PositiveInfinity { get { return new V4d(double.PositiveInfinity, double.PositiveInfinity, double.PositiveInfinity, double.PositiveInfinity); } } /// /// All elements set to NaN. /// public static V4d NaN { get { return new V4d(double.NaN, double.NaN, double.NaN, double.NaN); } } /// /// Normalized X-axis. /// public static V4d XAxis { get { return new V4d(1, 0, 0, 0); } } /// /// Normalized Y-axis. /// public static V4d YAxis { get { return new V4d(0, 1, 0, 0); } } /// /// Normalized Z-axis. /// public static V4d ZAxis { get { return new V4d(0, 0, 1, 0); } } /// /// Normalized W-axis. /// public static V4d WAxis { get { return new V4d(0, 0, 0, 1); } } /// /// An array of accessor functions for the coordinates of the vector. /// public static readonly Func[] SelectorArray = new Func[] { v => v.X, v => v.Y, v => v.Z, v => v.W }; /// /// Element getter function. /// public static readonly Func Getter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; case 3: return v.W; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action. /// public static readonly ActionRefValVal Setter = (ref V4d v, int i, double s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; case 3: v.W = s; return; default: throw new IndexOutOfRangeException(); } }; /// /// Element getter function with long index. /// public static readonly Func LongGetter = (v, i) => { switch (i) { case 0: return v.X; case 1: return v.Y; case 2: return v.Z; case 3: return v.W; default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action with long index. /// public static readonly ActionRefValVal LongSetter = (ref V4d v, long i, double s) => { switch (i) { case 0: v.X = s; return; case 1: v.Y = s; return; case 2: v.Z = s; return; case 3: v.W = s; return; default: throw new IndexOutOfRangeException(); } }; #endregion #region Static factories [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d FromV4i(V4i v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d FromV4ui(V4ui v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d FromV4l(V4l v) => new V4d(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d FromV4f(V4f v) => new V4d(v); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// W is set to 255. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d FromC3b(C3b c) => new V4d(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// W is set to 2^16 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d FromC3us(C3us c) => new V4d(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// W is set to 2^32 - 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d FromC3ui(C3ui c) => new V4d(c); /// /// Creates a vector from the given color. /// W is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d FromC3f(C3f c) => new V4d(c); /// /// Creates a vector from the given color. /// W is set to 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d FromC3d(C3d c) => new V4d(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d FromC4b(C4b c) => new V4d(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d FromC4us(C4us c) => new V4d(c); /// /// Creates a vector from the given color. /// The values are not mapped from the color range. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d FromC4ui(C4ui c) => new V4d(c); /// /// Creates a vector from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d FromC4f(C4f c) => new V4d(c); /// /// Creates a vector from the given color. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d FromC4d(C4d c) => new V4d(c); #endregion #region Norms /// /// Returns the squared length of the vector. /// public readonly double LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return X * X + Y * Y + Z * Z + W * W ; } } /// /// Returns the length of the vector. /// public readonly double Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z + W * W ); } } /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// public readonly double Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Abs(X) + Fun.Abs(Y) + Fun.Abs(Z) + Fun.Abs(W); } } /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// public readonly double Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(X * X + Y * Y + Z * Z + W * W); } } /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// public readonly double NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z), Fun.Abs(W)); } } /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// public readonly double NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z), Fun.Abs(W)); } } /// /// Returns a normalized copy of this vector. /// public readonly V4d Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Length; if (s == 0) return V4d.Zero; s = 1 / s; return new V4d(X * s, Y * s, Z * s, W * s); } } /// /// Returns a copy of the vector with the maximum component length of /// exactly 1. This corresponds to mapping the vector onto an origin- /// centered cube with side length 2. /// public readonly V4d CubeMapped { get { var s = 1 / Fun.Max(Fun.Abs(X), Fun.Abs(Y), Fun.Abs(Z), Fun.Abs(W)); return new V4d(X * s, Y * s, Z * s, W * s); } } #endregion #region Static methods for F# core and Aardvark library support [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Abs(V4d v) => v.Abs(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Floor(V4d v) => v.Floor(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Ceiling(V4d v) => v.Ceiling(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Round(V4d v) => v.Round(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Truncate(V4d v) => v.Truncate(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Acos(V4d v) => Fun.Acos(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Acoshb(V4d v) => Fun.Acosh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Cos(V4d v) => Fun.Cos(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Cosh(V4d v) => Fun.Cosh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Asin(V4d v) => Fun.Asin(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Asinhb(V4d v) => Fun.Asinh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Sin(V4d v) => Fun.Sin(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Sinh(V4d v) => Fun.Sinh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Atan(V4d v) => Fun.Atan(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Atanhb(V4d v) => Fun.Atanh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Atan2(V4d a, V4d b) => Fun.Atan2(a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Tan(V4d v) => Fun.Tan(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Tanh(V4d v) => Fun.Tanh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Sqrt(V4d v) => Fun.Sqrt(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d CubeRoot(V4d v) => Fun.Cbrt(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Exp(V4d v) => Fun.Exp(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log(V4d v) => Fun.Log(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d LogBinary(V4d v) => Fun.Log2(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log10(V4d v) => Fun.Log10(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d CopySgn(V4d value, V4d sign) => Fun.CopySign(value, sign); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d CopySgn(V4d value, double sign) => Fun.CopySign(value, sign); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d LinearInterp(double t, V4d a, V4d b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d LinearInterp(V4d t, V4d a, V4d b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Min(V4d v0, V4d v1) => Fun.Min(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Min(V4d v, double x) => Fun.Min(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Max(V4d v0, V4d v1) => Fun.Max(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Max(V4d v, double x) => Fun.Max(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Saturate(V4d v) => Fun.Saturate(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d DivideByInt(V4d v, int x) => v / x; #endregion #region Operations /// /// Sets the elements of a vector to the given int elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(int x, int y, int z, int w) { X = (double)x; Y = (double)y; Z = (double)z; W = (double)w; } /// /// Sets the elements of a vector to the given uint elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(uint x, uint y, uint z, uint w) { X = (double)x; Y = (double)y; Z = (double)z; W = (double)w; } /// /// Sets the elements of a vector to the given long elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(long x, long y, long z, long w) { X = (double)x; Y = (double)y; Z = (double)z; W = (double)w; } /// /// Sets the elements of a vector to the given float elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(float x, float y, float z, float w) { X = (double)x; Y = (double)y; Z = (double)z; W = (double)w; } /// /// Sets the elements of a vector to the given double elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(double x, double y, double z, double w) { X = x; Y = y; Z = z; W = w; } /// /// Returns a negated copy of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator -(V4d v) => new V4d(-v.X, -v.Y, -v.Z, -v.W); /// /// Gets a copy of this vector containing the reciprocal (1/x) of each element. /// public readonly V4d Reciprocal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new V4d(1 / X, 1 / Y, 1 / Z, 1 / W); } } /// /// Returns the component-wise sum of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator +(V4d a, V4d b) => new V4d(a.X + b.X, a.Y + b.Y, a.Z + b.Z, a.W + b.W); /// /// Returns the component-wise sum of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator +(V4d v, double s) => new V4d(v.X + s, v.Y + s, v.Z + s, v.W + s); /// /// Returns the component-wise sum of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator +(double s, V4d v) => new V4d(s + v.X, s + v.Y, s + v.Z, s + v.W); /// /// Returns the component-wise difference of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator -(V4d a, V4d b) => new V4d(a.X - b.X, a.Y - b.Y, a.Z - b.Z, a.W - b.W); /// /// Returns the component-wise difference of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator -(V4d v, double s) => new V4d(v.X - s, v.Y - s, v.Z - s, v.W - s); /// /// Returns the component-wise difference of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator -(double s, V4d v) => new V4d(s - v.X, s - v.Y, s - v.Z, s - v.W); /// /// Returns the component-wise product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator *(V4d a, V4d b) => new V4d(a.X * b.X, a.Y * b.Y, a.Z * b.Z, a.W * b.W); /// /// Returns the component-wise product of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator *(V4d v, double s) => new V4d(v.X * s, v.Y * s, v.Z * s, v.W * s); /// /// Returns the component-wise product of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator *(double s, V4d v) => new V4d(s * v.X, s * v.Y, s * v.Z, s * v.W); /// /// Returns the component-wise fraction of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator /(V4d a, V4d b) => new V4d(a.X / b.X, a.Y / b.Y, a.Z / b.Z, a.W / b.W); /// /// Returns the component-wise fraction of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator /(V4d v, double s) => new V4d(v.X / s, v.Y / s, v.Z / s, v.W / s); /// /// Returns the component-wise fraction of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator /(double s, V4d v) => new V4d(s / v.X, s / v.Y, s / v.Z, s / v.W); /// /// Returns the component-wise remainder of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator %(V4d a, V4d b) => new V4d(a.X % b.X, a.Y % b.Y, a.Z % b.Z, a.W % b.W); /// /// Returns the component-wise remainder of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator %(V4d v, double s) => new V4d(v.X % s, v.Y % s, v.Z % s, v.W % s); /// /// Returns the component-wise remainder of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d operator %(double s, V4d v) => new V4d(s % v.X, s % v.Y, s % v.Z, s % v.W); /// Attention: NEVER implement operators <, <=, >=, >, /// since these are not defined in a Vector space. /// Use AllSmaller() and similar comparators! #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V4d a, V4d b) { return a.X == b.X && a.Y == b.Y && a.Z == b.Z && a.W == b.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(V4d v, double s) { return v.X == s && v.Y == s && v.Z == s && v.W == s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(double s, V4d v) { return s == v.X && s == v.Y && s == v.Z && s == v.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V4d a, V4d b) { return a.X != b.X || a.Y != b.Y || a.Z != b.Z || a.W != b.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(V4d v, double s) { return v.X != s || v.Y != s || v.Z != s || v.W != s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(double s, V4d v) { return s != v.X || s != v.Y || s != v.Z || s != v.W; } #endregion #region IEquatable Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(V4d other) { return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && W.Equals(other.W); } #endregion #region Overrides public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin + X.ToString(format, fp) + between + Y.ToString(format, fp) + between + Z.ToString(format, fp) + between + W.ToString(format, fp) + end; } public override readonly int GetHashCode() { return HashCode.GetCombined(X, Y, Z, W); } public override readonly bool Equals(object other) => (other is V4d o) ? Equals(o) : false; public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "") + X.ToString(null, CultureInfo.InvariantCulture) + ", " + Y.ToString(null, CultureInfo.InvariantCulture) + ", " + Z.ToString(null, CultureInfo.InvariantCulture) + ", " + W.ToString(null, CultureInfo.InvariantCulture) + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Parsing public static V4d Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new V4d( double.Parse(x[0], CultureInfo.InvariantCulture), double.Parse(x[1], CultureInfo.InvariantCulture), double.Parse(x[2], CultureInfo.InvariantCulture), double.Parse(x[3], CultureInfo.InvariantCulture) ); } public static V4d Parse(Text t) { return t.NestedBracketSplit(1, Text.Parse, V4d.Setter); } public static V4d Parse(Text t, int bracketLevel) { return t.NestedBracketSplit(bracketLevel, Text.Parse, V4d.Setter); } #endregion #region Swizzle Methods [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d OX => new V2d(0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d OY => new V2d(0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d OZ => new V2d(0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d OW => new V2d(0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d IX => new V2d(1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d IY => new V2d(1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d IZ => new V2d(1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d IW => new V2d(1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d NX => new V2d(-1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d NY => new V2d(-1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d NZ => new V2d(-1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d NW => new V2d(-1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d XO => new V2d(X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d XI => new V2d(X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d XN => new V2d(X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d XX => new V2d(X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d XY { readonly get => new V2d(X, Y); set { X = value.X; Y = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d XZ { readonly get => new V2d(X, Z); set { X = value.X; Z = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d XW { readonly get => new V2d(X, W); set { X = value.X; W = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d YO => new V2d(Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d YI => new V2d(Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d YN => new V2d(Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d YX { readonly get => new V2d(Y, X); set { Y = value.X; X = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d YY => new V2d(Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d YZ { readonly get => new V2d(Y, Z); set { Y = value.X; Z = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d YW { readonly get => new V2d(Y, W); set { Y = value.X; W = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d ZO => new V2d(Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d ZI => new V2d(Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d ZN => new V2d(Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d ZX { readonly get => new V2d(Z, X); set { Z = value.X; X = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d ZY { readonly get => new V2d(Z, Y); set { Z = value.X; Y = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d ZZ => new V2d(Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d ZW { readonly get => new V2d(Z, W); set { Z = value.X; W = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d WO => new V2d(W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d WI => new V2d(W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d WN => new V2d(W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d WX { readonly get => new V2d(W, X); set { W = value.X; X = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d WY { readonly get => new V2d(W, Y); set { W = value.X; Y = value.Y; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V2d WZ { readonly get => new V2d(W, Z); set { W = value.X; Z = value.Y; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V2d WW => new V2d(W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OOX => new V3d(0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OOY => new V3d(0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OOZ => new V3d(0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OOW => new V3d(0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OIX => new V3d(0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OIY => new V3d(0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OIZ => new V3d(0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OIW => new V3d(0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ONX => new V3d(0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ONY => new V3d(0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ONZ => new V3d(0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ONW => new V3d(0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXO => new V3d(0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXI => new V3d(0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXN => new V3d(0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXX => new V3d(0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXY => new V3d(0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXZ => new V3d(0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OXW => new V3d(0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYO => new V3d(0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYI => new V3d(0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYN => new V3d(0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYX => new V3d(0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYY => new V3d(0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYZ => new V3d(0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OYW => new V3d(0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OZO => new V3d(0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OZI => new V3d(0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OZN => new V3d(0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OZX => new V3d(0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OZY => new V3d(0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OZZ => new V3d(0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OZW => new V3d(0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OWO => new V3d(0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OWI => new V3d(0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OWN => new V3d(0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OWX => new V3d(0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OWY => new V3d(0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OWZ => new V3d(0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d OWW => new V3d(0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IOX => new V3d(1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IOY => new V3d(1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IOZ => new V3d(1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IOW => new V3d(1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IIX => new V3d(1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IIY => new V3d(1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IIZ => new V3d(1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IIW => new V3d(1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PNX => new V3d(1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PNY => new V3d(1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PNZ => new V3d(1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PNW => new V3d(1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IXO => new V3d(1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IXI => new V3d(1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PXN => new V3d(1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IXX => new V3d(1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IXY => new V3d(1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IXZ => new V3d(1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IXW => new V3d(1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IYO => new V3d(1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IYI => new V3d(1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PYN => new V3d(1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IYX => new V3d(1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IYY => new V3d(1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IYZ => new V3d(1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IYW => new V3d(1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IZO => new V3d(1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IZI => new V3d(1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PZN => new V3d(1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IZX => new V3d(1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IZY => new V3d(1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IZZ => new V3d(1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IZW => new V3d(1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IWO => new V3d(1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IWI => new V3d(1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d PWN => new V3d(1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IWX => new V3d(1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IWY => new V3d(1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IWZ => new V3d(1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d IWW => new V3d(1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NOX => new V3d(-1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NOY => new V3d(-1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NOZ => new V3d(-1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NOW => new V3d(-1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NPX => new V3d(-1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NPY => new V3d(-1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NPZ => new V3d(-1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NPW => new V3d(-1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NNX => new V3d(-1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NNY => new V3d(-1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NNZ => new V3d(-1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NNW => new V3d(-1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXO => new V3d(-1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXP => new V3d(-1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXN => new V3d(-1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXX => new V3d(-1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXY => new V3d(-1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXZ => new V3d(-1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NXW => new V3d(-1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYO => new V3d(-1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYP => new V3d(-1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYN => new V3d(-1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYX => new V3d(-1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYY => new V3d(-1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYZ => new V3d(-1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NYW => new V3d(-1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NZO => new V3d(-1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NZP => new V3d(-1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NZN => new V3d(-1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NZX => new V3d(-1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NZY => new V3d(-1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NZZ => new V3d(-1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NZW => new V3d(-1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NWO => new V3d(-1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NWP => new V3d(-1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NWN => new V3d(-1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NWX => new V3d(-1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NWY => new V3d(-1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NWZ => new V3d(-1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d NWW => new V3d(-1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XOO => new V3d(X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XOI => new V3d(X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XON => new V3d(X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XOX => new V3d(X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XOY => new V3d(X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XOZ => new V3d(X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XOW => new V3d(X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XIO => new V3d(X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XII => new V3d(X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XPN => new V3d(X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XIX => new V3d(X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XIY => new V3d(X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XIZ => new V3d(X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XIW => new V3d(X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNO => new V3d(X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNP => new V3d(X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNN => new V3d(X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNX => new V3d(X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNY => new V3d(X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNZ => new V3d(X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XNW => new V3d(X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXO => new V3d(X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXI => new V3d(X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXN => new V3d(X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXX => new V3d(X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXY => new V3d(X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXZ => new V3d(X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XXW => new V3d(X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XYO => new V3d(X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XYI => new V3d(X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XYN => new V3d(X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XYX => new V3d(X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XYY => new V3d(X, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d XYZ { readonly get => new V3d(X, Y, Z); set { X = value.X; Y = value.Y; Z = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d XYW { readonly get => new V3d(X, Y, W); set { X = value.X; Y = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XZO => new V3d(X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XZI => new V3d(X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XZN => new V3d(X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XZX => new V3d(X, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d XZY { readonly get => new V3d(X, Z, Y); set { X = value.X; Z = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XZZ => new V3d(X, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d XZW { readonly get => new V3d(X, Z, W); set { X = value.X; Z = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XWO => new V3d(X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XWI => new V3d(X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XWN => new V3d(X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XWX => new V3d(X, W, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d XWY { readonly get => new V3d(X, W, Y); set { X = value.X; W = value.Y; Y = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d XWZ { readonly get => new V3d(X, W, Z); set { X = value.X; W = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d XWW => new V3d(X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YOO => new V3d(Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YOI => new V3d(Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YON => new V3d(Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YOX => new V3d(Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YOY => new V3d(Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YOZ => new V3d(Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YOW => new V3d(Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YIO => new V3d(Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YII => new V3d(Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YPN => new V3d(Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YIX => new V3d(Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YIY => new V3d(Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YIZ => new V3d(Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YIW => new V3d(Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNO => new V3d(Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNP => new V3d(Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNN => new V3d(Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNX => new V3d(Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNY => new V3d(Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNZ => new V3d(Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YNW => new V3d(Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YXO => new V3d(Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YXI => new V3d(Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YXN => new V3d(Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YXX => new V3d(Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YXY => new V3d(Y, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d YXZ { readonly get => new V3d(Y, X, Z); set { Y = value.X; X = value.Y; Z = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d YXW { readonly get => new V3d(Y, X, W); set { Y = value.X; X = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYO => new V3d(Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYI => new V3d(Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYN => new V3d(Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYX => new V3d(Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYY => new V3d(Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYZ => new V3d(Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YYW => new V3d(Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YZO => new V3d(Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YZI => new V3d(Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YZN => new V3d(Y, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d YZX { readonly get => new V3d(Y, Z, X); set { Y = value.X; Z = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YZY => new V3d(Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YZZ => new V3d(Y, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d YZW { readonly get => new V3d(Y, Z, W); set { Y = value.X; Z = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YWO => new V3d(Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YWI => new V3d(Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YWN => new V3d(Y, W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d YWX { readonly get => new V3d(Y, W, X); set { Y = value.X; W = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YWY => new V3d(Y, W, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d YWZ { readonly get => new V3d(Y, W, Z); set { Y = value.X; W = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d YWW => new V3d(Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZOO => new V3d(Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZOI => new V3d(Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZON => new V3d(Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZOX => new V3d(Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZOY => new V3d(Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZOZ => new V3d(Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZOW => new V3d(Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZIO => new V3d(Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZII => new V3d(Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZPN => new V3d(Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZIX => new V3d(Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZIY => new V3d(Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZIZ => new V3d(Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZIW => new V3d(Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZNO => new V3d(Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZNP => new V3d(Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZNN => new V3d(Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZNX => new V3d(Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZNY => new V3d(Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZNZ => new V3d(Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZNW => new V3d(Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZXO => new V3d(Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZXI => new V3d(Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZXN => new V3d(Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZXX => new V3d(Z, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d ZXY { readonly get => new V3d(Z, X, Y); set { Z = value.X; X = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZXZ => new V3d(Z, X, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d ZXW { readonly get => new V3d(Z, X, W); set { Z = value.X; X = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZYO => new V3d(Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZYI => new V3d(Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZYN => new V3d(Z, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d ZYX { readonly get => new V3d(Z, Y, X); set { Z = value.X; Y = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZYY => new V3d(Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZYZ => new V3d(Z, Y, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d ZYW { readonly get => new V3d(Z, Y, W); set { Z = value.X; Y = value.Y; W = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZZO => new V3d(Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZZI => new V3d(Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZZN => new V3d(Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZZX => new V3d(Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZZY => new V3d(Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZZZ => new V3d(Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZZW => new V3d(Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZWO => new V3d(Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZWI => new V3d(Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZWN => new V3d(Z, W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d ZWX { readonly get => new V3d(Z, W, X); set { Z = value.X; W = value.Y; X = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d ZWY { readonly get => new V3d(Z, W, Y); set { Z = value.X; W = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZWZ => new V3d(Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d ZWW => new V3d(Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WOO => new V3d(W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WOI => new V3d(W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WON => new V3d(W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WOX => new V3d(W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WOY => new V3d(W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WOZ => new V3d(W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WOW => new V3d(W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WIO => new V3d(W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WII => new V3d(W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WPN => new V3d(W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WIX => new V3d(W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WIY => new V3d(W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WIZ => new V3d(W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WIW => new V3d(W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WNO => new V3d(W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WNP => new V3d(W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WNN => new V3d(W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WNX => new V3d(W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WNY => new V3d(W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WNZ => new V3d(W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WNW => new V3d(W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WXO => new V3d(W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WXI => new V3d(W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WXN => new V3d(W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WXX => new V3d(W, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d WXY { readonly get => new V3d(W, X, Y); set { W = value.X; X = value.Y; Y = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d WXZ { readonly get => new V3d(W, X, Z); set { W = value.X; X = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WXW => new V3d(W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WYO => new V3d(W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WYI => new V3d(W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WYN => new V3d(W, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d WYX { readonly get => new V3d(W, Y, X); set { W = value.X; Y = value.Y; X = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WYY => new V3d(W, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d WYZ { readonly get => new V3d(W, Y, Z); set { W = value.X; Y = value.Y; Z = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WYW => new V3d(W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WZO => new V3d(W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WZI => new V3d(W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WZN => new V3d(W, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d WZX { readonly get => new V3d(W, Z, X); set { W = value.X; Z = value.Y; X = value.Z; } } [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V3d WZY { readonly get => new V3d(W, Z, Y); set { W = value.X; Z = value.Y; Y = value.Z; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WZZ => new V3d(W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WZW => new V3d(W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WWO => new V3d(W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WWI => new V3d(W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WWN => new V3d(W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WWX => new V3d(W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WWY => new V3d(W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WWZ => new V3d(W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V3d WWW => new V3d(W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OOOO => new V4d(0, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OOOI => new V4d(0, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OOON => new V4d(0, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOOX => new V4d(0, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOOY => new V4d(0, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOOZ => new V4d(0, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOOW => new V4d(0, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OOIO => new V4d(0, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OOII => new V4d(0, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OOPN => new V4d(0, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOIX => new V4d(0, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOIY => new V4d(0, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOIZ => new V4d(0, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOIW => new V4d(0, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OONO => new V4d(0, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OONP => new V4d(0, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OONN => new V4d(0, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OONX => new V4d(0, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OONY => new V4d(0, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OONZ => new V4d(0, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OONW => new V4d(0, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXO => new V4d(0, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXI => new V4d(0, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXN => new V4d(0, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXX => new V4d(0, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXY => new V4d(0, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXZ => new V4d(0, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOXW => new V4d(0, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYO => new V4d(0, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYI => new V4d(0, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYN => new V4d(0, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYX => new V4d(0, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYY => new V4d(0, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYZ => new V4d(0, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOYW => new V4d(0, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOZO => new V4d(0, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOZI => new V4d(0, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOZN => new V4d(0, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOZX => new V4d(0, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOZY => new V4d(0, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOZZ => new V4d(0, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOZW => new V4d(0, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOWO => new V4d(0, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOWI => new V4d(0, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOWN => new V4d(0, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOWX => new V4d(0, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOWY => new V4d(0, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOWZ => new V4d(0, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OOWW => new V4d(0, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OIOO => new V4d(0, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OIOI => new V4d(0, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OPON => new V4d(0, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIOX => new V4d(0, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIOY => new V4d(0, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIOZ => new V4d(0, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIOW => new V4d(0, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OIIO => new V4d(0, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OIII => new V4d(0, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OPPN => new V4d(0, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIIX => new V4d(0, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIIY => new V4d(0, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIIZ => new V4d(0, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIIW => new V4d(0, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OPNO => new V4d(0, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OPNP => new V4d(0, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d OPNN => new V4d(0, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPNX => new V4d(0, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPNY => new V4d(0, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPNZ => new V4d(0, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPNW => new V4d(0, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIXO => new V4d(0, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIXI => new V4d(0, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPXN => new V4d(0, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIXX => new V4d(0, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIXY => new V4d(0, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIXZ => new V4d(0, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIXW => new V4d(0, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIYO => new V4d(0, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIYI => new V4d(0, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPYN => new V4d(0, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIYX => new V4d(0, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIYY => new V4d(0, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIYZ => new V4d(0, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIYW => new V4d(0, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIZO => new V4d(0, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIZI => new V4d(0, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPZN => new V4d(0, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIZX => new V4d(0, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIZY => new V4d(0, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIZZ => new V4d(0, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIZW => new V4d(0, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIWO => new V4d(0, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIWI => new V4d(0, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OPWN => new V4d(0, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIWX => new V4d(0, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIWY => new V4d(0, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIWZ => new V4d(0, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OIWW => new V4d(0, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d ONOO => new V4d(0, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d ONOP => new V4d(0, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d ONON => new V4d(0, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONOX => new V4d(0, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONOY => new V4d(0, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONOZ => new V4d(0, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONOW => new V4d(0, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d ONPO => new V4d(0, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d ONPP => new V4d(0, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d ONPN => new V4d(0, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONPX => new V4d(0, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONPY => new V4d(0, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONPZ => new V4d(0, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONPW => new V4d(0, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d ONNO => new V4d(0, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d ONNP => new V4d(0, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d ONNN => new V4d(0, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONNX => new V4d(0, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONNY => new V4d(0, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONNZ => new V4d(0, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONNW => new V4d(0, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXO => new V4d(0, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXP => new V4d(0, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXN => new V4d(0, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXX => new V4d(0, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXY => new V4d(0, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXZ => new V4d(0, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONXW => new V4d(0, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYO => new V4d(0, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYP => new V4d(0, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYN => new V4d(0, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYX => new V4d(0, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYY => new V4d(0, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYZ => new V4d(0, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONYW => new V4d(0, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONZO => new V4d(0, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONZP => new V4d(0, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONZN => new V4d(0, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONZX => new V4d(0, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONZY => new V4d(0, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONZZ => new V4d(0, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONZW => new V4d(0, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONWO => new V4d(0, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONWP => new V4d(0, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONWN => new V4d(0, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONWX => new V4d(0, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONWY => new V4d(0, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONWZ => new V4d(0, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ONWW => new V4d(0, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXOO => new V4d(0, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXOI => new V4d(0, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXON => new V4d(0, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXOX => new V4d(0, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXOY => new V4d(0, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXOZ => new V4d(0, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXOW => new V4d(0, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXIO => new V4d(0, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXII => new V4d(0, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXPN => new V4d(0, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXIX => new V4d(0, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXIY => new V4d(0, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXIZ => new V4d(0, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXIW => new V4d(0, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNO => new V4d(0, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNP => new V4d(0, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNN => new V4d(0, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNX => new V4d(0, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNY => new V4d(0, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNZ => new V4d(0, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXNW => new V4d(0, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXO => new V4d(0, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXI => new V4d(0, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXN => new V4d(0, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXX => new V4d(0, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXY => new V4d(0, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXZ => new V4d(0, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXXW => new V4d(0, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYO => new V4d(0, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYI => new V4d(0, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYN => new V4d(0, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYX => new V4d(0, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYY => new V4d(0, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYZ => new V4d(0, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXYW => new V4d(0, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXZO => new V4d(0, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXZI => new V4d(0, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXZN => new V4d(0, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXZX => new V4d(0, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXZY => new V4d(0, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXZZ => new V4d(0, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXZW => new V4d(0, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXWO => new V4d(0, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXWI => new V4d(0, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXWN => new V4d(0, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXWX => new V4d(0, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXWY => new V4d(0, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXWZ => new V4d(0, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OXWW => new V4d(0, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYOO => new V4d(0, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYOI => new V4d(0, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYON => new V4d(0, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYOX => new V4d(0, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYOY => new V4d(0, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYOZ => new V4d(0, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYOW => new V4d(0, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYIO => new V4d(0, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYII => new V4d(0, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYPN => new V4d(0, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYIX => new V4d(0, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYIY => new V4d(0, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYIZ => new V4d(0, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYIW => new V4d(0, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNO => new V4d(0, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNP => new V4d(0, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNN => new V4d(0, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNX => new V4d(0, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNY => new V4d(0, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNZ => new V4d(0, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYNW => new V4d(0, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXO => new V4d(0, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXI => new V4d(0, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXN => new V4d(0, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXX => new V4d(0, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXY => new V4d(0, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXZ => new V4d(0, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYXW => new V4d(0, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYO => new V4d(0, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYI => new V4d(0, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYN => new V4d(0, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYX => new V4d(0, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYY => new V4d(0, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYZ => new V4d(0, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYYW => new V4d(0, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYZO => new V4d(0, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYZI => new V4d(0, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYZN => new V4d(0, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYZX => new V4d(0, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYZY => new V4d(0, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYZZ => new V4d(0, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYZW => new V4d(0, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYWO => new V4d(0, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYWI => new V4d(0, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYWN => new V4d(0, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYWX => new V4d(0, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYWY => new V4d(0, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYWZ => new V4d(0, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OYWW => new V4d(0, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZOO => new V4d(0, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZOI => new V4d(0, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZON => new V4d(0, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZOX => new V4d(0, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZOY => new V4d(0, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZOZ => new V4d(0, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZOW => new V4d(0, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZIO => new V4d(0, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZII => new V4d(0, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZPN => new V4d(0, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZIX => new V4d(0, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZIY => new V4d(0, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZIZ => new V4d(0, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZIW => new V4d(0, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZNO => new V4d(0, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZNP => new V4d(0, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZNN => new V4d(0, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZNX => new V4d(0, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZNY => new V4d(0, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZNZ => new V4d(0, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZNW => new V4d(0, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZXO => new V4d(0, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZXI => new V4d(0, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZXN => new V4d(0, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZXX => new V4d(0, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZXY => new V4d(0, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZXZ => new V4d(0, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZXW => new V4d(0, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZYO => new V4d(0, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZYI => new V4d(0, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZYN => new V4d(0, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZYX => new V4d(0, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZYY => new V4d(0, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZYZ => new V4d(0, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZYW => new V4d(0, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZZO => new V4d(0, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZZI => new V4d(0, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZZN => new V4d(0, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZZX => new V4d(0, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZZY => new V4d(0, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZZZ => new V4d(0, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZZW => new V4d(0, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZWO => new V4d(0, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZWI => new V4d(0, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZWN => new V4d(0, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZWX => new V4d(0, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZWY => new V4d(0, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZWZ => new V4d(0, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OZWW => new V4d(0, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWOO => new V4d(0, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWOI => new V4d(0, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWON => new V4d(0, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWOX => new V4d(0, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWOY => new V4d(0, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWOZ => new V4d(0, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWOW => new V4d(0, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWIO => new V4d(0, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWII => new V4d(0, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWPN => new V4d(0, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWIX => new V4d(0, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWIY => new V4d(0, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWIZ => new V4d(0, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWIW => new V4d(0, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWNO => new V4d(0, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWNP => new V4d(0, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWNN => new V4d(0, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWNX => new V4d(0, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWNY => new V4d(0, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWNZ => new V4d(0, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWNW => new V4d(0, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWXO => new V4d(0, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWXI => new V4d(0, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWXN => new V4d(0, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWXX => new V4d(0, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWXY => new V4d(0, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWXZ => new V4d(0, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWXW => new V4d(0, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWYO => new V4d(0, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWYI => new V4d(0, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWYN => new V4d(0, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWYX => new V4d(0, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWYY => new V4d(0, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWYZ => new V4d(0, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWYW => new V4d(0, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWZO => new V4d(0, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWZI => new V4d(0, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWZN => new V4d(0, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWZX => new V4d(0, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWZY => new V4d(0, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWZZ => new V4d(0, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWZW => new V4d(0, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWWO => new V4d(0, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWWI => new V4d(0, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWWN => new V4d(0, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWWX => new V4d(0, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWWY => new V4d(0, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWWZ => new V4d(0, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d OWWW => new V4d(0, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d IOOO => new V4d(1, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d IOOI => new V4d(1, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d POON => new V4d(1, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOOX => new V4d(1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOOY => new V4d(1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOOZ => new V4d(1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOOW => new V4d(1, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d IOIO => new V4d(1, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d IOII => new V4d(1, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d POPN => new V4d(1, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOIX => new V4d(1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOIY => new V4d(1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOIZ => new V4d(1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOIW => new V4d(1, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PONO => new V4d(1, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PONP => new V4d(1, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PONN => new V4d(1, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PONX => new V4d(1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PONY => new V4d(1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PONZ => new V4d(1, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PONW => new V4d(1, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOXO => new V4d(1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOXI => new V4d(1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d POXN => new V4d(1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOXX => new V4d(1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOXY => new V4d(1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOXZ => new V4d(1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOXW => new V4d(1, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOYO => new V4d(1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOYI => new V4d(1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d POYN => new V4d(1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOYX => new V4d(1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOYY => new V4d(1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOYZ => new V4d(1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOYW => new V4d(1, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOZO => new V4d(1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOZI => new V4d(1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d POZN => new V4d(1, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOZX => new V4d(1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOZY => new V4d(1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOZZ => new V4d(1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOZW => new V4d(1, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOWO => new V4d(1, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOWI => new V4d(1, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d POWN => new V4d(1, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOWX => new V4d(1, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOWY => new V4d(1, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOWZ => new V4d(1, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IOWW => new V4d(1, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d IIOO => new V4d(1, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d IIOI => new V4d(1, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PPON => new V4d(1, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIOX => new V4d(1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIOY => new V4d(1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIOZ => new V4d(1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIOW => new V4d(1, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d IIIO => new V4d(1, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d IIII => new V4d(1, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PPPN => new V4d(1, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIIX => new V4d(1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIIY => new V4d(1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIIZ => new V4d(1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIIW => new V4d(1, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PPNO => new V4d(1, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PPNP => new V4d(1, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PPNN => new V4d(1, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPNX => new V4d(1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPNY => new V4d(1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPNZ => new V4d(1, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPNW => new V4d(1, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIXO => new V4d(1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIXI => new V4d(1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPXN => new V4d(1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIXX => new V4d(1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIXY => new V4d(1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIXZ => new V4d(1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIXW => new V4d(1, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIYO => new V4d(1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIYI => new V4d(1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPYN => new V4d(1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIYX => new V4d(1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIYY => new V4d(1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIYZ => new V4d(1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIYW => new V4d(1, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIZO => new V4d(1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIZI => new V4d(1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPZN => new V4d(1, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIZX => new V4d(1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIZY => new V4d(1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIZZ => new V4d(1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIZW => new V4d(1, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIWO => new V4d(1, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIWI => new V4d(1, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PPWN => new V4d(1, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIWX => new V4d(1, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIWY => new V4d(1, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIWZ => new V4d(1, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IIWW => new V4d(1, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PNOO => new V4d(1, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PNOP => new V4d(1, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PNON => new V4d(1, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNOX => new V4d(1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNOY => new V4d(1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNOZ => new V4d(1, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNOW => new V4d(1, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PNPO => new V4d(1, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PNPP => new V4d(1, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PNPN => new V4d(1, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNPX => new V4d(1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNPY => new V4d(1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNPZ => new V4d(1, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNPW => new V4d(1, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PNNO => new V4d(1, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PNNP => new V4d(1, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d PNNN => new V4d(1, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNNX => new V4d(1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNNY => new V4d(1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNNZ => new V4d(1, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNNW => new V4d(1, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXO => new V4d(1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXP => new V4d(1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXN => new V4d(1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXX => new V4d(1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXY => new V4d(1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXZ => new V4d(1, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNXW => new V4d(1, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYO => new V4d(1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYP => new V4d(1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYN => new V4d(1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYX => new V4d(1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYY => new V4d(1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYZ => new V4d(1, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNYW => new V4d(1, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNZO => new V4d(1, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNZP => new V4d(1, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNZN => new V4d(1, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNZX => new V4d(1, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNZY => new V4d(1, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNZZ => new V4d(1, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNZW => new V4d(1, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNWO => new V4d(1, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNWP => new V4d(1, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNWN => new V4d(1, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNWX => new V4d(1, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNWY => new V4d(1, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNWZ => new V4d(1, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PNWW => new V4d(1, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXOO => new V4d(1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXOI => new V4d(1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXON => new V4d(1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXOX => new V4d(1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXOY => new V4d(1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXOZ => new V4d(1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXOW => new V4d(1, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXIO => new V4d(1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXII => new V4d(1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXPN => new V4d(1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXIX => new V4d(1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXIY => new V4d(1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXIZ => new V4d(1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXIW => new V4d(1, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNO => new V4d(1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNP => new V4d(1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNN => new V4d(1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNX => new V4d(1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNY => new V4d(1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNZ => new V4d(1, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXNW => new V4d(1, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXXO => new V4d(1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXXI => new V4d(1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXXN => new V4d(1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXXX => new V4d(1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXXY => new V4d(1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXXZ => new V4d(1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXXW => new V4d(1, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXYO => new V4d(1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXYI => new V4d(1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXYN => new V4d(1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXYX => new V4d(1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXYY => new V4d(1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXYZ => new V4d(1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXYW => new V4d(1, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXZO => new V4d(1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXZI => new V4d(1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXZN => new V4d(1, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXZX => new V4d(1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXZY => new V4d(1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXZZ => new V4d(1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXZW => new V4d(1, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXWO => new V4d(1, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXWI => new V4d(1, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PXWN => new V4d(1, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXWX => new V4d(1, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXWY => new V4d(1, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXWZ => new V4d(1, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IXWW => new V4d(1, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYOO => new V4d(1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYOI => new V4d(1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYON => new V4d(1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYOX => new V4d(1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYOY => new V4d(1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYOZ => new V4d(1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYOW => new V4d(1, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYIO => new V4d(1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYII => new V4d(1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYPN => new V4d(1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYIX => new V4d(1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYIY => new V4d(1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYIZ => new V4d(1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYIW => new V4d(1, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNO => new V4d(1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNP => new V4d(1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNN => new V4d(1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNX => new V4d(1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNY => new V4d(1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNZ => new V4d(1, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYNW => new V4d(1, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYXO => new V4d(1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYXI => new V4d(1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYXN => new V4d(1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYXX => new V4d(1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYXY => new V4d(1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYXZ => new V4d(1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYXW => new V4d(1, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYYO => new V4d(1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYYI => new V4d(1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYYN => new V4d(1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYYX => new V4d(1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYYY => new V4d(1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYYZ => new V4d(1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYYW => new V4d(1, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYZO => new V4d(1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYZI => new V4d(1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYZN => new V4d(1, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYZX => new V4d(1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYZY => new V4d(1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYZZ => new V4d(1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYZW => new V4d(1, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYWO => new V4d(1, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYWI => new V4d(1, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PYWN => new V4d(1, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYWX => new V4d(1, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYWY => new V4d(1, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYWZ => new V4d(1, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IYWW => new V4d(1, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZOO => new V4d(1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZOI => new V4d(1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZON => new V4d(1, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZOX => new V4d(1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZOY => new V4d(1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZOZ => new V4d(1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZOW => new V4d(1, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZIO => new V4d(1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZII => new V4d(1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZPN => new V4d(1, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZIX => new V4d(1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZIY => new V4d(1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZIZ => new V4d(1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZIW => new V4d(1, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZNO => new V4d(1, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZNP => new V4d(1, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZNN => new V4d(1, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZNX => new V4d(1, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZNY => new V4d(1, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZNZ => new V4d(1, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZNW => new V4d(1, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZXO => new V4d(1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZXI => new V4d(1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZXN => new V4d(1, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZXX => new V4d(1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZXY => new V4d(1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZXZ => new V4d(1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZXW => new V4d(1, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZYO => new V4d(1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZYI => new V4d(1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZYN => new V4d(1, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZYX => new V4d(1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZYY => new V4d(1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZYZ => new V4d(1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZYW => new V4d(1, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZZO => new V4d(1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZZI => new V4d(1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZZN => new V4d(1, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZZX => new V4d(1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZZY => new V4d(1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZZZ => new V4d(1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZZW => new V4d(1, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZWO => new V4d(1, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZWI => new V4d(1, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PZWN => new V4d(1, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZWX => new V4d(1, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZWY => new V4d(1, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZWZ => new V4d(1, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IZWW => new V4d(1, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWOO => new V4d(1, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWOI => new V4d(1, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PWON => new V4d(1, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWOX => new V4d(1, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWOY => new V4d(1, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWOZ => new V4d(1, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWOW => new V4d(1, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWIO => new V4d(1, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWII => new V4d(1, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PWPN => new V4d(1, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWIX => new V4d(1, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWIY => new V4d(1, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWIZ => new V4d(1, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWIW => new V4d(1, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PWNO => new V4d(1, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PWNP => new V4d(1, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PWNN => new V4d(1, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PWNX => new V4d(1, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PWNY => new V4d(1, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PWNZ => new V4d(1, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PWNW => new V4d(1, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWXO => new V4d(1, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWXI => new V4d(1, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PWXN => new V4d(1, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWXX => new V4d(1, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWXY => new V4d(1, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWXZ => new V4d(1, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWXW => new V4d(1, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWYO => new V4d(1, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWYI => new V4d(1, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PWYN => new V4d(1, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWYX => new V4d(1, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWYY => new V4d(1, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWYZ => new V4d(1, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWYW => new V4d(1, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWZO => new V4d(1, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWZI => new V4d(1, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PWZN => new V4d(1, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWZX => new V4d(1, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWZY => new V4d(1, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWZZ => new V4d(1, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWZW => new V4d(1, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWWO => new V4d(1, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWWI => new V4d(1, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d PWWN => new V4d(1, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWWX => new V4d(1, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWWY => new V4d(1, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWWZ => new V4d(1, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d IWWW => new V4d(1, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NOOO => new V4d(-1, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NOOP => new V4d(-1, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NOON => new V4d(-1, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOOX => new V4d(-1, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOOY => new V4d(-1, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOOZ => new V4d(-1, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOOW => new V4d(-1, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NOPO => new V4d(-1, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NOPP => new V4d(-1, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NOPN => new V4d(-1, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOPX => new V4d(-1, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOPY => new V4d(-1, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOPZ => new V4d(-1, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOPW => new V4d(-1, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NONO => new V4d(-1, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NONP => new V4d(-1, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NONN => new V4d(-1, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NONX => new V4d(-1, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NONY => new V4d(-1, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NONZ => new V4d(-1, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NONW => new V4d(-1, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXO => new V4d(-1, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXP => new V4d(-1, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXN => new V4d(-1, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXX => new V4d(-1, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXY => new V4d(-1, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXZ => new V4d(-1, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOXW => new V4d(-1, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYO => new V4d(-1, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYP => new V4d(-1, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYN => new V4d(-1, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYX => new V4d(-1, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYY => new V4d(-1, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYZ => new V4d(-1, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOYW => new V4d(-1, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOZO => new V4d(-1, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOZP => new V4d(-1, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOZN => new V4d(-1, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOZX => new V4d(-1, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOZY => new V4d(-1, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOZZ => new V4d(-1, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOZW => new V4d(-1, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOWO => new V4d(-1, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOWP => new V4d(-1, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOWN => new V4d(-1, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOWX => new V4d(-1, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOWY => new V4d(-1, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOWZ => new V4d(-1, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NOWW => new V4d(-1, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NPOO => new V4d(-1, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NPOP => new V4d(-1, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NPON => new V4d(-1, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPOX => new V4d(-1, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPOY => new V4d(-1, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPOZ => new V4d(-1, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPOW => new V4d(-1, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NPPO => new V4d(-1, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NPPP => new V4d(-1, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NPPN => new V4d(-1, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPPX => new V4d(-1, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPPY => new V4d(-1, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPPZ => new V4d(-1, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPPW => new V4d(-1, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NPNO => new V4d(-1, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NPNP => new V4d(-1, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NPNN => new V4d(-1, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPNX => new V4d(-1, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPNY => new V4d(-1, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPNZ => new V4d(-1, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPNW => new V4d(-1, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXO => new V4d(-1, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXP => new V4d(-1, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXN => new V4d(-1, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXX => new V4d(-1, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXY => new V4d(-1, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXZ => new V4d(-1, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPXW => new V4d(-1, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYO => new V4d(-1, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYP => new V4d(-1, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYN => new V4d(-1, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYX => new V4d(-1, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYY => new V4d(-1, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYZ => new V4d(-1, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPYW => new V4d(-1, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPZO => new V4d(-1, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPZP => new V4d(-1, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPZN => new V4d(-1, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPZX => new V4d(-1, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPZY => new V4d(-1, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPZZ => new V4d(-1, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPZW => new V4d(-1, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPWO => new V4d(-1, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPWP => new V4d(-1, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPWN => new V4d(-1, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPWX => new V4d(-1, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPWY => new V4d(-1, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPWZ => new V4d(-1, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NPWW => new V4d(-1, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NNOO => new V4d(-1, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NNOP => new V4d(-1, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NNON => new V4d(-1, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNOX => new V4d(-1, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNOY => new V4d(-1, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNOZ => new V4d(-1, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNOW => new V4d(-1, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NNPO => new V4d(-1, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NNPP => new V4d(-1, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NNPN => new V4d(-1, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNPX => new V4d(-1, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNPY => new V4d(-1, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNPZ => new V4d(-1, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNPW => new V4d(-1, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NNNO => new V4d(-1, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NNNP => new V4d(-1, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static V4d NNNN => new V4d(-1, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNNX => new V4d(-1, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNNY => new V4d(-1, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNNZ => new V4d(-1, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNNW => new V4d(-1, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXO => new V4d(-1, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXP => new V4d(-1, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXN => new V4d(-1, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXX => new V4d(-1, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXY => new V4d(-1, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXZ => new V4d(-1, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNXW => new V4d(-1, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYO => new V4d(-1, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYP => new V4d(-1, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYN => new V4d(-1, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYX => new V4d(-1, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYY => new V4d(-1, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYZ => new V4d(-1, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNYW => new V4d(-1, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNZO => new V4d(-1, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNZP => new V4d(-1, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNZN => new V4d(-1, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNZX => new V4d(-1, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNZY => new V4d(-1, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNZZ => new V4d(-1, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNZW => new V4d(-1, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNWO => new V4d(-1, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNWP => new V4d(-1, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNWN => new V4d(-1, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNWX => new V4d(-1, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNWY => new V4d(-1, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNWZ => new V4d(-1, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NNWW => new V4d(-1, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXOO => new V4d(-1, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXOP => new V4d(-1, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXON => new V4d(-1, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXOX => new V4d(-1, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXOY => new V4d(-1, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXOZ => new V4d(-1, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXOW => new V4d(-1, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPO => new V4d(-1, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPP => new V4d(-1, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPN => new V4d(-1, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPX => new V4d(-1, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPY => new V4d(-1, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPZ => new V4d(-1, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXPW => new V4d(-1, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNO => new V4d(-1, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNP => new V4d(-1, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNN => new V4d(-1, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNX => new V4d(-1, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNY => new V4d(-1, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNZ => new V4d(-1, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXNW => new V4d(-1, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXO => new V4d(-1, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXP => new V4d(-1, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXN => new V4d(-1, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXX => new V4d(-1, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXY => new V4d(-1, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXZ => new V4d(-1, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXXW => new V4d(-1, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYO => new V4d(-1, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYP => new V4d(-1, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYN => new V4d(-1, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYX => new V4d(-1, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYY => new V4d(-1, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYZ => new V4d(-1, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXYW => new V4d(-1, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXZO => new V4d(-1, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXZP => new V4d(-1, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXZN => new V4d(-1, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXZX => new V4d(-1, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXZY => new V4d(-1, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXZZ => new V4d(-1, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXZW => new V4d(-1, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXWO => new V4d(-1, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXWP => new V4d(-1, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXWN => new V4d(-1, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXWX => new V4d(-1, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXWY => new V4d(-1, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXWZ => new V4d(-1, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NXWW => new V4d(-1, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYOO => new V4d(-1, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYOP => new V4d(-1, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYON => new V4d(-1, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYOX => new V4d(-1, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYOY => new V4d(-1, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYOZ => new V4d(-1, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYOW => new V4d(-1, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPO => new V4d(-1, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPP => new V4d(-1, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPN => new V4d(-1, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPX => new V4d(-1, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPY => new V4d(-1, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPZ => new V4d(-1, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYPW => new V4d(-1, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNO => new V4d(-1, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNP => new V4d(-1, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNN => new V4d(-1, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNX => new V4d(-1, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNY => new V4d(-1, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNZ => new V4d(-1, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYNW => new V4d(-1, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXO => new V4d(-1, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXP => new V4d(-1, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXN => new V4d(-1, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXX => new V4d(-1, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXY => new V4d(-1, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXZ => new V4d(-1, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYXW => new V4d(-1, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYO => new V4d(-1, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYP => new V4d(-1, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYN => new V4d(-1, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYX => new V4d(-1, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYY => new V4d(-1, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYZ => new V4d(-1, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYYW => new V4d(-1, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYZO => new V4d(-1, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYZP => new V4d(-1, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYZN => new V4d(-1, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYZX => new V4d(-1, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYZY => new V4d(-1, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYZZ => new V4d(-1, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYZW => new V4d(-1, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYWO => new V4d(-1, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYWP => new V4d(-1, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYWN => new V4d(-1, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYWX => new V4d(-1, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYWY => new V4d(-1, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYWZ => new V4d(-1, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NYWW => new V4d(-1, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZOO => new V4d(-1, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZOP => new V4d(-1, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZON => new V4d(-1, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZOX => new V4d(-1, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZOY => new V4d(-1, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZOZ => new V4d(-1, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZOW => new V4d(-1, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZPO => new V4d(-1, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZPP => new V4d(-1, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZPN => new V4d(-1, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZPX => new V4d(-1, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZPY => new V4d(-1, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZPZ => new V4d(-1, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZPW => new V4d(-1, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZNO => new V4d(-1, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZNP => new V4d(-1, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZNN => new V4d(-1, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZNX => new V4d(-1, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZNY => new V4d(-1, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZNZ => new V4d(-1, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZNW => new V4d(-1, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZXO => new V4d(-1, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZXP => new V4d(-1, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZXN => new V4d(-1, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZXX => new V4d(-1, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZXY => new V4d(-1, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZXZ => new V4d(-1, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZXW => new V4d(-1, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZYO => new V4d(-1, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZYP => new V4d(-1, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZYN => new V4d(-1, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZYX => new V4d(-1, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZYY => new V4d(-1, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZYZ => new V4d(-1, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZYW => new V4d(-1, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZZO => new V4d(-1, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZZP => new V4d(-1, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZZN => new V4d(-1, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZZX => new V4d(-1, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZZY => new V4d(-1, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZZZ => new V4d(-1, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZZW => new V4d(-1, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZWO => new V4d(-1, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZWP => new V4d(-1, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZWN => new V4d(-1, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZWX => new V4d(-1, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZWY => new V4d(-1, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZWZ => new V4d(-1, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NZWW => new V4d(-1, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWOO => new V4d(-1, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWOP => new V4d(-1, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWON => new V4d(-1, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWOX => new V4d(-1, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWOY => new V4d(-1, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWOZ => new V4d(-1, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWOW => new V4d(-1, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWPO => new V4d(-1, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWPP => new V4d(-1, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWPN => new V4d(-1, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWPX => new V4d(-1, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWPY => new V4d(-1, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWPZ => new V4d(-1, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWPW => new V4d(-1, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWNO => new V4d(-1, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWNP => new V4d(-1, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWNN => new V4d(-1, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWNX => new V4d(-1, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWNY => new V4d(-1, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWNZ => new V4d(-1, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWNW => new V4d(-1, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWXO => new V4d(-1, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWXP => new V4d(-1, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWXN => new V4d(-1, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWXX => new V4d(-1, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWXY => new V4d(-1, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWXZ => new V4d(-1, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWXW => new V4d(-1, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWYO => new V4d(-1, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWYP => new V4d(-1, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWYN => new V4d(-1, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWYX => new V4d(-1, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWYY => new V4d(-1, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWYZ => new V4d(-1, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWYW => new V4d(-1, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWZO => new V4d(-1, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWZP => new V4d(-1, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWZN => new V4d(-1, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWZX => new V4d(-1, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWZY => new V4d(-1, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWZZ => new V4d(-1, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWZW => new V4d(-1, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWWO => new V4d(-1, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWWP => new V4d(-1, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWWN => new V4d(-1, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWWX => new V4d(-1, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWWY => new V4d(-1, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWWZ => new V4d(-1, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d NWWW => new V4d(-1, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOOO => new V4d(X, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOOI => new V4d(X, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOON => new V4d(X, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOOX => new V4d(X, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOOY => new V4d(X, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOOZ => new V4d(X, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOOW => new V4d(X, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOIO => new V4d(X, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOII => new V4d(X, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOPN => new V4d(X, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOIX => new V4d(X, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOIY => new V4d(X, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOIZ => new V4d(X, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOIW => new V4d(X, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONO => new V4d(X, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONP => new V4d(X, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONN => new V4d(X, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONX => new V4d(X, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONY => new V4d(X, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONZ => new V4d(X, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XONW => new V4d(X, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXO => new V4d(X, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXI => new V4d(X, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXN => new V4d(X, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXX => new V4d(X, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXY => new V4d(X, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXZ => new V4d(X, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOXW => new V4d(X, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYO => new V4d(X, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYI => new V4d(X, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYN => new V4d(X, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYX => new V4d(X, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYY => new V4d(X, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYZ => new V4d(X, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOYW => new V4d(X, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOZO => new V4d(X, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOZI => new V4d(X, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOZN => new V4d(X, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOZX => new V4d(X, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOZY => new V4d(X, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOZZ => new V4d(X, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOZW => new V4d(X, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOWO => new V4d(X, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOWI => new V4d(X, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOWN => new V4d(X, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOWX => new V4d(X, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOWY => new V4d(X, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOWZ => new V4d(X, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XOWW => new V4d(X, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIOO => new V4d(X, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIOI => new V4d(X, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPON => new V4d(X, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIOX => new V4d(X, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIOY => new V4d(X, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIOZ => new V4d(X, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIOW => new V4d(X, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIIO => new V4d(X, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIII => new V4d(X, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPPN => new V4d(X, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIIX => new V4d(X, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIIY => new V4d(X, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIIZ => new V4d(X, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIIW => new V4d(X, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNO => new V4d(X, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNP => new V4d(X, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNN => new V4d(X, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNX => new V4d(X, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNY => new V4d(X, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNZ => new V4d(X, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPNW => new V4d(X, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIXO => new V4d(X, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIXI => new V4d(X, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPXN => new V4d(X, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIXX => new V4d(X, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIXY => new V4d(X, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIXZ => new V4d(X, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIXW => new V4d(X, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIYO => new V4d(X, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIYI => new V4d(X, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPYN => new V4d(X, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIYX => new V4d(X, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIYY => new V4d(X, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIYZ => new V4d(X, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIYW => new V4d(X, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIZO => new V4d(X, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIZI => new V4d(X, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPZN => new V4d(X, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIZX => new V4d(X, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIZY => new V4d(X, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIZZ => new V4d(X, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIZW => new V4d(X, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIWO => new V4d(X, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIWI => new V4d(X, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XPWN => new V4d(X, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIWX => new V4d(X, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIWY => new V4d(X, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIWZ => new V4d(X, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XIWW => new V4d(X, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNOO => new V4d(X, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNOP => new V4d(X, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNON => new V4d(X, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNOX => new V4d(X, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNOY => new V4d(X, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNOZ => new V4d(X, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNOW => new V4d(X, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPO => new V4d(X, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPP => new V4d(X, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPN => new V4d(X, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPX => new V4d(X, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPY => new V4d(X, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPZ => new V4d(X, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNPW => new V4d(X, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNO => new V4d(X, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNP => new V4d(X, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNN => new V4d(X, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNX => new V4d(X, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNY => new V4d(X, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNZ => new V4d(X, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNNW => new V4d(X, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXO => new V4d(X, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXP => new V4d(X, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXN => new V4d(X, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXX => new V4d(X, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXY => new V4d(X, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXZ => new V4d(X, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNXW => new V4d(X, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYO => new V4d(X, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYP => new V4d(X, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYN => new V4d(X, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYX => new V4d(X, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYY => new V4d(X, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYZ => new V4d(X, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNYW => new V4d(X, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNZO => new V4d(X, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNZP => new V4d(X, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNZN => new V4d(X, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNZX => new V4d(X, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNZY => new V4d(X, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNZZ => new V4d(X, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNZW => new V4d(X, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNWO => new V4d(X, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNWP => new V4d(X, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNWN => new V4d(X, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNWX => new V4d(X, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNWY => new V4d(X, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNWZ => new V4d(X, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XNWW => new V4d(X, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXOO => new V4d(X, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXOI => new V4d(X, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXON => new V4d(X, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXOX => new V4d(X, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXOY => new V4d(X, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXOZ => new V4d(X, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXOW => new V4d(X, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXIO => new V4d(X, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXII => new V4d(X, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXPN => new V4d(X, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXIX => new V4d(X, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXIY => new V4d(X, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXIZ => new V4d(X, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXIW => new V4d(X, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNO => new V4d(X, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNP => new V4d(X, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNN => new V4d(X, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNX => new V4d(X, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNY => new V4d(X, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNZ => new V4d(X, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXNW => new V4d(X, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXO => new V4d(X, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXI => new V4d(X, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXN => new V4d(X, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXX => new V4d(X, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXY => new V4d(X, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXZ => new V4d(X, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXXW => new V4d(X, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYO => new V4d(X, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYI => new V4d(X, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYN => new V4d(X, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYX => new V4d(X, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYY => new V4d(X, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYZ => new V4d(X, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXYW => new V4d(X, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXZO => new V4d(X, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXZI => new V4d(X, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXZN => new V4d(X, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXZX => new V4d(X, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXZY => new V4d(X, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXZZ => new V4d(X, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXZW => new V4d(X, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXWO => new V4d(X, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXWI => new V4d(X, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXWN => new V4d(X, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXWX => new V4d(X, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXWY => new V4d(X, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXWZ => new V4d(X, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XXWW => new V4d(X, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYOO => new V4d(X, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYOI => new V4d(X, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYON => new V4d(X, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYOX => new V4d(X, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYOY => new V4d(X, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYOZ => new V4d(X, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYOW => new V4d(X, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYIO => new V4d(X, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYII => new V4d(X, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYPN => new V4d(X, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYIX => new V4d(X, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYIY => new V4d(X, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYIZ => new V4d(X, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYIW => new V4d(X, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNO => new V4d(X, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNP => new V4d(X, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNN => new V4d(X, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNX => new V4d(X, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNY => new V4d(X, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNZ => new V4d(X, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYNW => new V4d(X, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXO => new V4d(X, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXI => new V4d(X, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXN => new V4d(X, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXX => new V4d(X, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXY => new V4d(X, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXZ => new V4d(X, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYXW => new V4d(X, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYO => new V4d(X, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYI => new V4d(X, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYN => new V4d(X, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYX => new V4d(X, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYY => new V4d(X, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYZ => new V4d(X, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYYW => new V4d(X, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYZO => new V4d(X, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYZI => new V4d(X, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYZN => new V4d(X, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYZX => new V4d(X, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYZY => new V4d(X, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYZZ => new V4d(X, Y, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d XYZW { readonly get => new V4d(X, Y, Z, W); set { X = value.X; Y = value.Y; Z = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYWO => new V4d(X, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYWI => new V4d(X, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYWN => new V4d(X, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYWX => new V4d(X, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYWY => new V4d(X, Y, W, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d XYWZ { readonly get => new V4d(X, Y, W, Z); set { X = value.X; Y = value.Y; W = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XYWW => new V4d(X, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZOO => new V4d(X, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZOI => new V4d(X, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZON => new V4d(X, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZOX => new V4d(X, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZOY => new V4d(X, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZOZ => new V4d(X, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZOW => new V4d(X, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZIO => new V4d(X, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZII => new V4d(X, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZPN => new V4d(X, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZIX => new V4d(X, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZIY => new V4d(X, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZIZ => new V4d(X, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZIW => new V4d(X, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZNO => new V4d(X, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZNP => new V4d(X, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZNN => new V4d(X, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZNX => new V4d(X, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZNY => new V4d(X, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZNZ => new V4d(X, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZNW => new V4d(X, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZXO => new V4d(X, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZXI => new V4d(X, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZXN => new V4d(X, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZXX => new V4d(X, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZXY => new V4d(X, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZXZ => new V4d(X, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZXW => new V4d(X, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZYO => new V4d(X, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZYI => new V4d(X, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZYN => new V4d(X, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZYX => new V4d(X, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZYY => new V4d(X, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZYZ => new V4d(X, Z, Y, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d XZYW { readonly get => new V4d(X, Z, Y, W); set { X = value.X; Z = value.Y; Y = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZZO => new V4d(X, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZZI => new V4d(X, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZZN => new V4d(X, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZZX => new V4d(X, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZZY => new V4d(X, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZZZ => new V4d(X, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZZW => new V4d(X, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZWO => new V4d(X, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZWI => new V4d(X, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZWN => new V4d(X, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZWX => new V4d(X, Z, W, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d XZWY { readonly get => new V4d(X, Z, W, Y); set { X = value.X; Z = value.Y; W = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZWZ => new V4d(X, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XZWW => new V4d(X, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWOO => new V4d(X, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWOI => new V4d(X, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWON => new V4d(X, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWOX => new V4d(X, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWOY => new V4d(X, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWOZ => new V4d(X, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWOW => new V4d(X, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWIO => new V4d(X, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWII => new V4d(X, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWPN => new V4d(X, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWIX => new V4d(X, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWIY => new V4d(X, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWIZ => new V4d(X, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWIW => new V4d(X, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWNO => new V4d(X, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWNP => new V4d(X, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWNN => new V4d(X, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWNX => new V4d(X, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWNY => new V4d(X, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWNZ => new V4d(X, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWNW => new V4d(X, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWXO => new V4d(X, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWXI => new V4d(X, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWXN => new V4d(X, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWXX => new V4d(X, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWXY => new V4d(X, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWXZ => new V4d(X, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWXW => new V4d(X, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWYO => new V4d(X, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWYI => new V4d(X, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWYN => new V4d(X, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWYX => new V4d(X, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWYY => new V4d(X, W, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d XWYZ { readonly get => new V4d(X, W, Y, Z); set { X = value.X; W = value.Y; Y = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWYW => new V4d(X, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWZO => new V4d(X, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWZI => new V4d(X, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWZN => new V4d(X, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWZX => new V4d(X, W, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d XWZY { readonly get => new V4d(X, W, Z, Y); set { X = value.X; W = value.Y; Z = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWZZ => new V4d(X, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWZW => new V4d(X, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWWO => new V4d(X, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWWI => new V4d(X, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWWN => new V4d(X, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWWX => new V4d(X, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWWY => new V4d(X, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWWZ => new V4d(X, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d XWWW => new V4d(X, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOOO => new V4d(Y, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOOI => new V4d(Y, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOON => new V4d(Y, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOOX => new V4d(Y, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOOY => new V4d(Y, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOOZ => new V4d(Y, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOOW => new V4d(Y, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOIO => new V4d(Y, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOII => new V4d(Y, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOPN => new V4d(Y, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOIX => new V4d(Y, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOIY => new V4d(Y, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOIZ => new V4d(Y, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOIW => new V4d(Y, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONO => new V4d(Y, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONP => new V4d(Y, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONN => new V4d(Y, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONX => new V4d(Y, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONY => new V4d(Y, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONZ => new V4d(Y, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YONW => new V4d(Y, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXO => new V4d(Y, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXI => new V4d(Y, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXN => new V4d(Y, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXX => new V4d(Y, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXY => new V4d(Y, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXZ => new V4d(Y, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOXW => new V4d(Y, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYO => new V4d(Y, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYI => new V4d(Y, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYN => new V4d(Y, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYX => new V4d(Y, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYY => new V4d(Y, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYZ => new V4d(Y, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOYW => new V4d(Y, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOZO => new V4d(Y, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOZI => new V4d(Y, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOZN => new V4d(Y, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOZX => new V4d(Y, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOZY => new V4d(Y, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOZZ => new V4d(Y, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOZW => new V4d(Y, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOWO => new V4d(Y, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOWI => new V4d(Y, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOWN => new V4d(Y, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOWX => new V4d(Y, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOWY => new V4d(Y, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOWZ => new V4d(Y, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YOWW => new V4d(Y, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIOO => new V4d(Y, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIOI => new V4d(Y, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPON => new V4d(Y, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIOX => new V4d(Y, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIOY => new V4d(Y, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIOZ => new V4d(Y, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIOW => new V4d(Y, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIIO => new V4d(Y, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIII => new V4d(Y, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPPN => new V4d(Y, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIIX => new V4d(Y, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIIY => new V4d(Y, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIIZ => new V4d(Y, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIIW => new V4d(Y, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNO => new V4d(Y, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNP => new V4d(Y, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNN => new V4d(Y, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNX => new V4d(Y, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNY => new V4d(Y, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNZ => new V4d(Y, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPNW => new V4d(Y, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIXO => new V4d(Y, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIXI => new V4d(Y, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPXN => new V4d(Y, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIXX => new V4d(Y, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIXY => new V4d(Y, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIXZ => new V4d(Y, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIXW => new V4d(Y, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIYO => new V4d(Y, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIYI => new V4d(Y, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPYN => new V4d(Y, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIYX => new V4d(Y, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIYY => new V4d(Y, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIYZ => new V4d(Y, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIYW => new V4d(Y, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIZO => new V4d(Y, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIZI => new V4d(Y, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPZN => new V4d(Y, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIZX => new V4d(Y, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIZY => new V4d(Y, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIZZ => new V4d(Y, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIZW => new V4d(Y, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIWO => new V4d(Y, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIWI => new V4d(Y, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YPWN => new V4d(Y, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIWX => new V4d(Y, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIWY => new V4d(Y, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIWZ => new V4d(Y, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YIWW => new V4d(Y, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNOO => new V4d(Y, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNOP => new V4d(Y, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNON => new V4d(Y, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNOX => new V4d(Y, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNOY => new V4d(Y, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNOZ => new V4d(Y, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNOW => new V4d(Y, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPO => new V4d(Y, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPP => new V4d(Y, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPN => new V4d(Y, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPX => new V4d(Y, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPY => new V4d(Y, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPZ => new V4d(Y, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNPW => new V4d(Y, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNO => new V4d(Y, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNP => new V4d(Y, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNN => new V4d(Y, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNX => new V4d(Y, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNY => new V4d(Y, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNZ => new V4d(Y, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNNW => new V4d(Y, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXO => new V4d(Y, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXP => new V4d(Y, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXN => new V4d(Y, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXX => new V4d(Y, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXY => new V4d(Y, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXZ => new V4d(Y, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNXW => new V4d(Y, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYO => new V4d(Y, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYP => new V4d(Y, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYN => new V4d(Y, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYX => new V4d(Y, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYY => new V4d(Y, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYZ => new V4d(Y, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNYW => new V4d(Y, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNZO => new V4d(Y, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNZP => new V4d(Y, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNZN => new V4d(Y, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNZX => new V4d(Y, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNZY => new V4d(Y, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNZZ => new V4d(Y, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNZW => new V4d(Y, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNWO => new V4d(Y, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNWP => new V4d(Y, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNWN => new V4d(Y, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNWX => new V4d(Y, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNWY => new V4d(Y, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNWZ => new V4d(Y, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YNWW => new V4d(Y, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXOO => new V4d(Y, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXOI => new V4d(Y, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXON => new V4d(Y, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXOX => new V4d(Y, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXOY => new V4d(Y, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXOZ => new V4d(Y, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXOW => new V4d(Y, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXIO => new V4d(Y, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXII => new V4d(Y, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXPN => new V4d(Y, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXIX => new V4d(Y, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXIY => new V4d(Y, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXIZ => new V4d(Y, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXIW => new V4d(Y, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNO => new V4d(Y, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNP => new V4d(Y, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNN => new V4d(Y, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNX => new V4d(Y, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNY => new V4d(Y, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNZ => new V4d(Y, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXNW => new V4d(Y, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXO => new V4d(Y, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXI => new V4d(Y, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXN => new V4d(Y, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXX => new V4d(Y, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXY => new V4d(Y, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXZ => new V4d(Y, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXXW => new V4d(Y, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYO => new V4d(Y, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYI => new V4d(Y, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYN => new V4d(Y, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYX => new V4d(Y, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYY => new V4d(Y, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYZ => new V4d(Y, X, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXYW => new V4d(Y, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXZO => new V4d(Y, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXZI => new V4d(Y, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXZN => new V4d(Y, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXZX => new V4d(Y, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXZY => new V4d(Y, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXZZ => new V4d(Y, X, Z, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d YXZW { readonly get => new V4d(Y, X, Z, W); set { Y = value.X; X = value.Y; Z = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXWO => new V4d(Y, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXWI => new V4d(Y, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXWN => new V4d(Y, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXWX => new V4d(Y, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXWY => new V4d(Y, X, W, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d YXWZ { readonly get => new V4d(Y, X, W, Z); set { Y = value.X; X = value.Y; W = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YXWW => new V4d(Y, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYOO => new V4d(Y, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYOI => new V4d(Y, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYON => new V4d(Y, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYOX => new V4d(Y, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYOY => new V4d(Y, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYOZ => new V4d(Y, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYOW => new V4d(Y, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYIO => new V4d(Y, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYII => new V4d(Y, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYPN => new V4d(Y, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYIX => new V4d(Y, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYIY => new V4d(Y, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYIZ => new V4d(Y, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYIW => new V4d(Y, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNO => new V4d(Y, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNP => new V4d(Y, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNN => new V4d(Y, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNX => new V4d(Y, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNY => new V4d(Y, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNZ => new V4d(Y, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYNW => new V4d(Y, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXO => new V4d(Y, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXI => new V4d(Y, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXN => new V4d(Y, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXX => new V4d(Y, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXY => new V4d(Y, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXZ => new V4d(Y, Y, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYXW => new V4d(Y, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYO => new V4d(Y, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYI => new V4d(Y, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYN => new V4d(Y, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYX => new V4d(Y, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYY => new V4d(Y, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYZ => new V4d(Y, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYYW => new V4d(Y, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYZO => new V4d(Y, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYZI => new V4d(Y, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYZN => new V4d(Y, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYZX => new V4d(Y, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYZY => new V4d(Y, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYZZ => new V4d(Y, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYZW => new V4d(Y, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYWO => new V4d(Y, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYWI => new V4d(Y, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYWN => new V4d(Y, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYWX => new V4d(Y, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYWY => new V4d(Y, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYWZ => new V4d(Y, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YYWW => new V4d(Y, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZOO => new V4d(Y, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZOI => new V4d(Y, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZON => new V4d(Y, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZOX => new V4d(Y, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZOY => new V4d(Y, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZOZ => new V4d(Y, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZOW => new V4d(Y, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZIO => new V4d(Y, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZII => new V4d(Y, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZPN => new V4d(Y, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZIX => new V4d(Y, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZIY => new V4d(Y, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZIZ => new V4d(Y, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZIW => new V4d(Y, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZNO => new V4d(Y, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZNP => new V4d(Y, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZNN => new V4d(Y, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZNX => new V4d(Y, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZNY => new V4d(Y, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZNZ => new V4d(Y, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZNW => new V4d(Y, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZXO => new V4d(Y, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZXI => new V4d(Y, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZXN => new V4d(Y, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZXX => new V4d(Y, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZXY => new V4d(Y, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZXZ => new V4d(Y, Z, X, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d YZXW { readonly get => new V4d(Y, Z, X, W); set { Y = value.X; Z = value.Y; X = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZYO => new V4d(Y, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZYI => new V4d(Y, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZYN => new V4d(Y, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZYX => new V4d(Y, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZYY => new V4d(Y, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZYZ => new V4d(Y, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZYW => new V4d(Y, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZZO => new V4d(Y, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZZI => new V4d(Y, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZZN => new V4d(Y, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZZX => new V4d(Y, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZZY => new V4d(Y, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZZZ => new V4d(Y, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZZW => new V4d(Y, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZWO => new V4d(Y, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZWI => new V4d(Y, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZWN => new V4d(Y, Z, W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d YZWX { readonly get => new V4d(Y, Z, W, X); set { Y = value.X; Z = value.Y; W = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZWY => new V4d(Y, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZWZ => new V4d(Y, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YZWW => new V4d(Y, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWOO => new V4d(Y, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWOI => new V4d(Y, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWON => new V4d(Y, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWOX => new V4d(Y, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWOY => new V4d(Y, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWOZ => new V4d(Y, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWOW => new V4d(Y, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWIO => new V4d(Y, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWII => new V4d(Y, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWPN => new V4d(Y, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWIX => new V4d(Y, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWIY => new V4d(Y, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWIZ => new V4d(Y, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWIW => new V4d(Y, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWNO => new V4d(Y, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWNP => new V4d(Y, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWNN => new V4d(Y, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWNX => new V4d(Y, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWNY => new V4d(Y, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWNZ => new V4d(Y, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWNW => new V4d(Y, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWXO => new V4d(Y, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWXI => new V4d(Y, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWXN => new V4d(Y, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWXX => new V4d(Y, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWXY => new V4d(Y, W, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d YWXZ { readonly get => new V4d(Y, W, X, Z); set { Y = value.X; W = value.Y; X = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWXW => new V4d(Y, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWYO => new V4d(Y, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWYI => new V4d(Y, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWYN => new V4d(Y, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWYX => new V4d(Y, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWYY => new V4d(Y, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWYZ => new V4d(Y, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWYW => new V4d(Y, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWZO => new V4d(Y, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWZI => new V4d(Y, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWZN => new V4d(Y, W, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d YWZX { readonly get => new V4d(Y, W, Z, X); set { Y = value.X; W = value.Y; Z = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWZY => new V4d(Y, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWZZ => new V4d(Y, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWZW => new V4d(Y, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWWO => new V4d(Y, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWWI => new V4d(Y, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWWN => new V4d(Y, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWWX => new V4d(Y, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWWY => new V4d(Y, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWWZ => new V4d(Y, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d YWWW => new V4d(Y, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOOO => new V4d(Z, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOOI => new V4d(Z, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOON => new V4d(Z, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOOX => new V4d(Z, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOOY => new V4d(Z, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOOZ => new V4d(Z, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOOW => new V4d(Z, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOIO => new V4d(Z, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOII => new V4d(Z, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOPN => new V4d(Z, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOIX => new V4d(Z, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOIY => new V4d(Z, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOIZ => new V4d(Z, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOIW => new V4d(Z, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZONO => new V4d(Z, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZONP => new V4d(Z, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZONN => new V4d(Z, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZONX => new V4d(Z, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZONY => new V4d(Z, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZONZ => new V4d(Z, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZONW => new V4d(Z, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOXO => new V4d(Z, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOXI => new V4d(Z, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOXN => new V4d(Z, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOXX => new V4d(Z, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOXY => new V4d(Z, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOXZ => new V4d(Z, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOXW => new V4d(Z, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOYO => new V4d(Z, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOYI => new V4d(Z, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOYN => new V4d(Z, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOYX => new V4d(Z, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOYY => new V4d(Z, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOYZ => new V4d(Z, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOYW => new V4d(Z, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOZO => new V4d(Z, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOZI => new V4d(Z, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOZN => new V4d(Z, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOZX => new V4d(Z, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOZY => new V4d(Z, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOZZ => new V4d(Z, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOZW => new V4d(Z, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOWO => new V4d(Z, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOWI => new V4d(Z, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOWN => new V4d(Z, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOWX => new V4d(Z, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOWY => new V4d(Z, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOWZ => new V4d(Z, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZOWW => new V4d(Z, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIOO => new V4d(Z, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIOI => new V4d(Z, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPON => new V4d(Z, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIOX => new V4d(Z, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIOY => new V4d(Z, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIOZ => new V4d(Z, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIOW => new V4d(Z, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIIO => new V4d(Z, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIII => new V4d(Z, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPPN => new V4d(Z, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIIX => new V4d(Z, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIIY => new V4d(Z, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIIZ => new V4d(Z, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIIW => new V4d(Z, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPNO => new V4d(Z, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPNP => new V4d(Z, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPNN => new V4d(Z, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPNX => new V4d(Z, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPNY => new V4d(Z, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPNZ => new V4d(Z, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPNW => new V4d(Z, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIXO => new V4d(Z, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIXI => new V4d(Z, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPXN => new V4d(Z, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIXX => new V4d(Z, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIXY => new V4d(Z, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIXZ => new V4d(Z, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIXW => new V4d(Z, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIYO => new V4d(Z, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIYI => new V4d(Z, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPYN => new V4d(Z, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIYX => new V4d(Z, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIYY => new V4d(Z, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIYZ => new V4d(Z, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIYW => new V4d(Z, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIZO => new V4d(Z, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIZI => new V4d(Z, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPZN => new V4d(Z, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIZX => new V4d(Z, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIZY => new V4d(Z, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIZZ => new V4d(Z, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIZW => new V4d(Z, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIWO => new V4d(Z, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIWI => new V4d(Z, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZPWN => new V4d(Z, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIWX => new V4d(Z, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIWY => new V4d(Z, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIWZ => new V4d(Z, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZIWW => new V4d(Z, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNOO => new V4d(Z, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNOP => new V4d(Z, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNON => new V4d(Z, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNOX => new V4d(Z, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNOY => new V4d(Z, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNOZ => new V4d(Z, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNOW => new V4d(Z, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNPO => new V4d(Z, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNPP => new V4d(Z, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNPN => new V4d(Z, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNPX => new V4d(Z, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNPY => new V4d(Z, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNPZ => new V4d(Z, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNPW => new V4d(Z, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNNO => new V4d(Z, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNNP => new V4d(Z, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNNN => new V4d(Z, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNNX => new V4d(Z, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNNY => new V4d(Z, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNNZ => new V4d(Z, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNNW => new V4d(Z, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNXO => new V4d(Z, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNXP => new V4d(Z, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNXN => new V4d(Z, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNXX => new V4d(Z, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNXY => new V4d(Z, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNXZ => new V4d(Z, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNXW => new V4d(Z, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNYO => new V4d(Z, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNYP => new V4d(Z, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNYN => new V4d(Z, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNYX => new V4d(Z, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNYY => new V4d(Z, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNYZ => new V4d(Z, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNYW => new V4d(Z, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNZO => new V4d(Z, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNZP => new V4d(Z, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNZN => new V4d(Z, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNZX => new V4d(Z, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNZY => new V4d(Z, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNZZ => new V4d(Z, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNZW => new V4d(Z, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNWO => new V4d(Z, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNWP => new V4d(Z, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNWN => new V4d(Z, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNWX => new V4d(Z, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNWY => new V4d(Z, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNWZ => new V4d(Z, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZNWW => new V4d(Z, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXOO => new V4d(Z, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXOI => new V4d(Z, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXON => new V4d(Z, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXOX => new V4d(Z, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXOY => new V4d(Z, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXOZ => new V4d(Z, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXOW => new V4d(Z, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXIO => new V4d(Z, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXII => new V4d(Z, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXPN => new V4d(Z, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXIX => new V4d(Z, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXIY => new V4d(Z, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXIZ => new V4d(Z, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXIW => new V4d(Z, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXNO => new V4d(Z, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXNP => new V4d(Z, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXNN => new V4d(Z, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXNX => new V4d(Z, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXNY => new V4d(Z, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXNZ => new V4d(Z, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXNW => new V4d(Z, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXXO => new V4d(Z, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXXI => new V4d(Z, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXXN => new V4d(Z, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXXX => new V4d(Z, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXXY => new V4d(Z, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXXZ => new V4d(Z, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXXW => new V4d(Z, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXYO => new V4d(Z, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXYI => new V4d(Z, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXYN => new V4d(Z, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXYX => new V4d(Z, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXYY => new V4d(Z, X, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXYZ => new V4d(Z, X, Y, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d ZXYW { readonly get => new V4d(Z, X, Y, W); set { Z = value.X; X = value.Y; Y = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXZO => new V4d(Z, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXZI => new V4d(Z, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXZN => new V4d(Z, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXZX => new V4d(Z, X, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXZY => new V4d(Z, X, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXZZ => new V4d(Z, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXZW => new V4d(Z, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXWO => new V4d(Z, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXWI => new V4d(Z, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXWN => new V4d(Z, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXWX => new V4d(Z, X, W, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d ZXWY { readonly get => new V4d(Z, X, W, Y); set { Z = value.X; X = value.Y; W = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXWZ => new V4d(Z, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZXWW => new V4d(Z, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYOO => new V4d(Z, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYOI => new V4d(Z, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYON => new V4d(Z, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYOX => new V4d(Z, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYOY => new V4d(Z, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYOZ => new V4d(Z, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYOW => new V4d(Z, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYIO => new V4d(Z, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYII => new V4d(Z, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYPN => new V4d(Z, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYIX => new V4d(Z, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYIY => new V4d(Z, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYIZ => new V4d(Z, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYIW => new V4d(Z, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYNO => new V4d(Z, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYNP => new V4d(Z, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYNN => new V4d(Z, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYNX => new V4d(Z, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYNY => new V4d(Z, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYNZ => new V4d(Z, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYNW => new V4d(Z, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYXO => new V4d(Z, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYXI => new V4d(Z, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYXN => new V4d(Z, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYXX => new V4d(Z, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYXY => new V4d(Z, Y, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYXZ => new V4d(Z, Y, X, Z); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d ZYXW { readonly get => new V4d(Z, Y, X, W); set { Z = value.X; Y = value.Y; X = value.Z; W = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYYO => new V4d(Z, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYYI => new V4d(Z, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYYN => new V4d(Z, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYYX => new V4d(Z, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYYY => new V4d(Z, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYYZ => new V4d(Z, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYYW => new V4d(Z, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYZO => new V4d(Z, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYZI => new V4d(Z, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYZN => new V4d(Z, Y, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYZX => new V4d(Z, Y, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYZY => new V4d(Z, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYZZ => new V4d(Z, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYZW => new V4d(Z, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYWO => new V4d(Z, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYWI => new V4d(Z, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYWN => new V4d(Z, Y, W, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d ZYWX { readonly get => new V4d(Z, Y, W, X); set { Z = value.X; Y = value.Y; W = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYWY => new V4d(Z, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYWZ => new V4d(Z, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZYWW => new V4d(Z, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZOO => new V4d(Z, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZOI => new V4d(Z, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZON => new V4d(Z, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZOX => new V4d(Z, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZOY => new V4d(Z, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZOZ => new V4d(Z, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZOW => new V4d(Z, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZIO => new V4d(Z, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZII => new V4d(Z, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZPN => new V4d(Z, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZIX => new V4d(Z, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZIY => new V4d(Z, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZIZ => new V4d(Z, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZIW => new V4d(Z, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZNO => new V4d(Z, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZNP => new V4d(Z, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZNN => new V4d(Z, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZNX => new V4d(Z, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZNY => new V4d(Z, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZNZ => new V4d(Z, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZNW => new V4d(Z, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZXO => new V4d(Z, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZXI => new V4d(Z, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZXN => new V4d(Z, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZXX => new V4d(Z, Z, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZXY => new V4d(Z, Z, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZXZ => new V4d(Z, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZXW => new V4d(Z, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZYO => new V4d(Z, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZYI => new V4d(Z, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZYN => new V4d(Z, Z, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZYX => new V4d(Z, Z, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZYY => new V4d(Z, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZYZ => new V4d(Z, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZYW => new V4d(Z, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZZO => new V4d(Z, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZZI => new V4d(Z, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZZN => new V4d(Z, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZZX => new V4d(Z, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZZY => new V4d(Z, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZZZ => new V4d(Z, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZZW => new V4d(Z, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZWO => new V4d(Z, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZWI => new V4d(Z, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZWN => new V4d(Z, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZWX => new V4d(Z, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZWY => new V4d(Z, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZWZ => new V4d(Z, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZZWW => new V4d(Z, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWOO => new V4d(Z, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWOI => new V4d(Z, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWON => new V4d(Z, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWOX => new V4d(Z, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWOY => new V4d(Z, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWOZ => new V4d(Z, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWOW => new V4d(Z, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWIO => new V4d(Z, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWII => new V4d(Z, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWPN => new V4d(Z, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWIX => new V4d(Z, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWIY => new V4d(Z, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWIZ => new V4d(Z, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWIW => new V4d(Z, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWNO => new V4d(Z, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWNP => new V4d(Z, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWNN => new V4d(Z, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWNX => new V4d(Z, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWNY => new V4d(Z, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWNZ => new V4d(Z, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWNW => new V4d(Z, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWXO => new V4d(Z, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWXI => new V4d(Z, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWXN => new V4d(Z, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWXX => new V4d(Z, W, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d ZWXY { readonly get => new V4d(Z, W, X, Y); set { Z = value.X; W = value.Y; X = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWXZ => new V4d(Z, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWXW => new V4d(Z, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWYO => new V4d(Z, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWYI => new V4d(Z, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWYN => new V4d(Z, W, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d ZWYX { readonly get => new V4d(Z, W, Y, X); set { Z = value.X; W = value.Y; Y = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWYY => new V4d(Z, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWYZ => new V4d(Z, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWYW => new V4d(Z, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWZO => new V4d(Z, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWZI => new V4d(Z, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWZN => new V4d(Z, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWZX => new V4d(Z, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWZY => new V4d(Z, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWZZ => new V4d(Z, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWZW => new V4d(Z, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWWO => new V4d(Z, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWWI => new V4d(Z, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWWN => new V4d(Z, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWWX => new V4d(Z, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWWY => new V4d(Z, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWWZ => new V4d(Z, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d ZWWW => new V4d(Z, W, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOOO => new V4d(W, 0, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOOI => new V4d(W, 0, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOON => new V4d(W, 0, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOOX => new V4d(W, 0, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOOY => new V4d(W, 0, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOOZ => new V4d(W, 0, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOOW => new V4d(W, 0, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOIO => new V4d(W, 0, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOII => new V4d(W, 0, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOPN => new V4d(W, 0, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOIX => new V4d(W, 0, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOIY => new V4d(W, 0, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOIZ => new V4d(W, 0, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOIW => new V4d(W, 0, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WONO => new V4d(W, 0, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WONP => new V4d(W, 0, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WONN => new V4d(W, 0, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WONX => new V4d(W, 0, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WONY => new V4d(W, 0, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WONZ => new V4d(W, 0, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WONW => new V4d(W, 0, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOXO => new V4d(W, 0, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOXI => new V4d(W, 0, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOXN => new V4d(W, 0, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOXX => new V4d(W, 0, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOXY => new V4d(W, 0, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOXZ => new V4d(W, 0, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOXW => new V4d(W, 0, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOYO => new V4d(W, 0, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOYI => new V4d(W, 0, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOYN => new V4d(W, 0, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOYX => new V4d(W, 0, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOYY => new V4d(W, 0, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOYZ => new V4d(W, 0, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOYW => new V4d(W, 0, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOZO => new V4d(W, 0, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOZI => new V4d(W, 0, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOZN => new V4d(W, 0, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOZX => new V4d(W, 0, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOZY => new V4d(W, 0, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOZZ => new V4d(W, 0, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOZW => new V4d(W, 0, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOWO => new V4d(W, 0, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOWI => new V4d(W, 0, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOWN => new V4d(W, 0, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOWX => new V4d(W, 0, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOWY => new V4d(W, 0, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOWZ => new V4d(W, 0, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WOWW => new V4d(W, 0, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIOO => new V4d(W, 1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIOI => new V4d(W, 1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WPON => new V4d(W, 1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIOX => new V4d(W, 1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIOY => new V4d(W, 1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIOZ => new V4d(W, 1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIOW => new V4d(W, 1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIIO => new V4d(W, 1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIII => new V4d(W, 1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WPPN => new V4d(W, 1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIIX => new V4d(W, 1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIIY => new V4d(W, 1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIIZ => new V4d(W, 1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIIW => new V4d(W, 1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WPNO => new V4d(W, 1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WPNP => new V4d(W, 1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WPNN => new V4d(W, 1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WPNX => new V4d(W, 1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WPNY => new V4d(W, 1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WPNZ => new V4d(W, 1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WPNW => new V4d(W, 1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIXO => new V4d(W, 1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIXI => new V4d(W, 1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WPXN => new V4d(W, 1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIXX => new V4d(W, 1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIXY => new V4d(W, 1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIXZ => new V4d(W, 1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIXW => new V4d(W, 1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIYO => new V4d(W, 1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIYI => new V4d(W, 1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WPYN => new V4d(W, 1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIYX => new V4d(W, 1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIYY => new V4d(W, 1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIYZ => new V4d(W, 1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIYW => new V4d(W, 1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIZO => new V4d(W, 1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIZI => new V4d(W, 1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WPZN => new V4d(W, 1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIZX => new V4d(W, 1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIZY => new V4d(W, 1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIZZ => new V4d(W, 1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIZW => new V4d(W, 1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIWO => new V4d(W, 1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIWI => new V4d(W, 1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WPWN => new V4d(W, 1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIWX => new V4d(W, 1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIWY => new V4d(W, 1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIWZ => new V4d(W, 1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WIWW => new V4d(W, 1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNOO => new V4d(W, -1, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNOP => new V4d(W, -1, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNON => new V4d(W, -1, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNOX => new V4d(W, -1, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNOY => new V4d(W, -1, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNOZ => new V4d(W, -1, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNOW => new V4d(W, -1, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNPO => new V4d(W, -1, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNPP => new V4d(W, -1, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNPN => new V4d(W, -1, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNPX => new V4d(W, -1, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNPY => new V4d(W, -1, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNPZ => new V4d(W, -1, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNPW => new V4d(W, -1, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNNO => new V4d(W, -1, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNNP => new V4d(W, -1, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNNN => new V4d(W, -1, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNNX => new V4d(W, -1, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNNY => new V4d(W, -1, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNNZ => new V4d(W, -1, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNNW => new V4d(W, -1, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNXO => new V4d(W, -1, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNXP => new V4d(W, -1, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNXN => new V4d(W, -1, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNXX => new V4d(W, -1, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNXY => new V4d(W, -1, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNXZ => new V4d(W, -1, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNXW => new V4d(W, -1, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNYO => new V4d(W, -1, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNYP => new V4d(W, -1, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNYN => new V4d(W, -1, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNYX => new V4d(W, -1, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNYY => new V4d(W, -1, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNYZ => new V4d(W, -1, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNYW => new V4d(W, -1, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNZO => new V4d(W, -1, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNZP => new V4d(W, -1, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNZN => new V4d(W, -1, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNZX => new V4d(W, -1, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNZY => new V4d(W, -1, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNZZ => new V4d(W, -1, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNZW => new V4d(W, -1, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNWO => new V4d(W, -1, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNWP => new V4d(W, -1, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNWN => new V4d(W, -1, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNWX => new V4d(W, -1, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNWY => new V4d(W, -1, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNWZ => new V4d(W, -1, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WNWW => new V4d(W, -1, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXOO => new V4d(W, X, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXOI => new V4d(W, X, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXON => new V4d(W, X, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXOX => new V4d(W, X, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXOY => new V4d(W, X, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXOZ => new V4d(W, X, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXOW => new V4d(W, X, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXIO => new V4d(W, X, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXII => new V4d(W, X, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXPN => new V4d(W, X, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXIX => new V4d(W, X, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXIY => new V4d(W, X, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXIZ => new V4d(W, X, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXIW => new V4d(W, X, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXNO => new V4d(W, X, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXNP => new V4d(W, X, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXNN => new V4d(W, X, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXNX => new V4d(W, X, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXNY => new V4d(W, X, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXNZ => new V4d(W, X, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXNW => new V4d(W, X, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXXO => new V4d(W, X, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXXI => new V4d(W, X, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXXN => new V4d(W, X, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXXX => new V4d(W, X, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXXY => new V4d(W, X, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXXZ => new V4d(W, X, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXXW => new V4d(W, X, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXYO => new V4d(W, X, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXYI => new V4d(W, X, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXYN => new V4d(W, X, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXYX => new V4d(W, X, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXYY => new V4d(W, X, Y, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d WXYZ { readonly get => new V4d(W, X, Y, Z); set { W = value.X; X = value.Y; Y = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXYW => new V4d(W, X, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXZO => new V4d(W, X, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXZI => new V4d(W, X, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXZN => new V4d(W, X, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXZX => new V4d(W, X, Z, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d WXZY { readonly get => new V4d(W, X, Z, Y); set { W = value.X; X = value.Y; Z = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXZZ => new V4d(W, X, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXZW => new V4d(W, X, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXWO => new V4d(W, X, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXWI => new V4d(W, X, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXWN => new V4d(W, X, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXWX => new V4d(W, X, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXWY => new V4d(W, X, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXWZ => new V4d(W, X, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WXWW => new V4d(W, X, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYOO => new V4d(W, Y, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYOI => new V4d(W, Y, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYON => new V4d(W, Y, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYOX => new V4d(W, Y, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYOY => new V4d(W, Y, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYOZ => new V4d(W, Y, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYOW => new V4d(W, Y, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYIO => new V4d(W, Y, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYII => new V4d(W, Y, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYPN => new V4d(W, Y, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYIX => new V4d(W, Y, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYIY => new V4d(W, Y, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYIZ => new V4d(W, Y, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYIW => new V4d(W, Y, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYNO => new V4d(W, Y, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYNP => new V4d(W, Y, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYNN => new V4d(W, Y, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYNX => new V4d(W, Y, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYNY => new V4d(W, Y, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYNZ => new V4d(W, Y, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYNW => new V4d(W, Y, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYXO => new V4d(W, Y, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYXI => new V4d(W, Y, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYXN => new V4d(W, Y, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYXX => new V4d(W, Y, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYXY => new V4d(W, Y, X, Y); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d WYXZ { readonly get => new V4d(W, Y, X, Z); set { W = value.X; Y = value.Y; X = value.Z; Z = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYXW => new V4d(W, Y, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYYO => new V4d(W, Y, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYYI => new V4d(W, Y, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYYN => new V4d(W, Y, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYYX => new V4d(W, Y, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYYY => new V4d(W, Y, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYYZ => new V4d(W, Y, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYYW => new V4d(W, Y, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYZO => new V4d(W, Y, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYZI => new V4d(W, Y, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYZN => new V4d(W, Y, Z, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d WYZX { readonly get => new V4d(W, Y, Z, X); set { W = value.X; Y = value.Y; Z = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYZY => new V4d(W, Y, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYZZ => new V4d(W, Y, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYZW => new V4d(W, Y, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYWO => new V4d(W, Y, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYWI => new V4d(W, Y, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYWN => new V4d(W, Y, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYWX => new V4d(W, Y, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYWY => new V4d(W, Y, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYWZ => new V4d(W, Y, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WYWW => new V4d(W, Y, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZOO => new V4d(W, Z, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZOI => new V4d(W, Z, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZON => new V4d(W, Z, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZOX => new V4d(W, Z, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZOY => new V4d(W, Z, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZOZ => new V4d(W, Z, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZOW => new V4d(W, Z, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZIO => new V4d(W, Z, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZII => new V4d(W, Z, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZPN => new V4d(W, Z, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZIX => new V4d(W, Z, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZIY => new V4d(W, Z, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZIZ => new V4d(W, Z, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZIW => new V4d(W, Z, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZNO => new V4d(W, Z, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZNP => new V4d(W, Z, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZNN => new V4d(W, Z, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZNX => new V4d(W, Z, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZNY => new V4d(W, Z, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZNZ => new V4d(W, Z, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZNW => new V4d(W, Z, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZXO => new V4d(W, Z, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZXI => new V4d(W, Z, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZXN => new V4d(W, Z, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZXX => new V4d(W, Z, X, X); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d WZXY { readonly get => new V4d(W, Z, X, Y); set { W = value.X; Z = value.Y; X = value.Z; Y = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZXZ => new V4d(W, Z, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZXW => new V4d(W, Z, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZYO => new V4d(W, Z, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZYI => new V4d(W, Z, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZYN => new V4d(W, Z, Y, -1); [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public V4d WZYX { readonly get => new V4d(W, Z, Y, X); set { W = value.X; Z = value.Y; Y = value.Z; X = value.W; } } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZYY => new V4d(W, Z, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZYZ => new V4d(W, Z, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZYW => new V4d(W, Z, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZZO => new V4d(W, Z, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZZI => new V4d(W, Z, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZZN => new V4d(W, Z, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZZX => new V4d(W, Z, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZZY => new V4d(W, Z, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZZZ => new V4d(W, Z, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZZW => new V4d(W, Z, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZWO => new V4d(W, Z, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZWI => new V4d(W, Z, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZWN => new V4d(W, Z, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZWX => new V4d(W, Z, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZWY => new V4d(W, Z, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZWZ => new V4d(W, Z, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WZWW => new V4d(W, Z, W, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWOO => new V4d(W, W, 0, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWOI => new V4d(W, W, 0, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWON => new V4d(W, W, 0, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWOX => new V4d(W, W, 0, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWOY => new V4d(W, W, 0, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWOZ => new V4d(W, W, 0, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWOW => new V4d(W, W, 0, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWIO => new V4d(W, W, 1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWII => new V4d(W, W, 1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWPN => new V4d(W, W, 1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWIX => new V4d(W, W, 1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWIY => new V4d(W, W, 1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWIZ => new V4d(W, W, 1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWIW => new V4d(W, W, 1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWNO => new V4d(W, W, -1, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWNP => new V4d(W, W, -1, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWNN => new V4d(W, W, -1, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWNX => new V4d(W, W, -1, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWNY => new V4d(W, W, -1, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWNZ => new V4d(W, W, -1, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWNW => new V4d(W, W, -1, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWXO => new V4d(W, W, X, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWXI => new V4d(W, W, X, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWXN => new V4d(W, W, X, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWXX => new V4d(W, W, X, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWXY => new V4d(W, W, X, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWXZ => new V4d(W, W, X, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWXW => new V4d(W, W, X, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWYO => new V4d(W, W, Y, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWYI => new V4d(W, W, Y, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWYN => new V4d(W, W, Y, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWYX => new V4d(W, W, Y, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWYY => new V4d(W, W, Y, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWYZ => new V4d(W, W, Y, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWYW => new V4d(W, W, Y, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWZO => new V4d(W, W, Z, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWZI => new V4d(W, W, Z, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWZN => new V4d(W, W, Z, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWZX => new V4d(W, W, Z, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWZY => new V4d(W, W, Z, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWZZ => new V4d(W, W, Z, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWZW => new V4d(W, W, Z, W); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWWO => new V4d(W, W, W, 0); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWWI => new V4d(W, W, W, 1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWWN => new V4d(W, W, W, -1); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWWX => new V4d(W, W, W, X); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWWY => new V4d(W, W, W, Y); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWWZ => new V4d(W, W, W, Z); [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly V4d WWWW => new V4d(W, W, W, W); #endregion #region IVector Members /// /// By using long indices, the IVector<double> interface is /// accessed. /// public double this[long i] { readonly get { return (double)this[(int)i]; } set { this[(int)i] = (double)value; } } #endregion #region ISize4d Members public readonly V4d Size4d { get { return this; } } #endregion #region IVector public readonly long Dim { get { return 4; } } public readonly object GetValue(long index) { return (object)this[(int)index]; } public void SetValue(object value, long index) { this[(int)index] = (double)value; } #endregion } public class V4dEqualityComparer : IEqualityComparer { public static V4dEqualityComparer Default => new V4dEqualityComparer(); #region IEqualityComparer Members public bool Equals(V4d v0, V4d v1) { return v0 == v1; } public int GetHashCode(V4d v) { return v.GetHashCode(); } #endregion } public static partial class Fun { #region Min and Max /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Min(this V4d a, V4d b) { return new V4d(Min(a.X, b.X), Min(a.Y, b.Y), Min(a.Z, b.Z), Min(a.W, b.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Min(this V4d a, double b) { return new V4d(Min(a.X, b), Min(a.Y, b), Min(a.Z, b), Min(a.W, b)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Min(this double a, V4d b) { return new V4d(Min(a, b.X), Min(a, b.Y), Min(a, b.Z), Min(a, b.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Max(this V4d a, V4d b) { return new V4d(Max(a.X, b.X), Max(a.Y, b.Y), Max(a.Z, b.Z), Max(a.W, b.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Max(this V4d a, double b) { return new V4d(Max(a.X, b), Max(a.Y, b), Max(a.Z, b), Max(a.W, b)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Max(this double a, V4d b) { return new V4d(Max(a, b.X), Max(a, b.Y), Max(a, b.Z), Max(a, b.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Min(this V4d a, V4d b, V4d c) { return new V4d(Min(a.X, b.X, c.X), Min(a.Y, b.Y, c.Y), Min(a.Z, b.Z, c.Z), Min(a.W, b.W, c.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Max(this V4d a, V4d b, V4d c) { return new V4d(Max(a.X, b.X, c.X), Max(a.Y, b.Y, c.Y), Max(a.Z, b.Z, c.Z), Max(a.W, b.W, c.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Min(this V4d a, V4d b, V4d c, V4d d) { return new V4d(Min(a.X, b.X, c.X, d.X), Min(a.Y, b.Y, c.Y, d.Y), Min(a.Z, b.Z, c.Z, d.Z), Min(a.W, b.W, c.W, d.W)); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Max(this V4d a, V4d b, V4d c, V4d d) { return new V4d(Max(a.X, b.X, c.X, d.X), Max(a.Y, b.Y, c.Y, d.Y), Max(a.Z, b.Z, c.Z, d.Z), Max(a.W, b.W, c.W, d.W)); } /// /// Applies Fun.Min to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Min(this V4d x, params V4d[] values) { return new V4d(Min(x.X, values.Map(a => a.X)), Min(x.Y, values.Map(a => a.Y)), Min(x.Z, values.Map(a => a.Z)), Min(x.W, values.Map(a => a.W))); } /// /// Applies Fun.Max to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Max(this V4d x, params V4d[] values) { return new V4d(Max(x.X, values.Map(a => a.X)), Max(x.Y, values.Map(a => a.Y)), Max(x.Z, values.Map(a => a.Z)), Max(x.W, values.Map(a => a.W))); } #endregion #region Abs /// /// Applies Fun.Abs to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Abs(this V4d x) { return new V4d(Abs(x.X), Abs(x.Y), Abs(x.Z), Abs(x.W)); } #endregion #region Rounding /// /// Applies Fun.Floor to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Floor(this V4d x) { return new V4d(Floor(x.X), Floor(x.Y), Floor(x.Z), Floor(x.W)); } /// /// Applies Fun.Ceiling to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Ceiling(this V4d x) { return new V4d(Ceiling(x.X), Ceiling(x.Y), Ceiling(x.Z), Ceiling(x.W)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Round(this V4d x) { return new V4d(Round(x.X), Round(x.Y), Round(x.Z), Round(x.W)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Round(this V4d x, MidpointRounding mode) { return new V4d(Round(x.X, mode), Round(x.Y, mode), Round(x.Z, mode), Round(x.W, mode)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Round(this V4d x, int digits) { return new V4d(Round(x.X, digits), Round(x.Y, digits), Round(x.Z, digits), Round(x.W, digits)); } /// /// Applies Fun.Round to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Round(this V4d x, int digits, MidpointRounding mode) { return new V4d(Round(x.X, digits, mode), Round(x.Y, digits, mode), Round(x.Z, digits, mode), Round(x.W, digits, mode)); } /// /// Applies Fun.Truncate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Truncate(this V4d x) { return new V4d(Truncate(x.X), Truncate(x.Y), Truncate(x.Z), Truncate(x.W)); } #endregion #region Frac /// /// Applies Fun.Frac to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Frac(this V4d x) { return new V4d(Frac(x.X), Frac(x.Y), Frac(x.Z), Frac(x.W)); } #endregion #region Clamping /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Clamp(this V4d x, V4d a, V4d b) { return new V4d(Clamp(x.X, a.X, b.X), Clamp(x.Y, a.Y, b.Y), Clamp(x.Z, a.Z, b.Z), Clamp(x.W, a.W, b.W)); } /// /// Applies Fun.Clamp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Clamp(this V4d x, double a, double b) { return new V4d(Clamp(x.X, a, b), Clamp(x.Y, a, b), Clamp(x.Z, a, b), Clamp(x.W, a, b)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d ClampWrap(this V4d x, V4d a, V4d b) { return new V4d(ClampWrap(x.X, a.X, b.X), ClampWrap(x.Y, a.Y, b.Y), ClampWrap(x.Z, a.Z, b.Z), ClampWrap(x.W, a.W, b.W)); } /// /// Applies Fun.ClampWrap to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d ClampWrap(this V4d x, double a, double b) { return new V4d(ClampWrap(x.X, a, b), ClampWrap(x.Y, a, b), ClampWrap(x.Z, a, b), ClampWrap(x.W, a, b)); } /// /// Applies Fun.Saturate to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Saturate(this V4d x) { return new V4d(Saturate(x.X), Saturate(x.Y), Saturate(x.Z), Saturate(x.W)); } #endregion #region MapToUnitInterval /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d MapToUnitInterval(this V4d t, V4d tMax, bool repeat, bool mirror) { return new V4d(MapToUnitInterval(t.X, tMax.X, repeat, mirror), MapToUnitInterval(t.Y, tMax.Y, repeat, mirror), MapToUnitInterval(t.Z, tMax.Z, repeat, mirror), MapToUnitInterval(t.W, tMax.W, repeat, mirror)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d MapToUnitInterval(this V4d t, V4d tMax, bool repeat) { return new V4d(MapToUnitInterval(t.X, tMax.X, repeat), MapToUnitInterval(t.Y, tMax.Y, repeat), MapToUnitInterval(t.Z, tMax.Z, repeat), MapToUnitInterval(t.W, tMax.W, repeat)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d MapToUnitInterval(this V4d t, V4d tMax) { return new V4d(MapToUnitInterval(t.X, tMax.X), MapToUnitInterval(t.Y, tMax.Y), MapToUnitInterval(t.Z, tMax.Z), MapToUnitInterval(t.W, tMax.W)); } /// /// Applies Fun.MapToUnitInterval to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d MapToUnitInterval(this V4d t, V4d tMin, V4d tMax) { return new V4d(MapToUnitInterval(t.X, tMin.X, tMax.X), MapToUnitInterval(t.Y, tMin.Y, tMax.Y), MapToUnitInterval(t.Z, tMin.Z, tMax.Z), MapToUnitInterval(t.W, tMin.W, tMax.W)); } #endregion #region Sign /// /// Applies Fun.Sign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Sign(this V4d x) { return new V4i(Sign(x.X), Sign(x.Y), Sign(x.Z), Sign(x.W)); } /// /// Applies Fun.Signumi to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Signumi(this V4d x) { return new V4i(Signumi(x.X), Signumi(x.Y), Signumi(x.Z), Signumi(x.W)); } /// /// Applies Fun.Signum to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Signum(this V4d x) { return new V4d(Signum(x.X), Signum(x.Y), Signum(x.Z), Signum(x.W)); } #endregion #region Multiply-Add /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d MultiplyAdd(V4d x, V4d y, V4d z) { return new V4d(MultiplyAdd(x.X, y.X, z.X), MultiplyAdd(x.Y, y.Y, z.Y), MultiplyAdd(x.Z, y.Z, z.Z), MultiplyAdd(x.W, y.W, z.W)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d MultiplyAdd(V4d x, double y, V4d z) { return new V4d(MultiplyAdd(x.X, y, z.X), MultiplyAdd(x.Y, y, z.Y), MultiplyAdd(x.Z, y, z.Z), MultiplyAdd(x.W, y, z.W)); } /// /// Applies Fun.MultiplyAdd to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d MultiplyAdd(double x, V4d y, V4d z) { return new V4d(MultiplyAdd(x, y.X, z.X), MultiplyAdd(x, y.Y, z.Y), MultiplyAdd(x, y.Z, z.Z), MultiplyAdd(x, y.W, z.W)); } #endregion #region Copy sign /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d CopySign(V4d value, V4d sign) { return new V4d(CopySign(value.X, sign.X), CopySign(value.Y, sign.Y), CopySign(value.Z, sign.Z), CopySign(value.W, sign.W)); } /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d CopySign(double value, V4d sign) { return new V4d(CopySign(value, sign.X), CopySign(value, sign.Y), CopySign(value, sign.Z), CopySign(value, sign.W)); } /// /// Applies Fun.CopySign to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d CopySign(V4d value, double sign) { return new V4d(CopySign(value.X, sign), CopySign(value.Y, sign), CopySign(value.Z, sign), CopySign(value.W, sign)); } #endregion #region Roots /// /// Applies Fun.Sqrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Sqrt(this V4d x) { return new V4d(Sqrt(x.X), Sqrt(x.Y), Sqrt(x.Z), Sqrt(x.W)); } /// /// Applies Fun.Cbrt to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Cbrt(this V4d x) { return new V4d(Cbrt(x.X), Cbrt(x.Y), Cbrt(x.Z), Cbrt(x.W)); } #endregion #region Square /// /// Applies Fun.Square to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Square(this V4d x) { return new V4d(Square(x.X), Square(x.Y), Square(x.Z), Square(x.W)); } #endregion #region Power /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Pown(this V4d x, V4i y) { return new V4d(Pown(x.X, y.X), Pown(x.Y, y.Y), Pown(x.Z, y.Z), Pown(x.W, y.W)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Pown(this V4d x, int y) { return new V4d(Pown(x.X, y), Pown(x.Y, y), Pown(x.Z, y), Pown(x.W, y)); } /// /// Applies Fun.Pown to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Pown(this double x, V4i y) { return new V4d(Pown(x, y.X), Pown(x, y.Y), Pown(x, y.Z), Pown(x, y.W)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Pow(this V4d x, V4d y) { return new V4d(Pow(x.X, y.X), Pow(x.Y, y.Y), Pow(x.Z, y.Z), Pow(x.W, y.W)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Pow(this V4d x, double y) { return new V4d(Pow(x.X, y), Pow(x.Y, y), Pow(x.Z, y), Pow(x.W, y)); } /// /// Applies Fun.Pow to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Pow(this double x, V4d y) { return new V4d(Pow(x, y.X), Pow(x, y.Y), Pow(x, y.Z), Pow(x, y.W)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Power(this V4d x, V4d y) { return new V4d(Power(x.X, y.X), Power(x.Y, y.Y), Power(x.Z, y.Z), Power(x.W, y.W)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Power(this V4d x, double y) { return new V4d(Power(x.X, y), Power(x.Y, y), Power(x.Z, y), Power(x.W, y)); } /// /// Applies Fun.Power to each element of the given vector(s). /// [Pure] [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Power(this double x, V4d y) { return new V4d(Power(x, y.X), Power(x, y.Y), Power(x, y.Z), Power(x, y.W)); } #endregion #region Exp and Log /// /// Applies Fun.Exp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Exp(this V4d x) { return new V4d(Exp(x.X), Exp(x.Y), Exp(x.Z), Exp(x.W)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log(this V4d x) { return new V4d(Log(x.X), Log(x.Y), Log(x.Z), Log(x.W)); } /// /// Applies Fun.Log2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log2(this V4d x) { return new V4d(Log2(x.X), Log2(x.Y), Log2(x.Z), Log2(x.W)); } /// /// Applies Fun.Log2Int to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4i Log2Int(this V4d x) { return new V4i(Log2Int(x.X), Log2Int(x.Y), Log2Int(x.Z), Log2Int(x.W)); } /// /// Applies Fun.Log10 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log10(this V4d x) { return new V4d(Log10(x.X), Log10(x.Y), Log10(x.Z), Log10(x.W)); } /// /// Applies Fun.Log to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Log(this V4d x, double basis) { return new V4d(Log(x.X, basis), Log(x.Y, basis), Log(x.Z, basis), Log(x.W, basis)); } #endregion #region ModP /// /// Applies Fun.ModP to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d ModP(this V4d a, V4d b) { return new V4d(ModP(a.X, b.X), ModP(a.Y, b.Y), ModP(a.Z, b.Z), ModP(a.W, b.W)); } #endregion #region Power of Two /// /// Applies Fun.PowerOfTwo to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d PowerOfTwo(this V4d x) { return new V4d(PowerOfTwo(x.X), PowerOfTwo(x.Y), PowerOfTwo(x.Z), PowerOfTwo(x.W)); } #endregion #region Trigonometry /// /// Applies Fun.Sin to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Sin(this V4d x) { return new V4d(Sin(x.X), Sin(x.Y), Sin(x.Z), Sin(x.W)); } /// /// Applies Fun.Cos to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Cos(this V4d x) { return new V4d(Cos(x.X), Cos(x.Y), Cos(x.Z), Cos(x.W)); } /// /// Applies Fun.Tan to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Tan(this V4d x) { return new V4d(Tan(x.X), Tan(x.Y), Tan(x.Z), Tan(x.W)); } /// /// Applies Fun.Asin to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Asin(this V4d x) { return new V4d(Asin(x.X), Asin(x.Y), Asin(x.Z), Asin(x.W)); } /// /// Applies Fun.AsinClamped to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d AsinClamped(this V4d x) { return new V4d(AsinClamped(x.X), AsinClamped(x.Y), AsinClamped(x.Z), AsinClamped(x.W)); } /// /// Applies Fun.Acos to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Acos(this V4d x) { return new V4d(Acos(x.X), Acos(x.Y), Acos(x.Z), Acos(x.W)); } /// /// Applies Fun.AcosClamped to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d AcosClamped(this V4d x) { return new V4d(AcosClamped(x.X), AcosClamped(x.Y), AcosClamped(x.Z), AcosClamped(x.W)); } /// /// Applies Fun.Atan to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Atan(this V4d x) { return new V4d(Atan(x.X), Atan(x.Y), Atan(x.Z), Atan(x.W)); } /// /// Applies Fun.Atan2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Atan2(V4d y, V4d x) { return new V4d(Atan2(y.X, x.X), Atan2(y.Y, x.Y), Atan2(y.Z, x.Z), Atan2(y.W, x.W)); } /// /// Applies Fun.FastAtan2 to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d FastAtan2(V4d y, V4d x) { return new V4d(FastAtan2(y.X, x.X), FastAtan2(y.Y, x.Y), FastAtan2(y.Z, x.Z), FastAtan2(y.W, x.W)); } /// /// Applies Fun.Sinh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Sinh(this V4d x) { return new V4d(Sinh(x.X), Sinh(x.Y), Sinh(x.Z), Sinh(x.W)); } /// /// Applies Fun.Cosh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Cosh(this V4d x) { return new V4d(Cosh(x.X), Cosh(x.Y), Cosh(x.Z), Cosh(x.W)); } /// /// Applies Fun.Tanh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Tanh(this V4d x) { return new V4d(Tanh(x.X), Tanh(x.Y), Tanh(x.Z), Tanh(x.W)); } /// /// Applies Fun.Asinh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Asinh(this V4d x) { return new V4d(Asinh(x.X), Asinh(x.Y), Asinh(x.Z), Asinh(x.W)); } /// /// Applies Fun.Acosh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Acosh(this V4d x) { return new V4d(Acosh(x.X), Acosh(x.Y), Acosh(x.Z), Acosh(x.W)); } /// /// Applies Fun.Atanh to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Atanh(this V4d x) { return new V4d(Atanh(x.X), Atanh(x.Y), Atanh(x.Z), Atanh(x.W)); } #endregion #region Step functions /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Step(this V4d x, V4d edge) { return new V4d(Step(x.X, edge.X), Step(x.Y, edge.Y), Step(x.Z, edge.Z), Step(x.W, edge.W)); } /// /// Applies Fun.Step to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Step(this V4d x, double edge) { return new V4d(Step(x.X, edge), Step(x.Y, edge), Step(x.Z, edge), Step(x.W, edge)); } /// /// Applies Fun.Linearstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Linearstep(this V4d x, V4d edge0, V4d edge1) { return new V4d(Linearstep(x.X, edge0.X, edge1.X), Linearstep(x.Y, edge0.Y, edge1.Y), Linearstep(x.Z, edge0.Z, edge1.Z), Linearstep(x.W, edge0.W, edge1.W)); } /// /// Applies Fun.Linearstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Linearstep(this V4d x, double edge0, double edge1) { return new V4d(Linearstep(x.X, edge0, edge1), Linearstep(x.Y, edge0, edge1), Linearstep(x.Z, edge0, edge1), Linearstep(x.W, edge0, edge1)); } /// /// Applies Fun.Smoothstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Smoothstep(this V4d x, V4d edge0, V4d edge1) { return new V4d(Smoothstep(x.X, edge0.X, edge1.X), Smoothstep(x.Y, edge0.Y, edge1.Y), Smoothstep(x.Z, edge0.Z, edge1.Z), Smoothstep(x.W, edge0.W, edge1.W)); } /// /// Applies Fun.Smoothstep to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Smoothstep(this V4d x, double edge0, double edge1) { return new V4d(Smoothstep(x.X, edge0, edge1), Smoothstep(x.Y, edge0, edge1), Smoothstep(x.Z, edge0, edge1), Smoothstep(x.W, edge0, edge1)); } #endregion #region Interpolation /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Lerp(this double t, V4d a, V4d b) { return new V4d(Lerp(t, a.X, b.X), Lerp(t, a.Y, b.Y), Lerp(t, a.Z, b.Z), Lerp(t, a.W, b.W)); } /// /// Applies Fun.Lerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Lerp(this V4d t, V4d a, V4d b) { return new V4d(Lerp(t.X, a.X, b.X), Lerp(t.Y, a.Y, b.Y), Lerp(t.Z, a.Z, b.Z), Lerp(t.W, a.W, b.W)); } /// /// Applies Fun.InvLerp to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d InvLerp(this V4d y, V4d a, V4d b) { return new V4d(InvLerp(y.X, a.X, b.X), InvLerp(y.Y, a.Y, b.Y), InvLerp(y.Z, a.Z, b.Z), InvLerp(y.W, a.W, b.W)); } #endregion #region Floating point bits /// /// Applies Fun.FloatToBits to each element of the given vector(s). /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4l FloatToBits(this V4d x) { return new V4l(FloatToBits(x.X), FloatToBits(x.Y), FloatToBits(x.Z), FloatToBits(x.W)); } #endregion #region ApproximateEquals /// /// Returns whether the given vectors are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V4d a, V4d b, double tolerance) { return ApproximateEquals(a.X, b.X, tolerance) && ApproximateEquals(a.Y, b.Y, tolerance) && ApproximateEquals(a.Z, b.Z, tolerance) && ApproximateEquals(a.W, b.W, tolerance); } /// /// Returns whether the given vectors are equal within /// Constant{double}.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this V4d a, V4d b) { return ApproximateEquals(a, b, Constant.PositiveTinyValue); } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this V4d v, double epsilon) => Vec.AllTiny(v, epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than Constant<double>.PositiveTinyValue. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(V4d v) => v.IsTiny; #endregion #region Special Floating Point Value Checks /// /// Returns whether any component of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(V4d v) => v.IsNaN; /// /// Returns whether any component of the the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(V4d v) => v.IsInfinity; /// /// Returns whether any component of the the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(V4d v) => v.IsPositiveInfinity; /// /// Returns whether any component of the the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(V4d v) => v.IsNegativeInfinity; /// /// Returns whether all components of the the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(V4d v) => v.IsFinite; #endregion } public static partial class Conversion { #region Angles (Radians, Degrees, Gons) /// /// Converts the angles given in degrees to radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d RadiansFromDegrees(this V4d degrees) => new V4d( RadiansFromDegrees(degrees.X), RadiansFromDegrees(degrees.Y), RadiansFromDegrees(degrees.Z), RadiansFromDegrees(degrees.W) ); /// /// Converts the angles given in gons to radians. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d RadiansFromGons(this V4d gons) => new V4d( RadiansFromGons(gons.X), RadiansFromGons(gons.Y), RadiansFromGons(gons.Z), RadiansFromGons(gons.W) ); /// /// Converts the angles given in radians to degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d DegreesFromRadians(this V4d radians) => new V4d( DegreesFromRadians(radians.X), DegreesFromRadians(radians.Y), DegreesFromRadians(radians.Z), DegreesFromRadians(radians.W) ); /// /// Converts the angles given in gons to degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d DegreesFromGons(this V4d gons) => new V4d( DegreesFromGons(gons.X), DegreesFromGons(gons.Y), DegreesFromGons(gons.Z), DegreesFromGons(gons.W) ); /// /// Converts the angles given in radians to gons. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d GonsFromRadians(this V4d radians) => new V4d( GonsFromRadians(radians.X), GonsFromRadians(radians.Y), GonsFromRadians(radians.Z), GonsFromRadians(radians.W) ); /// /// Converts the angles given in degrees to gons. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d GonsFromDegrees(this V4d degrees) => new V4d( GonsFromDegrees(degrees.X), GonsFromDegrees(degrees.Y), GonsFromDegrees(degrees.Z), GonsFromDegrees(degrees.W) ); #endregion } /// /// Contains static methods /// public static partial class Vec { #region Length /// /// Returns the squared length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double LengthSquared(V4d v) => v.LengthSquared; /// /// Returns the length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Length(V4d v) => v.Length; #endregion #region Normalize /// /// Normalizes the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref V4d v) { var s = v.Length; if (s == 0) return; s = 1 / s; v.X *= s; v.Y *= s; v.Z *= s; v.W *= s; } /// /// Returns a normalized copy of this vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Normalized(V4d v) => v.Normalized; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm1(V4d v) => v.Norm1; /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm2(V4d v) => v.Norm2; /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormMax(V4d v) => v.NormMax; /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NormMin(V4d v) => v.NormMin; /// /// Gets the p-norm. This is calculated as the p-th root of (|x|^n + |y|^n + ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Norm(this V4d v, double p) { return ( Fun.Abs(v.X).Pow(p) + Fun.Abs(v.Y).Pow(p) + Fun.Abs(v.Z).Pow(p) + Fun.Abs(v.W).Pow(p)).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the squared distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceSquared(this V4d a, V4d b) => Fun.Square(b.X - a.X) + Fun.Square(b.Y - a.Y) + Fun.Square(b.Z - a.Z) + Fun.Square(b.W - a.W); /// /// Returns the distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V4d a, V4d b) => Fun.Sqrt(DistanceSquared(a, b)); /// /// Returns the Manhatten (or 1-) distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance1(this V4d a, V4d b) => Fun.Abs(b.X - a.X) + Fun.Abs(b.Y - a.Y) + Fun.Abs(b.Z - a.Z) + Fun.Abs(b.W - a.W); /// /// Returns the p-distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this V4d a, V4d b, double p) => (Fun.Abs(b.X - a.X).Pow(p) + Fun.Abs(b.Y - a.Y).Pow(p) + Fun.Abs(b.Z - a.Z).Pow(p) + Fun.Abs(b.W - a.W).Pow(p)).Pow(1 / p); /// /// Returns the maximal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceMax(this V4d a, V4d b) => Fun.Max(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y), Fun.Abs(b.Z - a.Z), Fun.Abs(b.W - a.W)); /// /// Returns the minimal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceMin(this V4d a, V4d b) => Fun.Min(Fun.Abs(b.X - a.X), Fun.Abs(b.Y - a.Y), Fun.Abs(b.Z - a.Z), Fun.Abs(b.W - a.W)); /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V4d query, V4d p0, V4d p1) { var p0p1 = p1 - p0; var p0q = query - p0; var t = Dot(p0q, p0p1); if (t <= 0) { return p0q.Length; } var denom = p0p1.LengthSquared; if (t >= denom) { return Distance(query, p1); } t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V4d query, V4d p0, V4d p1) { var p0p1 = p1 - p0; var p0q = query - p0; var t = Dot(p0q, p0p1); var denom = p0p1.LengthSquared; t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToLine( this V4d query, V4d p0, V4d p1, out double t) { var p0p1 = p1 - p0; var p0q = query - p0; t = Dot(p0q, p0p1); if (t <= 0) { t = 0; return p0q.Length; } var denom = p0p1.LengthSquared; if (t >= denom) { t = 1; return Distance(query, p1); } t /= denom; return (p0q - t * p0p1).Length; } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double DistanceToInfiniteLine( this V4d query, V4d p0, V4d p1, out double t) { var p0p1 = p1 - p0; var p0q = query - p0; t = Dot(p0q, p0p1); var denom = p0p1.LengthSquared; t /= denom; return (p0q - t * p0p1).Length; } #endregion #region Operations /// /// Gets a copy of the given vector containing the reciprocal (1/x) of each element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Reciprocal(V4d v) => v.Reciprocal; /// /// Negates the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Negate(this ref V4d v) { v.X = -v.X; v.Y = -v.Y; v.Z = -v.Z; v.W = -v.W; } /// /// Returns the outer product (tensor-product) of a * b^T as a 4x4 matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static M44d Outer(this V4d a, V4d b) { return new M44d( a.X * b.X, a.X * b.Y, a.X * b.Z, a.X * b.W, a.Y * b.X, a.Y * b.Y, a.Y * b.Z, a.Y * b.W, a.Z * b.X, a.Z * b.Y, a.Z * b.Z, a.Z * b.W, a.W * b.X, a.W * b.Y, a.W * b.Z, a.W * b.W); } /// /// Returns the dot product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Dot(this V4d a, V4d b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z + a.W * b.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DirFlags DirFlags(this V4d v) { DirFlags flags = Aardbase.DirFlags.None; if (v.X > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveX; if (v.X < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeX; if (v.Y > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveY; if (v.Y < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeY; if (v.Z > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveZ; if (v.Z < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeZ; if (v.W > Constant.PositiveTinyValue) flags |= Aardbase.DirFlags.PositiveW; if (v.W < Constant.NegativeTinyValue) flags |= Aardbase.DirFlags.NegativeW; return flags; } /// /// Returns the reflection direction of the given vector v (pointing to the surface) for the given normal (should be normalized). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Reflect(this V4d v, V4d normal) { return v - 2 * v.Dot(normal) * normal; } /// /// Returns the refraction direction of the given vector v (pointing to the surface) for the given normal and ratio of refraction indices (n_out / n_in). /// Both the input vectors should be normalized. /// Returns a zero-vector in case of total internal reflection. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d Refract(this V4d v, V4d normal, double eta) { var t = v.Dot(normal); var k = 1 - eta * eta * (1 - t * t); if (k < 0) { return V4d.Zero; } else { return eta * v - (eta * t + Fun.Sqrt(k)) * normal; } } #endregion #region Comparisons /// /// Returns whether ALL elements of a are Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V4d a, V4d b) { return (a.X < b.X && a.Y < b.Y && a.Z < b.Z && a.W < b.W); } /// /// Returns whether ALL elements of v are Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(this V4d v, double s) { return (v.X < s && v.Y < s && v.Z < s && v.W < s); } /// /// Returns whether a is Smaller ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmaller(double s, V4d v) { return (s < v.X && s < v.Y && s < v.Z && s < v.W); } /// /// Returns whether AT LEAST ONE element of a is Smaller the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V4d a, V4d b) { return (a.X < b.X || a.Y < b.Y || a.Z < b.Z || a.W < b.W); } /// /// Returns whether AT LEAST ONE element of v is Smaller s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(this V4d v, double s) { return (v.X < s || v.Y < s || v.Z < s || v.W < s); } /// /// Returns whether a is Smaller AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmaller(double s, V4d v) { return (s < v.X || s < v.Y || s < v.Z || s < v.W); } /// /// Returns whether ALL elements of a are Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V4d a, V4d b) { return (a.X > b.X && a.Y > b.Y && a.Z > b.Z && a.W > b.W); } /// /// Returns whether ALL elements of v are Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(this V4d v, double s) { return (v.X > s && v.Y > s && v.Z > s && v.W > s); } /// /// Returns whether a is Greater ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreater(double s, V4d v) { return (s > v.X && s > v.Y && s > v.Z && s > v.W); } /// /// Returns whether AT LEAST ONE element of a is Greater the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V4d a, V4d b) { return (a.X > b.X || a.Y > b.Y || a.Z > b.Z || a.W > b.W); } /// /// Returns whether AT LEAST ONE element of v is Greater s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(this V4d v, double s) { return (v.X > s || v.Y > s || v.Z > s || v.W > s); } /// /// Returns whether a is Greater AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreater(double s, V4d v) { return (s > v.X || s > v.Y || s > v.Z || s > v.W); } /// /// Returns whether ALL elements of a are SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V4d a, V4d b) { return (a.X <= b.X && a.Y <= b.Y && a.Z <= b.Z && a.W <= b.W); } /// /// Returns whether ALL elements of v are SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(this V4d v, double s) { return (v.X <= s && v.Y <= s && v.Z <= s && v.W <= s); } /// /// Returns whether a is SmallerOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllSmallerOrEqual(double s, V4d v) { return (s <= v.X && s <= v.Y && s <= v.Z && s <= v.W); } /// /// Returns whether AT LEAST ONE element of a is SmallerOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V4d a, V4d b) { return (a.X <= b.X || a.Y <= b.Y || a.Z <= b.Z || a.W <= b.W); } /// /// Returns whether AT LEAST ONE element of v is SmallerOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(this V4d v, double s) { return (v.X <= s || v.Y <= s || v.Z <= s || v.W <= s); } /// /// Returns whether a is SmallerOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnySmallerOrEqual(double s, V4d v) { return (s <= v.X || s <= v.Y || s <= v.Z || s <= v.W); } /// /// Returns whether ALL elements of a are GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V4d a, V4d b) { return (a.X >= b.X && a.Y >= b.Y && a.Z >= b.Z && a.W >= b.W); } /// /// Returns whether ALL elements of v are GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(this V4d v, double s) { return (v.X >= s && v.Y >= s && v.Z >= s && v.W >= s); } /// /// Returns whether a is GreaterOrEqual ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllGreaterOrEqual(double s, V4d v) { return (s >= v.X && s >= v.Y && s >= v.Z && s >= v.W); } /// /// Returns whether AT LEAST ONE element of a is GreaterOrEqual the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V4d a, V4d b) { return (a.X >= b.X || a.Y >= b.Y || a.Z >= b.Z || a.W >= b.W); } /// /// Returns whether AT LEAST ONE element of v is GreaterOrEqual s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(this V4d v, double s) { return (v.X >= s || v.Y >= s || v.Z >= s || v.W >= s); } /// /// Returns whether a is GreaterOrEqual AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyGreaterOrEqual(double s, V4d v) { return (s >= v.X || s >= v.Y || s >= v.Z || s >= v.W); } /// /// Returns whether ALL elements of a are Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V4d a, V4d b) { return (a.X == b.X && a.Y == b.Y && a.Z == b.Z && a.W == b.W); } /// /// Returns whether ALL elements of v are Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(this V4d v, double s) { return (v.X == s && v.Y == s && v.Z == s && v.W == s); } /// /// Returns whether a is Equal ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllEqual(double s, V4d v) { return (s == v.X && s == v.Y && s == v.Z && s == v.W); } /// /// Returns whether AT LEAST ONE element of a is Equal the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V4d a, V4d b) { return (a.X == b.X || a.Y == b.Y || a.Z == b.Z || a.W == b.W); } /// /// Returns whether AT LEAST ONE element of v is Equal s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(this V4d v, double s) { return (v.X == s || v.Y == s || v.Z == s || v.W == s); } /// /// Returns whether a is Equal AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyEqual(double s, V4d v) { return (s == v.X || s == v.Y || s == v.Z || s == v.W); } /// /// Returns whether ALL elements of a are Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V4d a, V4d b) { return (a.X != b.X && a.Y != b.Y && a.Z != b.Z && a.W != b.W); } /// /// Returns whether ALL elements of v are Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(this V4d v, double s) { return (v.X != s && v.Y != s && v.Z != s && v.W != s); } /// /// Returns whether a is Different ALL elements of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllDifferent(double s, V4d v) { return (s != v.X && s != v.Y && s != v.Z && s != v.W); } /// /// Returns whether AT LEAST ONE element of a is Different the corresponding element of b. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V4d a, V4d b) { return (a.X != b.X || a.Y != b.Y || a.Z != b.Z || a.W != b.W); } /// /// Returns whether AT LEAST ONE element of v is Different s. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(this V4d v, double s) { return (v.X != s || v.Y != s || v.Z != s || v.W != s); } /// /// Returns whether a is Different AT LEAST ONE element of v. /// ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b)). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyDifferent(double s, V4d v) { return (s != v.X || s != v.Y || s != v.Z || s != v.W); } /// /// Compare x-coordinate before y-coordinate, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this V4d v0, V4d v1) { if (v0.X < v1.X) return -1; if (v0.X > v1.X) return +1; if (v0.Y < v1.Y) return -1; if (v0.Y > v1.Y) return +1; if (v0.Z < v1.Z) return -1; if (v0.Z > v1.Z) return +1; if (v0.W < v1.W) return -1; if (v0.W > v1.W) return +1; return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MinElement(V4d v) => v.MinElement; /// /// Returns the maximum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double MaxElement(V4d v) => v.MaxElement; #endregion #region Angle between two vectors /// /// Computes the angle between two given vectors in radians. The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double AngleBetweenFast(this V4d x, V4d y) { return Fun.AcosClamped(x.Dot(y)); } /// /// Computes the angle between two given vectors in radians using a numerically stable algorithm. /// The input vectors have to be normalized. /// // https://scicomp.stackexchange.com/a/27769 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double AngleBetween(this V4d x, V4d y) { var a = x + y; var b = x - y; return 2 * Fun.Atan2(b.Length, a.Length); } #endregion #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this V4d v, double epsilon) => v.X.IsTiny(epsilon) || v.Y.IsTiny(epsilon) || v.Z.IsTiny(epsilon) || v.W.IsTiny(epsilon); /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this V4d v, double epsilon) => v.X.IsTiny(epsilon) && v.Y.IsTiny(epsilon) && v.Z.IsTiny(epsilon) && v.W.IsTiny(epsilon); #endregion #region Special Floating Point Value Checks [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyFinite(V4d v) => v.AnyFinite; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllFinite(V4d v) => v.AllFinite; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNaN(V4d v) => v.AnyNaN; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNaN(V4d v) => v.AllNaN; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyInfinity(V4d v) => v.AnyInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllInfinity(V4d v) => v.AllInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyPositiveInfinity(V4d v) => v.AnyPositiveInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllPositiveInfinity(V4d v) => v.AllPositiveInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyNegativeInfinity(V4d v) => v.AnyNegativeInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllNegativeInfinity(V4d v) => v.AllNegativeInfinity; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(V4d v) => v.AnyTiny; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(V4d v) => v.AllTiny; #endregion #region Linear Combination [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d LinCom(V4d p0, V4d p1, ref Tup2 w) { return p0 * w.E0 + p1 * w.E1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d LinCom(V4d p0, V4d p1, V4d p2, ref Tup3 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d LinCom(V4d p0, V4d p1, V4d p2, V4d p3, ref Tup4 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d LinCom(V4d p0, V4d p1, V4d p2, V4d p3, V4d p4, ref Tup5 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d LinCom(V4d p0, V4d p1, V4d p2, V4d p3, V4d p4, V4d p5, ref Tup6 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d LinCom(V4d p0, V4d p1, V4d p2, V4d p3, V4d p4, V4d p5, V4d p6, ref Tup7 w) { return p0 * w.E0 + p1 * w.E1 + p2 * w.E2 + p3 * w.E3 + p4 * w.E4 + p5 * w.E5 + p6 * w.E6; } #endregion #region ArrayExtensions public static int IndexOfClosestPoint(this V4d[] pointArray, V4d point) { var bestDist = DistanceSquared(point, pointArray[0]); int bestIndex = 0; int count = pointArray.Length; for (int i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this V4d[] array, int start, int count, V4d point) { var bestDist = DistanceSquared(point, array[start]); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static int IndexOfClosestPoint( this T[] array, int start, int count, Func pointSelector, V4d point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); int bestIndex = 0; for (int i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint(this V4d[] pointArray, V4d point) { var bestDist = DistanceSquared(point, pointArray[0]); long bestIndex = 0; long count = pointArray.LongLength; for (long i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this V4d[] array, long start, long count, V4d point) { var bestDist = DistanceSquared(point, array[start]); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static long LongIndexOfClosestPoint( this T[] array, long start, long count, Func pointSelector, V4d point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); long bestIndex = 0; for (long i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static int IndexOfMinX(this V4d[] vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the array. /// public static long LongIndexOfMinX(this V4d[] vectorArray, long count = 0) { var minimum = vectorArray[0].X; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static int IndexOfMaxX(this V4d[] vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the array. /// public static long LongIndexOfMaxX(this V4d[] vectorArray, long count = 0) { var maximum = vectorArray[0].X; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static int IndexOfMinY(this V4d[] vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the array. /// public static long LongIndexOfMinY(this V4d[] vectorArray, long count = 0) { var minimum = vectorArray[0].Y; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static int IndexOfMaxY(this V4d[] vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the array. /// public static long LongIndexOfMaxY(this V4d[] vectorArray, long count = 0) { var maximum = vectorArray[0].Y; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static int IndexOfMinZ(this V4d[] vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the array. /// public static long LongIndexOfMinZ(this V4d[] vectorArray, long count = 0) { var minimum = vectorArray[0].Z; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static int IndexOfMaxZ(this V4d[] vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the array. /// public static long LongIndexOfMaxZ(this V4d[] vectorArray, long count = 0) { var maximum = vectorArray[0].Z; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal W coordinate /// within the array. /// public static int IndexOfMinW(this V4d[] vectorArray, int count = 0) { var minimum = vectorArray[0].W; int minIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the minimal W coordinate /// within the array. /// public static long LongIndexOfMinW(this V4d[] vectorArray, long count = 0) { var minimum = vectorArray[0].W; long minIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].W; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal W coordinate /// within the array. /// public static int IndexOfMaxW(this V4d[] vectorArray, int count = 0) { var maximum = vectorArray[0].W; int maxIndex = 0; if (count == 0) count = vectorArray.Length; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the maximal W coordinate /// within the array. /// public static long LongIndexOfMaxW(this V4d[] vectorArray, long count = 0) { var maximum = vectorArray[0].W; long maxIndex = 0; if (count == 0) count = vectorArray.LongLength; for (long i = 1; i < count; i++) { var p = vectorArray[i].W; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal X coordinate /// within the list. /// public static int IndexOfMinX(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].X; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal X coordinate /// within the list. /// public static int IndexOfMaxX(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].X; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].X; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Y coordinate /// within the list. /// public static int IndexOfMinY(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Y; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Y coordinate /// within the list. /// public static int IndexOfMaxY(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Y; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Y; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal Z coordinate /// within the list. /// public static int IndexOfMinZ(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].Z; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal Z coordinate /// within the list. /// public static int IndexOfMaxZ(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].Z; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].Z; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the index of the element with the minimal W coordinate /// within the list. /// public static int IndexOfMinW(this IList vectorArray, int count = 0) { var minimum = vectorArray[0].W; int minIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p < minimum) { minimum = p; minIndex = i; } } return minIndex; } /// /// Returns the index of the element with the maximal W coordinate /// within the list. /// public static int IndexOfMaxW(this IList vectorArray, int count = 0) { var maximum = vectorArray[0].W; int maxIndex = 0; if (count == 0) count = vectorArray.Count; for (int i = 1; i < count; i++) { var p = vectorArray[i].W; if (p > maximum) { maximum = p; maxIndex = i; } } return maxIndex; } /// /// Returns the array of the index-th coordinate of each vector. /// public static double[] CopyCoord(this V4d[] self, int index) { switch (index) { case 0: return self.Map(v => v.X); case 1: return self.Map(v => v.Y); case 2: return self.Map(v => v.Z); case 3: return self.Map(v => v.W); default: throw new IndexOutOfRangeException(); } } public static V4d WeightedSum( this V4d[] vectorArray, double[] weightArray) { var r = V4d.Zero; var count = vectorArray.LongLength; for (long i = 0; i < count; i++) r += vectorArray[i] * weightArray[i]; return r; } #endregion } public static class IRandomUniformV4dExtensions { #region IRandomUniform extensions for V4d /// /// Uses UniformDouble() to generate the elements of a V4d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d UniformV4d(this IRandomUniform rnd) { return new V4d(rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble(), rnd.UniformDouble()); } /// /// Uses UniformDoubleClosed() to generate the elements of a V4d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d UniformV4dClosed(this IRandomUniform rnd) { return new V4d(rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed(), rnd.UniformDoubleClosed()); } /// /// Uses UniformDoubleOpen() to generate the elements of a V4d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d UniformV4dOpen(this IRandomUniform rnd) { return new V4d(rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen(), rnd.UniformDoubleOpen()); } /// /// Uses UniformDoubleFull() to generate the elements of a V4d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d UniformV4dFull(this IRandomUniform rnd) { return new V4d(rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull(), rnd.UniformDoubleFull()); } /// /// Uses UniformDoubleFullClosed() to generate the elements of a V4d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d UniformV4dFullClosed(this IRandomUniform rnd) { return new V4d(rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed(), rnd.UniformDoubleFullClosed()); } /// /// Uses UniformDoubleFullOpen() to generate the elements of a V4d vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static V4d UniformV4dFullOpen(this IRandomUniform rnd) { return new V4d(rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen(), rnd.UniformDoubleFullOpen()); } #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Math/Vectors/Vector_template.cs ================================================ using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Xml.Serialization; #if NETCOREAPP3_1_OR_GREATER using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics; #endif using Aardbase = Aardvark.Base; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! [Flags] public enum DirFlags { None = 0x00, NegativeX = 0x01, PositiveX = 0x02, NegativeY = 0x04, PositiveY = 0x08, NegativeZ = 0x10, PositiveZ = 0x20, NegativeW = 0x40, PositiveW = 0x80, X = NegativeX | PositiveX, Y = NegativeY | PositiveY, Z = NegativeZ | PositiveZ, }; //# Action comma = () => Out(", "); //# Action add = () => Out(" + "); //# Action addqcommaspace = () => Out(" + \", \" "); //# Action addbetween = () => Out(" + between "); //# Action andand = () => Out(" && "); //# Action oror = () => Out(" || "); //# Action xor = () => Out(" ^ "); //# Action el = () => Out("else "); //# string f0 = Meta.VecFields[0], f1 = Meta.VecFields[1]; //# string f2 = Meta.VecFields[2], f3 = Meta.VecFields[3]; //# var fdtypes = new[] { Meta.FloatType, Meta.DoubleType }; //# var allfields = Meta.VecFields; //# //# Func iscolormapped = //# (t1, t2) => (t1 != t2) && !(t1.IsReal && t2.IsReal); //# //# Func coltovecsupported = //# (cft, vft) => (!cft.IsReal || vft.IsReal) && (cft != Meta.UIntType || vft != Meta.IntType); //# //# var colmaxvalmap = new Dictionary //# { //# { Meta.ByteType, "255" }, //# { Meta.UShortType, "2^16 - 1" }, //# { Meta.UIntType, "2^32 - 1" }, //# { Meta.FloatType, "1" }, //# { Meta.DoubleType, "1" }, //# }; //# foreach (var vt in Meta.VecTypes) { //# int d = vt.Len; //# var ft = vt.FieldType; //# var unsigned = Meta.UnsignedTypes.Contains(ft); //# var ct = Meta.ComputationTypeOf(ft); //# var ht = Meta.HighPrecisionTypeOf(ft); //# var vct = Meta.VecTypeOf(d, ct); //# var vtype = vt.Name; //# var fcaps = ft.Caps; //# var ftype = ft.Name; //# var fchar = ft.Char; //# var ctype = ct.Name; //# var htype = ht.Name; //# var vctype = vct.Name; //# var vitype = Meta.VecTypeOf(d, Meta.IntType).Name; //# var v2type = Meta.VecTypeOf(2, ft).Name; //# var v3type = Meta.VecTypeOf(3, ft).Name; //# var v4type = Meta.VecTypeOf(4, ft).Name; //# var mtype = unsigned ? "UnknownMatrixType" : Meta.MatTypeOf(d, d, ft).Name; //# var fields = vt.Fields; //# var args = fields.ToLower(); //# var getptr = "&" + fields[0]; #region __vtype__ [DataContract] [Serializable] [StructLayout(LayoutKind.Sequential)] public partial struct __vtype__ : IVector, ISize__d____fchar__, IFormattable, IEquatable<__vtype__> { //# fields.ForEach(f => { [DataMember] public __ftype__ __f__; //# }); #region Constructors //# foreach (var ft1 in Meta.VecFieldTypes) { //# var vt1 = Meta.VecTypeOf(d, ft1); //# var ftype1 = ft1.Name; /// /// Creates a new vector from given elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __vtype__(/*# args.ForEach(a => { */__ftype1__ __a__/*# }, comma); */) { //# fields.ForEach(args, (f, a) => { __f__ = /*# if (ft != ft1) { */(__ftype__)/*# } */__a__; //# }); } /// /// Creates a new vector by assigning the given to all elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __vtype__(__ftype1__ v) { //# fields.ForEach(args, (f, a) => { __f__ = /*# if (ft != ft1) { */(__ftype__)/*# } */v; //# }); } /// /// Creates a new vector from the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __vtype__(__ftype1__[] a) { //# fields.ForEach((f, i) => { __f__ = /*# if (ft != ft1) { */(__ftype__)/*# } */a[__i__]; //# }); } /// /// Creates a new vector from given array, starting at specified index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __vtype__(__ftype1__[] a, int start) { //# fields.ForEach((f, i) => { __f__ = /*# if (ft != ft1) {*/(__ftype__)/*# } */a[start + __i__]; //# }); } //# if (d > 2) { for (int i = 1; i < d; i++) { var j = d - i; //# var fsttype = (i > 1) ? Meta.VecTypeOf(i, ft1) : ft1; //# var sndtype = (j > 1) ? Meta.VecTypeOf(j, ft1) : ft1; /// /// Creates a new vector from the given and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __vtype__(__fsttype.Name__ a, __sndtype.Name__ b) { //# if (i == 1) { __f0__ = /*# if (ft != ft1) {*/(__ftype__)/*# }*/a; //# } else { for (int k = 0; k < i; k++) { var fk = Meta.VecFields[k]; __fk__ = /*# if (ft != ft1) {*/(__ftype__)/*# }*/a.__fk__; //# } } //# if (j == 1) { var fj = Meta.VecFields[i]; __fj__ = /*# if (ft != ft1) {*/(__ftype__)/*# }*/b; //# } else { for (int k = 0; k < j; k++) { var fj = Meta.VecFields[i + k]; var fk = Meta.VecFields[k]; __fj__ = /*# if (ft != ft1) {*/(__ftype__)/*# }*/b.__fk__; //# } } } //# } } //# if (d > 3) { for (int i = 0; i < 3; i++) { //# var t0 = (i == 0) ? Meta.VecTypeOf(2, ft1).Name : ft1.Name; //# var t1 = (i == 1) ? Meta.VecTypeOf(2, ft1).Name : ft1.Name; //# var t2 = (i == 2) ? Meta.VecTypeOf(2, ft1).Name : ft1.Name; /// /// Creates a new vector from the given , , and . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __vtype__(__t0__ a, __t1__ b, __t2__ c) { //# if (i != 0) { __f0__ = /*# if (ft != ft1) {*/(__ftype__)/*# }*/a; //# } else { for (int k = 0; k < 2; k++) { var fk = Meta.VecFields[k]; __fk__ = /*# if (ft != ft1) {*/(__ftype__)/*# }*/a.__fk__; //# } } //# if (i != 1) { var fj = Meta.VecFields[(i < 1) ? 2 : 1]; __fj__ = /*# if (ft != ft1) {*/(__ftype__)/*# }*/b; //# } else { for (int k = 0; k < 2; k++) { var fj = Meta.VecFields[((i < 1) ? 2 : 1) + k]; var fk = Meta.VecFields[k]; __fj__ = /*# if (ft != ft1) {*/(__ftype__)/*# }*/b.__fk__; //# } } //# if (i != 2) { __f3__ = /*# if (ft != ft1) {*/(__ftype__)/*# }*/c; //# } else { for (int k = 0; k < 2; k++) { var fj = Meta.VecFields[2 + k]; var fk = Meta.VecFields[k]; __fj__ = /*# if (ft != ft1) {*/(__ftype__)/*# }*/c.__fk__; //# } } } //# } } //# } /// /// Creates a vector from the results of the supplied function of the index. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __vtype__(Func index_fun) { //# fields.ForEach((f, fi) => { __f__ = index_fun(__fi__); //# }); } /// /// Creates a vector from a general vector implementing the IVector<__ftype__> interface. /// The caller has to verify that the dimension of is at least __d__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __vtype__(IVector v) : this(/*# d.ForEach(i => {*/v[__i__]/*# }, comma); */) { } //# foreach (var vt1 in Meta.VecTypes) { //# var vtype1 = vt1.Name; //# var d1 = vt1.Len; //# var ft1 = vt1.FieldType; //# var cast = (ft != ft1) ? "(" + ftype + ")" : ""; //# var missingfields = allfields.Skip(d1).Take(d - d1); //# var mfcount = missingfields.Count(); //# var ignoredfields = allfields.Skip(d).Take(d1 - d); //# var ifcount = ignoredfields.Count(); /// /// Creates a vector from another vector of type . //# if (mfcount > 0) { var isare = (mfcount > 1) ? "are" : "is"; /// /*# missingfields.ForEach(f => {*/__f__/*# }, comma);*/ __isare__ set to zero. //# } //# if (ifcount > 0) { var isare = (ifcount > 1) ? "are" : "is"; /// /*# ignoredfields.ForEach(f => {*/v.__f__/*# }, comma);*/ __isare__ ignored. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __vtype__(__vtype1__ v) { //# fields.ForEach((f, i) => { //# if (i < d1) { __f__ = __cast__v.__f__; //# } else { __f__ = 0; //# } //# }); } //# } //# if (d == 3 || d == 4) { //# foreach (var t1 in Meta.ColorTypes) { var ft1 = t1.FieldType; //# if (coltovecsupported(ft1, ft)) { //# var type1 = t1.Name; //# var ftype1 = ft1.Name; //# var convert = ft != ft1 ? "("+ ftype +")" : ""; //# var maxval = colmaxvalmap[ft1]; /// /// Creates a vector from a color. //# if (iscolormapped(ft, ft1)) { /// The values are not mapped from the color range. //# } //# if (d == 4 && !t1.HasAlpha) { /// W is set to __maxval__. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public __vtype__(__type1__ c) { //# t1.Channels.ForEach(fields, (c, f) => { __f__ = __convert__(c.__c__); //# }); //# if (d == 4) { //# if (t1.HasAlpha) { W = __convert__(c.A); //# } else { W = __convert____t1.MaxValue__; //# } //# } } //# } } //# } #endregion #region Conversions //# foreach (var vt1 in Meta.VecTypes) { //# var vtype1 = vt1.Name; //# if (vt != vt1) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __vtype__(__vtype1__ v) => new __vtype__(v); //# } } //# foreach (var vt1 in Meta.VecTypes) { //# var ft1 = vt1.FieldType; //# var vtype1 = vt1.Name; //# var d1 = vt1.Len; //# if (vt != vt1 && (ft != ft1 || d < d1)) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __vtype1__ To__vtype1__() => (__vtype1__)this; //# } } //# foreach (var ft1 in Meta.VecFieldTypes) { //# var ftype1 = ft1.Name; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __ftype1__[](__vtype__ v) => new __ftype1__[] { /*# fields.ForEach(f => { if (ft != ft1) { */(__ftype1__)/*# } */v.__f__/*# }, comma); */ }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __vtype__(__ftype1__[] v) => new __vtype__(/*# d.ForEach(fi => { if (ft != ft1) { */(__ftype__)/*# } */v[__fi__]/*# }, comma); */); //# } //# if (d == 3 || d == 4) { //# foreach (var t1 in Meta.ColorTypes) { var ft1 = t1.FieldType; //# if (coltovecsupported(ft1, ft)) { //# var type1 = t1.Name; //# var ftype1 = ft1.Name; //# var convert = ft != ft1 ? "("+ ftype +")" : ""; //# var maxval = colmaxvalmap[ft1]; /// /// Converts the given color to a vector. //# if (iscolormapped(ft, ft1)) { /// The values are not mapped from the color range. //# } //# if (d == 4 && !t1.HasAlpha) { /// W is set to __maxval__. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator __vtype__(__type1__ v) => new __vtype__(v); /// /// Converts the given vector to a color. //# if (iscolormapped(ft, ft1)) { /// The values are not mapped to the color range. //# } //# if (d == 3 && t1.HasAlpha) { /// The alpha channel is set to __maxval__. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __type1__ To__type1__() => (__type1__)this; //# } } //# } //# if (ft.IsReal) { //# var ichar = ft == Meta.DoubleType ? "l" : "i"; //# var icast = ft == Meta.DoubleType ? "long" : "int"; //# foreach (var floor in new[] { "Floor", "Ceiling" }) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly V__d____ichar__ To__floor__V__d____ichar__() => new V__d____ichar__(/*# vt.Fields.ForEach(f => { */(__icast__)Fun.__floor__(__f__)/*# }, comma); */); //# } //# } //# if (d >= 3 && ft.IsReal) { //# foreach (var ft1 in Meta.VecFieldTypes) { //# var vt1 = Meta.VecTypeOf(d-1, ft1); //# var vtype1 = vt1.Name; //# var ftype1 = ft1.Name; //# var lastF = fields.Last(); /// /// Creates the inhomogenized Version by dividing the first elements by the last element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __vtype1__ To__vtype1__Inhomo() { var div = 1 / __lastF__; return new __vtype1__(/*# vt1.Fields.ForEach(f => { */__f__ * div/*# }, comma); */); } //# } //# } //# if (d <= 3 && ft.IsReal) { //# foreach (var ft1 in Meta.VecFieldTypes) { //# var vt1 = Meta.VecTypeOf(d+1, ft1); //# var vtype1 = vt1.Name; //# var ftype1 = ft1.Name; /// /// Creates the homogenized Version by adding an additional element 1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __vtype1__ To__vtype1__Homo() => new __vtype1__(/*# fields.ForEach(f => { */__f__/*# }, comma); */, 1); //# } //# } //# foreach (var ft1 in Meta.VecFieldTypes) { //# var vt1 = Meta.VecTypeOf(d, ft1); //# var vtype1 = vt1.Name; //# var ftype1 = ft1.Name; /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __vtype1__ Copy(Func<__ftype__, __ftype1__> element_fun) => new __vtype1__(/*# fields.ForEach(f => { */element_fun(__f__)/*# }, comma); */); /// /// Returns a copy with all elements transformed by the supplied function. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __vtype1__ Copy(Func<__ftype__, int, __ftype1__> element_index_fun) => new __vtype1__(/*# fields.ForEach((f, i) => { */element_index_fun(__f__, __i__)/*# }, comma); */); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(__ftype1__[] array, int start) { //# fields.ForEach((f, i) => { array[start + __i__] = /*# if (ft != ft1) { */(__ftype1__)/*# } */__f__; //# }); } //# } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func<__ftype__, T> element_fun) { //# fields.ForEach((f, i) => { array[start + __i__] = element_fun(__f__); //# }); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void CopyTo(T[] array, int start, Func<__ftype__, int, T> element_index_fun) { //# fields.ForEach((f, i) => { array[start + __i__] = element_index_fun(__f__, __i__); //# }); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly __ftype__[] ToArray() => new __ftype__[] { /*# fields.ForEach((f, i) => { */__f__/*# }, comma); */ }; #endregion #region Properties and Indexers //# fields.ForEach(f => { //# var pf = "P_" + f; /// /// Property for the field __f__. /// Useful when properties are required, but the field __f__ is recommended for general use. /// [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] [XmlIgnore] public __ftype__ __pf__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { return __f__; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { __f__ = value; } } //# }); /// /// Enumerates all elements of this vector. /// public readonly IEnumerable<__ftype__> Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { //# fields.ForEach(f => { yield return __f__; //# }); } } /// /// Gets or sets element with given index. /// public unsafe __ftype__ this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get { fixed (__ftype__* ptr = __getptr__) { return ptr[index]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { fixed (__ftype__* ptr = __getptr__) { ptr[index] = value; } } } /// /// Returns the index of the largest dimension of the vector. /// public readonly int MajorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { //# if (d == 2) { return X >= Y ? 0 : 1; //# } //# if (d == 3) { return X >= Y ? (X >= Z ? 0 : 2) : (Y >= Z ? 1 : 2); //# } //# if (d == 4) { return X >= Y ? (X >= Z ? (X >= W ? 0 : 3) : (Z >= W ? 2 : 3)) : (Y >= Z ? (Y >= W ? 1 : 3) : (Z >= W ? 2 : 3)); //# } } } /// /// Returns the index of the smallest dimension of the vector. /// public readonly int MinorDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { //# if (d == 2) { return X <= Y ? 0 : 1; //# } //# if (d == 3) { return X <= Y ? (X <= Z ? 0 : 2) : (Y <= Z ? 1 : 2); //# } //# if (d == 4) { return X <= Y ? (X <= Z ? (X <= W ? 0 : 3) : (Z <= W ? 2 : 3)) : (Y <= Z ? (Y <= W ? 1 : 3) : (Z <= W ? 2 : 3)); //# } } } /// /// Returns the minimum element of the vector. /// public readonly __ftype__ MinElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Min(/*# fields.ForEach(f => { */__f__/*# }, comma); */); } /// /// Returns the maximum element of the vector. /// public readonly __ftype__ MaxElement { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Fun.Max(/*# fields.ForEach(f => { */__f__/*# }, comma); */); } //# if (ft.IsReal) { //# var condArray = new[] { "Finite", "NaN", "Infinity", "PositiveInfinity", "NegativeInfinity", "Tiny" }; //# var scopeArray = new[] { "Fun", ftype, ftype, ftype, ftype, "Fun" }; //# var quantArray = new[] { "Any", "All" }; //# var actArray = new[] { oror, andand }; //# condArray.ForEach(scopeArray, (cond, scope) => { //# quantArray.ForEach(actArray, (qant, act) => { public readonly bool __qant____cond__ { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => /*# fields.ForEach((f, i) => { */__scope__.Is__cond__(__f__)/*# }, act); */; } //# }); // quantArray //# }); // condArray /// /// Returns true if the absolute value of each component of the vector is smaller than Constant<__ftype__>.PositiveTinyValue, false otherwise. /// public readonly bool IsTiny { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AllTiny; } /// /// Returns true if any component of the vector is NaN, false otherwise. /// public readonly bool IsNaN { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNaN; } /// /// Returns true if any component of the vector is infinite (positive or negative), false otherwise. /// public readonly bool IsInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyInfinity; } /// /// Returns true if any component of the vector is infinite and positive, false otherwise. /// public readonly bool IsPositiveInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyPositiveInfinity; } /// /// Returns true if any component of the vector is infinite and negative, false otherwise. /// public readonly bool IsNegativeInfinity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => AnyNegativeInfinity; } /// /// Returns whether all components of the vector are finite (i.e. not NaN and not infinity). /// public readonly bool IsFinite { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !(IsInfinity || IsNaN); } //# } // ft.IsReal #endregion #region Constants /// /// Number of elements in this vector. /// public const int Dimension = __d__; /// /// All elements zero. /// public static __vtype__ Zero { get { return new __vtype__(/*# d.ForEach(i => { */0/*# }, comma); */); } } //# if (ft.IsReal) { /// /// All elements half. /// public static __vtype__ Half { get { return new __vtype__(/*# d.ForEach(i => { */0.5/*# }, comma); */); } } //# } // ft.IsReal /// /// All elements one. /// public static __vtype__ One { get { return new __vtype__(/*# d.ForEach(i => { */1/*# }, comma); */); } } /// /// All elements set to maximum possible value. /// public static __vtype__ MaxValue { get { return new __vtype__(/*# d.ForEach(i => { */Constant<__ftype__>.ParseableMaxValue/*# }, comma); */); } } /// /// All elements set to minimum possible value. /// public static __vtype__ MinValue { get { return new __vtype__(/*# d.ForEach(i => { */Constant<__ftype__>.ParseableMinValue/*# }, comma); */); } } //# if (ft.IsReal) { /// /// All elements set to negative infinity. /// public static __vtype__ NegativeInfinity { get { return new __vtype__(/*# d.ForEach(i => { */__ftype__.NegativeInfinity/*# }, comma); */); } } /// /// All elements set to positive infinity. /// public static __vtype__ PositiveInfinity { get { return new __vtype__(/*# d.ForEach(i => { */__ftype__.PositiveInfinity/*# }, comma); */); } } /// /// All elements set to NaN. /// public static __vtype__ NaN { get { return new __vtype__(/*# d.ForEach(i => { */__ftype__.NaN/*# }, comma); */); } } //# } //# fields.ForEach((f, j) => { /// /// Normalized __f__-axis. /// public static __vtype__ __f__Axis { get { return new __vtype__(/*# d.ForEach(i => { var v = i != j ? 0 : 1; */__v__/*# }, comma); */); } } //# }); /// /// An array of accessor functions for the coordinates of the vector. /// public static readonly Func<__vtype__, __ftype__>[] SelectorArray = new Func<__vtype__, __ftype__>[] { /*# fields.ForEach(f => { */v => v.__f__/*# }, comma); */ }; /// /// Element getter function. /// public static readonly Func<__vtype__, int, __ftype__> Getter = (v, i) => { switch (i) { //# fields.ForEach((f, i) => { case __i__: return v.__f__; //# }); default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action. /// public static readonly ActionRefValVal<__vtype__, int, __ftype__> Setter = (ref __vtype__ v, int i, __ftype__ s) => { switch (i) { //# fields.ForEach((f, i) => { case __i__: v.__f__ = s; return; //# }); default: throw new IndexOutOfRangeException(); } }; /// /// Element getter function with long index. /// public static readonly Func<__vtype__, long, __ftype__> LongGetter = (v, i) => { switch (i) { //# fields.ForEach((f, i) => { case __i__: return v.__f__; //# }); default: throw new IndexOutOfRangeException(); } }; /// /// Element setter action with long index. /// public static readonly ActionRefValVal<__vtype__, long, __ftype__> LongSetter = (ref __vtype__ v, long i, __ftype__ s) => { switch (i) { //# fields.ForEach((f, i) => { case __i__: v.__f__ = s; return; //# }); default: throw new IndexOutOfRangeException(); } }; #endregion #region Static factories //# foreach (var ft1 in Meta.VecFieldTypes) { //# var vt1 = Meta.VecTypeOf(d, ft1); //# var vtype1 = vt1.Name; //# if (ft != ft1) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ From__vtype1__(__vtype1__ v) => new __vtype__(v); //# } //# } //# if (d == 3 || d == 4) { //# foreach (var t1 in Meta.ColorTypes) { var ft1 = t1.FieldType; //# if (coltovecsupported(ft1, ft)) { //# var type1 = t1.Name; //# var ftype1 = ft1.Name; //# var convert = ft != ft1 ? "("+ ftype +")" : ""; //# var maxval = colmaxvalmap[ft1]; /// /// Creates a vector from the given color. //# if (iscolormapped(ft, ft1)) { /// The values are not mapped from the color range. //# } //# if (d == 4 && !t1.HasAlpha) { /// W is set to __maxval__. //# } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ From__type1__(__type1__ c) => new __vtype__(c); //# } } //# } //# if (ft.IsReal) { //# if (d == 2) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ FromPolar(__ftype__ angleInRadians, __ftype__ radius) => new __vtype__(Fun.Cos(angleInRadians) * radius, Fun.Sin(angleInRadians) * radius); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ FromPolar(__ftype__ angleInRadians) => new __vtype__(Fun.Cos(angleInRadians), Fun.Sin(angleInRadians)); //# } else if (d == 3) { private static readonly __vtype__[] s_fromCubeCode = new __vtype__[] { -__vtype__.XAxis, -__vtype__.YAxis, -__vtype__.ZAxis, __vtype__.XAxis, __vtype__.YAxis, __vtype__.ZAxis }; /// /// Return the vector for the supplied cube face code. /// 0 ... -XAxis, 1 ... -YAxis, 2 ... -ZAsix, 3 ... XAxis, 4 ... YAxis, 5 ... ZAxis. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ FromCubeFaceCode(int i) { return s_fromCubeCode[i]; } //# } // d = 3 //# } // ft.IsReal #endregion #region Norms /// /// Returns the squared length of the vector. /// public readonly __ftype__ LengthSquared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return /*# fields.ForEach(f => { */__f__ * __f__ /*# }, add); */; } } //# if (ft == Meta.FloatType && d == 4) { #if NETCOREAPP3_1_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] static __ctype__ Length_Sse41(__vtype__ vec) { unsafe { //# if (d == 2) { var vv = Vector128.Create(vec.X, vec.Y, 0.0f, 0.0f); vv = Sse41.DotProduct(vv, vv, 0x31); //# } else if (d == 3) { var vv = Vector128.Create(vec.X, vec.Y, vec.Z, 0.0f); vv = Sse41.DotProduct(vv, vv, 0x71); //# } else { // d == 4 var x = (float*)&vec; var vv = Sse.LoadVector128(x); vv = Sse41.DotProduct(vv, vv, 0xF1); //# } var l2 = vv.GetElement(0); return MathF.Sqrt(l2); } } #endif //# } // end ft == Meta.FloatType /// /// Returns the length of the vector. /// public readonly __ctype__ Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { //# if (ft == Meta.FloatType && d == 4) { #if NETCOREAPP3_1_OR_GREATER if (Sse41.IsSupported) return Length_Sse41(this); #endif //# } return Fun.Sqrt(/*# fields.ForEach(f => { */__f__ * __f__ /*# }, add); */); } } /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// public readonly __ftype__ Norm1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return /*# fields.ForEach(f => { if (unsigned) {*/__f__/*# } else {*/Fun.Abs(__f__)/*# } }, add); */; } } /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// public readonly __ctype__ Norm2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Sqrt(/*# fields.ForEach(f => { */__f__ * __f__/*# }, add); */); } } /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// public readonly __ftype__ NormMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Max(/*# fields.ForEach(f => { if (unsigned) {*/__f__/*# } else {*/Fun.Abs(__f__)/*# } }, comma); */); } } /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// public readonly __ftype__ NormMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Fun.Min(/*# fields.ForEach(f => { if (unsigned) {*/__f__/*# } else {*/Fun.Abs(__f__)/*# } }, comma); */); } } /// /// Returns a normalized copy of this vector. /// public readonly __vctype__ Normalized { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { var s = Length; if (s == 0) return __vctype__.Zero; s = 1 / s; return new __vctype__(/*# fields.ForEach(f => { */__f__ * s/*# }, comma); */); } } //# if (d == 2 && !unsigned) { /// /// Vector rotated 90° counter clockwise: (-Y, X) /// public readonly __vtype__ Rot90 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new __vtype__(-Y, X); } } /// /// Vector rotated 180° counter clockwise: (-X, -Y) /// public readonly __vtype__ Rot180 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new __vtype__(-X, -Y); } } /// /// Vector rotated 270° counter clockwise: (Y, -X) /// public readonly __vtype__ Rot270 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new __vtype__(Y, -X); } } //# } // d == 2 //# if (ft.IsReal) { //# if (d == 2) { /// /// Returns a copy of the vector with the maximum component length of /// exactly 1. This corresponds to mapping the vector onto an origin- /// centered square with side length 2. /// public readonly __vtype__ CubeMapped { get { __ftype__ x = Fun.Abs(X); __ftype__ y = Fun.Abs(Y); return x > y ? new __vtype__(Fun.Sign(X), Y / x) : new __vtype__(X / y, Fun.Sign(Y)); } } //# } // d == 2 //# else if (d == 3) { //# foreach (var face in new bool[] { false, true }) { //# string facepar = face ? "OnFace(out int face)" : ""; /// /// Returns a copy of the vector with the maximum component length of /// exactly 1. This corresponds to mapping the vector onto an origin- /// centered cube with side length 2. //# if (face) { /// The out parameter face indicate which face the vector was mapped to: /// 0 ... -XAxis, 1 ... -YAxis, 2 ... -ZAsix, 3 ... XAxis, 4 ... YAxis, 5 ... ZAxis. //# } /// public readonly __vtype__ CubeMapped__facepar__ { //# if (!face) { get { //# } __ftype__ x = Fun.Abs(X); __ftype__ y = Fun.Abs(Y); __ftype__ z = Fun.Abs(Z); if (x > y) { if (x > z) { double s = 1 / x;/*# if (face) { */ face = X < 0 ? 0 : 3;/*# } */ return new __vtype__(Fun.Sign(X), Y * s, Z * s); } else { double s = 1 / z;/*# if (face) { */ face = Z < 0 ? 2 : 5;/*# } */ return new __vtype__(X * s, Y * s, Fun.Sign(Z)); } } else { if (y > z) { double s = 1 / y;/*# if (face) { */ face = Y < 0 ? 1 : 4;/*# } */ return new __vtype__(X * s, Fun.Sign(Y), Z * s); } else { double s = 1 / z;/*# if (face) { */ face = Z < 0 ? 2 : 5;/*# } */ return new __vtype__(X * s, Y * s, Fun.Sign(Z)); } } //# if (!face) { } //# } } //# } // face /// /// Return an index for the cube face onto which the vector points. /// 0 ... -XAxis, 1 ... -YAxis, 2 ... -ZAsix, 3 ... XAxis, 4 ... YAxis, 5 ... ZAxis. /// public readonly int CubeFaceCode { get { double x = Fun.Abs(X); double y = Fun.Abs(Y); double z = Fun.Abs(Z); int c; double v; if (x > y) { if (x > z) { c = 0; v = X; } else { c = 2; v = Z; } } else { if (y > z) { c = 1; v = Y; } else { c = 2; v = Z; } } return v < 0 ? c : c + 3; } } //# } // d == 3 //# else { /// /// Returns a copy of the vector with the maximum component length of /// exactly 1. This corresponds to mapping the vector onto an origin- /// centered cube with side length 2. /// public readonly __vtype__ CubeMapped { get { var s = 1 / Fun.Max(/*# fields.ForEach(f => { */Fun.Abs(__f__)/*# }, comma); */); return new __vtype__(/*# fields.ForEach(f => { */__f__ * s/*# }, comma); */); } } //# } // d > 3 //# } // ft.IsReal #endregion #region Static methods for F# core and Aardvark library support //# if (!unsigned) { [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Abs(__vtype__ v) => v.Abs(); //# } //# if (ft.IsReal) { [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Floor(__vtype__ v) => v.Floor(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Ceiling(__vtype__ v) => v.Ceiling(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Round(__vtype__ v) => v.Round(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Truncate(__vtype__ v) => v.Truncate(); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Acos(__vtype__ v) => Fun.Acos(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Acoshb(__vtype__ v) => Fun.Acosh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Cos(__vtype__ v) => Fun.Cos(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Cosh(__vtype__ v) => Fun.Cosh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Asin(__vtype__ v) => Fun.Asin(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Asinhb(__vtype__ v) => Fun.Asinh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Sin(__vtype__ v) => Fun.Sin(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Sinh(__vtype__ v) => Fun.Sinh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Atan(__vtype__ v) => Fun.Atan(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Atanhb(__vtype__ v) => Fun.Atanh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Atan2(__vtype__ a, __vtype__ b) => Fun.Atan2(a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Tan(__vtype__ v) => Fun.Tan(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Tanh(__vtype__ v) => Fun.Tanh(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Sqrt(__vtype__ v) => Fun.Sqrt(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ CubeRoot(__vtype__ v) => Fun.Cbrt(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Exp(__vtype__ v) => Fun.Exp(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Log(__vtype__ v) => Fun.Log(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ LogBinary(__vtype__ v) => Fun.Log2(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Log10(__vtype__ v) => Fun.Log10(v); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ CopySgn(__vtype__ value, __vtype__ sign) => Fun.CopySign(value, sign); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ CopySgn(__vtype__ value, __ftype__ sign) => Fun.CopySign(value, sign); //# } // ft.IsReal //# foreach(var tt in fdtypes) { //# var vtt = Meta.VecTypeOf(d, tt); //# if (ft.IsReal && tt != ft) continue; [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ LinearInterp(__tt.Name__ t, __vtype__ a, __vtype__ b) => Fun.Lerp(t, a, b); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ LinearInterp(__vtt.Name__ t, __vtype__ a, __vtype__ b) => Fun.Lerp(t, a, b); //#} [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Min(__vtype__ v0, __vtype__ v1) => Fun.Min(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Min(__vtype__ v, __ftype__ x) => Fun.Min(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Max(__vtype__ v0, __vtype__ v1) => Fun.Max(v0, v1); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Max(__vtype__ v, __ftype__ x) => Fun.Max(v, x); [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Saturate(__vtype__ v) => Fun.Saturate(v); //# if (!unsigned) { [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ DivideByInt(__vtype__ v, int x) => v / x; //# } #endregion #region Operations //# foreach (var ft1 in Meta.VecFieldTypes) { //# var vt1 = Meta.VecTypeOf(d, ft1); //# var ftype1 = ft1.Name; /// /// Sets the elements of a vector to the given __ftype1__ elements. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(/*# args.ForEach(a => { */__ftype1__ __a__/*# }, comma); */) { //# fields.ForEach(args, (f, a) => { __f__ = /*# if (ft != ft1) { */(__ftype__)/*# } */__a__; //# }); } //# } //# if (!unsigned) { /// /// Returns a negated copy of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ operator -(__vtype__ v) => new __vtype__(/*# fields.ForEach(f => { */-v.__f__/*# }, comma); */); //# } //# if (!ft.IsReal) { /// /// Returns the component-wise bitwise complement of the specified vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ operator ~(__vtype__ v) => new __vtype__(/*# fields.ForEach(f => { */~v.__f__/*# }, comma); */); //# } //# if (d == 2 && !unsigned) { /// /// Returns a vector that is orthogonal to this one (i.e. {x,y} -> {-y,x}). /// public readonly __vtype__ Orthogonal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new __vtype__(-__f1__, __f0__); } } //# } //# if (ft.IsReal) { /// /// Gets a copy of this vector containing the reciprocal (1/x) of each element. /// public readonly __vtype__ Reciprocal { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new __vtype__(/*# fields.ForEach(f => { */1 / __f__/*# }, comma); */); } } //# } //# { //# var ops = new[] {" + ", " - ", " * ", " / ", " % "}; //# var opactions = new[] { "operator +", "operator -", "operator *", "operator /", "operator %"}; //# var opnames = new[] {"sum", "difference", "product", "fraction", "remainder"}; //# for (int o = 0; o < ops.Length; o++) { //# var op = ops[o]; //# var opname = opnames[o]; //# var opaction = opactions[o]; /// /// Returns the component-wise __opname__ of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ __opaction__(__vtype__ a, __vtype__ b) => new __vtype__(/*# fields.ForEach(f => { */a.__f____op__b.__f__/*# }, comma); */); /// /// Returns the component-wise __opname__ of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ __opaction__(__vtype__ v, __ftype__ s) => new __vtype__(/*# fields.ForEach(f => { */v.__f____op__s/*# }, comma); */); /// /// Returns the component-wise __opname__ of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ __opaction__(__ftype__ s, __vtype__ v) => new __vtype__(/*# fields.ForEach(f => { */s__op__v.__f__/*# }, comma); */); //# } //# } //# if (!ft.IsReal) { //# var ops = new[] {"&", "|", "^"}; //# var opnames = new[] {"bitwise and", "bitwise or", "bitwise exclusive or" }; //# for (int o = 0; o < ops.Length; o++) { //# var op = ops[o]; //# var opname = opnames[o]; /// /// Returns the component-wise __opname__ of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ operator __op__(__vtype__ a, __vtype__ b) => new __vtype__(/*# fields.ForEach(f => { */a.__f__ __op__ b.__f__/*# }, comma); */); /// /// Returns the component-wise __opname__ of a vector and a scalar. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ operator __op__(__vtype__ v, __ftype__ s) => new __vtype__(/*# fields.ForEach(f => { */v.__f__ __op__ s/*# }, comma); */); /// /// Returns the component-wise __opname__ of a scalar and a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ operator __op__(__ftype__ s, __vtype__ v) => new __vtype__(/*# fields.ForEach(f => { */s __op__ v.__f__/*# }, comma); */); //# } /// /// Returns the component-wise left bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ operator <<(__vtype__ v, int s) => new __vtype__(/*# fields.ForEach(f => { */v.__f__ << s/*# }, comma); */); /// /// Returns the component-wise right bitshift of a vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ operator >>(__vtype__ v, int s) => new __vtype__(/*# fields.ForEach(f => { */v.__f__ >> s/*# }, comma); */); //# } /// Attention: NEVER implement operators <, <=, >=, >, /// since these are not defined in a Vector space. /// Use AllSmaller() and similar comparators! #endregion #region Comparisons [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__vtype__ a, __vtype__ b) { return /*# fields.ForEach(f => { */a.__f__ == b.__f__/*# }, andand); */; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__vtype__ v, __ftype__ s) { return /*# fields.ForEach(f => { */v.__f__ == s/*# }, andand); */; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(__ftype__ s, __vtype__ v) { return /*# fields.ForEach(f => { */s == v.__f__/*# }, andand); */; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__vtype__ a, __vtype__ b) { return /*# fields.ForEach(f => { */a.__f__ != b.__f__/*# }, oror); */; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__vtype__ v, __ftype__ s) { return /*# fields.ForEach(f => { */v.__f__ != s/*# }, oror); */; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(__ftype__ s, __vtype__ v) { return /*# fields.ForEach(f => { */s != v.__f__/*# }, oror); */; } #endregion #region IEquatable<__vtype__> Members [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(__vtype__ other) { return /*# fields.ForEach(f => { */__f__.Equals(other.__f__)/*# }, andand); */; } #endregion #region Overrides public override readonly string ToString() { return ToString(null, CultureInfo.InvariantCulture); } public readonly string ToString(string format) { return ToString(format, CultureInfo.InvariantCulture); } public readonly string ToString(string format, IFormatProvider fp) { return ToString(format, fp, "[", ", ", "]"); } /// /// Outputs e.g. a 3D-Vector in the form "(begin)x(between)y(between)z(end)". /// public readonly string ToString(string format, IFormatProvider fp, string begin, string between, string end) { if (fp == null) fp = CultureInfo.InvariantCulture; return begin /*# fields.ForEach(f => {*/+ __f__.ToString(format, fp) /*# }, addbetween); */ + end; } public override readonly int GetHashCode() { return HashCode.GetCombined(/*# fields.ForEach(f => { */__f__/*# }, comma); */); } public override readonly bool Equals(object other) => (other is __vtype__ o) ? Equals(o) : false; public readonly Text ToText(int bracketLevel = 1) { return ((bracketLevel == 1 ? "[" : "")/*# fields.ForEach(f => {*/ + __f__.ToString(null, CultureInfo.InvariantCulture) /*# }, addqcommaspace); */ + (bracketLevel == 1 ? "]" : "")).ToText(); } #endregion #region Parsing public static __vtype__ Parse(string s) { var x = s.NestedBracketSplitLevelOne().ToArray(); return new __vtype__(/*# d.ForEach(p => { */ __ftype__.Parse(x[__p__], CultureInfo.InvariantCulture)/*# }, comma); */ ); } public static __vtype__ Parse(Text t) { return t.NestedBracketSplit(1, Text<__ftype__>.Parse, __vtype__.Setter); } public static __vtype__ Parse(Text t, int bracketLevel) { return t.NestedBracketSplit(bracketLevel, Text<__ftype__>.Parse, __vtype__.Setter); } #endregion #region Swizzle Methods //# var snames = unsigned ? new string[] { "O", "I", "X", "Y", "Z", "W" } : new string[] { "O", "I", "N", "X", "Y", "Z", "W" }; //# var svalues = unsigned ? new string[] { "0", "1", "X", "Y", "Z", "W" } : new string[] { "0", "1", "-1","X", "Y", "Z", "W" }; //# var isConst = new Func(i => i < (unsigned ? 2 : 3)); //# var s = d + (unsigned ? 2 : 3); //# var getName = new Func((anyN, i) => anyN && i == 1 ? "P" : snames[i]); //# for (int xi = 0; xi < s; xi++) { var x = svalues[xi]; //# for (int yi = 0; yi < s; yi++) { var y = svalues[yi]; //# var anyN = !unsigned && (xi == 2 || yi == 2); // replace I by P if any N //# var name = getName(anyN, xi) + getName(anyN, yi); //# if (isConst(xi) && isConst(yi)) { // check for constant -> otherwise property //# if (d == 2) { // only constants of matching size [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static __v2type__ __name__ => new __v2type__(__x__, __y__); //# } //# } //# else { //# if (xi == yi || isConst(xi) || isConst(yi)) { // readonly if the same or constants [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly __v2type__ __name__ => new __v2type__(__x__, __y__); //# } else { [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public __v2type__ __name__ { readonly get => new __v2type__(__x__, __y__); set { __x__ = value.X; __y__ = value.Y; } } //# } //# } //# } //# } //# for (int xi = 0; xi < s; xi++) { var x = svalues[xi]; //# for (int yi = 0; yi < s; yi++) { var y = svalues[yi]; //# for (int zi = 0; zi < s; zi++) { var z = svalues[zi]; //# var anyN = !unsigned && (xi == 2 || yi == 2 || zi == 2); // replace I by P if any N //# var name = getName(anyN, xi) + getName(anyN, yi) + getName(anyN, zi); //# if (isConst(xi) && isConst(yi) && isConst(zi)) { // check for constant -> otherwise property //# if (d == 3) { // only constants of matching size [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static __v3type__ __name__ => new __v3type__(__x__, __y__, __z__); //# } //# } //# else { //# if (xi == yi || xi == zi || yi == zi || isConst(xi) || isConst(yi) || isConst(zi)) { // readonly if the same or constants [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly __v3type__ __name__ => new __v3type__(__x__, __y__, __z__); //# } else { [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public __v3type__ __name__ { readonly get => new __v3type__(__x__, __y__, __z__); set { __x__ = value.X; __y__ = value.Y; __z__ = value.Z; } } //# } //# } //# } //# } //# } //# // if (d != 4) { // lets try if it does not explode //# for (int xi = 0; xi < s; xi++) { var x = svalues[xi]; //# for (int yi = 0; yi < s; yi++) { var y = svalues[yi]; //# for (int zi = 0; zi < s; zi++) { var z = svalues[zi]; //# for (int wi = 0; wi < s; wi++) { var w = svalues[wi]; //# var anyN = !unsigned && (xi == 2 || yi == 2 || zi == 2 || wi == 2); // replace I by P if any N //# var name = getName(anyN, xi) + getName(anyN, yi) + getName(anyN, zi) + getName(anyN, wi); //# if (isConst(xi) && isConst(yi) && isConst(zi) && isConst(wi)) { // check for constant -> otherwise property //# if (d == 4) { // only constants of matching size [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public static __v4type__ __name__ => new __v4type__(__x__, __y__, __z__, __w__); //# } //# } //# else { //# if (xi == yi || xi == zi || xi == wi || //# yi == zi || yi == wi || zi == wi || //# isConst(xi) || isConst(yi) || isConst(zi) || isConst(wi)) { // readonly if the same or constants [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly __v4type__ __name__ => new __v4type__(__x__, __y__, __z__, __w__); //# } else { [XmlIgnore] [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)] public __v4type__ __name__ { readonly get => new __v4type__(__x__, __y__, __z__, __w__); set { __x__ = value.X; __y__ = value.Y; __z__ = value.Z; __w__ = value.W; } } //# } //# } //# } //# } //# } //# } //# // } #endregion #region IVector Members /// /// By using long indices, the IVector<double> interface is /// accessed. /// public double this[long i] { readonly get { return (double)this[(int)i]; } set { this[(int)i] = (__ftype__)value; } } #endregion #region ISize__d____fchar__ Members public readonly __vtype__ Size__d____fchar__ { get { return this; } } #endregion #region IVector public readonly long Dim { get { return __d__; } } public readonly object GetValue(long index) { return (object)this[(int)index]; } public void SetValue(object value, long index) { this[(int)index] = (__ftype__)value; } #endregion } public class __vtype__EqualityComparer : IEqualityComparer<__vtype__> { public static __vtype__EqualityComparer Default => new __vtype__EqualityComparer(); #region IEqualityComparer<__vtype__> Members public bool Equals(__vtype__ v0, __vtype__ v1) { return v0 == v1; } public int GetHashCode(__vtype__ v) { return v.GetHashCode(); } #endregion } public static partial class Fun { //# Func getParamType = //# (p) => //# { //# var elemType = p.ElementType ?? ft; //# return (p.IsScalar()) ? elemType : Meta.VecTypeOf(d, elemType); //# }; //# //# foreach (var group in Meta.ElementwiseFuns.Keys) { //# var isEmpty = Meta.ElementwiseFuns[group].TrueForAll(f => !f.Domain.Contains(ft)); //# if (!isEmpty) { #region __group__ //# foreach (var fun in Meta.ElementwiseFuns[group]) { //# if (!fun.Domain.Contains(ft)) continue; //# var retType = Meta.VecTypeOf(d, fun.ReturnType ?? ft).Name; /// /// Applies Fun.__fun.Name__ to each element of the given vector(s). /// [Pure] //# if (fun.Obsolete) { [Obsolete] //# } //# if (!fun.EditorBrowsable) { [EditorBrowsable(EditorBrowsableState.Never)] //# } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __retType__ __fun.Name__(/*# fun.Parameters.ForEach((p, i) => { var name = p.Name; var ptype = getParamType(p).Name; var ext = fun.IsExtension && (i == 0); var varg = fun.HasVarArgs && (i == fun.Parameters.Length - 1); if (ext) { */this /*# } if (varg) { */params /*# } */__ptype__/*# if (varg) {*/[]/*# }*/ __name__/*#}, comma); */) { return new __retType__(/*# fields.ForEach(f => {*/__fun.Name__(/*# fun.Parameters.ForEach((p, i) => { var vec = !p.IsScalar(); var varg = fun.HasVarArgs && (i == fun.Parameters.Length - 1); */__p.Name__/*#if (vec) { if (varg) {*/.Map(a => a.__f__)/*# } else {*/.__f__/*#} } }, comma); */)/*#}, comma); */); } //# } #endregion //# } // isEmpty //# } #region ApproximateEquals /// /// Returns whether the given vectors are equal within the given tolerance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __vtype__ a, __vtype__ b, __ftype__ tolerance) { return /*# fields.ForEach(f => { */ApproximateEquals(a.__f__, b.__f__, tolerance)/*# }, andand); */; } //# if (ft.IsReal) { /// /// Returns whether the given vectors are equal within /// Constant{__ftype__}.PositiveTinyValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ApproximateEquals(this __vtype__ a, __vtype__ b) { return ApproximateEquals(a, b, Constant<__ftype__>.PositiveTinyValue); } //# } #endregion #region IsTiny /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(this __vtype__ v, __ftype__ epsilon) => Vec.AllTiny(v, epsilon); //# if (ft.IsReal) { /// /// Returns whether the absolute value of each component of the given is smaller than Constant<__ftype__>.PositiveTinyValue. /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsTiny(__vtype__ v) => v.IsTiny; //# } #endregion //# if (ft.IsReal) { #region Special Floating Point Value Checks /// /// Returns whether any component of the given is NaN. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(__vtype__ v) => v.IsNaN; /// /// Returns whether any component of the the given is infinity (positive or negative). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(__vtype__ v) => v.IsInfinity; /// /// Returns whether any component of the the given is positive infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPositiveInfinity(__vtype__ v) => v.IsPositiveInfinity; /// /// Returns whether any component of the the given is negative infinity. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNegativeInfinity(__vtype__ v) => v.IsNegativeInfinity; /// /// Returns whether all components of the the given are finite (i.e. not NaN and not infinity). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFinite(__vtype__ v) => v.IsFinite; #endregion //# } } //# if (ft.IsReal) { public static partial class Conversion { #region Angles (Radians, Degrees, Gons) //# var units = new[] { "Radians", "Degrees", "Gons" }; //# units.ForEach(u1 => { //# units.ForEach(u2 => { if (u1 == u2) return; //# var n1 = u1.ToLower(); //# var n2 = u2.ToLower(); /// /// Converts the angles given in __n2__ to __n1__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ __u1__From__u2__(this __vtype__ __n2__) => new __vtype__(/*# fields.ForEach(f => {*/ __u1__From__u2__(__n2__.__f__)/*# }, comma); */ ); //# }); }); #endregion } //# } /// /// Contains static methods /// public static partial class Vec { #region Length /// /// Returns the squared length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ LengthSquared(__vtype__ v) => v.LengthSquared; /// /// Returns the length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ctype__ Length(__vtype__ v) => v.Length; #endregion #region Normalize //# if (ft.IsReal) { /// /// Normalizes the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Normalize(this ref __vtype__ v) { var s = v.Length; if (s == 0) return; s = 1 / s; //# fields.ForEach(f => { v.__f__ *= s; //# }); } //# } // ft.IsReal /// /// Returns a normalized copy of this vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vctype__ Normalized(__vtype__ v) => v.Normalized; #endregion #region Norms /// /// Returns the Manhattan (or 1-) norm of the vector. This is /// calculated as |x| + |y| + ... /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Norm1(__vtype__ v) => v.Norm1; /// /// Returns the Euclidean (or 2-) norm of the vector. This is the /// length of the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ctype__ Norm2(__vtype__ v) => v.Norm2; /// /// Returns the infinite (or maximum) norm of the vector. This is /// calculated as max(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ NormMax(__vtype__ v) => v.NormMax; /// /// Returns the minimum norm of the vector. This is calculated as /// min(|x|, |y|, ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ NormMin(__vtype__ v) => v.NormMin; /// /// Gets the p-norm. This is calculated as the p-th root of (|x|^n + |y|^n + ...). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ctype__ Norm(this __vtype__ v, __ctype__ p) { return (/*# fields.ForEach(f => { */ Fun.Abs(v.__f__).Pow(p)/*# }, add); */).Pow(1 / p); } #endregion #region Distance functions /// /// Returns the squared distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ DistanceSquared(this __vtype__ a, __vtype__ b) //# if (unsigned) { => /*# fields.ForEach(f => { */Fun.Square((a.__f__ < b.__f__) ? (b.__f__ - a.__f__) : (a.__f__ - b.__f__))/*# }, add); */; //# } else { => /*# fields.ForEach(f => { */Fun.Square(b.__f__ - a.__f__)/*# }, add); */; //# } /// /// Returns the distance between the given points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ctype__ Distance(this __vtype__ a, __vtype__ b) => Fun.Sqrt(DistanceSquared(a, b)); /// /// Returns the Manhatten (or 1-) distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Distance1(this __vtype__ a, __vtype__ b) //# if (unsigned) { => /*# fields.ForEach(f => { */((a.__f__ < b.__f__) ? (b.__f__ - a.__f__) : (a.__f__ - b.__f__))/*# }, add); */; //# } else { => /*# fields.ForEach(f => { */Fun.Abs(b.__f__ - a.__f__)/*# }, add); */; //# } /// /// Returns the p-distance between two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ctype__ Distance(this __vtype__ a, __vtype__ b, __ctype__ p) //# if (unsigned) { => (/*# fields.ForEach(f => { */((a.__f__ < b.__f__) ? (b.__f__ - a.__f__) : (a.__f__ - b.__f__)).Pow(p)/*# }, add); */).Pow(1 / p); //# } else { => (/*# fields.ForEach(f => { */Fun.Abs(b.__f__ - a.__f__).Pow(p)/*# }, add); */).Pow(1 / p); //# } /// /// Returns the maximal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ DistanceMax(this __vtype__ a, __vtype__ b) //# if (unsigned) { => Fun.Max(/*# fields.ForEach(f => { */((a.__f__ < b.__f__) ? (b.__f__ - a.__f__) : (a.__f__ - b.__f__))/*# }, comma); */); //# } else { => Fun.Max(/*# fields.ForEach(f => { */Fun.Abs(b.__f__ - a.__f__)/*# }, comma); */); //# } /// /// Returns the minimal absolute distance between the components of /// the two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ DistanceMin(this __vtype__ a, __vtype__ b) //# if (unsigned) { => Fun.Min(/*# fields.ForEach(f => { */((a.__f__ < b.__f__) ? (b.__f__ - a.__f__) : (a.__f__ - b.__f__))/*# }, comma); */); //# } else { => Fun.Min(/*# fields.ForEach(f => { */Fun.Abs(b.__f__ - a.__f__)/*# }, comma); */); //# } //# foreach (var hasT in new[] { false, true }) { //# var cast = (ft != ct) ? "(" + vctype + ") " : ""; /// /// Returns the minimal euclidean distance between the supplied query /// point and the line segment defined by the two supplied line end /// points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ctype__ DistanceToLine( this __vtype__ query, __vtype__ p0, __vtype__ p1/*# if (hasT) { */, out __ctype__ t/*# } */) { //# if (ft.IsReal) { var p0p1 = p1 - p0; var p0q = query - p0; /*# if (!hasT) { */var /*# } */t = Dot(p0q, p0p1); if (t <= 0) { /*# if (hasT) { */t = 0; /*# } */return p0q.Length; } var denom = p0p1.LengthSquared; if (t >= denom) { /*# if (hasT) { */t = 1; /*# } */return Distance(query, p1); } t /= denom; return (p0q - t * p0p1).Length; //# } else { return DistanceToLine(__cast__query, __cast__p0, __cast__p1/*# if (hasT) { */, out t/*# } */); //# } } /// /// Returns the minimal euclidean distance between the supplied query /// point and the infinite line defined by two points. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ctype__ DistanceToInfiniteLine( this __vtype__ query, __vtype__ p0, __vtype__ p1/*# if (hasT) { */, out __ctype__ t/*# } */) { //# if (ft.IsReal) { var p0p1 = p1 - p0; var p0q = query - p0; /*# if (!hasT) { */var /*# } */t = Dot(p0q, p0p1); var denom = p0p1.LengthSquared; t /= denom; return (p0q - t * p0p1).Length; //# } else { return DistanceToInfiniteLine(__cast__query, __cast__p0, __cast__p1/*# if (hasT) { */, out t/*# } */); //# } } //# } // hasT #endregion #region Operations //# if (d == 2 && !unsigned) { /// /// Returns a vector that is orthogonal to the given one (i.e. {x,y} -> {-y,x}). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Orthogonal(__vtype__ v) => v.Orthogonal; //# } //# if (ft.IsReal) { /// /// Gets a copy of the given vector containing the reciprocal (1/x) of each element. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Reciprocal(__vtype__ v) => v.Reciprocal; //# } //# if (!unsigned) { /// /// Negates the vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Negate(this ref __vtype__ v) { //# fields.ForEach(f => { v.__f__ = -v.__f__; //# }); } /// /// Returns the outer product (tensor-product) of a * b^T as a __d__x__d__ matrix. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __mtype__ Outer(this __vtype__ a, __vtype__ b) { return new __mtype__(/*# d.ForEach(i => { var fi = fields[i]; */ /*# d.ForEach(j => { var fj = fields[j]; */a.__fi__ * b.__fj__/*# }, comma); }, comma); */); } //# } /// /// Returns the dot product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Dot(this __vtype__ a, __vtype__ b) { return /*# fields.ForEach(f => { */a.__f__ * b.__f__/*# }, add); */; } //# if (d == 3 && !unsigned) { /// /// Returns the skew-symmetric "cross" matrix (A^T = -A) of the vector v. /// public static __mtype__ CrossMatrix(this __vtype__ v) { return new __mtype__(0, -v.Z, +v.Y, +v.Z, 0, -v.X, -v.Y, +v.X, 0); } //# } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DirFlags DirFlags(this __vtype__ v) { //# var posTiny = ft.IsReal ? "Constant<" + ftype + ">.PositiveTinyValue" : "0"; //# var negTiny = ft.IsReal ? "Constant<" + ftype + ">.NegativeTinyValue" : "0"; DirFlags flags = Aardbase.DirFlags.None; //# fields.ForEach(f => { if (v.__f__ > __posTiny__) flags |= Aardbase.DirFlags.Positive__f__; if (v.__f__ < __negTiny__) flags |= Aardbase.DirFlags.Negative__f__; //# }); return flags; } //# if (ft.IsReal) { /// /// Returns the reflection direction of the given vector v (pointing to the surface) for the given normal (should be normalized). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Reflect(this __vtype__ v, __vtype__ normal) { return v - 2 * v.Dot(normal) * normal; } /// /// Returns the refraction direction of the given vector v (pointing to the surface) for the given normal and ratio of refraction indices (n_out / n_in). /// Both the input vectors should be normalized. /// Returns a zero-vector in case of total internal reflection. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Refract(this __vtype__ v, __vtype__ normal, __ftype__ eta) { var t = v.Dot(normal); var k = 1 - eta * eta * (1 - t * t); if (k < 0) { return __vtype__.Zero; } else { return eta * v - (eta * t + Fun.Sqrt(k)) * normal; } } //# } // ft.IsReal //# if (d == 3 && !unsigned) { /// /// Returns the cross product of two vectors. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Cross(this __vtype__ a, __vtype__ b) { return new __vtype__( a.__f1__ * b.__f2__ - a.__f2__ * b.__f1__, a.__f2__ * b.__f0__ - a.__f0__ * b.__f2__, a.__f0__ * b.__f1__ - a.__f1__ * b.__f0__ ); } //# } //# if (d == 2 && !unsigned) { /// /// Returns the cross product of vector a. /// In 2D the cross product is simply a vector that is normal /// to the given vector (i.e. {x,y} -> {-y,x}) /// public static __vtype__ Cross(this __vtype__ a) { return new __vtype__(-a.__f1__, a.__f0__); } //# } #endregion #region Comparisons //# var bops = new[,] { { "<", "Smaller" }, { ">" , "Greater"}, //# { "<=", "SmallerOrEqual" }, { ">=", "GreaterOrEqual"}, //# { "==", "Equal" }, { "!=", "Different" } }; //# var attention = "ATTENTION: For example (AllSmaller(a,b)) is not the same as !(AllGreaterOrEqual(a,b)) but !(AnyGreaterOrEqual(a,b))."; //# for(int o = 0; o < bops.GetLength(0); o++) { //# string bop = " " + bops[o,0] + " ", opName = bops[o,1]; /// /// Returns whether ALL elements of a are __opName__ the corresponding element of b. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool All__opName__(this __vtype__ a, __vtype__ b) { return (/*# fields.ForEach(f => { */a.__f____bop__b.__f__/*# }, andand); */); } /// /// Returns whether ALL elements of v are __opName__ s. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool All__opName__(this __vtype__ v, __ftype__ s) { return (/*# fields.ForEach(f => { */v.__f____bop__s/*# }, andand); */); } /// /// Returns whether a is __opName__ ALL elements of v. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool All__opName__(__ftype__ s, __vtype__ v) { return (/*# fields.ForEach(f => { */s__bop__v.__f__/*# }, andand); */); } /// /// Returns whether AT LEAST ONE element of a is __opName__ the corresponding element of b. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Any__opName__(this __vtype__ a, __vtype__ b) { return (/*# fields.ForEach(f => { */a.__f____bop__b.__f__/*# }, oror); */); } /// /// Returns whether AT LEAST ONE element of v is __opName__ s. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Any__opName__(this __vtype__ v, __ftype__ s) { return (/*# fields.ForEach(f => { */v.__f____bop__s/*# }, oror); */); } /// /// Returns whether a is __opName__ AT LEAST ONE element of v. /// __attention__ /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Any__opName__(__ftype__ s, __vtype__ v) { return (/*# fields.ForEach(f => { */s__bop__v.__f__/*# }, oror); */); } //# } /// /// Compare x-coordinate before y-coordinate, aso. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LexicalCompare(this __vtype__ v0, __vtype__ v1) { //# fields.ForEach(f => { if (v0.__f__ < v1.__f__) return -1; if (v0.__f__ > v1.__f__) return +1; //# }); return 0; } #endregion #region Min- / MaxElement /// /// Returns the minimum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ MinElement(__vtype__ v) => v.MinElement; /// /// Returns the maximum element of the given vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ MaxElement(__vtype__ v) => v.MaxElement; #endregion //# if (d == 3 && ft.IsReal) { #region Axis aligned normal /// /// Returns an arbitrary normal vector, which /// is also normal to either the x, y or z-axis. /// public static __vtype__ AxisAlignedNormal(this __vtype__ v) { __vtype__ vector; __ftype__ x = v.X.Abs(); __ftype__ y = v.Y.Abs(); __ftype__ z = v.Z.Abs(); if (x < y) { if (x < z) vector = __vtype__.XAxis; else vector = __vtype__.ZAxis; } else { if (y < z) vector = __vtype__.YAxis; else vector = __vtype__.ZAxis; } return v.Cross(vector).Normalized; } #endregion //# } //# if (ft.IsReal) { #region Angle between two vectors /// /// Computes the angle between two given vectors in radians. The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ctype__ AngleBetweenFast(this __vtype__ x, __vtype__ y) { return Fun.AcosClamped(x.Dot(y)); } /// /// Computes the angle between two given vectors in radians using a numerically stable algorithm. /// The input vectors have to be normalized. /// // https://scicomp.stackexchange.com/a/27769 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ctype__ AngleBetween(this __vtype__ x, __vtype__ y) { var a = x + y; var b = x - y; return 2 * Fun.Atan2(b.Length, a.Length); } //# if (d == 2) { /// /// Computes the signed angle between two given vectors in radians. The input vectors have to be normalized. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ctype__ AngleBetweenSigned(this __vtype__ x, __vtype__ y) { var a = x.X * y.Y - x.Y * y.X; var b = x.X * y.X + x.Y * y.Y; return Fun.Atan2(a, b); } //# } #endregion //# } #region AnyTiny, AllTiny /// /// Returns whether the absolute value of any component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AnyTiny(this __vtype__ v, __ftype__ epsilon) => /*# fields.ForEach(f => { */v.__f__.IsTiny(epsilon)/*# }, oror);*/; /// /// Returns whether the absolute value of each component of the given is smaller than . /// [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AllTiny(this __vtype__ v, __ftype__ epsilon) => /*# fields.ForEach(f => { */v.__f__.IsTiny(epsilon)/*# }, andand);*/; #endregion //# if (ft.IsReal) { #region Special Floating Point Value Checks //# var condArray = new[] { "Finite", "NaN", "Infinity", "PositiveInfinity", "NegativeInfinity", "Tiny" }; //# var quantArray = new[] { "Any", "All" }; //# condArray.ForEach(cond => { //# quantArray.ForEach(qant => { [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool __qant____cond__(__vtype__ v) => v.__qant____cond__; //# }); // quantArray //# }); // condArray #endregion //# if (d == 2 && !unsigned) { #region 2D Vector Arithmetics /// /// Dot product of vector with dir rotated by 90 degrees counterclockwise. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Dot90(this __vtype__ v, __vtype__ dir) { return v.Y * dir.X - v.X * dir.Y; } /// /// Dot product of vector with dir rotated by 180 degrees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Dot180(this __vtype__ v, __vtype__ dir) { return -(v.X * dir.X + v.Y * dir.Y); } /// /// Dot product of vector with dir rotated by 270 degrees counterclockwise. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ Dot270(this __vtype__ v, __vtype__ dir) { return v.X * dir.Y - v.Y * dir.X; } /// /// Returns the left value of the direction v with respect to the /// line from p0 to p1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ DirLeftOfLineValue(this __vtype__ v, __vtype__ p0, __vtype__ p1) { return v.X * (p0.Y - p1.Y) + v.Y * (p1.X - p0.X); } /// /// Returns the right value of the direction v with respect to the /// line from p0 to p1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ DirRightOfLineValue(this __vtype__ v, __vtype__ p0, __vtype__ p1) { return v.X * (p1.Y - p0.Y) + v.Y * (p0.X - p1.X); } /// /// Returns the left value of the point p with respect to the /// line from p0 to p1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ PosLeftOfLineValue(this __vtype__ p, __vtype__ p0, __vtype__ p1) { return (p.X - p0.X) * (p0.Y - p1.Y) + (p.Y - p0.Y) * (p1.X - p0.X); } /// /// Returns the right value of the point p with respect to the /// line from p0 to p1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __ftype__ PosRightOfLineValue(this __vtype__ p, __vtype__ p0, __vtype__ p1) { return (p.X - p0.X) * (p1.Y - p0.Y) + (p.Y - p0.Y) * (p0.X - p1.X); } #endregion //# } // d == 2 #region Linear Combination //# if (ft.IsReal) { //# for (int tpc = 2; tpc < 8; tpc++ ) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ LinCom(/*# tpc.ForEach(i => { */__vtype__ p__i__/*# }, comma); */, ref Tup__tpc__<__ftype__> w) { return /*# tpc.ForEach(i => { */p__i__ * w.E__i__/*# }, add); */; } //# } // tpc //# } // isreal #endregion //# } // ft.IsReal #region ArrayExtensions //# foreach (var it in Meta.IndexTypes) { var itype = it.Name; //# var prefix = it == Meta.LongType ? "Long" : ""; public static __itype__ __prefix__IndexOfClosestPoint(this __vtype__[] pointArray, __vtype__ point) { var bestDist = DistanceSquared(point, pointArray[0]); __itype__ bestIndex = 0; __itype__ count = pointArray.__prefix__Length; for (__itype__ i = 1; i < count; i++) { var dist = DistanceSquared(point, pointArray[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static __itype__ __prefix__IndexOfClosestPoint( this __vtype__[] array, __itype__ start, __itype__ count, __vtype__ point) { var bestDist = DistanceSquared(point, array[start]); __itype__ bestIndex = 0; for (__itype__ i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, array[i]); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } public static __itype__ __prefix__IndexOfClosestPoint( this T[] array, __itype__ start, __itype__ count, Func pointSelector, __vtype__ point) { var bestDist = DistanceSquared(point, pointSelector(array[start])); __itype__ bestIndex = 0; for (__itype__ i = start + 1, e = start + count; i < e; i++) { var dist = DistanceSquared(point, pointSelector(array[i])); if (dist < bestDist) { bestDist = dist; bestIndex = i; } } return bestIndex; } //# } // it //# var opArray = new[] { " < ", " > " }; //# var exArray = new[] { "min", "max" }; //# foreach (var isList in new[] { false, true }) { //# fields.ForEach(f => { //# for (int ei = 0; ei < 2; ei++) { //# var op = opArray[ei]; var ex = exArray[ei]; var fun = ex.Capitalized(); //# foreach (var it in Meta.IndexTypes) { var itype = it.Name; //# if (isList && it == Meta.LongType) continue; //# var prefix = it == Meta.LongType ? "Long" : ""; //# var arrayLen = isList ? "Count" : prefix + "Length"; //# var atype = isList ? "IList<" + vtype + ">" : vtype + "[]"; //# var listText = isList ? "list" : "array"; /// /// Returns the index of the element with the __ex__imal __f__ coordinate /// within the __listText__. /// public static __itype__ __prefix__IndexOf__fun____f__(this __atype__ vectorArray, __itype__ count = 0) { var __ex__imum = vectorArray[0].__f__; __itype__ __ex__Index = 0; if (count == 0) count = vectorArray.__arrayLen__; for (__itype__ i = 1; i < count; i++) { var p = vectorArray[i].__f__; if (p__op____ex__imum) { __ex__imum = p; __ex__Index = i; } } return __ex__Index; } //# } // it //# } // fi //# }); //# } // isList /// /// Returns the array of the index-th coordinate of each vector. /// public static __ftype__[] CopyCoord(this __vtype__[] self, int index) { switch (index) { //# fields.ForEach((f, i) => { case __i__: return self.Map(v => v.__f__); //# }); default: throw new IndexOutOfRangeException(); } } //# if (ft.IsReal) { public static __vtype__ WeightedSum( this __vtype__[] vectorArray, __ftype__[] weightArray) { var r = __vtype__.Zero; var count = vectorArray.LongLength; for (long i = 0; i < count; i++) r += vectorArray[i] * weightArray[i]; return r; } //# } // ft.IsReal #endregion } public static class IRandomUniform__vtype__Extensions { #region IRandomUniform extensions for __vtype__ //# string[] variants; //# if (ft == Meta.FloatType) { //# variants = new string[] { "", "Closed", "Open" }; //# } else if (ft == Meta.DoubleType) { //# variants = new string[] { "", "Closed", "Open", "Full", "FullClosed", "FullOpen" }; //# } else if (!unsigned) { //# variants = new string[] { "", "NonZero" }; //# } else { //# variants = new string[] { "" }; //# } //# foreach (var v in variants) { /// /// Uses Uniform__fcaps____v__() to generate the elements of a __vtype__ vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Uniform__vtype____v__(this IRandomUniform rnd) { return new __vtype__(/*# fields.ForEach(f => { */rnd.Uniform__fcaps____v__()/*# }, comma); */); } //# if (ft.IsReal && d < 4) { /// /// Uses Uniform__fcaps____v__() to generate the elements of a __vtype__ /// vector within the given Box__d____fchar__. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Uniform__vtype____v__(this IRandomUniform rnd, Box__d____fchar__ box) { return new __vtype__(/*# fields.ForEach(f => { */box.Min.__f__ + rnd.Uniform__fcaps____v__() * (box.Max.__f__ - box.Min.__f__)/*# }, comma); */); } //# } //# } //# if (ft.IsReal) { //# var constant = (ft != Meta.DoubleType) ? "ConstantF" : "Constant"; //# variants = (ft == Meta.FloatType) ? new string[] { "" } : new string[] { "", "Full" }; //# foreach (var v in variants) { //# if (d == 2) { /// /// Returns a uniformly distributed vector (corresponds to a /// uniformly distributed point on the unit circle). Uses Uniform__fcaps____v__() internally. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Uniform__vtype____v__Direction(this IRandomUniform rnd) { __ftype__ phi = rnd.Uniform__fcaps____v__() * __constant__.PiTimesTwo; return new __vtype__(Fun.Cos(phi), Fun.Sin(phi)); } //# } else if (d == 3) { /// /// Returns a uniformly distributed vector (corresponds to a /// uniformly distributed point on the surface of the unit sphere). /// Note however, that the returned vector will never be equal to /// [0, 0, -1]. Uses Uniform__fcaps____v__() internally. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Uniform__vtype____v__Direction(this IRandomUniform rnd) { __ftype__ phi = rnd.Uniform__fcaps____v__() * __constant__.PiTimesTwo; __ftype__ z = 1 - rnd.Uniform__fcaps____v__() * 2; __ftype__ s = Fun.Sqrt(1 - z * z); return new __vtype__(Fun.Cos(phi) * s, Fun.Sin(phi) * s, z); } //# var sphereVariants = new string[] { "Closed", "Open" }; //# foreach (var sv in sphereVariants) { //# if (sv == "Closed") { /// /// Uniform vector in the closed unit sphere (i.e vectors to /// the surface of the sphere may be generated). Uses Uniform__vtype____sv__() internally. /// //# } else { /// /// Uniform vector inside the open unit sphere (i.e. no vector /// ends on the surface of the sphere). Uses Uniform__vtype____sv__() internally. /// //# } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Uniform__vtype____v____sv__Sphere(this IRandomUniform rnd) { __ftype__ r2; __vtype__ p; __vtype__ c_shift = -__vtype__.Half; do { p = (rnd.Uniform__vtype____sv__() + c_shift) * 2; r2 = p.LengthSquared; } while (r2 >= 1); return p; } //# } //# } //d //# } //# } else if (!unsigned) { //ft.Real /// /// Uses Uniform__fcaps__(__ftype__) to generate the elements of a __vtype__ vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Uniform__vtype__(this IRandomUniform rnd, __ftype__ size) { return new __vtype__(/*# fields.ForEach(f => { */rnd.Uniform__fcaps__(size)/*# }, comma); */); } /// /// Uses Uniform__fcaps__(__ftype__) to generate the elements of a __vtype__ vector. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static __vtype__ Uniform__vtype__(this IRandomUniform rnd, __vtype__ size) { return new __vtype__(/*# fields.ForEach(f => { */rnd.Uniform__fcaps__(size.__f__)/*# }, comma); */); } //# } #endregion } #endregion //# } // vt } ================================================ FILE: src/Aardvark.Base/Random/ForcedRandomSeries.cs ================================================ using System.IO; using System.Runtime.InteropServices; using System; namespace Aardvark.Base { /// /// Provides an IRandomSeries view of a pre-computed 2d random sequence. /// public class ForcedRandomSeries : IRandomSeries { V2i m_index = V2i.OO; readonly V2i[] m_series; readonly int m_matrixSize; readonly double m_norm; readonly IRandomUniform m_rnd; V2i m_seed; readonly bool m_jitter; /// /// Reads a file that contains a raw V2i binary array as V2i[]. /// The binary data is supposed to contain NxN points as (int, int) in random order. /// public static V2i[] ReadSeries(string frsSqFile) { var bytes = File.ReadAllBytes(frsSqFile); var matrixSize = (int)(bytes.Length / 8).Sqrt(); // V2i[] encoded in byte array must be NxN and a multiple of 8. if (matrixSize * matrixSize * 8 != bytes.Length) throw new InvalidDataException("Forced Random series data has invalid length."); var dst = new V2i[bytes.Length / 8]; bytes.AsSpan().CopyTo(MemoryMarshal.AsBytes(dst.AsSpan())); return dst; } /// /// Create a ForcedRandomSeries with the given sample sequence and the seed as offset. /// The sequence is supposed to contain NxN points in random order. /// public ForcedRandomSeries(V2i[] series, int matrixSize, IRandomUniform rnd, bool jitter = true) { m_series = series; m_matrixSize = matrixSize; m_norm = 1.0 / m_matrixSize; // [0, 1) m_rnd = rnd; m_jitter = jitter; // random offset of sample pattern m_seed = new V2i(rnd.UniformInt(m_matrixSize), rnd.UniformInt(m_matrixSize)); } /// /// Create a ForcedRandomSeries with the given sample sequence and the seed as offset. /// The sequence is supposed to contain NxN points in random order. /// public ForcedRandomSeries(V2i[] series, IRandomUniform rnd, bool jitter = true) : this(series, (int)series.Length.Sqrt(), rnd, jitter) { } /// /// Create a ForcedRandomSeries from the given sequence data file /// and a random generator that is used to generate a seed. /// public ForcedRandomSeries(string frsSqFile, IRandomUniform rndSeed, bool jitter = true) : this(ReadSeries(frsSqFile), rndSeed, jitter) { } public double UniformDouble(int seriesIndex) { var ind = m_index[seriesIndex]++; var rnd = m_series[ind++ % m_series.Length][seriesIndex]; rnd += m_seed[seriesIndex]; // shift complete pattern by seed return ((rnd + (m_jitter ? m_rnd.UniformDouble() : 0.0)) * m_norm).Frac(); // optionally add sub-pixel jittering } } } ================================================ FILE: src/Aardvark.Base/Random/HaltonRandomSeries.cs ================================================ namespace Aardvark.Base { /// /// A halton series generator, that uses a normal random generator for /// higher order series, in order to avoid the slow coverage of higher /// order halton series. /// public class HaltonRandomSeries : IRandomSeries { public HaltonRandomSeries( int haltonCount, IRandomUniform randomUniform) { m_haltonStateArray = new double[haltonCount].SetByIndex( i => randomUniform.UniformDouble()); m_randomUniform = randomUniform; } public double UniformDouble(int seriesIndex) { if (seriesIndex < m_haltonStateArray.Length) { double value = Quasi.QuasiHaltonWithIndex( seriesIndex, m_haltonStateArray[seriesIndex]); m_haltonStateArray[seriesIndex] = value; return value; } else return m_randomUniform.UniformDouble(); } private readonly double [] m_haltonStateArray; private readonly IRandomUniform m_randomUniform; } } ================================================ FILE: src/Aardvark.Base/Random/IRandomDistribution.cs ================================================ namespace Aardvark.Base { public interface IRandomDistribution { /// /// Returns a distributed double. /// double GetDouble(); } } ================================================ FILE: src/Aardvark.Base/Random/IRandomSeries.cs ================================================ namespace Aardvark.Base { /// /// Maintain multiple independent series of random or quasi-random /// variables. For two-dimensional sampling the random variables of two /// series need to be combined (e.g. a random variable of series k and /// a random variable of series k+1). For quasi-random sampling, the /// lower series are assumed to achieve a faster coverage of the domain, /// and should therefore be used for the sampling dimensions with a /// larger influence on the result. /// public interface IRandomSeries { double UniformDouble(int seriesIndex); } public static class RandomSeriesExtensions { /// /// Returns a uniformly distributed vector (corresponds to a /// uniformly distributed point on the unit sphere) by using /// 2 random values from the series with the supplied indices. /// Note, that the returned vector will never be equal to [0, 0, -1]. /// public static V3d UniformV3dDirection(this IRandomSeries rnd, int si0, int si1) { double phi = rnd.UniformDouble(si0) * Constant.PiTimesTwo; double z = 1.0 - rnd.UniformDouble(si1) * 2.0; double s = System.Math.Sqrt(1.0 - z * z); return new V3d(System.Math.Cos(phi) * s, System.Math.Sin(phi) * s, z); } } } ================================================ FILE: src/Aardvark.Base/Random/IRandomUniform.cs ================================================ using Aardvark.Base.Sorting; using System; using System.Collections.Generic; using System.Linq; namespace Aardvark.Base { /// /// This interface enforces a common API for random number generators. /// public interface IRandomUniform { #region Info and Seeding /// /// Returns the number of random bits that the generator /// delivers. This many bits are actually random in the /// doubles returned by . /// int RandomBits { get; } /// /// Returns true if the doubles generated by this random /// generator contain 52 random mantissa bits. /// bool GeneratesFullDoubles { get; } /// /// Reinitializes the random generator with the specified seed. /// void ReSeed(int seed); #endregion #region Random Integers /// /// Returns a uniformly distributed integer in the interval /// [0, 2^31-1]. /// int UniformInt(); /// /// Returns a uniformly distributed integer in the interval /// [0, 2^32-1]. /// uint UniformUInt(); /// /// Returns a uniformly distributed integer in the interval /// [0, 2^63-1]. /// long UniformLong(); /// /// Returns a uniformly distributed integer in the interval /// [0, 2^64-1]. /// ulong UniformULong(); #endregion #region Random Floating Point Values /// /// Returns a uniformly distributed float in the half-open interval /// [0.0f, 1.0f). /// float UniformFloat(); /// /// Returns a uniformly distributed float in the closed interval /// [0.0f, 1.0f]. /// float UniformFloatClosed(); /// /// Returns a uniformly distributed float in the open interval /// (0.0f, 1.0f). /// float UniformFloatOpen(); /// /// Returns a uniformly distributed double in the half-open interval /// [0.0, 1.0). Note, that only RandomBits bits are guaranteed to be /// random. /// double UniformDouble(); /// /// Returns a uniformly distributed double in the closed interval /// [0.0, 1.0]. Note, that only RandomBits bits are guaranteed to be /// random. /// double UniformDoubleClosed(); /// /// Returns a uniformly distributed double in the open interval /// (0.0, 1.0). Note, that only RandomBits bits are guaranteed to be /// random. /// double UniformDoubleOpen(); #endregion } public static class IRandomUniformExtensions { #region Random Bits /// /// Supply random bits one at a time. The currently unused bits are /// maintained in the supplied reference parameter. Before the first /// call randomBits must be 0. /// public static bool RandomBit( this IRandomUniform rnd, ref int randomBits) { if (randomBits <= 1) { randomBits = rnd.UniformInt(); bool bit = (randomBits & 1) != 0; randomBits = 0x40000000 | (randomBits >> 1); return bit; } else { bool bit = (randomBits & 1) != 0; randomBits >>= 1; return bit; } } #endregion #region Random Integers /// /// Returns a uniformly distributed int in the interval [0, count-1]. /// In order to avoid excessive aliasing, two random numbers are used /// when count is greater or equal 2^24 and the random generator /// delivers 32 random bits or less. The method thus works fairly /// decently for all integers. /// public static int UniformInt(this IRandomUniform rnd, int size) { if (rnd.GeneratesFullDoubles || size < 16777216) return (int)(rnd.UniformDouble() * size); else return (int)(rnd.UniformDoubleFull() * size); } /// /// Returns a uniformly distributed long in the interval [0, size-1]. /// NOTE: If count has more than about 48 bits, aliasing leads to /// noticeable (greater 5%) shifts in the probabilities (i.e. one /// long has a probability of x and the other a probability of /// x * (2^(52-b)-1)/(2^(52-b)), where b is log(size)/log(2)). /// public static long UniformLong(this IRandomUniform rnd, long size) { if (rnd.GeneratesFullDoubles || size < 16777216) return (long)(rnd.UniformDouble() * size); else return (long)(rnd.UniformDoubleFull() * size); } /// /// Returns a uniform int which is guaranteed not to be zero. /// public static int UniformIntNonZero(this IRandomUniform rnd) { int r; do { r = rnd.UniformInt(); } while (r == 0); return r; } /// /// Returns a uniform long which is guaranteed not to be zero. /// public static long UniformLongNonZero(this IRandomUniform rnd) { long r; do { r = rnd.UniformLong(); } while (r == 0); return r; } #endregion #region Random Floating Point Values /// /// Returns a uniformly distributed double in the half-open interval /// [0.0, 1.0). Note, that two random values are used to make all 53 /// bits random. If you use this repeatedly, consider using a 64-bit /// random generator, which can provide such doubles directly using /// UniformDouble(). /// public static double UniformDoubleFull(this IRandomUniform rnd) { if (rnd.GeneratesFullDoubles) return rnd.UniformDouble(); long r = ((~0xfL & (long)rnd.UniformInt()) << 22) | ((long)rnd.UniformInt() >> 5); return r * (1.0 / 9007199254740992.0); } /// /// Returns a uniformly distributed double in the closed interval /// [0.0, 1.0]. Note, that two random values are used to make all 53 /// bits random. /// public static double UniformDoubleFullClosed(this IRandomUniform rnd) { if (rnd.GeneratesFullDoubles) return rnd.UniformDoubleClosed(); long r = ((~0xfL & (long)rnd.UniformInt()) << 22) | ((long)rnd.UniformInt() >> 5); return r * (1.0 / 9007199254740991.0); } /// /// Returns a uniformly distributed double in the open interval /// (0.0, 1.0). Note, that two random values are used to make all 53 /// bits random. /// public static double UniformDoubleFullOpen(this IRandomUniform rnd) { if (rnd.GeneratesFullDoubles) return rnd.UniformDoubleOpen(); long r; do { r = ((~0xfL & (long)rnd.UniformInt()) << 22) | ((long)rnd.UniformInt() >> 5); } while (r == 0); return r * (1.0 / 9007199254740992.0); } #endregion #region Creating Randomly Filled Arrays /// /// Create a random array of ints in the interval /// [0, 2^31-1] of the specified length. /// public static int[] CreateUniformIntArray( this IRandomUniform rnd, long length) { var array = new int[length]; rnd.FillUniform(array); return array; } /// /// Create a random array of longs in the interval /// [0, 2^63-1] of the specified length. /// public static long[] CreateUniformLongArray( this IRandomUniform rnd, long length) { var array = new long[length]; rnd.FillUniform(array); return array; } /// /// Create a random array of floats in the half-open interval /// [0.0, 1.0) of the specified length. /// public static float[] CreateUniformFloatArray( this IRandomUniform rnd, long length) { var array = new float[length]; rnd.FillUniform(array); return array; } /// /// Create a random array of doubles in the half-open interval /// [0.0, 1.0) of the specified length. /// public static double[] CreateUniformDoubleArray( this IRandomUniform rnd, long length) { var array = new double[length]; rnd.FillUniform(array); return array; } /// /// Create a random array of full doubles in the half-open interval /// [0.0, 1.0) of the specified length. /// public static double[] CreateUniformDoubleFullArray( this IRandomUniform rnd, long length) { var array = new double[length]; rnd.FillUniformFull(array); return array; } /// /// Fills the specified array with random ints in the interval /// [0, 2^31-1]. /// public static void FillUniform(this IRandomUniform rnd, int[] array) { long count = array.LongLength; for (long i = 0; i < count; i++) array[i] = rnd.UniformInt(); } /// /// Fills the specified array with random longs in the interval /// [0, 2^63-1]. /// public static void FillUniform(this IRandomUniform rnd, long[] array) { long count = array.LongLength; for (long i = 0; i < count; i++) array[i] = rnd.UniformLong(); } /// /// Fills the specified array with random floats in the half-open /// interval [0.0f, 1.0f). /// public static void FillUniform(this IRandomUniform rnd, float[] array) { long count = array.LongLength; for (long i = 0; i < count; i++) array[i] = rnd.UniformFloat(); } /// /// Fills the specified array with random doubles in the half-open /// interval [0.0, 1.0). /// public static void FillUniform( this IRandomUniform rnd, double[] array) { long count = array.LongLength; for (long i = 0; i < count; i++) array[i] = rnd.UniformDouble(); } /// /// Fills the specified array with fully random doubles (53 random /// bits) in the half-open interval [0.0, 1.0). /// public static void FillUniformFull( this IRandomUniform rnd, double[] array) { long count = array.LongLength; if (rnd.GeneratesFullDoubles) { for (long i = 0; i < count; i++) array[i] = rnd.UniformDoubleFull(); } else { for (long i = 0; i < count; i++) array[i] = rnd.UniformDouble(); } } /// /// Creates an array that contains a random permutation of the /// ints in the interval [0, count-1]. /// public static int[] CreatePermutationArray( this IRandomUniform rnd, int count) { var p = new int[count].SetByIndex(i => i); rnd.Randomize(p); return p; } /// /// Creates an array that contains a random permutation of the /// numbers in the interval [0, count-1]. /// public static long[] CreatePermutationArrayLong( this IRandomUniform rnd, long count) { var p = new long[count].SetByIndexLong(i => i); rnd.Randomize(p); return p; } #endregion #region Creationg a Random Subset (while maintaing order) /// /// Returns a random subset of an array with a supplied number of /// elements (subsetCount). The elements in the subset are in the /// same order as in the original array. O(count). /// NOTE: this method needs to generate one random number for each /// element of the original array. If subsetCount is significantly /// smaller than count, it is more efficient to use /// or /// or /// or /// . /// public static T[] CreateRandomSubsetOfSize( this T[] array, long subsetCount, IRandomUniform rnd = null) { if (rnd == null) rnd = new RandomSystem(); long count = array.LongLength; if (!(subsetCount >= 0 && subsetCount <= count)) throw new ArgumentOutOfRangeException(nameof(subsetCount)); var subset = new T[subsetCount]; long si = 0; for (int ai = 0; ai < count && si < subsetCount; ai++) { var p = (double)(subsetCount - si) / (double)(count - ai); if (rnd.UniformDouble() <= p) subset[si++] = array[ai]; } return subset; } /// /// Returns a random subset of the enumeration with a supplied number of /// elements (subsetCount). The elements in the subset are in the /// same order as in the input. O(count). /// NOTE: The number of elements of the Enumerable need to be calculated, in case of true enumerations /// the implementation of .Count() results in a second evaluation of the enumerable. /// public static T[] CreateRandomSubsetOfSize( this IEnumerable input, long subsetCount, IRandomUniform rnd = null) { if (rnd == null) rnd = new RandomSystem(); long count = input.Count(); if (!(subsetCount >= 0 && subsetCount <= count)) throw new ArgumentOutOfRangeException(nameof(subsetCount)); var subset = new T[subsetCount]; long si = 0, ai = 0; foreach (var a in input) { if (ai < count && si < subsetCount) { var p = (double)(subsetCount - si) / (double)(count - ai++); if (rnd.UniformDouble() <= p) subset[si++] = a; } else break; } return subset; } /// /// Creates an unordered array of subsetCount long indices that /// constitute a subset of all longs in the range [0, count-1]. /// O(subsetCount) for subsetCount << count. /// NOTE: It is assumed that subsetCount is significantly smaller /// than count. If this is not the case, use /// CreateRandomSubsetOfSize instead. /// WARNING: As subsetCount approaches count execution time /// increases significantly. /// public static long[] CreateSmallRandomSubsetIndexArrayLong( this IRandomUniform rnd, long subsetCount, long count) { if (!(subsetCount >= 0 && subsetCount <= count)) throw new ArgumentOutOfRangeException(nameof(subsetCount)); var subsetIndices = new LongSet(subsetCount); for (int i = 0; i < subsetCount; i++) { long index; do { index = rnd.UniformLong(count); } while (!subsetIndices.TryAdd(index)); } return subsetIndices.ToArray(); } /// /// Creates an ordered array of subsetCount long indices that /// constitute a subset of all longs in the range [0, count-1]. /// O(subsetCount * log(subsetCount)) for subsetCount << count. /// NOTE: It is assumed that subsetCount is significantly smaller /// than count. If this is not the case, use /// CreateRandomSubsetOfSize instead. /// WARNING: As subsetCount approaches count execution time /// increases significantly. /// public static long[] CreateSmallRandomOrderedSubsetIndexArrayLong( this IRandomUniform rnd, long subsetCount, long count) { var subsetIndexArray = rnd.CreateSmallRandomSubsetIndexArrayLong(subsetCount, count); subsetIndexArray.QuickSortAscending(); return subsetIndexArray; } /// /// Creates an unordered array of subsetCount int indices that /// constitute a subset of all ints in the range [0, count-1]. /// O(subsetCount) for subsetCount << count. /// NOTE: It is assumed that subsetCount is significantly smaller /// than count. If this is not the case, use /// CreateRandomSubsetOfSize instead. /// WARNING: As subsetCount approaches count execution time /// increases significantly. /// public static int[] CreateSmallRandomSubsetIndexArray( this IRandomUniform rnd, int subsetCount, int count) { if (!(subsetCount >= 0 && subsetCount <= count)) throw new ArgumentOutOfRangeException(nameof(subsetCount)); var subsetIndices = new IntSet(subsetCount); for (int i = 0; i < subsetCount; i++) { int index; do { index = rnd.UniformInt(count); } while (!subsetIndices.TryAdd(index)); } return subsetIndices.ToArray(); } /// /// Creates an ordered array of subsetCount int indices that /// constitute a subset of all ints in the range [0, count-1]. /// O(subsetCount * log(subsetCount)) for subsetCount << count. /// NOTE: It is assumed that subsetCount is significantly smaller /// than count. If this is not the case, use /// CreateRandomSubsetOfSize instead. /// WARNING: As subsetCount approaches count execution time /// increases significantly. /// public static int[] CreateSmallRandomOrderedSubsetIndexArray( this IRandomUniform rnd, int subsetCount, int count) { var subsetIndexArray = rnd.CreateSmallRandomSubsetIndexArray(subsetCount, count); subsetIndexArray.QuickSortAscending(); return subsetIndexArray; } #endregion #region Randomizing Existing Arrays /// /// Randomly permute the first count elements of the /// supplied array. This does work with counts of up /// to about 2^50. /// public static void Randomize( this IRandomUniform rnd, T[] array, long count) { if (count <= (long)int.MaxValue) { int intCount = (int)count; for (int i = 0; i < intCount; i++) array.Swap(i, rnd.UniformInt(intCount)); } else { for (long i = 0; i < count; i++) array.Swap(i, rnd.UniformLong(count)); } } /// /// Randomly permute the elements of the supplied array. This does /// work with arrays up to a length of about 2^50. /// public static void Randomize( this IRandomUniform rnd, T[] array) { rnd.Randomize(array, array.LongLength); } /// /// Randomly permute the elements of the supplied list. /// public static void Randomize( this IRandomUniform rnd, List list) { int count = list.Count; for (int i = 0; i < count; i++) list.Swap(i, rnd.UniformInt(count)); } /// /// Randomly permute the specified number of elements in the supplied /// array starting at the specified index. /// public static void Randomize( this IRandomUniform rnd, T[] array, int start, int count) { for (int i = start, e = start + count; i < e; i++) array.Swap(i, start + rnd.UniformInt(count)); } /// /// Randomly permute the specified number of elements in the supplied /// array starting at the specified index. /// public static void Randomize( this IRandomUniform rnd, T[] array, long start, long count) { for (long i = start, e = start + count; i < e; i++) array.Swap(i, start + rnd.UniformLong(count)); } /// /// Randomly permute the specified number of elements in the supplied /// list starting at the specified index. /// public static void Randomize( this IRandomUniform rnd, List list, int start, int count) { for (int i = start; i < start + count; i++) list.Swap(i, start + rnd.UniformInt(count)); } #endregion #region Random Distributions /// /// Generates normal distributed random variable with given mean and standard deviation. /// Uses the Box-Muller Transformation to transform two uniform distributed random variables to one normal distributed value. /// NOTE: If multiple normal distributed random values are required, consider using . /// public static double Gaussian(this IRandomUniform rnd, double mean = 0.0, double stdDev = 1.0) { // Box-Muller Transformation var u1 = 1.0 - rnd.UniformDouble(); // uniform (0,1] -> log requires > 0 var u2 = rnd.UniformDouble(); // uniform [0,1) var randStdNormal = Fun.Sqrt(-2.0 * Fun.Log(u1)) * Fun.Sin(Constant.PiTimesTwo * u2); return mean + stdDev * randStdNormal; } #endregion } public static class IRandomEnumerableExtensions { #region Random Order /// /// Enumerates elements in random order. /// public static IEnumerable RandomOrder(this IEnumerable self, IRandomUniform rnd = null) { var tmp = self.ToArray(); if (rnd == null) rnd = new RandomSystem(); var perm = rnd.CreatePermutationArray(tmp.Length); return perm.Select(index => tmp[index]); } #endregion } } ================================================ FILE: src/Aardvark.Base/Random/PerlinNoise.cs ================================================ using System; namespace Aardvark.Base { /// /// Perlin noise generation class. /// Contains functions for 1D, 2D and 3D perlin noise generation. /// public class PerlinNoise { private readonly int m_PrimeOne; private readonly int m_PrimeTwo; private readonly int m_PrimeThree; private int m_maxX; private int m_maxY; // private int m_maxZ; float[] m_lookup; private readonly Func m_interpolate; #region Constructors /// /// InitialintegerZes a new instance of the class. /// public PerlinNoise() { m_PrimeOne = 15731; m_PrimeTwo = 789221; m_PrimeThree = 1376312589; m_lookup = null; m_maxX = 0; m_maxY = 0; // m_maxZ = 0; m_interpolate = (a, b, x) => { x = (1 - (x * ConstantF.Pi).Cos()) * 0.5f; return a * (1 - x) + b * x; }; } #endregion /// /// Generates a pseudo-random number based upon one value(dimension). /// /// An integer value. /// A single-precision floating point value between -1 and 1. public float Noise(int x) { if (m_lookup != null) return m_lookup[x]; x = (x << 13) ^ x; double d = (double)((x * (x*x*m_PrimeOne+m_PrimeTwo)+m_PrimeThree) & 0x7fffffff); return ( 1.0f - (float)( d / 1073741824.0 ) ); } /// /// Generates a pseudo-random number based upon two value(dimensions). /// /// An integer value. /// An integer value. /// A single-precision floating point value between -1 and 1. public float Noise(int x, int y) { if (m_lookup != null) return m_lookup[x+y*m_maxX]; uint N = (uint)(x+y * 57); N = (N << 13) ^ N; double d = (double)((N * (N * N * m_PrimeOne+m_PrimeTwo )+m_PrimeThree) & 0x7fffffff); return(1.0f - (float)(d / 1073741824.0)); } /// /// Generates a pseudo-random number based upon three value(dimensions). /// /// An integer value. /// An integer value. /// An integer value. /// A single-precision floating point value between -1 and 1. public float Noise(int x, int y, int z) { if (m_lookup != null) return m_lookup[x+(z*m_maxY+y) * m_maxX]; int L = (x+y * 57); int M = (y+z * 57); uint N = (uint)(L+M * 57); N = (N << 13) ^ N; double d = (double)((N * (N * N * m_PrimeOne+m_PrimeTwo )+m_PrimeThree ) & 0x7fffffff); return(1.0f - (float)(d / 1073741824.0)); } public float SmoothNoise(int x) => (Noise(x)/2.0f)+(Noise(x-1)/4.0f)+(Noise(x+1)/4.0f); public float SmoothNoise(int x, int y) { float corners = (Noise(x-1, y-1) + Noise(x+1, y-1) + Noise(x-1, y+1) + Noise(x+1, y+1)) / 16.0f; float sides = (Noise(x-1, y ) + Noise(x+1, y ) + Noise(x , y-1) + Noise(x , y+1)) / 8.0f; float center = Noise(x, y)/4.0f; return(corners+sides+center); } public float SmoothNoise(int x, int y, int z) { float corners, sides, center; float averageZM1, averageZ, averageZP1; // average of neighbours in z-1 corners = (Noise(x-1, y-1, z-1) + Noise(x+1, y-1, z-1) + Noise(x-1, y+1, z-1) + Noise(x+1, y+1, z-1)) / 16.0f; sides = (Noise(x-1, y , z-1) + Noise(x+1, y , z-1) + Noise(x , y-1, z-1) + Noise(x , y+1, z-1)) / 8.0f; center = Noise(x , y , z-1) / 4.0f; averageZM1 = corners+sides+center; // average of neighbours in z corners = (Noise(x-1, y-1, z) + Noise(x+1, y-1, z) + Noise(x-1, y+1, z) + Noise(x+1, y+1, z)) / 16.0f; sides = (Noise(x-1, y , z) + Noise(x+1, y , z) + Noise(x , y-1, z) + Noise(x , y+1, z)) / 8.0f; center = Noise(x, y, z ) / 4.0f; averageZ = corners+sides+center; // average of neighbours in z+1 corners = (Noise(x-1, y-1, z+1) + Noise(x+1, y-1, z+1) + Noise(x-1, y+1, z+1) + Noise(x+1, y+1, z+1)) / 16.0f; sides = (Noise(x-1, y , z+1) + Noise(x+1, y , z+1) + Noise(x , y-1, z+1) + Noise(x , y+1, z+1)) / 8.0f; center = Noise(x , y , z+1) / 4.0f; averageZP1 = corners+sides+center; return((averageZM1 / 4.0f)+(averageZ / 2.0f)+(averageZP1 / 4.0f)); } public float InterpolateNoise(float x) { int integerX = (int)x; float fracX = x - (float)integerX; float v1 = SmoothNoise(integerX); float v2 = SmoothNoise(integerX + 1); return m_interpolate(v1, v2, fracX); } public float InterpolateNoise(float x, float y) { int integerX = (int)x; float fracX = x - (float)integerX; int integerY = (int)y; float fracY = y - (float)integerY; float v1 = SmoothNoise(integerX , integerY); float v2 = SmoothNoise(integerX+1 , integerY); float v3 = SmoothNoise(integerX , integerY+1); float v4 = SmoothNoise(integerX+1 , integerY+1); float i1 = m_interpolate(v1, v2, fracX); float i2 = m_interpolate(v3, v4, fracX); return m_interpolate(i1, i2, fracY); } public float InterpolateNoise(float x, float y, float z) { int integerX = (int)x; float fracX = x - (float)integerX; int integerY = (int)y; float fracY = y - (float)integerY; int integerZ = (int)z; float fracZ = z - (float)integerZ; float v1 = SmoothNoise(integerX , integerY , integerZ); float v2 = SmoothNoise(integerX+1 , integerY , integerZ); float v3 = SmoothNoise(integerX , integerY+1 , integerZ); float v4 = SmoothNoise(integerX+1 , integerY+1 , integerZ); float v5 = SmoothNoise(integerX , integerY , integerZ+1); float v6 = SmoothNoise(integerX+1 , integerY , integerZ+1); float v7 = SmoothNoise(integerX , integerY+1 , integerZ+1); float v8 = SmoothNoise(integerX+1 , integerY+1 , integerZ+1); float i1 = m_interpolate(v1, v2, fracX); float i2 = m_interpolate(v3, v4, fracX); float i3 = m_interpolate(v5, v6, fracX); float i4 = m_interpolate(v7, v8, fracX); float i5 = m_interpolate(i1, i2, fracY); float i6 = m_interpolate(i3, i4, fracY); return m_interpolate(i5, i6, fracZ); } public float PerlinNoise1F(float x, float amplitude, float frequencyX) { return InterpolateNoise(x*frequencyX) * amplitude; } public float PerlinNoise2F(float x, float y, float amplitude, float frequencyX, float frequencyY) { return InterpolateNoise(x*frequencyX, y*frequencyY ) * amplitude; } public float PerlinNoise3F(float x, float y, float z, float amplitude, float frequencyX, float frequencyY, float frequencyZ) { return InterpolateNoise(x*frequencyX, y*frequencyY, z*frequencyZ) * amplitude; } /// /// Generates the 1d noise and stores it in the lookup table(for faster processing). /// /// max x value (generates noise from 0 to uiMaxX) void GenerateLookup(int maxX) { m_maxX = maxX; m_lookup = new float[maxX]; for (int x = 0; x < maxX; x++) m_lookup[x] = Noise(x); } /// /// Generates the 2d noise and stores it in the lookup table (for faster processing). /// /// max x value (generates noise from 0 to uiMaxX) /// max y value (generates noise from 0 to uiMaxY) void GenerateLookup(int maxX, int maxY) { m_maxX = maxX; m_maxY = maxY; m_lookup = new float[maxX * maxY]; int offsetY = 0; for (int y = 0; y < maxY; y++) { for (int x = 0; x < maxX; x++) m_lookup[x + offsetY] = Noise(x,y); offsetY += maxX; } } /// /// Generates the 3d noise and stores it in the lookup table (for faster processing). /// /// max x value (generates noise from 0 to uiMaxX) /// max y value (generates noise from 0 to uiMaxY) /// max z value (generates noise from 0 to uiMaxZ) void GenerateLookup(int maxX, int maxY, int maxZ) { m_maxX = maxX; m_maxY = maxY; // m_maxZ = maxZ; m_lookup = new float[maxX * maxY * maxZ]; int offsetY = 0; int offsetZ = 0; int stepZ = maxX * maxY; for (int z = 0; z < maxZ; z++) { for (int y = 0; y < maxY; y++) { for (int x = 0; x < maxX; x++) m_lookup[x + offsetY + offsetZ] = Noise(x,y,z); offsetY += maxX; } offsetY = 0; offsetZ += stepZ; } } } public static class ImprovedNoise { public static double Noise(double x, double y, double z) { int xc = (int)Fun.Floor(x) & 0xff, // Find unit cube that yc = (int)Fun.Floor(y) & 0xff, // contains point. zc = (int)Fun.Floor(z) & 0xff; x -= Fun.Floor(x); // Find relative x,y,z y -= Fun.Floor(y); // of point in cube. z -= Fun.Floor(z); double u = Fade(x), v = Fade(y), w = Fade(z); int a = p[xc ]+yc, aa = p[a]+zc, ab = p[a+1]+zc, // hash of cube b = p[xc+1]+yc, ba = p[b]+zc, bb = p[b+1]+zc; // corners return Lerp(w, Lerp(v, Lerp(u, Grad(p[aa ], x , y , z ), Grad(p[ba ], x-1, y , z )), Lerp(u, Grad(p[ab ], x , y-1, z ), Grad(p[bb ], x-1, y-1, z ))), Lerp(v, Lerp(u, Grad(p[aa+1], x , y , z-1), Grad(p[ba+1], x-1, y , z-1)), Lerp(u, Grad(p[ab+1], x , y-1, z-1), Grad(p[bb+1], x-1, y-1, z-1)))); } static double Fade(double t) => t * t * t * (t * (t * 6 - 15) + 10); static double Lerp(double t, double a, double b) => a + t * (b - a); static double Grad(int hash, double x, double y, double z) { int h = hash & 0xf; // Convert lo 4 bits of hash code double u = h < 8 ? x : y, // into 12 gradient directions. v = h < 4 ? y : h == 12 || h == 14 ? x : z; return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); } static readonly int[] permutation = { 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103, 30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75, 0,26,197, 62,94,252,219,203,117,35, 11,32,57,177,33,88,237,149,56,87,174,20, 125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231, 83,111,229,122,60,211,133,230,220,105,92, 41,55,46,245,40,244,102, 143,54,65,25,63,161, 1,216,80,73,209,76,132,187,208,89,18,169,200, 196,135,130,116,188,159, 86,164,100,109,198,173,186, 3,64, 52,217, 226,250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227, 47, 16,58,17,182,189, 28,42,223,183,170,213,119,248,152, 2,44,154, 163,70,221,153,101,155,167,43,172, 9,129, 22,39,253,19,98,108,110, 79,113,224,232,178,185,112,104,218,246,97,228,251, 34,242,193,238, 210,144, 12,191,179,162,241,81,51,145,235,249, 14,239,107, 49,192, 214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254, 138,236,205,93,222,114,67,29, 24,72,243,141,128,195,78, 66,215,61, 156,180 }; static readonly int[] p; static ImprovedNoise() { p = new int[512]; for (int i = 0; i < 256 ; i++) p[256+i] = p[i] = permutation[i]; } } } ================================================ FILE: src/Aardvark.Base/Random/Prime.cs ================================================ using System; namespace Aardvark.Base { public static class Prime { const int c_initialPrimeCount = 64; const int c_maxPrimeCount = 1 << 24; public static bool IsTrueFor(long value) { if (value < 0) return false; if (value < isPrimeArray.Length) return isPrimeArray[value]; int root = (int)Fun.Sqrt(value); int directMaxPrime = Fun.Min(primeArray[primeCount - 1], root); int pi; for (pi = 0; primeArray[pi] <= directMaxPrime; pi++) if (value % primeArray[pi] == 0) return false; if (directMaxPrime == root) return true; while (true) { int p = Prime.WithIndex(pi); if (p > root) break; if (value % p == 0) return false; pi++; } return true; } /// /// Returns the prime number with the supplied index. Indices start at /// zero and the first prime number is 2. Thus /// 'Prime.WithIndex(0) == 2'. /// public static int WithIndex(int primeIndex) { if (primeIndex >= primeCount) CalculateUpToIndex(primeIndex); return primeArray[primeIndex]; } /// /// Returns the inverse of the prime number with the supplied index. /// Indices start at zero and the first prime number is 2. Thus /// 'Prime.InverseWithIndex(0) == 0.5'. /// public static double InverseWithIndex(int primeIndex) { if (primeIndex >= primeCount) CalculateUpToIndex(primeIndex); return primeInverseArray[primeIndex]; } /// /// The number of primes that have already been calculated. /// private static int primeCount; private static int candidate = 5; private static int root = 3; private static int square = 9; private static int step = 2; private static int logIndexCount = 3; private static int logIndexTrigger = 8; private static void CalculateUpToIndex(int last) { if (last >= c_maxPrimeCount) throw new ArgumentException("exceeded prime table size limit"); if (last >= primeCapacity) { while (last >= primeCapacity) primeCapacity *= 2; Array.Resize(ref primeArray, primeCapacity); Array.Resize(ref primeInverseArray, primeCapacity); } while (primeCount <= last) { for (bool found = false; !found; ) { candidate += step; step = 6 - step; if (candidate > square) { ++root; square = root * root; } found = true; for (int pi = 2; primeArray[pi] <= root; pi++) if (candidate % primeArray[pi] == 0) { found = false; break; } } if (candidate > logIndexTrigger) { primeLogIndexArray[logIndexCount++] = primeCount; logIndexTrigger *= 2; } primeArray[primeCount] = candidate; primeInverseArray[primeCount] = 1.0/(double)candidate; ++primeCount; } } static Prime() { primeCapacity = c_initialPrimeCount; primeArray[0] = 2; primeArray[1] = 3; primeArray[2] = 5; primeInverseArray[0] = 1/2.0; primeInverseArray[1] = 1/3.0; primeInverseArray[2] = 1/5.0; primeLogIndexArray[0] = -1; primeLogIndexArray[1] = 0; primeLogIndexArray[2] = 2; primeCount = 3; CalculateUpToIndex(c_initialPrimeCount - 1); int isPrimeCount = primeArray[c_initialPrimeCount - 1] + 1; isPrimeArray = new bool[isPrimeCount]; for (int pi = 0; pi < primeCount; pi++) isPrimeArray[primeArray[pi]] = true; } private static int primeCapacity; private static int[] primeArray = new int[c_initialPrimeCount]; private static double[] primeInverseArray = new double[c_initialPrimeCount]; private static readonly bool[] isPrimeArray; private static readonly int[] primeLogIndexArray = new int[64]; } } ================================================ FILE: src/Aardvark.Base/Random/PseudoRandomSeries.cs ================================================ using System; using System.Collections.Generic; using System.Text; namespace Aardvark.Base { /// /// Uses an IRandomUniform generator to create an IRandomSeries. /// The series that are generated will not correlated. /// public class PseudoRandomSeries : IRandomSeries { readonly IRandomUniform m_rnd; public PseudoRandomSeries(IRandomUniform rnd) { m_rnd = rnd; } public double UniformDouble(int seriesIndex) { return m_rnd.UniformDouble(); } } } ================================================ FILE: src/Aardvark.Base/Random/Quasi.cs ================================================ namespace Aardvark.Base { public static class Quasi { /// /// Generates a new number in the halton sequence /// with the given inverse base, and the previous /// number in the sequence. /// /// This is the incremental version to generate /// the halton squence of quasi-random numbers of /// a given base. It has been taken from: /// /// A. Keller: Instant Radiosity, /// In Computer Graphics (SIGGRAPH 97 Conference Proceedings), /// pp. 49--56, August 1997. /// /// As a small optimization, the inverse of the base is used. /// public static double QuasiHalton( double inverse_base, double value) { double r = 1.0 - value - 1e-10; if (inverse_base < r) { value += inverse_base; } else { double h = inverse_base * inverse_base; double hh = inverse_base; while (h >= r) { hh = h; h *= inverse_base; } value += hh + h - 1.0; } return value; } /// /// Generates a new number in the halton sequence /// with the 'index'th prime as base. /// public static double QuasiHaltonWithIndex( int index, double value) { return QuasiHalton(Prime.InverseWithIndex(index), value); } } } ================================================ FILE: src/Aardvark.Base/Random/RandomDistributions.cs ================================================ using System; namespace Aardvark.Base { /// /// Generator of normal distributed random values. /// The generator uses the Box-Muller transformation to generate two samples at /// once and thereby is superior to if multiple samples are required. /// public class RandomGaussian : IRandomDistribution { private readonly IRandomUniform m_rndUniform; private double m_cachedValue; public RandomGaussian(IRandomUniform rndUniform) { m_rndUniform = rndUniform; m_cachedValue = Double.NaN; } #region IRandomDistribution Members /// /// Returns a Gaussian distributed double. /// public double GetDouble() { double value; if (!Double.IsNaN(m_cachedValue)) { value = m_cachedValue; m_cachedValue = Double.NaN; } else { // using the polar form of the Box-Muller transformation to // transform two random uniform values to two Gaussian // distributed values double x1, x2, w; do { x1 = 2.0 * m_rndUniform.UniformDouble() - 1.0; x2 = 2.0 * m_rndUniform.UniformDouble() - 1.0; w = x1 * x1 + x2 * x2; } while (w >= 1.0); w = Fun.Sqrt((-2.0 * Fun.Log(w)) / w); value = x1 * w; m_cachedValue = x2 * w; } return value; } #endregion #region Other Methods /// /// Returns a Gaussian distributed double given a mean and standard deviation. /// public double GetDouble(double mean, double standardDeviation) => GetDouble() * standardDeviation + mean; #endregion } } ================================================ FILE: src/Aardvark.Base/Random/RandomIEnumerableExtensions.cs ================================================ using System; using System.Collections.Generic; namespace Aardvark.Base { public static class RandomIEnumerableExtensions { /// /// Yields each element with propability p. /// public static IEnumerable TakeRandomly(this IEnumerable self, double p, IRandomUniform random = null) { if (self == null) throw new ArgumentNullException(nameof(self)); if (double.IsNaN(p) || p < 0 || p > 1) throw new ArgumentOutOfRangeException(nameof(p)); if (random == null) random = new RandomSystem(); foreach (var s in self) if (random.UniformDouble() <= p) yield return s; } /// /// Yields each element with propability p. /// public static IEnumerable TakeRandomly(this IEnumerable self, Func selector, double p, IRandomUniform random = null) { if (self == null) throw new ArgumentNullException(nameof(self)); if (double.IsNaN(p) || p < 0 || p > 1) throw new ArgumentOutOfRangeException(nameof(p)); if (random == null) random = new RandomSystem(); foreach (var s in self) if (random.UniformDouble() <= p) yield return selector(s); } } } ================================================ FILE: src/Aardvark.Base/Random/RandomSample.cs ================================================ namespace Aardvark.Base { public static class RandomSample { /// /// Uses the 2 random series (seriesIndex, seriesIndex+1) to generate a random point on a sphere. /// public static V3d Spherical(IRandomSeries rnds, int seriesIndex) { return Spherical(rnds.UniformDouble(seriesIndex), rnds.UniformDouble(seriesIndex + 1)); } /// /// Uses the 2 random variables x1 and x2 to generate a random point on a sphere. /// public static V3d Spherical(double x1, double x2) { var phi = Constant.PiTimesTwo * x1; var z = 1 - 2 * x2; var r = Fun.Max(1 - z * z, 0).Sqrt(); return new V3d(r * phi.Cos(), r * phi.Sin(), z); } /// /// Uses the 2 random variables x1 and x2 to generate a random point on a sphere. /// public static V3f Spherical(float x1, float x2) { var phi = ConstantF.PiTimesTwo * x1; var z = 1 - 2 * x2; var r = Fun.Max(1 - z * z, 0).Sqrt(); return new V3f(r * phi.Cos(), r * phi.Sin(), z); } /// /// Generate a cosine weighted random sample oriented in the supplied normal direction /// using two random series (seriesIndex, seriesIndex+1). /// The normal is expected to be normalized. /// public static V3d Lambertian(V3d normal, IRandomSeries rnds, int seriesIndex) { return Lambertian(normal, rnds.UniformDouble(seriesIndex), rnds.UniformDouble(seriesIndex + 1)); } /// /// Generate a cosine weighted random sample oriented in the supplied normal direction /// using two random series (seriesIndex, seriesIndex+1). /// The normal is expected to be normalized. /// public static V3f Lambertian(V3f normal, IRandomSeries rnds, int seriesIndex) { return Lambertian(normal, (float)rnds.UniformDouble(seriesIndex), (float)rnds.UniformDouble(seriesIndex + 1)); } /// /// Generate a cosine weighted random sample oriented in the supplied normal direction /// using the 2 random variables x1 and x2. /// The normal is expected to be normalized. /// public static V3d Lambertian(V3d normal, double x1, double x2) { // random point on cylinder barrel var phi = Constant.PiTimesTwo * x1; var z = 1 - 2 * x2; // project to sphere var r = Fun.Max(1 - z * z, 0).Sqrt(); var vec = new V3d(r * phi.Cos(), r * phi.Sin(), z) + normal; var squareLen = vec.LengthSquared; // check if random sphere point was perfectly opposite of the normal direction (in case x2 ~= 1) if (squareLen < 1e-9) return normal; var norm = 1 / squareLen.Sqrt(); return vec * norm; } /// /// Generate a cosine weighted random sample oriented in the supplied normal direction /// using the 2 random variables x1 and x2. /// The normal is expected to be normalized. /// public static V3f Lambertian(V3f normal, float x1, float x2) { // random point on cylinder barrel var phi = ConstantF.PiTimesTwo * x1; var z = 1 - 2 * x2; // project to sphere var r = Fun.Max(1 - z * z, 0).Sqrt(); var vec = new V3f(r * phi.Cos(), r * phi.Sin(), z) + normal; var squareLen = vec.LengthSquared; // check if random sphere point was perfectly opposite of the normal direction (in case x2 ~= 1) if (squareLen < 1e-9f) return normal; var norm = 1 / squareLen.Sqrt(); return vec * norm; } /// /// Generates a cosine weighted random direction using the 2 random series (seriesIndex, seriesIndex+1). /// See Global Illuminatin Compendium, Dutre 2003, (35) /// PDF = cos(theta)/PI /// public static V3d Lambertian(IRandomSeries rnds, int seriesIndex) { return Lambertian( rnds.UniformDouble(seriesIndex), rnds.UniformDouble(seriesIndex + 1)); } /// /// Generates a cosine weighted random direction using the 2 random varables x1 and x2. /// See Global Illuminatin Compendium, Dutr 2003, (35) /// PDF = cos(theta)/PI /// public static V3d Lambertian(double x1, double x2) { // random point on disk var r = Fun.Sqrt(x1); var phi = Constant.PiTimesTwo * x2; var x = r * Fun.Cos(phi); var y = r * Fun.Sin(phi); // project to hemisphere var z = Fun.Sqrt(1 - x1); // x1 = r^2 return new V3d(x, y, z); } /// /// Generates a cosine weighted random direction using the 2 random varables x1 and x2. /// See Global Illuminatin Compendium, Dutr 2003, (35) /// PDF = cos(theta)/PI /// public static V3f Lambertian(float x1, float x2) { // random point on disk var r = Fun.Sqrt(x1); var phi = ConstantF.PiTimesTwo * x2; var x = r * Fun.Cos(phi); var y = r * Fun.Sin(phi); // project to hemisphere var z = Fun.Sqrt(1 - x1); // x1 = r^2 return new V3f(x, y, z); } /// /// Generates a uniform distributed 2d random sample on a disk with radius 1. /// It uses two random series (seriesIndex, seriesIndex+1). /// public static V2d Disk(IRandomSeries rnd, int seriesIndex) { return Disk(rnd.UniformDouble(seriesIndex), rnd.UniformDouble(seriesIndex + 1)); } /// /// Generates a uniform distributed 2d random sample on a disk with radius 1 /// using the 2 random variables x1 and x2. /// public static V2d Disk(double x1, double x2) { // random direction var phi = x1 * Constant.PiTimesTwo; // random radius transformed by sqrt to result in area equivalent samples distribution var r = x2.Sqrt(); return new V2d(r * Fun.Cos(phi), r * Fun.Sin(phi)); } /// /// Generates a uniform distributed 2d random sample on a disk with radius 1 /// using the 2 random variables x1 and x2. /// public static V2f Disk(float x1, float x2) { // random direction var phi = x1 * ConstantF.PiTimesTwo; // random radius transformed by sqrt to result in area equivalent samples distribution var r = x2.Sqrt(); return new V2f(r * Fun.Cos(phi), r * Fun.Sin(phi)); } /// /// Generates a uniform distributed random sample on the given triangle using /// two random series (seriesIndex, seriesIndex + 1). /// public static V2d Triangle(Triangle2d t, IRandomSeries rnd, int seriesIndex) { return Triangle(t.P0, t.P1, t.P2, rnd.UniformDouble(seriesIndex), rnd.UniformDouble(seriesIndex + 1)); } /// /// Generates a uniform distributed random sample on the given triangle using /// two random series (seriesIndex, seriesIndex + 1). /// public static V2f Triangle(Triangle2f t, IRandomSeries rnd, int seriesIndex) { return Triangle(t.P0, t.P1, t.P2, (float)rnd.UniformDouble(seriesIndex), (float)rnd.UniformDouble(seriesIndex + 1)); } /// /// Generates a uniform distributed random sample on the given triangle using /// two random variables x1 and x2. /// public static V2d Triangle(Triangle2d t, double x1, double x2) { return Triangle(t.P0, t.P1, t.P2, x1, x2); } /// /// Generates a uniform distributed random sample on the given triangle using /// two random variables x1 and x2. /// public static V2f Triangle(Triangle2f t, float x1, float x2) { return Triangle(t.P0, t.P1, t.P2, x1, x2); } /// /// Generates a uniform distributed random sample on the given triangle using /// two random series (seriesIndex, seriesIndex + 1). /// public static V2d Triangle(V2d p0, V2d p1, V2d p2, IRandomSeries rnd, int seriesIndex) { return Triangle(p0, p1, p2, rnd.UniformDouble(seriesIndex), rnd.UniformDouble(seriesIndex + 1)); } /// /// Generates a uniform distributed random sample on the given triangle using /// two random series (seriesIndex, seriesIndex + 1). /// public static V2f Triangle(V2f p0, V2f p1, V2f p2, IRandomSeries rnd, int seriesIndex) { return Triangle(p0, p1, p2, (float)rnd.UniformDouble(seriesIndex), (float)rnd.UniformDouble(seriesIndex + 1)); } /// /// Generates a uniform distributed random sample on the given triangle using /// two random variables x1 and x2. /// public static V2d Triangle(V2d p0, V2d p1, V2d p2, double x1, double x2) { var x1sq = x1.Sqrt(); return (1 - x1sq) * p0 + (x1sq * (1 - x2)) * p1 + (x1sq * x2) * p2; } /// /// Generates a uniform distributed random sample on the given triangle using /// two random variables x1 and x2. /// public static V2f Triangle(V2f p0, V2f p1, V2f p2, float x1, float x2) { var x1sq = x1.Sqrt(); return (1 - x1sq) * p0 + (x1sq * (1 - x2)) * p1 + (x1sq * x2) * p2; } /// /// Generates a uniform distributed random sample on the given triangle using /// two random series (seriesIndex, seriesIndex + 1). /// public static V3d Triangle(Triangle3d t, IRandomSeries rnd, int seriesIndex) { return Triangle(t.P0, t.P1, t.P2, rnd.UniformDouble(seriesIndex), rnd.UniformDouble(seriesIndex + 1)); } /// /// Generates a uniform distributed random sample on the given triangle using /// two random series (seriesIndex, seriesIndex + 1). /// public static V3f Triangle(Triangle3f t, IRandomSeries rnd, int seriesIndex) { return Triangle(t.P0, t.P1, t.P2, (float)rnd.UniformDouble(seriesIndex), (float)rnd.UniformDouble(seriesIndex + 1)); } /// /// Generates a uniform distributed random sample on the given triangle using /// two random variables x1 and x2. /// public static V3d Triangle(Triangle3d t, double x1, double x2) { return Triangle(t.P0, t.P1, t.P2, x1, x2); } /// /// Generates a uniform distributed random sample on the given triangle using /// two random variables x1 and x2. /// public static V3f Triangle(Triangle3f t, float x1, float x2) { return Triangle(t.P0, t.P1, t.P2, x1, x2); } /// /// Generates a uniform distributed random sample on the given triangle using /// two random series (seriesIndex, seriesIndex + 1). /// public static V3d Triangle(V3d p0, V3d p1, V3d p2, IRandomSeries rnd, int seriesIndex) { return Triangle(p0, p1, p2, rnd.UniformDouble(seriesIndex), rnd.UniformDouble(seriesIndex + 1)); } /// /// Generates a uniform distributed random sample on the given triangle using /// two random series (seriesIndex, seriesIndex + 1). /// public static V3f Triangle(V3f p0, V3f p1, V3f p2, IRandomSeries rnd, int seriesIndex) { return Triangle(p0, p1, p2, (float)rnd.UniformDouble(seriesIndex), (float)rnd.UniformDouble(seriesIndex + 1)); } /// /// Generates a uniform distributed random sample on the given triangle using /// two random variables x1 and x2. /// public static V3d Triangle(V3d p0, V3d p1, V3d p2, double x1, double x2) { var x1sq = x1.Sqrt(); return (1 - x1sq) * p0 + (x1sq * (1 - x2)) * p1 + (x1sq * x2) * p2; } /// /// Generates a uniform distributed random sample on the given triangle using /// two random variables x1 and x2. /// public static V3f Triangle(V3f p0, V3f p1, V3f p2, float x1, float x2) { var x1sq = x1.Sqrt(); return (1 - x1sq) * p0 + (x1sq * (1 - x2)) * p1 + (x1sq * x2) * p2; } } } ================================================ FILE: src/Aardvark.Base/Random/RandomSystem.cs ================================================ using System; using System.Threading; namespace Aardvark.Base { /// /// System Random Generator. /// public class RandomSystem : IRandomUniform { public Random Generator; #region Constructors /// /// Initialize using the time of day in milliseconds as seed. /// public RandomSystem() => Generator = new Random(); /// /// Initialize using custom seed. /// public RandomSystem(int seed) => Generator = new Random(seed); #endregion #region IRandomUniform Members public int RandomBits => 31; public bool GeneratesFullDoubles => false; public void ReSeed(int seed) => Generator = new Random(seed); private static readonly ThreadLocal s_buffer4 = new ThreadLocal(() => new byte[4]); public int UniformInt() { var array = s_buffer4.Value; Generator.NextBytes(array); return (int)(BitConverter.ToUInt32(array, 0) & 0x7fffffffu); } /// /// Returns a uniformly distributed uint in the interval [0, 2^63-1]. /// Constructed using 16 bits of each of two random integers. /// public uint UniformUInt() { var array = s_buffer4.Value; Generator.NextBytes(array); return BitConverter.ToUInt32(array, 0); } private static readonly ThreadLocal s_buffer8 = new ThreadLocal(() => new byte[8]); /// /// Returns a uniformly distributed long in the interval [0, 2^63-1]. /// public long UniformLong() { var array = s_buffer8.Value; Generator.NextBytes(array); return (long)(BitConverter.ToUInt64(array, 0) & 0x7ffffffffffffffful); } /// /// Returns a uniformly distributed long in the interval [0, 2^64-1]. /// public ulong UniformULong() { var array = s_buffer8.Value; Generator.NextBytes(array); return BitConverter.ToUInt64(array, 0); } public float UniformFloat() => (UniformInt() >> 7) * (float)(1.0 / 16777216.0); public float UniformFloatClosed() => (float)(UniformInt() / 2147483647.0); public float UniformFloatOpen() { int r; do { r = UniformInt() >> 7; } while (r == 0); return r * (float)(1.0 / 16777216.0); } public double UniformDouble() => Generator.NextDouble(); public double UniformDoubleClosed() => UniformInt() / 2147483647.0; public double UniformDoubleOpen() { int r; do { r = UniformInt(); } while (r == 0); return r * (1.0 / 2147483648.0); } #endregion } } ================================================ FILE: src/Aardvark.Base/Reporting/FilterLogTarget.cs ================================================ using System; namespace Aardvark.Base { /// /// A filtering log target that only records messages for which the /// filter function supplied in the constructor returns true. /// public class FilterLogTarget : ILogTarget { private readonly ILogTarget m_target; private readonly Func m_filterFun; public FilterLogTarget(ILogTarget target, Func filterFun) { m_target = target; m_filterFun = filterFun; } public void NewThreadIndex(int threadIndex) { m_target.NewThreadIndex(threadIndex); } public void Log(int threadIndex, LogMsg msg) { if (m_filterFun(msg)) m_target.Log(threadIndex, msg); } public void Dispose() { m_target.Dispose(); } } } ================================================ FILE: src/Aardvark.Base/Reporting/IJobReporter.cs ================================================ namespace Aardvark.Base { public interface IJobReporter { /// /// The number of spaces of indent caused by Begin / Report.End. /// This property should only be set BEFORE actual reporting. /// int Indent { get; set; } void Line(LogType type, int level, ILogTarget target, string leftText, int rightPos = 0, string rightText = null); // the following methods are regarded as LogType.Info void Text(int level, ILogTarget target, string text); void Wrap(int level, ILogTarget target, string text); ReportJob Begin(ReportJob parentJob, int level, ILogTarget target, string text, bool timed, bool noLog = false); double End(int level, ILogTarget target, string text, bool addTimeToParent); void Tests(TestInfo testInfo); void Progress(int level, ILogTarget target, double progress, bool relative = false); void Values(int level, ILogTarget target, string name, string separator, object[] values); // internal API for managing external reporters void AddReporter(IReporter reporter); void RemoveReporter(IReporter reporter); } } ================================================ FILE: src/Aardvark.Base/Reporting/ILogTarget.cs ================================================ using System; namespace Aardvark.Base { public interface ILogTarget : IDisposable { void NewThreadIndex(int threadIndex); void Log(int threadIndex, LogMsg msg); } } ================================================ FILE: src/Aardvark.Base/Reporting/IReportable.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Aardvark.Base { public interface IReportable { void ReportValue(int verbosity, string name); } } ================================================ FILE: src/Aardvark.Base/Reporting/IReporter.cs ================================================ namespace Aardvark.Base { /// /// The IReporter interface can be implemented for objects to catch /// reports on a level, where some info is passed with typed parameters /// (e.g. timing seconds as doubles, values as objects). /// As soon as a reporter object is added, all Report calls from the /// same thread are also delivered to that reporter object. Reporting /// on other threads, where the reporter object was not added, does not /// appear. If the same reporter object is added multiple times from /// different threads, all these methods need to do their own locking. /// If only one reporter object is added from one thread, no locking is /// necessary. The supplied threadIndex, is a running number for each /// thread assigned based on their first sending of a Report message. /// It can be directly used as a key in e.g. an IntDict. /// public interface IReporter { void Line(int threadIndex, LogType type, int level, ILogTarget target, string leftText, int rightPos = 0, string rightText = null); // the following methods are regarded as LogType.Info void Text(int threadIndex, int level, ILogTarget target, string text); void Wrap(int threadIndex, int level, ILogTarget target, string text); void Begin(int threadIndex, int level, ILogTarget target, string text, bool timed); void End(int threadIndex, int level, ILogTarget target, string text, double seconds); void Progress(int threadIndex, int level, ILogTarget target, string text, double progress, double seconds); void Values(int threadIndex, int level, ILogTarget target, string name, string separator, object[] values); } } ================================================ FILE: src/Aardvark.Base/Reporting/JobReporter.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; namespace Aardvark.Base { public class JobReporter : IJobReporter { private readonly int m_ti; public int m_indent; private ReportJob m_job; private readonly Stack m_jobStack; private volatile IReporter[] m_reporterArray; private readonly object m_reporterArrayLock; #region Constructor public JobReporter(int threadIndex = 0) { m_ti = threadIndex; m_indent = 2; m_job = new ReportJob("THREAD", 0, true); m_jobStack = new Stack(); m_reporterArray = null; m_reporterArrayLock = new object(); } #endregion #region Properties public int Indent { get { return m_indent; } set { m_indent = value; } } #endregion #region IJobReporter public void Line(LogType type, int level, ILogTarget target, string t0, int p1 = 0, string t1 = null) { target.Log(m_ti, new LogMsg(type, LogOpt.EndLine, level, m_job.HierarchyLevel * m_indent, t0, p1, t1)); var reporterArray = m_reporterArray; if (reporterArray != null) for (int i = 0; i < reporterArray.Length; i++) reporterArray[i].Line(m_ti, type, level, target, t0, p1, t1); } public void Wrap(int level, ILogTarget target, string text) { target.Log(m_ti, new LogMsg(LogType.Info, LogOpt.Join | LogOpt.Wrap, level, m_job.HierarchyLevel * m_indent, text, -2)); var reporterArray = m_reporterArray; if (reporterArray != null) for (int i = 0; i < reporterArray.Length; i++) reporterArray[i].Wrap(m_ti, level, target, text); } public void Text(int level, ILogTarget target, string text) { string[] lines = text.Split('\n'); var last = lines.Length - 1; if (last == 0) { target.Log(m_ti, new LogMsg(LogType.Info, LogOpt.Join, level, m_job.HierarchyLevel * m_indent, lines[0], -2)); } else { for (int i = 0; i < last; i++) target.Log(m_ti, new LogMsg(LogType.Info, LogOpt.Join | LogOpt.EndLine, level, m_job.HierarchyLevel * m_indent, lines[i])); if (lines[last].Length > 0) target.Log(m_ti, new LogMsg(LogType.Info, LogOpt.Join, level, m_job.HierarchyLevel * m_indent, lines[last])); } var reporterArray = m_reporterArray; if (reporterArray != null) for (int i = 0; i < reporterArray.Length; i++) reporterArray[i].Text(m_ti, level, target, text); } public ReportJob Begin(ReportJob parentJob, int level, ILogTarget target, string text, bool timed, bool noLog = false) { if (parentJob == null) parentJob = m_job; var reporterArray = m_reporterArray; if (reporterArray != null) for (int i = 0; i < reporterArray.Length; i++) reporterArray[i].Begin(m_ti, level, target, text, timed); var opt = timed ? LogOpt.Timed : LogOpt.None; if (!noLog) target.Log(m_ti, new LogMsg(LogType.Begin, opt, level, parentJob.HierarchyLevel * m_indent, text, -2)); m_jobStack.Push(m_job); m_job = new ReportJob(text, level, timed, parentJob); return m_job; } public void Tests(TestInfo testInfo) { m_job.TestInfo += testInfo; m_job.ReportTests = true; } public double End(int level, ILogTarget target, string text, bool addTimeToParent) { var parentJob = m_job.ParentJob; if (m_jobStack.Count == 0) { Report.Warn("superfluous Report.End() encountered"); if (text != null) // still report message if some target.Log(m_ti, new LogMsg(LogType.End, LogOpt.NewText, level, 0, text, -2, null)); return 0.0; } double seconds; string time; LogOpt opt; if (m_job.IsTimed) { seconds = m_job.ElapsedSeconds; opt = LogOpt.EndLine | LogOpt.Timed; time = String.Format(CultureInfo.InvariantCulture, "{0:F3} s", seconds); } else { seconds = 0.0; time = null; opt = LogOpt.EndLine; } m_job.Disposed = true; if (level != m_job.Level) { Report.Warn("Report.Begin({0}) level different from Report.End({1})," + " using Report.End({0})", m_job.Level, level); level = m_job.Level; } var beginText = m_job.Message; if (text == null) text = beginText; else if (text != beginText) { text = beginText + text; opt |= LogOpt.NewText; } if (m_job.ReportTests == true) { var testInfo = m_job.TestInfo; m_job = m_jobStack.Pop(); m_job.TestInfo += testInfo; var passed = String.Format(CultureInfo.InvariantCulture, "[{0}/{1} OK]", testInfo.PassedCount, testInfo.TestCount); time = time != null ? passed + ' ' + time : passed; target.Log(m_ti, new LogMsg(LogType.End, opt, level, parentJob.HierarchyLevel * m_indent, text, -2, time)); if (testInfo.FailedCount > 0) { var failed = String.Format(CultureInfo.InvariantCulture, " {0}/{1} FAILED", testInfo.FailedCount, testInfo.TestCount); target.Log(m_ti, new LogMsg(LogType.Warn, opt, level, parentJob.HierarchyLevel * m_indent, "WARNING: " + text + failed)); } } else { var childrenTime = m_job.ChildrenTime; if (seconds > 0.0 && childrenTime > 0.0) time = String.Format(CultureInfo.InvariantCulture, "[{0:F2}x] ", childrenTime / seconds) + time; if (addTimeToParent) { lock (parentJob) parentJob.ChildrenTime += seconds; } m_job = m_jobStack.Pop(); target.Log(m_ti, new LogMsg(LogType.End, opt, level, parentJob.HierarchyLevel * m_indent, text, -2, time)); } var reporterArray = m_reporterArray; if (reporterArray != null) for (int i = 1; i < reporterArray.Length; i++) reporterArray[i].End(m_ti, level, target, text, seconds); return seconds; } public void Progress(int level, ILogTarget target, double progress, bool relative = false) { if (relative) progress += m_job.Progress; if (progress > 1.0) progress = 1.0; m_job.Progress = progress; double seconds; string text; LogOpt opt; if (!m_job.IsTimed) { seconds = -1.0; opt = LogOpt.None; text = String.Format(CultureInfo.InvariantCulture, "{0,6:F2}%", 100.0 * progress); } else { seconds = m_job.ElapsedSeconds; opt = LogOpt.Timed; text = String.Format(CultureInfo.InvariantCulture, "{0,6:F2}% {1,10:F3} s", 100.0 * progress, seconds); } target.Log(m_ti, new LogMsg(LogType.Progress, opt, level, (m_job.HierarchyLevel - 1) * m_indent, m_job.Message, -2, text)); var reporterArray = m_reporterArray; if (reporterArray != null) for (int i = 0; i < reporterArray.Length; i++) reporterArray[i].Progress(m_ti, level, target, m_job.Message, progress, seconds); } public void Values(int level, ILogTarget target, string name, string separator, object[] values) { var text = values.Length == 1 ? values[0].ToString() : values.Map(o => o.ToString()).Join(separator); target.Log(m_ti, new LogMsg(LogType.Info, LogOpt.EndLine, level, m_job.HierarchyLevel * m_indent, name, 40, text)); var reporterArray = m_reporterArray; if (reporterArray != null) for (int i = 0; i < reporterArray.Length; i++) reporterArray[i].Values(m_ti, level, target, name, separator, values); } #endregion #region Adding and Removing IReporters public void AddReporter(IReporter reporter) { lock (m_reporterArrayLock) { m_reporterArray = m_reporterArray.WithAppended(reporter); } } public void RemoveReporter(IReporter reporter) { lock (m_reporterArrayLock) { m_reporterArray = m_reporterArray.WithRemoved(reporter); } } #endregion } } ================================================ FILE: src/Aardvark.Base/Reporting/LogMsg.cs ================================================ using System; namespace Aardvark.Base { [Flags] public enum LogType { Unknown = 0, Info = 1, Begin = 2, End = 3, Progress = 4, Warn = 5, Trace = 6, Debug = 7, Error = 8, Fatal = 9, } [Flags] public enum LogOpt { None = 0x00, EndLine = 0x01, Timed = 0x02, Join = 0x04, Wrap = 0x08, NewText = 0x10, // new text on Report.End }; public struct LogMsg { public LogType Type; public LogOpt Opt; public int Level; public int LeftPos; public string LeftText; public int RightPos; public string RightText; public LogMsg(LogType type, LogOpt opt, int level, int leftPos, string leftText, int rightPos = 0, string rightText = null) { Type = type; Opt = opt; Level = level; LeftPos = leftPos; LeftText = leftText; RightPos = rightPos; RightText = rightText; } } } ================================================ FILE: src/Aardvark.Base/Reporting/MultiLogTarget.cs ================================================ namespace Aardvark.Base { public class MultiLogTarget : ILogTarget { private volatile ILogTarget[] m_targetArray; private readonly object m_targetArrayLock; #region Constructor public MultiLogTarget(params ILogTarget[] targetArray) { m_targetArray = targetArray; m_targetArrayLock = new object(); } #endregion #region ILogTarget public void NewThreadIndex(int threadIndex) { var targetArray = m_targetArray; for (int i = 0; i < targetArray.Length; i++) targetArray[i].NewThreadIndex(threadIndex); } public void Log(int threadIndex, LogMsg msg) { var targetArray = m_targetArray; for (int i = 0; i < targetArray.Length; i++) targetArray[i].Log(threadIndex, msg); } public void Dispose() { var targetArray = m_targetArray; for (int i = 0; i < targetArray.Length; i++) targetArray[i].Dispose(); } #endregion #region Adding and Removing Targets public void Add(ILogTarget target) { lock (m_targetArrayLock) { m_targetArray = m_targetArray.WithAppended(target); } } public void Remove(ILogTarget target) { lock (m_targetArrayLock) { m_targetArray = m_targetArray.WithRemoved(target); } } #endregion } } ================================================ FILE: src/Aardvark.Base/Reporting/NullReporter.cs ================================================ namespace Aardvark.Base { public class NullReporter : IJobReporter { public int Indent { get { return 0; } set { } } public void AddReporter(IReporter reporter) { } public ReportJob Begin(ReportJob parentJob, int level, ILogTarget target, string text, bool timed, bool noLog = false) { return null; } public double End(int level, ILogTarget target, string text, bool addTimeToParent) { return 0.0; } public void Line(LogType type, int level, ILogTarget target, string leftText, int rightPos = 0, string rightText = null) { } public void Progress(int level, ILogTarget target, double progress, bool relative = false) { } public void RemoveReporter(IReporter reporter) { } public void Tests(TestInfo testInfo) { } public void Text(int level, ILogTarget target, string text) { } public void Values(int level, ILogTarget target, string name, string separator, object[] values) { } public void Wrap(int level, ILogTarget target, string text) { } } } ================================================ FILE: src/Aardvark.Base/Reporting/PerThreadJobReporter.cs ================================================ using System.Collections.Generic; using System.Threading; namespace Aardvark.Base { public class PerThreadJobReporter : IJobReporter { private SpinLock m_lock; private readonly Dictionary m_reporterMap; private volatile int m_threadCount; private int m_indent; #region Constructor public PerThreadJobReporter() { m_reporterMap = new Dictionary(); m_threadCount = 0; m_indent = 2; } #endregion #region Thread Handling private IJobReporter CurrentReporter(ILogTarget target = null) { IJobReporter reporter; var threadId = Thread.CurrentThread.ManagedThreadId; bool lockTaken = false; try { m_lock.Enter(ref lockTaken); if (!m_reporterMap.TryGetValue(threadId, out reporter)) { var threadIndex = m_threadCount++; reporter = new JobReporter(threadIndex) { Indent = m_indent }; m_reporterMap[threadId] = reporter; if (target != null) target.NewThreadIndex(threadIndex); } } finally { if (lockTaken) m_lock.Exit(true); } return reporter; } #endregion #region IJobReporter public int Indent { get { return m_indent; } set { m_indent = value; } } public void Line(LogType type, int level, ILogTarget target, string text0, int pos1 = 0, string text1 = null) { CurrentReporter(target).Line(type, level, target, text0, pos1, text1); } public void Text(int level, ILogTarget target, string text) { CurrentReporter(target).Text(level, target, text); } public void Wrap(int level, ILogTarget target, string text) { CurrentReporter(target).Wrap(level, target, text); } public ReportJob Begin(ReportJob parentJob, int level, ILogTarget target, string text, bool timed, bool noLog = false) { return CurrentReporter(target).Begin(parentJob, level, target, text, timed, noLog); } public double End(int level, ILogTarget target, string text, bool addTimeToParent) { return CurrentReporter(target).End(level, target, text, addTimeToParent); } public void Tests(TestInfo testInfo) { CurrentReporter().Tests(testInfo); } public void Progress(int level, ILogTarget target, double progress, bool relative = false) { CurrentReporter(target).Progress(level, target, progress, relative); } public void Values(int level, ILogTarget target, string name, string separator, object[] values) { CurrentReporter(target).Values(level, target, name, separator, values); } public void AddReporter(IReporter reporter) { CurrentReporter().AddReporter(reporter); } public void RemoveReporter(IReporter reporter) { CurrentReporter().RemoveReporter(reporter); } #endregion } } ================================================ FILE: src/Aardvark.Base/Reporting/PerThreadLogTarget.cs ================================================ using System; namespace Aardvark.Base { public class PerThreadLogTarget : ILogTarget { private volatile ILogTarget[] m_targetArray; readonly Func m_targetCreator; #region Constructor public PerThreadLogTarget(Func targetCreator) { m_targetArray = null; m_targetCreator = targetCreator; } #endregion #region ILogTarget public void NewThreadIndex(int threadIndex) { m_targetArray = m_targetArray.With(threadIndex, m_targetCreator(threadIndex)); } public void Log(int threadIndex, LogMsg msg) { m_targetArray[threadIndex].Log(threadIndex, msg); } public void Dispose() { for (int i = 0; i < m_targetArray.Length; i++) if (m_targetArray != null) m_targetArray[i].Dispose(); } #endregion } } ================================================ FILE: src/Aardvark.Base/Reporting/Report.cs ================================================ using System; using System.ComponentModel; using System.Globalization; using System.IO; #if __ANDROID__ using Log = Android.Util.Log; #endif namespace Aardvark.Base { /// /// This class makes it possible to report messages with different /// verbosity levels to the console or a stream. /// /// In the simplest case, you can start by reporting single line messages /// with a level Report.Line. The level gives an /// indication of how important this message is: a value of 0 indicates /// that this is a message of utmost importance that cannot be suppressed. /// The higher the level, the lower the importance of the message. In the /// default case only messages of level 0, 1 and 2 are actually reported. /// /// The following use of levels is suggested: /// /// 0 ... unsupressable message of utmost importance (e.g warning), /// 1 ... very short output, /// 2 ... short output (this is the default level), /// 3 ... normal output, /// 4 ... detailed output, /// 5-9 ... debugging levels /// /// The static Report class wraps all methods to a concrete reporter that /// performs the actual reporting. The default reporting setup consists /// of a console reporter at verbosity level 2, and a file reporter at /// reporting level 9 that writes it contents to the file /// "Aardvark.log". Each thread gets its own reporters, which report to /// the logs in a synchronized manner. In order to globally change the /// console report level, you can just conveniently use the static /// Verbosity property. /// public static class Report { #region /// /// Breaks and throws an exception on error if a debugger is attached. /// public static bool ThrowOnError = false; #endregion #region Telemetry public static Telemetry.Counter CountCallsToBeginTimed = new Telemetry.Counter(); public static Telemetry.Counter CountCallsToBegin = new Telemetry.Counter(); public static Telemetry.Counter CountCallsToEnd = new Telemetry.Counter(); public static Telemetry.Counter CountCallsToLine = new Telemetry.Counter(); public static Telemetry.Counter CountCallsToText = new Telemetry.Counter(); public static Telemetry.Counter CountCallsToWarn = new Telemetry.Counter(); public static Telemetry.Counter CountCallsToDebug = new Telemetry.Counter(); public static Telemetry.Counter CountCallsToTrace = new Telemetry.Counter(); public static Telemetry.Counter CountCallsToError = new Telemetry.Counter(); public static Telemetry.Counter CountCallsToFatal = new Telemetry.Counter(); public static Telemetry.Counter CountCallsToValues = new Telemetry.Counter(); public static Telemetry.Counter CountCallsToProgress = new Telemetry.Counter(); static Report() { Telemetry.Register("Report: BeginTimed", CountCallsToBeginTimed); Telemetry.Register("Report: BeginTimed/s", CountCallsToBeginTimed.RatePerSecond()); Telemetry.Register("Report: Begin", CountCallsToBegin); Telemetry.Register("Report: Begin/s", CountCallsToBegin.RatePerSecond()); Telemetry.Register("Report: End", CountCallsToEnd); Telemetry.Register("Report: End/s", CountCallsToEnd.RatePerSecond()); Telemetry.Register("Report: Line", CountCallsToLine); Telemetry.Register("Report: Line/s", CountCallsToLine.RatePerSecond()); Telemetry.Register("Report: Text", CountCallsToText); Telemetry.Register("Report: Text/s", CountCallsToText.RatePerSecond()); Telemetry.Register("Report: Warn", CountCallsToWarn); Telemetry.Register("Report: Warn/s", CountCallsToWarn.RatePerSecond()); Telemetry.Register("Report: Debug", CountCallsToDebug); Telemetry.Register("Report: Debug/s", CountCallsToDebug.RatePerSecond()); Telemetry.Register("Report: Trace", CountCallsToTrace); Telemetry.Register("Report: Trace/s", CountCallsToTrace.RatePerSecond()); Telemetry.Register("Report: Error", CountCallsToError); Telemetry.Register("Report: Error/s", CountCallsToError.RatePerSecond()); Telemetry.Register("Report: Fatal", CountCallsToFatal); Telemetry.Register("Report: Fatal/s", CountCallsToFatal.RatePerSecond()); Telemetry.Register("Report: Values", CountCallsToValues); Telemetry.Register("Report: Values/s", CountCallsToValues.RatePerSecond()); Telemetry.Register("Report: Progress", CountCallsToProgress); Telemetry.Register("Report: Progress/s", CountCallsToProgress.RatePerSecond()); try { s_defaultForeground = Console.ForegroundColor; s_defaultBackground = Console.BackgroundColor; s_coloredConsole = true; } catch { s_coloredConsole = false; s_defaultForeground = ConsoleColor.White; s_defaultBackground = ConsoleColor.Black; } } #endregion #region Static Report Targets public static readonly PerThreadJobReporter ThreadedJobReporter = new PerThreadJobReporter { Indent = 2 }; public static readonly JobReporter JobReporter = new JobReporter { Indent = 2 }; /// /// By assigning this property multi-threaded reporting can be turned on or off. /// This is mainly a feature for cosmetic and performance reasons of single- /// threaded applciations. /// public static bool MultiThreaded { get { return s_reporter is PerThreadJobReporter; } set { s_reporter = value ? (IJobReporter)ThreadedJobReporter : (IJobReporter)JobReporter; } } private static IJobReporter s_reporter = ThreadedJobReporter; public static void ConsoleWriteAct(int threadIndex, LogType type, int level, string message) { Console.Write(message); Console.Out.Flush(); } private static readonly bool s_coloredConsole; private static readonly ConsoleColor s_defaultForeground; private static readonly ConsoleColor s_defaultBackground; #if !__ANDROID__ public static void ConsoleColoredWriteAct(int threadIndex, LogType type, int level, string message) { if(!s_coloredConsole) { ConsoleWriteAct(threadIndex, type, level, message); return; } bool resetBackground = false; switch (type) { case LogType.Fatal: { Console.ForegroundColor = ConsoleColor.Black; Console.BackgroundColor = ConsoleColor.Red; resetBackground = true; break; } case LogType.Error: Console.ForegroundColor = ConsoleColor.Red; break; case LogType.Warn: Console.ForegroundColor = ConsoleColor.Yellow; break; case LogType.Info: switch (level) { case 0: Console.ForegroundColor = s_defaultForeground; break; case 1: Console.ForegroundColor = ConsoleColor.Gray; break; case 2: Console.ForegroundColor = ConsoleColor.DarkGray; break; default: Console.ForegroundColor = ConsoleColor.DarkGreen; break; } break; default: Console.ForegroundColor = s_defaultForeground; break; } Console.Write(message); Console.ForegroundColor = s_defaultForeground; if (resetBackground) Console.BackgroundColor = s_defaultBackground; Console.Out.Flush(); } public static void ConsoleForegroundColoredWriteAct( int threadIndex, LogType type, int level, string message) { if (!s_coloredConsole) { ConsoleWriteAct(threadIndex, type, level, message); return; } switch (type) { case LogType.Fatal: Console.ForegroundColor = ConsoleColor.Red; break; case LogType.Error: Console.ForegroundColor = ConsoleColor.Red; break; case LogType.Warn: Console.ForegroundColor = ConsoleColor.Yellow; break; case LogType.Info: switch (level) { case 0: Console.ForegroundColor = s_defaultForeground; break; case 1: Console.ForegroundColor = ConsoleColor.Gray; break; case 2: Console.ForegroundColor = ConsoleColor.DarkGray; break; default: Console.ForegroundColor = ConsoleColor.DarkGreen; break; } break; default: Console.ForegroundColor = s_defaultForeground; break; } Console.Write(message); Console.ForegroundColor = s_defaultForeground; Console.Out.Flush(); } #else public static void ConsoleColoredWriteAct(int threadIndex, LogType type, int level, string message) { Log.Verbose ("Aardvark", "{0}", message); } public static void ConsoleForegroundColoredWriteAct(int threadIndex, LogType type, int level, string message) { Log.Verbose ("Aardvark", "{0}", message); } #endif // Note that TextLogTarget needs to be created with a writer function that // gets the (type, level, message) triple as parameter. The writer functions // flush their output in order to provide output even if incomplete lines are // sent. public static readonly TextLogTarget ConsoleTarget = new TextLogTarget(ConsoleColoredWriteAct) { Width = 80, Verbosity = 2, AllowBackspace = true, }; public static readonly TextLogTarget TraceTarget = new TextLogTarget((i, t, l, m) => { System.Diagnostics.Debug.Write(m); System.Diagnostics.Debug.Flush(); }) { Width = 100, Verbosity = 15, /* LogCompleteLinesOnly = true, */ }; /// /// The LogFileName may be modified before the first log message is written. /// public static string LogFileName = @"Aardvark.log"; /// /// Creates a stream writer writing to LogFileName but retries, if file is /// already open by another instance. /// private static StreamWriter CreateLogFileWriter(string fileName, int cnt) { if (cnt > 5) throw new Exception("Could not create writer (many instances running?)"); try { var dir = Path.GetDirectoryName(fileName); if (!dir.IsNullOrEmpty() && !Directory.Exists(dir)) { Directory.CreateDirectory(dir); } var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Read); return new StreamWriter(stream); } catch (IOException) { return CreateLogFileWriter(string.Format("{0}_{1}", fileName, cnt), cnt + 1); } catch (UnauthorizedAccessException) { var dir = Path.Combine(Path.GetTempPath(), "Aardvark", "logs"); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); var now = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss-fffffff"); var name = Path.Combine(dir, now); return CreateLogFileWriter(name, cnt + 1); } } /// /// The LogTarget opens the log file on the first logging write, so that it can /// be deactivated before first use by calling Report.Targets.Remove(Report.LogTarget) /// without leaving an empty log file /// public readonly static TextLogTarget LogTarget = new TextLogTarget((firstThreadIndex, firstType, firstLevel, firstMessage) => { StreamWriter writer = CreateLogFileWriter(LogFileName, 0); LogTarget.WriteAct = (i, t, l, m) => { try { writer.Write(m); writer.Flush(); } catch (ObjectDisposedException) // in finalization, finalizers which perform logging fail due to non deterministic finalization order { } }; LogTarget.WriteAct(firstThreadIndex, firstType, firstLevel, firstMessage); }) { Width = 100, Verbosity = 9 }; public static string PerThreadLogName = @"Aardvark_{0}.log"; public readonly static PerThreadLogTarget PerThreadLogTarget = new PerThreadLogTarget(CreatePerThreadLogTarget); private static TextLogTarget CreatePerThreadLogTarget(int index) { TextLogTarget logTarget = new TextLogTarget(null, index) { Width = 100, Verbosity = 9, Synchronized = false }; logTarget.WriteAct = (firstThreadIndex, firstType, firstLevel, firstMessage) => { var writer = new StreamWriter( new FileStream(String.Format(PerThreadLogName, firstThreadIndex), FileMode.Create, FileAccess.Write, FileShare.Read)); logTarget.WriteAct = (i, t, l, m) => { writer.Write(m); writer.Flush(); }; logTarget.WriteAct(firstThreadIndex, firstType, firstLevel, firstMessage); }; return logTarget; } /// /// You can add and remove log targets by adding or removing them from Targets. /// public readonly static MultiLogTarget Targets = new MultiLogTarget(ConsoleTarget, LogTarget); public static readonly ILogTarget NoTarget = new MultiLogTarget(); /// /// If you only want a single log target, you can assign it to the RootTarget. /// public static ILogTarget RootTarget = Targets; #endregion #region Static Reporting Methods /// /// A shortcut for the verbosity of the ConsoleTarget. /// public static int Verbosity { get { return ConsoleTarget.Verbosity; } set { ConsoleTarget.Verbosity = value; } } private static string Format(string message, params object[] args) { if (args.Length == 0) return message; try { return String.Format(CultureInfo.InvariantCulture, message, args); } catch (FormatException) { Report.Warn("Report FormatException in \"{0}\"", message); return message; } } /// /// Begin a timed block with a formatted message that will only be logged at the end of the job. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// At the of the block the run time is reported. /// public static ReportJob JobTimedNoBeginLog(ReportJob parentJob, int level, [Localizable(true)] string message, params object[] args) { CountCallsToBeginTimed.Increment(); return s_reporter.Begin(parentJob, level, RootTarget, Format(message, args), true, true); } /// /// Begin a timed block with a formatted message that will only be logged at the end of the job. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// At the of the block the run time is reported. /// public static ReportJob JobTimedNoBeginLog(ReportJob parentJob, [Localizable(true)] string message, params object[] args) { CountCallsToBeginTimed.Increment(); return s_reporter.Begin(parentJob, 0, RootTarget, Format(message, args), true, true); } /// /// Begin a timed block with a formatted message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// At the of the block the run time is reported. /// public static ReportJob JobTimed(ReportJob parentJob, int level, [Localizable(true)] string message, params object[] args) { CountCallsToBeginTimed.Increment(); return s_reporter.Begin(parentJob, level, RootTarget, Format(message, args), true); } /// /// Begin a timed block with a formatted message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// At the of the block the run time is reported. /// public static ReportJob JobTimed(ReportJob parentJob, [Localizable(true)] string message, params object[] args) { CountCallsToBeginTimed.Increment(); return s_reporter.Begin(parentJob, 0, RootTarget, Format(message, args), true); } /// /// Begin a block with a formatted message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// public static ReportJob Job(ReportJob parentJob, int level, [Localizable(true)] string message, params object[] args) { CountCallsToBegin.Increment(); return s_reporter.Begin(parentJob, level, RootTarget, Format(message, args), false); } /// /// Begin a block with a formatted message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// public static ReportJob Job(ReportJob parentJob, [Localizable(true)] string message, params object[] args) { CountCallsToBegin.Increment(); return s_reporter.Begin(parentJob, 0, RootTarget, Format(message, args), false); } /// /// Begin a timed block with a formatted message that will only be logged at the end of the job. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// At the of the block the run time is reported. /// public static ReportJob JobTimedNoBeginLog(int level, [Localizable(true)] string message, params object[] args) { CountCallsToBeginTimed.Increment(); return s_reporter.Begin(null, level, RootTarget, Format(message, args), true, true); } /// /// Begin a timed block with a formatted message that will only be logged at the end of the job. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// At the of the block the run time is reported. /// public static ReportJob JobTimedNoBeginLog([Localizable(true)] string message, params object[] args) { CountCallsToBeginTimed.Increment(); return s_reporter.Begin(null, 0, RootTarget, Format(message, args), true, true); } /// /// Begin a timed block with a formatted message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// At the of the block the run time is reported. /// public static ReportJob JobTimed(int level, [Localizable(true)] string message, params object[] args) { CountCallsToBeginTimed.Increment(); return s_reporter.Begin(null, level, RootTarget, Format(message, args), true); } /// /// Begin a timed block with a formatted message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// At the of the block the run time is reported. /// public static ReportJob JobTimed([Localizable(true)] string message, params object[] args) { CountCallsToBeginTimed.Increment(); return s_reporter.Begin(null, 0, RootTarget, Format(message, args), true); } /// /// Begin a block with a formatted message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// public static ReportJob Job(int level, [Localizable(true)] string message, params object[] args) { CountCallsToBegin.Increment(); return s_reporter.Begin(null, level, RootTarget, Format(message, args), false); } /// /// Begin a block with a formatted message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// public static ReportJob Job([Localizable(true)] string message, params object[] args) { CountCallsToBegin.Increment(); return s_reporter.Begin(null, 0, RootTarget, Format(message, args), false); } /// /// Begin a timed block with a formatted message that will only be logged at the end of the job. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// At the of the block the run time is reported. /// public static void BeginTimedNoLog(ReportJob parentJob, int level, [Localizable(true)] string message, params object[] args) { CountCallsToBeginTimed.Increment(); s_reporter.Begin(parentJob, level, RootTarget, Format(message, args), true, true); } /// /// Begin a timed block with a formatted message that will only be logged at the end of the job. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// At the of the block the run time is reported. /// public static void BeginTimedNoLog(ReportJob parentJob, [Localizable(true)] string message, params object[] args) { CountCallsToBeginTimed.Increment(); s_reporter.Begin(parentJob, 0, RootTarget, Format(message, args), true, true); } /// /// Begin a timed block with a formatted message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// At the of the block the run time is reported. /// public static void BeginTimed(ReportJob parentJob, int level, [Localizable(true)] string message, params object[] args) { CountCallsToBeginTimed.Increment(); s_reporter.Begin(parentJob, level, RootTarget, Format(message, args), true); } /// /// Begin a timed block with a formatted message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// At the of the block the run time is reported. /// public static void BeginTimed(ReportJob parentJob, [Localizable(true)] string message, params object[] args) { CountCallsToBeginTimed.Increment(); s_reporter.Begin(parentJob, 0, RootTarget, Format(message, args), true); } /// /// Begin a block with a formatted message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// public static void Begin(ReportJob parentJob, int level, [Localizable(true)] string message, params object[] args) { CountCallsToBegin.Increment(); s_reporter.Begin(parentJob, level, RootTarget, Format(message, args), false); } /// /// Begin a block with a formatted message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// public static void Begin(ReportJob parentJob, [Localizable(true)] string message, params object[] args) { CountCallsToBegin.Increment(); s_reporter.Begin(parentJob, 0, RootTarget, Format(message, args), false); } /// /// Begin a block without an explicit message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// public static void Begin(ReportJob parentJob, int level) { CountCallsToBegin.Increment(); s_reporter.Begin(parentJob, level, RootTarget, "", false); } /// /// Begin a block without an explicit message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// public static void Begin(ReportJob parentJob) { CountCallsToBegin.Increment(); s_reporter.Begin(parentJob, 0, RootTarget, "", false); } /// /// Begin a timed block with a formatted message that will only be logged at the end of the job. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// At the of the block the run time is reported. /// public static void BeginTimedNoLog(int level, [Localizable(true)] string message, params object[] args) { CountCallsToBeginTimed.Increment(); s_reporter.Begin(null, level, RootTarget, Format(message, args), true, true); } /// /// Begin a timed block with a formatted message that will only be logged at the end of the job. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// At the of the block the run time is reported. /// public static void BeginTimedNoLog([Localizable(true)] string message, params object[] args) { CountCallsToBeginTimed.Increment(); s_reporter.Begin(null, 0, RootTarget, Format(message, args), true, true); } /// /// Begin a timed block with a formatted message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// At the of the block the run time is reported. /// public static void BeginTimed(int level, [Localizable(true)] string message, params object[] args) { CountCallsToBeginTimed.Increment(); s_reporter.Begin(null, level, RootTarget, Format(message, args), true); } /// /// Begin a timed block with a formatted message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// At the of the block the run time is reported. /// public static void BeginTimed([Localizable(true)] string message, params object[] args) { CountCallsToBeginTimed.Increment(); s_reporter.Begin(null, 0, RootTarget, Format(message, args), true); } /// /// Begin a block with a formatted message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// public static void Begin(int level, [Localizable(true)] string message, params object[] args) { CountCallsToBegin.Increment(); s_reporter.Begin(null, level, RootTarget, Format(message, args), false); } /// /// Begin a block with a formatted message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// public static void Begin([Localizable(true)] string message, params object[] args) { CountCallsToBegin.Increment(); s_reporter.Begin(null, 0, RootTarget, Format(message, args), false); } /// /// Begin a block without an explicit message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// public static void Begin(int level) { CountCallsToBegin.Increment(); s_reporter.Begin(null, level, RootTarget, "", false); } /// /// Begin a block without an explicit message. /// All report calls till the call to the next /// are either indented (console/stream) or /// hierarchical children of this block (treeview). /// public static void Begin() { CountCallsToBegin.Increment(); s_reporter.Begin(null, 0, RootTarget, "", false); } /// /// Ends a block of messages. If the block was timed, its runtime is /// reported. The End call MUST use the same level as the /// corresponding Begin/BeginTimed. The runtime in seconds is also returned. /// public static double End(int level) { CountCallsToEnd.Increment(); return s_reporter.End(level, RootTarget, null, false); } /// /// Ends a block of messages. If the block was timed, its runtime is /// reported. The End call MUST use the same level as the /// corresponding Begin/BeginTimed. The runtime in seconds is also returned. /// public static double End() { CountCallsToEnd.Increment(); return s_reporter.End(0, RootTarget, null, false); } /// /// Ends a block of messages, and supply an end message. If the end /// message is the very same as the begin message it is suppressed. /// If the end message starts with a continuation character (a space, /// a colon or a comma), it is viewed as a continuation message of /// the begin message, and appended as appropriate. If it is not the /// same and does not start with a continuation character, it is used /// as a distinct end message. /// public static double End(int level, [Localizable(true)] string message, params object[] args) { CountCallsToEnd.Increment(); return s_reporter.End(level, RootTarget, Format(message, args), false); } /// /// Ends a block of messages, and supply an end message. If the end /// message is the very same as the begin message it is suppressed. /// If the end message starts with a continuation character (a space, /// a colon or a comma), it is viewed as a continuation message of /// the begin message, and appended as appropriate. If it is not the /// same and does not start with a continuation character, it is used /// as a distinct end message. /// public static double End([Localizable(true)] string message, params object[] args) { CountCallsToEnd.Increment(); return s_reporter.End(0, RootTarget, Format(message, args), false); } /// /// Ends a block of messages. If the block was timed, its runtime is /// reported. The End call MUST use the same level as the /// corresponding Begin/BeginTimed. The runtime in seconds is also returned. /// public static double EndTimed(int level) { CountCallsToEnd.Increment(); return s_reporter.End(level, RootTarget, null, true); } /// /// Ends a block of messages. If the block was timed, its runtime is /// reported. The End call MUST use the same level as the /// corresponding Begin/BeginTimed. The runtime in seconds is also returned. /// public static double EndTimed() { CountCallsToEnd.Increment(); return s_reporter.End(0, RootTarget, null, true); } /// /// Ends a block of messages, and supply an end message. If the end /// message is the very same as the begin message it is suppressed. /// If the end message starts with a continuation character (a space, /// a colon or a comma), it is viewed as a continuation message of /// the begin message, and appended as appropriate. If it is not the /// same and does not start with a continuation character, it is used /// as a distinct end message. /// public static double EndTimed(int level, [Localizable(true)] string message, params object[] args) { CountCallsToEnd.Increment(); return s_reporter.End(level, RootTarget, Format(message, args), true); } /// /// Ends a block of messages, and supply an end message. If the end /// message is the very same as the begin message it is suppressed. /// If the end message starts with a continuation character (a space, /// a colon or a comma), it is viewed as a continuation message of /// the begin message, and appended as appropriate. If it is not the /// same and does not start with a continuation character, it is used /// as a distinct end message. /// public static double EndTimed([Localizable(true)] string message, params object[] args) { CountCallsToEnd.Increment(); return s_reporter.End(0, RootTarget, Format(message, args), true); } /// /// Report a single message line with formatted parameters. /// public static void Line(int level, [Localizable(true)] string line, params object[] args) { CountCallsToLine.Increment(); s_reporter.Line(LogType.Info, level, RootTarget, Format(line, args)); } /// /// Report a single message line with formatted parameters. /// public static void Line([Localizable(true)] string line, params object[] args) { CountCallsToLine.Increment(); s_reporter.Line(LogType.Info, 0, RootTarget, Format(line, args)); } /// /// Report an empty line or end the line after using Text. /// public static void Line(int level) { CountCallsToLine.Increment(); s_reporter.Line(LogType.Info, level, RootTarget, ""); } /// /// Report an empty line or end the line after using Text. /// public static void Line() { CountCallsToLine.Increment(); s_reporter.Line(LogType.Info, 0, RootTarget, ""); } /// /// Report a (possibly multilined) message with formatted parameters. /// public static void Text(int level, [Localizable(true)] string message, params object[] args) { CountCallsToText.Increment(); s_reporter.Text(level, RootTarget, Format(message, args)); } /// /// Report a (possibly multilined) message with formatted parameters. /// public static void Text([Localizable(true)] string message, params object[] args) { CountCallsToText.Increment(); s_reporter.Text(0, RootTarget, Format(message, args)); } /// /// Report a message that will be written in the current line if it fits, or in /// the next line (with correct indent) if it does not fit. /// public static void Wrap(int level, [Localizable(true)] string message, params object[] args) { CountCallsToText.Increment(); s_reporter.Wrap(level, RootTarget, Format(message, args)); } /// /// Report a message that will be written in the current line if it fits, or in /// the next line (with correct indent) if it does not fit. /// public static void Wrap([Localizable(true)] string message, params object[] args) { CountCallsToText.Increment(); s_reporter.Wrap(0, RootTarget, Format(message, args)); } /// /// Write a warning. Warnings are at level 0 and cannot be /// suppressed. /// public static void Warn([Localizable(true)] string line, params object[] args) { CountCallsToWarn.Increment(); s_reporter.Line(LogType.Warn, 0, RootTarget, "WARNING:", 0, Format(line, args)); } /// /// Write a warning. Warnings are at level 0 and cannot be /// suppressed. /// public static void WarnNoPrefix([Localizable(true)] string line, params object[] args) { CountCallsToWarn.Increment(); s_reporter.Line(LogType.Warn, 0, RootTarget, "", 0, Format(line, args)); } /// /// Write a debug message. /// public static void Debug([Localizable(true)] string line, params object[] args) { CountCallsToDebug.Increment(); s_reporter.Line(LogType.Debug, 0, RootTarget, "Debug:", 0, Format(line, args)); } /// /// Write a debug message. /// public static void DebugNoPrefix([Localizable(true)] string line, params object[] args) { CountCallsToDebug.Increment(); s_reporter.Line(LogType.Debug, 0, RootTarget, "", 0, Format(line, args)); } /// /// Write a debug message. /// public static void Debug(int level, [Localizable(true)] string line, params object[] args) { CountCallsToDebug.Increment(); s_reporter.Line(LogType.Debug, level, RootTarget, "Debug:", 0, Format(line, args)); } /// /// Write a debug message. /// public static void Trace([Localizable(true)] string line, params object[] args) { CountCallsToTrace.Increment(); s_reporter.Line(LogType.Trace, 0, RootTarget, "Trace:", 0, Format(line, args)); } /// /// Write a debug message. /// public static void Trace(int level, [Localizable(true)] string line, params object[] args) { CountCallsToTrace.Increment(); s_reporter.Line(LogType.Trace, level, RootTarget, "Trace:", 0, Format(line, args)); } /// /// Write an error. Errors are at level 0 and cannot be /// suppressed. More serious than a Warning, the program commences. /// public static void Error([Localizable(true)] string line, params object[] args) { var output = Format(line, args); CountCallsToError.Increment(); s_reporter.Line(LogType.Error, 0, RootTarget, "ERROR:", 0, output); if (ThrowOnError) { System.Diagnostics.Debugger.Break(); if (System.Diagnostics.Debugger.IsAttached) { throw new Exception(output); } } } /// /// Write an error. Errors are at level 0 and cannot be /// suppressed. More serious than a Warning, the program commences. /// public static void ErrorNoPrefix([Localizable(true)] string line, params object[] args) { var output = Format(line, args); CountCallsToError.Increment(); s_reporter.Line(LogType.Error, 0, RootTarget, "", 0, output); if (ThrowOnError) { System.Diagnostics.Debugger.Break(); if (System.Diagnostics.Debugger.IsAttached) { throw new Exception(output); } } } /// /// Report a critical failure and break into the debugger, if /// one is attached. /// public static void Fatal([Localizable(true)] string line, params object[] args) { CountCallsToFatal.Increment(); s_reporter.Line(LogType.Fatal, 0, RootTarget, "CRITICAL ERROR:", 0, Format(line, args)); /* System.Diagnostics.StackTrace trace = */ new System.Diagnostics.StackTrace(1); if (System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Break(); throw new NotImplementedException(); } public static void Progress(int level, double progress) { CountCallsToProgress.Increment(); s_reporter.Progress(level, RootTarget, progress, false); } public static void Progress(double progress) { CountCallsToProgress.Increment(); s_reporter.Progress(0, RootTarget, progress, false); } public static void ProgressDelta(int level, double progressDelta) { CountCallsToProgress.Increment(); s_reporter.Progress(level, RootTarget, progressDelta, true); } public static void ProgressDelta(double progressDelta) { CountCallsToProgress.Increment(); s_reporter.Progress(0, RootTarget, progressDelta, true); } /// /// Report a single, named, reportable value. /// public static void Value(int level, [Localizable(true)] string name, IReportable reportable) { CountCallsToValues.Increment(); reportable.ReportValue(level, name); } /// /// Report a single, named, reportable value. /// public static void Value([Localizable(true)] string name, IReportable reportable) { CountCallsToValues.Increment(); reportable.ReportValue(0, name); } /// /// Report a single, named, formattable value. /// public static void Value(int level, [Localizable(true)] string name, object value) { CountCallsToValues.Increment(); s_reporter.Values(level, RootTarget, name, null, value.IntoArray()); } /// /// Report a single, named, formattable value. /// public static void Value([Localizable(true)] string name, object value) { CountCallsToValues.Increment(); s_reporter.Values(0, RootTarget, name, null, value.IntoArray()); } /// /// Report a sequence of formattable values. /// public static void Values(int level, [Localizable(true)] string name, string separator, params object[] values) { CountCallsToValues.Increment(); s_reporter.Values(level, RootTarget, name, separator, values); } /// /// Report a sequence of formattable values. /// public static void Values([Localizable(true)] string name, string separator, params object[] values) { CountCallsToValues.Increment(); s_reporter.Values(0, RootTarget, name, separator, values); } public static void Tests(TestInfo testInfo) { s_reporter.Tests(testInfo); } public static void Tests() { s_reporter.Tests(TestInfo.Empty); } /// /// Adds the reporter to report for the current active thread. /// public static void AddReporter(IReporter reporter) { s_reporter.AddReporter(reporter); } /// /// Removes the reporter to report for the current active thread. /// public static void RemoveReporter(IReporter reporter) { s_reporter.RemoveReporter(reporter); } #endregion } } ================================================ FILE: src/Aardvark.Base/Reporting/ReportJob.cs ================================================ using System; using System.Diagnostics; namespace Aardvark.Base { public class ReportJob : IDisposable { internal string Message; public readonly int HierarchyLevel; public readonly ReportJob ParentJob; public double ChildrenTime; internal int Level; internal long StartTime = -1; internal double Progress; internal bool ReportTests; internal TestInfo TestInfo; internal bool Disposed; internal bool IsTimed => StartTime >= 0; #if NET8_0_OR_GREATER internal double ElapsedSeconds => Stopwatch.GetElapsedTime(StartTime).TotalSeconds; #else internal double ElapsedSeconds => new TimeSpan((Stopwatch.GetTimestamp() - StartTime) * TimeSpan.TicksPerSecond / Stopwatch.Frequency).TotalSeconds; #endif public ReportJob(string message, int level, bool timed, ReportJob parentJob = null) { Disposed = false; Message = message; ParentJob = parentJob; ChildrenTime = 0.0; HierarchyLevel = parentJob == null ? 0 : parentJob.HierarchyLevel + 1; Level = level; Progress = -1.0; ReportTests = false; TestInfo = default(TestInfo); if (timed) StartTime = Stopwatch.GetTimestamp(); } public void Dispose() { if (!Disposed) Report.End(Level); } } } ================================================ FILE: src/Aardvark.Base/Reporting/Skipper.cs ================================================ namespace Aardvark.Base { /// /// This small struct helps to optimize the number of calls to Report.Progress. /// If you initialize it with a value of N, each Nth call of /// will return true. /// public struct Skipper { int m_count; readonly int m_limit; #region Constructor /// /// Initialize a skipper that results true every Nth call to Do. /// /// N public Skipper(int limit) { m_count = limit; m_limit = limit; } #endregion #region Do public readonly bool HasDone { get { return m_count == m_limit; } } public bool Do { get { if (--m_count > 0) return false; m_count = m_limit; return true; } } #endregion } } ================================================ FILE: src/Aardvark.Base/Reporting/TestInfo.cs ================================================ namespace Aardvark.Base { /// /// A container for passed and failed counts. /// public struct TestInfo { public long PassedCount; public long FailedCount; #region Constructor public TestInfo(long passed, long failed) { PassedCount = passed; FailedCount = failed; } #endregion #region Operations public readonly long TestCount { get { return PassedCount + FailedCount; } } public static TestInfo operator +(TestInfo a, TestInfo b) { return new TestInfo(a.PassedCount + b.PassedCount, a.FailedCount + b.FailedCount); } public static readonly TestInfo Empty = new TestInfo(0, 0); #endregion } } ================================================ FILE: src/Aardvark.Base/Reporting/TextLogTarget.cs ================================================ using System; using System.Collections.Generic; using System.Text; using static System.Math; namespace Aardvark.Base { public class TextLogTarget : ILogTarget { private readonly object m_lock; private ReportState m_state; private readonly Dictionary m_stateTable; public Action WriteAct; private int m_width = 80; private int m_maxIndent = 40; public int Verbosity = 0; public bool LogCompleteLinesOnly = false; public bool AllowBackspace = false; public bool Synchronized = true; public Func m_prefixFun = threadIndex => String.Format("{0,2:x}: ", threadIndex); #region Constructor public TextLogTarget(Action write, int threadIndex = 0) { m_lock = new object(); m_state = new ReportState(threadIndex, m_prefixFun(threadIndex)); m_stateTable = new Dictionary(); WriteAct = write; } #endregion #region Properties public int Width { get { return m_width; } set { m_width = value; m_maxIndent = value / 2; } } public Func PrefixFun { set { m_prefixFun = value; m_state.Prefix = value(m_state.TIdx); m_state.PrefixLength = m_state.Prefix.Length; } } #endregion #region Constants const int c_maxWidth = 160; const string c_spaces160 = " " + " "; const string c_dots160 = "................................................................................" + "................................................................................"; const string c_back160 = "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08"; #endregion #region ILogTarget public void NewThreadIndex(int threadIndex) { } public void Log(int threadIndex, LogMsg msg) { if (msg.Level > Verbosity) return; if (!Synchronized) { Log(msg); return; } lock (m_lock) { if (threadIndex != m_state.TIdx) { if (m_state.Level <= Verbosity && m_state.Buffer.Length > 0 && !LogCompleteLinesOnly) { WriteAct(m_state.TIdx, m_state.Type, m_state.Level, "\n"); // crlf for clean start m_state.DoneCount = 0; // trigger the line to be printed again by the thread later } if (!m_stateTable.TryGetValue(threadIndex, out m_state)) m_stateTable[threadIndex] = m_state = new ReportState(threadIndex, m_prefixFun(threadIndex)); } Log(msg); } } public void Dispose() { lock (m_lock) { if (m_state.Level <= Verbosity && m_state.Buffer.Length > 0) WriteAct(m_state.TIdx, m_state.Type, m_state.Level, m_state.GetBufferLineAndClear()); } } #endregion #region ReportState private class ReportState { public int TIdx; public string Prefix; public int PrefixLength; public LogType Type; public int Level = 0; public StringBuilder Buffer; public bool Timed; public int LeftPos; public int RightPos; public int DoneCount; public ReportState(int threadIndex, string prefix) { TIdx = threadIndex; Type = LogType.Unknown; Level = 0; Prefix = prefix; PrefixLength = Prefix.Length; Buffer = new StringBuilder(80); DoneCount = 0; } public void AddSpaceText(int pos, string text) { int len = Buffer.Length - PrefixLength; var fillCount = pos < len ? 0 : pos - len; if (fillCount > 0) Buffer.Append(c_spaces160, 0, fillCount); Buffer.Append(text); } public void AddDotsText(int pos, string text, int width) { int len = Buffer.Length; if (pos < 0) pos = width + pos - text.Length; if (len > PrefixLength && Buffer[len - 1] != ' ') { Buffer.Append(' '); len += 1; } var empty = text == ""; var fillCount = pos < len ? -1 : pos - len - 1 + (empty ? 1 : 0); if (fillCount > 0) Buffer.Append(c_dots160, 0, fillCount); if (fillCount >= 0 && !empty) Buffer.Append(' '); Buffer.Append(text); } public string Backspace(int count) { if (count > Buffer.Length) count = Buffer.Length; if (count > DoneCount) count = DoneCount; Buffer.Length -= count; DoneCount -= count; return c_back160.Substring(160 - count); } public string GetBufferLineAndClear() { int pos = DoneCount; DoneCount = 0; Buffer.Append("\r\n"); var text = Buffer.ToString(pos, Buffer.Length - pos); Buffer.Clear(); return text; } } #endregion #region Log Message public void Log(LogMsg msg) { if (msg.Type == LogType.End) { if (m_state.Buffer.Length > 0 && (m_state.Type == LogType.Info || (m_state.Type != LogType.Unknown && m_state.LeftPos != msg.LeftPos))) // different indent == other job WriteAct(m_state.TIdx, m_state.Type, m_state.Level, m_state.GetBufferLineAndClear()); if ((msg.Opt & (LogOpt.Timed | LogOpt.NewText)) == 0) return;// if End is not timed, suppress repeated start message } if (msg.Type == LogType.Progress && !AllowBackspace) msg.Opt |= LogOpt.EndLine; if (LogCompleteLinesOnly) { if (msg.Type == LogType.Begin) { msg.Opt = msg.Opt | LogOpt.EndLine; if ((msg.Opt & LogOpt.Timed) != 0) msg.RightText = ""; } else if (msg.Type == LogType.Progress) { msg.Opt = msg.Opt | LogOpt.EndLine; } } else if (m_state.Type == LogType.Begin) { if (msg.Type == LogType.End) { var pos = m_state.LeftPos + m_state.PrefixLength; var len = m_state.Buffer.Length - pos; if (len > 0 // len < 0 if we are from a different indent == other job && msg.LeftText.StartsWith(m_state.Buffer.ToString(pos, len))) { msg.LeftText = msg.LeftText.Substring(len); msg.LeftPos = 0; } } else if (msg.Type == LogType.Progress) { msg.LeftText = null; } else if ((msg.Opt & LogOpt.Wrap) == 0) { if (m_state.Timed) m_state.AddDotsText(m_state.RightPos, "", m_width); // dots to line end WriteAct(m_state.TIdx, m_state.Type, m_state.Level, m_state.GetBufferLineAndClear()); } } else if (m_state.Type == LogType.Progress) { if (msg.Type == LogType.Progress) { if (AllowBackspace) { if (m_state.DoneCount > 0) { WriteAct(m_state.TIdx, msg.Type, msg.Level, m_state.Backspace(msg.RightText.Length)); msg.LeftText = null; } else m_state.Buffer.Clear(); } } else if (msg.Type == LogType.End) { if (AllowBackspace) { if (m_state.DoneCount > 0) { var len = m_state.Buffer.Length - m_state.PrefixLength - m_state.LeftPos; WriteAct(m_state.TIdx, msg.Type, msg.Level, m_state.Backspace(len)); } else m_state.Buffer.Clear(); } } else WriteAct(m_state.TIdx, m_state.Type, m_state.Level, m_state.GetBufferLineAndClear()); } if ((msg.Opt & LogOpt.Wrap) != 0) { if (m_state.Buffer.Length + msg.LeftText.Length + 1 > Width + msg.RightPos) WriteAct(m_state.TIdx, m_state.Type, m_state.Level, m_state.GetBufferLineAndClear()); else if (m_state.Buffer.Length > 0 && m_state.Buffer[m_state.Buffer.Length - 1] != ' ') m_state.Buffer.Append(' '); } if (m_state.Buffer.Length == 0) m_state.Buffer.Append(m_state.Prefix); if (msg.LeftText != null) m_state.AddSpaceText(Min(msg.LeftPos, m_maxIndent), msg.LeftText); if (msg.RightText != null) m_state.AddDotsText(Min(msg.RightPos, m_width), msg.RightText, m_width); if ((msg.Opt & LogOpt.EndLine) != 0) { WriteAct(m_state.TIdx, msg.Type, msg.Level, m_state.GetBufferLineAndClear()); m_state.Type = LogType.Unknown; } else { if (!LogCompleteLinesOnly) { int pos = m_state.DoneCount; int len = m_state.Buffer.Length - pos; WriteAct(m_state.TIdx, msg.Type, msg.Level, m_state.Buffer.ToString(pos, len)); m_state.DoneCount = pos + len; } m_state.Type = msg.Type; m_state.Timed = (msg.Opt & LogOpt.Timed) != 0; m_state.LeftPos = msg.LeftPos; m_state.RightPos = msg.RightPos; // remember EndPos of timed begins for dotting to lineEnd } m_state.Level = msg.Level; } #endregion } } ================================================ FILE: src/Aardvark.Base/Sorting/ArrayExtensions.cs ================================================ using Aardvark.Base.Sorting; using System; namespace Aardvark.Base { public static class ComparableArrayExtensions { #region Comparable Array public static int IndexOfNSmallest(this T[] a, int n) where T : IComparable { if (n == 0) return a.IndexOfMin(); var p = a.CreatePermutationQuickMedianAscending(n); return p[n]; } public static int IndexOfNLargest(this T[] a, int n) where T : IComparable { if (n == 0) return a.IndexOfMax(); var p = a.CreatePermutationQuickMedianDescending(n); return p[n]; } #endregion } } ================================================ FILE: src/Aardvark.Base/Sorting/IEnumerableExtensions.cs ================================================ using Aardvark.Base.Sorting; using System; using System.Collections.Generic; using System.Linq; namespace Aardvark.Base { public static class IEnumerableSortingExtensions { public static SymbolSet ToSymbolSet(this IEnumerable symbols) => new SymbolSet(symbols); public static bool SetEquals(this IEnumerable self, IEnumerable other) { if (self == null && other != null) return false; if (self != null && other == null) return false; if (self.Count() != other.Count()) return false; if (self.Count() != self.Distinct().Count()) throw new Exception("not a proper set"); if (other.Count() != other.Distinct().Count()) throw new Exception("not a proper set"); var tmp = new Dictionary(); tmp.AddRange(self.Select(x => new KeyValuePair(x, x))); foreach (var x in other) if (!tmp.ContainsKey(x)) return false; return true; } #region Median /// /// Searches for the median-element in the Enumerable (according to cmp) and returns its value. /// Runtime is in O(N) and Memory in O(N) /// For partitioning use QuickMedian /// public static T Median(this IEnumerable self, Func cmp) { var array = self.ToArray(); var med = array.Length / 2; array.QuickMedian(cmp, med); var result = array[med]; array = null; return result; } /// /// Searches for the median-element in the Enumerable and returns its value. /// Runtime is in O(N) and Memory in O(N) /// For partitioning use QuickMedian /// public static T Median(this IEnumerable self) where T : IComparable => Median(self, (a, b) => a.CompareTo(b)); /// /// Searches for the median-element in the Array (according to cmp) and returns its value. /// Does not change the given Array /// Runtime is in O(N) and Memory in O(N) /// For partitioning use QuickMedian /// public static T Median(this T[] self, Func cmp) { var med = self.Length / 2; var indices = self.CreatePermutationQuickMedian(cmp, med); var result = self[indices[med]]; indices = null; return result; } /// /// Searches for the median-element in the Array and returns its value. /// Does not change the given Array /// Runtime is in O(N) and Memory in O(N) /// For partitioning use QuickMedian /// public static T Median(this T[] self) where T : IComparable => Median(self, (a, b) => a.CompareTo(b)); /// /// Searches for the median-element in the List (according to cmp) and returns its value. /// Does not change the given List /// Runtime is in O(N) and Memory in O(N) /// For partitioning use QuickMedian /// public static T Median(this List self, Func cmp) { var med = self.Count / 2; var indices = self.CreatePermutationQuickMedian(cmp, med); var result = self[indices[med]]; indices = null; return result; } /// /// Searches for the median-element in the List and returns its value. /// Does not change the given List /// Runtime is in O(N) and Memory in O(N) /// For partitioning use QuickMedian /// public static T Median(this List self) where T : IComparable => Median(self, (a, b) => a.CompareTo(b)); #endregion } } ================================================ FILE: src/Aardvark.Base/Sorting/ListExtensions.cs ================================================ using Aardvark.Base.Sorting; using System; using System.Collections.Generic; namespace Aardvark.Base { public static class ListOrderingExtensions { public static int NSmallestIndex(this List a, int n) where T : IComparable { if (n == 0) return a.SmallestIndex(); var p = a.CreatePermutationQuickMedianAscending(n); return p[n]; } public static int NLargestIndex(this List a, int n) where T : IComparable { if (n == 0) return a.LargestIndex(); var p = a.CreatePermutationQuickMedianDescending(n); return p[n]; } } } ================================================ FILE: src/Aardvark.Base/Sorting/Sorting_auto.cs ================================================ using System; using System.Collections.Generic; using System.ComponentModel; namespace Aardvark.Base.Sorting { // AUTO GENERATED CODE - DO NOT CHANGE! public static class SortingExtensions { #region Constants /// Use insertion sort if count smaller than this (quicksort, quickmedian). private const int c_insertionSortThreshold = 31; private const int c_insertionMedianThreshold = 7; private const int c_minMerge = 32; private const int c_minGallop = 7; private const int c_initialTmpStorageLength = 256; #endregion #region Sort/Median for int[] /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this int[] a, long med) { long last = a.LongLength - 1; QuickMedianAscending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this int[] a, long beginIncl, long endExcl, long med) { QuickMedianAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this int[] a, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1] > a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] > a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] > a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] > a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] > a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai > p2) { while (a[hi] > p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] > p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo] == p1) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai < a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this int[] a) { long last = a.LongLength - 1; QuickSortAscending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this int[] a, long beginIncl, long endExcl) { QuickSortAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this int[] a, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1] > a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] > a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] > a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] > a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] > a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai > p2) { while (a[hi] > p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] > p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); { while (a[lo] == p1) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, lo, hi, cm); QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai < a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this int[] a, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element < a[i2 + begin]) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1 + begin] < a[i2 + begin]) ? i2 : i1; // smaller child if (a[ni + begin] < element) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this int[] a) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element < a[i2]) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1] < a[i2]) ? i2 : i1; // smaller child if (a[ni] < element) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this int[] a) { SmoothSortAscendingInclusiveRange(a, 0, a.LongLength - 1); } public static void SmoothSortAscending( this int[] a, long beginIncl, long endExcl) { SmoothSortAscendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this int[] a, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); else SmoothSortAscendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortAscendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this int[] a, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (val >= a[lf] && val >= a[rt]) break; if (a[lf] >= a[rt]) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this int[] a, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (vstepson <= val) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[rt] >= vstepson || a[lf] >= vstepson) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this int[] a) { TimSortAscending(a, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this int[] a, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, lo, hi); BinarySortAscending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLong(a); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderAscending(a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortAscending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseIntLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseIntLongAsc(ti); } private static void MergeCollapseIntLongAsc(this TimSortInfoLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtIntLongAsc(ti, n); else break; } } private static void MergeForceCollapseIntLongAsc(this TimSortInfoLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntLongAsc(ti, n); } } private static void MergeAtIntLongAsc(this TimSortInfoLong ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightAscending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoIntLongAsc(ti, start1, len1, start2, len2); else MergeHiIntLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoIntLongAsc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[idx2] < t[idx1]) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightAscending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiIntLongAsc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (t[idx2] < a[idx1]) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftAscending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftAscending( this int[] a, int key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (key > a[start + hint]) { long maxOfs = len - hint; while (ofs < maxOfs && key > a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && key <= a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key > a[start + m]) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightAscending( this int[] a, int key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (key < a[start + hint]) { long maxOfs = hint + 1; while (ofs < maxOfs && key < a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && key >= a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key < a[start + m]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this int[] a, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (pivot < a[mid]) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderAscending( this int[] a, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++] < a[beginIncl]) { while (runHi < endExcl && a[runHi] < a[runHi - 1]) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi] >= a[runHi - 1]) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this int[] a, long med) { long last = a.LongLength - 1; QuickMedianDescending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this int[] a, long beginIncl, long endExcl, long med) { QuickMedianDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this int[] a, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1] < a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] < a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] < a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] < a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] < a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai < p2) { while (a[hi] < p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] < p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo] == p1) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai > a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this int[] a) { long last = a.LongLength - 1; QuickSortDescending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this int[] a, long beginIncl, long endExcl) { QuickSortDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this int[] a, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1] < a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] < a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] < a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] < a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] < a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai < p2) { while (a[hi] < p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] < p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); { while (a[lo] == p1) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, lo, hi, cm); QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai > a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this int[] a, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element > a[i2 + begin]) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1 + begin] > a[i2 + begin]) ? i2 : i1; // smaller child if (a[ni + begin] > element) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this int[] a) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element > a[i2]) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1] > a[i2]) ? i2 : i1; // smaller child if (a[ni] > element) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this int[] a) { SmoothSortDescendingInclusiveRange(a, 0, a.LongLength - 1); } public static void SmoothSortDescending( this int[] a, long beginIncl, long endExcl) { SmoothSortDescendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this int[] a, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); else SmoothSortDescendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortDescendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this int[] a, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (val <= a[lf] && val <= a[rt]) break; if (a[lf] <= a[rt]) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this int[] a, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (vstepson >= val) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[rt] <= vstepson || a[lf] <= vstepson) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this int[] a) { TimSortDescending(a, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this int[] a, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, lo, hi); BinarySortDescending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLong(a); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderDescending(a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortDescending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseIntLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseIntLongDesc(ti); } private static void MergeCollapseIntLongDesc(this TimSortInfoLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtIntLongDesc(ti, n); else break; } } private static void MergeForceCollapseIntLongDesc(this TimSortInfoLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntLongDesc(ti, n); } } private static void MergeAtIntLongDesc(this TimSortInfoLong ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightDescending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoIntLongDesc(ti, start1, len1, start2, len2); else MergeHiIntLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoIntLongDesc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[idx2] > t[idx1]) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightDescending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiIntLongDesc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (t[idx2] > a[idx1]) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftDescending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftDescending( this int[] a, int key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (key < a[start + hint]) { long maxOfs = len - hint; while (ofs < maxOfs && key < a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && key >= a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key < a[start + m]) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightDescending( this int[] a, int key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (key > a[start + hint]) { long maxOfs = hint + 1; while (ofs < maxOfs && key > a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && key <= a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key > a[start + m]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this int[] a, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (pivot > a[mid]) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderDescending( this int[] a, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++] > a[beginIncl]) { while (runHi < endExcl && a[runHi] > a[runHi - 1]) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi] <= a[runHi - 1]) runHi++; } return runHi - beginIncl; } #endregion #region Permutation Sort/Median for int[] /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this int[] a, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, int[] a, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, int[] a, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, int[] a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this int[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, int[] a) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, int[] a, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, int[] a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, lo, hi, cm); PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this int[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, int[] a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] < a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]] < a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] < a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, int[] a) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] < a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]] < a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] < a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this int[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a); return p; } public static void PermutationSmoothSortAscending( this int[] p, int[] a) { PermutationSmoothSortAscendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, int[] a, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, int[] a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, int[] a, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val] >= a[p[lf]] && a[val] >= a[p[rt]]) break; if (a[p[lf]] >= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, int[] a, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson] <= a[val]) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]] >= a[vstepson] || a[p[lf]] >= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this int[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, int[] a) { PermutationTimSortAscending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, int[] a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); PermutationBinarySortAscending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseIntPermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseIntPermAsc(ti); } private static void MergeCollapseIntPermAsc(this TimSortInfoPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtIntPermAsc(ti, n); else break; } } private static void MergeForceCollapseIntPermAsc(this TimSortInfoPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntPermAsc(ti, n); } } private static void MergeAtIntPermAsc(this TimSortInfoPerm ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoIntPermAsc(ti, start1, len1, start2, len2); else MergeHiIntPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoIntPermAsc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]] < a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiIntPermAsc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]] < a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, int[] a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (a[key] > a[p[start + hint]]) { int maxOfs = len - hint; while (ofs < maxOfs && a[key] > a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] <= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, int[] a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (a[key] < a[p[start + hint]]) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] < a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key] >= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, int[] a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot] < a[p[mid]]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, int[] a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] < a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] < a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] >= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianAscendingLong( this int[] a, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianAscending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this long[] p, int[] a, long med) { long last = p.LongLength - 1; PermutationQuickMedianAscending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this long[] p, int[] a, long beginIncl, long endExcl, long med) { PermutationQuickMedianAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this long[] p, int[] a, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortAscendingLong( this int[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortAscending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, int[] a) { long last = p.LongLength - 1; PermutationQuickSortAscending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, int[] a, long beginIncl, long endExcl) { PermutationQuickSortAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this long[] p, int[] a, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, lo, hi, cm); PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortAscendingLong( this int[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortAscending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, int[] a, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element] < a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1 + begin]] < a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] < a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, int[] a) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element] < a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1]] < a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] < a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortAscendingLong( this int[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortAscending(p, a); return p; } public static void PermutationSmoothSortAscending( this long[] p, int[] a) { PermutationSmoothSortAscendingInclusiveRange(p, a, 0, p.LongLength - 1); } public static void PermutationSmoothSortAscending( this long[] p, int[] a, long beginIncl, long endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this long[] p, int[] a, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this long[] p, int[] a, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[val] >= a[p[lf]] && a[val] >= a[p[rt]]) break; if (a[p[lf]] >= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this long[] p, int[] a, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (a[vstepson] <= a[val]) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[p[rt]] >= a[vstepson] || a[p[lf]] >= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortAscendingLong( this int[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortAscending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, int[] a) { PermutationTimSortAscending(p, a, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, int[] a, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); PermutationBinarySortAscending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLong(p, a); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseIntPermLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseIntPermLongAsc(ti); } private static void MergeCollapseIntPermLongAsc(this TimSortInfoPermLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntPermLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtIntPermLongAsc(ti, n); else break; } } private static void MergeForceCollapseIntPermLongAsc(this TimSortInfoPermLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntPermLongAsc(ti, n); } } private static void MergeAtIntPermLongAsc(this TimSortInfoPermLong ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightAscending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoIntPermLongAsc(ti, start1, len1, start2, len2); else MergeHiIntPermLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoIntPermLongAsc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[p[idx2]] < a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiIntPermLongAsc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[t[idx2]] < a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftAscending( this long[] p, int[] a, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (a[key] > a[p[start + hint]]) { long maxOfs = len - hint; while (ofs < maxOfs && a[key] > a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && a[key] <= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightAscending( this long[] p, int[] a, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (a[key] < a[p[start + hint]]) { long maxOfs = hint + 1; while (ofs < maxOfs && a[key] < a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && a[key] >= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this long[] p, int[] a, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (a[pivot] < a[p[mid]]) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderAscending( this long[] p, int[] a, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] < a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] < a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] >= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this int[] a, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, int[] a, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, int[] a, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, int[] a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this int[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, int[] a) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, int[] a, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, int[] a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, lo, hi, cm); PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this int[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, int[] a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] > a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]] > a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] > a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, int[] a) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] > a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]] > a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] > a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this int[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a); return p; } public static void PermutationSmoothSortDescending( this int[] p, int[] a) { PermutationSmoothSortDescendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, int[] a, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, int[] a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, int[] a, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val] <= a[p[lf]] && a[val] <= a[p[rt]]) break; if (a[p[lf]] <= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, int[] a, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson] >= a[val]) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]] <= a[vstepson] || a[p[lf]] <= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this int[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, int[] a) { PermutationTimSortDescending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, int[] a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); PermutationBinarySortDescending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseIntPermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseIntPermDesc(ti); } private static void MergeCollapseIntPermDesc(this TimSortInfoPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtIntPermDesc(ti, n); else break; } } private static void MergeForceCollapseIntPermDesc(this TimSortInfoPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntPermDesc(ti, n); } } private static void MergeAtIntPermDesc(this TimSortInfoPerm ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoIntPermDesc(ti, start1, len1, start2, len2); else MergeHiIntPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoIntPermDesc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]] > a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiIntPermDesc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]] > a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, int[] a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (a[key] < a[p[start + hint]]) { int maxOfs = len - hint; while (ofs < maxOfs && a[key] < a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] >= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, int[] a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (a[key] > a[p[start + hint]]) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] > a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key] <= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, int[] a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot] > a[p[mid]]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, int[] a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] > a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] > a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] <= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianDescendingLong( this int[] a, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianDescending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this long[] p, int[] a, long med) { long last = p.LongLength - 1; PermutationQuickMedianDescending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this long[] p, int[] a, long beginIncl, long endExcl, long med) { PermutationQuickMedianDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this long[] p, int[] a, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortDescendingLong( this int[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortDescending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, int[] a) { long last = p.LongLength - 1; PermutationQuickSortDescending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, int[] a, long beginIncl, long endExcl) { PermutationQuickSortDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this long[] p, int[] a, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, lo, hi, cm); PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortDescendingLong( this int[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortDescending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, int[] a, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element] > a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1 + begin]] > a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] > a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, int[] a) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element] > a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1]] > a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] > a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortDescendingLong( this int[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortDescending(p, a); return p; } public static void PermutationSmoothSortDescending( this long[] p, int[] a) { PermutationSmoothSortDescendingInclusiveRange(p, a, 0, p.LongLength - 1); } public static void PermutationSmoothSortDescending( this long[] p, int[] a, long beginIncl, long endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this long[] p, int[] a, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this long[] p, int[] a, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[val] <= a[p[lf]] && a[val] <= a[p[rt]]) break; if (a[p[lf]] <= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this long[] p, int[] a, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (a[vstepson] >= a[val]) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[p[rt]] <= a[vstepson] || a[p[lf]] <= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortDescendingLong( this int[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortDescending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, int[] a) { PermutationTimSortDescending(p, a, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, int[] a, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); PermutationBinarySortDescending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLong(p, a); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseIntPermLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseIntPermLongDesc(ti); } private static void MergeCollapseIntPermLongDesc(this TimSortInfoPermLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntPermLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtIntPermLongDesc(ti, n); else break; } } private static void MergeForceCollapseIntPermLongDesc(this TimSortInfoPermLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntPermLongDesc(ti, n); } } private static void MergeAtIntPermLongDesc(this TimSortInfoPermLong ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightDescending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoIntPermLongDesc(ti, start1, len1, start2, len2); else MergeHiIntPermLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoIntPermLongDesc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[p[idx2]] > a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiIntPermLongDesc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[t[idx2]] > a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftDescending( this long[] p, int[] a, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (a[key] < a[p[start + hint]]) { long maxOfs = len - hint; while (ofs < maxOfs && a[key] < a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && a[key] >= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightDescending( this long[] p, int[] a, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (a[key] > a[p[start + hint]]) { long maxOfs = hint + 1; while (ofs < maxOfs && a[key] > a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && a[key] <= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this long[] p, int[] a, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (a[pivot] > a[p[mid]]) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderDescending( this long[] p, int[] a, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] > a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] > a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] <= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } #endregion #region Sort/Median for long[] /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this long[] a, long med) { long last = a.LongLength - 1; QuickMedianAscending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this long[] a, long beginIncl, long endExcl, long med) { QuickMedianAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this long[] a, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1] > a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] > a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] > a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] > a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] > a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai > p2) { while (a[hi] > p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] > p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo] == p1) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai < a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this long[] a) { long last = a.LongLength - 1; QuickSortAscending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this long[] a, long beginIncl, long endExcl) { QuickSortAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this long[] a, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1] > a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] > a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] > a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] > a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] > a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai > p2) { while (a[hi] > p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] > p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); { while (a[lo] == p1) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, lo, hi, cm); QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai < a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this long[] a, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element < a[i2 + begin]) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1 + begin] < a[i2 + begin]) ? i2 : i1; // smaller child if (a[ni + begin] < element) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this long[] a) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element < a[i2]) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1] < a[i2]) ? i2 : i1; // smaller child if (a[ni] < element) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this long[] a) { SmoothSortAscendingInclusiveRange(a, 0, a.LongLength - 1); } public static void SmoothSortAscending( this long[] a, long beginIncl, long endExcl) { SmoothSortAscendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this long[] a, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); else SmoothSortAscendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortAscendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this long[] a, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (val >= a[lf] && val >= a[rt]) break; if (a[lf] >= a[rt]) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this long[] a, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (vstepson <= val) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[rt] >= vstepson || a[lf] >= vstepson) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this long[] a) { TimSortAscending(a, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this long[] a, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, lo, hi); BinarySortAscending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLong(a); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderAscending(a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortAscending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongLongAsc(ti); } private static void MergeCollapseLongLongAsc(this TimSortInfoLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongLongAsc(ti, n); else break; } } private static void MergeForceCollapseLongLongAsc(this TimSortInfoLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongLongAsc(ti, n); } } private static void MergeAtLongLongAsc(this TimSortInfoLong ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightAscending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongLongAsc(ti, start1, len1, start2, len2); else MergeHiLongLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoLongLongAsc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[idx2] < t[idx1]) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightAscending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiLongLongAsc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (t[idx2] < a[idx1]) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftAscending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftAscending( this long[] a, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (key > a[start + hint]) { long maxOfs = len - hint; while (ofs < maxOfs && key > a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && key <= a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key > a[start + m]) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightAscending( this long[] a, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (key < a[start + hint]) { long maxOfs = hint + 1; while (ofs < maxOfs && key < a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && key >= a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key < a[start + m]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this long[] a, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (pivot < a[mid]) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderAscending( this long[] a, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++] < a[beginIncl]) { while (runHi < endExcl && a[runHi] < a[runHi - 1]) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi] >= a[runHi - 1]) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this long[] a, long med) { long last = a.LongLength - 1; QuickMedianDescending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this long[] a, long beginIncl, long endExcl, long med) { QuickMedianDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this long[] a, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1] < a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] < a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] < a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] < a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] < a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai < p2) { while (a[hi] < p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] < p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo] == p1) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai > a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this long[] a) { long last = a.LongLength - 1; QuickSortDescending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this long[] a, long beginIncl, long endExcl) { QuickSortDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this long[] a, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1] < a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] < a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] < a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] < a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] < a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai < p2) { while (a[hi] < p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] < p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); { while (a[lo] == p1) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, lo, hi, cm); QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai > a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this long[] a, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element > a[i2 + begin]) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1 + begin] > a[i2 + begin]) ? i2 : i1; // smaller child if (a[ni + begin] > element) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this long[] a) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element > a[i2]) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1] > a[i2]) ? i2 : i1; // smaller child if (a[ni] > element) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this long[] a) { SmoothSortDescendingInclusiveRange(a, 0, a.LongLength - 1); } public static void SmoothSortDescending( this long[] a, long beginIncl, long endExcl) { SmoothSortDescendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this long[] a, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); else SmoothSortDescendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortDescendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this long[] a, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (val <= a[lf] && val <= a[rt]) break; if (a[lf] <= a[rt]) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this long[] a, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (vstepson >= val) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[rt] <= vstepson || a[lf] <= vstepson) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this long[] a) { TimSortDescending(a, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this long[] a, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, lo, hi); BinarySortDescending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLong(a); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderDescending(a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortDescending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongLongDesc(ti); } private static void MergeCollapseLongLongDesc(this TimSortInfoLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongLongDesc(ti, n); else break; } } private static void MergeForceCollapseLongLongDesc(this TimSortInfoLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongLongDesc(ti, n); } } private static void MergeAtLongLongDesc(this TimSortInfoLong ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightDescending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongLongDesc(ti, start1, len1, start2, len2); else MergeHiLongLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoLongLongDesc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[idx2] > t[idx1]) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightDescending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiLongLongDesc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (t[idx2] > a[idx1]) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftDescending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftDescending( this long[] a, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (key < a[start + hint]) { long maxOfs = len - hint; while (ofs < maxOfs && key < a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && key >= a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key < a[start + m]) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightDescending( this long[] a, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (key > a[start + hint]) { long maxOfs = hint + 1; while (ofs < maxOfs && key > a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && key <= a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key > a[start + m]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this long[] a, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (pivot > a[mid]) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderDescending( this long[] a, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++] > a[beginIncl]) { while (runHi < endExcl && a[runHi] > a[runHi - 1]) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi] <= a[runHi - 1]) runHi++; } return runHi - beginIncl; } #endregion #region Permutation Sort/Median for long[] /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this long[] a, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, long[] a, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, long[] a, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, long[] a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this long[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, long[] a) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, long[] a, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, long[] a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, lo, hi, cm); PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this long[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, long[] a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] < a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]] < a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] < a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, long[] a) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] < a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]] < a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] < a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this long[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a); return p; } public static void PermutationSmoothSortAscending( this int[] p, long[] a) { PermutationSmoothSortAscendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, long[] a, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, long[] a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, long[] a, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val] >= a[p[lf]] && a[val] >= a[p[rt]]) break; if (a[p[lf]] >= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, long[] a, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson] <= a[val]) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]] >= a[vstepson] || a[p[lf]] >= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this long[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, long[] a) { PermutationTimSortAscending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, long[] a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); PermutationBinarySortAscending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongPermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongPermAsc(ti); } private static void MergeCollapseLongPermAsc(this TimSortInfoPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongPermAsc(ti, n); else break; } } private static void MergeForceCollapseLongPermAsc(this TimSortInfoPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongPermAsc(ti, n); } } private static void MergeAtLongPermAsc(this TimSortInfoPerm ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongPermAsc(ti, start1, len1, start2, len2); else MergeHiLongPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoLongPermAsc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]] < a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiLongPermAsc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]] < a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, long[] a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (a[key] > a[p[start + hint]]) { int maxOfs = len - hint; while (ofs < maxOfs && a[key] > a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] <= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, long[] a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (a[key] < a[p[start + hint]]) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] < a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key] >= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, long[] a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot] < a[p[mid]]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, long[] a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] < a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] < a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] >= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianAscendingLong( this long[] a, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianAscending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this long[] p, long[] a, long med) { long last = p.LongLength - 1; PermutationQuickMedianAscending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this long[] p, long[] a, long beginIncl, long endExcl, long med) { PermutationQuickMedianAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this long[] p, long[] a, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortAscendingLong( this long[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortAscending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, long[] a) { long last = p.LongLength - 1; PermutationQuickSortAscending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, long[] a, long beginIncl, long endExcl) { PermutationQuickSortAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this long[] p, long[] a, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, lo, hi, cm); PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortAscendingLong( this long[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortAscending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, long[] a, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element] < a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1 + begin]] < a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] < a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, long[] a) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element] < a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1]] < a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] < a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortAscendingLong( this long[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortAscending(p, a); return p; } public static void PermutationSmoothSortAscending( this long[] p, long[] a) { PermutationSmoothSortAscendingInclusiveRange(p, a, 0, p.LongLength - 1); } public static void PermutationSmoothSortAscending( this long[] p, long[] a, long beginIncl, long endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this long[] p, long[] a, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this long[] p, long[] a, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[val] >= a[p[lf]] && a[val] >= a[p[rt]]) break; if (a[p[lf]] >= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this long[] p, long[] a, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (a[vstepson] <= a[val]) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[p[rt]] >= a[vstepson] || a[p[lf]] >= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortAscendingLong( this long[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortAscending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, long[] a) { PermutationTimSortAscending(p, a, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, long[] a, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); PermutationBinarySortAscending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLong(p, a); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongPermLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongPermLongAsc(ti); } private static void MergeCollapseLongPermLongAsc(this TimSortInfoPermLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongPermLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongPermLongAsc(ti, n); else break; } } private static void MergeForceCollapseLongPermLongAsc(this TimSortInfoPermLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongPermLongAsc(ti, n); } } private static void MergeAtLongPermLongAsc(this TimSortInfoPermLong ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightAscending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongPermLongAsc(ti, start1, len1, start2, len2); else MergeHiLongPermLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoLongPermLongAsc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[p[idx2]] < a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiLongPermLongAsc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[t[idx2]] < a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftAscending( this long[] p, long[] a, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (a[key] > a[p[start + hint]]) { long maxOfs = len - hint; while (ofs < maxOfs && a[key] > a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && a[key] <= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightAscending( this long[] p, long[] a, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (a[key] < a[p[start + hint]]) { long maxOfs = hint + 1; while (ofs < maxOfs && a[key] < a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && a[key] >= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this long[] p, long[] a, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (a[pivot] < a[p[mid]]) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderAscending( this long[] p, long[] a, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] < a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] < a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] >= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this long[] a, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, long[] a, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, long[] a, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, long[] a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this long[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, long[] a) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, long[] a, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, long[] a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, lo, hi, cm); PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this long[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, long[] a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] > a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]] > a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] > a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, long[] a) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] > a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]] > a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] > a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this long[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a); return p; } public static void PermutationSmoothSortDescending( this int[] p, long[] a) { PermutationSmoothSortDescendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, long[] a, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, long[] a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, long[] a, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val] <= a[p[lf]] && a[val] <= a[p[rt]]) break; if (a[p[lf]] <= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, long[] a, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson] >= a[val]) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]] <= a[vstepson] || a[p[lf]] <= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this long[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, long[] a) { PermutationTimSortDescending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, long[] a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); PermutationBinarySortDescending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongPermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongPermDesc(ti); } private static void MergeCollapseLongPermDesc(this TimSortInfoPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongPermDesc(ti, n); else break; } } private static void MergeForceCollapseLongPermDesc(this TimSortInfoPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongPermDesc(ti, n); } } private static void MergeAtLongPermDesc(this TimSortInfoPerm ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongPermDesc(ti, start1, len1, start2, len2); else MergeHiLongPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoLongPermDesc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]] > a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiLongPermDesc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]] > a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, long[] a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (a[key] < a[p[start + hint]]) { int maxOfs = len - hint; while (ofs < maxOfs && a[key] < a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] >= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, long[] a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (a[key] > a[p[start + hint]]) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] > a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key] <= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, long[] a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot] > a[p[mid]]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, long[] a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] > a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] > a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] <= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianDescendingLong( this long[] a, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianDescending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this long[] p, long[] a, long med) { long last = p.LongLength - 1; PermutationQuickMedianDescending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this long[] p, long[] a, long beginIncl, long endExcl, long med) { PermutationQuickMedianDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this long[] p, long[] a, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortDescendingLong( this long[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortDescending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, long[] a) { long last = p.LongLength - 1; PermutationQuickSortDescending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, long[] a, long beginIncl, long endExcl) { PermutationQuickSortDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this long[] p, long[] a, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, lo, hi, cm); PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortDescendingLong( this long[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortDescending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, long[] a, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element] > a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1 + begin]] > a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] > a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, long[] a) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element] > a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1]] > a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] > a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortDescendingLong( this long[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortDescending(p, a); return p; } public static void PermutationSmoothSortDescending( this long[] p, long[] a) { PermutationSmoothSortDescendingInclusiveRange(p, a, 0, p.LongLength - 1); } public static void PermutationSmoothSortDescending( this long[] p, long[] a, long beginIncl, long endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this long[] p, long[] a, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this long[] p, long[] a, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[val] <= a[p[lf]] && a[val] <= a[p[rt]]) break; if (a[p[lf]] <= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this long[] p, long[] a, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (a[vstepson] >= a[val]) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[p[rt]] <= a[vstepson] || a[p[lf]] <= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortDescendingLong( this long[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortDescending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, long[] a) { PermutationTimSortDescending(p, a, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, long[] a, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); PermutationBinarySortDescending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLong(p, a); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongPermLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongPermLongDesc(ti); } private static void MergeCollapseLongPermLongDesc(this TimSortInfoPermLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongPermLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongPermLongDesc(ti, n); else break; } } private static void MergeForceCollapseLongPermLongDesc(this TimSortInfoPermLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongPermLongDesc(ti, n); } } private static void MergeAtLongPermLongDesc(this TimSortInfoPermLong ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightDescending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongPermLongDesc(ti, start1, len1, start2, len2); else MergeHiLongPermLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoLongPermLongDesc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[p[idx2]] > a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiLongPermLongDesc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[t[idx2]] > a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftDescending( this long[] p, long[] a, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (a[key] < a[p[start + hint]]) { long maxOfs = len - hint; while (ofs < maxOfs && a[key] < a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && a[key] >= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightDescending( this long[] p, long[] a, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (a[key] > a[p[start + hint]]) { long maxOfs = hint + 1; while (ofs < maxOfs && a[key] > a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && a[key] <= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this long[] p, long[] a, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (a[pivot] > a[p[mid]]) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderDescending( this long[] p, long[] a, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] > a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] > a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] <= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } #endregion #region Sort/Median for float[] /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this float[] a, long med) { long last = a.LongLength - 1; QuickMedianAscending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this float[] a, long beginIncl, long endExcl, long med) { QuickMedianAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this float[] a, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1] > a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] > a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] > a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] > a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] > a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai > p2) { while (a[hi] > p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] > p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo] == p1) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai < a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this float[] a) { long last = a.LongLength - 1; QuickSortAscending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this float[] a, long beginIncl, long endExcl) { QuickSortAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this float[] a, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1] > a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] > a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] > a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] > a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] > a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai > p2) { while (a[hi] > p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] > p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); { while (a[lo] == p1) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, lo, hi, cm); QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai < a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this float[] a, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element < a[i2 + begin]) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1 + begin] < a[i2 + begin]) ? i2 : i1; // smaller child if (a[ni + begin] < element) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this float[] a) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element < a[i2]) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1] < a[i2]) ? i2 : i1; // smaller child if (a[ni] < element) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this float[] a) { SmoothSortAscendingInclusiveRange(a, 0, a.LongLength - 1); } public static void SmoothSortAscending( this float[] a, long beginIncl, long endExcl) { SmoothSortAscendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this float[] a, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); else SmoothSortAscendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortAscendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this float[] a, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (val >= a[lf] && val >= a[rt]) break; if (a[lf] >= a[rt]) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this float[] a, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (vstepson <= val) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[rt] >= vstepson || a[lf] >= vstepson) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this float[] a) { TimSortAscending(a, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this float[] a, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, lo, hi); BinarySortAscending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLong(a); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderAscending(a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortAscending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseFloatLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseFloatLongAsc(ti); } private static void MergeCollapseFloatLongAsc(this TimSortInfoLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtFloatLongAsc(ti, n); else break; } } private static void MergeForceCollapseFloatLongAsc(this TimSortInfoLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatLongAsc(ti, n); } } private static void MergeAtFloatLongAsc(this TimSortInfoLong ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightAscending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoFloatLongAsc(ti, start1, len1, start2, len2); else MergeHiFloatLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoFloatLongAsc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[idx2] < t[idx1]) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightAscending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiFloatLongAsc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (t[idx2] < a[idx1]) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftAscending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftAscending( this float[] a, float key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (key > a[start + hint]) { long maxOfs = len - hint; while (ofs < maxOfs && key > a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && key <= a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key > a[start + m]) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightAscending( this float[] a, float key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (key < a[start + hint]) { long maxOfs = hint + 1; while (ofs < maxOfs && key < a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && key >= a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key < a[start + m]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this float[] a, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (pivot < a[mid]) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderAscending( this float[] a, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++] < a[beginIncl]) { while (runHi < endExcl && a[runHi] < a[runHi - 1]) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi] >= a[runHi - 1]) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this float[] a, long med) { long last = a.LongLength - 1; QuickMedianDescending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this float[] a, long beginIncl, long endExcl, long med) { QuickMedianDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this float[] a, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1] < a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] < a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] < a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] < a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] < a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai < p2) { while (a[hi] < p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] < p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo] == p1) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai > a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this float[] a) { long last = a.LongLength - 1; QuickSortDescending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this float[] a, long beginIncl, long endExcl) { QuickSortDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this float[] a, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1] < a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] < a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] < a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] < a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] < a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai < p2) { while (a[hi] < p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] < p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); { while (a[lo] == p1) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, lo, hi, cm); QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai > a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this float[] a, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element > a[i2 + begin]) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1 + begin] > a[i2 + begin]) ? i2 : i1; // smaller child if (a[ni + begin] > element) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this float[] a) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element > a[i2]) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1] > a[i2]) ? i2 : i1; // smaller child if (a[ni] > element) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this float[] a) { SmoothSortDescendingInclusiveRange(a, 0, a.LongLength - 1); } public static void SmoothSortDescending( this float[] a, long beginIncl, long endExcl) { SmoothSortDescendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this float[] a, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); else SmoothSortDescendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortDescendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this float[] a, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (val <= a[lf] && val <= a[rt]) break; if (a[lf] <= a[rt]) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this float[] a, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (vstepson >= val) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[rt] <= vstepson || a[lf] <= vstepson) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this float[] a) { TimSortDescending(a, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this float[] a, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, lo, hi); BinarySortDescending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLong(a); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderDescending(a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortDescending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseFloatLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseFloatLongDesc(ti); } private static void MergeCollapseFloatLongDesc(this TimSortInfoLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtFloatLongDesc(ti, n); else break; } } private static void MergeForceCollapseFloatLongDesc(this TimSortInfoLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatLongDesc(ti, n); } } private static void MergeAtFloatLongDesc(this TimSortInfoLong ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightDescending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoFloatLongDesc(ti, start1, len1, start2, len2); else MergeHiFloatLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoFloatLongDesc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[idx2] > t[idx1]) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightDescending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiFloatLongDesc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (t[idx2] > a[idx1]) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftDescending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftDescending( this float[] a, float key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (key < a[start + hint]) { long maxOfs = len - hint; while (ofs < maxOfs && key < a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && key >= a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key < a[start + m]) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightDescending( this float[] a, float key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (key > a[start + hint]) { long maxOfs = hint + 1; while (ofs < maxOfs && key > a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && key <= a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key > a[start + m]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this float[] a, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (pivot > a[mid]) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderDescending( this float[] a, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++] > a[beginIncl]) { while (runHi < endExcl && a[runHi] > a[runHi - 1]) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi] <= a[runHi - 1]) runHi++; } return runHi - beginIncl; } #endregion #region Permutation Sort/Median for float[] /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this float[] a, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, float[] a, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, float[] a, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, float[] a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this float[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, float[] a) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, float[] a, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, float[] a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, lo, hi, cm); PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this float[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, float[] a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] < a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]] < a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] < a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, float[] a) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] < a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]] < a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] < a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this float[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a); return p; } public static void PermutationSmoothSortAscending( this int[] p, float[] a) { PermutationSmoothSortAscendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, float[] a, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, float[] a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, float[] a, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val] >= a[p[lf]] && a[val] >= a[p[rt]]) break; if (a[p[lf]] >= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, float[] a, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson] <= a[val]) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]] >= a[vstepson] || a[p[lf]] >= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this float[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, float[] a) { PermutationTimSortAscending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, float[] a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); PermutationBinarySortAscending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseFloatPermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseFloatPermAsc(ti); } private static void MergeCollapseFloatPermAsc(this TimSortInfoPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtFloatPermAsc(ti, n); else break; } } private static void MergeForceCollapseFloatPermAsc(this TimSortInfoPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatPermAsc(ti, n); } } private static void MergeAtFloatPermAsc(this TimSortInfoPerm ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoFloatPermAsc(ti, start1, len1, start2, len2); else MergeHiFloatPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoFloatPermAsc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]] < a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiFloatPermAsc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]] < a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, float[] a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (a[key] > a[p[start + hint]]) { int maxOfs = len - hint; while (ofs < maxOfs && a[key] > a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] <= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, float[] a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (a[key] < a[p[start + hint]]) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] < a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key] >= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, float[] a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot] < a[p[mid]]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, float[] a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] < a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] < a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] >= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianAscendingLong( this float[] a, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianAscending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this long[] p, float[] a, long med) { long last = p.LongLength - 1; PermutationQuickMedianAscending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this long[] p, float[] a, long beginIncl, long endExcl, long med) { PermutationQuickMedianAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this long[] p, float[] a, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortAscendingLong( this float[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortAscending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, float[] a) { long last = p.LongLength - 1; PermutationQuickSortAscending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, float[] a, long beginIncl, long endExcl) { PermutationQuickSortAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this long[] p, float[] a, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, lo, hi, cm); PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortAscendingLong( this float[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortAscending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, float[] a, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element] < a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1 + begin]] < a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] < a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, float[] a) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element] < a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1]] < a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] < a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortAscendingLong( this float[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortAscending(p, a); return p; } public static void PermutationSmoothSortAscending( this long[] p, float[] a) { PermutationSmoothSortAscendingInclusiveRange(p, a, 0, p.LongLength - 1); } public static void PermutationSmoothSortAscending( this long[] p, float[] a, long beginIncl, long endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this long[] p, float[] a, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this long[] p, float[] a, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[val] >= a[p[lf]] && a[val] >= a[p[rt]]) break; if (a[p[lf]] >= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this long[] p, float[] a, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (a[vstepson] <= a[val]) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[p[rt]] >= a[vstepson] || a[p[lf]] >= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortAscendingLong( this float[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortAscending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, float[] a) { PermutationTimSortAscending(p, a, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, float[] a, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); PermutationBinarySortAscending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLong(p, a); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseFloatPermLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseFloatPermLongAsc(ti); } private static void MergeCollapseFloatPermLongAsc(this TimSortInfoPermLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatPermLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtFloatPermLongAsc(ti, n); else break; } } private static void MergeForceCollapseFloatPermLongAsc(this TimSortInfoPermLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatPermLongAsc(ti, n); } } private static void MergeAtFloatPermLongAsc(this TimSortInfoPermLong ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightAscending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoFloatPermLongAsc(ti, start1, len1, start2, len2); else MergeHiFloatPermLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoFloatPermLongAsc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[p[idx2]] < a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiFloatPermLongAsc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[t[idx2]] < a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftAscending( this long[] p, float[] a, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (a[key] > a[p[start + hint]]) { long maxOfs = len - hint; while (ofs < maxOfs && a[key] > a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && a[key] <= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightAscending( this long[] p, float[] a, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (a[key] < a[p[start + hint]]) { long maxOfs = hint + 1; while (ofs < maxOfs && a[key] < a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && a[key] >= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this long[] p, float[] a, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (a[pivot] < a[p[mid]]) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderAscending( this long[] p, float[] a, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] < a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] < a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] >= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this float[] a, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, float[] a, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, float[] a, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, float[] a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this float[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, float[] a) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, float[] a, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, float[] a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, lo, hi, cm); PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this float[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, float[] a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] > a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]] > a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] > a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, float[] a) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] > a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]] > a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] > a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this float[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a); return p; } public static void PermutationSmoothSortDescending( this int[] p, float[] a) { PermutationSmoothSortDescendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, float[] a, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, float[] a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, float[] a, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val] <= a[p[lf]] && a[val] <= a[p[rt]]) break; if (a[p[lf]] <= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, float[] a, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson] >= a[val]) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]] <= a[vstepson] || a[p[lf]] <= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this float[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, float[] a) { PermutationTimSortDescending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, float[] a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); PermutationBinarySortDescending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseFloatPermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseFloatPermDesc(ti); } private static void MergeCollapseFloatPermDesc(this TimSortInfoPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtFloatPermDesc(ti, n); else break; } } private static void MergeForceCollapseFloatPermDesc(this TimSortInfoPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatPermDesc(ti, n); } } private static void MergeAtFloatPermDesc(this TimSortInfoPerm ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoFloatPermDesc(ti, start1, len1, start2, len2); else MergeHiFloatPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoFloatPermDesc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]] > a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiFloatPermDesc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]] > a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, float[] a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (a[key] < a[p[start + hint]]) { int maxOfs = len - hint; while (ofs < maxOfs && a[key] < a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] >= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, float[] a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (a[key] > a[p[start + hint]]) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] > a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key] <= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, float[] a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot] > a[p[mid]]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, float[] a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] > a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] > a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] <= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianDescendingLong( this float[] a, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianDescending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this long[] p, float[] a, long med) { long last = p.LongLength - 1; PermutationQuickMedianDescending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this long[] p, float[] a, long beginIncl, long endExcl, long med) { PermutationQuickMedianDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this long[] p, float[] a, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortDescendingLong( this float[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortDescending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, float[] a) { long last = p.LongLength - 1; PermutationQuickSortDescending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, float[] a, long beginIncl, long endExcl) { PermutationQuickSortDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this long[] p, float[] a, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, lo, hi, cm); PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortDescendingLong( this float[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortDescending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, float[] a, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element] > a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1 + begin]] > a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] > a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, float[] a) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element] > a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1]] > a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] > a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortDescendingLong( this float[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortDescending(p, a); return p; } public static void PermutationSmoothSortDescending( this long[] p, float[] a) { PermutationSmoothSortDescendingInclusiveRange(p, a, 0, p.LongLength - 1); } public static void PermutationSmoothSortDescending( this long[] p, float[] a, long beginIncl, long endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this long[] p, float[] a, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this long[] p, float[] a, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[val] <= a[p[lf]] && a[val] <= a[p[rt]]) break; if (a[p[lf]] <= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this long[] p, float[] a, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (a[vstepson] >= a[val]) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[p[rt]] <= a[vstepson] || a[p[lf]] <= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortDescendingLong( this float[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortDescending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, float[] a) { PermutationTimSortDescending(p, a, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, float[] a, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); PermutationBinarySortDescending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLong(p, a); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseFloatPermLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseFloatPermLongDesc(ti); } private static void MergeCollapseFloatPermLongDesc(this TimSortInfoPermLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatPermLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtFloatPermLongDesc(ti, n); else break; } } private static void MergeForceCollapseFloatPermLongDesc(this TimSortInfoPermLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatPermLongDesc(ti, n); } } private static void MergeAtFloatPermLongDesc(this TimSortInfoPermLong ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightDescending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoFloatPermLongDesc(ti, start1, len1, start2, len2); else MergeHiFloatPermLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoFloatPermLongDesc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[p[idx2]] > a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiFloatPermLongDesc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[t[idx2]] > a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftDescending( this long[] p, float[] a, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (a[key] < a[p[start + hint]]) { long maxOfs = len - hint; while (ofs < maxOfs && a[key] < a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && a[key] >= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightDescending( this long[] p, float[] a, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (a[key] > a[p[start + hint]]) { long maxOfs = hint + 1; while (ofs < maxOfs && a[key] > a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && a[key] <= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this long[] p, float[] a, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (a[pivot] > a[p[mid]]) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderDescending( this long[] p, float[] a, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] > a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] > a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] <= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } #endregion #region Sort/Median for double[] /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this double[] a, long med) { long last = a.LongLength - 1; QuickMedianAscending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this double[] a, long beginIncl, long endExcl, long med) { QuickMedianAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this double[] a, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1] > a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] > a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] > a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] > a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] > a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai > p2) { while (a[hi] > p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] > p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo] == p1) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai < a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this double[] a) { long last = a.LongLength - 1; QuickSortAscending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this double[] a, long beginIncl, long endExcl) { QuickSortAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this double[] a, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1] > a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] > a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] > a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] > a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] > a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai > p2) { while (a[hi] > p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] > p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); { while (a[lo] == p1) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, lo, hi, cm); QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai < a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this double[] a, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element < a[i2 + begin]) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1 + begin] < a[i2 + begin]) ? i2 : i1; // smaller child if (a[ni + begin] < element) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this double[] a) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element < a[i2]) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1] < a[i2]) ? i2 : i1; // smaller child if (a[ni] < element) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this double[] a) { SmoothSortAscendingInclusiveRange(a, 0, a.LongLength - 1); } public static void SmoothSortAscending( this double[] a, long beginIncl, long endExcl) { SmoothSortAscendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this double[] a, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); else SmoothSortAscendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortAscendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this double[] a, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (val >= a[lf] && val >= a[rt]) break; if (a[lf] >= a[rt]) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this double[] a, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (vstepson <= val) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[rt] >= vstepson || a[lf] >= vstepson) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this double[] a) { TimSortAscending(a, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this double[] a, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, lo, hi); BinarySortAscending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLong(a); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderAscending(a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortAscending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseDoubleLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseDoubleLongAsc(ti); } private static void MergeCollapseDoubleLongAsc(this TimSortInfoLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoubleLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtDoubleLongAsc(ti, n); else break; } } private static void MergeForceCollapseDoubleLongAsc(this TimSortInfoLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoubleLongAsc(ti, n); } } private static void MergeAtDoubleLongAsc(this TimSortInfoLong ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightAscending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoDoubleLongAsc(ti, start1, len1, start2, len2); else MergeHiDoubleLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoDoubleLongAsc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[idx2] < t[idx1]) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightAscending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiDoubleLongAsc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (t[idx2] < a[idx1]) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftAscending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftAscending( this double[] a, double key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (key > a[start + hint]) { long maxOfs = len - hint; while (ofs < maxOfs && key > a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && key <= a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key > a[start + m]) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightAscending( this double[] a, double key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (key < a[start + hint]) { long maxOfs = hint + 1; while (ofs < maxOfs && key < a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && key >= a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key < a[start + m]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this double[] a, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (pivot < a[mid]) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderAscending( this double[] a, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++] < a[beginIncl]) { while (runHi < endExcl && a[runHi] < a[runHi - 1]) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi] >= a[runHi - 1]) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this double[] a, long med) { long last = a.LongLength - 1; QuickMedianDescending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this double[] a, long beginIncl, long endExcl, long med) { QuickMedianDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this double[] a, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1] < a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] < a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] < a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] < a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] < a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai < p2) { while (a[hi] < p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] < p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo] == p1) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai > a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this double[] a) { long last = a.LongLength - 1; QuickSortDescending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this double[] a, long beginIncl, long endExcl) { QuickSortDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this double[] a, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1] < a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] < a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] < a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] < a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] < a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai < p2) { while (a[hi] < p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] < p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); { while (a[lo] == p1) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, lo, hi, cm); QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai > a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this double[] a, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element > a[i2 + begin]) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1 + begin] > a[i2 + begin]) ? i2 : i1; // smaller child if (a[ni + begin] > element) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this double[] a) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element > a[i2]) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1] > a[i2]) ? i2 : i1; // smaller child if (a[ni] > element) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this double[] a) { SmoothSortDescendingInclusiveRange(a, 0, a.LongLength - 1); } public static void SmoothSortDescending( this double[] a, long beginIncl, long endExcl) { SmoothSortDescendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this double[] a, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); else SmoothSortDescendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortDescendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this double[] a, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (val <= a[lf] && val <= a[rt]) break; if (a[lf] <= a[rt]) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this double[] a, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (vstepson >= val) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[rt] <= vstepson || a[lf] <= vstepson) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this double[] a) { TimSortDescending(a, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this double[] a, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, lo, hi); BinarySortDescending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLong(a); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderDescending(a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortDescending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseDoubleLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseDoubleLongDesc(ti); } private static void MergeCollapseDoubleLongDesc(this TimSortInfoLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoubleLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtDoubleLongDesc(ti, n); else break; } } private static void MergeForceCollapseDoubleLongDesc(this TimSortInfoLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoubleLongDesc(ti, n); } } private static void MergeAtDoubleLongDesc(this TimSortInfoLong ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightDescending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoDoubleLongDesc(ti, start1, len1, start2, len2); else MergeHiDoubleLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoDoubleLongDesc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[idx2] > t[idx1]) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightDescending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiDoubleLongDesc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (t[idx2] > a[idx1]) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftDescending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftDescending( this double[] a, double key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (key < a[start + hint]) { long maxOfs = len - hint; while (ofs < maxOfs && key < a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && key >= a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key < a[start + m]) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightDescending( this double[] a, double key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (key > a[start + hint]) { long maxOfs = hint + 1; while (ofs < maxOfs && key > a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && key <= a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key > a[start + m]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this double[] a, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (pivot > a[mid]) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderDescending( this double[] a, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++] > a[beginIncl]) { while (runHi < endExcl && a[runHi] > a[runHi - 1]) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi] <= a[runHi - 1]) runHi++; } return runHi - beginIncl; } #endregion #region Permutation Sort/Median for double[] /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this double[] a, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, double[] a, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, double[] a, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, double[] a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this double[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, double[] a) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, double[] a, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, double[] a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, lo, hi, cm); PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this double[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, double[] a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] < a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]] < a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] < a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, double[] a) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] < a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]] < a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] < a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this double[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a); return p; } public static void PermutationSmoothSortAscending( this int[] p, double[] a) { PermutationSmoothSortAscendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, double[] a, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, double[] a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, double[] a, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val] >= a[p[lf]] && a[val] >= a[p[rt]]) break; if (a[p[lf]] >= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, double[] a, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson] <= a[val]) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]] >= a[vstepson] || a[p[lf]] >= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this double[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, double[] a) { PermutationTimSortAscending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, double[] a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); PermutationBinarySortAscending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseDoublePermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseDoublePermAsc(ti); } private static void MergeCollapseDoublePermAsc(this TimSortInfoPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoublePermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtDoublePermAsc(ti, n); else break; } } private static void MergeForceCollapseDoublePermAsc(this TimSortInfoPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoublePermAsc(ti, n); } } private static void MergeAtDoublePermAsc(this TimSortInfoPerm ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoDoublePermAsc(ti, start1, len1, start2, len2); else MergeHiDoublePermAsc(ti, start1, len1, start2, len2); } private static void MergeLoDoublePermAsc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]] < a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiDoublePermAsc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]] < a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, double[] a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (a[key] > a[p[start + hint]]) { int maxOfs = len - hint; while (ofs < maxOfs && a[key] > a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] <= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, double[] a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (a[key] < a[p[start + hint]]) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] < a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key] >= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, double[] a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot] < a[p[mid]]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, double[] a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] < a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] < a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] >= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianAscendingLong( this double[] a, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianAscending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this long[] p, double[] a, long med) { long last = p.LongLength - 1; PermutationQuickMedianAscending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this long[] p, double[] a, long beginIncl, long endExcl, long med) { PermutationQuickMedianAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this long[] p, double[] a, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortAscendingLong( this double[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortAscending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, double[] a) { long last = p.LongLength - 1; PermutationQuickSortAscending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, double[] a, long beginIncl, long endExcl) { PermutationQuickSortAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this long[] p, double[] a, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, lo, hi, cm); PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortAscendingLong( this double[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortAscending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, double[] a, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element] < a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1 + begin]] < a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] < a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, double[] a) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element] < a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1]] < a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] < a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortAscendingLong( this double[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortAscending(p, a); return p; } public static void PermutationSmoothSortAscending( this long[] p, double[] a) { PermutationSmoothSortAscendingInclusiveRange(p, a, 0, p.LongLength - 1); } public static void PermutationSmoothSortAscending( this long[] p, double[] a, long beginIncl, long endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this long[] p, double[] a, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this long[] p, double[] a, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[val] >= a[p[lf]] && a[val] >= a[p[rt]]) break; if (a[p[lf]] >= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this long[] p, double[] a, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (a[vstepson] <= a[val]) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[p[rt]] >= a[vstepson] || a[p[lf]] >= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortAscendingLong( this double[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortAscending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, double[] a) { PermutationTimSortAscending(p, a, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, double[] a, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); PermutationBinarySortAscending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLong(p, a); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseDoublePermLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseDoublePermLongAsc(ti); } private static void MergeCollapseDoublePermLongAsc(this TimSortInfoPermLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoublePermLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtDoublePermLongAsc(ti, n); else break; } } private static void MergeForceCollapseDoublePermLongAsc(this TimSortInfoPermLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoublePermLongAsc(ti, n); } } private static void MergeAtDoublePermLongAsc(this TimSortInfoPermLong ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightAscending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoDoublePermLongAsc(ti, start1, len1, start2, len2); else MergeHiDoublePermLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoDoublePermLongAsc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[p[idx2]] < a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiDoublePermLongAsc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[t[idx2]] < a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftAscending( this long[] p, double[] a, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (a[key] > a[p[start + hint]]) { long maxOfs = len - hint; while (ofs < maxOfs && a[key] > a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && a[key] <= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightAscending( this long[] p, double[] a, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (a[key] < a[p[start + hint]]) { long maxOfs = hint + 1; while (ofs < maxOfs && a[key] < a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && a[key] >= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this long[] p, double[] a, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (a[pivot] < a[p[mid]]) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderAscending( this long[] p, double[] a, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] < a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] < a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] >= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this double[] a, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, double[] a, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, double[] a, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, double[] a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this double[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, double[] a) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, double[] a, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, double[] a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, lo, hi, cm); PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this double[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, double[] a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] > a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]] > a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] > a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, double[] a) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] > a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]] > a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] > a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this double[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a); return p; } public static void PermutationSmoothSortDescending( this int[] p, double[] a) { PermutationSmoothSortDescendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, double[] a, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, double[] a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, double[] a, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val] <= a[p[lf]] && a[val] <= a[p[rt]]) break; if (a[p[lf]] <= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, double[] a, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson] >= a[val]) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]] <= a[vstepson] || a[p[lf]] <= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this double[] a) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, double[] a) { PermutationTimSortDescending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, double[] a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); PermutationBinarySortDescending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseDoublePermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseDoublePermDesc(ti); } private static void MergeCollapseDoublePermDesc(this TimSortInfoPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoublePermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtDoublePermDesc(ti, n); else break; } } private static void MergeForceCollapseDoublePermDesc(this TimSortInfoPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoublePermDesc(ti, n); } } private static void MergeAtDoublePermDesc(this TimSortInfoPerm ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoDoublePermDesc(ti, start1, len1, start2, len2); else MergeHiDoublePermDesc(ti, start1, len1, start2, len2); } private static void MergeLoDoublePermDesc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]] > a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiDoublePermDesc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]] > a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, double[] a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (a[key] < a[p[start + hint]]) { int maxOfs = len - hint; while (ofs < maxOfs && a[key] < a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] >= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, double[] a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (a[key] > a[p[start + hint]]) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] > a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key] <= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, double[] a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot] > a[p[mid]]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, double[] a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] > a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] > a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] <= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianDescendingLong( this double[] a, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianDescending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this long[] p, double[] a, long med) { long last = p.LongLength - 1; PermutationQuickMedianDescending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this long[] p, double[] a, long beginIncl, long endExcl, long med) { PermutationQuickMedianDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this long[] p, double[] a, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortDescendingLong( this double[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortDescending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, double[] a) { long last = p.LongLength - 1; PermutationQuickSortDescending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, double[] a, long beginIncl, long endExcl) { PermutationQuickSortDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this long[] p, double[] a, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, lo, hi, cm); PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortDescendingLong( this double[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortDescending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, double[] a, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element] > a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1 + begin]] > a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] > a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, double[] a) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element] > a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1]] > a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] > a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortDescendingLong( this double[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortDescending(p, a); return p; } public static void PermutationSmoothSortDescending( this long[] p, double[] a) { PermutationSmoothSortDescendingInclusiveRange(p, a, 0, p.LongLength - 1); } public static void PermutationSmoothSortDescending( this long[] p, double[] a, long beginIncl, long endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this long[] p, double[] a, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this long[] p, double[] a, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[val] <= a[p[lf]] && a[val] <= a[p[rt]]) break; if (a[p[lf]] <= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this long[] p, double[] a, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (a[vstepson] >= a[val]) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[p[rt]] <= a[vstepson] || a[p[lf]] <= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortDescendingLong( this double[] a) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortDescending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, double[] a) { PermutationTimSortDescending(p, a, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, double[] a, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); PermutationBinarySortDescending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLong(p, a); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseDoublePermLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseDoublePermLongDesc(ti); } private static void MergeCollapseDoublePermLongDesc(this TimSortInfoPermLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoublePermLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtDoublePermLongDesc(ti, n); else break; } } private static void MergeForceCollapseDoublePermLongDesc(this TimSortInfoPermLong ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoublePermLongDesc(ti, n); } } private static void MergeAtDoublePermLongDesc(this TimSortInfoPermLong ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightDescending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoDoublePermLongDesc(ti, start1, len1, start2, len2); else MergeHiDoublePermLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoDoublePermLongDesc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[p[idx2]] > a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiDoublePermLongDesc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[t[idx2]] > a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftDescending( this long[] p, double[] a, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (a[key] < a[p[start + hint]]) { long maxOfs = len - hint; while (ofs < maxOfs && a[key] < a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && a[key] >= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightDescending( this long[] p, double[] a, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (a[key] > a[p[start + hint]]) { long maxOfs = hint + 1; while (ofs < maxOfs && a[key] > a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && a[key] <= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this long[] p, double[] a, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (a[pivot] > a[p[mid]]) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderDescending( this long[] p, double[] a, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] > a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] > a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] <= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } #endregion #region Sort/Median for List /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this List a, int med) { int last = a.Count - 1; QuickMedianAscending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this List a, int beginIncl, int endExcl, int med) { QuickMedianAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this List a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1] > a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] > a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] > a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] > a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] > a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai > p2) { while (a[hi] > p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] > p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo] == p1) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai < a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this List a) { int last = a.Count - 1; QuickSortAscending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this List a, int beginIncl, int endExcl) { QuickSortAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this List a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1] > a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] > a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] > a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] > a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] > a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai > p2) { while (a[hi] > p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] > p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); { while (a[lo] == p1) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, lo, hi, cm); QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai < a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element < a[i2 + begin]) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1 + begin] < a[i2 + begin]) ? i2 : i1; // smaller child if (a[ni + begin] < element) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element < a[i2]) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1] < a[i2]) ? i2 : i1; // smaller child if (a[ni] < element) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this List a) { SmoothSortAscendingInclusiveRange(a, 0, a.Count - 1); } public static void SmoothSortAscending( this List a, int beginIncl, int endExcl) { SmoothSortAscendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this List a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); else SmoothSortAscendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortAscendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this List a, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (val >= a[lf] && val >= a[rt]) break; if (a[lf] >= a[rt]) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this List a, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (vstepson <= val) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[rt] >= vstepson || a[lf] >= vstepson) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a) { TimSortAscending(a, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, lo, hi); BinarySortAscending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoList(a); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderAscending(a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortAscending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseIntListAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseIntListAsc(ti); } private static void MergeCollapseIntListAsc(this TimSortInfoList ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntListAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtIntListAsc(ti, n); else break; } } private static void MergeForceCollapseIntListAsc(this TimSortInfoList ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntListAsc(ti, n); } } private static void MergeAtIntListAsc(this TimSortInfoList ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightAscending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoIntListAsc(ti, start1, len1, start2, len2); else MergeHiIntListAsc(ti, start1, len1, start2, len2); } private static void MergeLoIntListAsc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[idx2] < t[idx1]) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightAscending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiIntListAsc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (t[idx2] < a[idx1]) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftAscending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftAscending( this List a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (key > a[start + hint]) { int maxOfs = len - hint; while (ofs < maxOfs && key > a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && key <= a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key > a[start + m]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightAscending( this List a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (key < a[start + hint]) { int maxOfs = hint + 1; while (ofs < maxOfs && key < a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && key >= a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key < a[start + m]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this List a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (pivot < a[mid]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderAscending( this List a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++] < a[beginIncl]) { while (runHi < endExcl && a[runHi] < a[runHi - 1]) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi] >= a[runHi - 1]) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this List a, int med) { int last = a.Count - 1; QuickMedianDescending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this List a, int beginIncl, int endExcl, int med) { QuickMedianDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this List a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1] < a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] < a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] < a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] < a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] < a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai < p2) { while (a[hi] < p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] < p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo] == p1) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai > a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this List a) { int last = a.Count - 1; QuickSortDescending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this List a, int beginIncl, int endExcl) { QuickSortDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this List a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1] < a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] < a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] < a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] < a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] < a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai < p2) { while (a[hi] < p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] < p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); { while (a[lo] == p1) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, lo, hi, cm); QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai > a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element > a[i2 + begin]) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1 + begin] > a[i2 + begin]) ? i2 : i1; // smaller child if (a[ni + begin] > element) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element > a[i2]) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1] > a[i2]) ? i2 : i1; // smaller child if (a[ni] > element) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this List a) { SmoothSortDescendingInclusiveRange(a, 0, a.Count - 1); } public static void SmoothSortDescending( this List a, int beginIncl, int endExcl) { SmoothSortDescendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this List a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); else SmoothSortDescendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortDescendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this List a, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (val <= a[lf] && val <= a[rt]) break; if (a[lf] <= a[rt]) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this List a, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (vstepson >= val) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[rt] <= vstepson || a[lf] <= vstepson) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a) { TimSortDescending(a, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, lo, hi); BinarySortDescending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoList(a); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderDescending(a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortDescending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseIntListDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseIntListDesc(ti); } private static void MergeCollapseIntListDesc(this TimSortInfoList ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntListDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtIntListDesc(ti, n); else break; } } private static void MergeForceCollapseIntListDesc(this TimSortInfoList ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntListDesc(ti, n); } } private static void MergeAtIntListDesc(this TimSortInfoList ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightDescending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoIntListDesc(ti, start1, len1, start2, len2); else MergeHiIntListDesc(ti, start1, len1, start2, len2); } private static void MergeLoIntListDesc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[idx2] > t[idx1]) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightDescending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiIntListDesc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (t[idx2] > a[idx1]) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftDescending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftDescending( this List a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (key < a[start + hint]) { int maxOfs = len - hint; while (ofs < maxOfs && key < a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && key >= a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key < a[start + m]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightDescending( this List a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (key > a[start + hint]) { int maxOfs = hint + 1; while (ofs < maxOfs && key > a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && key <= a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key > a[start + m]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this List a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (pivot > a[mid]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderDescending( this List a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++] > a[beginIncl]) { while (runHi < endExcl && a[runHi] > a[runHi - 1]) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi] <= a[runHi - 1]) runHi++; } return runHi - beginIncl; } #endregion #region Permutation Sort/Median for List /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this List a, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, List a, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, List a, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, List a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, List a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, lo, hi, cm); PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] < a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]] < a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] < a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] < a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]] < a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] < a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a); return p; } public static void PermutationSmoothSortAscending( this int[] p, List a) { PermutationSmoothSortAscendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, List a, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, List a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, List a, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val] >= a[p[lf]] && a[val] >= a[p[rt]]) break; if (a[p[lf]] >= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, List a, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson] <= a[val]) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]] >= a[vstepson] || a[p[lf]] >= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a) { PermutationTimSortAscending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); PermutationBinarySortAscending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseIntListPermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseIntListPermAsc(ti); } private static void MergeCollapseIntListPermAsc(this TimSortInfoListPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntListPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtIntListPermAsc(ti, n); else break; } } private static void MergeForceCollapseIntListPermAsc(this TimSortInfoListPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntListPermAsc(ti, n); } } private static void MergeAtIntListPermAsc(this TimSortInfoListPerm ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoIntListPermAsc(ti, start1, len1, start2, len2); else MergeHiIntListPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoIntListPermAsc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]] < a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightAscending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiIntListPermAsc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]] < a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftAscending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, List a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (a[key] > a[p[start + hint]]) { int maxOfs = len - hint; while (ofs < maxOfs && a[key] > a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] <= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, List a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (a[key] < a[p[start + hint]]) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] < a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key] >= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, List a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot] < a[p[mid]]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, List a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] < a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] < a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] >= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this List a, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, List a, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, List a, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, List a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, List a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, lo, hi, cm); PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] > a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]] > a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] > a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] > a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]] > a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] > a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a); return p; } public static void PermutationSmoothSortDescending( this int[] p, List a) { PermutationSmoothSortDescendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, List a, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, List a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, List a, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val] <= a[p[lf]] && a[val] <= a[p[rt]]) break; if (a[p[lf]] <= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, List a, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson] >= a[val]) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]] <= a[vstepson] || a[p[lf]] <= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a) { PermutationTimSortDescending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); PermutationBinarySortDescending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseIntListPermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseIntListPermDesc(ti); } private static void MergeCollapseIntListPermDesc(this TimSortInfoListPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntListPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtIntListPermDesc(ti, n); else break; } } private static void MergeForceCollapseIntListPermDesc(this TimSortInfoListPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtIntListPermDesc(ti, n); } } private static void MergeAtIntListPermDesc(this TimSortInfoListPerm ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoIntListPermDesc(ti, start1, len1, start2, len2); else MergeHiIntListPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoIntListPermDesc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]] > a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightDescending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiIntListPermDesc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]] > a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftDescending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, List a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (a[key] < a[p[start + hint]]) { int maxOfs = len - hint; while (ofs < maxOfs && a[key] < a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] >= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, List a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (a[key] > a[p[start + hint]]) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] > a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key] <= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, List a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot] > a[p[mid]]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, List a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] > a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] > a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] <= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } #endregion #region Sort/Median for List /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this List a, int med) { int last = a.Count - 1; QuickMedianAscending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this List a, int beginIncl, int endExcl, int med) { QuickMedianAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this List a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1] > a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] > a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] > a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] > a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] > a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai > p2) { while (a[hi] > p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] > p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo] == p1) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai < a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this List a) { int last = a.Count - 1; QuickSortAscending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this List a, int beginIncl, int endExcl) { QuickSortAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this List a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1] > a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] > a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] > a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] > a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] > a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai > p2) { while (a[hi] > p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] > p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); { while (a[lo] == p1) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, lo, hi, cm); QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai < a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element < a[i2 + begin]) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1 + begin] < a[i2 + begin]) ? i2 : i1; // smaller child if (a[ni + begin] < element) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element < a[i2]) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1] < a[i2]) ? i2 : i1; // smaller child if (a[ni] < element) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this List a) { SmoothSortAscendingInclusiveRange(a, 0, a.Count - 1); } public static void SmoothSortAscending( this List a, int beginIncl, int endExcl) { SmoothSortAscendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this List a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); else SmoothSortAscendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortAscendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this List a, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (val >= a[lf] && val >= a[rt]) break; if (a[lf] >= a[rt]) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this List a, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (vstepson <= val) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[rt] >= vstepson || a[lf] >= vstepson) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a) { TimSortAscending(a, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, lo, hi); BinarySortAscending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoList(a); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderAscending(a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortAscending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongListAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongListAsc(ti); } private static void MergeCollapseLongListAsc(this TimSortInfoList ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongListAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongListAsc(ti, n); else break; } } private static void MergeForceCollapseLongListAsc(this TimSortInfoList ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongListAsc(ti, n); } } private static void MergeAtLongListAsc(this TimSortInfoList ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightAscending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongListAsc(ti, start1, len1, start2, len2); else MergeHiLongListAsc(ti, start1, len1, start2, len2); } private static void MergeLoLongListAsc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[idx2] < t[idx1]) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightAscending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiLongListAsc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (t[idx2] < a[idx1]) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftAscending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftAscending( this List a, long key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (key > a[start + hint]) { int maxOfs = len - hint; while (ofs < maxOfs && key > a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && key <= a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key > a[start + m]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightAscending( this List a, long key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (key < a[start + hint]) { int maxOfs = hint + 1; while (ofs < maxOfs && key < a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && key >= a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key < a[start + m]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this List a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (pivot < a[mid]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderAscending( this List a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++] < a[beginIncl]) { while (runHi < endExcl && a[runHi] < a[runHi - 1]) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi] >= a[runHi - 1]) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this List a, int med) { int last = a.Count - 1; QuickMedianDescending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this List a, int beginIncl, int endExcl, int med) { QuickMedianDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this List a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1] < a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] < a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] < a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] < a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] < a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai < p2) { while (a[hi] < p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] < p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo] == p1) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai > a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this List a) { int last = a.Count - 1; QuickSortDescending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this List a, int beginIncl, int endExcl) { QuickSortDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this List a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1] < a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] < a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] < a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] < a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] < a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai < p2) { while (a[hi] < p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] < p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); { while (a[lo] == p1) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, lo, hi, cm); QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai > a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element > a[i2 + begin]) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1 + begin] > a[i2 + begin]) ? i2 : i1; // smaller child if (a[ni + begin] > element) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element > a[i2]) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1] > a[i2]) ? i2 : i1; // smaller child if (a[ni] > element) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this List a) { SmoothSortDescendingInclusiveRange(a, 0, a.Count - 1); } public static void SmoothSortDescending( this List a, int beginIncl, int endExcl) { SmoothSortDescendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this List a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); else SmoothSortDescendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortDescendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this List a, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (val <= a[lf] && val <= a[rt]) break; if (a[lf] <= a[rt]) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this List a, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (vstepson >= val) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[rt] <= vstepson || a[lf] <= vstepson) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a) { TimSortDescending(a, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, lo, hi); BinarySortDescending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoList(a); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderDescending(a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortDescending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongListDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongListDesc(ti); } private static void MergeCollapseLongListDesc(this TimSortInfoList ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongListDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongListDesc(ti, n); else break; } } private static void MergeForceCollapseLongListDesc(this TimSortInfoList ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongListDesc(ti, n); } } private static void MergeAtLongListDesc(this TimSortInfoList ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightDescending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongListDesc(ti, start1, len1, start2, len2); else MergeHiLongListDesc(ti, start1, len1, start2, len2); } private static void MergeLoLongListDesc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[idx2] > t[idx1]) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightDescending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiLongListDesc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (t[idx2] > a[idx1]) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftDescending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftDescending( this List a, long key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (key < a[start + hint]) { int maxOfs = len - hint; while (ofs < maxOfs && key < a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && key >= a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key < a[start + m]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightDescending( this List a, long key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (key > a[start + hint]) { int maxOfs = hint + 1; while (ofs < maxOfs && key > a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && key <= a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key > a[start + m]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this List a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (pivot > a[mid]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderDescending( this List a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++] > a[beginIncl]) { while (runHi < endExcl && a[runHi] > a[runHi - 1]) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi] <= a[runHi - 1]) runHi++; } return runHi - beginIncl; } #endregion #region Permutation Sort/Median for List /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this List a, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, List a, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, List a, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, List a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, List a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, lo, hi, cm); PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] < a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]] < a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] < a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] < a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]] < a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] < a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a); return p; } public static void PermutationSmoothSortAscending( this int[] p, List a) { PermutationSmoothSortAscendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, List a, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, List a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, List a, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val] >= a[p[lf]] && a[val] >= a[p[rt]]) break; if (a[p[lf]] >= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, List a, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson] <= a[val]) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]] >= a[vstepson] || a[p[lf]] >= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a) { PermutationTimSortAscending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); PermutationBinarySortAscending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongListPermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongListPermAsc(ti); } private static void MergeCollapseLongListPermAsc(this TimSortInfoListPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongListPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongListPermAsc(ti, n); else break; } } private static void MergeForceCollapseLongListPermAsc(this TimSortInfoListPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongListPermAsc(ti, n); } } private static void MergeAtLongListPermAsc(this TimSortInfoListPerm ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongListPermAsc(ti, start1, len1, start2, len2); else MergeHiLongListPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoLongListPermAsc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]] < a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightAscending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiLongListPermAsc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]] < a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftAscending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, List a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (a[key] > a[p[start + hint]]) { int maxOfs = len - hint; while (ofs < maxOfs && a[key] > a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] <= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, List a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (a[key] < a[p[start + hint]]) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] < a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key] >= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, List a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot] < a[p[mid]]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, List a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] < a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] < a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] >= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this List a, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, List a, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, List a, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, List a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, List a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, lo, hi, cm); PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] > a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]] > a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] > a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] > a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]] > a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] > a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a); return p; } public static void PermutationSmoothSortDescending( this int[] p, List a) { PermutationSmoothSortDescendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, List a, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, List a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, List a, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val] <= a[p[lf]] && a[val] <= a[p[rt]]) break; if (a[p[lf]] <= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, List a, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson] >= a[val]) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]] <= a[vstepson] || a[p[lf]] <= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a) { PermutationTimSortDescending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); PermutationBinarySortDescending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongListPermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongListPermDesc(ti); } private static void MergeCollapseLongListPermDesc(this TimSortInfoListPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongListPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongListPermDesc(ti, n); else break; } } private static void MergeForceCollapseLongListPermDesc(this TimSortInfoListPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongListPermDesc(ti, n); } } private static void MergeAtLongListPermDesc(this TimSortInfoListPerm ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongListPermDesc(ti, start1, len1, start2, len2); else MergeHiLongListPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoLongListPermDesc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]] > a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightDescending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiLongListPermDesc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]] > a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftDescending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, List a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (a[key] < a[p[start + hint]]) { int maxOfs = len - hint; while (ofs < maxOfs && a[key] < a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] >= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, List a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (a[key] > a[p[start + hint]]) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] > a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key] <= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, List a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot] > a[p[mid]]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, List a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] > a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] > a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] <= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } #endregion #region Sort/Median for List /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this List a, int med) { int last = a.Count - 1; QuickMedianAscending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this List a, int beginIncl, int endExcl, int med) { QuickMedianAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this List a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1] > a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] > a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] > a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] > a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] > a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai > p2) { while (a[hi] > p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] > p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo] == p1) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai < a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this List a) { int last = a.Count - 1; QuickSortAscending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this List a, int beginIncl, int endExcl) { QuickSortAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this List a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1] > a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] > a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] > a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] > a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] > a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai > p2) { while (a[hi] > p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] > p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); { while (a[lo] == p1) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, lo, hi, cm); QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai < a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element < a[i2 + begin]) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1 + begin] < a[i2 + begin]) ? i2 : i1; // smaller child if (a[ni + begin] < element) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element < a[i2]) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1] < a[i2]) ? i2 : i1; // smaller child if (a[ni] < element) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this List a) { SmoothSortAscendingInclusiveRange(a, 0, a.Count - 1); } public static void SmoothSortAscending( this List a, int beginIncl, int endExcl) { SmoothSortAscendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this List a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); else SmoothSortAscendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortAscendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this List a, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (val >= a[lf] && val >= a[rt]) break; if (a[lf] >= a[rt]) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this List a, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (vstepson <= val) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[rt] >= vstepson || a[lf] >= vstepson) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a) { TimSortAscending(a, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, lo, hi); BinarySortAscending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoList(a); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderAscending(a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortAscending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseFloatListAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseFloatListAsc(ti); } private static void MergeCollapseFloatListAsc(this TimSortInfoList ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatListAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtFloatListAsc(ti, n); else break; } } private static void MergeForceCollapseFloatListAsc(this TimSortInfoList ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatListAsc(ti, n); } } private static void MergeAtFloatListAsc(this TimSortInfoList ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightAscending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoFloatListAsc(ti, start1, len1, start2, len2); else MergeHiFloatListAsc(ti, start1, len1, start2, len2); } private static void MergeLoFloatListAsc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[idx2] < t[idx1]) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightAscending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiFloatListAsc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (t[idx2] < a[idx1]) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftAscending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftAscending( this List a, float key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (key > a[start + hint]) { int maxOfs = len - hint; while (ofs < maxOfs && key > a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && key <= a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key > a[start + m]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightAscending( this List a, float key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (key < a[start + hint]) { int maxOfs = hint + 1; while (ofs < maxOfs && key < a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && key >= a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key < a[start + m]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this List a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (pivot < a[mid]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderAscending( this List a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++] < a[beginIncl]) { while (runHi < endExcl && a[runHi] < a[runHi - 1]) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi] >= a[runHi - 1]) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this List a, int med) { int last = a.Count - 1; QuickMedianDescending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this List a, int beginIncl, int endExcl, int med) { QuickMedianDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this List a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1] < a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] < a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] < a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] < a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] < a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai < p2) { while (a[hi] < p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] < p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo] == p1) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai > a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this List a) { int last = a.Count - 1; QuickSortDescending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this List a, int beginIncl, int endExcl) { QuickSortDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this List a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1] < a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] < a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] < a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] < a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] < a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai < p2) { while (a[hi] < p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] < p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); { while (a[lo] == p1) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, lo, hi, cm); QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai > a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element > a[i2 + begin]) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1 + begin] > a[i2 + begin]) ? i2 : i1; // smaller child if (a[ni + begin] > element) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element > a[i2]) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1] > a[i2]) ? i2 : i1; // smaller child if (a[ni] > element) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this List a) { SmoothSortDescendingInclusiveRange(a, 0, a.Count - 1); } public static void SmoothSortDescending( this List a, int beginIncl, int endExcl) { SmoothSortDescendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this List a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); else SmoothSortDescendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortDescendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this List a, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (val <= a[lf] && val <= a[rt]) break; if (a[lf] <= a[rt]) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this List a, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (vstepson >= val) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[rt] <= vstepson || a[lf] <= vstepson) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a) { TimSortDescending(a, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, lo, hi); BinarySortDescending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoList(a); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderDescending(a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortDescending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseFloatListDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseFloatListDesc(ti); } private static void MergeCollapseFloatListDesc(this TimSortInfoList ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatListDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtFloatListDesc(ti, n); else break; } } private static void MergeForceCollapseFloatListDesc(this TimSortInfoList ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatListDesc(ti, n); } } private static void MergeAtFloatListDesc(this TimSortInfoList ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightDescending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoFloatListDesc(ti, start1, len1, start2, len2); else MergeHiFloatListDesc(ti, start1, len1, start2, len2); } private static void MergeLoFloatListDesc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[idx2] > t[idx1]) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightDescending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiFloatListDesc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (t[idx2] > a[idx1]) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftDescending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftDescending( this List a, float key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (key < a[start + hint]) { int maxOfs = len - hint; while (ofs < maxOfs && key < a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && key >= a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key < a[start + m]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightDescending( this List a, float key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (key > a[start + hint]) { int maxOfs = hint + 1; while (ofs < maxOfs && key > a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && key <= a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key > a[start + m]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this List a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (pivot > a[mid]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderDescending( this List a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++] > a[beginIncl]) { while (runHi < endExcl && a[runHi] > a[runHi - 1]) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi] <= a[runHi - 1]) runHi++; } return runHi - beginIncl; } #endregion #region Permutation Sort/Median for List /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this List a, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, List a, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, List a, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, List a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, List a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, lo, hi, cm); PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] < a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]] < a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] < a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] < a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]] < a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] < a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a); return p; } public static void PermutationSmoothSortAscending( this int[] p, List a) { PermutationSmoothSortAscendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, List a, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, List a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, List a, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val] >= a[p[lf]] && a[val] >= a[p[rt]]) break; if (a[p[lf]] >= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, List a, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson] <= a[val]) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]] >= a[vstepson] || a[p[lf]] >= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a) { PermutationTimSortAscending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); PermutationBinarySortAscending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseFloatListPermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseFloatListPermAsc(ti); } private static void MergeCollapseFloatListPermAsc(this TimSortInfoListPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatListPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtFloatListPermAsc(ti, n); else break; } } private static void MergeForceCollapseFloatListPermAsc(this TimSortInfoListPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatListPermAsc(ti, n); } } private static void MergeAtFloatListPermAsc(this TimSortInfoListPerm ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoFloatListPermAsc(ti, start1, len1, start2, len2); else MergeHiFloatListPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoFloatListPermAsc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]] < a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightAscending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiFloatListPermAsc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]] < a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftAscending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, List a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (a[key] > a[p[start + hint]]) { int maxOfs = len - hint; while (ofs < maxOfs && a[key] > a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] <= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, List a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (a[key] < a[p[start + hint]]) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] < a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key] >= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, List a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot] < a[p[mid]]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, List a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] < a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] < a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] >= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this List a, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, List a, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, List a, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, List a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, List a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, lo, hi, cm); PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] > a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]] > a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] > a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] > a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]] > a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] > a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a); return p; } public static void PermutationSmoothSortDescending( this int[] p, List a) { PermutationSmoothSortDescendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, List a, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, List a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, List a, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val] <= a[p[lf]] && a[val] <= a[p[rt]]) break; if (a[p[lf]] <= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, List a, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson] >= a[val]) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]] <= a[vstepson] || a[p[lf]] <= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a) { PermutationTimSortDescending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); PermutationBinarySortDescending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseFloatListPermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseFloatListPermDesc(ti); } private static void MergeCollapseFloatListPermDesc(this TimSortInfoListPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatListPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtFloatListPermDesc(ti, n); else break; } } private static void MergeForceCollapseFloatListPermDesc(this TimSortInfoListPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtFloatListPermDesc(ti, n); } } private static void MergeAtFloatListPermDesc(this TimSortInfoListPerm ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoFloatListPermDesc(ti, start1, len1, start2, len2); else MergeHiFloatListPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoFloatListPermDesc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]] > a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightDescending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiFloatListPermDesc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]] > a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftDescending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, List a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (a[key] < a[p[start + hint]]) { int maxOfs = len - hint; while (ofs < maxOfs && a[key] < a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] >= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, List a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (a[key] > a[p[start + hint]]) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] > a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key] <= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, List a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot] > a[p[mid]]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, List a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] > a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] > a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] <= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } #endregion #region Sort/Median for List /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this List a, int med) { int last = a.Count - 1; QuickMedianAscending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this List a, int beginIncl, int endExcl, int med) { QuickMedianAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this List a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1] > a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] > a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] > a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] > a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] > a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai > p2) { while (a[hi] > p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] > p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo] == p1) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai < a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this List a) { int last = a.Count - 1; QuickSortAscending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this List a, int beginIncl, int endExcl) { QuickSortAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this List a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1] > a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] > a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] > a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] > a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] > a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] > a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] > a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai > p2) { while (a[hi] > p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] > p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai < p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); { while (a[lo] == p1) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, lo, hi, cm); QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai < a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element < a[i2 + begin]) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1 + begin] < a[i2 + begin]) ? i2 : i1; // smaller child if (a[ni + begin] < element) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element < a[i2]) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1] < a[i2]) ? i2 : i1; // smaller child if (a[ni] < element) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this List a) { SmoothSortAscendingInclusiveRange(a, 0, a.Count - 1); } public static void SmoothSortAscending( this List a, int beginIncl, int endExcl) { SmoothSortAscendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this List a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); else SmoothSortAscendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortAscendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this List a, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (val >= a[lf] && val >= a[rt]) break; if (a[lf] >= a[rt]) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this List a, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (vstepson <= val) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[rt] >= vstepson || a[lf] >= vstepson) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a) { TimSortAscending(a, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, lo, hi); BinarySortAscending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoList(a); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderAscending(a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortAscending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseDoubleListAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseDoubleListAsc(ti); } private static void MergeCollapseDoubleListAsc(this TimSortInfoList ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoubleListAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtDoubleListAsc(ti, n); else break; } } private static void MergeForceCollapseDoubleListAsc(this TimSortInfoList ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoubleListAsc(ti, n); } } private static void MergeAtDoubleListAsc(this TimSortInfoList ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightAscending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoDoubleListAsc(ti, start1, len1, start2, len2); else MergeHiDoubleListAsc(ti, start1, len1, start2, len2); } private static void MergeLoDoubleListAsc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[idx2] < t[idx1]) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightAscending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiDoubleListAsc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (t[idx2] < a[idx1]) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftAscending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftAscending( this List a, double key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (key > a[start + hint]) { int maxOfs = len - hint; while (ofs < maxOfs && key > a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && key <= a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key > a[start + m]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightAscending( this List a, double key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (key < a[start + hint]) { int maxOfs = hint + 1; while (ofs < maxOfs && key < a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && key >= a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key < a[start + m]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this List a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (pivot < a[mid]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderAscending( this List a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++] < a[beginIncl]) { while (runHi < endExcl && a[runHi] < a[runHi - 1]) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi] >= a[runHi - 1]) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this List a, int med) { int last = a.Count - 1; QuickMedianDescending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this List a, int beginIncl, int endExcl, int med) { QuickMedianDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this List a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1] < a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] < a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] < a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] < a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] < a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai < p2) { while (a[hi] < p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] < p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo] == p1) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai > a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this List a) { int last = a.Count - 1; QuickSortDescending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this List a, int beginIncl, int endExcl) { QuickSortDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this List a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1] < a[e2]) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1] < a[e3]) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1] < a[e4]) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3] < a[e4]) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2] < a[e5]) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2] < a[e3]) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4] < a[e5]) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1 != p2; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai < p2) { while (a[hi] < p2 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai == p1) continue; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi] < p1) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai > p1) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); { while (a[lo] == p1) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i] == p1) { a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi] == p2) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i] == p2) { a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, lo, hi, cm); QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai > a[j]; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element > a[i2 + begin]) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1 + begin] > a[i2 + begin]) ? i2 : i1; // smaller child if (a[ni + begin] > element) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element > a[i2]) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1] > a[i2]) ? i2 : i1; // smaller child if (a[ni] > element) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this List a) { SmoothSortDescendingInclusiveRange(a, 0, a.Count - 1); } public static void SmoothSortDescending( this List a, int beginIncl, int endExcl) { SmoothSortDescendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this List a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); else SmoothSortDescendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortDescendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this List a, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (val <= a[lf] && val <= a[rt]) break; if (a[lf] <= a[rt]) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this List a, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (vstepson >= val) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[rt] <= vstepson || a[lf] <= vstepson) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a) { TimSortDescending(a, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, lo, hi); BinarySortDescending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoList(a); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderDescending(a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortDescending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseDoubleListDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseDoubleListDesc(ti); } private static void MergeCollapseDoubleListDesc(this TimSortInfoList ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoubleListDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtDoubleListDesc(ti, n); else break; } } private static void MergeForceCollapseDoubleListDesc(this TimSortInfoList ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoubleListDesc(ti, n); } } private static void MergeAtDoubleListDesc(this TimSortInfoList ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightDescending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoDoubleListDesc(ti, start1, len1, start2, len2); else MergeHiDoubleListDesc(ti, start1, len1, start2, len2); } private static void MergeLoDoubleListDesc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[idx2] > t[idx1]) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightDescending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiDoubleListDesc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (t[idx2] > a[idx1]) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftDescending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftDescending( this List a, double key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (key < a[start + hint]) { int maxOfs = len - hint; while (ofs < maxOfs && key < a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && key >= a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key < a[start + m]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightDescending( this List a, double key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (key > a[start + hint]) { int maxOfs = hint + 1; while (ofs < maxOfs && key > a[start + hint - ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && key <= a[start + hint + ofs]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key > a[start + m]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this List a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (pivot > a[mid]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderDescending( this List a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++] > a[beginIncl]) { while (runHi < endExcl && a[runHi] > a[runHi - 1]) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi] <= a[runHi - 1]) runHi++; } return runHi - beginIncl; } #endregion #region Permutation Sort/Median for List /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this List a, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, List a, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, List a, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, List a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, List a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] > a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] > a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] > a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] > a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] > a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] > a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] > a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] > a[p2]) { while (a[p[hi]] > a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] > a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] < a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, lo, hi, cm); PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] < a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] < a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]] < a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] < a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] < a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]] < a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] < a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a); return p; } public static void PermutationSmoothSortAscending( this int[] p, List a) { PermutationSmoothSortAscendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, List a, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, List a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, List a, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val] >= a[p[lf]] && a[val] >= a[p[rt]]) break; if (a[p[lf]] >= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, List a, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson] <= a[val]) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]] >= a[vstepson] || a[p[lf]] >= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a) { PermutationTimSortAscending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); PermutationBinarySortAscending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseDoubleListPermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseDoubleListPermAsc(ti); } private static void MergeCollapseDoubleListPermAsc(this TimSortInfoListPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoubleListPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtDoubleListPermAsc(ti, n); else break; } } private static void MergeForceCollapseDoubleListPermAsc(this TimSortInfoListPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoubleListPermAsc(ti, n); } } private static void MergeAtDoubleListPermAsc(this TimSortInfoListPerm ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoDoubleListPermAsc(ti, start1, len1, start2, len2); else MergeHiDoubleListPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoDoubleListPermAsc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]] < a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightAscending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiDoubleListPermAsc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]] < a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftAscending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, List a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (a[key] > a[p[start + hint]]) { int maxOfs = len - hint; while (ofs < maxOfs && a[key] > a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] <= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, List a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (a[key] < a[p[start + hint]]) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] < a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key] >= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, List a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot] < a[p[mid]]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, List a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] < a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] < a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] >= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this List a, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, List a, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, List a, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, List a, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, List a, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]] < a[p[e2]]) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]] < a[p[e3]]) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]] < a[p[e4]]) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]] < a[p[e4]]) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]] < a[p[e5]]) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]] < a[p[e3]]) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]] < a[p[e5]]) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1] != a[p2]; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai] < a[p2]) { while (a[p[hi]] < a[p2] && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai] == a[p1]) continue; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]] < a[p1]) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai] > a[p1]) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); { while (a[p[lo]] == a[p1]) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]] == a[p1]) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]] == a[p2]) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]] == a[p2]) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, lo, hi, cm); PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai] > a[p[j]]; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] > a[p[i2 + begin]]) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]] > a[p[i2 + begin]]) ? i2 : i1; // smaller child if (a[p[ni + begin]] > a[element]) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element] > a[p[i2]]) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]] > a[p[i2]]) ? i2 : i1; // smaller child if (a[p[ni]] > a[element]) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a); return p; } public static void PermutationSmoothSortDescending( this int[] p, List a) { PermutationSmoothSortDescendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, List a, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, List a, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, List a, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val] <= a[p[lf]] && a[val] <= a[p[rt]]) break; if (a[p[lf]] <= a[p[rt]]) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, List a, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson] >= a[val]) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]] <= a[vstepson] || a[p[lf]] <= a[vstepson]) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this List a) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a) { PermutationTimSortDescending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); PermutationBinarySortDescending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseDoubleListPermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseDoubleListPermDesc(ti); } private static void MergeCollapseDoubleListPermDesc(this TimSortInfoListPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoubleListPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtDoubleListPermDesc(ti, n); else break; } } private static void MergeForceCollapseDoubleListPermDesc(this TimSortInfoListPerm ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtDoubleListPermDesc(ti, n); } } private static void MergeAtDoubleListPermDesc(this TimSortInfoListPerm ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoDoubleListPermDesc(ti, start1, len1, start2, len2); else MergeHiDoubleListPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoDoubleListPermDesc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]] > a[t[idx1]]) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightDescending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiDoubleListPermDesc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]] > a[p[idx1]]) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftDescending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, List a, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (a[key] < a[p[start + hint]]) { int maxOfs = len - hint; while (ofs < maxOfs && a[key] < a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] >= a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] < a[p[start + m]]) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, List a, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (a[key] > a[p[start + hint]]) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key] > a[p[start + hint - ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key] <= a[p[start + hint + ofs]]) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key] > a[p[start + m]]) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, List a, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot] > a[p[mid]]) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, List a, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]] > a[p[beginIncl]]) { while (runHi < endExcl && a[p[runHi]] > a[p[runHi - 1]]) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]] <= a[p[runHi - 1]]) runHi++; } return runHi - beginIncl; } #endregion #region Sort/Median for T[] /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedian( this T[] a, Func cmp, long med) { long last = a.LongLength - 1; QuickMedian(a, cmp, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedian( this T[] a, Func cmp, long beginIncl, long endExcl, long med) { QuickMedian(a, cmp, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedian( this T[] a, Func cmp, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (cmp(a[e1], a[e2]) > 0) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (cmp(a[e4], a[e5]) > 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (cmp(a[e1], a[e3]) > 0) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (cmp(a[e2], a[e3]) > 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (cmp(a[e1], a[e4]) > 0) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (cmp(a[e3], a[e4]) > 0) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (cmp(a[e2], a[e5]) > 0) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (cmp(a[e2], a[e3]) > 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (cmp(a[e4], a[e5]) > 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = cmp(p1, p2) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (cmp(ai, p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (cmp(ai, p2) > 0) { while (cmp(a[hi], p2) > 0 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (cmp(ai, p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (cmp(ai, p1) == 0) continue; if (cmp(ai, p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (cmp(a[hi], p1) > 0) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (cmp(ai, p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (cmp(a[lo], p1) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (cmp(a[i], p1) == 0) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (cmp(a[hi], p2) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (cmp(a[i], p2) == 0) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && cmp(ai, a[j]) < 0; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSort( this T[] a, Func cmp) { long last = a.LongLength - 1; QuickSort(a, cmp, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSort( this T[] a, Func cmp, long beginIncl, long endExcl) { QuickSort(a, cmp, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSort( this T[] a, Func cmp, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (cmp(a[e1], a[e2]) > 0) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (cmp(a[e4], a[e5]) > 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (cmp(a[e1], a[e3]) > 0) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (cmp(a[e2], a[e3]) > 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (cmp(a[e1], a[e4]) > 0) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (cmp(a[e3], a[e4]) > 0) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (cmp(a[e2], a[e5]) > 0) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (cmp(a[e2], a[e3]) > 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (cmp(a[e4], a[e5]) > 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = cmp(p1, p2) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (cmp(ai, p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (cmp(ai, p2) > 0) { while (cmp(a[hi], p2) > 0 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (cmp(ai, p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (cmp(ai, p1) == 0) continue; if (cmp(ai, p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (cmp(a[hi], p1) > 0) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (cmp(ai, p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSort(a, cmp, l, lo - 2, cl); QuickSort(a, cmp, hi + 2, r, cr); { while (cmp(a[lo], p1) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (cmp(a[i], p1) == 0) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (cmp(a[hi], p2) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (cmp(a[i], p2) == 0) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSort(a, cmp, lo, hi, cm); QuickSort(a, cmp, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSort(a, cmp, l, lo - 2, cl); QuickSort(a, cmp, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSort(a, cmp, l, lo - 2, cl); QuickSort(a, cmp, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSort(a, cmp, l, lo - 2, cl); QuickSort(a, cmp, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSort(a, cmp, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSort(a, cmp, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && cmp(ai, a[j]) < 0; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSort( this T[] a, Func cmp, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (cmp(element, a[i2 + begin]) < 0) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && cmp(a[i1 + begin], a[i2 + begin]) < 0) ? i2 : i1; // smaller child if (cmp(a[ni + begin], element) < 0) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSort( this T[] a, Func cmp) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (cmp(element, a[i2]) < 0) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && cmp(a[i1], a[i2]) < 0) ? i2 : i1; // smaller child if (cmp(a[ni], element) < 0) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSort( this T[] a, Func cmp) { SmoothSortInclusiveRange(a, cmp, 0, a.LongLength - 1); } public static void SmoothSort( this T[] a, Func cmp, long beginIncl, long endExcl) { SmoothSortInclusiveRange(a, cmp, beginIncl, endExcl - 1); } private static void SmoothSortInclusiveRange( this T[] a, Func cmp, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortSift(a, cmp, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortTrinkle(a, cmp, pbits, pshift, head, false); else SmoothSortSift(a, cmp, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortTrinkle(a, cmp, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortTrinkle(a, cmp, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortTrinkle(a, cmp, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortSift( this T[] a, Func cmp, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (cmp(val, a[lf]) >= 0 && cmp(val, a[rt]) >= 0) break; if (cmp(a[lf], a[rt]) >= 0) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortTrinkle( this T[] a, Func cmp, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (cmp(vstepson, val) <= 0) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (cmp(a[rt], vstepson) >= 0 || cmp(a[lf], vstepson) >= 0) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortSift(a, cmp, pshift, head); } } public class TimSortInfoLongCmp { public T[] m_a; public Func m_cmp; public long m_minGallop = c_minGallop; public T[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoLongCmp(T[] a, Func cmp) { m_a = a; m_cmp = cmp; long count = a.LongLength; m_tmp = new T[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public T[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new T[c < 0 ? cap : Math.Min(c, m_a.LongLength >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSort( this T[] a, Func cmp) { TimSort(a, cmp, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSort( this T[] a, Func cmp, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrder(a, cmp, lo, hi); BinarySort(a, cmp, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongCmp(a, cmp); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrder(a, cmp, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySort(a, cmp, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongCmp(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongCmp(ti); } private static void MergeCollapseLongCmp(this TimSortInfoLongCmp ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongCmp(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongCmp(ti, n); else break; } } private static void MergeForceCollapseLongCmp(this TimSortInfoLongCmp ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongCmp(ti, n); } } private static void MergeAtLongCmp(this TimSortInfoLongCmp ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRight(a, ti.m_cmp, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeft(a, ti.m_cmp, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongCmp(ti, start1, len1, start2, len2); else MergeHiLongCmp(ti, start1, len1, start2, len2); } private static void MergeLoLongCmp(this TimSortInfoLongCmp ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func cmp = ti.m_cmp; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (cmp(a[idx2], t[idx1]) < 0) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRight(t, cmp, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeft(a, cmp, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiLongCmp(this TimSortInfoLongCmp ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func cmp = ti.m_cmp; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (cmp(t[idx2], a[idx1]) < 0) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRight(a, cmp, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeft(t, cmp, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeft( this T[] a, Func cmp, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (cmp(key, a[start + hint]) > 0) { long maxOfs = len - hint; while (ofs < maxOfs && cmp(key, a[start + hint + ofs]) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && cmp(key, a[start + hint - ofs]) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (cmp(key, a[start + m]) > 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRight( this T[] a, Func cmp, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (cmp(key, a[start + hint]) < 0) { long maxOfs = hint + 1; while (ofs < maxOfs && cmp(key, a[start + hint - ofs]) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && cmp(key, a[start + hint + ofs]) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (cmp(key, a[start + m]) < 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySort( this T[] a, Func cmp, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (cmp(pivot, a[mid]) < 0) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrder( this T[] a, Func cmp, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (cmp(a[runHi++], a[beginIncl]) < 0) { while (runHi < endExcl && cmp(a[runHi], a[runHi - 1]) < 0) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && cmp(a[runHi], a[runHi - 1]) >= 0) runHi++; } return runHi - beginIncl; } public static void ReverseRange( T[] a, long beginIncl, long endExcl) { endExcl--; // now incorrectly named while (beginIncl < endExcl) { var t = a[beginIncl]; a[beginIncl] = a[endExcl]; a[endExcl] = t; ++beginIncl; --endExcl; } } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this T[] a, long med) where T : IComparable { long last = a.LongLength - 1; QuickMedianAscending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this T[] a, long beginIncl, long endExcl, long med) where T : IComparable { QuickMedianAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this T[] a, long l, long r, long countSub1, long med) where T : IComparable { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1].CompareTo(a[e2]) > 0) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4].CompareTo(a[e5]) > 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1].CompareTo(a[e3]) > 0) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2].CompareTo(a[e3]) > 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1].CompareTo(a[e4]) > 0) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3].CompareTo(a[e4]) > 0) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2].CompareTo(a[e5]) > 0) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2].CompareTo(a[e3]) > 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4].CompareTo(a[e5]) > 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1.CompareTo(p2) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai.CompareTo(p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai.CompareTo(p2) > 0) { while (a[hi].CompareTo(p2) > 0 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai.CompareTo(p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai.CompareTo(p1) == 0) continue; if (ai.CompareTo(p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi].CompareTo(p1) > 0) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai.CompareTo(p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo].CompareTo(p1) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i].CompareTo(p1) == 0) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi].CompareTo(p2) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i].CompareTo(p2) == 0) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai.CompareTo(a[j]) < 0; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this T[] a) where T : IComparable { long last = a.LongLength - 1; QuickSortAscending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this T[] a, long beginIncl, long endExcl) where T : IComparable { QuickSortAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this T[] a, long l, long r, long countSub1) where T : IComparable { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1].CompareTo(a[e2]) > 0) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4].CompareTo(a[e5]) > 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1].CompareTo(a[e3]) > 0) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2].CompareTo(a[e3]) > 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1].CompareTo(a[e4]) > 0) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3].CompareTo(a[e4]) > 0) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2].CompareTo(a[e5]) > 0) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2].CompareTo(a[e3]) > 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4].CompareTo(a[e5]) > 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1.CompareTo(p2) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai.CompareTo(p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai.CompareTo(p2) > 0) { while (a[hi].CompareTo(p2) > 0 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai.CompareTo(p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai.CompareTo(p1) == 0) continue; if (ai.CompareTo(p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi].CompareTo(p1) > 0) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai.CompareTo(p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); { while (a[lo].CompareTo(p1) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i].CompareTo(p1) == 0) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi].CompareTo(p2) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i].CompareTo(p2) == 0) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, lo, hi, cm); QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai.CompareTo(a[j]) < 0; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this T[] a, long begin, long end) where T : IComparable { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element.CompareTo(a[i2 + begin]) < 0) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1 + begin].CompareTo(a[i2 + begin]) < 0) ? i2 : i1; // smaller child if (a[ni + begin].CompareTo(element) < 0) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this T[] a) where T : IComparable { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element.CompareTo(a[i2]) < 0) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1].CompareTo(a[i2]) < 0) ? i2 : i1; // smaller child if (a[ni].CompareTo(element) < 0) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this T[] a) where T : IComparable { SmoothSortAscendingInclusiveRange(a, 0, a.LongLength - 1); } public static void SmoothSortAscending( this T[] a, long beginIncl, long endExcl) where T : IComparable { SmoothSortAscendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this T[] a, long lo, long hi) where T : IComparable { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); else SmoothSortAscendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortAscendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this T[] a, int pshift, long head) where T : IComparable { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (val.CompareTo(a[lf]) >= 0 && val.CompareTo(a[rt]) >= 0) break; if (a[lf].CompareTo(a[rt]) >= 0) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this T[] a, long pbits, int pshift, long head, bool isTrusty) where T : IComparable { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (vstepson.CompareTo(val) <= 0) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[rt].CompareTo(vstepson) >= 0 || a[lf].CompareTo(vstepson) >= 0) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, pshift, head); } } public class TimSortInfoLong where T : IComparable { public T[] m_a; public long m_minGallop = c_minGallop; public T[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoLong(T[] a) { m_a = a; long count = a.LongLength; m_tmp = new T[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public T[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new T[c < 0 ? cap : Math.Min(c, m_a.LongLength >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this T[] a) where T : IComparable { TimSortAscending(a, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this T[] a, long lo, long hi) where T : IComparable { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, lo, hi); BinarySortAscending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLong(a); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderAscending(a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortAscending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongAsc(ti); } private static void MergeCollapseLongAsc(this TimSortInfoLong ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongAsc(ti, n); else break; } } private static void MergeForceCollapseLongAsc(this TimSortInfoLong ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } } private static void MergeAtLongAsc(this TimSortInfoLong ti, int i) where T : IComparable { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightAscending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongAsc(ti, start1, len1, start2, len2); else MergeHiLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoLongAsc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) where T : IComparable { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[idx2].CompareTo(t[idx1]) < 0) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightAscending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiLongAsc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) where T : IComparable { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (t[idx2].CompareTo(a[idx1]) < 0) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftAscending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftAscending( this T[] a, T key, long start, long len, long hint) where T : IComparable { long lastOfs = 0, ofs = 1; if (key.CompareTo(a[start + hint]) > 0) { long maxOfs = len - hint; while (ofs < maxOfs && key.CompareTo(a[start + hint + ofs]) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && key.CompareTo(a[start + hint - ofs]) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key.CompareTo(a[start + m]) > 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightAscending( this T[] a, T key, long start, long len, long hint) where T : IComparable { long ofs = 1, lastOfs = 0; if (key.CompareTo(a[start + hint]) < 0) { long maxOfs = hint + 1; while (ofs < maxOfs && key.CompareTo(a[start + hint - ofs]) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && key.CompareTo(a[start + hint + ofs]) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key.CompareTo(a[start + m]) < 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this T[] a, long beginIncl, long endExcl, long beginUnsorted) where T : IComparable { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (pivot.CompareTo(a[mid]) < 0) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderAscending( this T[] a, long beginIncl, long endExcl) where T : IComparable { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++].CompareTo(a[beginIncl]) < 0) { while (runHi < endExcl && a[runHi].CompareTo(a[runHi - 1]) < 0) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi].CompareTo(a[runHi - 1]) >= 0) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this T[] a, long med) where T : IComparable { long last = a.LongLength - 1; QuickMedianDescending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this T[] a, long beginIncl, long endExcl, long med) where T : IComparable { QuickMedianDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this T[] a, long l, long r, long countSub1, long med) where T : IComparable { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1].CompareTo(a[e2]) < 0) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4].CompareTo(a[e5]) < 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1].CompareTo(a[e3]) < 0) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2].CompareTo(a[e3]) < 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1].CompareTo(a[e4]) < 0) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3].CompareTo(a[e4]) < 0) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2].CompareTo(a[e5]) < 0) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2].CompareTo(a[e3]) < 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4].CompareTo(a[e5]) < 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1.CompareTo(p2) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai.CompareTo(p1) > 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai.CompareTo(p2) < 0) { while (a[hi].CompareTo(p2) < 0 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai.CompareTo(p1) > 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai.CompareTo(p1) == 0) continue; if (ai.CompareTo(p1) > 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi].CompareTo(p1) < 0) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai.CompareTo(p1) > 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo].CompareTo(p1) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i].CompareTo(p1) == 0) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi].CompareTo(p2) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i].CompareTo(p2) == 0) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai.CompareTo(a[j]) > 0; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this T[] a) where T : IComparable { long last = a.LongLength - 1; QuickSortDescending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this T[] a, long beginIncl, long endExcl) where T : IComparable { QuickSortDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this T[] a, long l, long r, long countSub1) where T : IComparable { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[e1].CompareTo(a[e2]) < 0) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4].CompareTo(a[e5]) < 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1].CompareTo(a[e3]) < 0) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2].CompareTo(a[e3]) < 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1].CompareTo(a[e4]) < 0) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3].CompareTo(a[e4]) < 0) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2].CompareTo(a[e5]) < 0) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2].CompareTo(a[e3]) < 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4].CompareTo(a[e5]) < 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1.CompareTo(p2) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai.CompareTo(p1) > 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai.CompareTo(p2) < 0) { while (a[hi].CompareTo(p2) < 0 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai.CompareTo(p1) > 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (ai.CompareTo(p1) == 0) continue; if (ai.CompareTo(p1) > 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi].CompareTo(p1) < 0) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai.CompareTo(p1) > 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); { while (a[lo].CompareTo(p1) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[i].CompareTo(p1) == 0) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi].CompareTo(p2) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[i].CompareTo(p2) == 0) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, lo, hi, cm); QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && ai.CompareTo(a[j]) > 0; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this T[] a, long begin, long end) where T : IComparable { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element.CompareTo(a[i2 + begin]) > 0) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1 + begin].CompareTo(a[i2 + begin]) > 0) ? i2 : i1; // smaller child if (a[ni + begin].CompareTo(element) > 0) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this T[] a) where T : IComparable { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element.CompareTo(a[i2]) > 0) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[i1].CompareTo(a[i2]) > 0) ? i2 : i1; // smaller child if (a[ni].CompareTo(element) > 0) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this T[] a) where T : IComparable { SmoothSortDescendingInclusiveRange(a, 0, a.LongLength - 1); } public static void SmoothSortDescending( this T[] a, long beginIncl, long endExcl) where T : IComparable { SmoothSortDescendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this T[] a, long lo, long hi) where T : IComparable { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); else SmoothSortDescendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortDescendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this T[] a, int pshift, long head) where T : IComparable { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (val.CompareTo(a[lf]) <= 0 && val.CompareTo(a[rt]) <= 0) break; if (a[lf].CompareTo(a[rt]) <= 0) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this T[] a, long pbits, int pshift, long head, bool isTrusty) where T : IComparable { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (vstepson.CompareTo(val) >= 0) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[rt].CompareTo(vstepson) <= 0 || a[lf].CompareTo(vstepson) <= 0) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this T[] a) where T : IComparable { TimSortDescending(a, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this T[] a, long lo, long hi) where T : IComparable { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, lo, hi); BinarySortDescending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLong(a); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderDescending(a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortDescending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongDesc(ti); } private static void MergeCollapseLongDesc(this TimSortInfoLong ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongDesc(ti, n); else break; } } private static void MergeForceCollapseLongDesc(this TimSortInfoLong ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } } private static void MergeAtLongDesc(this TimSortInfoLong ti, int i) where T : IComparable { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightDescending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongDesc(ti, start1, len1, start2, len2); else MergeHiLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoLongDesc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) where T : IComparable { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[idx2].CompareTo(t[idx1]) > 0) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightDescending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiLongDesc(this TimSortInfoLong ti, long start1, long len1, long start2, long len2) where T : IComparable { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (t[idx2].CompareTo(a[idx1]) > 0) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftDescending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftDescending( this T[] a, T key, long start, long len, long hint) where T : IComparable { long lastOfs = 0, ofs = 1; if (key.CompareTo(a[start + hint]) < 0) { long maxOfs = len - hint; while (ofs < maxOfs && key.CompareTo(a[start + hint + ofs]) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && key.CompareTo(a[start + hint - ofs]) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key.CompareTo(a[start + m]) < 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightDescending( this T[] a, T key, long start, long len, long hint) where T : IComparable { long ofs = 1, lastOfs = 0; if (key.CompareTo(a[start + hint]) > 0) { long maxOfs = hint + 1; while (ofs < maxOfs && key.CompareTo(a[start + hint - ofs]) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && key.CompareTo(a[start + hint + ofs]) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key.CompareTo(a[start + m]) > 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this T[] a, long beginIncl, long endExcl, long beginUnsorted) where T : IComparable { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (pivot.CompareTo(a[mid]) > 0) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderDescending( this T[] a, long beginIncl, long endExcl) where T : IComparable { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++].CompareTo(a[beginIncl]) > 0) { while (runHi < endExcl && a[runHi].CompareTo(a[runHi - 1]) > 0) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi].CompareTo(a[runHi - 1]) <= 0) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this T[] a, Func selector, long med) { long last = a.LongLength - 1; QuickMedianAscending(a, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this T[] a, Func selector, long beginIncl, long endExcl, long med) { QuickMedianAscending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this T[] a, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[e1]) > selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) > selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) > selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) > selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) > selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) > selector(p2)) { while (selector(a[hi]) > selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) > selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[lo]) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && selector(ai) < selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this T[] a, Func selector) { long last = a.LongLength - 1; QuickSortAscending(a, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this T[] a, Func selector, long beginIncl, long endExcl) { QuickSortAscending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this T[] a, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[e1]) > selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) > selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) > selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) > selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) > selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) > selector(p2)) { while (selector(a[hi]) > selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) > selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); { while (selector(a[lo]) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, selector, lo, hi, cm); QuickSortAscending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && selector(ai) < selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this T[] a, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) < selector(a[i2 + begin])) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[i1 + begin]) < selector(a[i2 + begin])) ? i2 : i1; // smaller child if (selector(a[ni + begin]) < selector(element)) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this T[] a, Func selector) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) < selector(a[i2])) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[i1]) < selector(a[i2])) ? i2 : i1; // smaller child if (selector(a[ni]) < selector(element)) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this T[] a, Func selector) { SmoothSortAscendingInclusiveRange(a, selector, 0, a.LongLength - 1); } public static void SmoothSortAscending( this T[] a, Func selector, long beginIncl, long endExcl) { SmoothSortAscendingInclusiveRange(a, selector, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this T[] a, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head, false); else SmoothSortAscendingSift(a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this T[] a, Func selector, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(val) >= selector(a[lf]) && selector(val) >= selector(a[rt])) break; if (selector(a[lf]) >= selector(a[rt])) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this T[] a, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (selector(vstepson) <= selector(val)) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[rt]) >= selector(vstepson) || selector(a[lf]) >= selector(vstepson)) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, selector, pshift, head); } } public class TimSortInfoLongIntSel { public T[] m_a; public Func m_sel; public long m_minGallop = c_minGallop; public T[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoLongIntSel(T[] a, Func selector) { m_a = a; m_sel = selector; long count = a.LongLength; m_tmp = new T[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public T[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new T[c < 0 ? cap : Math.Min(c, m_a.LongLength >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this T[] a, Func selector) { TimSortAscending(a, selector, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this T[] a, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, selector, lo, hi); BinarySortAscending(a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongIntSel(a, selector); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderAscending(a, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortAscending(a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongAsc(ti); } private static void MergeCollapseLongAsc(this TimSortInfoLongIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongAsc(ti, n); else break; } } private static void MergeForceCollapseLongAsc(this TimSortInfoLongIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } } private static void MergeAtLongAsc(this TimSortInfoLongIntSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightAscending(a, ti.m_sel, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_sel, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongAsc(ti, start1, len1, start2, len2); else MergeHiLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoLongAsc(this TimSortInfoLongIntSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[idx2]) < selector(t[idx1])) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightAscending(t, selector, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiLongAsc(this TimSortInfoLongIntSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(t[idx2]) < selector(a[idx1])) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftAscending(t, selector, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftAscending( this T[] a, Func selector, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(key) > selector(a[start + hint])) { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) > selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) <= selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(a[start + m])) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightAscending( this T[] a, Func selector, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(key) < selector(a[start + hint])) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) < selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) >= selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(a[start + m])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this T[] a, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(pivot) < selector(a[mid])) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderAscending( this T[] a, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[runHi++]) < selector(a[beginIncl])) { while (runHi < endExcl && selector(a[runHi]) < selector(a[runHi - 1])) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[runHi]) >= selector(a[runHi - 1])) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this T[] a, Func selector, long med) { long last = a.LongLength - 1; QuickMedianDescending(a, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this T[] a, Func selector, long beginIncl, long endExcl, long med) { QuickMedianDescending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this T[] a, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[e1]) < selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) < selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) < selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) < selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) < selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) < selector(p2)) { while (selector(a[hi]) < selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) < selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[lo]) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && selector(ai) > selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this T[] a, Func selector) { long last = a.LongLength - 1; QuickSortDescending(a, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this T[] a, Func selector, long beginIncl, long endExcl) { QuickSortDescending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this T[] a, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[e1]) < selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) < selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) < selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) < selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) < selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) < selector(p2)) { while (selector(a[hi]) < selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) < selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); { while (selector(a[lo]) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, selector, lo, hi, cm); QuickSortDescending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && selector(ai) > selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this T[] a, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) > selector(a[i2 + begin])) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[i1 + begin]) > selector(a[i2 + begin])) ? i2 : i1; // smaller child if (selector(a[ni + begin]) > selector(element)) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this T[] a, Func selector) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) > selector(a[i2])) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[i1]) > selector(a[i2])) ? i2 : i1; // smaller child if (selector(a[ni]) > selector(element)) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this T[] a, Func selector) { SmoothSortDescendingInclusiveRange(a, selector, 0, a.LongLength - 1); } public static void SmoothSortDescending( this T[] a, Func selector, long beginIncl, long endExcl) { SmoothSortDescendingInclusiveRange(a, selector, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this T[] a, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head, false); else SmoothSortDescendingSift(a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this T[] a, Func selector, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(val) <= selector(a[lf]) && selector(val) <= selector(a[rt])) break; if (selector(a[lf]) <= selector(a[rt])) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this T[] a, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (selector(vstepson) >= selector(val)) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[rt]) <= selector(vstepson) || selector(a[lf]) <= selector(vstepson)) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this T[] a, Func selector) { TimSortDescending(a, selector, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this T[] a, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, selector, lo, hi); BinarySortDescending(a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongIntSel(a, selector); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderDescending(a, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortDescending(a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongDesc(ti); } private static void MergeCollapseLongDesc(this TimSortInfoLongIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongDesc(ti, n); else break; } } private static void MergeForceCollapseLongDesc(this TimSortInfoLongIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } } private static void MergeAtLongDesc(this TimSortInfoLongIntSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightDescending(a, ti.m_sel, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_sel, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongDesc(ti, start1, len1, start2, len2); else MergeHiLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoLongDesc(this TimSortInfoLongIntSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[idx2]) > selector(t[idx1])) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightDescending(t, selector, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiLongDesc(this TimSortInfoLongIntSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(t[idx2]) > selector(a[idx1])) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftDescending(t, selector, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftDescending( this T[] a, Func selector, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(key) < selector(a[start + hint])) { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) < selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) >= selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(a[start + m])) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightDescending( this T[] a, Func selector, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(key) > selector(a[start + hint])) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) > selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) <= selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(a[start + m])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this T[] a, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(pivot) > selector(a[mid])) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderDescending( this T[] a, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[runHi++]) > selector(a[beginIncl])) { while (runHi < endExcl && selector(a[runHi]) > selector(a[runHi - 1])) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[runHi]) <= selector(a[runHi - 1])) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this T[] a, Func selector, long med) { long last = a.LongLength - 1; QuickMedianAscending(a, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this T[] a, Func selector, long beginIncl, long endExcl, long med) { QuickMedianAscending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this T[] a, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[e1]) > selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) > selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) > selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) > selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) > selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) > selector(p2)) { while (selector(a[hi]) > selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) > selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[lo]) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && selector(ai) < selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this T[] a, Func selector) { long last = a.LongLength - 1; QuickSortAscending(a, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this T[] a, Func selector, long beginIncl, long endExcl) { QuickSortAscending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this T[] a, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[e1]) > selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) > selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) > selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) > selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) > selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) > selector(p2)) { while (selector(a[hi]) > selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) > selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); { while (selector(a[lo]) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, selector, lo, hi, cm); QuickSortAscending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && selector(ai) < selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this T[] a, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) < selector(a[i2 + begin])) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[i1 + begin]) < selector(a[i2 + begin])) ? i2 : i1; // smaller child if (selector(a[ni + begin]) < selector(element)) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this T[] a, Func selector) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) < selector(a[i2])) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[i1]) < selector(a[i2])) ? i2 : i1; // smaller child if (selector(a[ni]) < selector(element)) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this T[] a, Func selector) { SmoothSortAscendingInclusiveRange(a, selector, 0, a.LongLength - 1); } public static void SmoothSortAscending( this T[] a, Func selector, long beginIncl, long endExcl) { SmoothSortAscendingInclusiveRange(a, selector, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this T[] a, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head, false); else SmoothSortAscendingSift(a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this T[] a, Func selector, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(val) >= selector(a[lf]) && selector(val) >= selector(a[rt])) break; if (selector(a[lf]) >= selector(a[rt])) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this T[] a, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (selector(vstepson) <= selector(val)) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[rt]) >= selector(vstepson) || selector(a[lf]) >= selector(vstepson)) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, selector, pshift, head); } } public class TimSortInfoLongLongSel { public T[] m_a; public Func m_sel; public long m_minGallop = c_minGallop; public T[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoLongLongSel(T[] a, Func selector) { m_a = a; m_sel = selector; long count = a.LongLength; m_tmp = new T[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public T[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new T[c < 0 ? cap : Math.Min(c, m_a.LongLength >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this T[] a, Func selector) { TimSortAscending(a, selector, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this T[] a, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, selector, lo, hi); BinarySortAscending(a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongLongSel(a, selector); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderAscending(a, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortAscending(a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongAsc(ti); } private static void MergeCollapseLongAsc(this TimSortInfoLongLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongAsc(ti, n); else break; } } private static void MergeForceCollapseLongAsc(this TimSortInfoLongLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } } private static void MergeAtLongAsc(this TimSortInfoLongLongSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightAscending(a, ti.m_sel, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_sel, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongAsc(ti, start1, len1, start2, len2); else MergeHiLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoLongAsc(this TimSortInfoLongLongSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[idx2]) < selector(t[idx1])) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightAscending(t, selector, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiLongAsc(this TimSortInfoLongLongSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(t[idx2]) < selector(a[idx1])) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftAscending(t, selector, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftAscending( this T[] a, Func selector, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(key) > selector(a[start + hint])) { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) > selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) <= selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(a[start + m])) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightAscending( this T[] a, Func selector, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(key) < selector(a[start + hint])) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) < selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) >= selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(a[start + m])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this T[] a, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(pivot) < selector(a[mid])) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderAscending( this T[] a, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[runHi++]) < selector(a[beginIncl])) { while (runHi < endExcl && selector(a[runHi]) < selector(a[runHi - 1])) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[runHi]) >= selector(a[runHi - 1])) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this T[] a, Func selector, long med) { long last = a.LongLength - 1; QuickMedianDescending(a, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this T[] a, Func selector, long beginIncl, long endExcl, long med) { QuickMedianDescending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this T[] a, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[e1]) < selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) < selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) < selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) < selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) < selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) < selector(p2)) { while (selector(a[hi]) < selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) < selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[lo]) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && selector(ai) > selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this T[] a, Func selector) { long last = a.LongLength - 1; QuickSortDescending(a, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this T[] a, Func selector, long beginIncl, long endExcl) { QuickSortDescending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this T[] a, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[e1]) < selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) < selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) < selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) < selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) < selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) < selector(p2)) { while (selector(a[hi]) < selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) < selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); { while (selector(a[lo]) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, selector, lo, hi, cm); QuickSortDescending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && selector(ai) > selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this T[] a, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) > selector(a[i2 + begin])) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[i1 + begin]) > selector(a[i2 + begin])) ? i2 : i1; // smaller child if (selector(a[ni + begin]) > selector(element)) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this T[] a, Func selector) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) > selector(a[i2])) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[i1]) > selector(a[i2])) ? i2 : i1; // smaller child if (selector(a[ni]) > selector(element)) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this T[] a, Func selector) { SmoothSortDescendingInclusiveRange(a, selector, 0, a.LongLength - 1); } public static void SmoothSortDescending( this T[] a, Func selector, long beginIncl, long endExcl) { SmoothSortDescendingInclusiveRange(a, selector, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this T[] a, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head, false); else SmoothSortDescendingSift(a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this T[] a, Func selector, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(val) <= selector(a[lf]) && selector(val) <= selector(a[rt])) break; if (selector(a[lf]) <= selector(a[rt])) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this T[] a, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (selector(vstepson) >= selector(val)) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[rt]) <= selector(vstepson) || selector(a[lf]) <= selector(vstepson)) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this T[] a, Func selector) { TimSortDescending(a, selector, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this T[] a, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, selector, lo, hi); BinarySortDescending(a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongLongSel(a, selector); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderDescending(a, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortDescending(a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongDesc(ti); } private static void MergeCollapseLongDesc(this TimSortInfoLongLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongDesc(ti, n); else break; } } private static void MergeForceCollapseLongDesc(this TimSortInfoLongLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } } private static void MergeAtLongDesc(this TimSortInfoLongLongSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightDescending(a, ti.m_sel, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_sel, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongDesc(ti, start1, len1, start2, len2); else MergeHiLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoLongDesc(this TimSortInfoLongLongSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[idx2]) > selector(t[idx1])) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightDescending(t, selector, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiLongDesc(this TimSortInfoLongLongSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(t[idx2]) > selector(a[idx1])) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftDescending(t, selector, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftDescending( this T[] a, Func selector, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(key) < selector(a[start + hint])) { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) < selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) >= selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(a[start + m])) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightDescending( this T[] a, Func selector, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(key) > selector(a[start + hint])) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) > selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) <= selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(a[start + m])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this T[] a, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(pivot) > selector(a[mid])) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderDescending( this T[] a, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[runHi++]) > selector(a[beginIncl])) { while (runHi < endExcl && selector(a[runHi]) > selector(a[runHi - 1])) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[runHi]) <= selector(a[runHi - 1])) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this T[] a, Func selector, long med) { long last = a.LongLength - 1; QuickMedianAscending(a, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this T[] a, Func selector, long beginIncl, long endExcl, long med) { QuickMedianAscending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this T[] a, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[e1]) > selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) > selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) > selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) > selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) > selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) > selector(p2)) { while (selector(a[hi]) > selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) > selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[lo]) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && selector(ai) < selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this T[] a, Func selector) { long last = a.LongLength - 1; QuickSortAscending(a, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this T[] a, Func selector, long beginIncl, long endExcl) { QuickSortAscending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this T[] a, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[e1]) > selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) > selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) > selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) > selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) > selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) > selector(p2)) { while (selector(a[hi]) > selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) > selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); { while (selector(a[lo]) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, selector, lo, hi, cm); QuickSortAscending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && selector(ai) < selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this T[] a, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) < selector(a[i2 + begin])) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[i1 + begin]) < selector(a[i2 + begin])) ? i2 : i1; // smaller child if (selector(a[ni + begin]) < selector(element)) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this T[] a, Func selector) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) < selector(a[i2])) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[i1]) < selector(a[i2])) ? i2 : i1; // smaller child if (selector(a[ni]) < selector(element)) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this T[] a, Func selector) { SmoothSortAscendingInclusiveRange(a, selector, 0, a.LongLength - 1); } public static void SmoothSortAscending( this T[] a, Func selector, long beginIncl, long endExcl) { SmoothSortAscendingInclusiveRange(a, selector, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this T[] a, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head, false); else SmoothSortAscendingSift(a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this T[] a, Func selector, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(val) >= selector(a[lf]) && selector(val) >= selector(a[rt])) break; if (selector(a[lf]) >= selector(a[rt])) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this T[] a, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (selector(vstepson) <= selector(val)) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[rt]) >= selector(vstepson) || selector(a[lf]) >= selector(vstepson)) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, selector, pshift, head); } } public class TimSortInfoLongFloatSel { public T[] m_a; public Func m_sel; public long m_minGallop = c_minGallop; public T[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoLongFloatSel(T[] a, Func selector) { m_a = a; m_sel = selector; long count = a.LongLength; m_tmp = new T[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public T[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new T[c < 0 ? cap : Math.Min(c, m_a.LongLength >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this T[] a, Func selector) { TimSortAscending(a, selector, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this T[] a, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, selector, lo, hi); BinarySortAscending(a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongFloatSel(a, selector); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderAscending(a, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortAscending(a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongAsc(ti); } private static void MergeCollapseLongAsc(this TimSortInfoLongFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongAsc(ti, n); else break; } } private static void MergeForceCollapseLongAsc(this TimSortInfoLongFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } } private static void MergeAtLongAsc(this TimSortInfoLongFloatSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightAscending(a, ti.m_sel, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_sel, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongAsc(ti, start1, len1, start2, len2); else MergeHiLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoLongAsc(this TimSortInfoLongFloatSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[idx2]) < selector(t[idx1])) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightAscending(t, selector, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiLongAsc(this TimSortInfoLongFloatSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(t[idx2]) < selector(a[idx1])) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftAscending(t, selector, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftAscending( this T[] a, Func selector, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(key) > selector(a[start + hint])) { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) > selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) <= selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(a[start + m])) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightAscending( this T[] a, Func selector, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(key) < selector(a[start + hint])) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) < selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) >= selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(a[start + m])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this T[] a, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(pivot) < selector(a[mid])) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderAscending( this T[] a, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[runHi++]) < selector(a[beginIncl])) { while (runHi < endExcl && selector(a[runHi]) < selector(a[runHi - 1])) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[runHi]) >= selector(a[runHi - 1])) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this T[] a, Func selector, long med) { long last = a.LongLength - 1; QuickMedianDescending(a, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this T[] a, Func selector, long beginIncl, long endExcl, long med) { QuickMedianDescending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this T[] a, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[e1]) < selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) < selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) < selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) < selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) < selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) < selector(p2)) { while (selector(a[hi]) < selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) < selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[lo]) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && selector(ai) > selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this T[] a, Func selector) { long last = a.LongLength - 1; QuickSortDescending(a, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this T[] a, Func selector, long beginIncl, long endExcl) { QuickSortDescending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this T[] a, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[e1]) < selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) < selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) < selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) < selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) < selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) < selector(p2)) { while (selector(a[hi]) < selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) < selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); { while (selector(a[lo]) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, selector, lo, hi, cm); QuickSortDescending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && selector(ai) > selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this T[] a, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) > selector(a[i2 + begin])) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[i1 + begin]) > selector(a[i2 + begin])) ? i2 : i1; // smaller child if (selector(a[ni + begin]) > selector(element)) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this T[] a, Func selector) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) > selector(a[i2])) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[i1]) > selector(a[i2])) ? i2 : i1; // smaller child if (selector(a[ni]) > selector(element)) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this T[] a, Func selector) { SmoothSortDescendingInclusiveRange(a, selector, 0, a.LongLength - 1); } public static void SmoothSortDescending( this T[] a, Func selector, long beginIncl, long endExcl) { SmoothSortDescendingInclusiveRange(a, selector, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this T[] a, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head, false); else SmoothSortDescendingSift(a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this T[] a, Func selector, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(val) <= selector(a[lf]) && selector(val) <= selector(a[rt])) break; if (selector(a[lf]) <= selector(a[rt])) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this T[] a, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (selector(vstepson) >= selector(val)) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[rt]) <= selector(vstepson) || selector(a[lf]) <= selector(vstepson)) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this T[] a, Func selector) { TimSortDescending(a, selector, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this T[] a, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, selector, lo, hi); BinarySortDescending(a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongFloatSel(a, selector); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderDescending(a, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortDescending(a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongDesc(ti); } private static void MergeCollapseLongDesc(this TimSortInfoLongFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongDesc(ti, n); else break; } } private static void MergeForceCollapseLongDesc(this TimSortInfoLongFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } } private static void MergeAtLongDesc(this TimSortInfoLongFloatSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightDescending(a, ti.m_sel, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_sel, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongDesc(ti, start1, len1, start2, len2); else MergeHiLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoLongDesc(this TimSortInfoLongFloatSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[idx2]) > selector(t[idx1])) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightDescending(t, selector, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiLongDesc(this TimSortInfoLongFloatSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(t[idx2]) > selector(a[idx1])) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftDescending(t, selector, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftDescending( this T[] a, Func selector, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(key) < selector(a[start + hint])) { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) < selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) >= selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(a[start + m])) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightDescending( this T[] a, Func selector, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(key) > selector(a[start + hint])) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) > selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) <= selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(a[start + m])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this T[] a, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(pivot) > selector(a[mid])) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderDescending( this T[] a, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[runHi++]) > selector(a[beginIncl])) { while (runHi < endExcl && selector(a[runHi]) > selector(a[runHi - 1])) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[runHi]) <= selector(a[runHi - 1])) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this T[] a, Func selector, long med) { long last = a.LongLength - 1; QuickMedianAscending(a, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this T[] a, Func selector, long beginIncl, long endExcl, long med) { QuickMedianAscending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this T[] a, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[e1]) > selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) > selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) > selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) > selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) > selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) > selector(p2)) { while (selector(a[hi]) > selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) > selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[lo]) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && selector(ai) < selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this T[] a, Func selector) { long last = a.LongLength - 1; QuickSortAscending(a, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this T[] a, Func selector, long beginIncl, long endExcl) { QuickSortAscending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this T[] a, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[e1]) > selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) > selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) > selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) > selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) > selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) > selector(p2)) { while (selector(a[hi]) > selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) > selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); { while (selector(a[lo]) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, selector, lo, hi, cm); QuickSortAscending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && selector(ai) < selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this T[] a, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) < selector(a[i2 + begin])) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[i1 + begin]) < selector(a[i2 + begin])) ? i2 : i1; // smaller child if (selector(a[ni + begin]) < selector(element)) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this T[] a, Func selector) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) < selector(a[i2])) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[i1]) < selector(a[i2])) ? i2 : i1; // smaller child if (selector(a[ni]) < selector(element)) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this T[] a, Func selector) { SmoothSortAscendingInclusiveRange(a, selector, 0, a.LongLength - 1); } public static void SmoothSortAscending( this T[] a, Func selector, long beginIncl, long endExcl) { SmoothSortAscendingInclusiveRange(a, selector, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this T[] a, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head, false); else SmoothSortAscendingSift(a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this T[] a, Func selector, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(val) >= selector(a[lf]) && selector(val) >= selector(a[rt])) break; if (selector(a[lf]) >= selector(a[rt])) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this T[] a, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (selector(vstepson) <= selector(val)) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[rt]) >= selector(vstepson) || selector(a[lf]) >= selector(vstepson)) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, selector, pshift, head); } } public class TimSortInfoLongDoubleSel { public T[] m_a; public Func m_sel; public long m_minGallop = c_minGallop; public T[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoLongDoubleSel(T[] a, Func selector) { m_a = a; m_sel = selector; long count = a.LongLength; m_tmp = new T[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public T[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new T[c < 0 ? cap : Math.Min(c, m_a.LongLength >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this T[] a, Func selector) { TimSortAscending(a, selector, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this T[] a, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, selector, lo, hi); BinarySortAscending(a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongDoubleSel(a, selector); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderAscending(a, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortAscending(a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongAsc(ti); } private static void MergeCollapseLongAsc(this TimSortInfoLongDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongAsc(ti, n); else break; } } private static void MergeForceCollapseLongAsc(this TimSortInfoLongDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } } private static void MergeAtLongAsc(this TimSortInfoLongDoubleSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightAscending(a, ti.m_sel, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_sel, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongAsc(ti, start1, len1, start2, len2); else MergeHiLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoLongAsc(this TimSortInfoLongDoubleSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[idx2]) < selector(t[idx1])) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightAscending(t, selector, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiLongAsc(this TimSortInfoLongDoubleSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(t[idx2]) < selector(a[idx1])) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftAscending(t, selector, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftAscending( this T[] a, Func selector, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(key) > selector(a[start + hint])) { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) > selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) <= selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(a[start + m])) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightAscending( this T[] a, Func selector, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(key) < selector(a[start + hint])) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) < selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) >= selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(a[start + m])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this T[] a, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(pivot) < selector(a[mid])) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderAscending( this T[] a, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[runHi++]) < selector(a[beginIncl])) { while (runHi < endExcl && selector(a[runHi]) < selector(a[runHi - 1])) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[runHi]) >= selector(a[runHi - 1])) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this T[] a, Func selector, long med) { long last = a.LongLength - 1; QuickMedianDescending(a, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this T[] a, Func selector, long beginIncl, long endExcl, long med) { QuickMedianDescending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this T[] a, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[e1]) < selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) < selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) < selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) < selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) < selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) < selector(p2)) { while (selector(a[hi]) < selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) < selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[lo]) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && selector(ai) > selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this T[] a, Func selector) { long last = a.LongLength - 1; QuickSortDescending(a, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this T[] a, Func selector, long beginIncl, long endExcl) { QuickSortDescending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this T[] a, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[e1]) < selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) < selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) < selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) < selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) < selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) < selector(p2)) { while (selector(a[hi]) < selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) < selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); { while (selector(a[lo]) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, selector, lo, hi, cm); QuickSortDescending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = a[i]; long j; for (j = i - 1; j >= l && selector(ai) > selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this T[] a, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = a[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) > selector(a[i2 + begin])) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[i1 + begin]) > selector(a[i2 + begin])) ? i2 : i1; // smaller child if (selector(a[ni + begin]) > selector(element)) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this T[] a, Func selector) { long count = a.LongLength; for (long c = 1; c < count; c++) { var element = a[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) > selector(a[i2])) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[i1]) > selector(a[i2])) ? i2 : i1; // smaller child if (selector(a[ni]) > selector(element)) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this T[] a, Func selector) { SmoothSortDescendingInclusiveRange(a, selector, 0, a.LongLength - 1); } public static void SmoothSortDescending( this T[] a, Func selector, long beginIncl, long endExcl) { SmoothSortDescendingInclusiveRange(a, selector, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this T[] a, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head, false); else SmoothSortDescendingSift(a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this T[] a, Func selector, int pshift, long head) { var val = a[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(val) <= selector(a[lf]) && selector(val) <= selector(a[rt])) break; if (selector(a[lf]) <= selector(a[rt])) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this T[] a, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = a[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = a[stepson]; if (selector(vstepson) >= selector(val)) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[rt]) <= selector(vstepson) || selector(a[lf]) <= selector(vstepson)) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this T[] a, Func selector) { TimSortDescending(a, selector, 0, a.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this T[] a, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, selector, lo, hi); BinarySortDescending(a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongDoubleSel(a, selector); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderDescending(a, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortDescending(a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongDesc(ti); } private static void MergeCollapseLongDesc(this TimSortInfoLongDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongDesc(ti, n); else break; } } private static void MergeForceCollapseLongDesc(this TimSortInfoLongDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } } private static void MergeAtLongDesc(this TimSortInfoLongDoubleSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightDescending(a, ti.m_sel, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_sel, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongDesc(ti, start1, len1, start2, len2); else MergeHiLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoLongDesc(this TimSortInfoLongDoubleSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, a, dest, len1); return; } if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[idx2]) > selector(t[idx1])) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightDescending(t, selector, a[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, a, dest, len1); } private static void MergeHiLongDesc(this TimSortInfoLongDoubleSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(t[idx2]) > selector(a[idx1])) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftDescending(t, selector, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftDescending( this T[] a, Func selector, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(key) < selector(a[start + hint])) { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) < selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) >= selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(a[start + m])) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightDescending( this T[] a, Func selector, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(key) > selector(a[start + hint])) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) > selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) <= selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(a[start + m])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this T[] a, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(pivot) > selector(a[mid])) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: Array.Copy(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static long CountRunAndOrderDescending( this T[] a, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[runHi++]) > selector(a[beginIncl])) { while (runHi < endExcl && selector(a[runHi]) > selector(a[runHi - 1])) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[runHi]) <= selector(a[runHi - 1])) runHi++; } return runHi - beginIncl; } #endregion #region Permutation Sort/Median for T[] /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedian( this T[] a, Func cmp, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedian(p, a, cmp, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedian( this int[] p, T[] a, Func cmp, int med) { int last = p.Length - 1; PermutationQuickMedian(p, a, cmp, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedian( this int[] p, T[] a, Func cmp, int beginIncl, int endExcl, int med) { PermutationQuickMedian(p, a, cmp, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedian( this int[] p, T[] a, Func cmp, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (cmp(a[p[e1]], a[p[e2]]) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (cmp(a[p[e4]], a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (cmp(a[p[e1]], a[p[e3]]) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (cmp(a[p[e2]], a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(a[p[e1]], a[p[e4]]) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (cmp(a[p[e3]], a[p[e4]]) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (cmp(a[p[e2]], a[p[e5]]) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (cmp(a[p[e2]], a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(a[p[e4]], a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = cmp(a[p1], a[p2]) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (cmp(a[ai], a[p2]) > 0) { while (cmp(a[p[hi]], a[p2]) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(a[ai], a[p1]) == 0) continue; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (cmp(a[p[hi]], a[p1]) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (cmp(a[p[lo]], a[p1]) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (cmp(a[p[i]], a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (cmp(a[p[hi]], a[p2]) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (cmp(a[p[i]], a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && cmp(a[ai], a[p[j]]) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSort( this T[] a, Func cmp) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSort(p, a, cmp, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSort( this int[] p, T[] a, Func cmp) { int last = p.Length - 1; PermutationQuickSort(p, a, cmp, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSort( this int[] p, T[] a, Func cmp, int beginIncl, int endExcl) { PermutationQuickSort(p, a, cmp, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSort( this int[] p, T[] a, Func cmp, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (cmp(a[p[e1]], a[p[e2]]) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (cmp(a[p[e4]], a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (cmp(a[p[e1]], a[p[e3]]) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (cmp(a[p[e2]], a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(a[p[e1]], a[p[e4]]) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (cmp(a[p[e3]], a[p[e4]]) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (cmp(a[p[e2]], a[p[e5]]) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (cmp(a[p[e2]], a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(a[p[e4]], a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = cmp(a[p1], a[p2]) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (cmp(a[ai], a[p2]) > 0) { while (cmp(a[p[hi]], a[p2]) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(a[ai], a[p1]) == 0) continue; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (cmp(a[p[hi]], a[p1]) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSort(p, a, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, cmp, hi + 2, r, cr); { while (cmp(a[p[lo]], a[p1]) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (cmp(a[p[i]], a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (cmp(a[p[hi]], a[p2]) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (cmp(a[p[i]], a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSort(p, a, cmp, lo, hi, cm); PermutationQuickSort(p, a, cmp, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSort(p, a, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, cmp, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSort(p, a, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, cmp, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSort(p, a, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, cmp, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSort(p, a, cmp, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSort(p, a, cmp, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && cmp(a[ai], a[p[j]]) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSort( this T[] a, Func cmp) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSort(p, a, cmp); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSort( this int[] p, T[] a, Func cmp, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (cmp(a[element], a[p[i2 + begin]]) < 0) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && cmp(a[p[i1 + begin]], a[p[i2 + begin]]) < 0) ? i2 : i1; // smaller child if (cmp(a[p[ni + begin]], a[element]) < 0) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSort( this int[] p, T[] a, Func cmp) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (cmp(a[element], a[p[i2]]) < 0) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && cmp(a[p[i1]], a[p[i2]]) < 0) ? i2 : i1; // smaller child if (cmp(a[p[ni]], a[element]) < 0) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSort( this T[] a, Func cmp) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSort(p, a, cmp); return p; } public static void PermutationSmoothSort( this int[] p, T[] a, Func cmp) { PermutationSmoothSortInclusiveRange(p, a, cmp, 0, p.Length - 1); } public static void PermutationSmoothSort( this int[] p, T[] a, Func cmp, int beginIncl, int endExcl) { PermutationSmoothSortInclusiveRange(p, a, cmp, beginIncl, endExcl - 1); } private static void PermutationSmoothSortInclusiveRange( this int[] p, T[] a, Func cmp, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortSift(p, a, cmp, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortTrinkle(p, a, cmp, pbits, pshift, head, false); else PermutationSmoothSortSift(p, a, cmp, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortTrinkle(p, a, cmp, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortTrinkle(p, a, cmp, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortTrinkle(p, a, cmp, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortSift( this int[] p, T[] a, Func cmp, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (cmp(a[val], a[p[lf]]) >= 0 && cmp(a[val], a[p[rt]]) >= 0) break; if (cmp(a[p[lf]], a[p[rt]]) >= 0) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortTrinkle( this int[] p, T[] a, Func cmp, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (cmp(a[vstepson], a[val]) <= 0) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (cmp(a[p[rt]], a[vstepson]) >= 0 || cmp(a[p[lf]], a[vstepson]) >= 0) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortSift(p, a, cmp, pshift, head); } } public class TimSortInfoPermCmp { public int[] m_p; public T[] m_a; public Func m_cmp; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoPermCmp(int[] p, T[] a, Func cmp) { m_p = p; m_a = a; m_cmp = cmp; int count = p.Length; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSort( this T[] a, Func cmp) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSort(p, a, cmp); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSort( this int[] p, T[] a, Func cmp) { PermutationTimSort(p, a, cmp, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSort( this int[] p, T[] a, Func cmp, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrder(p, a, cmp, lo, hi); PermutationBinarySort(p, a, cmp, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermCmp(p, a, cmp); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrder(p, a, cmp, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySort(p, a, cmp, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermCmp(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermCmp(ti); } private static void MergeCollapsePermCmp(this TimSortInfoPermCmp ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermCmp(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermCmp(ti, n); else break; } } private static void MergeForceCollapsePermCmp(this TimSortInfoPermCmp ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermCmp(ti, n); } } private static void MergeAtPermCmp(this TimSortInfoPermCmp ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRight(ti.m_p, a, ti.m_cmp, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeft(ti.m_p, a, ti.m_cmp, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermCmp(ti, start1, len1, start2, len2); else MergeHiPermCmp(ti, start1, len1, start2, len2); } private static void MergeLoPermCmp(this TimSortInfoPermCmp ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func cmp = ti.m_cmp; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (cmp(a[p[idx2]], a[t[idx1]]) < 0) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRight(t, a, cmp, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeft(p, a, cmp, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermCmp(this TimSortInfoPermCmp ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func cmp = ti.m_cmp; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (cmp(a[t[idx2]], a[p[idx1]]) < 0) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRight(p, a, cmp, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeft(t, a, cmp, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeft( this int[] p, T[] a, Func cmp, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (cmp(a[key], a[p[start + hint]]) > 0) { int maxOfs = len - hint; while (ofs < maxOfs && cmp(a[key], a[p[start + hint + ofs]]) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && cmp(a[key], a[p[start + hint - ofs]]) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (cmp(a[key], a[p[start + m]]) > 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRight( this int[] p, T[] a, Func cmp, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (cmp(a[key], a[p[start + hint]]) < 0) { int maxOfs = hint + 1; while (ofs < maxOfs && cmp(a[key], a[p[start + hint - ofs]]) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && cmp(a[key], a[p[start + hint + ofs]]) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (cmp(a[key], a[p[start + m]]) < 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySort( this int[] p, T[] a, Func cmp, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (cmp(a[pivot], a[p[mid]]) < 0) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrder( this int[] p, T[] a, Func cmp, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (cmp(a[p[runHi++]], a[p[beginIncl]]) < 0) { while (runHi < endExcl && cmp(a[p[runHi]], a[p[runHi - 1]]) < 0) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && cmp(a[p[runHi]], a[p[runHi - 1]]) >= 0) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianLong( this T[] a, Func cmp, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedian(p, a, cmp, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedian( this long[] p, T[] a, Func cmp, long med) { long last = p.LongLength - 1; PermutationQuickMedian(p, a, cmp, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedian( this long[] p, T[] a, Func cmp, long beginIncl, long endExcl, long med) { PermutationQuickMedian(p, a, cmp, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedian( this long[] p, T[] a, Func cmp, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (cmp(a[p[e1]], a[p[e2]]) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (cmp(a[p[e4]], a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (cmp(a[p[e1]], a[p[e3]]) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (cmp(a[p[e2]], a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(a[p[e1]], a[p[e4]]) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (cmp(a[p[e3]], a[p[e4]]) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (cmp(a[p[e2]], a[p[e5]]) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (cmp(a[p[e2]], a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(a[p[e4]], a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = cmp(a[p1], a[p2]) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (cmp(a[ai], a[p2]) > 0) { while (cmp(a[p[hi]], a[p2]) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(a[ai], a[p1]) == 0) continue; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (cmp(a[p[hi]], a[p1]) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (cmp(a[p[lo]], a[p1]) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (cmp(a[p[i]], a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (cmp(a[p[hi]], a[p2]) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (cmp(a[p[i]], a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && cmp(a[ai], a[p[j]]) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortLong( this T[] a, Func cmp) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSort(p, a, cmp, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSort( this long[] p, T[] a, Func cmp) { long last = p.LongLength - 1; PermutationQuickSort(p, a, cmp, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSort( this long[] p, T[] a, Func cmp, long beginIncl, long endExcl) { PermutationQuickSort(p, a, cmp, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSort( this long[] p, T[] a, Func cmp, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (cmp(a[p[e1]], a[p[e2]]) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (cmp(a[p[e4]], a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (cmp(a[p[e1]], a[p[e3]]) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (cmp(a[p[e2]], a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(a[p[e1]], a[p[e4]]) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (cmp(a[p[e3]], a[p[e4]]) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (cmp(a[p[e2]], a[p[e5]]) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (cmp(a[p[e2]], a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(a[p[e4]], a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = cmp(a[p1], a[p2]) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (cmp(a[ai], a[p2]) > 0) { while (cmp(a[p[hi]], a[p2]) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(a[ai], a[p1]) == 0) continue; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (cmp(a[p[hi]], a[p1]) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSort(p, a, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, cmp, hi + 2, r, cr); { while (cmp(a[p[lo]], a[p1]) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (cmp(a[p[i]], a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (cmp(a[p[hi]], a[p2]) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (cmp(a[p[i]], a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSort(p, a, cmp, lo, hi, cm); PermutationQuickSort(p, a, cmp, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSort(p, a, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, cmp, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSort(p, a, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, cmp, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSort(p, a, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, cmp, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSort(p, a, cmp, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSort(p, a, cmp, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && cmp(a[ai], a[p[j]]) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortLong( this T[] a, Func cmp) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSort(p, a, cmp); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSort( this long[] p, T[] a, Func cmp, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (cmp(a[element], a[p[i2 + begin]]) < 0) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && cmp(a[p[i1 + begin]], a[p[i2 + begin]]) < 0) ? i2 : i1; // smaller child if (cmp(a[p[ni + begin]], a[element]) < 0) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSort( this long[] p, T[] a, Func cmp) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (cmp(a[element], a[p[i2]]) < 0) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && cmp(a[p[i1]], a[p[i2]]) < 0) ? i2 : i1; // smaller child if (cmp(a[p[ni]], a[element]) < 0) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortLong( this T[] a, Func cmp) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSort(p, a, cmp); return p; } public static void PermutationSmoothSort( this long[] p, T[] a, Func cmp) { PermutationSmoothSortInclusiveRange(p, a, cmp, 0, p.LongLength - 1); } public static void PermutationSmoothSort( this long[] p, T[] a, Func cmp, long beginIncl, long endExcl) { PermutationSmoothSortInclusiveRange(p, a, cmp, beginIncl, endExcl - 1); } private static void PermutationSmoothSortInclusiveRange( this long[] p, T[] a, Func cmp, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortSift(p, a, cmp, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortTrinkle(p, a, cmp, pbits, pshift, head, false); else PermutationSmoothSortSift(p, a, cmp, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortTrinkle(p, a, cmp, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortTrinkle(p, a, cmp, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortTrinkle(p, a, cmp, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortSift( this long[] p, T[] a, Func cmp, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (cmp(a[val], a[p[lf]]) >= 0 && cmp(a[val], a[p[rt]]) >= 0) break; if (cmp(a[p[lf]], a[p[rt]]) >= 0) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortTrinkle( this long[] p, T[] a, Func cmp, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (cmp(a[vstepson], a[val]) <= 0) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (cmp(a[p[rt]], a[vstepson]) >= 0 || cmp(a[p[lf]], a[vstepson]) >= 0) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortSift(p, a, cmp, pshift, head); } } public class TimSortInfoPermLongCmp { public long[] m_p; public T[] m_a; public Func m_cmp; public long m_minGallop = c_minGallop; public long[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoPermLongCmp(long[] p, T[] a, Func cmp) { m_p = p; m_a = a; m_cmp = cmp; long count = p.LongLength; m_tmp = new long[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public long[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new long[c < 0 ? cap : Math.Min(c, m_p.LongLength >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortLong( this T[] a, Func cmp) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSort(p, a, cmp); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSort( this long[] p, T[] a, Func cmp) { PermutationTimSort(p, a, cmp, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSort( this long[] p, T[] a, Func cmp, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrder(p, a, cmp, lo, hi); PermutationBinarySort(p, a, cmp, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongCmp(p, a, cmp); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrder(p, a, cmp, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySort(p, a, cmp, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongCmp(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongCmp(ti); } private static void MergeCollapsePermLongCmp(this TimSortInfoPermLongCmp ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongCmp(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongCmp(ti, n); else break; } } private static void MergeForceCollapsePermLongCmp(this TimSortInfoPermLongCmp ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongCmp(ti, n); } } private static void MergeAtPermLongCmp(this TimSortInfoPermLongCmp ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRight(ti.m_p, a, ti.m_cmp, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeft(ti.m_p, a, ti.m_cmp, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongCmp(ti, start1, len1, start2, len2); else MergeHiPermLongCmp(ti, start1, len1, start2, len2); } private static void MergeLoPermLongCmp(this TimSortInfoPermLongCmp ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func cmp = ti.m_cmp; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (cmp(a[p[idx2]], a[t[idx1]]) < 0) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRight(t, a, cmp, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeft(p, a, cmp, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongCmp(this TimSortInfoPermLongCmp ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func cmp = ti.m_cmp; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (cmp(a[t[idx2]], a[p[idx1]]) < 0) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRight(p, a, cmp, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeft(t, a, cmp, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeft( this long[] p, T[] a, Func cmp, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (cmp(a[key], a[p[start + hint]]) > 0) { long maxOfs = len - hint; while (ofs < maxOfs && cmp(a[key], a[p[start + hint + ofs]]) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && cmp(a[key], a[p[start + hint - ofs]]) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (cmp(a[key], a[p[start + m]]) > 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRight( this long[] p, T[] a, Func cmp, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (cmp(a[key], a[p[start + hint]]) < 0) { long maxOfs = hint + 1; while (ofs < maxOfs && cmp(a[key], a[p[start + hint - ofs]]) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && cmp(a[key], a[p[start + hint + ofs]]) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (cmp(a[key], a[p[start + m]]) < 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySort( this long[] p, T[] a, Func cmp, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (cmp(a[pivot], a[p[mid]]) < 0) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrder( this long[] p, T[] a, Func cmp, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (cmp(a[p[runHi++]], a[p[beginIncl]]) < 0) { while (runHi < endExcl && cmp(a[p[runHi]], a[p[runHi - 1]]) < 0) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && cmp(a[p[runHi]], a[p[runHi - 1]]) >= 0) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this T[] a, int med) where T : IComparable { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, T[] a, int med) where T : IComparable { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, T[] a, int beginIncl, int endExcl, int med) where T : IComparable { PermutationQuickMedianAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, T[] a, int l, int r, int countSub1, int med) where T : IComparable { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]].CompareTo(a[p[e2]]) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]].CompareTo(a[p[e3]]) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]].CompareTo(a[p[e4]]) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]].CompareTo(a[p[e4]]) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]].CompareTo(a[p[e5]]) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1].CompareTo(a[p2]) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai].CompareTo(a[p2]) > 0) { while (a[p[hi]].CompareTo(a[p2]) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) == 0) continue; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]].CompareTo(a[p1]) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]].CompareTo(a[p1]) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]].CompareTo(a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]].CompareTo(a[p2]) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]].CompareTo(a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai].CompareTo(a[p[j]]) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this T[] a) where T : IComparable { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, T[] a) where T : IComparable { int last = p.Length - 1; PermutationQuickSortAscending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, T[] a, int beginIncl, int endExcl) where T : IComparable { PermutationQuickSortAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, T[] a, int l, int r, int countSub1) where T : IComparable { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]].CompareTo(a[p[e2]]) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]].CompareTo(a[p[e3]]) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]].CompareTo(a[p[e4]]) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]].CompareTo(a[p[e4]]) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]].CompareTo(a[p[e5]]) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1].CompareTo(a[p2]) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai].CompareTo(a[p2]) > 0) { while (a[p[hi]].CompareTo(a[p2]) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) == 0) continue; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]].CompareTo(a[p1]) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); { while (a[p[lo]].CompareTo(a[p1]) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]].CompareTo(a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]].CompareTo(a[p2]) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]].CompareTo(a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, lo, hi, cm); PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai].CompareTo(a[p[j]]) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this T[] a) where T : IComparable { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, T[] a, int begin, int end) where T : IComparable { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element].CompareTo(a[p[i2 + begin]]) < 0) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]].CompareTo(a[p[i2 + begin]]) < 0) ? i2 : i1; // smaller child if (a[p[ni + begin]].CompareTo(a[element]) < 0) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, T[] a) where T : IComparable { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element].CompareTo(a[p[i2]]) < 0) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]].CompareTo(a[p[i2]]) < 0) ? i2 : i1; // smaller child if (a[p[ni]].CompareTo(a[element]) < 0) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this T[] a) where T : IComparable { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a); return p; } public static void PermutationSmoothSortAscending( this int[] p, T[] a) where T : IComparable { PermutationSmoothSortAscendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, T[] a, int beginIncl, int endExcl) where T : IComparable { PermutationSmoothSortAscendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, T[] a, int lo, int hi) where T : IComparable { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, T[] a, int pshift, int head) where T : IComparable { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val].CompareTo(a[p[lf]]) >= 0 && a[val].CompareTo(a[p[rt]]) >= 0) break; if (a[p[lf]].CompareTo(a[p[rt]]) >= 0) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, T[] a, long pbits, int pshift, int head, bool isTrusty) where T : IComparable { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson].CompareTo(a[val]) <= 0) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]].CompareTo(a[vstepson]) >= 0 || a[p[lf]].CompareTo(a[vstepson]) >= 0) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, pshift, head); } } public class TimSortInfoPerm where T : IComparable { public int[] m_p; public T[] m_a; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoPerm(int[] p, T[] a) { m_p = p; m_a = a; int count = p.Length; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this T[] a) where T : IComparable { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, T[] a) where T : IComparable { PermutationTimSortAscending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, T[] a, int lo, int hi) where T : IComparable { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); PermutationBinarySortAscending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermAsc(ti); } private static void MergeCollapsePermAsc(this TimSortInfoPerm ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermAsc(ti, n); else break; } } private static void MergeForceCollapsePermAsc(this TimSortInfoPerm ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } } private static void MergeAtPermAsc(this TimSortInfoPerm ti, int i) where T : IComparable { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermAsc(ti, start1, len1, start2, len2); else MergeHiPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermAsc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]].CompareTo(a[t[idx1]]) < 0) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermAsc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]].CompareTo(a[p[idx1]]) < 0) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, T[] a, int key, int start, int len, int hint) where T : IComparable { int lastOfs = 0, ofs = 1; if (a[key].CompareTo(a[p[start + hint]]) > 0) { int maxOfs = len - hint; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint + ofs]]) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint - ofs]]) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key].CompareTo(a[p[start + m]]) > 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, T[] a, int key, int start, int len, int hint) where T : IComparable { int ofs = 1, lastOfs = 0; if (a[key].CompareTo(a[p[start + hint]]) < 0) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint - ofs]]) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint + ofs]]) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key].CompareTo(a[p[start + m]]) < 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, T[] a, int beginIncl, int endExcl, int beginUnsorted) where T : IComparable { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot].CompareTo(a[p[mid]]) < 0) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, T[] a, int beginIncl, int endExcl) where T : IComparable { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]].CompareTo(a[p[beginIncl]]) < 0) { while (runHi < endExcl && a[p[runHi]].CompareTo(a[p[runHi - 1]]) < 0) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]].CompareTo(a[p[runHi - 1]]) >= 0) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianAscendingLong( this T[] a, long med) where T : IComparable { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianAscending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this long[] p, T[] a, long med) where T : IComparable { long last = p.LongLength - 1; PermutationQuickMedianAscending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this long[] p, T[] a, long beginIncl, long endExcl, long med) where T : IComparable { PermutationQuickMedianAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this long[] p, T[] a, long l, long r, long countSub1, long med) where T : IComparable { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]].CompareTo(a[p[e2]]) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]].CompareTo(a[p[e3]]) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]].CompareTo(a[p[e4]]) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]].CompareTo(a[p[e4]]) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]].CompareTo(a[p[e5]]) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1].CompareTo(a[p2]) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai].CompareTo(a[p2]) > 0) { while (a[p[hi]].CompareTo(a[p2]) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) == 0) continue; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]].CompareTo(a[p1]) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]].CompareTo(a[p1]) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]].CompareTo(a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]].CompareTo(a[p2]) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]].CompareTo(a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai].CompareTo(a[p[j]]) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortAscendingLong( this T[] a) where T : IComparable { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortAscending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, T[] a) where T : IComparable { long last = p.LongLength - 1; PermutationQuickSortAscending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, T[] a, long beginIncl, long endExcl) where T : IComparable { PermutationQuickSortAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this long[] p, T[] a, long l, long r, long countSub1) where T : IComparable { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]].CompareTo(a[p[e2]]) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]].CompareTo(a[p[e3]]) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]].CompareTo(a[p[e4]]) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]].CompareTo(a[p[e4]]) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]].CompareTo(a[p[e5]]) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1].CompareTo(a[p2]) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai].CompareTo(a[p2]) > 0) { while (a[p[hi]].CompareTo(a[p2]) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) == 0) continue; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]].CompareTo(a[p1]) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); { while (a[p[lo]].CompareTo(a[p1]) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]].CompareTo(a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]].CompareTo(a[p2]) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]].CompareTo(a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, lo, hi, cm); PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai].CompareTo(a[p[j]]) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortAscendingLong( this T[] a) where T : IComparable { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortAscending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, T[] a, long begin, long end) where T : IComparable { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element].CompareTo(a[p[i2 + begin]]) < 0) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1 + begin]].CompareTo(a[p[i2 + begin]]) < 0) ? i2 : i1; // smaller child if (a[p[ni + begin]].CompareTo(a[element]) < 0) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, T[] a) where T : IComparable { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element].CompareTo(a[p[i2]]) < 0) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1]].CompareTo(a[p[i2]]) < 0) ? i2 : i1; // smaller child if (a[p[ni]].CompareTo(a[element]) < 0) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortAscendingLong( this T[] a) where T : IComparable { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortAscending(p, a); return p; } public static void PermutationSmoothSortAscending( this long[] p, T[] a) where T : IComparable { PermutationSmoothSortAscendingInclusiveRange(p, a, 0, p.LongLength - 1); } public static void PermutationSmoothSortAscending( this long[] p, T[] a, long beginIncl, long endExcl) where T : IComparable { PermutationSmoothSortAscendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this long[] p, T[] a, long lo, long hi) where T : IComparable { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this long[] p, T[] a, int pshift, long head) where T : IComparable { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[val].CompareTo(a[p[lf]]) >= 0 && a[val].CompareTo(a[p[rt]]) >= 0) break; if (a[p[lf]].CompareTo(a[p[rt]]) >= 0) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this long[] p, T[] a, long pbits, int pshift, long head, bool isTrusty) where T : IComparable { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (a[vstepson].CompareTo(a[val]) <= 0) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[p[rt]].CompareTo(a[vstepson]) >= 0 || a[p[lf]].CompareTo(a[vstepson]) >= 0) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, pshift, head); } } public class TimSortInfoPermLong where T : IComparable { public long[] m_p; public T[] m_a; public long m_minGallop = c_minGallop; public long[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoPermLong(long[] p, T[] a) { m_p = p; m_a = a; long count = p.LongLength; m_tmp = new long[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public long[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new long[c < 0 ? cap : Math.Min(c, m_p.LongLength >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortAscendingLong( this T[] a) where T : IComparable { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortAscending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, T[] a) where T : IComparable { PermutationTimSortAscending(p, a, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, T[] a, long lo, long hi) where T : IComparable { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); PermutationBinarySortAscending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLong(p, a); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongAsc(ti); } private static void MergeCollapsePermLongAsc(this TimSortInfoPermLong ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongAsc(ti, n); else break; } } private static void MergeForceCollapsePermLongAsc(this TimSortInfoPermLong ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } } private static void MergeAtPermLongAsc(this TimSortInfoPermLong ti, int i) where T : IComparable { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightAscending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongAsc(ti, start1, len1, start2, len2); else MergeHiPermLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongAsc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[p[idx2]].CompareTo(a[t[idx1]]) < 0) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongAsc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[t[idx2]].CompareTo(a[p[idx1]]) < 0) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftAscending( this long[] p, T[] a, long key, long start, long len, long hint) where T : IComparable { long lastOfs = 0, ofs = 1; if (a[key].CompareTo(a[p[start + hint]]) > 0) { long maxOfs = len - hint; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint + ofs]]) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint - ofs]]) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key].CompareTo(a[p[start + m]]) > 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightAscending( this long[] p, T[] a, long key, long start, long len, long hint) where T : IComparable { long ofs = 1, lastOfs = 0; if (a[key].CompareTo(a[p[start + hint]]) < 0) { long maxOfs = hint + 1; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint - ofs]]) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint + ofs]]) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key].CompareTo(a[p[start + m]]) < 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this long[] p, T[] a, long beginIncl, long endExcl, long beginUnsorted) where T : IComparable { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (a[pivot].CompareTo(a[p[mid]]) < 0) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderAscending( this long[] p, T[] a, long beginIncl, long endExcl) where T : IComparable { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]].CompareTo(a[p[beginIncl]]) < 0) { while (runHi < endExcl && a[p[runHi]].CompareTo(a[p[runHi - 1]]) < 0) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]].CompareTo(a[p[runHi - 1]]) >= 0) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this T[] a, int med) where T : IComparable { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, T[] a, int med) where T : IComparable { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, T[] a, int beginIncl, int endExcl, int med) where T : IComparable { PermutationQuickMedianDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, T[] a, int l, int r, int countSub1, int med) where T : IComparable { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]].CompareTo(a[p[e2]]) < 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]].CompareTo(a[p[e3]]) < 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]].CompareTo(a[p[e4]]) < 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]].CompareTo(a[p[e4]]) < 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]].CompareTo(a[p[e5]]) < 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1].CompareTo(a[p2]) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai].CompareTo(a[p2]) < 0) { while (a[p[hi]].CompareTo(a[p2]) < 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) == 0) continue; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]].CompareTo(a[p1]) < 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]].CompareTo(a[p1]) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]].CompareTo(a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]].CompareTo(a[p2]) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]].CompareTo(a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai].CompareTo(a[p[j]]) > 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this T[] a) where T : IComparable { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, T[] a) where T : IComparable { int last = p.Length - 1; PermutationQuickSortDescending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, T[] a, int beginIncl, int endExcl) where T : IComparable { PermutationQuickSortDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, T[] a, int l, int r, int countSub1) where T : IComparable { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]].CompareTo(a[p[e2]]) < 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]].CompareTo(a[p[e3]]) < 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]].CompareTo(a[p[e4]]) < 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]].CompareTo(a[p[e4]]) < 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]].CompareTo(a[p[e5]]) < 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1].CompareTo(a[p2]) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai].CompareTo(a[p2]) < 0) { while (a[p[hi]].CompareTo(a[p2]) < 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) == 0) continue; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]].CompareTo(a[p1]) < 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); { while (a[p[lo]].CompareTo(a[p1]) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]].CompareTo(a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]].CompareTo(a[p2]) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]].CompareTo(a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, lo, hi, cm); PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai].CompareTo(a[p[j]]) > 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this T[] a) where T : IComparable { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, T[] a, int begin, int end) where T : IComparable { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element].CompareTo(a[p[i2 + begin]]) > 0) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]].CompareTo(a[p[i2 + begin]]) > 0) ? i2 : i1; // smaller child if (a[p[ni + begin]].CompareTo(a[element]) > 0) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, T[] a) where T : IComparable { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element].CompareTo(a[p[i2]]) > 0) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]].CompareTo(a[p[i2]]) > 0) ? i2 : i1; // smaller child if (a[p[ni]].CompareTo(a[element]) > 0) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this T[] a) where T : IComparable { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a); return p; } public static void PermutationSmoothSortDescending( this int[] p, T[] a) where T : IComparable { PermutationSmoothSortDescendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, T[] a, int beginIncl, int endExcl) where T : IComparable { PermutationSmoothSortDescendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, T[] a, int lo, int hi) where T : IComparable { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, T[] a, int pshift, int head) where T : IComparable { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val].CompareTo(a[p[lf]]) <= 0 && a[val].CompareTo(a[p[rt]]) <= 0) break; if (a[p[lf]].CompareTo(a[p[rt]]) <= 0) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, T[] a, long pbits, int pshift, int head, bool isTrusty) where T : IComparable { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson].CompareTo(a[val]) >= 0) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]].CompareTo(a[vstepson]) <= 0 || a[p[lf]].CompareTo(a[vstepson]) <= 0) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this T[] a) where T : IComparable { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, T[] a) where T : IComparable { PermutationTimSortDescending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, T[] a, int lo, int hi) where T : IComparable { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); PermutationBinarySortDescending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermDesc(ti); } private static void MergeCollapsePermDesc(this TimSortInfoPerm ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermDesc(ti, n); else break; } } private static void MergeForceCollapsePermDesc(this TimSortInfoPerm ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } } private static void MergeAtPermDesc(this TimSortInfoPerm ti, int i) where T : IComparable { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermDesc(ti, start1, len1, start2, len2); else MergeHiPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermDesc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]].CompareTo(a[t[idx1]]) > 0) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermDesc(this TimSortInfoPerm ti, int start1, int len1, int start2, int len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]].CompareTo(a[p[idx1]]) > 0) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, T[] a, int key, int start, int len, int hint) where T : IComparable { int lastOfs = 0, ofs = 1; if (a[key].CompareTo(a[p[start + hint]]) < 0) { int maxOfs = len - hint; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint + ofs]]) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint - ofs]]) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key].CompareTo(a[p[start + m]]) < 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, T[] a, int key, int start, int len, int hint) where T : IComparable { int ofs = 1, lastOfs = 0; if (a[key].CompareTo(a[p[start + hint]]) > 0) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint - ofs]]) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint + ofs]]) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key].CompareTo(a[p[start + m]]) > 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, T[] a, int beginIncl, int endExcl, int beginUnsorted) where T : IComparable { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot].CompareTo(a[p[mid]]) > 0) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, T[] a, int beginIncl, int endExcl) where T : IComparable { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]].CompareTo(a[p[beginIncl]]) > 0) { while (runHi < endExcl && a[p[runHi]].CompareTo(a[p[runHi - 1]]) > 0) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]].CompareTo(a[p[runHi - 1]]) <= 0) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianDescendingLong( this T[] a, long med) where T : IComparable { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianDescending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this long[] p, T[] a, long med) where T : IComparable { long last = p.LongLength - 1; PermutationQuickMedianDescending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this long[] p, T[] a, long beginIncl, long endExcl, long med) where T : IComparable { PermutationQuickMedianDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this long[] p, T[] a, long l, long r, long countSub1, long med) where T : IComparable { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]].CompareTo(a[p[e2]]) < 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]].CompareTo(a[p[e3]]) < 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]].CompareTo(a[p[e4]]) < 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]].CompareTo(a[p[e4]]) < 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]].CompareTo(a[p[e5]]) < 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1].CompareTo(a[p2]) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai].CompareTo(a[p2]) < 0) { while (a[p[hi]].CompareTo(a[p2]) < 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) == 0) continue; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]].CompareTo(a[p1]) < 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]].CompareTo(a[p1]) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]].CompareTo(a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]].CompareTo(a[p2]) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]].CompareTo(a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai].CompareTo(a[p[j]]) > 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortDescendingLong( this T[] a) where T : IComparable { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortDescending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, T[] a) where T : IComparable { long last = p.LongLength - 1; PermutationQuickSortDescending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, T[] a, long beginIncl, long endExcl) where T : IComparable { PermutationQuickSortDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this long[] p, T[] a, long l, long r, long countSub1) where T : IComparable { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (a[p[e1]].CompareTo(a[p[e2]]) < 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]].CompareTo(a[p[e3]]) < 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]].CompareTo(a[p[e4]]) < 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]].CompareTo(a[p[e4]]) < 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]].CompareTo(a[p[e5]]) < 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = a[p1].CompareTo(a[p2]) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai].CompareTo(a[p2]) < 0) { while (a[p[hi]].CompareTo(a[p2]) < 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) == 0) continue; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]].CompareTo(a[p1]) < 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); { while (a[p[lo]].CompareTo(a[p1]) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (a[p[i]].CompareTo(a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]].CompareTo(a[p2]) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (a[p[i]].CompareTo(a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, lo, hi, cm); PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && a[ai].CompareTo(a[p[j]]) > 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortDescendingLong( this T[] a) where T : IComparable { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortDescending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, T[] a, long begin, long end) where T : IComparable { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element].CompareTo(a[p[i2 + begin]]) > 0) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1 + begin]].CompareTo(a[p[i2 + begin]]) > 0) ? i2 : i1; // smaller child if (a[p[ni + begin]].CompareTo(a[element]) > 0) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, T[] a) where T : IComparable { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (a[element].CompareTo(a[p[i2]]) > 0) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && a[p[i1]].CompareTo(a[p[i2]]) > 0) ? i2 : i1; // smaller child if (a[p[ni]].CompareTo(a[element]) > 0) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortDescendingLong( this T[] a) where T : IComparable { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortDescending(p, a); return p; } public static void PermutationSmoothSortDescending( this long[] p, T[] a) where T : IComparable { PermutationSmoothSortDescendingInclusiveRange(p, a, 0, p.LongLength - 1); } public static void PermutationSmoothSortDescending( this long[] p, T[] a, long beginIncl, long endExcl) where T : IComparable { PermutationSmoothSortDescendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this long[] p, T[] a, long lo, long hi) where T : IComparable { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this long[] p, T[] a, int pshift, long head) where T : IComparable { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[val].CompareTo(a[p[lf]]) <= 0 && a[val].CompareTo(a[p[rt]]) <= 0) break; if (a[p[lf]].CompareTo(a[p[rt]]) <= 0) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this long[] p, T[] a, long pbits, int pshift, long head, bool isTrusty) where T : IComparable { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (a[vstepson].CompareTo(a[val]) >= 0) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (a[p[rt]].CompareTo(a[vstepson]) <= 0 || a[p[lf]].CompareTo(a[vstepson]) <= 0) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortDescendingLong( this T[] a) where T : IComparable { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortDescending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, T[] a) where T : IComparable { PermutationTimSortDescending(p, a, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, T[] a, long lo, long hi) where T : IComparable { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); PermutationBinarySortDescending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLong(p, a); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongDesc(ti); } private static void MergeCollapsePermLongDesc(this TimSortInfoPermLong ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongDesc(ti, n); else break; } } private static void MergeForceCollapsePermLongDesc(this TimSortInfoPermLong ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } } private static void MergeAtPermLongDesc(this TimSortInfoPermLong ti, int i) where T : IComparable { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightDescending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongDesc(ti, start1, len1, start2, len2); else MergeHiPermLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongDesc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[p[idx2]].CompareTo(a[t[idx1]]) > 0) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongDesc(this TimSortInfoPermLong ti, long start1, long len1, long start2, long len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (a[t[idx2]].CompareTo(a[p[idx1]]) > 0) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftDescending( this long[] p, T[] a, long key, long start, long len, long hint) where T : IComparable { long lastOfs = 0, ofs = 1; if (a[key].CompareTo(a[p[start + hint]]) < 0) { long maxOfs = len - hint; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint + ofs]]) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint - ofs]]) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key].CompareTo(a[p[start + m]]) < 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightDescending( this long[] p, T[] a, long key, long start, long len, long hint) where T : IComparable { long ofs = 1, lastOfs = 0; if (a[key].CompareTo(a[p[start + hint]]) > 0) { long maxOfs = hint + 1; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint - ofs]]) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint + ofs]]) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key].CompareTo(a[p[start + m]]) > 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this long[] p, T[] a, long beginIncl, long endExcl, long beginUnsorted) where T : IComparable { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (a[pivot].CompareTo(a[p[mid]]) > 0) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderDescending( this long[] p, T[] a, long beginIncl, long endExcl) where T : IComparable { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]].CompareTo(a[p[beginIncl]]) > 0) { while (runHi < endExcl && a[p[runHi]].CompareTo(a[p[runHi - 1]]) > 0) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]].CompareTo(a[p[runHi - 1]]) <= 0) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this T[] a, Func selector, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, T[] a, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, T[] a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, T[] a, Func selector) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, T[] a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, T[] a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) < selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) < selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, T[] a, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1]]) < selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) < selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a, selector); return p; } public static void PermutationSmoothSortAscending( this int[] p, T[] a, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, T[] a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, T[] a, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[val]) >= selector(a[p[lf]]) && selector(a[val]) >= selector(a[p[rt]])) break; if (selector(a[p[lf]]) >= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, T[] a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) <= selector(a[val])) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[p[rt]]) >= selector(a[vstepson]) || selector(a[p[lf]]) >= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); } } public class TimSortInfoPermIntSel { public int[] m_p; public T[] m_a; public Func m_sel; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoPermIntSel(int[] p, T[] a, Func selector) { m_p = p; m_a = a; m_sel = selector; int count = p.Length; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, T[] a, Func selector) { PermutationTimSortAscending(p, a, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, T[] a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); PermutationBinarySortAscending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermIntSel(p, a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermAsc(ti); } private static void MergeCollapsePermAsc(this TimSortInfoPermIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermAsc(ti, n); else break; } } private static void MergeForceCollapsePermAsc(this TimSortInfoPermIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } } private static void MergeAtPermAsc(this TimSortInfoPermIntSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermAsc(ti, start1, len1, start2, len2); else MergeHiPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermAsc(this TimSortInfoPermIntSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) < selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermAsc(this TimSortInfoPermIntSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) < selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, T[] a, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(a[key]) > selector(a[p[start + hint]])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, T[] a, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(a[key]) < selector(a[p[start + hint]])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(a[pivot]) < selector(a[p[mid]])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) < selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) < selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) >= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianAscendingLong( this T[] a, Func selector, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianAscending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this long[] p, T[] a, Func selector, long med) { long last = p.LongLength - 1; PermutationQuickMedianAscending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl, long med) { PermutationQuickMedianAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this long[] p, T[] a, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortAscendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortAscending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, T[] a, Func selector) { long last = p.LongLength - 1; PermutationQuickSortAscending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { PermutationQuickSortAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this long[] p, T[] a, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortAscendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortAscending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, T[] a, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) < selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) < selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, T[] a, Func selector) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[p[i1]]) < selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) < selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortAscendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortAscending(p, a, selector); return p; } public static void PermutationSmoothSortAscending( this long[] p, T[] a, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, 0, p.LongLength - 1); } public static void PermutationSmoothSortAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this long[] p, T[] a, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this long[] p, T[] a, Func selector, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[val]) >= selector(a[p[lf]]) && selector(a[val]) >= selector(a[p[rt]])) break; if (selector(a[p[lf]]) >= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this long[] p, T[] a, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) <= selector(a[val])) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[p[rt]]) >= selector(a[vstepson]) || selector(a[p[lf]]) >= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); } } public class TimSortInfoPermLongIntSel { public long[] m_p; public T[] m_a; public Func m_sel; public long m_minGallop = c_minGallop; public long[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoPermLongIntSel(long[] p, T[] a, Func selector) { m_p = p; m_a = a; m_sel = selector; long count = p.LongLength; m_tmp = new long[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public long[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new long[c < 0 ? cap : Math.Min(c, m_p.LongLength >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortAscendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortAscending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, T[] a, Func selector) { PermutationTimSortAscending(p, a, selector, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, T[] a, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); PermutationBinarySortAscending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongIntSel(p, a, selector); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongAsc(ti); } private static void MergeCollapsePermLongAsc(this TimSortInfoPermLongIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongAsc(ti, n); else break; } } private static void MergeForceCollapsePermLongAsc(this TimSortInfoPermLongIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } } private static void MergeAtPermLongAsc(this TimSortInfoPermLongIntSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightAscending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongAsc(ti, start1, len1, start2, len2); else MergeHiPermLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongAsc(this TimSortInfoPermLongIntSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) < selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongAsc(this TimSortInfoPermLongIntSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) < selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftAscending( this long[] p, T[] a, Func selector, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(a[key]) > selector(a[p[start + hint]])) { long maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightAscending( this long[] p, T[] a, Func selector, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(a[key]) < selector(a[p[start + hint]])) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(a[pivot]) < selector(a[p[mid]])) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) < selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) < selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) >= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this T[] a, Func selector, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, T[] a, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, T[] a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, T[] a, Func selector) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, T[] a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, T[] a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) > selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) > selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, T[] a, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1]]) > selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) > selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a, selector); return p; } public static void PermutationSmoothSortDescending( this int[] p, T[] a, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, T[] a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, T[] a, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[val]) <= selector(a[p[lf]]) && selector(a[val]) <= selector(a[p[rt]])) break; if (selector(a[p[lf]]) <= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, T[] a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) >= selector(a[val])) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[p[rt]]) <= selector(a[vstepson]) || selector(a[p[lf]]) <= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, T[] a, Func selector) { PermutationTimSortDescending(p, a, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, T[] a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); PermutationBinarySortDescending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermIntSel(p, a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermDesc(ti); } private static void MergeCollapsePermDesc(this TimSortInfoPermIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermDesc(ti, n); else break; } } private static void MergeForceCollapsePermDesc(this TimSortInfoPermIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } } private static void MergeAtPermDesc(this TimSortInfoPermIntSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermDesc(ti, start1, len1, start2, len2); else MergeHiPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermDesc(this TimSortInfoPermIntSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) > selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermDesc(this TimSortInfoPermIntSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) > selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, T[] a, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(a[key]) < selector(a[p[start + hint]])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, T[] a, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(a[key]) > selector(a[p[start + hint]])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(a[pivot]) > selector(a[p[mid]])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) > selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) > selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) <= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianDescendingLong( this T[] a, Func selector, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianDescending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this long[] p, T[] a, Func selector, long med) { long last = p.LongLength - 1; PermutationQuickMedianDescending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl, long med) { PermutationQuickMedianDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this long[] p, T[] a, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortDescendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortDescending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, T[] a, Func selector) { long last = p.LongLength - 1; PermutationQuickSortDescending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { PermutationQuickSortDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this long[] p, T[] a, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortDescendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortDescending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, T[] a, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) > selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) > selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, T[] a, Func selector) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[p[i1]]) > selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) > selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortDescendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortDescending(p, a, selector); return p; } public static void PermutationSmoothSortDescending( this long[] p, T[] a, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, 0, p.LongLength - 1); } public static void PermutationSmoothSortDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this long[] p, T[] a, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this long[] p, T[] a, Func selector, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[val]) <= selector(a[p[lf]]) && selector(a[val]) <= selector(a[p[rt]])) break; if (selector(a[p[lf]]) <= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this long[] p, T[] a, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) >= selector(a[val])) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[p[rt]]) <= selector(a[vstepson]) || selector(a[p[lf]]) <= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortDescendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortDescending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, T[] a, Func selector) { PermutationTimSortDescending(p, a, selector, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, T[] a, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); PermutationBinarySortDescending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongIntSel(p, a, selector); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongDesc(ti); } private static void MergeCollapsePermLongDesc(this TimSortInfoPermLongIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongDesc(ti, n); else break; } } private static void MergeForceCollapsePermLongDesc(this TimSortInfoPermLongIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } } private static void MergeAtPermLongDesc(this TimSortInfoPermLongIntSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightDescending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongDesc(ti, start1, len1, start2, len2); else MergeHiPermLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongDesc(this TimSortInfoPermLongIntSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) > selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongDesc(this TimSortInfoPermLongIntSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) > selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftDescending( this long[] p, T[] a, Func selector, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(a[key]) < selector(a[p[start + hint]])) { long maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightDescending( this long[] p, T[] a, Func selector, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(a[key]) > selector(a[p[start + hint]])) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(a[pivot]) > selector(a[p[mid]])) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) > selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) > selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) <= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this T[] a, Func selector, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, T[] a, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, T[] a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, T[] a, Func selector) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, T[] a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, T[] a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) < selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) < selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, T[] a, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1]]) < selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) < selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a, selector); return p; } public static void PermutationSmoothSortAscending( this int[] p, T[] a, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, T[] a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, T[] a, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[val]) >= selector(a[p[lf]]) && selector(a[val]) >= selector(a[p[rt]])) break; if (selector(a[p[lf]]) >= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, T[] a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) <= selector(a[val])) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[p[rt]]) >= selector(a[vstepson]) || selector(a[p[lf]]) >= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); } } public class TimSortInfoPermLongSel { public int[] m_p; public T[] m_a; public Func m_sel; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoPermLongSel(int[] p, T[] a, Func selector) { m_p = p; m_a = a; m_sel = selector; int count = p.Length; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, T[] a, Func selector) { PermutationTimSortAscending(p, a, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, T[] a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); PermutationBinarySortAscending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongSel(p, a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermAsc(ti); } private static void MergeCollapsePermAsc(this TimSortInfoPermLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermAsc(ti, n); else break; } } private static void MergeForceCollapsePermAsc(this TimSortInfoPermLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } } private static void MergeAtPermAsc(this TimSortInfoPermLongSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermAsc(ti, start1, len1, start2, len2); else MergeHiPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermAsc(this TimSortInfoPermLongSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) < selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermAsc(this TimSortInfoPermLongSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) < selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, T[] a, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(a[key]) > selector(a[p[start + hint]])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, T[] a, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(a[key]) < selector(a[p[start + hint]])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(a[pivot]) < selector(a[p[mid]])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) < selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) < selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) >= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianAscendingLong( this T[] a, Func selector, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianAscending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this long[] p, T[] a, Func selector, long med) { long last = p.LongLength - 1; PermutationQuickMedianAscending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl, long med) { PermutationQuickMedianAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this long[] p, T[] a, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortAscendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortAscending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, T[] a, Func selector) { long last = p.LongLength - 1; PermutationQuickSortAscending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { PermutationQuickSortAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this long[] p, T[] a, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortAscendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortAscending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, T[] a, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) < selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) < selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, T[] a, Func selector) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[p[i1]]) < selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) < selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortAscendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortAscending(p, a, selector); return p; } public static void PermutationSmoothSortAscending( this long[] p, T[] a, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, 0, p.LongLength - 1); } public static void PermutationSmoothSortAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this long[] p, T[] a, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this long[] p, T[] a, Func selector, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[val]) >= selector(a[p[lf]]) && selector(a[val]) >= selector(a[p[rt]])) break; if (selector(a[p[lf]]) >= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this long[] p, T[] a, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) <= selector(a[val])) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[p[rt]]) >= selector(a[vstepson]) || selector(a[p[lf]]) >= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); } } public class TimSortInfoPermLongLongSel { public long[] m_p; public T[] m_a; public Func m_sel; public long m_minGallop = c_minGallop; public long[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoPermLongLongSel(long[] p, T[] a, Func selector) { m_p = p; m_a = a; m_sel = selector; long count = p.LongLength; m_tmp = new long[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public long[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new long[c < 0 ? cap : Math.Min(c, m_p.LongLength >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortAscendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortAscending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, T[] a, Func selector) { PermutationTimSortAscending(p, a, selector, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, T[] a, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); PermutationBinarySortAscending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongLongSel(p, a, selector); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongAsc(ti); } private static void MergeCollapsePermLongAsc(this TimSortInfoPermLongLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongAsc(ti, n); else break; } } private static void MergeForceCollapsePermLongAsc(this TimSortInfoPermLongLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } } private static void MergeAtPermLongAsc(this TimSortInfoPermLongLongSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightAscending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongAsc(ti, start1, len1, start2, len2); else MergeHiPermLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongAsc(this TimSortInfoPermLongLongSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) < selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongAsc(this TimSortInfoPermLongLongSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) < selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftAscending( this long[] p, T[] a, Func selector, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(a[key]) > selector(a[p[start + hint]])) { long maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightAscending( this long[] p, T[] a, Func selector, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(a[key]) < selector(a[p[start + hint]])) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(a[pivot]) < selector(a[p[mid]])) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) < selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) < selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) >= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this T[] a, Func selector, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, T[] a, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, T[] a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, T[] a, Func selector) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, T[] a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, T[] a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) > selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) > selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, T[] a, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1]]) > selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) > selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a, selector); return p; } public static void PermutationSmoothSortDescending( this int[] p, T[] a, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, T[] a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, T[] a, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[val]) <= selector(a[p[lf]]) && selector(a[val]) <= selector(a[p[rt]])) break; if (selector(a[p[lf]]) <= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, T[] a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) >= selector(a[val])) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[p[rt]]) <= selector(a[vstepson]) || selector(a[p[lf]]) <= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, T[] a, Func selector) { PermutationTimSortDescending(p, a, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, T[] a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); PermutationBinarySortDescending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongSel(p, a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermDesc(ti); } private static void MergeCollapsePermDesc(this TimSortInfoPermLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermDesc(ti, n); else break; } } private static void MergeForceCollapsePermDesc(this TimSortInfoPermLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } } private static void MergeAtPermDesc(this TimSortInfoPermLongSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermDesc(ti, start1, len1, start2, len2); else MergeHiPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermDesc(this TimSortInfoPermLongSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) > selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermDesc(this TimSortInfoPermLongSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) > selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, T[] a, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(a[key]) < selector(a[p[start + hint]])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, T[] a, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(a[key]) > selector(a[p[start + hint]])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(a[pivot]) > selector(a[p[mid]])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) > selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) > selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) <= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianDescendingLong( this T[] a, Func selector, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianDescending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this long[] p, T[] a, Func selector, long med) { long last = p.LongLength - 1; PermutationQuickMedianDescending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl, long med) { PermutationQuickMedianDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this long[] p, T[] a, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortDescendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortDescending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, T[] a, Func selector) { long last = p.LongLength - 1; PermutationQuickSortDescending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { PermutationQuickSortDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this long[] p, T[] a, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortDescendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortDescending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, T[] a, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) > selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) > selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, T[] a, Func selector) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[p[i1]]) > selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) > selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortDescendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortDescending(p, a, selector); return p; } public static void PermutationSmoothSortDescending( this long[] p, T[] a, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, 0, p.LongLength - 1); } public static void PermutationSmoothSortDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this long[] p, T[] a, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this long[] p, T[] a, Func selector, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[val]) <= selector(a[p[lf]]) && selector(a[val]) <= selector(a[p[rt]])) break; if (selector(a[p[lf]]) <= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this long[] p, T[] a, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) >= selector(a[val])) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[p[rt]]) <= selector(a[vstepson]) || selector(a[p[lf]]) <= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortDescendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortDescending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, T[] a, Func selector) { PermutationTimSortDescending(p, a, selector, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, T[] a, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); PermutationBinarySortDescending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongLongSel(p, a, selector); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongDesc(ti); } private static void MergeCollapsePermLongDesc(this TimSortInfoPermLongLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongDesc(ti, n); else break; } } private static void MergeForceCollapsePermLongDesc(this TimSortInfoPermLongLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } } private static void MergeAtPermLongDesc(this TimSortInfoPermLongLongSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightDescending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongDesc(ti, start1, len1, start2, len2); else MergeHiPermLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongDesc(this TimSortInfoPermLongLongSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) > selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongDesc(this TimSortInfoPermLongLongSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) > selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftDescending( this long[] p, T[] a, Func selector, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(a[key]) < selector(a[p[start + hint]])) { long maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightDescending( this long[] p, T[] a, Func selector, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(a[key]) > selector(a[p[start + hint]])) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(a[pivot]) > selector(a[p[mid]])) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) > selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) > selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) <= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this T[] a, Func selector, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, T[] a, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, T[] a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, T[] a, Func selector) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, T[] a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, T[] a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) < selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) < selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, T[] a, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1]]) < selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) < selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a, selector); return p; } public static void PermutationSmoothSortAscending( this int[] p, T[] a, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, T[] a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, T[] a, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[val]) >= selector(a[p[lf]]) && selector(a[val]) >= selector(a[p[rt]])) break; if (selector(a[p[lf]]) >= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, T[] a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) <= selector(a[val])) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[p[rt]]) >= selector(a[vstepson]) || selector(a[p[lf]]) >= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); } } public class TimSortInfoPermFloatSel { public int[] m_p; public T[] m_a; public Func m_sel; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoPermFloatSel(int[] p, T[] a, Func selector) { m_p = p; m_a = a; m_sel = selector; int count = p.Length; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, T[] a, Func selector) { PermutationTimSortAscending(p, a, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, T[] a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); PermutationBinarySortAscending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermFloatSel(p, a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermAsc(ti); } private static void MergeCollapsePermAsc(this TimSortInfoPermFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermAsc(ti, n); else break; } } private static void MergeForceCollapsePermAsc(this TimSortInfoPermFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } } private static void MergeAtPermAsc(this TimSortInfoPermFloatSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermAsc(ti, start1, len1, start2, len2); else MergeHiPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermAsc(this TimSortInfoPermFloatSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) < selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermAsc(this TimSortInfoPermFloatSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) < selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, T[] a, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(a[key]) > selector(a[p[start + hint]])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, T[] a, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(a[key]) < selector(a[p[start + hint]])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(a[pivot]) < selector(a[p[mid]])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) < selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) < selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) >= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianAscendingLong( this T[] a, Func selector, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianAscending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this long[] p, T[] a, Func selector, long med) { long last = p.LongLength - 1; PermutationQuickMedianAscending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl, long med) { PermutationQuickMedianAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this long[] p, T[] a, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortAscendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortAscending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, T[] a, Func selector) { long last = p.LongLength - 1; PermutationQuickSortAscending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { PermutationQuickSortAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this long[] p, T[] a, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortAscendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortAscending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, T[] a, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) < selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) < selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, T[] a, Func selector) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[p[i1]]) < selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) < selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortAscendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortAscending(p, a, selector); return p; } public static void PermutationSmoothSortAscending( this long[] p, T[] a, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, 0, p.LongLength - 1); } public static void PermutationSmoothSortAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this long[] p, T[] a, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this long[] p, T[] a, Func selector, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[val]) >= selector(a[p[lf]]) && selector(a[val]) >= selector(a[p[rt]])) break; if (selector(a[p[lf]]) >= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this long[] p, T[] a, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) <= selector(a[val])) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[p[rt]]) >= selector(a[vstepson]) || selector(a[p[lf]]) >= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); } } public class TimSortInfoPermLongFloatSel { public long[] m_p; public T[] m_a; public Func m_sel; public long m_minGallop = c_minGallop; public long[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoPermLongFloatSel(long[] p, T[] a, Func selector) { m_p = p; m_a = a; m_sel = selector; long count = p.LongLength; m_tmp = new long[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public long[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new long[c < 0 ? cap : Math.Min(c, m_p.LongLength >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortAscendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortAscending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, T[] a, Func selector) { PermutationTimSortAscending(p, a, selector, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, T[] a, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); PermutationBinarySortAscending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongFloatSel(p, a, selector); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongAsc(ti); } private static void MergeCollapsePermLongAsc(this TimSortInfoPermLongFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongAsc(ti, n); else break; } } private static void MergeForceCollapsePermLongAsc(this TimSortInfoPermLongFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } } private static void MergeAtPermLongAsc(this TimSortInfoPermLongFloatSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightAscending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongAsc(ti, start1, len1, start2, len2); else MergeHiPermLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongAsc(this TimSortInfoPermLongFloatSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) < selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongAsc(this TimSortInfoPermLongFloatSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) < selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftAscending( this long[] p, T[] a, Func selector, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(a[key]) > selector(a[p[start + hint]])) { long maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightAscending( this long[] p, T[] a, Func selector, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(a[key]) < selector(a[p[start + hint]])) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(a[pivot]) < selector(a[p[mid]])) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) < selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) < selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) >= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this T[] a, Func selector, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, T[] a, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, T[] a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, T[] a, Func selector) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, T[] a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, T[] a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) > selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) > selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, T[] a, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1]]) > selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) > selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a, selector); return p; } public static void PermutationSmoothSortDescending( this int[] p, T[] a, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, T[] a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, T[] a, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[val]) <= selector(a[p[lf]]) && selector(a[val]) <= selector(a[p[rt]])) break; if (selector(a[p[lf]]) <= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, T[] a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) >= selector(a[val])) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[p[rt]]) <= selector(a[vstepson]) || selector(a[p[lf]]) <= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, T[] a, Func selector) { PermutationTimSortDescending(p, a, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, T[] a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); PermutationBinarySortDescending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermFloatSel(p, a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermDesc(ti); } private static void MergeCollapsePermDesc(this TimSortInfoPermFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermDesc(ti, n); else break; } } private static void MergeForceCollapsePermDesc(this TimSortInfoPermFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } } private static void MergeAtPermDesc(this TimSortInfoPermFloatSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermDesc(ti, start1, len1, start2, len2); else MergeHiPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermDesc(this TimSortInfoPermFloatSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) > selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermDesc(this TimSortInfoPermFloatSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) > selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, T[] a, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(a[key]) < selector(a[p[start + hint]])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, T[] a, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(a[key]) > selector(a[p[start + hint]])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(a[pivot]) > selector(a[p[mid]])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) > selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) > selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) <= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianDescendingLong( this T[] a, Func selector, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianDescending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this long[] p, T[] a, Func selector, long med) { long last = p.LongLength - 1; PermutationQuickMedianDescending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl, long med) { PermutationQuickMedianDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this long[] p, T[] a, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortDescendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortDescending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, T[] a, Func selector) { long last = p.LongLength - 1; PermutationQuickSortDescending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { PermutationQuickSortDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this long[] p, T[] a, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortDescendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortDescending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, T[] a, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) > selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) > selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, T[] a, Func selector) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[p[i1]]) > selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) > selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortDescendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortDescending(p, a, selector); return p; } public static void PermutationSmoothSortDescending( this long[] p, T[] a, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, 0, p.LongLength - 1); } public static void PermutationSmoothSortDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this long[] p, T[] a, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this long[] p, T[] a, Func selector, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[val]) <= selector(a[p[lf]]) && selector(a[val]) <= selector(a[p[rt]])) break; if (selector(a[p[lf]]) <= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this long[] p, T[] a, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) >= selector(a[val])) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[p[rt]]) <= selector(a[vstepson]) || selector(a[p[lf]]) <= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortDescendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortDescending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, T[] a, Func selector) { PermutationTimSortDescending(p, a, selector, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, T[] a, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); PermutationBinarySortDescending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongFloatSel(p, a, selector); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongDesc(ti); } private static void MergeCollapsePermLongDesc(this TimSortInfoPermLongFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongDesc(ti, n); else break; } } private static void MergeForceCollapsePermLongDesc(this TimSortInfoPermLongFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } } private static void MergeAtPermLongDesc(this TimSortInfoPermLongFloatSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightDescending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongDesc(ti, start1, len1, start2, len2); else MergeHiPermLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongDesc(this TimSortInfoPermLongFloatSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) > selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongDesc(this TimSortInfoPermLongFloatSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) > selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftDescending( this long[] p, T[] a, Func selector, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(a[key]) < selector(a[p[start + hint]])) { long maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightDescending( this long[] p, T[] a, Func selector, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(a[key]) > selector(a[p[start + hint]])) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(a[pivot]) > selector(a[p[mid]])) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) > selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) > selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) <= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this T[] a, Func selector, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, T[] a, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, T[] a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, T[] a, Func selector) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, T[] a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, T[] a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) < selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) < selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, T[] a, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1]]) < selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) < selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a, selector); return p; } public static void PermutationSmoothSortAscending( this int[] p, T[] a, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, T[] a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, T[] a, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[val]) >= selector(a[p[lf]]) && selector(a[val]) >= selector(a[p[rt]])) break; if (selector(a[p[lf]]) >= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, T[] a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) <= selector(a[val])) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[p[rt]]) >= selector(a[vstepson]) || selector(a[p[lf]]) >= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); } } public class TimSortInfoPermDoubleSel { public int[] m_p; public T[] m_a; public Func m_sel; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoPermDoubleSel(int[] p, T[] a, Func selector) { m_p = p; m_a = a; m_sel = selector; int count = p.Length; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, T[] a, Func selector) { PermutationTimSortAscending(p, a, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, T[] a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); PermutationBinarySortAscending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermDoubleSel(p, a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermAsc(ti); } private static void MergeCollapsePermAsc(this TimSortInfoPermDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermAsc(ti, n); else break; } } private static void MergeForceCollapsePermAsc(this TimSortInfoPermDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } } private static void MergeAtPermAsc(this TimSortInfoPermDoubleSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermAsc(ti, start1, len1, start2, len2); else MergeHiPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermAsc(this TimSortInfoPermDoubleSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) < selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermAsc(this TimSortInfoPermDoubleSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) < selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, T[] a, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(a[key]) > selector(a[p[start + hint]])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, T[] a, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(a[key]) < selector(a[p[start + hint]])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(a[pivot]) < selector(a[p[mid]])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) < selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) < selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) >= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianAscendingLong( this T[] a, Func selector, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianAscending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this long[] p, T[] a, Func selector, long med) { long last = p.LongLength - 1; PermutationQuickMedianAscending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl, long med) { PermutationQuickMedianAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this long[] p, T[] a, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortAscendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortAscending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, T[] a, Func selector) { long last = p.LongLength - 1; PermutationQuickSortAscending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { PermutationQuickSortAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this long[] p, T[] a, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortAscendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortAscending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, T[] a, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) < selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) < selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this long[] p, T[] a, Func selector) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[p[i1]]) < selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) < selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortAscendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortAscending(p, a, selector); return p; } public static void PermutationSmoothSortAscending( this long[] p, T[] a, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, 0, p.LongLength - 1); } public static void PermutationSmoothSortAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this long[] p, T[] a, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this long[] p, T[] a, Func selector, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[val]) >= selector(a[p[lf]]) && selector(a[val]) >= selector(a[p[rt]])) break; if (selector(a[p[lf]]) >= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this long[] p, T[] a, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) <= selector(a[val])) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[p[rt]]) >= selector(a[vstepson]) || selector(a[p[lf]]) >= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); } } public class TimSortInfoPermLongDoubleSel { public long[] m_p; public T[] m_a; public Func m_sel; public long m_minGallop = c_minGallop; public long[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoPermLongDoubleSel(long[] p, T[] a, Func selector) { m_p = p; m_a = a; m_sel = selector; long count = p.LongLength; m_tmp = new long[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public long[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new long[c < 0 ? cap : Math.Min(c, m_p.LongLength >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortAscendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortAscending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, T[] a, Func selector) { PermutationTimSortAscending(p, a, selector, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this long[] p, T[] a, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); PermutationBinarySortAscending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongDoubleSel(p, a, selector); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongAsc(ti); } private static void MergeCollapsePermLongAsc(this TimSortInfoPermLongDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongAsc(ti, n); else break; } } private static void MergeForceCollapsePermLongAsc(this TimSortInfoPermLongDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } } private static void MergeAtPermLongAsc(this TimSortInfoPermLongDoubleSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightAscending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongAsc(ti, start1, len1, start2, len2); else MergeHiPermLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongAsc(this TimSortInfoPermLongDoubleSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) < selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongAsc(this TimSortInfoPermLongDoubleSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) < selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftAscending( this long[] p, T[] a, Func selector, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(a[key]) > selector(a[p[start + hint]])) { long maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightAscending( this long[] p, T[] a, Func selector, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(a[key]) < selector(a[p[start + hint]])) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(a[pivot]) < selector(a[p[mid]])) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderAscending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) < selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) < selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) >= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this T[] a, Func selector, int med) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, T[] a, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, T[] a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, T[] a, Func selector) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, T[] a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, T[] a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) > selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) > selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, T[] a, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1]]) > selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) > selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a, selector); return p; } public static void PermutationSmoothSortDescending( this int[] p, T[] a, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, T[] a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, T[] a, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[val]) <= selector(a[p[lf]]) && selector(a[val]) <= selector(a[p[rt]])) break; if (selector(a[p[lf]]) <= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, T[] a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) >= selector(a[val])) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[p[rt]]) <= selector(a[vstepson]) || selector(a[p[lf]]) <= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this T[] a, Func selector) { int len = a.Length; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, T[] a, Func selector) { PermutationTimSortDescending(p, a, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, T[] a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); PermutationBinarySortDescending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermDoubleSel(p, a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermDesc(ti); } private static void MergeCollapsePermDesc(this TimSortInfoPermDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermDesc(ti, n); else break; } } private static void MergeForceCollapsePermDesc(this TimSortInfoPermDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } } private static void MergeAtPermDesc(this TimSortInfoPermDoubleSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermDesc(ti, start1, len1, start2, len2); else MergeHiPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermDesc(this TimSortInfoPermDoubleSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) > selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermDesc(this TimSortInfoPermDoubleSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) > selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, T[] a, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(a[key]) < selector(a[p[start + hint]])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, T[] a, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(a[key]) > selector(a[p[start + hint]])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(a[pivot]) > selector(a[p[mid]])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, T[] a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) > selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) > selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) <= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static long[] CreatePermutationQuickMedianDescendingLong( this T[] a, Func selector, long med) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickMedianDescending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this long[] p, T[] a, Func selector, long med) { long last = p.LongLength - 1; PermutationQuickMedianDescending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl, long med) { PermutationQuickMedianDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this long[] p, T[] a, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static long[] CreatePermutationQuickSortDescendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationQuickSortDescending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, T[] a, Func selector) { long last = p.LongLength - 1; PermutationQuickSortDescending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { PermutationQuickSortDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this long[] p, T[] a, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static long[] CreatePermutationHeapSortDescendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationHeapSortDescending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, T[] a, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) > selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) > selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this long[] p, T[] a, Func selector) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(a[p[i1]]) > selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) > selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static long[] CreatePermutationSmoothSortDescendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationSmoothSortDescending(p, a, selector); return p; } public static void PermutationSmoothSortDescending( this long[] p, T[] a, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, 0, p.LongLength - 1); } public static void PermutationSmoothSortDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this long[] p, T[] a, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this long[] p, T[] a, Func selector, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[val]) <= selector(a[p[lf]]) && selector(a[val]) <= selector(a[p[rt]])) break; if (selector(a[p[lf]]) <= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this long[] p, T[] a, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) >= selector(a[val])) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(a[p[rt]]) <= selector(a[vstepson]) || selector(a[p[lf]]) <= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static long[] CreatePermutationTimSortDescendingLong( this T[] a, Func selector) { long len = a.LongLength; var p = new long[len].SetByIndexLong(i => i); PermutationTimSortDescending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, T[] a, Func selector) { PermutationTimSortDescending(p, a, selector, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this long[] p, T[] a, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); PermutationBinarySortDescending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongDoubleSel(p, a, selector); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongDesc(ti); } private static void MergeCollapsePermLongDesc(this TimSortInfoPermLongDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongDesc(ti, n); else break; } } private static void MergeForceCollapsePermLongDesc(this TimSortInfoPermLongDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } } private static void MergeAtPermLongDesc(this TimSortInfoPermLongDoubleSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightDescending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongDesc(ti, start1, len1, start2, len2); else MergeHiPermLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongDesc(this TimSortInfoPermLongDoubleSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) > selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongDesc(this TimSortInfoPermLongDoubleSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) > selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftDescending( this long[] p, T[] a, Func selector, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(a[key]) < selector(a[p[start + hint]])) { long maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightDescending( this long[] p, T[] a, Func selector, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(a[key]) > selector(a[p[start + hint]])) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(a[pivot]) > selector(a[p[mid]])) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderDescending( this long[] p, T[] a, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) > selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) > selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) <= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } #endregion #region Sort/Median for List /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedian( this List a, Func cmp, int med) { int last = a.Count - 1; QuickMedian(a, cmp, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedian( this List a, Func cmp, int beginIncl, int endExcl, int med) { QuickMedian(a, cmp, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedian( this List a, Func cmp, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (cmp(a[e1], a[e2]) > 0) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (cmp(a[e4], a[e5]) > 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (cmp(a[e1], a[e3]) > 0) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (cmp(a[e2], a[e3]) > 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (cmp(a[e1], a[e4]) > 0) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (cmp(a[e3], a[e4]) > 0) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (cmp(a[e2], a[e5]) > 0) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (cmp(a[e2], a[e3]) > 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (cmp(a[e4], a[e5]) > 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = cmp(p1, p2) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (cmp(ai, p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (cmp(ai, p2) > 0) { while (cmp(a[hi], p2) > 0 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (cmp(ai, p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (cmp(ai, p1) == 0) continue; if (cmp(ai, p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (cmp(a[hi], p1) > 0) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (cmp(ai, p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (cmp(a[lo], p1) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (cmp(a[i], p1) == 0) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (cmp(a[hi], p2) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (cmp(a[i], p2) == 0) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && cmp(ai, a[j]) < 0; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSort( this List a, Func cmp) { int last = a.Count - 1; QuickSort(a, cmp, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSort( this List a, Func cmp, int beginIncl, int endExcl) { QuickSort(a, cmp, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSort( this List a, Func cmp, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (cmp(a[e1], a[e2]) > 0) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (cmp(a[e4], a[e5]) > 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (cmp(a[e1], a[e3]) > 0) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (cmp(a[e2], a[e3]) > 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (cmp(a[e1], a[e4]) > 0) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (cmp(a[e3], a[e4]) > 0) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (cmp(a[e2], a[e5]) > 0) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (cmp(a[e2], a[e3]) > 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (cmp(a[e4], a[e5]) > 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = cmp(p1, p2) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (cmp(ai, p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (cmp(ai, p2) > 0) { while (cmp(a[hi], p2) > 0 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (cmp(ai, p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (cmp(ai, p1) == 0) continue; if (cmp(ai, p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (cmp(a[hi], p1) > 0) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (cmp(ai, p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSort(a, cmp, l, lo - 2, cl); QuickSort(a, cmp, hi + 2, r, cr); { while (cmp(a[lo], p1) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (cmp(a[i], p1) == 0) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (cmp(a[hi], p2) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (cmp(a[i], p2) == 0) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSort(a, cmp, lo, hi, cm); QuickSort(a, cmp, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSort(a, cmp, l, lo - 2, cl); QuickSort(a, cmp, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSort(a, cmp, l, lo - 2, cl); QuickSort(a, cmp, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSort(a, cmp, l, lo - 2, cl); QuickSort(a, cmp, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSort(a, cmp, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSort(a, cmp, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && cmp(ai, a[j]) < 0; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSort( this List a, Func cmp, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (cmp(element, a[i2 + begin]) < 0) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && cmp(a[i1 + begin], a[i2 + begin]) < 0) ? i2 : i1; // smaller child if (cmp(a[ni + begin], element) < 0) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSort( this List a, Func cmp) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (cmp(element, a[i2]) < 0) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && cmp(a[i1], a[i2]) < 0) ? i2 : i1; // smaller child if (cmp(a[ni], element) < 0) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSort( this List a, Func cmp) { SmoothSortInclusiveRange(a, cmp, 0, a.Count - 1); } public static void SmoothSort( this List a, Func cmp, int beginIncl, int endExcl) { SmoothSortInclusiveRange(a, cmp, beginIncl, endExcl - 1); } private static void SmoothSortInclusiveRange( this List a, Func cmp, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortSift(a, cmp, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortTrinkle(a, cmp, pbits, pshift, head, false); else SmoothSortSift(a, cmp, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortTrinkle(a, cmp, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortTrinkle(a, cmp, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortTrinkle(a, cmp, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortSift( this List a, Func cmp, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (cmp(val, a[lf]) >= 0 && cmp(val, a[rt]) >= 0) break; if (cmp(a[lf], a[rt]) >= 0) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortTrinkle( this List a, Func cmp, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (cmp(vstepson, val) <= 0) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (cmp(a[rt], vstepson) >= 0 || cmp(a[lf], vstepson) >= 0) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortSift(a, cmp, pshift, head); } } public class TimSortInfoListCmp { public List m_a; public Func m_cmp; public int m_minGallop = c_minGallop; public T[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoListCmp(List a, Func cmp) { m_a = a; m_cmp = cmp; int count = a.Count; m_tmp = new T[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public T[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new T[c < 0 ? cap : Math.Min(c, m_a.Count >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSort( this List a, Func cmp) { TimSort(a, cmp, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSort( this List a, Func cmp, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrder(a, cmp, lo, hi); BinarySort(a, cmp, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListCmp(a, cmp); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrder(a, cmp, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySort(a, cmp, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListCmp(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListCmp(ti); } private static void MergeCollapseListCmp(this TimSortInfoListCmp ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListCmp(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListCmp(ti, n); else break; } } private static void MergeForceCollapseListCmp(this TimSortInfoListCmp ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListCmp(ti, n); } } private static void MergeAtListCmp(this TimSortInfoListCmp ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRight(a, ti.m_cmp, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeft(a, ti.m_cmp, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListCmp(ti, start1, len1, start2, len2); else MergeHiListCmp(ti, start1, len1, start2, len2); } private static void MergeLoListCmp(this TimSortInfoListCmp ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func cmp = ti.m_cmp; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (cmp(a[idx2], t[idx1]) < 0) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRight(t, cmp, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeft(a, cmp, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiListCmp(this TimSortInfoListCmp ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func cmp = ti.m_cmp; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (cmp(t[idx2], a[idx1]) < 0) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRight(a, cmp, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeft(t, cmp, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeft( this List a, Func cmp, T key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (cmp(key, a[start + hint]) > 0) { int maxOfs = len - hint; while (ofs < maxOfs && cmp(key, a[start + hint + ofs]) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && cmp(key, a[start + hint - ofs]) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (cmp(key, a[start + m]) > 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRight( this List a, Func cmp, T key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (cmp(key, a[start + hint]) < 0) { int maxOfs = hint + 1; while (ofs < maxOfs && cmp(key, a[start + hint - ofs]) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && cmp(key, a[start + hint + ofs]) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (cmp(key, a[start + m]) < 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySort( this List a, Func cmp, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (cmp(pivot, a[mid]) < 0) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrder( this List a, Func cmp, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (cmp(a[runHi++], a[beginIncl]) < 0) { while (runHi < endExcl && cmp(a[runHi], a[runHi - 1]) < 0) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && cmp(a[runHi], a[runHi - 1]) >= 0) runHi++; } return runHi - beginIncl; } public static void ReverseRange( List a, int beginIncl, int endExcl) { endExcl--; // now incorrectly named while (beginIncl < endExcl) { var t = a[beginIncl]; a[beginIncl] = a[endExcl]; a[endExcl] = t; ++beginIncl; --endExcl; } } private static void CopyElements( List src, int start, List dst, int dstStart, int count) { for (var end = start + count; start < end; start++, dstStart++) dst[dstStart] = src[start]; } private static void CopyElements( List src, int start, T[] dst, int dstStart, int count) { for (var end = start + count; start < end; start++, dstStart++) dst[dstStart] = src[start]; } private static void CopyElements( T[] src, int start, List dst, int dstStart, int count) { for (var end = start + count; start < end; start++, dstStart++) dst[dstStart] = src[start]; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this List a, int med) where T : IComparable { int last = a.Count - 1; QuickMedianAscending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this List a, int beginIncl, int endExcl, int med) where T : IComparable { QuickMedianAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this List a, int l, int r, int countSub1, int med) where T : IComparable { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1].CompareTo(a[e2]) > 0) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4].CompareTo(a[e5]) > 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1].CompareTo(a[e3]) > 0) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2].CompareTo(a[e3]) > 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1].CompareTo(a[e4]) > 0) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3].CompareTo(a[e4]) > 0) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2].CompareTo(a[e5]) > 0) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2].CompareTo(a[e3]) > 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4].CompareTo(a[e5]) > 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1.CompareTo(p2) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai.CompareTo(p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai.CompareTo(p2) > 0) { while (a[hi].CompareTo(p2) > 0 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai.CompareTo(p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai.CompareTo(p1) == 0) continue; if (ai.CompareTo(p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi].CompareTo(p1) > 0) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai.CompareTo(p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo].CompareTo(p1) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i].CompareTo(p1) == 0) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi].CompareTo(p2) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i].CompareTo(p2) == 0) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai.CompareTo(a[j]) < 0; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this List a) where T : IComparable { int last = a.Count - 1; QuickSortAscending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this List a, int beginIncl, int endExcl) where T : IComparable { QuickSortAscending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this List a, int l, int r, int countSub1) where T : IComparable { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1].CompareTo(a[e2]) > 0) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4].CompareTo(a[e5]) > 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1].CompareTo(a[e3]) > 0) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2].CompareTo(a[e3]) > 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1].CompareTo(a[e4]) > 0) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3].CompareTo(a[e4]) > 0) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2].CompareTo(a[e5]) > 0) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2].CompareTo(a[e3]) > 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4].CompareTo(a[e5]) > 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1.CompareTo(p2) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai.CompareTo(p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai.CompareTo(p2) > 0) { while (a[hi].CompareTo(p2) > 0 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai.CompareTo(p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai.CompareTo(p1) == 0) continue; if (ai.CompareTo(p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi].CompareTo(p1) > 0) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai.CompareTo(p1) < 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); { while (a[lo].CompareTo(p1) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i].CompareTo(p1) == 0) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi].CompareTo(p2) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i].CompareTo(p2) == 0) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, lo, hi, cm); QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, l, lo - 2, cl); QuickSortAscending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai.CompareTo(a[j]) < 0; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a, int begin, int end) where T : IComparable { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element.CompareTo(a[i2 + begin]) < 0) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1 + begin].CompareTo(a[i2 + begin]) < 0) ? i2 : i1; // smaller child if (a[ni + begin].CompareTo(element) < 0) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a) where T : IComparable { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element.CompareTo(a[i2]) < 0) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1].CompareTo(a[i2]) < 0) ? i2 : i1; // smaller child if (a[ni].CompareTo(element) < 0) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this List a) where T : IComparable { SmoothSortAscendingInclusiveRange(a, 0, a.Count - 1); } public static void SmoothSortAscending( this List a, int beginIncl, int endExcl) where T : IComparable { SmoothSortAscendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this List a, int lo, int hi) where T : IComparable { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); else SmoothSortAscendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortAscendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this List a, int pshift, int head) where T : IComparable { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (val.CompareTo(a[lf]) >= 0 && val.CompareTo(a[rt]) >= 0) break; if (a[lf].CompareTo(a[rt]) >= 0) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this List a, long pbits, int pshift, int head, bool isTrusty) where T : IComparable { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (vstepson.CompareTo(val) <= 0) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[rt].CompareTo(vstepson) >= 0 || a[lf].CompareTo(vstepson) >= 0) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, pshift, head); } } public class TimSortInfoList where T : IComparable { public List m_a; public int m_minGallop = c_minGallop; public T[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoList(List a) { m_a = a; int count = a.Count; m_tmp = new T[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public T[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new T[c < 0 ? cap : Math.Min(c, m_a.Count >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a) where T : IComparable { TimSortAscending(a, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a, int lo, int hi) where T : IComparable { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, lo, hi); BinarySortAscending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoList(a); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderAscending(a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortAscending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListAsc(ti); } private static void MergeCollapseListAsc(this TimSortInfoList ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListAsc(ti, n); else break; } } private static void MergeForceCollapseListAsc(this TimSortInfoList ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListAsc(ti, n); } } private static void MergeAtListAsc(this TimSortInfoList ti, int i) where T : IComparable { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightAscending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListAsc(ti, start1, len1, start2, len2); else MergeHiListAsc(ti, start1, len1, start2, len2); } private static void MergeLoListAsc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) where T : IComparable { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[idx2].CompareTo(t[idx1]) < 0) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightAscending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiListAsc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) where T : IComparable { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (t[idx2].CompareTo(a[idx1]) < 0) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftAscending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftAscending( this List a, T key, int start, int len, int hint) where T : IComparable { int lastOfs = 0, ofs = 1; if (key.CompareTo(a[start + hint]) > 0) { int maxOfs = len - hint; while (ofs < maxOfs && key.CompareTo(a[start + hint + ofs]) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && key.CompareTo(a[start + hint - ofs]) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key.CompareTo(a[start + m]) > 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightAscending( this List a, T key, int start, int len, int hint) where T : IComparable { int ofs = 1, lastOfs = 0; if (key.CompareTo(a[start + hint]) < 0) { int maxOfs = hint + 1; while (ofs < maxOfs && key.CompareTo(a[start + hint - ofs]) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && key.CompareTo(a[start + hint + ofs]) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key.CompareTo(a[start + m]) < 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this List a, int beginIncl, int endExcl, int beginUnsorted) where T : IComparable { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (pivot.CompareTo(a[mid]) < 0) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderAscending( this List a, int beginIncl, int endExcl) where T : IComparable { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++].CompareTo(a[beginIncl]) < 0) { while (runHi < endExcl && a[runHi].CompareTo(a[runHi - 1]) < 0) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi].CompareTo(a[runHi - 1]) >= 0) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this List a, int med) where T : IComparable { int last = a.Count - 1; QuickMedianDescending(a, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this List a, int beginIncl, int endExcl, int med) where T : IComparable { QuickMedianDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this List a, int l, int r, int countSub1, int med) where T : IComparable { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1].CompareTo(a[e2]) < 0) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4].CompareTo(a[e5]) < 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1].CompareTo(a[e3]) < 0) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2].CompareTo(a[e3]) < 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1].CompareTo(a[e4]) < 0) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3].CompareTo(a[e4]) < 0) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2].CompareTo(a[e5]) < 0) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2].CompareTo(a[e3]) < 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4].CompareTo(a[e5]) < 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1.CompareTo(p2) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai.CompareTo(p1) > 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai.CompareTo(p2) < 0) { while (a[hi].CompareTo(p2) < 0 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai.CompareTo(p1) > 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai.CompareTo(p1) == 0) continue; if (ai.CompareTo(p1) > 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi].CompareTo(p1) < 0) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai.CompareTo(p1) > 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[lo].CompareTo(p1) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i].CompareTo(p1) == 0) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi].CompareTo(p2) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i].CompareTo(p2) == 0) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai.CompareTo(a[j]) > 0; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this List a) where T : IComparable { int last = a.Count - 1; QuickSortDescending(a, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this List a, int beginIncl, int endExcl) where T : IComparable { QuickSortDescending(a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this List a, int l, int r, int countSub1) where T : IComparable { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[e1].CompareTo(a[e2]) < 0) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (a[e4].CompareTo(a[e5]) < 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (a[e1].CompareTo(a[e3]) < 0) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (a[e2].CompareTo(a[e3]) < 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e1].CompareTo(a[e4]) < 0) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (a[e3].CompareTo(a[e4]) < 0) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (a[e2].CompareTo(a[e5]) < 0) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (a[e2].CompareTo(a[e3]) < 0) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (a[e4].CompareTo(a[e5]) < 0) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = p1.CompareTo(p2) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai.CompareTo(p1) > 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (ai.CompareTo(p2) < 0) { while (a[hi].CompareTo(p2) < 0 && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai.CompareTo(p1) > 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (ai.CompareTo(p1) == 0) continue; if (ai.CompareTo(p1) > 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (a[hi].CompareTo(p1) < 0) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (ai.CompareTo(p1) > 0) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); { while (a[lo].CompareTo(p1) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[i].CompareTo(p1) == 0) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (a[hi].CompareTo(p2) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[i].CompareTo(p2) == 0) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, lo, hi, cm); QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, l, lo - 2, cl); QuickSortDescending(a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && ai.CompareTo(a[j]) > 0; j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a, int begin, int end) where T : IComparable { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element.CompareTo(a[i2 + begin]) > 0) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1 + begin].CompareTo(a[i2 + begin]) > 0) ? i2 : i1; // smaller child if (a[ni + begin].CompareTo(element) > 0) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a) where T : IComparable { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (element.CompareTo(a[i2]) > 0) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[i1].CompareTo(a[i2]) > 0) ? i2 : i1; // smaller child if (a[ni].CompareTo(element) > 0) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this List a) where T : IComparable { SmoothSortDescendingInclusiveRange(a, 0, a.Count - 1); } public static void SmoothSortDescending( this List a, int beginIncl, int endExcl) where T : IComparable { SmoothSortDescendingInclusiveRange(a, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this List a, int lo, int hi) where T : IComparable { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); else SmoothSortDescendingSift(a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortDescendingTrinkle(a, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this List a, int pshift, int head) where T : IComparable { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (val.CompareTo(a[lf]) <= 0 && val.CompareTo(a[rt]) <= 0) break; if (a[lf].CompareTo(a[rt]) <= 0) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this List a, long pbits, int pshift, int head, bool isTrusty) where T : IComparable { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (vstepson.CompareTo(val) >= 0) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[rt].CompareTo(vstepson) <= 0 || a[lf].CompareTo(vstepson) <= 0) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a) where T : IComparable { TimSortDescending(a, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a, int lo, int hi) where T : IComparable { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, lo, hi); BinarySortDescending(a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoList(a); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderDescending(a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortDescending(a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListDesc(ti); } private static void MergeCollapseListDesc(this TimSortInfoList ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListDesc(ti, n); else break; } } private static void MergeForceCollapseListDesc(this TimSortInfoList ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListDesc(ti, n); } } private static void MergeAtListDesc(this TimSortInfoList ti, int i) where T : IComparable { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightDescending(a, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListDesc(ti, start1, len1, start2, len2); else MergeHiListDesc(ti, start1, len1, start2, len2); } private static void MergeLoListDesc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) where T : IComparable { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[idx2].CompareTo(t[idx1]) > 0) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightDescending(t, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiListDesc(this TimSortInfoList ti, int start1, int len1, int start2, int len2) where T : IComparable { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (t[idx2].CompareTo(a[idx1]) > 0) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftDescending(t, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftDescending( this List a, T key, int start, int len, int hint) where T : IComparable { int lastOfs = 0, ofs = 1; if (key.CompareTo(a[start + hint]) < 0) { int maxOfs = len - hint; while (ofs < maxOfs && key.CompareTo(a[start + hint + ofs]) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && key.CompareTo(a[start + hint - ofs]) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key.CompareTo(a[start + m]) < 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightDescending( this List a, T key, int start, int len, int hint) where T : IComparable { int ofs = 1, lastOfs = 0; if (key.CompareTo(a[start + hint]) > 0) { int maxOfs = hint + 1; while (ofs < maxOfs && key.CompareTo(a[start + hint - ofs]) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && key.CompareTo(a[start + hint + ofs]) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (key.CompareTo(a[start + m]) > 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this List a, int beginIncl, int endExcl, int beginUnsorted) where T : IComparable { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (pivot.CompareTo(a[mid]) > 0) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderDescending( this List a, int beginIncl, int endExcl) where T : IComparable { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[runHi++].CompareTo(a[beginIncl]) > 0) { while (runHi < endExcl && a[runHi].CompareTo(a[runHi - 1]) > 0) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && a[runHi].CompareTo(a[runHi - 1]) <= 0) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this List a, Func selector, int med) { int last = a.Count - 1; QuickMedianAscending(a, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this List a, Func selector, int beginIncl, int endExcl, int med) { QuickMedianAscending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this List a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[e1]) > selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) > selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) > selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) > selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) > selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) > selector(p2)) { while (selector(a[hi]) > selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) > selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[lo]) == selector(p1)) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && selector(ai) < selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this List a, Func selector) { int last = a.Count - 1; QuickSortAscending(a, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this List a, Func selector, int beginIncl, int endExcl) { QuickSortAscending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this List a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[e1]) > selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) > selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) > selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) > selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) > selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) > selector(p2)) { while (selector(a[hi]) > selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) > selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); { while (selector(a[lo]) == selector(p1)) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, selector, lo, hi, cm); QuickSortAscending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && selector(ai) < selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(element) < selector(a[i2 + begin])) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[i1 + begin]) < selector(a[i2 + begin])) ? i2 : i1; // smaller child if (selector(a[ni + begin]) < selector(element)) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a, Func selector) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(element) < selector(a[i2])) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[i1]) < selector(a[i2])) ? i2 : i1; // smaller child if (selector(a[ni]) < selector(element)) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this List a, Func selector) { SmoothSortAscendingInclusiveRange(a, selector, 0, a.Count - 1); } public static void SmoothSortAscending( this List a, Func selector, int beginIncl, int endExcl) { SmoothSortAscendingInclusiveRange(a, selector, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this List a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head, false); else SmoothSortAscendingSift(a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this List a, Func selector, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(val) >= selector(a[lf]) && selector(val) >= selector(a[rt])) break; if (selector(a[lf]) >= selector(a[rt])) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this List a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (selector(vstepson) <= selector(val)) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[rt]) >= selector(vstepson) || selector(a[lf]) >= selector(vstepson)) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, selector, pshift, head); } } public class TimSortInfoListIntSel { public List m_a; public Func m_sel; public int m_minGallop = c_minGallop; public T[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoListIntSel(List a, Func selector) { m_a = a; m_sel = selector; int count = a.Count; m_tmp = new T[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public T[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new T[c < 0 ? cap : Math.Min(c, m_a.Count >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a, Func selector) { TimSortAscending(a, selector, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, selector, lo, hi); BinarySortAscending(a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListIntSel(a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderAscending(a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortAscending(a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListAsc(ti); } private static void MergeCollapseListAsc(this TimSortInfoListIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListAsc(ti, n); else break; } } private static void MergeForceCollapseListAsc(this TimSortInfoListIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListAsc(ti, n); } } private static void MergeAtListAsc(this TimSortInfoListIntSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightAscending(a, ti.m_sel, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_sel, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListAsc(ti, start1, len1, start2, len2); else MergeHiListAsc(ti, start1, len1, start2, len2); } private static void MergeLoListAsc(this TimSortInfoListIntSel ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[idx2]) < selector(t[idx1])) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightAscending(t, selector, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiListAsc(this TimSortInfoListIntSel ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(t[idx2]) < selector(a[idx1])) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftAscending(t, selector, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftAscending( this List a, Func selector, T key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(key) > selector(a[start + hint])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(key) > selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(key) <= selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(a[start + m])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightAscending( this List a, Func selector, T key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(key) < selector(a[start + hint])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(key) < selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(key) >= selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(a[start + m])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this List a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(pivot) < selector(a[mid])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderAscending( this List a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[runHi++]) < selector(a[beginIncl])) { while (runHi < endExcl && selector(a[runHi]) < selector(a[runHi - 1])) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[runHi]) >= selector(a[runHi - 1])) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this List a, Func selector, int med) { int last = a.Count - 1; QuickMedianDescending(a, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this List a, Func selector, int beginIncl, int endExcl, int med) { QuickMedianDescending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this List a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[e1]) < selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) < selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) < selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) < selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) < selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) < selector(p2)) { while (selector(a[hi]) < selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) < selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[lo]) == selector(p1)) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && selector(ai) > selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this List a, Func selector) { int last = a.Count - 1; QuickSortDescending(a, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this List a, Func selector, int beginIncl, int endExcl) { QuickSortDescending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this List a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[e1]) < selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) < selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) < selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) < selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) < selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) < selector(p2)) { while (selector(a[hi]) < selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) < selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); { while (selector(a[lo]) == selector(p1)) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, selector, lo, hi, cm); QuickSortDescending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && selector(ai) > selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(element) > selector(a[i2 + begin])) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[i1 + begin]) > selector(a[i2 + begin])) ? i2 : i1; // smaller child if (selector(a[ni + begin]) > selector(element)) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a, Func selector) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(element) > selector(a[i2])) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[i1]) > selector(a[i2])) ? i2 : i1; // smaller child if (selector(a[ni]) > selector(element)) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this List a, Func selector) { SmoothSortDescendingInclusiveRange(a, selector, 0, a.Count - 1); } public static void SmoothSortDescending( this List a, Func selector, int beginIncl, int endExcl) { SmoothSortDescendingInclusiveRange(a, selector, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this List a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head, false); else SmoothSortDescendingSift(a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this List a, Func selector, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(val) <= selector(a[lf]) && selector(val) <= selector(a[rt])) break; if (selector(a[lf]) <= selector(a[rt])) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this List a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (selector(vstepson) >= selector(val)) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[rt]) <= selector(vstepson) || selector(a[lf]) <= selector(vstepson)) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a, Func selector) { TimSortDescending(a, selector, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, selector, lo, hi); BinarySortDescending(a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListIntSel(a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderDescending(a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortDescending(a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListDesc(ti); } private static void MergeCollapseListDesc(this TimSortInfoListIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListDesc(ti, n); else break; } } private static void MergeForceCollapseListDesc(this TimSortInfoListIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListDesc(ti, n); } } private static void MergeAtListDesc(this TimSortInfoListIntSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightDescending(a, ti.m_sel, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_sel, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListDesc(ti, start1, len1, start2, len2); else MergeHiListDesc(ti, start1, len1, start2, len2); } private static void MergeLoListDesc(this TimSortInfoListIntSel ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[idx2]) > selector(t[idx1])) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightDescending(t, selector, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiListDesc(this TimSortInfoListIntSel ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(t[idx2]) > selector(a[idx1])) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftDescending(t, selector, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftDescending( this List a, Func selector, T key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(key) < selector(a[start + hint])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(key) < selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(key) >= selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(a[start + m])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightDescending( this List a, Func selector, T key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(key) > selector(a[start + hint])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(key) > selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(key) <= selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(a[start + m])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this List a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(pivot) > selector(a[mid])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderDescending( this List a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[runHi++]) > selector(a[beginIncl])) { while (runHi < endExcl && selector(a[runHi]) > selector(a[runHi - 1])) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[runHi]) <= selector(a[runHi - 1])) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this List a, Func selector, int med) { int last = a.Count - 1; QuickMedianAscending(a, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this List a, Func selector, int beginIncl, int endExcl, int med) { QuickMedianAscending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this List a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[e1]) > selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) > selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) > selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) > selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) > selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) > selector(p2)) { while (selector(a[hi]) > selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) > selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[lo]) == selector(p1)) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && selector(ai) < selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this List a, Func selector) { int last = a.Count - 1; QuickSortAscending(a, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this List a, Func selector, int beginIncl, int endExcl) { QuickSortAscending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this List a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[e1]) > selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) > selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) > selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) > selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) > selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) > selector(p2)) { while (selector(a[hi]) > selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) > selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); { while (selector(a[lo]) == selector(p1)) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, selector, lo, hi, cm); QuickSortAscending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && selector(ai) < selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(element) < selector(a[i2 + begin])) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[i1 + begin]) < selector(a[i2 + begin])) ? i2 : i1; // smaller child if (selector(a[ni + begin]) < selector(element)) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a, Func selector) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(element) < selector(a[i2])) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[i1]) < selector(a[i2])) ? i2 : i1; // smaller child if (selector(a[ni]) < selector(element)) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this List a, Func selector) { SmoothSortAscendingInclusiveRange(a, selector, 0, a.Count - 1); } public static void SmoothSortAscending( this List a, Func selector, int beginIncl, int endExcl) { SmoothSortAscendingInclusiveRange(a, selector, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this List a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head, false); else SmoothSortAscendingSift(a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this List a, Func selector, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(val) >= selector(a[lf]) && selector(val) >= selector(a[rt])) break; if (selector(a[lf]) >= selector(a[rt])) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this List a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (selector(vstepson) <= selector(val)) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[rt]) >= selector(vstepson) || selector(a[lf]) >= selector(vstepson)) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, selector, pshift, head); } } public class TimSortInfoListLongSel { public List m_a; public Func m_sel; public int m_minGallop = c_minGallop; public T[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoListLongSel(List a, Func selector) { m_a = a; m_sel = selector; int count = a.Count; m_tmp = new T[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public T[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new T[c < 0 ? cap : Math.Min(c, m_a.Count >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a, Func selector) { TimSortAscending(a, selector, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, selector, lo, hi); BinarySortAscending(a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListLongSel(a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderAscending(a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortAscending(a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListAsc(ti); } private static void MergeCollapseListAsc(this TimSortInfoListLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListAsc(ti, n); else break; } } private static void MergeForceCollapseListAsc(this TimSortInfoListLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListAsc(ti, n); } } private static void MergeAtListAsc(this TimSortInfoListLongSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightAscending(a, ti.m_sel, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_sel, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListAsc(ti, start1, len1, start2, len2); else MergeHiListAsc(ti, start1, len1, start2, len2); } private static void MergeLoListAsc(this TimSortInfoListLongSel ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[idx2]) < selector(t[idx1])) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightAscending(t, selector, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiListAsc(this TimSortInfoListLongSel ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(t[idx2]) < selector(a[idx1])) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftAscending(t, selector, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftAscending( this List a, Func selector, T key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(key) > selector(a[start + hint])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(key) > selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(key) <= selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(a[start + m])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightAscending( this List a, Func selector, T key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(key) < selector(a[start + hint])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(key) < selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(key) >= selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(a[start + m])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this List a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(pivot) < selector(a[mid])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderAscending( this List a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[runHi++]) < selector(a[beginIncl])) { while (runHi < endExcl && selector(a[runHi]) < selector(a[runHi - 1])) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[runHi]) >= selector(a[runHi - 1])) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this List a, Func selector, int med) { int last = a.Count - 1; QuickMedianDescending(a, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this List a, Func selector, int beginIncl, int endExcl, int med) { QuickMedianDescending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this List a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[e1]) < selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) < selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) < selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) < selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) < selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) < selector(p2)) { while (selector(a[hi]) < selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) < selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[lo]) == selector(p1)) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && selector(ai) > selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this List a, Func selector) { int last = a.Count - 1; QuickSortDescending(a, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this List a, Func selector, int beginIncl, int endExcl) { QuickSortDescending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this List a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[e1]) < selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) < selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) < selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) < selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) < selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) < selector(p2)) { while (selector(a[hi]) < selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) < selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); { while (selector(a[lo]) == selector(p1)) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, selector, lo, hi, cm); QuickSortDescending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && selector(ai) > selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(element) > selector(a[i2 + begin])) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[i1 + begin]) > selector(a[i2 + begin])) ? i2 : i1; // smaller child if (selector(a[ni + begin]) > selector(element)) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a, Func selector) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(element) > selector(a[i2])) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[i1]) > selector(a[i2])) ? i2 : i1; // smaller child if (selector(a[ni]) > selector(element)) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this List a, Func selector) { SmoothSortDescendingInclusiveRange(a, selector, 0, a.Count - 1); } public static void SmoothSortDescending( this List a, Func selector, int beginIncl, int endExcl) { SmoothSortDescendingInclusiveRange(a, selector, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this List a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head, false); else SmoothSortDescendingSift(a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this List a, Func selector, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(val) <= selector(a[lf]) && selector(val) <= selector(a[rt])) break; if (selector(a[lf]) <= selector(a[rt])) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this List a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (selector(vstepson) >= selector(val)) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[rt]) <= selector(vstepson) || selector(a[lf]) <= selector(vstepson)) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a, Func selector) { TimSortDescending(a, selector, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, selector, lo, hi); BinarySortDescending(a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListLongSel(a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderDescending(a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortDescending(a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListDesc(ti); } private static void MergeCollapseListDesc(this TimSortInfoListLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListDesc(ti, n); else break; } } private static void MergeForceCollapseListDesc(this TimSortInfoListLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListDesc(ti, n); } } private static void MergeAtListDesc(this TimSortInfoListLongSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightDescending(a, ti.m_sel, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_sel, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListDesc(ti, start1, len1, start2, len2); else MergeHiListDesc(ti, start1, len1, start2, len2); } private static void MergeLoListDesc(this TimSortInfoListLongSel ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[idx2]) > selector(t[idx1])) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightDescending(t, selector, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiListDesc(this TimSortInfoListLongSel ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(t[idx2]) > selector(a[idx1])) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftDescending(t, selector, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftDescending( this List a, Func selector, T key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(key) < selector(a[start + hint])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(key) < selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(key) >= selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(a[start + m])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightDescending( this List a, Func selector, T key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(key) > selector(a[start + hint])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(key) > selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(key) <= selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(a[start + m])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this List a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(pivot) > selector(a[mid])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderDescending( this List a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[runHi++]) > selector(a[beginIncl])) { while (runHi < endExcl && selector(a[runHi]) > selector(a[runHi - 1])) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[runHi]) <= selector(a[runHi - 1])) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this List a, Func selector, int med) { int last = a.Count - 1; QuickMedianAscending(a, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this List a, Func selector, int beginIncl, int endExcl, int med) { QuickMedianAscending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this List a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[e1]) > selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) > selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) > selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) > selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) > selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) > selector(p2)) { while (selector(a[hi]) > selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) > selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[lo]) == selector(p1)) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && selector(ai) < selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this List a, Func selector) { int last = a.Count - 1; QuickSortAscending(a, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this List a, Func selector, int beginIncl, int endExcl) { QuickSortAscending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this List a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[e1]) > selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) > selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) > selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) > selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) > selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) > selector(p2)) { while (selector(a[hi]) > selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) > selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); { while (selector(a[lo]) == selector(p1)) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, selector, lo, hi, cm); QuickSortAscending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && selector(ai) < selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(element) < selector(a[i2 + begin])) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[i1 + begin]) < selector(a[i2 + begin])) ? i2 : i1; // smaller child if (selector(a[ni + begin]) < selector(element)) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a, Func selector) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(element) < selector(a[i2])) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[i1]) < selector(a[i2])) ? i2 : i1; // smaller child if (selector(a[ni]) < selector(element)) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this List a, Func selector) { SmoothSortAscendingInclusiveRange(a, selector, 0, a.Count - 1); } public static void SmoothSortAscending( this List a, Func selector, int beginIncl, int endExcl) { SmoothSortAscendingInclusiveRange(a, selector, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this List a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head, false); else SmoothSortAscendingSift(a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this List a, Func selector, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(val) >= selector(a[lf]) && selector(val) >= selector(a[rt])) break; if (selector(a[lf]) >= selector(a[rt])) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this List a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (selector(vstepson) <= selector(val)) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[rt]) >= selector(vstepson) || selector(a[lf]) >= selector(vstepson)) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, selector, pshift, head); } } public class TimSortInfoListFloatSel { public List m_a; public Func m_sel; public int m_minGallop = c_minGallop; public T[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoListFloatSel(List a, Func selector) { m_a = a; m_sel = selector; int count = a.Count; m_tmp = new T[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public T[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new T[c < 0 ? cap : Math.Min(c, m_a.Count >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a, Func selector) { TimSortAscending(a, selector, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, selector, lo, hi); BinarySortAscending(a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListFloatSel(a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderAscending(a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortAscending(a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListAsc(ti); } private static void MergeCollapseListAsc(this TimSortInfoListFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListAsc(ti, n); else break; } } private static void MergeForceCollapseListAsc(this TimSortInfoListFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListAsc(ti, n); } } private static void MergeAtListAsc(this TimSortInfoListFloatSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightAscending(a, ti.m_sel, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_sel, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListAsc(ti, start1, len1, start2, len2); else MergeHiListAsc(ti, start1, len1, start2, len2); } private static void MergeLoListAsc(this TimSortInfoListFloatSel ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[idx2]) < selector(t[idx1])) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightAscending(t, selector, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiListAsc(this TimSortInfoListFloatSel ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(t[idx2]) < selector(a[idx1])) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftAscending(t, selector, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftAscending( this List a, Func selector, T key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(key) > selector(a[start + hint])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(key) > selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(key) <= selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(a[start + m])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightAscending( this List a, Func selector, T key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(key) < selector(a[start + hint])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(key) < selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(key) >= selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(a[start + m])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this List a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(pivot) < selector(a[mid])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderAscending( this List a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[runHi++]) < selector(a[beginIncl])) { while (runHi < endExcl && selector(a[runHi]) < selector(a[runHi - 1])) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[runHi]) >= selector(a[runHi - 1])) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this List a, Func selector, int med) { int last = a.Count - 1; QuickMedianDescending(a, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this List a, Func selector, int beginIncl, int endExcl, int med) { QuickMedianDescending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this List a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[e1]) < selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) < selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) < selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) < selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) < selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) < selector(p2)) { while (selector(a[hi]) < selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) < selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[lo]) == selector(p1)) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && selector(ai) > selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this List a, Func selector) { int last = a.Count - 1; QuickSortDescending(a, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this List a, Func selector, int beginIncl, int endExcl) { QuickSortDescending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this List a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[e1]) < selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) < selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) < selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) < selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) < selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) < selector(p2)) { while (selector(a[hi]) < selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) < selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); { while (selector(a[lo]) == selector(p1)) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, selector, lo, hi, cm); QuickSortDescending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && selector(ai) > selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(element) > selector(a[i2 + begin])) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[i1 + begin]) > selector(a[i2 + begin])) ? i2 : i1; // smaller child if (selector(a[ni + begin]) > selector(element)) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a, Func selector) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(element) > selector(a[i2])) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[i1]) > selector(a[i2])) ? i2 : i1; // smaller child if (selector(a[ni]) > selector(element)) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this List a, Func selector) { SmoothSortDescendingInclusiveRange(a, selector, 0, a.Count - 1); } public static void SmoothSortDescending( this List a, Func selector, int beginIncl, int endExcl) { SmoothSortDescendingInclusiveRange(a, selector, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this List a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head, false); else SmoothSortDescendingSift(a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this List a, Func selector, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(val) <= selector(a[lf]) && selector(val) <= selector(a[rt])) break; if (selector(a[lf]) <= selector(a[rt])) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this List a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (selector(vstepson) >= selector(val)) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[rt]) <= selector(vstepson) || selector(a[lf]) <= selector(vstepson)) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a, Func selector) { TimSortDescending(a, selector, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, selector, lo, hi); BinarySortDescending(a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListFloatSel(a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderDescending(a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortDescending(a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListDesc(ti); } private static void MergeCollapseListDesc(this TimSortInfoListFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListDesc(ti, n); else break; } } private static void MergeForceCollapseListDesc(this TimSortInfoListFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListDesc(ti, n); } } private static void MergeAtListDesc(this TimSortInfoListFloatSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightDescending(a, ti.m_sel, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_sel, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListDesc(ti, start1, len1, start2, len2); else MergeHiListDesc(ti, start1, len1, start2, len2); } private static void MergeLoListDesc(this TimSortInfoListFloatSel ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[idx2]) > selector(t[idx1])) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightDescending(t, selector, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiListDesc(this TimSortInfoListFloatSel ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(t[idx2]) > selector(a[idx1])) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftDescending(t, selector, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftDescending( this List a, Func selector, T key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(key) < selector(a[start + hint])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(key) < selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(key) >= selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(a[start + m])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightDescending( this List a, Func selector, T key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(key) > selector(a[start + hint])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(key) > selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(key) <= selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(a[start + m])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this List a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(pivot) > selector(a[mid])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderDescending( this List a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[runHi++]) > selector(a[beginIncl])) { while (runHi < endExcl && selector(a[runHi]) > selector(a[runHi - 1])) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[runHi]) <= selector(a[runHi - 1])) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianAscending( this List a, Func selector, int med) { int last = a.Count - 1; QuickMedianAscending(a, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianAscending( this List a, Func selector, int beginIncl, int endExcl, int med) { QuickMedianAscending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this List a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[e1]) > selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) > selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) > selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) > selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) > selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) > selector(p2)) { while (selector(a[hi]) > selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) > selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[lo]) == selector(p1)) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && selector(ai) < selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortAscending( this List a, Func selector) { int last = a.Count - 1; QuickSortAscending(a, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortAscending( this List a, Func selector, int beginIncl, int endExcl) { QuickSortAscending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this List a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[e1]) > selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) > selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) > selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) > selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) > selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) > selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) > selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) > selector(p2)) { while (selector(a[hi]) > selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) > selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) < selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); { while (selector(a[lo]) == selector(p1)) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, selector, lo, hi, cm); QuickSortAscending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, selector, l, lo - 2, cl); QuickSortAscending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && selector(ai) < selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(element) < selector(a[i2 + begin])) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[i1 + begin]) < selector(a[i2 + begin])) ? i2 : i1; // smaller child if (selector(a[ni + begin]) < selector(element)) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortAscending( this List a, Func selector) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(element) < selector(a[i2])) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[i1]) < selector(a[i2])) ? i2 : i1; // smaller child if (selector(a[ni]) < selector(element)) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortAscending( this List a, Func selector) { SmoothSortAscendingInclusiveRange(a, selector, 0, a.Count - 1); } public static void SmoothSortAscending( this List a, Func selector, int beginIncl, int endExcl) { SmoothSortAscendingInclusiveRange(a, selector, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this List a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head, false); else SmoothSortAscendingSift(a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortAscendingTrinkle(a, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this List a, Func selector, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(val) >= selector(a[lf]) && selector(val) >= selector(a[rt])) break; if (selector(a[lf]) >= selector(a[rt])) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortAscendingTrinkle( this List a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (selector(vstepson) <= selector(val)) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[rt]) >= selector(vstepson) || selector(a[lf]) >= selector(vstepson)) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortAscendingSift(a, selector, pshift, head); } } public class TimSortInfoListDoubleSel { public List m_a; public Func m_sel; public int m_minGallop = c_minGallop; public T[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoListDoubleSel(List a, Func selector) { m_a = a; m_sel = selector; int count = a.Count; m_tmp = new T[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public T[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new T[c < 0 ? cap : Math.Min(c, m_a.Count >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a, Func selector) { TimSortAscending(a, selector, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortAscending( this List a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, selector, lo, hi); BinarySortAscending(a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListDoubleSel(a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderAscending(a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortAscending(a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListAsc(ti); } private static void MergeCollapseListAsc(this TimSortInfoListDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListAsc(ti, n); else break; } } private static void MergeForceCollapseListAsc(this TimSortInfoListDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListAsc(ti, n); } } private static void MergeAtListAsc(this TimSortInfoListDoubleSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightAscending(a, ti.m_sel, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_sel, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListAsc(ti, start1, len1, start2, len2); else MergeHiListAsc(ti, start1, len1, start2, len2); } private static void MergeLoListAsc(this TimSortInfoListDoubleSel ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[idx2]) < selector(t[idx1])) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightAscending(t, selector, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiListAsc(this TimSortInfoListDoubleSel ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(t[idx2]) < selector(a[idx1])) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftAscending(t, selector, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftAscending( this List a, Func selector, T key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(key) > selector(a[start + hint])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(key) > selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(key) <= selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(a[start + m])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightAscending( this List a, Func selector, T key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(key) < selector(a[start + hint])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(key) < selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(key) >= selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(a[start + m])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this List a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(pivot) < selector(a[mid])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderAscending( this List a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[runHi++]) < selector(a[beginIncl])) { while (runHi < endExcl && selector(a[runHi]) < selector(a[runHi - 1])) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[runHi]) >= selector(a[runHi - 1])) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// public static void QuickMedianDescending( this List a, Func selector, int med) { int last = a.Count - 1; QuickMedianDescending(a, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// public static void QuickMedianDescending( this List a, Func selector, int beginIncl, int endExcl, int med) { QuickMedianDescending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this List a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[e1]) < selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) < selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) < selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) < selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) < selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) < selector(p2)) { while (selector(a[hi]) < selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) < selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[lo]) == selector(p1)) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && selector(ai) > selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The QuickSort algorithm sorts the data array. /// public static void QuickSortDescending( this List a, Func selector) { int last = a.Count - 1; QuickSortDescending(a, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// public static void QuickSortDescending( this List a, Func selector, int beginIncl, int endExcl) { QuickSortDescending(a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this List a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[e1]) < selector(a[e2])) { var t = a[e1]; a[e1] = a[e2]; a[e2] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } if (selector(a[e1]) < selector(a[e3])) { var t = a[e1]; a[e1] = a[e3]; a[e3] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e1]) < selector(a[e4])) { var t = a[e1]; a[e1] = a[e4]; a[e4] = t; } if (selector(a[e3]) < selector(a[e4])) { var t = a[e3]; a[e3] = a[e4]; a[e4] = t; } if (selector(a[e2]) < selector(a[e5])) { var t = a[e2]; a[e2] = a[e5]; a[e5] = t; } if (selector(a[e2]) < selector(a[e3])) { var t = a[e2]; a[e2] = a[e3]; a[e3] = t; } if (selector(a[e4]) < selector(a[e5])) { var t = a[e4]; a[e4] = a[e5]; a[e5] = t; } var p1 = a[e2]; a[e2] = a[l]; var p2 = a[e4]; a[e4] = a[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else if (selector(ai) < selector(p2)) { while (selector(a[hi]) < selector(p2) && i < hi) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = a[i]; if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } else { while (selector(a[hi]) < selector(p1)) --hi; a[i] = a[hi]; a[hi] = ai; --hi; ai = a[i]; if (selector(ai) > selector(p1)) { a[i] = a[lo]; a[lo] = ai; ++lo; } } } } a[l] = a[lo - 1]; a[lo - 1] = p1; a[r] = a[hi + 1]; a[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); { while (selector(a[lo]) == selector(p1)) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[i]) == selector(p1)) { p1 = a[i]; a[i] = a[lo]; a[lo] = p1; ++lo; } } while (selector(a[hi]) == selector(p2)) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[i]) == selector(p2)) { p2 = a[i]; a[i] = a[hi]; a[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, selector, lo, hi, cm); QuickSortDescending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, selector, l, lo - 2, cl); QuickSortDescending(a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = a[i]; int j; for (j = i - 1; j >= l && selector(ai) > selector(a[j]); j--) a[j + 1] = a[j]; a[j + 1] = ai; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = a[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(element) > selector(a[i2 + begin])) break; a[i + begin] = a[i2 + begin]; i = i2; } a[i + begin] = element; } while (count > 1) { --count; var element = a[count + begin]; a[count + begin] = a[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[i1 + begin]) > selector(a[i2 + begin])) ? i2 : i1; // smaller child if (selector(a[ni + begin]) > selector(element)) break; a[i + begin] = a[ni + begin]; i = ni; i1 = 2 * i + 1; } a[i + begin] = element; } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void HeapSortDescending( this List a, Func selector) { int count = a.Count; for (int c = 1; c < count; c++) { var element = a[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(element) > selector(a[i2])) break; a[i] = a[i2]; i = i2; } a[i] = element; } while (count > 1) { --count; var element = a[count]; a[count] = a[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[i1]) > selector(a[i2])) ? i2 : i1; // smaller child if (selector(a[ni]) > selector(element)) break; a[i] = a[ni]; i = ni; i1 = 2 * i + 1; } a[i] = element; } } public static void SmoothSortDescending( this List a, Func selector) { SmoothSortDescendingInclusiveRange(a, selector, 0, a.Count - 1); } public static void SmoothSortDescending( this List a, Func selector, int beginIncl, int endExcl) { SmoothSortDescendingInclusiveRange(a, selector, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this List a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head, false); else SmoothSortDescendingSift(a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); SmoothSortDescendingTrinkle(a, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this List a, Func selector, int pshift, int head) { var val = a[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(val) <= selector(a[lf]) && selector(val) <= selector(a[rt])) break; if (selector(a[lf]) <= selector(a[rt])) { a[head] = a[lf]; head = lf; pshift -= 1; } else { a[head] = a[rt]; head = rt; pshift -= 2; } } a[head] = val; } private static void SmoothSortDescendingTrinkle( this List a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = a[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = a[stepson]; if (selector(vstepson) >= selector(val)) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[rt]) <= selector(vstepson) || selector(a[lf]) <= selector(vstepson)) break; } a[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { a[head] = val; SmoothSortDescendingSift(a, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a, Func selector) { TimSortDescending(a, selector, 0, a.Count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void TimSortDescending( this List a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, selector, lo, hi); BinarySortDescending(a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListDoubleSel(a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = CountRunAndOrderDescending(a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; BinarySortDescending(a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListDesc(ti); } private static void MergeCollapseListDesc(this TimSortInfoListDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListDesc(ti, n); else break; } } private static void MergeForceCollapseListDesc(this TimSortInfoListDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListDesc(ti, n); } } private static void MergeAtListDesc(this TimSortInfoListDoubleSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = GallopRightDescending(a, ti.m_sel, ti.m_a[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_sel, ti.m_a[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListDesc(ti, start1, len1, start2, len2); else MergeHiListDesc(ti, start1, len1, start2, len2); } private static void MergeLoListDesc(this TimSortInfoListDoubleSel ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len1); CopyElements(a, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; a[dest++] = a[idx2++]; if (--len2 == 0) { CopyElements(t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[idx2]) > selector(t[idx1])) { a[dest++] = a[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { a[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)GallopRightDescending(t, selector, a[idx2], idx1, len1, 0); if (count1 != 0) { CopyElements(t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } a[dest++] = a[idx2++]; if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { CopyElements(a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } a[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(a, idx2, a, dest, len2); a[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, idx1, a, dest, len1); } private static void MergeHiListDesc(this TimSortInfoListDoubleSel ti, int start1, int len1, int start2, int len2) { var a = ti.m_a; var t = ti.EnsureCapacity(len2); CopyElements(a, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; a[dest--] = a[idx1--]; if (--len1 == 0) { CopyElements(t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(t[idx2]) > selector(a[idx1])) { a[dest--] = a[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { a[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } a[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)GallopLeftDescending(t, selector, a[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } a[dest--] = a[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(a, idx1 + 1, a, dest + 1, len1); a[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(t, 0, a, dest - (len2 - 1), len2); } private static int GallopLeftDescending( this List a, Func selector, T key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(key) < selector(a[start + hint])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(key) < selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(key) >= selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(a[start + m])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int GallopRightDescending( this List a, Func selector, T key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(key) > selector(a[start + hint])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(key) > selector(a[start + hint - ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(key) <= selector(a[start + hint + ofs])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(a[start + m])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this List a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = a[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(pivot) > selector(a[mid])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: a[l + 2] = a[l + 1]; a[l + 1] = a[l]; break; case 1: a[l + 1] = a[l]; break; default: CopyElements(a, l, a, l + 1, n); break; } a[l] = pivot; } } private static int CountRunAndOrderDescending( this List a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[runHi++]) > selector(a[beginIncl])) { while (runHi < endExcl && selector(a[runHi]) > selector(a[runHi - 1])) runHi++; ReverseRange(a, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[runHi]) <= selector(a[runHi - 1])) runHi++; } return runHi - beginIncl; } #endregion #region Permutation Sort/Median for List /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedian( this List a, Func cmp, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedian(p, a, cmp, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedian( this int[] p, List a, Func cmp, int med) { int last = p.Length - 1; PermutationQuickMedian(p, a, cmp, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedian( this int[] p, List a, Func cmp, int beginIncl, int endExcl, int med) { PermutationQuickMedian(p, a, cmp, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedian( this int[] p, List a, Func cmp, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (cmp(a[p[e1]], a[p[e2]]) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (cmp(a[p[e4]], a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (cmp(a[p[e1]], a[p[e3]]) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (cmp(a[p[e2]], a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(a[p[e1]], a[p[e4]]) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (cmp(a[p[e3]], a[p[e4]]) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (cmp(a[p[e2]], a[p[e5]]) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (cmp(a[p[e2]], a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(a[p[e4]], a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = cmp(a[p1], a[p2]) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (cmp(a[ai], a[p2]) > 0) { while (cmp(a[p[hi]], a[p2]) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(a[ai], a[p1]) == 0) continue; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (cmp(a[p[hi]], a[p1]) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (cmp(a[p[lo]], a[p1]) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (cmp(a[p[i]], a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (cmp(a[p[hi]], a[p2]) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (cmp(a[p[i]], a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && cmp(a[ai], a[p[j]]) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSort( this List a, Func cmp) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSort(p, a, cmp, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSort( this int[] p, List a, Func cmp) { int last = p.Length - 1; PermutationQuickSort(p, a, cmp, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSort( this int[] p, List a, Func cmp, int beginIncl, int endExcl) { PermutationQuickSort(p, a, cmp, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSort( this int[] p, List a, Func cmp, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (cmp(a[p[e1]], a[p[e2]]) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (cmp(a[p[e4]], a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (cmp(a[p[e1]], a[p[e3]]) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (cmp(a[p[e2]], a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(a[p[e1]], a[p[e4]]) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (cmp(a[p[e3]], a[p[e4]]) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (cmp(a[p[e2]], a[p[e5]]) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (cmp(a[p[e2]], a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(a[p[e4]], a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = cmp(a[p1], a[p2]) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (cmp(a[ai], a[p2]) > 0) { while (cmp(a[p[hi]], a[p2]) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(a[ai], a[p1]) == 0) continue; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (cmp(a[p[hi]], a[p1]) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(a[ai], a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSort(p, a, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, cmp, hi + 2, r, cr); { while (cmp(a[p[lo]], a[p1]) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (cmp(a[p[i]], a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (cmp(a[p[hi]], a[p2]) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (cmp(a[p[i]], a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSort(p, a, cmp, lo, hi, cm); PermutationQuickSort(p, a, cmp, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSort(p, a, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, cmp, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSort(p, a, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, cmp, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSort(p, a, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, cmp, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSort(p, a, cmp, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSort(p, a, cmp, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && cmp(a[ai], a[p[j]]) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSort( this List a, Func cmp) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSort(p, a, cmp); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSort( this int[] p, List a, Func cmp, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (cmp(a[element], a[p[i2 + begin]]) < 0) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && cmp(a[p[i1 + begin]], a[p[i2 + begin]]) < 0) ? i2 : i1; // smaller child if (cmp(a[p[ni + begin]], a[element]) < 0) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSort( this int[] p, List a, Func cmp) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (cmp(a[element], a[p[i2]]) < 0) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && cmp(a[p[i1]], a[p[i2]]) < 0) ? i2 : i1; // smaller child if (cmp(a[p[ni]], a[element]) < 0) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSort( this List a, Func cmp) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSort(p, a, cmp); return p; } public static void PermutationSmoothSort( this int[] p, List a, Func cmp) { PermutationSmoothSortInclusiveRange(p, a, cmp, 0, p.Length - 1); } public static void PermutationSmoothSort( this int[] p, List a, Func cmp, int beginIncl, int endExcl) { PermutationSmoothSortInclusiveRange(p, a, cmp, beginIncl, endExcl - 1); } private static void PermutationSmoothSortInclusiveRange( this int[] p, List a, Func cmp, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortSift(p, a, cmp, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortTrinkle(p, a, cmp, pbits, pshift, head, false); else PermutationSmoothSortSift(p, a, cmp, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortTrinkle(p, a, cmp, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortTrinkle(p, a, cmp, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortTrinkle(p, a, cmp, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortSift( this int[] p, List a, Func cmp, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (cmp(a[val], a[p[lf]]) >= 0 && cmp(a[val], a[p[rt]]) >= 0) break; if (cmp(a[p[lf]], a[p[rt]]) >= 0) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortTrinkle( this int[] p, List a, Func cmp, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (cmp(a[vstepson], a[val]) <= 0) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (cmp(a[p[rt]], a[vstepson]) >= 0 || cmp(a[p[lf]], a[vstepson]) >= 0) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortSift(p, a, cmp, pshift, head); } } public class TimSortInfoListPermCmp { public int[] m_p; public List m_a; public Func m_cmp; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoListPermCmp(int[] p, List a, Func cmp) { m_p = p; m_a = a; m_cmp = cmp; int count = p.Length; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSort( this List a, Func cmp) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSort(p, a, cmp); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSort( this int[] p, List a, Func cmp) { PermutationTimSort(p, a, cmp, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSort( this int[] p, List a, Func cmp, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrder(p, a, cmp, lo, hi); PermutationBinarySort(p, a, cmp, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPermCmp(p, a, cmp); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrder(p, a, cmp, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySort(p, a, cmp, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListPermCmp(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListPermCmp(ti); } private static void MergeCollapseListPermCmp(this TimSortInfoListPermCmp ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermCmp(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListPermCmp(ti, n); else break; } } private static void MergeForceCollapseListPermCmp(this TimSortInfoListPermCmp ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermCmp(ti, n); } } private static void MergeAtListPermCmp(this TimSortInfoListPermCmp ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRight(ti.m_p, a, ti.m_cmp, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeft(ti.m_p, a, ti.m_cmp, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListPermCmp(ti, start1, len1, start2, len2); else MergeHiListPermCmp(ti, start1, len1, start2, len2); } private static void MergeLoListPermCmp(this TimSortInfoListPermCmp ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func cmp = ti.m_cmp; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (cmp(a[p[idx2]], a[t[idx1]]) < 0) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRight(t, a, cmp, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeft(p, a, cmp, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiListPermCmp(this TimSortInfoListPermCmp ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func cmp = ti.m_cmp; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (cmp(a[t[idx2]], a[p[idx1]]) < 0) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRight(p, a, cmp, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeft(t, a, cmp, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeft( this int[] p, List a, Func cmp, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (cmp(a[key], a[p[start + hint]]) > 0) { int maxOfs = len - hint; while (ofs < maxOfs && cmp(a[key], a[p[start + hint + ofs]]) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && cmp(a[key], a[p[start + hint - ofs]]) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (cmp(a[key], a[p[start + m]]) > 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRight( this int[] p, List a, Func cmp, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (cmp(a[key], a[p[start + hint]]) < 0) { int maxOfs = hint + 1; while (ofs < maxOfs && cmp(a[key], a[p[start + hint - ofs]]) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && cmp(a[key], a[p[start + hint + ofs]]) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (cmp(a[key], a[p[start + m]]) < 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySort( this int[] p, List a, Func cmp, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (cmp(a[pivot], a[p[mid]]) < 0) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrder( this int[] p, List a, Func cmp, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (cmp(a[p[runHi++]], a[p[beginIncl]]) < 0) { while (runHi < endExcl && cmp(a[p[runHi]], a[p[runHi - 1]]) < 0) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && cmp(a[p[runHi]], a[p[runHi - 1]]) >= 0) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this List a, int med) where T : IComparable { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, List a, int med) where T : IComparable { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, List a, int beginIncl, int endExcl, int med) where T : IComparable { PermutationQuickMedianAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, List a, int l, int r, int countSub1, int med) where T : IComparable { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]].CompareTo(a[p[e2]]) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]].CompareTo(a[p[e3]]) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]].CompareTo(a[p[e4]]) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]].CompareTo(a[p[e4]]) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]].CompareTo(a[p[e5]]) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1].CompareTo(a[p2]) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai].CompareTo(a[p2]) > 0) { while (a[p[hi]].CompareTo(a[p2]) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) == 0) continue; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]].CompareTo(a[p1]) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]].CompareTo(a[p1]) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]].CompareTo(a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]].CompareTo(a[p2]) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]].CompareTo(a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai].CompareTo(a[p[j]]) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this List a) where T : IComparable { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a) where T : IComparable { int last = p.Length - 1; PermutationQuickSortAscending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a, int beginIncl, int endExcl) where T : IComparable { PermutationQuickSortAscending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, List a, int l, int r, int countSub1) where T : IComparable { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]].CompareTo(a[p[e2]]) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]].CompareTo(a[p[e3]]) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]].CompareTo(a[p[e4]]) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]].CompareTo(a[p[e4]]) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]].CompareTo(a[p[e5]]) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1].CompareTo(a[p2]) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai].CompareTo(a[p2]) > 0) { while (a[p[hi]].CompareTo(a[p2]) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) == 0) continue; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]].CompareTo(a[p1]) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); { while (a[p[lo]].CompareTo(a[p1]) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]].CompareTo(a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]].CompareTo(a[p2]) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]].CompareTo(a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, lo, hi, cm); PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); PermutationQuickSortAscending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai].CompareTo(a[p[j]]) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this List a) where T : IComparable { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a, int begin, int end) where T : IComparable { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element].CompareTo(a[p[i2 + begin]]) < 0) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]].CompareTo(a[p[i2 + begin]]) < 0) ? i2 : i1; // smaller child if (a[p[ni + begin]].CompareTo(a[element]) < 0) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a) where T : IComparable { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element].CompareTo(a[p[i2]]) < 0) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]].CompareTo(a[p[i2]]) < 0) ? i2 : i1; // smaller child if (a[p[ni]].CompareTo(a[element]) < 0) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this List a) where T : IComparable { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a); return p; } public static void PermutationSmoothSortAscending( this int[] p, List a) where T : IComparable { PermutationSmoothSortAscendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, List a, int beginIncl, int endExcl) where T : IComparable { PermutationSmoothSortAscendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, List a, int lo, int hi) where T : IComparable { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, List a, int pshift, int head) where T : IComparable { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val].CompareTo(a[p[lf]]) >= 0 && a[val].CompareTo(a[p[rt]]) >= 0) break; if (a[p[lf]].CompareTo(a[p[rt]]) >= 0) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, List a, long pbits, int pshift, int head, bool isTrusty) where T : IComparable { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson].CompareTo(a[val]) <= 0) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]].CompareTo(a[vstepson]) >= 0 || a[p[lf]].CompareTo(a[vstepson]) >= 0) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, pshift, head); } } public class TimSortInfoListPerm where T : IComparable { public int[] m_p; public List m_a; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoListPerm(int[] p, List a) { m_p = p; m_a = a; int count = p.Length; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this List a) where T : IComparable { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a) where T : IComparable { PermutationTimSortAscending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a, int lo, int hi) where T : IComparable { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); PermutationBinarySortAscending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListPermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListPermAsc(ti); } private static void MergeCollapseListPermAsc(this TimSortInfoListPerm ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListPermAsc(ti, n); else break; } } private static void MergeForceCollapseListPermAsc(this TimSortInfoListPerm ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermAsc(ti, n); } } private static void MergeAtListPermAsc(this TimSortInfoListPerm ti, int i) where T : IComparable { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListPermAsc(ti, start1, len1, start2, len2); else MergeHiListPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoListPermAsc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]].CompareTo(a[t[idx1]]) < 0) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightAscending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiListPermAsc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]].CompareTo(a[p[idx1]]) < 0) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftAscending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, List a, int key, int start, int len, int hint) where T : IComparable { int lastOfs = 0, ofs = 1; if (a[key].CompareTo(a[p[start + hint]]) > 0) { int maxOfs = len - hint; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint + ofs]]) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint - ofs]]) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key].CompareTo(a[p[start + m]]) > 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, List a, int key, int start, int len, int hint) where T : IComparable { int ofs = 1, lastOfs = 0; if (a[key].CompareTo(a[p[start + hint]]) < 0) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint - ofs]]) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint + ofs]]) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key].CompareTo(a[p[start + m]]) < 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, List a, int beginIncl, int endExcl, int beginUnsorted) where T : IComparable { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot].CompareTo(a[p[mid]]) < 0) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, List a, int beginIncl, int endExcl) where T : IComparable { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]].CompareTo(a[p[beginIncl]]) < 0) { while (runHi < endExcl && a[p[runHi]].CompareTo(a[p[runHi - 1]]) < 0) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]].CompareTo(a[p[runHi - 1]]) >= 0) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this List a, int med) where T : IComparable { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, List a, int med) where T : IComparable { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, List a, int beginIncl, int endExcl, int med) where T : IComparable { PermutationQuickMedianDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, List a, int l, int r, int countSub1, int med) where T : IComparable { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]].CompareTo(a[p[e2]]) < 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]].CompareTo(a[p[e3]]) < 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]].CompareTo(a[p[e4]]) < 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]].CompareTo(a[p[e4]]) < 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]].CompareTo(a[p[e5]]) < 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1].CompareTo(a[p2]) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai].CompareTo(a[p2]) < 0) { while (a[p[hi]].CompareTo(a[p2]) < 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) == 0) continue; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]].CompareTo(a[p1]) < 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (a[p[lo]].CompareTo(a[p1]) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]].CompareTo(a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]].CompareTo(a[p2]) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]].CompareTo(a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai].CompareTo(a[p[j]]) > 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this List a) where T : IComparable { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a) where T : IComparable { int last = p.Length - 1; PermutationQuickSortDescending(p, a, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a, int beginIncl, int endExcl) where T : IComparable { PermutationQuickSortDescending(p, a, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, List a, int l, int r, int countSub1) where T : IComparable { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (a[p[e1]].CompareTo(a[p[e2]]) < 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (a[p[e1]].CompareTo(a[p[e3]]) < 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e1]].CompareTo(a[p[e4]]) < 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (a[p[e3]].CompareTo(a[p[e4]]) < 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (a[p[e2]].CompareTo(a[p[e5]]) < 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (a[p[e2]].CompareTo(a[p[e3]]) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (a[p[e4]].CompareTo(a[p[e5]]) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = a[p1].CompareTo(a[p2]) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (a[ai].CompareTo(a[p2]) < 0) { while (a[p[hi]].CompareTo(a[p2]) < 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (a[ai].CompareTo(a[p1]) == 0) continue; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (a[p[hi]].CompareTo(a[p1]) < 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (a[ai].CompareTo(a[p1]) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); { while (a[p[lo]].CompareTo(a[p1]) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (a[p[i]].CompareTo(a[p1]) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (a[p[hi]].CompareTo(a[p2]) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (a[p[i]].CompareTo(a[p2]) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, lo, hi, cm); PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); PermutationQuickSortDescending(p, a, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && a[ai].CompareTo(a[p[j]]) > 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this List a) where T : IComparable { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a, int begin, int end) where T : IComparable { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element].CompareTo(a[p[i2 + begin]]) > 0) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1 + begin]].CompareTo(a[p[i2 + begin]]) > 0) ? i2 : i1; // smaller child if (a[p[ni + begin]].CompareTo(a[element]) > 0) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a) where T : IComparable { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (a[element].CompareTo(a[p[i2]]) > 0) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && a[p[i1]].CompareTo(a[p[i2]]) > 0) ? i2 : i1; // smaller child if (a[p[ni]].CompareTo(a[element]) > 0) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this List a) where T : IComparable { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a); return p; } public static void PermutationSmoothSortDescending( this int[] p, List a) where T : IComparable { PermutationSmoothSortDescendingInclusiveRange(p, a, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, List a, int beginIncl, int endExcl) where T : IComparable { PermutationSmoothSortDescendingInclusiveRange(p, a, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, List a, int lo, int hi) where T : IComparable { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, List a, int pshift, int head) where T : IComparable { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[val].CompareTo(a[p[lf]]) <= 0 && a[val].CompareTo(a[p[rt]]) <= 0) break; if (a[p[lf]].CompareTo(a[p[rt]]) <= 0) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, List a, long pbits, int pshift, int head, bool isTrusty) where T : IComparable { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (a[vstepson].CompareTo(a[val]) >= 0) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (a[p[rt]].CompareTo(a[vstepson]) <= 0 || a[p[lf]].CompareTo(a[vstepson]) <= 0) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this List a) where T : IComparable { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a) where T : IComparable { PermutationTimSortDescending(p, a, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a, int lo, int hi) where T : IComparable { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); PermutationBinarySortDescending(p, a, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPerm(p, a); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListPermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListPermDesc(ti); } private static void MergeCollapseListPermDesc(this TimSortInfoListPerm ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListPermDesc(ti, n); else break; } } private static void MergeForceCollapseListPermDesc(this TimSortInfoListPerm ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermDesc(ti, n); } } private static void MergeAtListPermDesc(this TimSortInfoListPerm ti, int i) where T : IComparable { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListPermDesc(ti, start1, len1, start2, len2); else MergeHiListPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoListPermDesc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[p[idx2]].CompareTo(a[t[idx1]]) > 0) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightDescending(t, a, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiListPermDesc(this TimSortInfoListPerm ti, int start1, int len1, int start2, int len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (a[t[idx2]].CompareTo(a[p[idx1]]) > 0) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftDescending(t, a, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, List a, int key, int start, int len, int hint) where T : IComparable { int lastOfs = 0, ofs = 1; if (a[key].CompareTo(a[p[start + hint]]) < 0) { int maxOfs = len - hint; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint + ofs]]) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint - ofs]]) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key].CompareTo(a[p[start + m]]) < 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, List a, int key, int start, int len, int hint) where T : IComparable { int ofs = 1, lastOfs = 0; if (a[key].CompareTo(a[p[start + hint]]) > 0) { int maxOfs = hint + 1; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint - ofs]]) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && a[key].CompareTo(a[p[start + hint + ofs]]) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (a[key].CompareTo(a[p[start + m]]) > 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, List a, int beginIncl, int endExcl, int beginUnsorted) where T : IComparable { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (a[pivot].CompareTo(a[p[mid]]) > 0) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, List a, int beginIncl, int endExcl) where T : IComparable { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (a[p[runHi++]].CompareTo(a[p[beginIncl]]) > 0) { while (runHi < endExcl && a[p[runHi]].CompareTo(a[p[runHi - 1]]) > 0) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && a[p[runHi]].CompareTo(a[p[runHi - 1]]) <= 0) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this List a, Func selector, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, List a, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, List a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a, Func selector) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, List a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) < selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) < selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1]]) < selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) < selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a, selector); return p; } public static void PermutationSmoothSortAscending( this int[] p, List a, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, List a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, List a, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[val]) >= selector(a[p[lf]]) && selector(a[val]) >= selector(a[p[rt]])) break; if (selector(a[p[lf]]) >= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, List a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) <= selector(a[val])) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[p[rt]]) >= selector(a[vstepson]) || selector(a[p[lf]]) >= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); } } public class TimSortInfoListPermIntSel { public int[] m_p; public List m_a; public Func m_sel; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoListPermIntSel(int[] p, List a, Func selector) { m_p = p; m_a = a; m_sel = selector; int count = p.Length; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a, Func selector) { PermutationTimSortAscending(p, a, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); PermutationBinarySortAscending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPermIntSel(p, a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListPermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListPermAsc(ti); } private static void MergeCollapseListPermAsc(this TimSortInfoListPermIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListPermAsc(ti, n); else break; } } private static void MergeForceCollapseListPermAsc(this TimSortInfoListPermIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermAsc(ti, n); } } private static void MergeAtListPermAsc(this TimSortInfoListPermIntSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListPermAsc(ti, start1, len1, start2, len2); else MergeHiListPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoListPermAsc(this TimSortInfoListPermIntSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) < selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightAscending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiListPermAsc(this TimSortInfoListPermIntSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) < selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftAscending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, List a, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(a[key]) > selector(a[p[start + hint]])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, List a, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(a[key]) < selector(a[p[start + hint]])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(a[pivot]) < selector(a[p[mid]])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) < selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) < selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) >= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this List a, Func selector, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, List a, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, List a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a, Func selector) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, List a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) > selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) > selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1]]) > selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) > selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a, selector); return p; } public static void PermutationSmoothSortDescending( this int[] p, List a, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, List a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, List a, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[val]) <= selector(a[p[lf]]) && selector(a[val]) <= selector(a[p[rt]])) break; if (selector(a[p[lf]]) <= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, List a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) >= selector(a[val])) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[p[rt]]) <= selector(a[vstepson]) || selector(a[p[lf]]) <= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a, Func selector) { PermutationTimSortDescending(p, a, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); PermutationBinarySortDescending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPermIntSel(p, a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListPermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListPermDesc(ti); } private static void MergeCollapseListPermDesc(this TimSortInfoListPermIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListPermDesc(ti, n); else break; } } private static void MergeForceCollapseListPermDesc(this TimSortInfoListPermIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermDesc(ti, n); } } private static void MergeAtListPermDesc(this TimSortInfoListPermIntSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListPermDesc(ti, start1, len1, start2, len2); else MergeHiListPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoListPermDesc(this TimSortInfoListPermIntSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) > selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightDescending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiListPermDesc(this TimSortInfoListPermIntSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) > selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftDescending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, List a, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(a[key]) < selector(a[p[start + hint]])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, List a, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(a[key]) > selector(a[p[start + hint]])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(a[pivot]) > selector(a[p[mid]])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) > selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) > selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) <= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this List a, Func selector, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, List a, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, List a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a, Func selector) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, List a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) < selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) < selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1]]) < selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) < selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a, selector); return p; } public static void PermutationSmoothSortAscending( this int[] p, List a, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, List a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, List a, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[val]) >= selector(a[p[lf]]) && selector(a[val]) >= selector(a[p[rt]])) break; if (selector(a[p[lf]]) >= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, List a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) <= selector(a[val])) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[p[rt]]) >= selector(a[vstepson]) || selector(a[p[lf]]) >= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); } } public class TimSortInfoListPermLongSel { public int[] m_p; public List m_a; public Func m_sel; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoListPermLongSel(int[] p, List a, Func selector) { m_p = p; m_a = a; m_sel = selector; int count = p.Length; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a, Func selector) { PermutationTimSortAscending(p, a, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); PermutationBinarySortAscending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPermLongSel(p, a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListPermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListPermAsc(ti); } private static void MergeCollapseListPermAsc(this TimSortInfoListPermLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListPermAsc(ti, n); else break; } } private static void MergeForceCollapseListPermAsc(this TimSortInfoListPermLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermAsc(ti, n); } } private static void MergeAtListPermAsc(this TimSortInfoListPermLongSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListPermAsc(ti, start1, len1, start2, len2); else MergeHiListPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoListPermAsc(this TimSortInfoListPermLongSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) < selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightAscending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiListPermAsc(this TimSortInfoListPermLongSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) < selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftAscending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, List a, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(a[key]) > selector(a[p[start + hint]])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, List a, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(a[key]) < selector(a[p[start + hint]])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(a[pivot]) < selector(a[p[mid]])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) < selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) < selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) >= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this List a, Func selector, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, List a, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, List a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a, Func selector) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, List a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) > selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) > selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1]]) > selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) > selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a, selector); return p; } public static void PermutationSmoothSortDescending( this int[] p, List a, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, List a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, List a, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[val]) <= selector(a[p[lf]]) && selector(a[val]) <= selector(a[p[rt]])) break; if (selector(a[p[lf]]) <= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, List a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) >= selector(a[val])) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[p[rt]]) <= selector(a[vstepson]) || selector(a[p[lf]]) <= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a, Func selector) { PermutationTimSortDescending(p, a, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); PermutationBinarySortDescending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPermLongSel(p, a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListPermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListPermDesc(ti); } private static void MergeCollapseListPermDesc(this TimSortInfoListPermLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListPermDesc(ti, n); else break; } } private static void MergeForceCollapseListPermDesc(this TimSortInfoListPermLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermDesc(ti, n); } } private static void MergeAtListPermDesc(this TimSortInfoListPermLongSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListPermDesc(ti, start1, len1, start2, len2); else MergeHiListPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoListPermDesc(this TimSortInfoListPermLongSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) > selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightDescending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiListPermDesc(this TimSortInfoListPermLongSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) > selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftDescending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, List a, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(a[key]) < selector(a[p[start + hint]])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, List a, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(a[key]) > selector(a[p[start + hint]])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(a[pivot]) > selector(a[p[mid]])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) > selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) > selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) <= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this List a, Func selector, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, List a, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, List a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a, Func selector) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, List a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) < selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) < selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1]]) < selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) < selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a, selector); return p; } public static void PermutationSmoothSortAscending( this int[] p, List a, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, List a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, List a, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[val]) >= selector(a[p[lf]]) && selector(a[val]) >= selector(a[p[rt]])) break; if (selector(a[p[lf]]) >= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, List a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) <= selector(a[val])) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[p[rt]]) >= selector(a[vstepson]) || selector(a[p[lf]]) >= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); } } public class TimSortInfoListPermFloatSel { public int[] m_p; public List m_a; public Func m_sel; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoListPermFloatSel(int[] p, List a, Func selector) { m_p = p; m_a = a; m_sel = selector; int count = p.Length; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a, Func selector) { PermutationTimSortAscending(p, a, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); PermutationBinarySortAscending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPermFloatSel(p, a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListPermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListPermAsc(ti); } private static void MergeCollapseListPermAsc(this TimSortInfoListPermFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListPermAsc(ti, n); else break; } } private static void MergeForceCollapseListPermAsc(this TimSortInfoListPermFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermAsc(ti, n); } } private static void MergeAtListPermAsc(this TimSortInfoListPermFloatSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListPermAsc(ti, start1, len1, start2, len2); else MergeHiListPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoListPermAsc(this TimSortInfoListPermFloatSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) < selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightAscending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiListPermAsc(this TimSortInfoListPermFloatSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) < selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftAscending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, List a, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(a[key]) > selector(a[p[start + hint]])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, List a, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(a[key]) < selector(a[p[start + hint]])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(a[pivot]) < selector(a[p[mid]])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) < selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) < selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) >= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this List a, Func selector, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, List a, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, List a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a, Func selector) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, List a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) > selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) > selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1]]) > selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) > selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a, selector); return p; } public static void PermutationSmoothSortDescending( this int[] p, List a, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, List a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, List a, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[val]) <= selector(a[p[lf]]) && selector(a[val]) <= selector(a[p[rt]])) break; if (selector(a[p[lf]]) <= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, List a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) >= selector(a[val])) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[p[rt]]) <= selector(a[vstepson]) || selector(a[p[lf]]) <= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a, Func selector) { PermutationTimSortDescending(p, a, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); PermutationBinarySortDescending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPermFloatSel(p, a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListPermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListPermDesc(ti); } private static void MergeCollapseListPermDesc(this TimSortInfoListPermFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListPermDesc(ti, n); else break; } } private static void MergeForceCollapseListPermDesc(this TimSortInfoListPermFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermDesc(ti, n); } } private static void MergeAtListPermDesc(this TimSortInfoListPermFloatSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListPermDesc(ti, start1, len1, start2, len2); else MergeHiListPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoListPermDesc(this TimSortInfoListPermFloatSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) > selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightDescending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiListPermDesc(this TimSortInfoListPermFloatSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) > selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftDescending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, List a, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(a[key]) < selector(a[p[start + hint]])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, List a, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(a[key]) > selector(a[p[start + hint]])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(a[pivot]) > selector(a[p[mid]])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) > selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) > selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) <= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianAscending( this List a, Func selector, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianAscending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianAscending( this int[] p, List a, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, List a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortAscending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortAscending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a, Func selector) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, List a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) > selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) > selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) > selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) > selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) > selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) > selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) > selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) > selector(a[p2])) { while (selector(a[p[hi]]) > selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) > selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) < selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) < selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortAscending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortAscending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) < selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) < selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortAscending( this int[] p, List a, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) < selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1]]) < selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) < selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortAscending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortAscending(p, a, selector); return p; } public static void PermutationSmoothSortAscending( this int[] p, List a, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, 0, p.Length - 1); } public static void PermutationSmoothSortAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, List a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, List a, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[val]) >= selector(a[p[lf]]) && selector(a[val]) >= selector(a[p[rt]])) break; if (selector(a[p[lf]]) >= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, List a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) <= selector(a[val])) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[p[rt]]) >= selector(a[vstepson]) || selector(a[p[lf]]) >= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, selector, pshift, head); } } public class TimSortInfoListPermDoubleSel { public int[] m_p; public List m_a; public Func m_sel; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoListPermDoubleSel(int[] p, List a, Func selector) { m_p = p; m_a = a; m_sel = selector; int count = p.Length; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortAscending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortAscending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a, Func selector) { PermutationTimSortAscending(p, a, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortAscending( this int[] p, List a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); PermutationBinarySortAscending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPermDoubleSel(p, a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListPermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListPermAsc(ti); } private static void MergeCollapseListPermAsc(this TimSortInfoListPermDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListPermAsc(ti, n); else break; } } private static void MergeForceCollapseListPermAsc(this TimSortInfoListPermDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermAsc(ti, n); } } private static void MergeAtListPermAsc(this TimSortInfoListPermDoubleSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListPermAsc(ti, start1, len1, start2, len2); else MergeHiListPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoListPermAsc(this TimSortInfoListPermDoubleSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) < selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightAscending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiListPermAsc(this TimSortInfoListPermDoubleSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) < selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftAscending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, List a, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(a[key]) > selector(a[p[start + hint]])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, List a, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(a[key]) < selector(a[p[start + hint]])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(a[pivot]) < selector(a[p[mid]])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) < selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) < selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) >= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } /// /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. /// public static int[] CreatePermutationQuickMedianDescending( this List a, Func selector, int med) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickMedianDescending(p, a, selector, 0, len - 1, len - 1, med); return p; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// public static void PermutationQuickMedianDescending( this int[] p, List a, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// public static void PermutationQuickMedianDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, List a, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. /// public static int[] CreatePermutationQuickSortDescending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationQuickSortDescending(p, a, selector, 0, len - 1, len - 1); return p; } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a, Func selector) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// public static void PermutationQuickSortDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, List a, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(a[p[e1]]) < selector(a[p[e2]])) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(a[p[e1]]) < selector(a[p[e3]])) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e1]]) < selector(a[p[e4]])) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(a[p[e3]]) < selector(a[p[e4]])) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(a[p[e2]]) < selector(a[p[e5]])) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(a[p[e2]]) < selector(a[p[e3]])) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(a[p[e4]]) < selector(a[p[e5]])) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(a[p1]) != selector(a[p2]); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(a[ai]) < selector(a[p2])) { while (selector(a[p[hi]]) < selector(a[p2]) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(a[ai]) == selector(a[p1])) continue; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(a[p[hi]]) < selector(a[p1])) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(a[ai]) > selector(a[p1])) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); { while (selector(a[p[lo]]) == selector(a[p1])) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(a[p[i]]) == selector(a[p1])) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(a[p[hi]]) == selector(a[p2])) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(a[p[i]]) == selector(a[p2])) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(a[ai]) > selector(a[p[j]]); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// public static int[] CreatePermutationHeapSortDescending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationHeapSortDescending(p, a, selector); return p; } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2 + begin]])) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1 + begin]]) > selector(a[p[i2 + begin]])) ? i2 : i1; // smaller child if (selector(a[p[ni + begin]]) > selector(a[element])) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// public static void PermutationHeapSortDescending( this int[] p, List a, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(a[element]) > selector(a[p[i2]])) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(a[p[i1]]) > selector(a[p[i2]])) ? i2 : i1; // smaller child if (selector(a[p[ni]]) > selector(a[element])) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// public static int[] CreatePermutationSmoothSortDescending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationSmoothSortDescending(p, a, selector); return p; } public static void PermutationSmoothSortDescending( this int[] p, List a, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, 0, p.Length - 1); } public static void PermutationSmoothSortDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, List a, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, List a, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[val]) <= selector(a[p[lf]]) && selector(a[val]) <= selector(a[p[rt]])) break; if (selector(a[p[lf]]) <= selector(a[p[rt]])) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, List a, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(a[vstepson]) >= selector(a[val])) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(a[p[rt]]) <= selector(a[vstepson]) || selector(a[p[lf]]) <= selector(a[vstepson])) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, selector, pshift, head); } } /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static int[] CreatePermutationTimSortDescending( this List a, Func selector) { int len = a.Count; var p = new int[len].SetByIndex(i => i); PermutationTimSortDescending(p, a, selector); return p; } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a, Func selector) { PermutationTimSortDescending(p, a, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// public static void PermutationTimSortDescending( this int[] p, List a, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); PermutationBinarySortDescending(p, a, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoListPermDoubleSel(p, a, selector); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseListPermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseListPermDesc(ti); } private static void MergeCollapseListPermDesc(this TimSortInfoListPermDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtListPermDesc(ti, n); else break; } } private static void MergeForceCollapseListPermDesc(this TimSortInfoListPermDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtListPermDesc(ti, n); } } private static void MergeAtListPermDesc(this TimSortInfoListPermDoubleSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoListPermDesc(ti, start1, len1, start2, len2); else MergeHiListPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoListPermDesc(this TimSortInfoListPermDoubleSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[p[idx2]]) > selector(a[t[idx1]])) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = (int)PermutationGallopRightDescending(t, a, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiListPermDesc(this TimSortInfoListPermDoubleSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(a[t[idx2]]) > selector(a[p[idx1]])) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - (int)PermutationGallopLeftDescending(t, a, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, List a, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(a[key]) < selector(a[p[start + hint]])) { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) < selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) >= selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) < selector(a[p[start + m]])) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, List a, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(a[key]) > selector(a[p[start + hint]])) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(a[key]) > selector(a[p[start + hint - ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(a[key]) <= selector(a[p[start + hint + ofs]])) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(a[key]) > selector(a[p[start + m]])) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(a[pivot]) > selector(a[p[mid]])) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, List a, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(a[p[runHi++]]) > selector(a[p[beginIncl]])) { while (runHi < endExcl && selector(a[p[runHi]]) > selector(a[p[runHi - 1]])) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(a[p[runHi]]) <= selector(a[p[runHi - 1]])) runHi++; } return runHi - beginIncl; } #endregion #region Sort/Median for TArray /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedian( this TArray a, long count, Func aget, Action aset, Func cmp, long med) { long last = count - 1; QuickMedian(a, aget, aset, cmp, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedian( this TArray a, Func aget, Action aset, Func cmp, long beginIncl, long endExcl, long med) { QuickMedian(a, aget, aset, cmp, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedian( this TArray a, Func aget, Action aset, Func cmp, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (cmp(aget(a, e1), aget(a, e2)) > 0) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (cmp(aget(a, e4), aget(a, e5)) > 0) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (cmp(aget(a, e1), aget(a, e3)) > 0) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (cmp(aget(a, e2), aget(a, e3)) > 0) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (cmp(aget(a, e1), aget(a, e4)) > 0) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (cmp(aget(a, e3), aget(a, e4)) > 0) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (cmp(aget(a, e2), aget(a, e5)) > 0) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (cmp(aget(a, e2), aget(a, e3)) > 0) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (cmp(aget(a, e4), aget(a, e5)) > 0) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = cmp(p1, p2) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (cmp(ai, p1) < 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (cmp(ai, p2) > 0) { while (cmp(aget(a, hi), p2) > 0 && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (cmp(ai, p1) < 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (cmp(ai, p1) == 0) continue; if (cmp(ai, p1) < 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (cmp(aget(a, hi), p1) > 0) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (cmp(ai, p1) < 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (cmp(aget(a, lo), p1) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (cmp(aget(a, i), p1) == 0) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (cmp(aget(a, hi), p2) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (cmp(aget(a, i), p2) == 0) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && cmp(ai, aget(a, j)) < 0; j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The QuickSort algorithm sorts the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSort( this TArray a, long count, Func aget, Action aset, Func cmp) { long last = count - 1; QuickSort(a, aget, aset, cmp, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSort( this TArray a, Func aget, Action aset, Func cmp, long beginIncl, long endExcl) { QuickSort(a, aget, aset, cmp, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSort( this TArray a, Func aget, Action aset, Func cmp, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (cmp(aget(a, e1), aget(a, e2)) > 0) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (cmp(aget(a, e4), aget(a, e5)) > 0) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (cmp(aget(a, e1), aget(a, e3)) > 0) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (cmp(aget(a, e2), aget(a, e3)) > 0) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (cmp(aget(a, e1), aget(a, e4)) > 0) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (cmp(aget(a, e3), aget(a, e4)) > 0) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (cmp(aget(a, e2), aget(a, e5)) > 0) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (cmp(aget(a, e2), aget(a, e3)) > 0) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (cmp(aget(a, e4), aget(a, e5)) > 0) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = cmp(p1, p2) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (cmp(ai, p1) < 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (cmp(ai, p2) > 0) { while (cmp(aget(a, hi), p2) > 0 && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (cmp(ai, p1) < 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (cmp(ai, p1) == 0) continue; if (cmp(ai, p1) < 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (cmp(aget(a, hi), p1) > 0) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (cmp(ai, p1) < 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSort(a, aget, aset, cmp, l, lo - 2, cl); QuickSort(a, aget, aset, cmp, hi + 2, r, cr); { while (cmp(aget(a, lo), p1) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (cmp(aget(a, i), p1) == 0) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (cmp(aget(a, hi), p2) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (cmp(aget(a, i), p2) == 0) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSort(a, aget, aset, cmp, lo, hi, cm); QuickSort(a, aget, aset, cmp, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSort(a, aget, aset, cmp, l, lo - 2, cl); QuickSort(a, aget, aset, cmp, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSort(a, aget, aset, cmp, l, lo - 2, cl); QuickSort(a, aget, aset, cmp, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSort(a, aget, aset, cmp, l, lo - 2, cl); QuickSort(a, aget, aset, cmp, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSort(a, aget, aset, cmp, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSort(a, aget, aset, cmp, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && cmp(ai, aget(a, j)) < 0; j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSort( this TArray a, Func aget, Action aset, Func cmp, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = aget(a, c + begin); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (cmp(element, aget(a, i2 + begin)) < 0) break; aset(a, i + begin, aget(a, i2 + begin)); i = i2; } aset(a, i + begin, element); } while (count > 1) { --count; var element = aget(a, count + begin); aset(a, count + begin, aget(a, 0 + begin)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && cmp(aget(a, i1 + begin), aget(a, i2 + begin)) < 0) ? i2 : i1; // smaller child if (cmp(aget(a, ni + begin), element) < 0) break; aset(a, i + begin, aget(a, ni + begin)); i = ni; i1 = 2 * i + 1; } aset(a, i + begin, element); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSort( this TArray a, long count, Func aget, Action aset, Func cmp) { for (long c = 1; c < count; c++) { var element = aget(a, c); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (cmp(element, aget(a, i2)) < 0) break; aset(a, i, aget(a, i2)); i = i2; } aset(a, i, element); } while (count > 1) { --count; var element = aget(a, count); aset(a, count, aget(a, 0)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && cmp(aget(a, i1), aget(a, i2)) < 0) ? i2 : i1; // smaller child if (cmp(aget(a, ni), element) < 0) break; aset(a, i, aget(a, ni)); i = ni; i1 = 2 * i + 1; } aset(a, i, element); } } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSort( this TArray a, long count, Func aget, Action aset, Func cmp) { SmoothSortInclusiveRange(a, aget, aset, cmp, 0, count - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSort( this TArray a, Func aget, Action aset, Func cmp, long beginIncl, long endExcl) { SmoothSortInclusiveRange(a, aget, aset, cmp, beginIncl, endExcl - 1); } private static void SmoothSortInclusiveRange( this TArray a, Func aget, Action aset, Func cmp, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortSift(a, aget, aset, cmp, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortTrinkle(a, aget, aset, cmp, pbits, pshift, head, false); else SmoothSortSift(a, aget, aset, cmp, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortTrinkle(a, aget, aset, cmp, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortTrinkle(a, aget, aset, cmp, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortTrinkle(a, aget, aset, cmp, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortSift( this TArray a, Func aget, Action aset, Func cmp, int pshift, long head) { var val = aget(a, head); while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (cmp(val, aget(a, lf)) >= 0 && cmp(val, aget(a, rt)) >= 0) break; if (cmp(aget(a, lf), aget(a, rt)) >= 0) { aset(a, head, aget(a, lf)); head = lf; pshift -= 1; } else { aset(a, head, aget(a, rt)); head = rt; pshift -= 2; } } aset(a, head, val); } private static void SmoothSortTrinkle( this TArray a, Func aget, Action aset, Func cmp, long pbits, int pshift, long head, bool isTrusty) { var val = aget(a, head); while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = aget(a, stepson); if (cmp(vstepson, val) <= 0) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (cmp(aget(a, rt), vstepson) >= 0 || cmp(aget(a, lf), vstepson) >= 0) break; } aset(a, head, vstepson); head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { aset(a, head, val); SmoothSortSift(a, aget, aset, cmp, pshift, head); } } public class TimSortInfoLongGetCmp { public TArray m_a; public long m_count; public Func m_aget; public Action m_aset; public Func m_amake; public Func m_cmp; public long m_minGallop = c_minGallop; public TArray m_tmp; public long m_len; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoLongGetCmp(TArray a, Func aget, Action aset, Func amake, Func cmp, long count) { m_a = a; m_count = count; m_aget = aget; m_aset = aset; m_amake = amake; m_cmp = cmp; m_len = count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength; m_tmp = amake(m_len); int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public TArray EnsureCapacity(long cap) { if (m_len < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_len = c < 0 ? cap : Math.Min(c, m_count >> 1); m_tmp = m_amake(m_len); } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSort( this TArray a, long count, Func aget, Action aset, Func amake, Func cmp) { TimSort(a, aget, aset, amake, cmp, 0, count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSort( this TArray a, Func aget, Action aset, Func amake, Func cmp, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrder(a, aget, aset, cmp, lo, hi); BinarySort(a, aget, aset, cmp, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongGetCmp(a, aget, aset, amake, cmp, count); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrder(a, aget, aset, cmp, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySort(a, aget, aset, cmp, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongCmp(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongCmp(ti); } private static void MergeCollapseLongCmp(this TimSortInfoLongGetCmp ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongCmp(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongCmp(ti, n); else break; } } private static void MergeForceCollapseLongCmp(this TimSortInfoLongGetCmp ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongCmp(ti, n); } } private static void MergeAtLongCmp(this TimSortInfoLongGetCmp ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRight(a, ti.m_aget, ti.m_cmp, ti.m_aget(a, start2), start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeft(a, ti.m_aget, ti.m_cmp, ti.m_aget(a, start1 + len1 - 1), start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongCmp(ti, start1, len1, start2, len2); else MergeHiLongCmp(ti, start1, len1, start2, len2); } private static void MergeLoLongCmp(this TimSortInfoLongGetCmp ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len1); CopyElements(aget, aset, a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) { CopyElements(aget, aset, t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); return; } Func cmp = ti.m_cmp; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (cmp(aget(a, idx2), aget(t, idx1)) < 0) { aset(a, dest++, aget(a, idx2++)); count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { aset(a, dest++, aget(t, idx1++)); count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRight(t, aget, cmp, aget(a, idx2), idx1, len1, 0); if (count1 != 0) { CopyElements(aget, aset, t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) goto breakouter; count2 = GallopLeft(a, aget, cmp, aget(t, idx1), idx2, len2, 0); if (count2 != 0) { CopyElements(aget, aset, a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } aset(a, dest++, aget(t, idx1++)); if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, idx1, a, dest, len1); } private static void MergeHiLongCmp(this TimSortInfoLongGetCmp ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len2); CopyElements(aget, aset, a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) { CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); return; } Func cmp = ti.m_cmp; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (cmp(aget(t, idx2), aget(a, idx1)) < 0) { aset(a, dest--, aget(a, idx1--)); count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { aset(a, dest--, aget(t, idx2--)); count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRight(a, aget, cmp, aget(t, idx2), start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } aset(a, dest--, aget(t, idx2--)); if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeft(t, aget, cmp, aget(a, idx1), 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(aget, aset, t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeft( this TArray a, Func aget, Func cmp, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (cmp(key, aget(a, start + hint)) > 0) { long maxOfs = len - hint; while (ofs < maxOfs && cmp(key, aget(a, start + hint + ofs)) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && cmp(key, aget(a, start + hint - ofs)) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (cmp(key, aget(a, start + m)) > 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRight( this TArray a, Func aget, Func cmp, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (cmp(key, aget(a, start + hint)) < 0) { long maxOfs = hint + 1; while (ofs < maxOfs && cmp(key, aget(a, start + hint - ofs)) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && cmp(key, aget(a, start + hint + ofs)) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (cmp(key, aget(a, start + m)) < 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySort( this TArray a, Func aget, Action aset, Func cmp, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = aget(a, beginUnsorted); long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (cmp(pivot, aget(a, mid)) < 0) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: aset(a, l + 2, aget(a, l + 1)); aset(a, l + 1, aget(a, l)); break; case 1: aset(a, l + 1, aget(a, l)); break; default: CopyElements(aget, aset, a, l, a, l + 1, n); break; } aset(a, l, pivot); } } private static long CountRunAndOrder( this TArray a, Func aget, Action aset, Func cmp, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (cmp(aget(a, runHi++), aget(a, beginIncl)) < 0) { while (runHi < endExcl && cmp(aget(a, runHi), aget(a, runHi - 1)) < 0) runHi++; ReverseRange(aget, aset, a, beginIncl, runHi); } else { while (runHi < endExcl && cmp(aget(a, runHi), aget(a, runHi - 1)) >= 0) runHi++; } return runHi - beginIncl; } [EditorBrowsable(EditorBrowsableState.Never)] public static void ReverseRange( Func aget, Action aset,TArray a, long beginIncl, long endExcl) { endExcl--; // now incorrectly named while (beginIncl < endExcl) { var t = aget(a, beginIncl); aset(a, beginIncl, aget(a, endExcl)); aset(a, endExcl, t); ++beginIncl; --endExcl; } } private static void CopyElements( Func aget, Action aset, TArray src, long start, TArray dst, long dstStart, long count) { for (var end = start + count; start < end; start++, dstStart++) aset(dst, dstStart, aget(src, start)); } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianAscending( this TArray a, long count, Func aget, Action aset, long med) where T : IComparable { long last = count - 1; QuickMedianAscending(a, aget, aset, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianAscending( this TArray a, Func aget, Action aset, long beginIncl, long endExcl, long med) where T : IComparable { QuickMedianAscending(a, aget, aset, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this TArray a, Func aget, Action aset, long l, long r, long countSub1, long med) where T : IComparable { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (aget(a, e1).CompareTo(aget(a, e2)) > 0) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (aget(a, e4).CompareTo(aget(a, e5)) > 0) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (aget(a, e1).CompareTo(aget(a, e3)) > 0) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (aget(a, e2).CompareTo(aget(a, e3)) > 0) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (aget(a, e1).CompareTo(aget(a, e4)) > 0) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (aget(a, e3).CompareTo(aget(a, e4)) > 0) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (aget(a, e2).CompareTo(aget(a, e5)) > 0) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (aget(a, e2).CompareTo(aget(a, e3)) > 0) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (aget(a, e4).CompareTo(aget(a, e5)) > 0) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1.CompareTo(p2) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (ai.CompareTo(p1) < 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (ai.CompareTo(p2) > 0) { while (aget(a, hi).CompareTo(p2) > 0 && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (ai.CompareTo(p1) < 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (ai.CompareTo(p1) == 0) continue; if (ai.CompareTo(p1) < 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (aget(a, hi).CompareTo(p1) > 0) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (ai.CompareTo(p1) < 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (aget(a, lo).CompareTo(p1) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (aget(a, i).CompareTo(p1) == 0) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (aget(a, hi).CompareTo(p2) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (aget(a, i).CompareTo(p2) == 0) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && ai.CompareTo(aget(a, j)) < 0; j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The QuickSort algorithm sorts the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortAscending( this TArray a, long count, Func aget, Action aset) where T : IComparable { long last = count - 1; QuickSortAscending(a, aget, aset, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortAscending( this TArray a, Func aget, Action aset, long beginIncl, long endExcl) where T : IComparable { QuickSortAscending(a, aget, aset, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this TArray a, Func aget, Action aset, long l, long r, long countSub1) where T : IComparable { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (aget(a, e1).CompareTo(aget(a, e2)) > 0) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (aget(a, e4).CompareTo(aget(a, e5)) > 0) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (aget(a, e1).CompareTo(aget(a, e3)) > 0) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (aget(a, e2).CompareTo(aget(a, e3)) > 0) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (aget(a, e1).CompareTo(aget(a, e4)) > 0) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (aget(a, e3).CompareTo(aget(a, e4)) > 0) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (aget(a, e2).CompareTo(aget(a, e5)) > 0) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (aget(a, e2).CompareTo(aget(a, e3)) > 0) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (aget(a, e4).CompareTo(aget(a, e5)) > 0) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1.CompareTo(p2) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (ai.CompareTo(p1) < 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (ai.CompareTo(p2) > 0) { while (aget(a, hi).CompareTo(p2) > 0 && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (ai.CompareTo(p1) < 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (ai.CompareTo(p1) == 0) continue; if (ai.CompareTo(p1) < 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (aget(a, hi).CompareTo(p1) > 0) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (ai.CompareTo(p1) < 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, aget, aset, l, lo - 2, cl); QuickSortAscending(a, aget, aset, hi + 2, r, cr); { while (aget(a, lo).CompareTo(p1) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (aget(a, i).CompareTo(p1) == 0) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (aget(a, hi).CompareTo(p2) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (aget(a, i).CompareTo(p2) == 0) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, aget, aset, lo, hi, cm); QuickSortAscending(a, aget, aset, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, aget, aset, l, lo - 2, cl); QuickSortAscending(a, aget, aset, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, aget, aset, l, lo - 2, cl); QuickSortAscending(a, aget, aset, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, aget, aset, l, lo - 2, cl); QuickSortAscending(a, aget, aset, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, aget, aset, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, aget, aset, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && ai.CompareTo(aget(a, j)) < 0; j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortAscending( this TArray a, Func aget, Action aset, long begin, long end) where T : IComparable { long count = end - begin; for (long c = 1; c < count; c++) { var element = aget(a, c + begin); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element.CompareTo(aget(a, i2 + begin)) < 0) break; aset(a, i + begin, aget(a, i2 + begin)); i = i2; } aset(a, i + begin, element); } while (count > 1) { --count; var element = aget(a, count + begin); aset(a, count + begin, aget(a, 0 + begin)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && aget(a, i1 + begin).CompareTo(aget(a, i2 + begin)) < 0) ? i2 : i1; // smaller child if (aget(a, ni + begin).CompareTo(element) < 0) break; aset(a, i + begin, aget(a, ni + begin)); i = ni; i1 = 2 * i + 1; } aset(a, i + begin, element); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortAscending( this TArray a, long count, Func aget, Action aset) where T : IComparable { for (long c = 1; c < count; c++) { var element = aget(a, c); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element.CompareTo(aget(a, i2)) < 0) break; aset(a, i, aget(a, i2)); i = i2; } aset(a, i, element); } while (count > 1) { --count; var element = aget(a, count); aset(a, count, aget(a, 0)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && aget(a, i1).CompareTo(aget(a, i2)) < 0) ? i2 : i1; // smaller child if (aget(a, ni).CompareTo(element) < 0) break; aset(a, i, aget(a, ni)); i = ni; i1 = 2 * i + 1; } aset(a, i, element); } } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortAscending( this TArray a, long count, Func aget, Action aset) where T : IComparable { SmoothSortAscendingInclusiveRange(a, aget, aset, 0, count - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortAscending( this TArray a, Func aget, Action aset, long beginIncl, long endExcl) where T : IComparable { SmoothSortAscendingInclusiveRange(a, aget, aset, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this TArray a, Func aget, Action aset, long lo, long hi) where T : IComparable { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, aget, aset, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, aget, aset, pbits, pshift, head, false); else SmoothSortAscendingSift(a, aget, aset, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, aget, aset, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, aget, aset, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortAscendingTrinkle(a, aget, aset, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this TArray a, Func aget, Action aset, int pshift, long head) where T : IComparable { var val = aget(a, head); while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (val.CompareTo(aget(a, lf)) >= 0 && val.CompareTo(aget(a, rt)) >= 0) break; if (aget(a, lf).CompareTo(aget(a, rt)) >= 0) { aset(a, head, aget(a, lf)); head = lf; pshift -= 1; } else { aset(a, head, aget(a, rt)); head = rt; pshift -= 2; } } aset(a, head, val); } private static void SmoothSortAscendingTrinkle( this TArray a, Func aget, Action aset, long pbits, int pshift, long head, bool isTrusty) where T : IComparable { var val = aget(a, head); while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = aget(a, stepson); if (vstepson.CompareTo(val) <= 0) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (aget(a, rt).CompareTo(vstepson) >= 0 || aget(a, lf).CompareTo(vstepson) >= 0) break; } aset(a, head, vstepson); head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { aset(a, head, val); SmoothSortAscendingSift(a, aget, aset, pshift, head); } } public class TimSortInfoLongGet where T : IComparable { public TArray m_a; public long m_count; public Func m_aget; public Action m_aset; public Func m_amake; public long m_minGallop = c_minGallop; public TArray m_tmp; public long m_len; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoLongGet(TArray a, Func aget, Action aset, Func amake, long count) { m_a = a; m_count = count; m_aget = aget; m_aset = aset; m_amake = amake; m_len = count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength; m_tmp = amake(m_len); int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public TArray EnsureCapacity(long cap) { if (m_len < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_len = c < 0 ? cap : Math.Min(c, m_count >> 1); m_tmp = m_amake(m_len); } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortAscending( this TArray a, long count, Func aget, Action aset, Func amake) where T : IComparable { TimSortAscending(a, aget, aset, amake, 0, count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortAscending( this TArray a, Func aget, Action aset, Func amake, long lo, long hi) where T : IComparable { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, aget, aset, lo, hi); BinarySortAscending(a, aget, aset, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongGet(a, aget, aset, amake, count); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderAscending(a, aget, aset, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortAscending(a, aget, aset, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongAsc(ti); } private static void MergeCollapseLongAsc(this TimSortInfoLongGet ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongAsc(ti, n); else break; } } private static void MergeForceCollapseLongAsc(this TimSortInfoLongGet ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } } private static void MergeAtLongAsc(this TimSortInfoLongGet ti, int i) where T : IComparable { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightAscending(a, ti.m_aget, ti.m_aget(a, start2), start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_aget, ti.m_aget(a, start1 + len1 - 1), start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongAsc(ti, start1, len1, start2, len2); else MergeHiLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoLongAsc(this TimSortInfoLongGet ti, long start1, long len1, long start2, long len2) where T : IComparable { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len1); CopyElements(aget, aset, a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) { CopyElements(aget, aset, t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (aget(a, idx2).CompareTo(aget(t, idx1)) < 0) { aset(a, dest++, aget(a, idx2++)); count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { aset(a, dest++, aget(t, idx1++)); count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightAscending(t, aget, aget(a, idx2), idx1, len1, 0); if (count1 != 0) { CopyElements(aget, aset, t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, aget, aget(t, idx1), idx2, len2, 0); if (count2 != 0) { CopyElements(aget, aset, a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } aset(a, dest++, aget(t, idx1++)); if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, idx1, a, dest, len1); } private static void MergeHiLongAsc(this TimSortInfoLongGet ti, long start1, long len1, long start2, long len2) where T : IComparable { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len2); CopyElements(aget, aset, a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) { CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (aget(t, idx2).CompareTo(aget(a, idx1)) < 0) { aset(a, dest--, aget(a, idx1--)); count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { aset(a, dest--, aget(t, idx2--)); count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, aget, aget(t, idx2), start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } aset(a, dest--, aget(t, idx2--)); if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftAscending(t, aget, aget(a, idx1), 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(aget, aset, t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftAscending( this TArray a, Func aget, T key, long start, long len, long hint) where T : IComparable { long lastOfs = 0, ofs = 1; if (key.CompareTo(aget(a, start + hint)) > 0) { long maxOfs = len - hint; while (ofs < maxOfs && key.CompareTo(aget(a, start + hint + ofs)) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && key.CompareTo(aget(a, start + hint - ofs)) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key.CompareTo(aget(a, start + m)) > 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightAscending( this TArray a, Func aget, T key, long start, long len, long hint) where T : IComparable { long ofs = 1, lastOfs = 0; if (key.CompareTo(aget(a, start + hint)) < 0) { long maxOfs = hint + 1; while (ofs < maxOfs && key.CompareTo(aget(a, start + hint - ofs)) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && key.CompareTo(aget(a, start + hint + ofs)) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key.CompareTo(aget(a, start + m)) < 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this TArray a, Func aget, Action aset, long beginIncl, long endExcl, long beginUnsorted) where T : IComparable { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = aget(a, beginUnsorted); long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (pivot.CompareTo(aget(a, mid)) < 0) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: aset(a, l + 2, aget(a, l + 1)); aset(a, l + 1, aget(a, l)); break; case 1: aset(a, l + 1, aget(a, l)); break; default: CopyElements(aget, aset, a, l, a, l + 1, n); break; } aset(a, l, pivot); } } private static long CountRunAndOrderAscending( this TArray a, Func aget, Action aset, long beginIncl, long endExcl) where T : IComparable { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (aget(a, runHi++).CompareTo(aget(a, beginIncl)) < 0) { while (runHi < endExcl && aget(a, runHi).CompareTo(aget(a, runHi - 1)) < 0) runHi++; ReverseRange(aget, aset, a, beginIncl, runHi); } else { while (runHi < endExcl && aget(a, runHi).CompareTo(aget(a, runHi - 1)) >= 0) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianDescending( this TArray a, long count, Func aget, Action aset, long med) where T : IComparable { long last = count - 1; QuickMedianDescending(a, aget, aset, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianDescending( this TArray a, Func aget, Action aset, long beginIncl, long endExcl, long med) where T : IComparable { QuickMedianDescending(a, aget, aset, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this TArray a, Func aget, Action aset, long l, long r, long countSub1, long med) where T : IComparable { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (aget(a, e1).CompareTo(aget(a, e2)) < 0) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (aget(a, e4).CompareTo(aget(a, e5)) < 0) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (aget(a, e1).CompareTo(aget(a, e3)) < 0) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (aget(a, e2).CompareTo(aget(a, e3)) < 0) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (aget(a, e1).CompareTo(aget(a, e4)) < 0) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (aget(a, e3).CompareTo(aget(a, e4)) < 0) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (aget(a, e2).CompareTo(aget(a, e5)) < 0) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (aget(a, e2).CompareTo(aget(a, e3)) < 0) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (aget(a, e4).CompareTo(aget(a, e5)) < 0) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1.CompareTo(p2) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (ai.CompareTo(p1) > 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (ai.CompareTo(p2) < 0) { while (aget(a, hi).CompareTo(p2) < 0 && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (ai.CompareTo(p1) > 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (ai.CompareTo(p1) == 0) continue; if (ai.CompareTo(p1) > 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (aget(a, hi).CompareTo(p1) < 0) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (ai.CompareTo(p1) > 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (aget(a, lo).CompareTo(p1) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (aget(a, i).CompareTo(p1) == 0) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (aget(a, hi).CompareTo(p2) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (aget(a, i).CompareTo(p2) == 0) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && ai.CompareTo(aget(a, j)) > 0; j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The QuickSort algorithm sorts the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortDescending( this TArray a, long count, Func aget, Action aset) where T : IComparable { long last = count - 1; QuickSortDescending(a, aget, aset, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortDescending( this TArray a, Func aget, Action aset, long beginIncl, long endExcl) where T : IComparable { QuickSortDescending(a, aget, aset, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this TArray a, Func aget, Action aset, long l, long r, long countSub1) where T : IComparable { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (aget(a, e1).CompareTo(aget(a, e2)) < 0) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (aget(a, e4).CompareTo(aget(a, e5)) < 0) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (aget(a, e1).CompareTo(aget(a, e3)) < 0) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (aget(a, e2).CompareTo(aget(a, e3)) < 0) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (aget(a, e1).CompareTo(aget(a, e4)) < 0) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (aget(a, e3).CompareTo(aget(a, e4)) < 0) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (aget(a, e2).CompareTo(aget(a, e5)) < 0) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (aget(a, e2).CompareTo(aget(a, e3)) < 0) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (aget(a, e4).CompareTo(aget(a, e5)) < 0) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = p1.CompareTo(p2) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (ai.CompareTo(p1) > 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (ai.CompareTo(p2) < 0) { while (aget(a, hi).CompareTo(p2) < 0 && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (ai.CompareTo(p1) > 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (ai.CompareTo(p1) == 0) continue; if (ai.CompareTo(p1) > 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (aget(a, hi).CompareTo(p1) < 0) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (ai.CompareTo(p1) > 0) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, aget, aset, l, lo - 2, cl); QuickSortDescending(a, aget, aset, hi + 2, r, cr); { while (aget(a, lo).CompareTo(p1) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (aget(a, i).CompareTo(p1) == 0) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (aget(a, hi).CompareTo(p2) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (aget(a, i).CompareTo(p2) == 0) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, aget, aset, lo, hi, cm); QuickSortDescending(a, aget, aset, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, aget, aset, l, lo - 2, cl); QuickSortDescending(a, aget, aset, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, aget, aset, l, lo - 2, cl); QuickSortDescending(a, aget, aset, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, aget, aset, l, lo - 2, cl); QuickSortDescending(a, aget, aset, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, aget, aset, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, aget, aset, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && ai.CompareTo(aget(a, j)) > 0; j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortDescending( this TArray a, Func aget, Action aset, long begin, long end) where T : IComparable { long count = end - begin; for (long c = 1; c < count; c++) { var element = aget(a, c + begin); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element.CompareTo(aget(a, i2 + begin)) > 0) break; aset(a, i + begin, aget(a, i2 + begin)); i = i2; } aset(a, i + begin, element); } while (count > 1) { --count; var element = aget(a, count + begin); aset(a, count + begin, aget(a, 0 + begin)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && aget(a, i1 + begin).CompareTo(aget(a, i2 + begin)) > 0) ? i2 : i1; // smaller child if (aget(a, ni + begin).CompareTo(element) > 0) break; aset(a, i + begin, aget(a, ni + begin)); i = ni; i1 = 2 * i + 1; } aset(a, i + begin, element); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortDescending( this TArray a, long count, Func aget, Action aset) where T : IComparable { for (long c = 1; c < count; c++) { var element = aget(a, c); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (element.CompareTo(aget(a, i2)) > 0) break; aset(a, i, aget(a, i2)); i = i2; } aset(a, i, element); } while (count > 1) { --count; var element = aget(a, count); aset(a, count, aget(a, 0)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && aget(a, i1).CompareTo(aget(a, i2)) > 0) ? i2 : i1; // smaller child if (aget(a, ni).CompareTo(element) > 0) break; aset(a, i, aget(a, ni)); i = ni; i1 = 2 * i + 1; } aset(a, i, element); } } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortDescending( this TArray a, long count, Func aget, Action aset) where T : IComparable { SmoothSortDescendingInclusiveRange(a, aget, aset, 0, count - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortDescending( this TArray a, Func aget, Action aset, long beginIncl, long endExcl) where T : IComparable { SmoothSortDescendingInclusiveRange(a, aget, aset, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this TArray a, Func aget, Action aset, long lo, long hi) where T : IComparable { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, aget, aset, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, aget, aset, pbits, pshift, head, false); else SmoothSortDescendingSift(a, aget, aset, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, aget, aset, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, aget, aset, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortDescendingTrinkle(a, aget, aset, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this TArray a, Func aget, Action aset, int pshift, long head) where T : IComparable { var val = aget(a, head); while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (val.CompareTo(aget(a, lf)) <= 0 && val.CompareTo(aget(a, rt)) <= 0) break; if (aget(a, lf).CompareTo(aget(a, rt)) <= 0) { aset(a, head, aget(a, lf)); head = lf; pshift -= 1; } else { aset(a, head, aget(a, rt)); head = rt; pshift -= 2; } } aset(a, head, val); } private static void SmoothSortDescendingTrinkle( this TArray a, Func aget, Action aset, long pbits, int pshift, long head, bool isTrusty) where T : IComparable { var val = aget(a, head); while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = aget(a, stepson); if (vstepson.CompareTo(val) >= 0) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (aget(a, rt).CompareTo(vstepson) <= 0 || aget(a, lf).CompareTo(vstepson) <= 0) break; } aset(a, head, vstepson); head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { aset(a, head, val); SmoothSortDescendingSift(a, aget, aset, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortDescending( this TArray a, long count, Func aget, Action aset, Func amake) where T : IComparable { TimSortDescending(a, aget, aset, amake, 0, count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortDescending( this TArray a, Func aget, Action aset, Func amake, long lo, long hi) where T : IComparable { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, aget, aset, lo, hi); BinarySortDescending(a, aget, aset, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongGet(a, aget, aset, amake, count); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderDescending(a, aget, aset, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortDescending(a, aget, aset, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongDesc(ti); } private static void MergeCollapseLongDesc(this TimSortInfoLongGet ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongDesc(ti, n); else break; } } private static void MergeForceCollapseLongDesc(this TimSortInfoLongGet ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } } private static void MergeAtLongDesc(this TimSortInfoLongGet ti, int i) where T : IComparable { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightDescending(a, ti.m_aget, ti.m_aget(a, start2), start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_aget, ti.m_aget(a, start1 + len1 - 1), start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongDesc(ti, start1, len1, start2, len2); else MergeHiLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoLongDesc(this TimSortInfoLongGet ti, long start1, long len1, long start2, long len2) where T : IComparable { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len1); CopyElements(aget, aset, a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) { CopyElements(aget, aset, t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (aget(a, idx2).CompareTo(aget(t, idx1)) > 0) { aset(a, dest++, aget(a, idx2++)); count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { aset(a, dest++, aget(t, idx1++)); count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightDescending(t, aget, aget(a, idx2), idx1, len1, 0); if (count1 != 0) { CopyElements(aget, aset, t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, aget, aget(t, idx1), idx2, len2, 0); if (count2 != 0) { CopyElements(aget, aset, a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } aset(a, dest++, aget(t, idx1++)); if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, idx1, a, dest, len1); } private static void MergeHiLongDesc(this TimSortInfoLongGet ti, long start1, long len1, long start2, long len2) where T : IComparable { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len2); CopyElements(aget, aset, a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) { CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (aget(t, idx2).CompareTo(aget(a, idx1)) > 0) { aset(a, dest--, aget(a, idx1--)); count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { aset(a, dest--, aget(t, idx2--)); count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, aget, aget(t, idx2), start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } aset(a, dest--, aget(t, idx2--)); if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftDescending(t, aget, aget(a, idx1), 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(aget, aset, t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftDescending( this TArray a, Func aget, T key, long start, long len, long hint) where T : IComparable { long lastOfs = 0, ofs = 1; if (key.CompareTo(aget(a, start + hint)) < 0) { long maxOfs = len - hint; while (ofs < maxOfs && key.CompareTo(aget(a, start + hint + ofs)) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && key.CompareTo(aget(a, start + hint - ofs)) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key.CompareTo(aget(a, start + m)) < 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightDescending( this TArray a, Func aget, T key, long start, long len, long hint) where T : IComparable { long ofs = 1, lastOfs = 0; if (key.CompareTo(aget(a, start + hint)) > 0) { long maxOfs = hint + 1; while (ofs < maxOfs && key.CompareTo(aget(a, start + hint - ofs)) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && key.CompareTo(aget(a, start + hint + ofs)) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (key.CompareTo(aget(a, start + m)) > 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this TArray a, Func aget, Action aset, long beginIncl, long endExcl, long beginUnsorted) where T : IComparable { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = aget(a, beginUnsorted); long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (pivot.CompareTo(aget(a, mid)) > 0) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: aset(a, l + 2, aget(a, l + 1)); aset(a, l + 1, aget(a, l)); break; case 1: aset(a, l + 1, aget(a, l)); break; default: CopyElements(aget, aset, a, l, a, l + 1, n); break; } aset(a, l, pivot); } } private static long CountRunAndOrderDescending( this TArray a, Func aget, Action aset, long beginIncl, long endExcl) where T : IComparable { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (aget(a, runHi++).CompareTo(aget(a, beginIncl)) > 0) { while (runHi < endExcl && aget(a, runHi).CompareTo(aget(a, runHi - 1)) > 0) runHi++; ReverseRange(aget, aset, a, beginIncl, runHi); } else { while (runHi < endExcl && aget(a, runHi).CompareTo(aget(a, runHi - 1)) <= 0) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianAscending( this TArray a, long count, Func aget, Action aset, Func selector, long med) { long last = count - 1; QuickMedianAscending(a, aget, aset, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl, long med) { QuickMedianAscending(a, aget, aset, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this TArray a, Func aget, Action aset, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a, e1)) > selector(aget(a, e2))) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (selector(aget(a, e4)) > selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e1)) > selector(aget(a, e3))) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e2)) > selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e1)) > selector(aget(a, e4))) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e3)) > selector(aget(a, e4))) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e2)) > selector(aget(a, e5))) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e2)) > selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e4)) > selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (selector(ai) > selector(p2)) { while (selector(aget(a, hi)) > selector(p2) && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (selector(aget(a, hi)) > selector(p1)) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a, lo)) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a, i)) == selector(p1)) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (selector(aget(a, hi)) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a, i)) == selector(p2)) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && selector(ai) < selector(aget(a, j)); j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The QuickSort algorithm sorts the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortAscending( this TArray a, long count, Func aget, Action aset, Func selector) { long last = count - 1; QuickSortAscending(a, aget, aset, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { QuickSortAscending(a, aget, aset, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this TArray a, Func aget, Action aset, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a, e1)) > selector(aget(a, e2))) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (selector(aget(a, e4)) > selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e1)) > selector(aget(a, e3))) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e2)) > selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e1)) > selector(aget(a, e4))) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e3)) > selector(aget(a, e4))) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e2)) > selector(aget(a, e5))) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e2)) > selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e4)) > selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (selector(ai) > selector(p2)) { while (selector(aget(a, hi)) > selector(p2) && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (selector(aget(a, hi)) > selector(p1)) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); { while (selector(aget(a, lo)) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a, i)) == selector(p1)) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (selector(aget(a, hi)) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a, i)) == selector(p2)) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, aget, aset, selector, lo, hi, cm); QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); QuickSortAscending(a, aget, aset, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && selector(ai) < selector(aget(a, j)); j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortAscending( this TArray a, Func aget, Action aset, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = aget(a, c + begin); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) < selector(aget(a, i2 + begin))) break; aset(a, i + begin, aget(a, i2 + begin)); i = i2; } aset(a, i + begin, element); } while (count > 1) { --count; var element = aget(a, count + begin); aset(a, count + begin, aget(a, 0 + begin)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a, i1 + begin)) < selector(aget(a, i2 + begin))) ? i2 : i1; // smaller child if (selector(aget(a, ni + begin)) < selector(element)) break; aset(a, i + begin, aget(a, ni + begin)); i = ni; i1 = 2 * i + 1; } aset(a, i + begin, element); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortAscending( this TArray a, long count, Func aget, Action aset, Func selector) { for (long c = 1; c < count; c++) { var element = aget(a, c); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) < selector(aget(a, i2))) break; aset(a, i, aget(a, i2)); i = i2; } aset(a, i, element); } while (count > 1) { --count; var element = aget(a, count); aset(a, count, aget(a, 0)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a, i1)) < selector(aget(a, i2))) ? i2 : i1; // smaller child if (selector(aget(a, ni)) < selector(element)) break; aset(a, i, aget(a, ni)); i = ni; i1 = 2 * i + 1; } aset(a, i, element); } } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortAscending( this TArray a, long count, Func aget, Action aset, Func selector) { SmoothSortAscendingInclusiveRange(a, aget, aset, selector, 0, count - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { SmoothSortAscendingInclusiveRange(a, aget, aset, selector, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this TArray a, Func aget, Action aset, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, aget, aset, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, aget, aset, selector, pbits, pshift, head, false); else SmoothSortAscendingSift(a, aget, aset, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, aget, aset, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, aget, aset, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortAscendingTrinkle(a, aget, aset, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this TArray a, Func aget, Action aset, Func selector, int pshift, long head) { var val = aget(a, head); while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(val) >= selector(aget(a, lf)) && selector(val) >= selector(aget(a, rt))) break; if (selector(aget(a, lf)) >= selector(aget(a, rt))) { aset(a, head, aget(a, lf)); head = lf; pshift -= 1; } else { aset(a, head, aget(a, rt)); head = rt; pshift -= 2; } } aset(a, head, val); } private static void SmoothSortAscendingTrinkle( this TArray a, Func aget, Action aset, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = aget(a, head); while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = aget(a, stepson); if (selector(vstepson) <= selector(val)) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a, rt)) >= selector(vstepson) || selector(aget(a, lf)) >= selector(vstepson)) break; } aset(a, head, vstepson); head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { aset(a, head, val); SmoothSortAscendingSift(a, aget, aset, selector, pshift, head); } } public class TimSortInfoLongGetIntSel { public TArray m_a; public long m_count; public Func m_aget; public Action m_aset; public Func m_amake; public Func m_sel; public long m_minGallop = c_minGallop; public TArray m_tmp; public long m_len; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoLongGetIntSel(TArray a, Func aget, Action aset, Func amake, Func selector, long count) { m_a = a; m_count = count; m_aget = aget; m_aset = aset; m_amake = amake; m_sel = selector; m_len = count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength; m_tmp = amake(m_len); int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public TArray EnsureCapacity(long cap) { if (m_len < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_len = c < 0 ? cap : Math.Min(c, m_count >> 1); m_tmp = m_amake(m_len); } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortAscending( this TArray a, long count, Func aget, Action aset, Func amake, Func selector) { TimSortAscending(a, aget, aset, amake, selector, 0, count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortAscending( this TArray a, Func aget, Action aset, Func amake, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, aget, aset, selector, lo, hi); BinarySortAscending(a, aget, aset, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongGetIntSel(a, aget, aset, amake, selector, count); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderAscending(a, aget, aset, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortAscending(a, aget, aset, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongAsc(ti); } private static void MergeCollapseLongAsc(this TimSortInfoLongGetIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongAsc(ti, n); else break; } } private static void MergeForceCollapseLongAsc(this TimSortInfoLongGetIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } } private static void MergeAtLongAsc(this TimSortInfoLongGetIntSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightAscending(a, ti.m_aget, ti.m_sel, ti.m_aget(a, start2), start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_aget, ti.m_sel, ti.m_aget(a, start1 + len1 - 1), start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongAsc(ti, start1, len1, start2, len2); else MergeHiLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoLongAsc(this TimSortInfoLongGetIntSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len1); CopyElements(aget, aset, a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) { CopyElements(aget, aset, t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a, idx2)) < selector(aget(t, idx1))) { aset(a, dest++, aget(a, idx2++)); count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { aset(a, dest++, aget(t, idx1++)); count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightAscending(t, aget, selector, aget(a, idx2), idx1, len1, 0); if (count1 != 0) { CopyElements(aget, aset, t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, aget, selector, aget(t, idx1), idx2, len2, 0); if (count2 != 0) { CopyElements(aget, aset, a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } aset(a, dest++, aget(t, idx1++)); if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, idx1, a, dest, len1); } private static void MergeHiLongAsc(this TimSortInfoLongGetIntSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len2); CopyElements(aget, aset, a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) { CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(t, idx2)) < selector(aget(a, idx1))) { aset(a, dest--, aget(a, idx1--)); count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { aset(a, dest--, aget(t, idx2--)); count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, aget, selector, aget(t, idx2), start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } aset(a, dest--, aget(t, idx2--)); if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftAscending(t, aget, selector, aget(a, idx1), 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(aget, aset, t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftAscending( this TArray a, Func aget, Func selector, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(key) > selector(aget(a, start + hint))) { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) > selector(aget(a, start + hint + ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) <= selector(aget(a, start + hint - ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(aget(a, start + m))) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightAscending( this TArray a, Func aget, Func selector, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(key) < selector(aget(a, start + hint))) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) < selector(aget(a, start + hint - ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) >= selector(aget(a, start + hint + ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(aget(a, start + m))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = aget(a, beginUnsorted); long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(pivot) < selector(aget(a, mid))) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: aset(a, l + 2, aget(a, l + 1)); aset(a, l + 1, aget(a, l)); break; case 1: aset(a, l + 1, aget(a, l)); break; default: CopyElements(aget, aset, a, l, a, l + 1, n); break; } aset(a, l, pivot); } } private static long CountRunAndOrderAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a, runHi++)) < selector(aget(a, beginIncl))) { while (runHi < endExcl && selector(aget(a, runHi)) < selector(aget(a, runHi - 1))) runHi++; ReverseRange(aget, aset, a, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a, runHi)) >= selector(aget(a, runHi - 1))) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianDescending( this TArray a, long count, Func aget, Action aset, Func selector, long med) { long last = count - 1; QuickMedianDescending(a, aget, aset, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl, long med) { QuickMedianDescending(a, aget, aset, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this TArray a, Func aget, Action aset, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a, e1)) < selector(aget(a, e2))) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (selector(aget(a, e4)) < selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e1)) < selector(aget(a, e3))) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e2)) < selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e1)) < selector(aget(a, e4))) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e3)) < selector(aget(a, e4))) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e2)) < selector(aget(a, e5))) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e2)) < selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e4)) < selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (selector(ai) < selector(p2)) { while (selector(aget(a, hi)) < selector(p2) && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (selector(aget(a, hi)) < selector(p1)) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a, lo)) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a, i)) == selector(p1)) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (selector(aget(a, hi)) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a, i)) == selector(p2)) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && selector(ai) > selector(aget(a, j)); j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The QuickSort algorithm sorts the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortDescending( this TArray a, long count, Func aget, Action aset, Func selector) { long last = count - 1; QuickSortDescending(a, aget, aset, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { QuickSortDescending(a, aget, aset, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this TArray a, Func aget, Action aset, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a, e1)) < selector(aget(a, e2))) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (selector(aget(a, e4)) < selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e1)) < selector(aget(a, e3))) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e2)) < selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e1)) < selector(aget(a, e4))) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e3)) < selector(aget(a, e4))) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e2)) < selector(aget(a, e5))) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e2)) < selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e4)) < selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (selector(ai) < selector(p2)) { while (selector(aget(a, hi)) < selector(p2) && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (selector(aget(a, hi)) < selector(p1)) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); { while (selector(aget(a, lo)) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a, i)) == selector(p1)) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (selector(aget(a, hi)) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a, i)) == selector(p2)) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, aget, aset, selector, lo, hi, cm); QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); QuickSortDescending(a, aget, aset, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && selector(ai) > selector(aget(a, j)); j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortDescending( this TArray a, Func aget, Action aset, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = aget(a, c + begin); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) > selector(aget(a, i2 + begin))) break; aset(a, i + begin, aget(a, i2 + begin)); i = i2; } aset(a, i + begin, element); } while (count > 1) { --count; var element = aget(a, count + begin); aset(a, count + begin, aget(a, 0 + begin)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a, i1 + begin)) > selector(aget(a, i2 + begin))) ? i2 : i1; // smaller child if (selector(aget(a, ni + begin)) > selector(element)) break; aset(a, i + begin, aget(a, ni + begin)); i = ni; i1 = 2 * i + 1; } aset(a, i + begin, element); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortDescending( this TArray a, long count, Func aget, Action aset, Func selector) { for (long c = 1; c < count; c++) { var element = aget(a, c); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) > selector(aget(a, i2))) break; aset(a, i, aget(a, i2)); i = i2; } aset(a, i, element); } while (count > 1) { --count; var element = aget(a, count); aset(a, count, aget(a, 0)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a, i1)) > selector(aget(a, i2))) ? i2 : i1; // smaller child if (selector(aget(a, ni)) > selector(element)) break; aset(a, i, aget(a, ni)); i = ni; i1 = 2 * i + 1; } aset(a, i, element); } } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortDescending( this TArray a, long count, Func aget, Action aset, Func selector) { SmoothSortDescendingInclusiveRange(a, aget, aset, selector, 0, count - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { SmoothSortDescendingInclusiveRange(a, aget, aset, selector, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this TArray a, Func aget, Action aset, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, aget, aset, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, aget, aset, selector, pbits, pshift, head, false); else SmoothSortDescendingSift(a, aget, aset, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, aget, aset, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, aget, aset, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortDescendingTrinkle(a, aget, aset, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this TArray a, Func aget, Action aset, Func selector, int pshift, long head) { var val = aget(a, head); while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(val) <= selector(aget(a, lf)) && selector(val) <= selector(aget(a, rt))) break; if (selector(aget(a, lf)) <= selector(aget(a, rt))) { aset(a, head, aget(a, lf)); head = lf; pshift -= 1; } else { aset(a, head, aget(a, rt)); head = rt; pshift -= 2; } } aset(a, head, val); } private static void SmoothSortDescendingTrinkle( this TArray a, Func aget, Action aset, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = aget(a, head); while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = aget(a, stepson); if (selector(vstepson) >= selector(val)) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a, rt)) <= selector(vstepson) || selector(aget(a, lf)) <= selector(vstepson)) break; } aset(a, head, vstepson); head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { aset(a, head, val); SmoothSortDescendingSift(a, aget, aset, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortDescending( this TArray a, long count, Func aget, Action aset, Func amake, Func selector) { TimSortDescending(a, aget, aset, amake, selector, 0, count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortDescending( this TArray a, Func aget, Action aset, Func amake, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, aget, aset, selector, lo, hi); BinarySortDescending(a, aget, aset, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongGetIntSel(a, aget, aset, amake, selector, count); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderDescending(a, aget, aset, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortDescending(a, aget, aset, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongDesc(ti); } private static void MergeCollapseLongDesc(this TimSortInfoLongGetIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongDesc(ti, n); else break; } } private static void MergeForceCollapseLongDesc(this TimSortInfoLongGetIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } } private static void MergeAtLongDesc(this TimSortInfoLongGetIntSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightDescending(a, ti.m_aget, ti.m_sel, ti.m_aget(a, start2), start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_aget, ti.m_sel, ti.m_aget(a, start1 + len1 - 1), start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongDesc(ti, start1, len1, start2, len2); else MergeHiLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoLongDesc(this TimSortInfoLongGetIntSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len1); CopyElements(aget, aset, a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) { CopyElements(aget, aset, t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a, idx2)) > selector(aget(t, idx1))) { aset(a, dest++, aget(a, idx2++)); count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { aset(a, dest++, aget(t, idx1++)); count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightDescending(t, aget, selector, aget(a, idx2), idx1, len1, 0); if (count1 != 0) { CopyElements(aget, aset, t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, aget, selector, aget(t, idx1), idx2, len2, 0); if (count2 != 0) { CopyElements(aget, aset, a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } aset(a, dest++, aget(t, idx1++)); if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, idx1, a, dest, len1); } private static void MergeHiLongDesc(this TimSortInfoLongGetIntSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len2); CopyElements(aget, aset, a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) { CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(t, idx2)) > selector(aget(a, idx1))) { aset(a, dest--, aget(a, idx1--)); count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { aset(a, dest--, aget(t, idx2--)); count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, aget, selector, aget(t, idx2), start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } aset(a, dest--, aget(t, idx2--)); if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftDescending(t, aget, selector, aget(a, idx1), 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(aget, aset, t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftDescending( this TArray a, Func aget, Func selector, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(key) < selector(aget(a, start + hint))) { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) < selector(aget(a, start + hint + ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) >= selector(aget(a, start + hint - ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(aget(a, start + m))) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightDescending( this TArray a, Func aget, Func selector, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(key) > selector(aget(a, start + hint))) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) > selector(aget(a, start + hint - ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) <= selector(aget(a, start + hint + ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(aget(a, start + m))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = aget(a, beginUnsorted); long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(pivot) > selector(aget(a, mid))) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: aset(a, l + 2, aget(a, l + 1)); aset(a, l + 1, aget(a, l)); break; case 1: aset(a, l + 1, aget(a, l)); break; default: CopyElements(aget, aset, a, l, a, l + 1, n); break; } aset(a, l, pivot); } } private static long CountRunAndOrderDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a, runHi++)) > selector(aget(a, beginIncl))) { while (runHi < endExcl && selector(aget(a, runHi)) > selector(aget(a, runHi - 1))) runHi++; ReverseRange(aget, aset, a, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a, runHi)) <= selector(aget(a, runHi - 1))) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianAscending( this TArray a, long count, Func aget, Action aset, Func selector, long med) { long last = count - 1; QuickMedianAscending(a, aget, aset, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl, long med) { QuickMedianAscending(a, aget, aset, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this TArray a, Func aget, Action aset, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a, e1)) > selector(aget(a, e2))) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (selector(aget(a, e4)) > selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e1)) > selector(aget(a, e3))) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e2)) > selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e1)) > selector(aget(a, e4))) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e3)) > selector(aget(a, e4))) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e2)) > selector(aget(a, e5))) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e2)) > selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e4)) > selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (selector(ai) > selector(p2)) { while (selector(aget(a, hi)) > selector(p2) && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (selector(aget(a, hi)) > selector(p1)) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a, lo)) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a, i)) == selector(p1)) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (selector(aget(a, hi)) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a, i)) == selector(p2)) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && selector(ai) < selector(aget(a, j)); j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The QuickSort algorithm sorts the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortAscending( this TArray a, long count, Func aget, Action aset, Func selector) { long last = count - 1; QuickSortAscending(a, aget, aset, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { QuickSortAscending(a, aget, aset, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this TArray a, Func aget, Action aset, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a, e1)) > selector(aget(a, e2))) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (selector(aget(a, e4)) > selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e1)) > selector(aget(a, e3))) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e2)) > selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e1)) > selector(aget(a, e4))) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e3)) > selector(aget(a, e4))) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e2)) > selector(aget(a, e5))) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e2)) > selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e4)) > selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (selector(ai) > selector(p2)) { while (selector(aget(a, hi)) > selector(p2) && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (selector(aget(a, hi)) > selector(p1)) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); { while (selector(aget(a, lo)) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a, i)) == selector(p1)) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (selector(aget(a, hi)) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a, i)) == selector(p2)) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, aget, aset, selector, lo, hi, cm); QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); QuickSortAscending(a, aget, aset, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && selector(ai) < selector(aget(a, j)); j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortAscending( this TArray a, Func aget, Action aset, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = aget(a, c + begin); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) < selector(aget(a, i2 + begin))) break; aset(a, i + begin, aget(a, i2 + begin)); i = i2; } aset(a, i + begin, element); } while (count > 1) { --count; var element = aget(a, count + begin); aset(a, count + begin, aget(a, 0 + begin)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a, i1 + begin)) < selector(aget(a, i2 + begin))) ? i2 : i1; // smaller child if (selector(aget(a, ni + begin)) < selector(element)) break; aset(a, i + begin, aget(a, ni + begin)); i = ni; i1 = 2 * i + 1; } aset(a, i + begin, element); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortAscending( this TArray a, long count, Func aget, Action aset, Func selector) { for (long c = 1; c < count; c++) { var element = aget(a, c); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) < selector(aget(a, i2))) break; aset(a, i, aget(a, i2)); i = i2; } aset(a, i, element); } while (count > 1) { --count; var element = aget(a, count); aset(a, count, aget(a, 0)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a, i1)) < selector(aget(a, i2))) ? i2 : i1; // smaller child if (selector(aget(a, ni)) < selector(element)) break; aset(a, i, aget(a, ni)); i = ni; i1 = 2 * i + 1; } aset(a, i, element); } } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortAscending( this TArray a, long count, Func aget, Action aset, Func selector) { SmoothSortAscendingInclusiveRange(a, aget, aset, selector, 0, count - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { SmoothSortAscendingInclusiveRange(a, aget, aset, selector, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this TArray a, Func aget, Action aset, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, aget, aset, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, aget, aset, selector, pbits, pshift, head, false); else SmoothSortAscendingSift(a, aget, aset, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, aget, aset, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, aget, aset, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortAscendingTrinkle(a, aget, aset, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this TArray a, Func aget, Action aset, Func selector, int pshift, long head) { var val = aget(a, head); while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(val) >= selector(aget(a, lf)) && selector(val) >= selector(aget(a, rt))) break; if (selector(aget(a, lf)) >= selector(aget(a, rt))) { aset(a, head, aget(a, lf)); head = lf; pshift -= 1; } else { aset(a, head, aget(a, rt)); head = rt; pshift -= 2; } } aset(a, head, val); } private static void SmoothSortAscendingTrinkle( this TArray a, Func aget, Action aset, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = aget(a, head); while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = aget(a, stepson); if (selector(vstepson) <= selector(val)) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a, rt)) >= selector(vstepson) || selector(aget(a, lf)) >= selector(vstepson)) break; } aset(a, head, vstepson); head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { aset(a, head, val); SmoothSortAscendingSift(a, aget, aset, selector, pshift, head); } } public class TimSortInfoLongGetLongSel { public TArray m_a; public long m_count; public Func m_aget; public Action m_aset; public Func m_amake; public Func m_sel; public long m_minGallop = c_minGallop; public TArray m_tmp; public long m_len; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoLongGetLongSel(TArray a, Func aget, Action aset, Func amake, Func selector, long count) { m_a = a; m_count = count; m_aget = aget; m_aset = aset; m_amake = amake; m_sel = selector; m_len = count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength; m_tmp = amake(m_len); int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public TArray EnsureCapacity(long cap) { if (m_len < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_len = c < 0 ? cap : Math.Min(c, m_count >> 1); m_tmp = m_amake(m_len); } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortAscending( this TArray a, long count, Func aget, Action aset, Func amake, Func selector) { TimSortAscending(a, aget, aset, amake, selector, 0, count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortAscending( this TArray a, Func aget, Action aset, Func amake, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, aget, aset, selector, lo, hi); BinarySortAscending(a, aget, aset, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongGetLongSel(a, aget, aset, amake, selector, count); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderAscending(a, aget, aset, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortAscending(a, aget, aset, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongAsc(ti); } private static void MergeCollapseLongAsc(this TimSortInfoLongGetLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongAsc(ti, n); else break; } } private static void MergeForceCollapseLongAsc(this TimSortInfoLongGetLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } } private static void MergeAtLongAsc(this TimSortInfoLongGetLongSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightAscending(a, ti.m_aget, ti.m_sel, ti.m_aget(a, start2), start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_aget, ti.m_sel, ti.m_aget(a, start1 + len1 - 1), start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongAsc(ti, start1, len1, start2, len2); else MergeHiLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoLongAsc(this TimSortInfoLongGetLongSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len1); CopyElements(aget, aset, a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) { CopyElements(aget, aset, t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a, idx2)) < selector(aget(t, idx1))) { aset(a, dest++, aget(a, idx2++)); count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { aset(a, dest++, aget(t, idx1++)); count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightAscending(t, aget, selector, aget(a, idx2), idx1, len1, 0); if (count1 != 0) { CopyElements(aget, aset, t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, aget, selector, aget(t, idx1), idx2, len2, 0); if (count2 != 0) { CopyElements(aget, aset, a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } aset(a, dest++, aget(t, idx1++)); if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, idx1, a, dest, len1); } private static void MergeHiLongAsc(this TimSortInfoLongGetLongSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len2); CopyElements(aget, aset, a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) { CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(t, idx2)) < selector(aget(a, idx1))) { aset(a, dest--, aget(a, idx1--)); count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { aset(a, dest--, aget(t, idx2--)); count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, aget, selector, aget(t, idx2), start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } aset(a, dest--, aget(t, idx2--)); if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftAscending(t, aget, selector, aget(a, idx1), 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(aget, aset, t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftAscending( this TArray a, Func aget, Func selector, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(key) > selector(aget(a, start + hint))) { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) > selector(aget(a, start + hint + ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) <= selector(aget(a, start + hint - ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(aget(a, start + m))) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightAscending( this TArray a, Func aget, Func selector, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(key) < selector(aget(a, start + hint))) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) < selector(aget(a, start + hint - ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) >= selector(aget(a, start + hint + ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(aget(a, start + m))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = aget(a, beginUnsorted); long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(pivot) < selector(aget(a, mid))) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: aset(a, l + 2, aget(a, l + 1)); aset(a, l + 1, aget(a, l)); break; case 1: aset(a, l + 1, aget(a, l)); break; default: CopyElements(aget, aset, a, l, a, l + 1, n); break; } aset(a, l, pivot); } } private static long CountRunAndOrderAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a, runHi++)) < selector(aget(a, beginIncl))) { while (runHi < endExcl && selector(aget(a, runHi)) < selector(aget(a, runHi - 1))) runHi++; ReverseRange(aget, aset, a, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a, runHi)) >= selector(aget(a, runHi - 1))) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianDescending( this TArray a, long count, Func aget, Action aset, Func selector, long med) { long last = count - 1; QuickMedianDescending(a, aget, aset, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl, long med) { QuickMedianDescending(a, aget, aset, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this TArray a, Func aget, Action aset, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a, e1)) < selector(aget(a, e2))) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (selector(aget(a, e4)) < selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e1)) < selector(aget(a, e3))) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e2)) < selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e1)) < selector(aget(a, e4))) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e3)) < selector(aget(a, e4))) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e2)) < selector(aget(a, e5))) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e2)) < selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e4)) < selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (selector(ai) < selector(p2)) { while (selector(aget(a, hi)) < selector(p2) && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (selector(aget(a, hi)) < selector(p1)) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a, lo)) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a, i)) == selector(p1)) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (selector(aget(a, hi)) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a, i)) == selector(p2)) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && selector(ai) > selector(aget(a, j)); j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The QuickSort algorithm sorts the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortDescending( this TArray a, long count, Func aget, Action aset, Func selector) { long last = count - 1; QuickSortDescending(a, aget, aset, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { QuickSortDescending(a, aget, aset, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this TArray a, Func aget, Action aset, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a, e1)) < selector(aget(a, e2))) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (selector(aget(a, e4)) < selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e1)) < selector(aget(a, e3))) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e2)) < selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e1)) < selector(aget(a, e4))) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e3)) < selector(aget(a, e4))) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e2)) < selector(aget(a, e5))) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e2)) < selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e4)) < selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (selector(ai) < selector(p2)) { while (selector(aget(a, hi)) < selector(p2) && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (selector(aget(a, hi)) < selector(p1)) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); { while (selector(aget(a, lo)) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a, i)) == selector(p1)) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (selector(aget(a, hi)) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a, i)) == selector(p2)) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, aget, aset, selector, lo, hi, cm); QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); QuickSortDescending(a, aget, aset, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && selector(ai) > selector(aget(a, j)); j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortDescending( this TArray a, Func aget, Action aset, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = aget(a, c + begin); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) > selector(aget(a, i2 + begin))) break; aset(a, i + begin, aget(a, i2 + begin)); i = i2; } aset(a, i + begin, element); } while (count > 1) { --count; var element = aget(a, count + begin); aset(a, count + begin, aget(a, 0 + begin)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a, i1 + begin)) > selector(aget(a, i2 + begin))) ? i2 : i1; // smaller child if (selector(aget(a, ni + begin)) > selector(element)) break; aset(a, i + begin, aget(a, ni + begin)); i = ni; i1 = 2 * i + 1; } aset(a, i + begin, element); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortDescending( this TArray a, long count, Func aget, Action aset, Func selector) { for (long c = 1; c < count; c++) { var element = aget(a, c); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) > selector(aget(a, i2))) break; aset(a, i, aget(a, i2)); i = i2; } aset(a, i, element); } while (count > 1) { --count; var element = aget(a, count); aset(a, count, aget(a, 0)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a, i1)) > selector(aget(a, i2))) ? i2 : i1; // smaller child if (selector(aget(a, ni)) > selector(element)) break; aset(a, i, aget(a, ni)); i = ni; i1 = 2 * i + 1; } aset(a, i, element); } } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortDescending( this TArray a, long count, Func aget, Action aset, Func selector) { SmoothSortDescendingInclusiveRange(a, aget, aset, selector, 0, count - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { SmoothSortDescendingInclusiveRange(a, aget, aset, selector, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this TArray a, Func aget, Action aset, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, aget, aset, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, aget, aset, selector, pbits, pshift, head, false); else SmoothSortDescendingSift(a, aget, aset, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, aget, aset, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, aget, aset, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortDescendingTrinkle(a, aget, aset, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this TArray a, Func aget, Action aset, Func selector, int pshift, long head) { var val = aget(a, head); while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(val) <= selector(aget(a, lf)) && selector(val) <= selector(aget(a, rt))) break; if (selector(aget(a, lf)) <= selector(aget(a, rt))) { aset(a, head, aget(a, lf)); head = lf; pshift -= 1; } else { aset(a, head, aget(a, rt)); head = rt; pshift -= 2; } } aset(a, head, val); } private static void SmoothSortDescendingTrinkle( this TArray a, Func aget, Action aset, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = aget(a, head); while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = aget(a, stepson); if (selector(vstepson) >= selector(val)) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a, rt)) <= selector(vstepson) || selector(aget(a, lf)) <= selector(vstepson)) break; } aset(a, head, vstepson); head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { aset(a, head, val); SmoothSortDescendingSift(a, aget, aset, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortDescending( this TArray a, long count, Func aget, Action aset, Func amake, Func selector) { TimSortDescending(a, aget, aset, amake, selector, 0, count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortDescending( this TArray a, Func aget, Action aset, Func amake, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, aget, aset, selector, lo, hi); BinarySortDescending(a, aget, aset, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongGetLongSel(a, aget, aset, amake, selector, count); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderDescending(a, aget, aset, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortDescending(a, aget, aset, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongDesc(ti); } private static void MergeCollapseLongDesc(this TimSortInfoLongGetLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongDesc(ti, n); else break; } } private static void MergeForceCollapseLongDesc(this TimSortInfoLongGetLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } } private static void MergeAtLongDesc(this TimSortInfoLongGetLongSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightDescending(a, ti.m_aget, ti.m_sel, ti.m_aget(a, start2), start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_aget, ti.m_sel, ti.m_aget(a, start1 + len1 - 1), start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongDesc(ti, start1, len1, start2, len2); else MergeHiLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoLongDesc(this TimSortInfoLongGetLongSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len1); CopyElements(aget, aset, a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) { CopyElements(aget, aset, t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a, idx2)) > selector(aget(t, idx1))) { aset(a, dest++, aget(a, idx2++)); count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { aset(a, dest++, aget(t, idx1++)); count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightDescending(t, aget, selector, aget(a, idx2), idx1, len1, 0); if (count1 != 0) { CopyElements(aget, aset, t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, aget, selector, aget(t, idx1), idx2, len2, 0); if (count2 != 0) { CopyElements(aget, aset, a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } aset(a, dest++, aget(t, idx1++)); if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, idx1, a, dest, len1); } private static void MergeHiLongDesc(this TimSortInfoLongGetLongSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len2); CopyElements(aget, aset, a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) { CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(t, idx2)) > selector(aget(a, idx1))) { aset(a, dest--, aget(a, idx1--)); count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { aset(a, dest--, aget(t, idx2--)); count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, aget, selector, aget(t, idx2), start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } aset(a, dest--, aget(t, idx2--)); if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftDescending(t, aget, selector, aget(a, idx1), 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(aget, aset, t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftDescending( this TArray a, Func aget, Func selector, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(key) < selector(aget(a, start + hint))) { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) < selector(aget(a, start + hint + ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) >= selector(aget(a, start + hint - ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(aget(a, start + m))) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightDescending( this TArray a, Func aget, Func selector, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(key) > selector(aget(a, start + hint))) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) > selector(aget(a, start + hint - ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) <= selector(aget(a, start + hint + ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(aget(a, start + m))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = aget(a, beginUnsorted); long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(pivot) > selector(aget(a, mid))) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: aset(a, l + 2, aget(a, l + 1)); aset(a, l + 1, aget(a, l)); break; case 1: aset(a, l + 1, aget(a, l)); break; default: CopyElements(aget, aset, a, l, a, l + 1, n); break; } aset(a, l, pivot); } } private static long CountRunAndOrderDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a, runHi++)) > selector(aget(a, beginIncl))) { while (runHi < endExcl && selector(aget(a, runHi)) > selector(aget(a, runHi - 1))) runHi++; ReverseRange(aget, aset, a, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a, runHi)) <= selector(aget(a, runHi - 1))) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianAscending( this TArray a, long count, Func aget, Action aset, Func selector, long med) { long last = count - 1; QuickMedianAscending(a, aget, aset, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl, long med) { QuickMedianAscending(a, aget, aset, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this TArray a, Func aget, Action aset, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a, e1)) > selector(aget(a, e2))) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (selector(aget(a, e4)) > selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e1)) > selector(aget(a, e3))) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e2)) > selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e1)) > selector(aget(a, e4))) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e3)) > selector(aget(a, e4))) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e2)) > selector(aget(a, e5))) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e2)) > selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e4)) > selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (selector(ai) > selector(p2)) { while (selector(aget(a, hi)) > selector(p2) && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (selector(aget(a, hi)) > selector(p1)) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a, lo)) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a, i)) == selector(p1)) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (selector(aget(a, hi)) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a, i)) == selector(p2)) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && selector(ai) < selector(aget(a, j)); j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The QuickSort algorithm sorts the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortAscending( this TArray a, long count, Func aget, Action aset, Func selector) { long last = count - 1; QuickSortAscending(a, aget, aset, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { QuickSortAscending(a, aget, aset, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this TArray a, Func aget, Action aset, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a, e1)) > selector(aget(a, e2))) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (selector(aget(a, e4)) > selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e1)) > selector(aget(a, e3))) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e2)) > selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e1)) > selector(aget(a, e4))) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e3)) > selector(aget(a, e4))) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e2)) > selector(aget(a, e5))) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e2)) > selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e4)) > selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (selector(ai) > selector(p2)) { while (selector(aget(a, hi)) > selector(p2) && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (selector(aget(a, hi)) > selector(p1)) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); { while (selector(aget(a, lo)) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a, i)) == selector(p1)) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (selector(aget(a, hi)) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a, i)) == selector(p2)) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, aget, aset, selector, lo, hi, cm); QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); QuickSortAscending(a, aget, aset, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && selector(ai) < selector(aget(a, j)); j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortAscending( this TArray a, Func aget, Action aset, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = aget(a, c + begin); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) < selector(aget(a, i2 + begin))) break; aset(a, i + begin, aget(a, i2 + begin)); i = i2; } aset(a, i + begin, element); } while (count > 1) { --count; var element = aget(a, count + begin); aset(a, count + begin, aget(a, 0 + begin)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a, i1 + begin)) < selector(aget(a, i2 + begin))) ? i2 : i1; // smaller child if (selector(aget(a, ni + begin)) < selector(element)) break; aset(a, i + begin, aget(a, ni + begin)); i = ni; i1 = 2 * i + 1; } aset(a, i + begin, element); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortAscending( this TArray a, long count, Func aget, Action aset, Func selector) { for (long c = 1; c < count; c++) { var element = aget(a, c); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) < selector(aget(a, i2))) break; aset(a, i, aget(a, i2)); i = i2; } aset(a, i, element); } while (count > 1) { --count; var element = aget(a, count); aset(a, count, aget(a, 0)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a, i1)) < selector(aget(a, i2))) ? i2 : i1; // smaller child if (selector(aget(a, ni)) < selector(element)) break; aset(a, i, aget(a, ni)); i = ni; i1 = 2 * i + 1; } aset(a, i, element); } } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortAscending( this TArray a, long count, Func aget, Action aset, Func selector) { SmoothSortAscendingInclusiveRange(a, aget, aset, selector, 0, count - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { SmoothSortAscendingInclusiveRange(a, aget, aset, selector, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this TArray a, Func aget, Action aset, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, aget, aset, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, aget, aset, selector, pbits, pshift, head, false); else SmoothSortAscendingSift(a, aget, aset, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, aget, aset, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, aget, aset, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortAscendingTrinkle(a, aget, aset, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this TArray a, Func aget, Action aset, Func selector, int pshift, long head) { var val = aget(a, head); while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(val) >= selector(aget(a, lf)) && selector(val) >= selector(aget(a, rt))) break; if (selector(aget(a, lf)) >= selector(aget(a, rt))) { aset(a, head, aget(a, lf)); head = lf; pshift -= 1; } else { aset(a, head, aget(a, rt)); head = rt; pshift -= 2; } } aset(a, head, val); } private static void SmoothSortAscendingTrinkle( this TArray a, Func aget, Action aset, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = aget(a, head); while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = aget(a, stepson); if (selector(vstepson) <= selector(val)) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a, rt)) >= selector(vstepson) || selector(aget(a, lf)) >= selector(vstepson)) break; } aset(a, head, vstepson); head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { aset(a, head, val); SmoothSortAscendingSift(a, aget, aset, selector, pshift, head); } } public class TimSortInfoLongGetFloatSel { public TArray m_a; public long m_count; public Func m_aget; public Action m_aset; public Func m_amake; public Func m_sel; public long m_minGallop = c_minGallop; public TArray m_tmp; public long m_len; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoLongGetFloatSel(TArray a, Func aget, Action aset, Func amake, Func selector, long count) { m_a = a; m_count = count; m_aget = aget; m_aset = aset; m_amake = amake; m_sel = selector; m_len = count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength; m_tmp = amake(m_len); int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public TArray EnsureCapacity(long cap) { if (m_len < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_len = c < 0 ? cap : Math.Min(c, m_count >> 1); m_tmp = m_amake(m_len); } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortAscending( this TArray a, long count, Func aget, Action aset, Func amake, Func selector) { TimSortAscending(a, aget, aset, amake, selector, 0, count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortAscending( this TArray a, Func aget, Action aset, Func amake, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, aget, aset, selector, lo, hi); BinarySortAscending(a, aget, aset, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongGetFloatSel(a, aget, aset, amake, selector, count); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderAscending(a, aget, aset, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortAscending(a, aget, aset, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongAsc(ti); } private static void MergeCollapseLongAsc(this TimSortInfoLongGetFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongAsc(ti, n); else break; } } private static void MergeForceCollapseLongAsc(this TimSortInfoLongGetFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } } private static void MergeAtLongAsc(this TimSortInfoLongGetFloatSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightAscending(a, ti.m_aget, ti.m_sel, ti.m_aget(a, start2), start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_aget, ti.m_sel, ti.m_aget(a, start1 + len1 - 1), start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongAsc(ti, start1, len1, start2, len2); else MergeHiLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoLongAsc(this TimSortInfoLongGetFloatSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len1); CopyElements(aget, aset, a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) { CopyElements(aget, aset, t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a, idx2)) < selector(aget(t, idx1))) { aset(a, dest++, aget(a, idx2++)); count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { aset(a, dest++, aget(t, idx1++)); count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightAscending(t, aget, selector, aget(a, idx2), idx1, len1, 0); if (count1 != 0) { CopyElements(aget, aset, t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, aget, selector, aget(t, idx1), idx2, len2, 0); if (count2 != 0) { CopyElements(aget, aset, a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } aset(a, dest++, aget(t, idx1++)); if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, idx1, a, dest, len1); } private static void MergeHiLongAsc(this TimSortInfoLongGetFloatSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len2); CopyElements(aget, aset, a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) { CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(t, idx2)) < selector(aget(a, idx1))) { aset(a, dest--, aget(a, idx1--)); count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { aset(a, dest--, aget(t, idx2--)); count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, aget, selector, aget(t, idx2), start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } aset(a, dest--, aget(t, idx2--)); if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftAscending(t, aget, selector, aget(a, idx1), 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(aget, aset, t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftAscending( this TArray a, Func aget, Func selector, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(key) > selector(aget(a, start + hint))) { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) > selector(aget(a, start + hint + ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) <= selector(aget(a, start + hint - ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(aget(a, start + m))) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightAscending( this TArray a, Func aget, Func selector, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(key) < selector(aget(a, start + hint))) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) < selector(aget(a, start + hint - ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) >= selector(aget(a, start + hint + ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(aget(a, start + m))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = aget(a, beginUnsorted); long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(pivot) < selector(aget(a, mid))) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: aset(a, l + 2, aget(a, l + 1)); aset(a, l + 1, aget(a, l)); break; case 1: aset(a, l + 1, aget(a, l)); break; default: CopyElements(aget, aset, a, l, a, l + 1, n); break; } aset(a, l, pivot); } } private static long CountRunAndOrderAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a, runHi++)) < selector(aget(a, beginIncl))) { while (runHi < endExcl && selector(aget(a, runHi)) < selector(aget(a, runHi - 1))) runHi++; ReverseRange(aget, aset, a, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a, runHi)) >= selector(aget(a, runHi - 1))) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianDescending( this TArray a, long count, Func aget, Action aset, Func selector, long med) { long last = count - 1; QuickMedianDescending(a, aget, aset, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl, long med) { QuickMedianDescending(a, aget, aset, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this TArray a, Func aget, Action aset, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a, e1)) < selector(aget(a, e2))) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (selector(aget(a, e4)) < selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e1)) < selector(aget(a, e3))) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e2)) < selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e1)) < selector(aget(a, e4))) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e3)) < selector(aget(a, e4))) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e2)) < selector(aget(a, e5))) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e2)) < selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e4)) < selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (selector(ai) < selector(p2)) { while (selector(aget(a, hi)) < selector(p2) && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (selector(aget(a, hi)) < selector(p1)) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a, lo)) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a, i)) == selector(p1)) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (selector(aget(a, hi)) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a, i)) == selector(p2)) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && selector(ai) > selector(aget(a, j)); j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The QuickSort algorithm sorts the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortDescending( this TArray a, long count, Func aget, Action aset, Func selector) { long last = count - 1; QuickSortDescending(a, aget, aset, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { QuickSortDescending(a, aget, aset, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this TArray a, Func aget, Action aset, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a, e1)) < selector(aget(a, e2))) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (selector(aget(a, e4)) < selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e1)) < selector(aget(a, e3))) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e2)) < selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e1)) < selector(aget(a, e4))) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e3)) < selector(aget(a, e4))) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e2)) < selector(aget(a, e5))) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e2)) < selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e4)) < selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (selector(ai) < selector(p2)) { while (selector(aget(a, hi)) < selector(p2) && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (selector(aget(a, hi)) < selector(p1)) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); { while (selector(aget(a, lo)) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a, i)) == selector(p1)) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (selector(aget(a, hi)) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a, i)) == selector(p2)) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, aget, aset, selector, lo, hi, cm); QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); QuickSortDescending(a, aget, aset, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && selector(ai) > selector(aget(a, j)); j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortDescending( this TArray a, Func aget, Action aset, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = aget(a, c + begin); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) > selector(aget(a, i2 + begin))) break; aset(a, i + begin, aget(a, i2 + begin)); i = i2; } aset(a, i + begin, element); } while (count > 1) { --count; var element = aget(a, count + begin); aset(a, count + begin, aget(a, 0 + begin)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a, i1 + begin)) > selector(aget(a, i2 + begin))) ? i2 : i1; // smaller child if (selector(aget(a, ni + begin)) > selector(element)) break; aset(a, i + begin, aget(a, ni + begin)); i = ni; i1 = 2 * i + 1; } aset(a, i + begin, element); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortDescending( this TArray a, long count, Func aget, Action aset, Func selector) { for (long c = 1; c < count; c++) { var element = aget(a, c); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) > selector(aget(a, i2))) break; aset(a, i, aget(a, i2)); i = i2; } aset(a, i, element); } while (count > 1) { --count; var element = aget(a, count); aset(a, count, aget(a, 0)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a, i1)) > selector(aget(a, i2))) ? i2 : i1; // smaller child if (selector(aget(a, ni)) > selector(element)) break; aset(a, i, aget(a, ni)); i = ni; i1 = 2 * i + 1; } aset(a, i, element); } } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortDescending( this TArray a, long count, Func aget, Action aset, Func selector) { SmoothSortDescendingInclusiveRange(a, aget, aset, selector, 0, count - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { SmoothSortDescendingInclusiveRange(a, aget, aset, selector, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this TArray a, Func aget, Action aset, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, aget, aset, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, aget, aset, selector, pbits, pshift, head, false); else SmoothSortDescendingSift(a, aget, aset, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, aget, aset, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, aget, aset, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortDescendingTrinkle(a, aget, aset, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this TArray a, Func aget, Action aset, Func selector, int pshift, long head) { var val = aget(a, head); while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(val) <= selector(aget(a, lf)) && selector(val) <= selector(aget(a, rt))) break; if (selector(aget(a, lf)) <= selector(aget(a, rt))) { aset(a, head, aget(a, lf)); head = lf; pshift -= 1; } else { aset(a, head, aget(a, rt)); head = rt; pshift -= 2; } } aset(a, head, val); } private static void SmoothSortDescendingTrinkle( this TArray a, Func aget, Action aset, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = aget(a, head); while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = aget(a, stepson); if (selector(vstepson) >= selector(val)) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a, rt)) <= selector(vstepson) || selector(aget(a, lf)) <= selector(vstepson)) break; } aset(a, head, vstepson); head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { aset(a, head, val); SmoothSortDescendingSift(a, aget, aset, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortDescending( this TArray a, long count, Func aget, Action aset, Func amake, Func selector) { TimSortDescending(a, aget, aset, amake, selector, 0, count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortDescending( this TArray a, Func aget, Action aset, Func amake, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, aget, aset, selector, lo, hi); BinarySortDescending(a, aget, aset, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongGetFloatSel(a, aget, aset, amake, selector, count); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderDescending(a, aget, aset, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortDescending(a, aget, aset, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongDesc(ti); } private static void MergeCollapseLongDesc(this TimSortInfoLongGetFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongDesc(ti, n); else break; } } private static void MergeForceCollapseLongDesc(this TimSortInfoLongGetFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } } private static void MergeAtLongDesc(this TimSortInfoLongGetFloatSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightDescending(a, ti.m_aget, ti.m_sel, ti.m_aget(a, start2), start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_aget, ti.m_sel, ti.m_aget(a, start1 + len1 - 1), start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongDesc(ti, start1, len1, start2, len2); else MergeHiLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoLongDesc(this TimSortInfoLongGetFloatSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len1); CopyElements(aget, aset, a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) { CopyElements(aget, aset, t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a, idx2)) > selector(aget(t, idx1))) { aset(a, dest++, aget(a, idx2++)); count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { aset(a, dest++, aget(t, idx1++)); count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightDescending(t, aget, selector, aget(a, idx2), idx1, len1, 0); if (count1 != 0) { CopyElements(aget, aset, t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, aget, selector, aget(t, idx1), idx2, len2, 0); if (count2 != 0) { CopyElements(aget, aset, a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } aset(a, dest++, aget(t, idx1++)); if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, idx1, a, dest, len1); } private static void MergeHiLongDesc(this TimSortInfoLongGetFloatSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len2); CopyElements(aget, aset, a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) { CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(t, idx2)) > selector(aget(a, idx1))) { aset(a, dest--, aget(a, idx1--)); count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { aset(a, dest--, aget(t, idx2--)); count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, aget, selector, aget(t, idx2), start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } aset(a, dest--, aget(t, idx2--)); if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftDescending(t, aget, selector, aget(a, idx1), 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(aget, aset, t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftDescending( this TArray a, Func aget, Func selector, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(key) < selector(aget(a, start + hint))) { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) < selector(aget(a, start + hint + ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) >= selector(aget(a, start + hint - ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(aget(a, start + m))) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightDescending( this TArray a, Func aget, Func selector, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(key) > selector(aget(a, start + hint))) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) > selector(aget(a, start + hint - ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) <= selector(aget(a, start + hint + ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(aget(a, start + m))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = aget(a, beginUnsorted); long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(pivot) > selector(aget(a, mid))) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: aset(a, l + 2, aget(a, l + 1)); aset(a, l + 1, aget(a, l)); break; case 1: aset(a, l + 1, aget(a, l)); break; default: CopyElements(aget, aset, a, l, a, l + 1, n); break; } aset(a, l, pivot); } } private static long CountRunAndOrderDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a, runHi++)) > selector(aget(a, beginIncl))) { while (runHi < endExcl && selector(aget(a, runHi)) > selector(aget(a, runHi - 1))) runHi++; ReverseRange(aget, aset, a, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a, runHi)) <= selector(aget(a, runHi - 1))) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianAscending( this TArray a, long count, Func aget, Action aset, Func selector, long med) { long last = count - 1; QuickMedianAscending(a, aget, aset, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl, long med) { QuickMedianAscending(a, aget, aset, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianAscending( this TArray a, Func aget, Action aset, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a, e1)) > selector(aget(a, e2))) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (selector(aget(a, e4)) > selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e1)) > selector(aget(a, e3))) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e2)) > selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e1)) > selector(aget(a, e4))) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e3)) > selector(aget(a, e4))) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e2)) > selector(aget(a, e5))) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e2)) > selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e4)) > selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (selector(ai) > selector(p2)) { while (selector(aget(a, hi)) > selector(p2) && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (selector(aget(a, hi)) > selector(p1)) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a, lo)) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a, i)) == selector(p1)) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (selector(aget(a, hi)) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a, i)) == selector(p2)) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && selector(ai) < selector(aget(a, j)); j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The QuickSort algorithm sorts the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortAscending( this TArray a, long count, Func aget, Action aset, Func selector) { long last = count - 1; QuickSortAscending(a, aget, aset, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { QuickSortAscending(a, aget, aset, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortAscending( this TArray a, Func aget, Action aset, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a, e1)) > selector(aget(a, e2))) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (selector(aget(a, e4)) > selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e1)) > selector(aget(a, e3))) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e2)) > selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e1)) > selector(aget(a, e4))) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e3)) > selector(aget(a, e4))) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e2)) > selector(aget(a, e5))) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e2)) > selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e4)) > selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (selector(ai) > selector(p2)) { while (selector(aget(a, hi)) > selector(p2) && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) == selector(p1)) continue; if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (selector(aget(a, hi)) > selector(p1)) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) < selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); { while (selector(aget(a, lo)) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a, i)) == selector(p1)) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (selector(aget(a, hi)) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a, i)) == selector(p2)) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortAscending(a, aget, aset, selector, lo, hi, cm); QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); QuickSortAscending(a, aget, aset, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortAscending(a, aget, aset, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortAscending(a, aget, aset, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && selector(ai) < selector(aget(a, j)); j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortAscending( this TArray a, Func aget, Action aset, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = aget(a, c + begin); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) < selector(aget(a, i2 + begin))) break; aset(a, i + begin, aget(a, i2 + begin)); i = i2; } aset(a, i + begin, element); } while (count > 1) { --count; var element = aget(a, count + begin); aset(a, count + begin, aget(a, 0 + begin)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a, i1 + begin)) < selector(aget(a, i2 + begin))) ? i2 : i1; // smaller child if (selector(aget(a, ni + begin)) < selector(element)) break; aset(a, i + begin, aget(a, ni + begin)); i = ni; i1 = 2 * i + 1; } aset(a, i + begin, element); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortAscending( this TArray a, long count, Func aget, Action aset, Func selector) { for (long c = 1; c < count; c++) { var element = aget(a, c); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) < selector(aget(a, i2))) break; aset(a, i, aget(a, i2)); i = i2; } aset(a, i, element); } while (count > 1) { --count; var element = aget(a, count); aset(a, count, aget(a, 0)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a, i1)) < selector(aget(a, i2))) ? i2 : i1; // smaller child if (selector(aget(a, ni)) < selector(element)) break; aset(a, i, aget(a, ni)); i = ni; i1 = 2 * i + 1; } aset(a, i, element); } } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortAscending( this TArray a, long count, Func aget, Action aset, Func selector) { SmoothSortAscendingInclusiveRange(a, aget, aset, selector, 0, count - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { SmoothSortAscendingInclusiveRange(a, aget, aset, selector, beginIncl, endExcl - 1); } private static void SmoothSortAscendingInclusiveRange( this TArray a, Func aget, Action aset, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortAscendingSift(a, aget, aset, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortAscendingTrinkle(a, aget, aset, selector, pbits, pshift, head, false); else SmoothSortAscendingSift(a, aget, aset, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortAscendingTrinkle(a, aget, aset, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortAscendingTrinkle(a, aget, aset, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortAscendingTrinkle(a, aget, aset, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortAscendingSift( this TArray a, Func aget, Action aset, Func selector, int pshift, long head) { var val = aget(a, head); while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(val) >= selector(aget(a, lf)) && selector(val) >= selector(aget(a, rt))) break; if (selector(aget(a, lf)) >= selector(aget(a, rt))) { aset(a, head, aget(a, lf)); head = lf; pshift -= 1; } else { aset(a, head, aget(a, rt)); head = rt; pshift -= 2; } } aset(a, head, val); } private static void SmoothSortAscendingTrinkle( this TArray a, Func aget, Action aset, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = aget(a, head); while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = aget(a, stepson); if (selector(vstepson) <= selector(val)) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a, rt)) >= selector(vstepson) || selector(aget(a, lf)) >= selector(vstepson)) break; } aset(a, head, vstepson); head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { aset(a, head, val); SmoothSortAscendingSift(a, aget, aset, selector, pshift, head); } } public class TimSortInfoLongGetDoubleSel { public TArray m_a; public long m_count; public Func m_aget; public Action m_aset; public Func m_amake; public Func m_sel; public long m_minGallop = c_minGallop; public TArray m_tmp; public long m_len; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoLongGetDoubleSel(TArray a, Func aget, Action aset, Func amake, Func selector, long count) { m_a = a; m_count = count; m_aget = aget; m_aset = aset; m_amake = amake; m_sel = selector; m_len = count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength; m_tmp = amake(m_len); int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public TArray EnsureCapacity(long cap) { if (m_len < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_len = c < 0 ? cap : Math.Min(c, m_count >> 1); m_tmp = m_amake(m_len); } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortAscending( this TArray a, long count, Func aget, Action aset, Func amake, Func selector) { TimSortAscending(a, aget, aset, amake, selector, 0, count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortAscending( this TArray a, Func aget, Action aset, Func amake, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderAscending(a, aget, aset, selector, lo, hi); BinarySortAscending(a, aget, aset, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongGetDoubleSel(a, aget, aset, amake, selector, count); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderAscending(a, aget, aset, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortAscending(a, aget, aset, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongAsc(ti); } private static void MergeCollapseLongAsc(this TimSortInfoLongGetDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongAsc(ti, n); else break; } } private static void MergeForceCollapseLongAsc(this TimSortInfoLongGetDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongAsc(ti, n); } } private static void MergeAtLongAsc(this TimSortInfoLongGetDoubleSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightAscending(a, ti.m_aget, ti.m_sel, ti.m_aget(a, start2), start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftAscending(a, ti.m_aget, ti.m_sel, ti.m_aget(a, start1 + len1 - 1), start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongAsc(ti, start1, len1, start2, len2); else MergeHiLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoLongAsc(this TimSortInfoLongGetDoubleSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len1); CopyElements(aget, aset, a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) { CopyElements(aget, aset, t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a, idx2)) < selector(aget(t, idx1))) { aset(a, dest++, aget(a, idx2++)); count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { aset(a, dest++, aget(t, idx1++)); count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightAscending(t, aget, selector, aget(a, idx2), idx1, len1, 0); if (count1 != 0) { CopyElements(aget, aset, t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) goto breakouter; count2 = GallopLeftAscending(a, aget, selector, aget(t, idx1), idx2, len2, 0); if (count2 != 0) { CopyElements(aget, aset, a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } aset(a, dest++, aget(t, idx1++)); if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, idx1, a, dest, len1); } private static void MergeHiLongAsc(this TimSortInfoLongGetDoubleSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len2); CopyElements(aget, aset, a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) { CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(t, idx2)) < selector(aget(a, idx1))) { aset(a, dest--, aget(a, idx1--)); count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { aset(a, dest--, aget(t, idx2--)); count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightAscending(a, aget, selector, aget(t, idx2), start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } aset(a, dest--, aget(t, idx2--)); if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftAscending(t, aget, selector, aget(a, idx1), 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(aget, aset, t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftAscending( this TArray a, Func aget, Func selector, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(key) > selector(aget(a, start + hint))) { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) > selector(aget(a, start + hint + ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) <= selector(aget(a, start + hint - ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(aget(a, start + m))) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightAscending( this TArray a, Func aget, Func selector, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(key) < selector(aget(a, start + hint))) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) < selector(aget(a, start + hint - ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) >= selector(aget(a, start + hint + ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(aget(a, start + m))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = aget(a, beginUnsorted); long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(pivot) < selector(aget(a, mid))) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: aset(a, l + 2, aget(a, l + 1)); aset(a, l + 1, aget(a, l)); break; case 1: aset(a, l + 1, aget(a, l)); break; default: CopyElements(aget, aset, a, l, a, l + 1, n); break; } aset(a, l, pivot); } } private static long CountRunAndOrderAscending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a, runHi++)) < selector(aget(a, beginIncl))) { while (runHi < endExcl && selector(aget(a, runHi)) < selector(aget(a, runHi - 1))) runHi++; ReverseRange(aget, aset, a, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a, runHi)) >= selector(aget(a, runHi - 1))) runHi++; } return runHi - beginIncl; } /// /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianDescending( this TArray a, long count, Func aget, Action aset, Func selector, long med) { long last = count - 1; QuickMedianDescending(a, aget, aset, selector, 0, last, last, med); } /// /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickMedianDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl, long med) { QuickMedianDescending(a, aget, aset, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickMedianDescending( this TArray a, Func aget, Action aset, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a, e1)) < selector(aget(a, e2))) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (selector(aget(a, e4)) < selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e1)) < selector(aget(a, e3))) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e2)) < selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e1)) < selector(aget(a, e4))) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e3)) < selector(aget(a, e4))) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e2)) < selector(aget(a, e5))) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e2)) < selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e4)) < selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (selector(ai) < selector(p2)) { while (selector(aget(a, hi)) < selector(p2) && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (selector(aget(a, hi)) < selector(p1)) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a, lo)) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a, i)) == selector(p1)) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (selector(aget(a, hi)) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a, i)) == selector(p2)) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && selector(ai) > selector(aget(a, j)); j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The QuickSort algorithm sorts the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortDescending( this TArray a, long count, Func aget, Action aset, Func selector) { long last = count - 1; QuickSortDescending(a, aget, aset, selector, 0, last, last); } /// /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void QuickSortDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { QuickSortDescending(a, aget, aset, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void QuickSortDescending( this TArray a, Func aget, Action aset, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a, e1)) < selector(aget(a, e2))) { var t = aget(a, e1); aset(a, e1, aget(a, e2)); aset(a, e2, t); } if (selector(aget(a, e4)) < selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e1)) < selector(aget(a, e3))) { var t = aget(a, e1); aset(a, e1, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e2)) < selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e1)) < selector(aget(a, e4))) { var t = aget(a, e1); aset(a, e1, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e3)) < selector(aget(a, e4))) { var t = aget(a, e3); aset(a, e3, aget(a, e4)); aset(a, e4, t); } if (selector(aget(a, e2)) < selector(aget(a, e5))) { var t = aget(a, e2); aset(a, e2, aget(a, e5)); aset(a, e5, t); } if (selector(aget(a, e2)) < selector(aget(a, e3))) { var t = aget(a, e2); aset(a, e2, aget(a, e3)); aset(a, e3, t); } if (selector(aget(a, e4)) < selector(aget(a, e5))) { var t = aget(a, e4); aset(a, e4, aget(a, e5)); aset(a, e5, t); } var p1 = aget(a, e2); aset(a, e2, aget(a, l)); var p2 = aget(a, e4); aset(a, e4, aget(a, r)); long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(p1) != selector(p2); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else if (selector(ai) < selector(p2)) { while (selector(aget(a, hi)) < selector(p2) && i < hi) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = aget(a, i); if (selector(ai) == selector(p1)) continue; if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } else { while (selector(aget(a, hi)) < selector(p1)) --hi; aset(a, i, aget(a, hi)); aset(a, hi, ai); --hi; ai = aget(a, i); if (selector(ai) > selector(p1)) { aset(a, i, aget(a, lo)); aset(a, lo, ai); ++lo; } } } } aset(a, l, aget(a, lo - 1)); aset(a, lo - 1, p1); aset(a, r, aget(a, hi + 1)); aset(a, hi + 1, p2); long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); { while (selector(aget(a, lo)) == selector(p1)) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a, i)) == selector(p1)) { p1 = aget(a, i); aset(a, i, aget(a, lo)); aset(a, lo, p1); ++lo; } } while (selector(aget(a, hi)) == selector(p2)) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a, i)) == selector(p2)) { p2 = aget(a, i); aset(a, i, aget(a, hi)); aset(a, hi, p2); --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { QuickSortDescending(a, aget, aset, selector, lo, hi, cm); QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); QuickSortDescending(a, aget, aset, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { QuickSortDescending(a, aget, aset, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { QuickSortDescending(a, aget, aset, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = aget(a, i); long j; for (j = i - 1; j >= l && selector(ai) > selector(aget(a, j)); j--) aset(a, j + 1, aget(a, j)); aset(a, j + 1, ai); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortDescending( this TArray a, Func aget, Action aset, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = aget(a, c + begin); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) > selector(aget(a, i2 + begin))) break; aset(a, i + begin, aget(a, i2 + begin)); i = i2; } aset(a, i + begin, element); } while (count > 1) { --count; var element = aget(a, count + begin); aset(a, count + begin, aget(a, 0 + begin)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a, i1 + begin)) > selector(aget(a, i2 + begin))) ? i2 : i1; // smaller child if (selector(aget(a, ni + begin)) > selector(element)) break; aset(a, i + begin, aget(a, ni + begin)); i = ni; i1 = 2 * i + 1; } aset(a, i + begin, element); } } /// /// The HeapSort algorithm sorts the data array. /// It is slower than the QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void HeapSortDescending( this TArray a, long count, Func aget, Action aset, Func selector) { for (long c = 1; c < count; c++) { var element = aget(a, c); long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(element) > selector(aget(a, i2))) break; aset(a, i, aget(a, i2)); i = i2; } aset(a, i, element); } while (count > 1) { --count; var element = aget(a, count); aset(a, count, aget(a, 0)); long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a, i1)) > selector(aget(a, i2))) ? i2 : i1; // smaller child if (selector(aget(a, ni)) > selector(element)) break; aset(a, i, aget(a, ni)); i = ni; i1 = 2 * i + 1; } aset(a, i, element); } } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortDescending( this TArray a, long count, Func aget, Action aset, Func selector) { SmoothSortDescendingInclusiveRange(a, aget, aset, selector, 0, count - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void SmoothSortDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { SmoothSortDescendingInclusiveRange(a, aget, aset, selector, beginIncl, endExcl - 1); } private static void SmoothSortDescendingInclusiveRange( this TArray a, Func aget, Action aset, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { SmoothSortDescendingSift(a, aget, aset, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) SmoothSortDescendingTrinkle(a, aget, aset, selector, pbits, pshift, head, false); else SmoothSortDescendingSift(a, aget, aset, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } SmoothSortDescendingTrinkle(a, aget, aset, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; SmoothSortDescendingTrinkle(a, aget, aset, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); SmoothSortDescendingTrinkle(a, aget, aset, selector, pbits, pshift, head - 1, true); } head--; } } private static void SmoothSortDescendingSift( this TArray a, Func aget, Action aset, Func selector, int pshift, long head) { var val = aget(a, head); while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(val) <= selector(aget(a, lf)) && selector(val) <= selector(aget(a, rt))) break; if (selector(aget(a, lf)) <= selector(aget(a, rt))) { aset(a, head, aget(a, lf)); head = lf; pshift -= 1; } else { aset(a, head, aget(a, rt)); head = rt; pshift -= 2; } } aset(a, head, val); } private static void SmoothSortDescendingTrinkle( this TArray a, Func aget, Action aset, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = aget(a, head); while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = aget(a, stepson); if (selector(vstepson) >= selector(val)) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a, rt)) <= selector(vstepson) || selector(aget(a, lf)) <= selector(vstepson)) break; } aset(a, head, vstepson); head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { aset(a, head, val); SmoothSortDescendingSift(a, aget, aset, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortDescending( this TArray a, long count, Func aget, Action aset, Func amake, Func selector) { TimSortDescending(a, aget, aset, amake, selector, 0, count); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void TimSortDescending( this TArray a, Func aget, Action aset, Func amake, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = CountRunAndOrderDescending(a, aget, aset, selector, lo, hi); BinarySortDescending(a, aget, aset, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoLongGetDoubleSel(a, aget, aset, amake, selector, count); long minRun = TimSortMinRunLength(count); do { long runLen = CountRunAndOrderDescending(a, aget, aset, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; BinarySortDescending(a, aget, aset, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapseLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapseLongDesc(ti); } private static void MergeCollapseLongDesc(this TimSortInfoLongGetDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtLongDesc(ti, n); else break; } } private static void MergeForceCollapseLongDesc(this TimSortInfoLongGetDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtLongDesc(ti, n); } } private static void MergeAtLongDesc(this TimSortInfoLongGetDoubleSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = GallopRightDescending(a, ti.m_aget, ti.m_sel, ti.m_aget(a, start2), start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = GallopLeftDescending(a, ti.m_aget, ti.m_sel, ti.m_aget(a, start1 + len1 - 1), start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoLongDesc(ti, start1, len1, start2, len2); else MergeHiLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoLongDesc(this TimSortInfoLongGetDoubleSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len1); CopyElements(aget, aset, a, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) { CopyElements(aget, aset, t, idx1, a, dest, len1); return; } if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a, idx2)) > selector(aget(t, idx1))) { aset(a, dest++, aget(a, idx2++)); count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { aset(a, dest++, aget(t, idx1++)); count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = GallopRightDescending(t, aget, selector, aget(a, idx2), idx1, len1, 0); if (count1 != 0) { CopyElements(aget, aset, t, idx1, a, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } aset(a, dest++, aget(a, idx2++)); if (--len2 == 0) goto breakouter; count2 = GallopLeftDescending(a, aget, selector, aget(t, idx1), idx2, len2, 0); if (count2 != 0) { CopyElements(aget, aset, a, idx2, a, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } aset(a, dest++, aget(t, idx1++)); if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { CopyElements(aget, aset, a, idx2, a, dest, len2); aset(a, dest + len2, aget(t, idx1)); } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, idx1, a, dest, len1); } private static void MergeHiLongDesc(this TimSortInfoLongGetDoubleSel ti, long start1, long len1, long start2, long len2) { var a = ti.m_a; var aget = ti.m_aget; var aset = ti.m_aset; var t = ti.EnsureCapacity(len2); CopyElements(aget, aset, a, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) { CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(t, idx2)) > selector(aget(a, idx1))) { aset(a, dest--, aget(a, idx1--)); count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { aset(a, dest--, aget(t, idx2--)); count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - GallopRightDescending(a, aget, selector, aget(t, idx2), start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, count1); if (len1 == 0) goto breakouter; } aset(a, dest--, aget(t, idx2--)); if (--len2 == 1) goto breakouter; count2 = len2 - GallopLeftDescending(t, aget, selector, aget(a, idx1), 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; CopyElements(aget, aset, t, idx2 + 1, a, dest + 1, count2); if (len2 <= 1) goto breakouter; } aset(a, dest--, aget(a, idx1--)); if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; CopyElements(aget, aset, a, idx1 + 1, a, dest + 1, len1); aset(a, dest, aget(t, idx2)); } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else CopyElements(aget, aset, t, 0, a, dest - (len2 - 1), len2); } private static long GallopLeftDescending( this TArray a, Func aget, Func selector, T key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(key) < selector(aget(a, start + hint))) { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) < selector(aget(a, start + hint + ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) >= selector(aget(a, start + hint - ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) < selector(aget(a, start + m))) lastOfs = m + 1; else ofs = m; } return ofs; } private static long GallopRightDescending( this TArray a, Func aget, Func selector, T key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(key) > selector(aget(a, start + hint))) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(key) > selector(aget(a, start + hint - ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(key) <= selector(aget(a, start + hint + ofs))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(key) > selector(aget(a, start + m))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void BinarySortDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = aget(a, beginUnsorted); long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(pivot) > selector(aget(a, mid))) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: aset(a, l + 2, aget(a, l + 1)); aset(a, l + 1, aget(a, l)); break; case 1: aset(a, l + 1, aget(a, l)); break; default: CopyElements(aget, aset, a, l, a, l + 1, n); break; } aset(a, l, pivot); } } private static long CountRunAndOrderDescending( this TArray a, Func aget, Action aset, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a, runHi++)) > selector(aget(a, beginIncl))) { while (runHi < endExcl && selector(aget(a, runHi)) > selector(aget(a, runHi - 1))) runHi++; ReverseRange(aget, aset, a, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a, runHi)) <= selector(aget(a, runHi - 1))) runHi++; } return runHi - beginIncl; } #endregion #region Permutation Sort/Median for TArray /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedian( this int[] p, TArray a, Func aget, Func cmp, int med) { int last = p.Length - 1; PermutationQuickMedian(p, a, aget, cmp, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedian( this int[] p, TArray a, Func aget, Func cmp, int beginIncl, int endExcl, int med) { PermutationQuickMedian(p, a, aget, cmp, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedian( this int[] p, TArray a, Func aget, Func cmp, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (cmp(aget(a,p[e1]), aget(a,p[e2])) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (cmp(aget(a,p[e4]), aget(a,p[e5])) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (cmp(aget(a,p[e1]), aget(a,p[e3])) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (cmp(aget(a,p[e2]), aget(a,p[e3])) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(aget(a,p[e1]), aget(a,p[e4])) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (cmp(aget(a,p[e3]), aget(a,p[e4])) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (cmp(aget(a,p[e2]), aget(a,p[e5])) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (cmp(aget(a,p[e2]), aget(a,p[e3])) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(aget(a,p[e4]), aget(a,p[e5])) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = cmp(aget(a,p1), aget(a,p2)) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(aget(a,ai), aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (cmp(aget(a,ai), aget(a,p2)) > 0) { while (cmp(aget(a,p[hi]), aget(a,p2)) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(aget(a,ai), aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(aget(a,ai), aget(a,p1)) == 0) continue; if (cmp(aget(a,ai), aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (cmp(aget(a,p[hi]), aget(a,p1)) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(aget(a,ai), aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (cmp(aget(a,p[lo]), aget(a,p1)) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (cmp(aget(a,p[i]), aget(a,p1)) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (cmp(aget(a,p[hi]), aget(a,p2)) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (cmp(aget(a,p[i]), aget(a,p2)) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && cmp(aget(a,ai), aget(a,p[j])) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSort( this int[] p, TArray a, Func aget, Func cmp) { int last = p.Length - 1; PermutationQuickSort(p, a, aget, cmp, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSort( this int[] p, TArray a, Func aget, Func cmp, int beginIncl, int endExcl) { PermutationQuickSort(p, a, aget, cmp, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSort( this int[] p, TArray a, Func aget, Func cmp, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (cmp(aget(a,p[e1]), aget(a,p[e2])) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (cmp(aget(a,p[e4]), aget(a,p[e5])) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (cmp(aget(a,p[e1]), aget(a,p[e3])) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (cmp(aget(a,p[e2]), aget(a,p[e3])) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(aget(a,p[e1]), aget(a,p[e4])) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (cmp(aget(a,p[e3]), aget(a,p[e4])) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (cmp(aget(a,p[e2]), aget(a,p[e5])) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (cmp(aget(a,p[e2]), aget(a,p[e3])) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(aget(a,p[e4]), aget(a,p[e5])) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = cmp(aget(a,p1), aget(a,p2)) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(aget(a,ai), aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (cmp(aget(a,ai), aget(a,p2)) > 0) { while (cmp(aget(a,p[hi]), aget(a,p2)) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(aget(a,ai), aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(aget(a,ai), aget(a,p1)) == 0) continue; if (cmp(aget(a,ai), aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (cmp(aget(a,p[hi]), aget(a,p1)) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(aget(a,ai), aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSort(p, a, aget, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, aget, cmp, hi + 2, r, cr); { while (cmp(aget(a,p[lo]), aget(a,p1)) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (cmp(aget(a,p[i]), aget(a,p1)) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (cmp(aget(a,p[hi]), aget(a,p2)) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (cmp(aget(a,p[i]), aget(a,p2)) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSort(p, a, aget, cmp, lo, hi, cm); PermutationQuickSort(p, a, aget, cmp, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSort(p, a, aget, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, aget, cmp, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSort(p, a, aget, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, aget, cmp, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSort(p, a, aget, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, aget, cmp, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSort(p, a, aget, cmp, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSort(p, a, aget, cmp, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && cmp(aget(a,ai), aget(a,p[j])) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSort( this int[] p, TArray a, Func aget, Func cmp, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (cmp(aget(a,element), aget(a,p[i2 + begin])) < 0) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && cmp(aget(a,p[i1 + begin]), aget(a,p[i2 + begin])) < 0) ? i2 : i1; // smaller child if (cmp(aget(a,p[ni + begin]), aget(a,element)) < 0) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSort( this int[] p, TArray a, Func aget, Func cmp) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (cmp(aget(a,element), aget(a,p[i2])) < 0) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && cmp(aget(a,p[i1]), aget(a,p[i2])) < 0) ? i2 : i1; // smaller child if (cmp(aget(a,p[ni]), aget(a,element)) < 0) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSort( this int[] p, TArray a, Func aget, Func cmp) { PermutationSmoothSortInclusiveRange(p, a, aget, cmp, 0, p.Length - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSort( this int[] p, TArray a, Func aget, Func cmp, int beginIncl, int endExcl) { PermutationSmoothSortInclusiveRange(p, a, aget, cmp, beginIncl, endExcl - 1); } private static void PermutationSmoothSortInclusiveRange( this int[] p, TArray a, Func aget, Func cmp, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortSift(p, a, aget, cmp, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortTrinkle(p, a, aget, cmp, pbits, pshift, head, false); else PermutationSmoothSortSift(p, a, aget, cmp, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortTrinkle(p, a, aget, cmp, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortTrinkle(p, a, aget, cmp, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortTrinkle(p, a, aget, cmp, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortSift( this int[] p, TArray a, Func aget, Func cmp, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (cmp(aget(a,val), aget(a,p[lf])) >= 0 && cmp(aget(a,val), aget(a,p[rt])) >= 0) break; if (cmp(aget(a,p[lf]), aget(a,p[rt])) >= 0) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortTrinkle( this int[] p, TArray a, Func aget, Func cmp, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (cmp(aget(a,vstepson), aget(a,val)) <= 0) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (cmp(aget(a,p[rt]), aget(a,vstepson)) >= 0 || cmp(aget(a,p[lf]), aget(a,vstepson)) >= 0) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortSift(p, a, aget, cmp, pshift, head); } } public class TimSortInfoPermGetCmp { public int[] m_p; public TArray m_a; public int m_count; public Func m_aget; public Func m_cmp; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoPermGetCmp(int[] p, TArray a, Func aget, Func cmp, int count) { m_p = p; m_a = a; m_count = count; m_aget = aget; m_cmp = cmp; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSort( this int[] p, TArray a, Func aget, Func cmp) { PermutationTimSort(p, a, aget, cmp, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSort( this int[] p, TArray a, Func aget, Func cmp, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrder(p, a, aget, cmp, lo, hi); PermutationBinarySort(p, a, aget, cmp, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermGetCmp(p, a, aget, cmp, count); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrder(p, a, aget, cmp, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySort(p, a, aget, cmp, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermCmp(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermCmp(ti); } private static void MergeCollapsePermCmp(this TimSortInfoPermGetCmp ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermCmp(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermCmp(ti, n); else break; } } private static void MergeForceCollapsePermCmp(this TimSortInfoPermGetCmp ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermCmp(ti, n); } } private static void MergeAtPermCmp(this TimSortInfoPermGetCmp ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRight(ti.m_p, a, ti.m_aget, ti.m_cmp, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeft(ti.m_p, a, ti.m_aget, ti.m_cmp, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermCmp(ti, start1, len1, start2, len2); else MergeHiPermCmp(ti, start1, len1, start2, len2); } private static void MergeLoPermCmp(this TimSortInfoPermGetCmp ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func cmp = ti.m_cmp; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (cmp(aget(a,p[idx2]), aget(a,t[idx1])) < 0) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRight(t, a, aget, cmp, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeft(p, a, aget, cmp, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermCmp(this TimSortInfoPermGetCmp ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func cmp = ti.m_cmp; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (cmp(aget(a,t[idx2]), aget(a,p[idx1])) < 0) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRight(p, a, aget, cmp, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeft(t, a, aget, cmp, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeft( this int[] p, TArray a, Func aget, Func cmp, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (cmp(aget(a,key), aget(a,p[start + hint])) > 0) { int maxOfs = len - hint; while (ofs < maxOfs && cmp(aget(a,key), aget(a,p[start + hint + ofs])) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && cmp(aget(a,key), aget(a,p[start + hint - ofs])) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (cmp(aget(a,key), aget(a,p[start + m])) > 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRight( this int[] p, TArray a, Func aget, Func cmp, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (cmp(aget(a,key), aget(a,p[start + hint])) < 0) { int maxOfs = hint + 1; while (ofs < maxOfs && cmp(aget(a,key), aget(a,p[start + hint - ofs])) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && cmp(aget(a,key), aget(a,p[start + hint + ofs])) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (cmp(aget(a,key), aget(a,p[start + m])) < 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySort( this int[] p, TArray a, Func aget, Func cmp, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (cmp(aget(a,pivot), aget(a,p[mid])) < 0) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrder( this int[] p, TArray a, Func aget, Func cmp, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (cmp(aget(a,p[runHi++]), aget(a,p[beginIncl])) < 0) { while (runHi < endExcl && cmp(aget(a,p[runHi]), aget(a,p[runHi - 1])) < 0) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && cmp(aget(a,p[runHi]), aget(a,p[runHi - 1])) >= 0) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedian( this long[] p, TArray a, Func aget, Func cmp, long med) { long last = p.LongLength - 1; PermutationQuickMedian(p, a, aget, cmp, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedian( this long[] p, TArray a, Func aget, Func cmp, long beginIncl, long endExcl, long med) { PermutationQuickMedian(p, a, aget, cmp, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedian( this long[] p, TArray a, Func aget, Func cmp, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (cmp(aget(a,p[e1]), aget(a,p[e2])) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (cmp(aget(a,p[e4]), aget(a,p[e5])) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (cmp(aget(a,p[e1]), aget(a,p[e3])) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (cmp(aget(a,p[e2]), aget(a,p[e3])) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(aget(a,p[e1]), aget(a,p[e4])) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (cmp(aget(a,p[e3]), aget(a,p[e4])) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (cmp(aget(a,p[e2]), aget(a,p[e5])) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (cmp(aget(a,p[e2]), aget(a,p[e3])) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(aget(a,p[e4]), aget(a,p[e5])) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = cmp(aget(a,p1), aget(a,p2)) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(aget(a,ai), aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (cmp(aget(a,ai), aget(a,p2)) > 0) { while (cmp(aget(a,p[hi]), aget(a,p2)) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(aget(a,ai), aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(aget(a,ai), aget(a,p1)) == 0) continue; if (cmp(aget(a,ai), aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (cmp(aget(a,p[hi]), aget(a,p1)) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(aget(a,ai), aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (cmp(aget(a,p[lo]), aget(a,p1)) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (cmp(aget(a,p[i]), aget(a,p1)) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (cmp(aget(a,p[hi]), aget(a,p2)) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (cmp(aget(a,p[i]), aget(a,p2)) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && cmp(aget(a,ai), aget(a,p[j])) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSort( this long[] p, TArray a, Func aget, Func cmp) { long last = p.LongLength - 1; PermutationQuickSort(p, a, aget, cmp, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSort( this long[] p, TArray a, Func aget, Func cmp, long beginIncl, long endExcl) { PermutationQuickSort(p, a, aget, cmp, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSort( this long[] p, TArray a, Func aget, Func cmp, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (cmp(aget(a,p[e1]), aget(a,p[e2])) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (cmp(aget(a,p[e4]), aget(a,p[e5])) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (cmp(aget(a,p[e1]), aget(a,p[e3])) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (cmp(aget(a,p[e2]), aget(a,p[e3])) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(aget(a,p[e1]), aget(a,p[e4])) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (cmp(aget(a,p[e3]), aget(a,p[e4])) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (cmp(aget(a,p[e2]), aget(a,p[e5])) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (cmp(aget(a,p[e2]), aget(a,p[e3])) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (cmp(aget(a,p[e4]), aget(a,p[e5])) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = cmp(aget(a,p1), aget(a,p2)) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(aget(a,ai), aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (cmp(aget(a,ai), aget(a,p2)) > 0) { while (cmp(aget(a,p[hi]), aget(a,p2)) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(aget(a,ai), aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (cmp(aget(a,ai), aget(a,p1)) == 0) continue; if (cmp(aget(a,ai), aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (cmp(aget(a,p[hi]), aget(a,p1)) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (cmp(aget(a,ai), aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSort(p, a, aget, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, aget, cmp, hi + 2, r, cr); { while (cmp(aget(a,p[lo]), aget(a,p1)) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (cmp(aget(a,p[i]), aget(a,p1)) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (cmp(aget(a,p[hi]), aget(a,p2)) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (cmp(aget(a,p[i]), aget(a,p2)) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSort(p, a, aget, cmp, lo, hi, cm); PermutationQuickSort(p, a, aget, cmp, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSort(p, a, aget, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, aget, cmp, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSort(p, a, aget, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, aget, cmp, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSort(p, a, aget, cmp, l, lo - 2, cl); PermutationQuickSort(p, a, aget, cmp, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSort(p, a, aget, cmp, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSort(p, a, aget, cmp, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && cmp(aget(a,ai), aget(a,p[j])) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSort( this long[] p, TArray a, Func aget, Func cmp, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (cmp(aget(a,element), aget(a,p[i2 + begin])) < 0) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && cmp(aget(a,p[i1 + begin]), aget(a,p[i2 + begin])) < 0) ? i2 : i1; // smaller child if (cmp(aget(a,p[ni + begin]), aget(a,element)) < 0) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSort( this long[] p, TArray a, Func aget, Func cmp) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (cmp(aget(a,element), aget(a,p[i2])) < 0) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && cmp(aget(a,p[i1]), aget(a,p[i2])) < 0) ? i2 : i1; // smaller child if (cmp(aget(a,p[ni]), aget(a,element)) < 0) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSort( this long[] p, TArray a, Func aget, Func cmp) { PermutationSmoothSortInclusiveRange(p, a, aget, cmp, 0, p.LongLength - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSort( this long[] p, TArray a, Func aget, Func cmp, long beginIncl, long endExcl) { PermutationSmoothSortInclusiveRange(p, a, aget, cmp, beginIncl, endExcl - 1); } private static void PermutationSmoothSortInclusiveRange( this long[] p, TArray a, Func aget, Func cmp, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortSift(p, a, aget, cmp, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortTrinkle(p, a, aget, cmp, pbits, pshift, head, false); else PermutationSmoothSortSift(p, a, aget, cmp, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortTrinkle(p, a, aget, cmp, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortTrinkle(p, a, aget, cmp, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortTrinkle(p, a, aget, cmp, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortSift( this long[] p, TArray a, Func aget, Func cmp, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (cmp(aget(a,val), aget(a,p[lf])) >= 0 && cmp(aget(a,val), aget(a,p[rt])) >= 0) break; if (cmp(aget(a,p[lf]), aget(a,p[rt])) >= 0) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortTrinkle( this long[] p, TArray a, Func aget, Func cmp, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (cmp(aget(a,vstepson), aget(a,val)) <= 0) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (cmp(aget(a,p[rt]), aget(a,vstepson)) >= 0 || cmp(aget(a,p[lf]), aget(a,vstepson)) >= 0) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortSift(p, a, aget, cmp, pshift, head); } } public class TimSortInfoPermLongGetCmp { public long[] m_p; public TArray m_a; public long m_count; public Func m_aget; public Func m_cmp; public long m_minGallop = c_minGallop; public long[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoPermLongGetCmp(long[] p, TArray a, Func aget, Func cmp, long count) { m_p = p; m_a = a; m_count = count; m_aget = aget; m_cmp = cmp; m_tmp = new long[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public long[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new long[c < 0 ? cap : Math.Min(c, m_p.LongLength >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSort( this long[] p, TArray a, Func aget, Func cmp) { PermutationTimSort(p, a, aget, cmp, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSort( this long[] p, TArray a, Func aget, Func cmp, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrder(p, a, aget, cmp, lo, hi); PermutationBinarySort(p, a, aget, cmp, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongGetCmp(p, a, aget, cmp, count); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrder(p, a, aget, cmp, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySort(p, a, aget, cmp, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongCmp(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongCmp(ti); } private static void MergeCollapsePermLongCmp(this TimSortInfoPermLongGetCmp ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongCmp(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongCmp(ti, n); else break; } } private static void MergeForceCollapsePermLongCmp(this TimSortInfoPermLongGetCmp ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongCmp(ti, n); } } private static void MergeAtPermLongCmp(this TimSortInfoPermLongGetCmp ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRight(ti.m_p, a, ti.m_aget, ti.m_cmp, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeft(ti.m_p, a, ti.m_aget, ti.m_cmp, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongCmp(ti, start1, len1, start2, len2); else MergeHiPermLongCmp(ti, start1, len1, start2, len2); } private static void MergeLoPermLongCmp(this TimSortInfoPermLongGetCmp ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func cmp = ti.m_cmp; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (cmp(aget(a,p[idx2]), aget(a,t[idx1])) < 0) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRight(t, a, aget, cmp, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeft(p, a, aget, cmp, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongCmp(this TimSortInfoPermLongGetCmp ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func cmp = ti.m_cmp; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (cmp(aget(a,t[idx2]), aget(a,p[idx1])) < 0) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRight(p, a, aget, cmp, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeft(t, a, aget, cmp, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeft( this long[] p, TArray a, Func aget, Func cmp, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (cmp(aget(a,key), aget(a,p[start + hint])) > 0) { long maxOfs = len - hint; while (ofs < maxOfs && cmp(aget(a,key), aget(a,p[start + hint + ofs])) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && cmp(aget(a,key), aget(a,p[start + hint - ofs])) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (cmp(aget(a,key), aget(a,p[start + m])) > 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRight( this long[] p, TArray a, Func aget, Func cmp, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (cmp(aget(a,key), aget(a,p[start + hint])) < 0) { long maxOfs = hint + 1; while (ofs < maxOfs && cmp(aget(a,key), aget(a,p[start + hint - ofs])) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && cmp(aget(a,key), aget(a,p[start + hint + ofs])) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (cmp(aget(a,key), aget(a,p[start + m])) < 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySort( this long[] p, TArray a, Func aget, Func cmp, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (cmp(aget(a,pivot), aget(a,p[mid])) < 0) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrder( this long[] p, TArray a, Func aget, Func cmp, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (cmp(aget(a,p[runHi++]), aget(a,p[beginIncl])) < 0) { while (runHi < endExcl && cmp(aget(a,p[runHi]), aget(a,p[runHi - 1])) < 0) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && cmp(aget(a,p[runHi]), aget(a,p[runHi - 1])) >= 0) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this int[] p, TArray a, Func aget, int med) where T : IComparable { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, aget, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this int[] p, TArray a, Func aget, int beginIncl, int endExcl, int med) where T : IComparable { PermutationQuickMedianAscending(p, a, aget, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, TArray a, Func aget, int l, int r, int countSub1, int med) where T : IComparable { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (aget(a,p[e1]).CompareTo(aget(a,p[e2])) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (aget(a,p[e4]).CompareTo(aget(a,p[e5])) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (aget(a,p[e1]).CompareTo(aget(a,p[e3])) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e3])) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (aget(a,p[e1]).CompareTo(aget(a,p[e4])) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (aget(a,p[e3]).CompareTo(aget(a,p[e4])) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e5])) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e3])) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (aget(a,p[e4]).CompareTo(aget(a,p[e5])) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = aget(a,p1).CompareTo(aget(a,p2)) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (aget(a,ai).CompareTo(aget(a,p2)) > 0) { while (aget(a,p[hi]).CompareTo(aget(a,p2)) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) == 0) continue; if (aget(a,ai).CompareTo(aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (aget(a,p[hi]).CompareTo(aget(a,p1)) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (aget(a,p[lo]).CompareTo(aget(a,p1)) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (aget(a,p[i]).CompareTo(aget(a,p1)) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (aget(a,p[hi]).CompareTo(aget(a,p2)) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (aget(a,p[i]).CompareTo(aget(a,p2)) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && aget(a,ai).CompareTo(aget(a,p[j])) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this int[] p, TArray a, Func aget) where T : IComparable { int last = p.Length - 1; PermutationQuickSortAscending(p, a, aget, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this int[] p, TArray a, Func aget, int beginIncl, int endExcl) where T : IComparable { PermutationQuickSortAscending(p, a, aget, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, TArray a, Func aget, int l, int r, int countSub1) where T : IComparable { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (aget(a,p[e1]).CompareTo(aget(a,p[e2])) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (aget(a,p[e4]).CompareTo(aget(a,p[e5])) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (aget(a,p[e1]).CompareTo(aget(a,p[e3])) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e3])) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (aget(a,p[e1]).CompareTo(aget(a,p[e4])) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (aget(a,p[e3]).CompareTo(aget(a,p[e4])) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e5])) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e3])) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (aget(a,p[e4]).CompareTo(aget(a,p[e5])) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = aget(a,p1).CompareTo(aget(a,p2)) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (aget(a,ai).CompareTo(aget(a,p2)) > 0) { while (aget(a,p[hi]).CompareTo(aget(a,p2)) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) == 0) continue; if (aget(a,ai).CompareTo(aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (aget(a,p[hi]).CompareTo(aget(a,p1)) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, aget, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, hi + 2, r, cr); { while (aget(a,p[lo]).CompareTo(aget(a,p1)) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (aget(a,p[i]).CompareTo(aget(a,p1)) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (aget(a,p[hi]).CompareTo(aget(a,p2)) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (aget(a,p[i]).CompareTo(aget(a,p2)) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, aget, lo, hi, cm); PermutationQuickSortAscending(p, a, aget, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, aget, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, aget, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, aget, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && aget(a,ai).CompareTo(aget(a,p[j])) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this int[] p, TArray a, Func aget, int begin, int end) where T : IComparable { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (aget(a,element).CompareTo(aget(a,p[i2 + begin])) < 0) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && aget(a,p[i1 + begin]).CompareTo(aget(a,p[i2 + begin])) < 0) ? i2 : i1; // smaller child if (aget(a,p[ni + begin]).CompareTo(aget(a,element)) < 0) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this int[] p, TArray a, Func aget) where T : IComparable { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (aget(a,element).CompareTo(aget(a,p[i2])) < 0) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && aget(a,p[i1]).CompareTo(aget(a,p[i2])) < 0) ? i2 : i1; // smaller child if (aget(a,p[ni]).CompareTo(aget(a,element)) < 0) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this int[] p, TArray a, Func aget) where T : IComparable { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, 0, p.Length - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this int[] p, TArray a, Func aget, int beginIncl, int endExcl) where T : IComparable { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, TArray a, Func aget, int lo, int hi) where T : IComparable { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, aget, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, aget, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, aget, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, aget, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, aget, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, aget, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, TArray a, Func aget, int pshift, int head) where T : IComparable { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (aget(a,val).CompareTo(aget(a,p[lf])) >= 0 && aget(a,val).CompareTo(aget(a,p[rt])) >= 0) break; if (aget(a,p[lf]).CompareTo(aget(a,p[rt])) >= 0) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, TArray a, Func aget, long pbits, int pshift, int head, bool isTrusty) where T : IComparable { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (aget(a,vstepson).CompareTo(aget(a,val)) <= 0) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (aget(a,p[rt]).CompareTo(aget(a,vstepson)) >= 0 || aget(a,p[lf]).CompareTo(aget(a,vstepson)) >= 0) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, aget, pshift, head); } } public class TimSortInfoPermGet where T : IComparable { public int[] m_p; public TArray m_a; public int m_count; public Func m_aget; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoPermGet(int[] p, TArray a, Func aget, int count) { m_p = p; m_a = a; m_count = count; m_aget = aget; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this int[] p, TArray a, Func aget) where T : IComparable { PermutationTimSortAscending(p, a, aget, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this int[] p, TArray a, Func aget, int lo, int hi) where T : IComparable { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, aget, lo, hi); PermutationBinarySortAscending(p, a, aget, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermGet(p, a, aget, count); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, aget, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, aget, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermAsc(ti); } private static void MergeCollapsePermAsc(this TimSortInfoPermGet ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermAsc(ti, n); else break; } } private static void MergeForceCollapsePermAsc(this TimSortInfoPermGet ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } } private static void MergeAtPermAsc(this TimSortInfoPermGet ti, int i) where T : IComparable { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_aget, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_aget, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermAsc(ti, start1, len1, start2, len2); else MergeHiPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermAsc(this TimSortInfoPermGet ti, int start1, int len1, int start2, int len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (aget(a,p[idx2]).CompareTo(aget(a,t[idx1])) < 0) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, aget, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, aget, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermAsc(this TimSortInfoPermGet ti, int start1, int len1, int start2, int len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (aget(a,t[idx2]).CompareTo(aget(a,p[idx1])) < 0) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, aget, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, aget, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, TArray a, Func aget, int key, int start, int len, int hint) where T : IComparable { int lastOfs = 0, ofs = 1; if (aget(a,key).CompareTo(aget(a,p[start + hint])) > 0) { int maxOfs = len - hint; while (ofs < maxOfs && aget(a,key).CompareTo(aget(a,p[start + hint + ofs])) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && aget(a,key).CompareTo(aget(a,p[start + hint - ofs])) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (aget(a,key).CompareTo(aget(a,p[start + m])) > 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, TArray a, Func aget, int key, int start, int len, int hint) where T : IComparable { int ofs = 1, lastOfs = 0; if (aget(a,key).CompareTo(aget(a,p[start + hint])) < 0) { int maxOfs = hint + 1; while (ofs < maxOfs && aget(a,key).CompareTo(aget(a,p[start + hint - ofs])) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && aget(a,key).CompareTo(aget(a,p[start + hint + ofs])) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (aget(a,key).CompareTo(aget(a,p[start + m])) < 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, TArray a, Func aget, int beginIncl, int endExcl, int beginUnsorted) where T : IComparable { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (aget(a,pivot).CompareTo(aget(a,p[mid])) < 0) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, TArray a, Func aget, int beginIncl, int endExcl) where T : IComparable { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (aget(a,p[runHi++]).CompareTo(aget(a,p[beginIncl])) < 0) { while (runHi < endExcl && aget(a,p[runHi]).CompareTo(aget(a,p[runHi - 1])) < 0) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && aget(a,p[runHi]).CompareTo(aget(a,p[runHi - 1])) >= 0) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this long[] p, TArray a, Func aget, long med) where T : IComparable { long last = p.LongLength - 1; PermutationQuickMedianAscending(p, a, aget, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this long[] p, TArray a, Func aget, long beginIncl, long endExcl, long med) where T : IComparable { PermutationQuickMedianAscending(p, a, aget, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this long[] p, TArray a, Func aget, long l, long r, long countSub1, long med) where T : IComparable { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (aget(a,p[e1]).CompareTo(aget(a,p[e2])) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (aget(a,p[e4]).CompareTo(aget(a,p[e5])) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (aget(a,p[e1]).CompareTo(aget(a,p[e3])) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e3])) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (aget(a,p[e1]).CompareTo(aget(a,p[e4])) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (aget(a,p[e3]).CompareTo(aget(a,p[e4])) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e5])) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e3])) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (aget(a,p[e4]).CompareTo(aget(a,p[e5])) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = aget(a,p1).CompareTo(aget(a,p2)) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (aget(a,ai).CompareTo(aget(a,p2)) > 0) { while (aget(a,p[hi]).CompareTo(aget(a,p2)) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) == 0) continue; if (aget(a,ai).CompareTo(aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (aget(a,p[hi]).CompareTo(aget(a,p1)) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (aget(a,p[lo]).CompareTo(aget(a,p1)) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (aget(a,p[i]).CompareTo(aget(a,p1)) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (aget(a,p[hi]).CompareTo(aget(a,p2)) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (aget(a,p[i]).CompareTo(aget(a,p2)) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && aget(a,ai).CompareTo(aget(a,p[j])) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this long[] p, TArray a, Func aget) where T : IComparable { long last = p.LongLength - 1; PermutationQuickSortAscending(p, a, aget, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this long[] p, TArray a, Func aget, long beginIncl, long endExcl) where T : IComparable { PermutationQuickSortAscending(p, a, aget, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this long[] p, TArray a, Func aget, long l, long r, long countSub1) where T : IComparable { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (aget(a,p[e1]).CompareTo(aget(a,p[e2])) > 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (aget(a,p[e4]).CompareTo(aget(a,p[e5])) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (aget(a,p[e1]).CompareTo(aget(a,p[e3])) > 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e3])) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (aget(a,p[e1]).CompareTo(aget(a,p[e4])) > 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (aget(a,p[e3]).CompareTo(aget(a,p[e4])) > 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e5])) > 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e3])) > 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (aget(a,p[e4]).CompareTo(aget(a,p[e5])) > 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = aget(a,p1).CompareTo(aget(a,p2)) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (aget(a,ai).CompareTo(aget(a,p2)) > 0) { while (aget(a,p[hi]).CompareTo(aget(a,p2)) > 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) == 0) continue; if (aget(a,ai).CompareTo(aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (aget(a,p[hi]).CompareTo(aget(a,p1)) > 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) < 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, aget, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, hi + 2, r, cr); { while (aget(a,p[lo]).CompareTo(aget(a,p1)) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (aget(a,p[i]).CompareTo(aget(a,p1)) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (aget(a,p[hi]).CompareTo(aget(a,p2)) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (aget(a,p[i]).CompareTo(aget(a,p2)) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, aget, lo, hi, cm); PermutationQuickSortAscending(p, a, aget, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, aget, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, aget, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, aget, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && aget(a,ai).CompareTo(aget(a,p[j])) < 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this long[] p, TArray a, Func aget, long begin, long end) where T : IComparable { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (aget(a,element).CompareTo(aget(a,p[i2 + begin])) < 0) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && aget(a,p[i1 + begin]).CompareTo(aget(a,p[i2 + begin])) < 0) ? i2 : i1; // smaller child if (aget(a,p[ni + begin]).CompareTo(aget(a,element)) < 0) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this long[] p, TArray a, Func aget) where T : IComparable { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (aget(a,element).CompareTo(aget(a,p[i2])) < 0) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && aget(a,p[i1]).CompareTo(aget(a,p[i2])) < 0) ? i2 : i1; // smaller child if (aget(a,p[ni]).CompareTo(aget(a,element)) < 0) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this long[] p, TArray a, Func aget) where T : IComparable { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, 0, p.LongLength - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this long[] p, TArray a, Func aget, long beginIncl, long endExcl) where T : IComparable { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this long[] p, TArray a, Func aget, long lo, long hi) where T : IComparable { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, aget, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, aget, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, aget, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, aget, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, aget, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, aget, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this long[] p, TArray a, Func aget, int pshift, long head) where T : IComparable { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (aget(a,val).CompareTo(aget(a,p[lf])) >= 0 && aget(a,val).CompareTo(aget(a,p[rt])) >= 0) break; if (aget(a,p[lf]).CompareTo(aget(a,p[rt])) >= 0) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this long[] p, TArray a, Func aget, long pbits, int pshift, long head, bool isTrusty) where T : IComparable { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (aget(a,vstepson).CompareTo(aget(a,val)) <= 0) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (aget(a,p[rt]).CompareTo(aget(a,vstepson)) >= 0 || aget(a,p[lf]).CompareTo(aget(a,vstepson)) >= 0) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, aget, pshift, head); } } public class TimSortInfoPermLongGet where T : IComparable { public long[] m_p; public TArray m_a; public long m_count; public Func m_aget; public long m_minGallop = c_minGallop; public long[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoPermLongGet(long[] p, TArray a, Func aget, long count) { m_p = p; m_a = a; m_count = count; m_aget = aget; m_tmp = new long[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public long[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new long[c < 0 ? cap : Math.Min(c, m_p.LongLength >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this long[] p, TArray a, Func aget) where T : IComparable { PermutationTimSortAscending(p, a, aget, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this long[] p, TArray a, Func aget, long lo, long hi) where T : IComparable { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, aget, lo, hi); PermutationBinarySortAscending(p, a, aget, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongGet(p, a, aget, count); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderAscending(p, a, aget, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, aget, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongAsc(ti); } private static void MergeCollapsePermLongAsc(this TimSortInfoPermLongGet ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongAsc(ti, n); else break; } } private static void MergeForceCollapsePermLongAsc(this TimSortInfoPermLongGet ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } } private static void MergeAtPermLongAsc(this TimSortInfoPermLongGet ti, int i) where T : IComparable { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightAscending(ti.m_p, a, ti.m_aget, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_aget, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongAsc(ti, start1, len1, start2, len2); else MergeHiPermLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongAsc(this TimSortInfoPermLongGet ti, long start1, long len1, long start2, long len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (aget(a,p[idx2]).CompareTo(aget(a,t[idx1])) < 0) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, aget, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, aget, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongAsc(this TimSortInfoPermLongGet ti, long start1, long len1, long start2, long len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (aget(a,t[idx2]).CompareTo(aget(a,p[idx1])) < 0) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, aget, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, aget, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftAscending( this long[] p, TArray a, Func aget, long key, long start, long len, long hint) where T : IComparable { long lastOfs = 0, ofs = 1; if (aget(a,key).CompareTo(aget(a,p[start + hint])) > 0) { long maxOfs = len - hint; while (ofs < maxOfs && aget(a,key).CompareTo(aget(a,p[start + hint + ofs])) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && aget(a,key).CompareTo(aget(a,p[start + hint - ofs])) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (aget(a,key).CompareTo(aget(a,p[start + m])) > 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightAscending( this long[] p, TArray a, Func aget, long key, long start, long len, long hint) where T : IComparable { long ofs = 1, lastOfs = 0; if (aget(a,key).CompareTo(aget(a,p[start + hint])) < 0) { long maxOfs = hint + 1; while (ofs < maxOfs && aget(a,key).CompareTo(aget(a,p[start + hint - ofs])) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && aget(a,key).CompareTo(aget(a,p[start + hint + ofs])) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (aget(a,key).CompareTo(aget(a,p[start + m])) < 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this long[] p, TArray a, Func aget, long beginIncl, long endExcl, long beginUnsorted) where T : IComparable { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (aget(a,pivot).CompareTo(aget(a,p[mid])) < 0) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderAscending( this long[] p, TArray a, Func aget, long beginIncl, long endExcl) where T : IComparable { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (aget(a,p[runHi++]).CompareTo(aget(a,p[beginIncl])) < 0) { while (runHi < endExcl && aget(a,p[runHi]).CompareTo(aget(a,p[runHi - 1])) < 0) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && aget(a,p[runHi]).CompareTo(aget(a,p[runHi - 1])) >= 0) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this int[] p, TArray a, Func aget, int med) where T : IComparable { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, aget, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this int[] p, TArray a, Func aget, int beginIncl, int endExcl, int med) where T : IComparable { PermutationQuickMedianDescending(p, a, aget, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, TArray a, Func aget, int l, int r, int countSub1, int med) where T : IComparable { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (aget(a,p[e1]).CompareTo(aget(a,p[e2])) < 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (aget(a,p[e4]).CompareTo(aget(a,p[e5])) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (aget(a,p[e1]).CompareTo(aget(a,p[e3])) < 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e3])) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (aget(a,p[e1]).CompareTo(aget(a,p[e4])) < 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (aget(a,p[e3]).CompareTo(aget(a,p[e4])) < 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e5])) < 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e3])) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (aget(a,p[e4]).CompareTo(aget(a,p[e5])) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = aget(a,p1).CompareTo(aget(a,p2)) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (aget(a,ai).CompareTo(aget(a,p2)) < 0) { while (aget(a,p[hi]).CompareTo(aget(a,p2)) < 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) == 0) continue; if (aget(a,ai).CompareTo(aget(a,p1)) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (aget(a,p[hi]).CompareTo(aget(a,p1)) < 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (aget(a,p[lo]).CompareTo(aget(a,p1)) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (aget(a,p[i]).CompareTo(aget(a,p1)) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (aget(a,p[hi]).CompareTo(aget(a,p2)) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (aget(a,p[i]).CompareTo(aget(a,p2)) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && aget(a,ai).CompareTo(aget(a,p[j])) > 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this int[] p, TArray a, Func aget) where T : IComparable { int last = p.Length - 1; PermutationQuickSortDescending(p, a, aget, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this int[] p, TArray a, Func aget, int beginIncl, int endExcl) where T : IComparable { PermutationQuickSortDescending(p, a, aget, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, TArray a, Func aget, int l, int r, int countSub1) where T : IComparable { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (aget(a,p[e1]).CompareTo(aget(a,p[e2])) < 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (aget(a,p[e4]).CompareTo(aget(a,p[e5])) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (aget(a,p[e1]).CompareTo(aget(a,p[e3])) < 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e3])) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (aget(a,p[e1]).CompareTo(aget(a,p[e4])) < 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (aget(a,p[e3]).CompareTo(aget(a,p[e4])) < 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e5])) < 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e3])) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (aget(a,p[e4]).CompareTo(aget(a,p[e5])) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = aget(a,p1).CompareTo(aget(a,p2)) != 0; if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (aget(a,ai).CompareTo(aget(a,p2)) < 0) { while (aget(a,p[hi]).CompareTo(aget(a,p2)) < 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) == 0) continue; if (aget(a,ai).CompareTo(aget(a,p1)) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (aget(a,p[hi]).CompareTo(aget(a,p1)) < 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, aget, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, hi + 2, r, cr); { while (aget(a,p[lo]).CompareTo(aget(a,p1)) == 0) ++lo; for (int i = lo + 1; i <= hi; i++) { if (aget(a,p[i]).CompareTo(aget(a,p1)) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (aget(a,p[hi]).CompareTo(aget(a,p2)) == 0) --hi; for (int i = hi - 1; i >= lo; i--) { if (aget(a,p[i]).CompareTo(aget(a,p2)) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, aget, lo, hi, cm); PermutationQuickSortDescending(p, a, aget, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, aget, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, aget, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, aget, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && aget(a,ai).CompareTo(aget(a,p[j])) > 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this int[] p, TArray a, Func aget, int begin, int end) where T : IComparable { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (aget(a,element).CompareTo(aget(a,p[i2 + begin])) > 0) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && aget(a,p[i1 + begin]).CompareTo(aget(a,p[i2 + begin])) > 0) ? i2 : i1; // smaller child if (aget(a,p[ni + begin]).CompareTo(aget(a,element)) > 0) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this int[] p, TArray a, Func aget) where T : IComparable { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (aget(a,element).CompareTo(aget(a,p[i2])) > 0) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && aget(a,p[i1]).CompareTo(aget(a,p[i2])) > 0) ? i2 : i1; // smaller child if (aget(a,p[ni]).CompareTo(aget(a,element)) > 0) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this int[] p, TArray a, Func aget) where T : IComparable { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, 0, p.Length - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this int[] p, TArray a, Func aget, int beginIncl, int endExcl) where T : IComparable { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, TArray a, Func aget, int lo, int hi) where T : IComparable { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, aget, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, aget, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, aget, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, aget, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, aget, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, aget, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, TArray a, Func aget, int pshift, int head) where T : IComparable { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (aget(a,val).CompareTo(aget(a,p[lf])) <= 0 && aget(a,val).CompareTo(aget(a,p[rt])) <= 0) break; if (aget(a,p[lf]).CompareTo(aget(a,p[rt])) <= 0) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, TArray a, Func aget, long pbits, int pshift, int head, bool isTrusty) where T : IComparable { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (aget(a,vstepson).CompareTo(aget(a,val)) >= 0) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (aget(a,p[rt]).CompareTo(aget(a,vstepson)) <= 0 || aget(a,p[lf]).CompareTo(aget(a,vstepson)) <= 0) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, aget, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this int[] p, TArray a, Func aget) where T : IComparable { PermutationTimSortDescending(p, a, aget, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this int[] p, TArray a, Func aget, int lo, int hi) where T : IComparable { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, aget, lo, hi); PermutationBinarySortDescending(p, a, aget, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermGet(p, a, aget, count); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, aget, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, aget, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermDesc(ti); } private static void MergeCollapsePermDesc(this TimSortInfoPermGet ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermDesc(ti, n); else break; } } private static void MergeForceCollapsePermDesc(this TimSortInfoPermGet ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } } private static void MergeAtPermDesc(this TimSortInfoPermGet ti, int i) where T : IComparable { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_aget, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_aget, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermDesc(ti, start1, len1, start2, len2); else MergeHiPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermDesc(this TimSortInfoPermGet ti, int start1, int len1, int start2, int len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (aget(a,p[idx2]).CompareTo(aget(a,t[idx1])) > 0) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, aget, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, aget, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermDesc(this TimSortInfoPermGet ti, int start1, int len1, int start2, int len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (aget(a,t[idx2]).CompareTo(aget(a,p[idx1])) > 0) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, aget, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, aget, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, TArray a, Func aget, int key, int start, int len, int hint) where T : IComparable { int lastOfs = 0, ofs = 1; if (aget(a,key).CompareTo(aget(a,p[start + hint])) < 0) { int maxOfs = len - hint; while (ofs < maxOfs && aget(a,key).CompareTo(aget(a,p[start + hint + ofs])) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && aget(a,key).CompareTo(aget(a,p[start + hint - ofs])) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (aget(a,key).CompareTo(aget(a,p[start + m])) < 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, TArray a, Func aget, int key, int start, int len, int hint) where T : IComparable { int ofs = 1, lastOfs = 0; if (aget(a,key).CompareTo(aget(a,p[start + hint])) > 0) { int maxOfs = hint + 1; while (ofs < maxOfs && aget(a,key).CompareTo(aget(a,p[start + hint - ofs])) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && aget(a,key).CompareTo(aget(a,p[start + hint + ofs])) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (aget(a,key).CompareTo(aget(a,p[start + m])) > 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, TArray a, Func aget, int beginIncl, int endExcl, int beginUnsorted) where T : IComparable { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (aget(a,pivot).CompareTo(aget(a,p[mid])) > 0) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, TArray a, Func aget, int beginIncl, int endExcl) where T : IComparable { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (aget(a,p[runHi++]).CompareTo(aget(a,p[beginIncl])) > 0) { while (runHi < endExcl && aget(a,p[runHi]).CompareTo(aget(a,p[runHi - 1])) > 0) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && aget(a,p[runHi]).CompareTo(aget(a,p[runHi - 1])) <= 0) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this long[] p, TArray a, Func aget, long med) where T : IComparable { long last = p.LongLength - 1; PermutationQuickMedianDescending(p, a, aget, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this long[] p, TArray a, Func aget, long beginIncl, long endExcl, long med) where T : IComparable { PermutationQuickMedianDescending(p, a, aget, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this long[] p, TArray a, Func aget, long l, long r, long countSub1, long med) where T : IComparable { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (aget(a,p[e1]).CompareTo(aget(a,p[e2])) < 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (aget(a,p[e4]).CompareTo(aget(a,p[e5])) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (aget(a,p[e1]).CompareTo(aget(a,p[e3])) < 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e3])) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (aget(a,p[e1]).CompareTo(aget(a,p[e4])) < 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (aget(a,p[e3]).CompareTo(aget(a,p[e4])) < 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e5])) < 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e3])) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (aget(a,p[e4]).CompareTo(aget(a,p[e5])) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = aget(a,p1).CompareTo(aget(a,p2)) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (aget(a,ai).CompareTo(aget(a,p2)) < 0) { while (aget(a,p[hi]).CompareTo(aget(a,p2)) < 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) == 0) continue; if (aget(a,ai).CompareTo(aget(a,p1)) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (aget(a,p[hi]).CompareTo(aget(a,p1)) < 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (aget(a,p[lo]).CompareTo(aget(a,p1)) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (aget(a,p[i]).CompareTo(aget(a,p1)) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (aget(a,p[hi]).CompareTo(aget(a,p2)) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (aget(a,p[i]).CompareTo(aget(a,p2)) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && aget(a,ai).CompareTo(aget(a,p[j])) > 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this long[] p, TArray a, Func aget) where T : IComparable { long last = p.LongLength - 1; PermutationQuickSortDescending(p, a, aget, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this long[] p, TArray a, Func aget, long beginIncl, long endExcl) where T : IComparable { PermutationQuickSortDescending(p, a, aget, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this long[] p, TArray a, Func aget, long l, long r, long countSub1) where T : IComparable { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (aget(a,p[e1]).CompareTo(aget(a,p[e2])) < 0) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (aget(a,p[e4]).CompareTo(aget(a,p[e5])) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (aget(a,p[e1]).CompareTo(aget(a,p[e3])) < 0) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e3])) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (aget(a,p[e1]).CompareTo(aget(a,p[e4])) < 0) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (aget(a,p[e3]).CompareTo(aget(a,p[e4])) < 0) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e5])) < 0) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (aget(a,p[e2]).CompareTo(aget(a,p[e3])) < 0) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (aget(a,p[e4]).CompareTo(aget(a,p[e5])) < 0) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = aget(a,p1).CompareTo(aget(a,p2)) != 0; if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (aget(a,ai).CompareTo(aget(a,p2)) < 0) { while (aget(a,p[hi]).CompareTo(aget(a,p2)) < 0 && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) == 0) continue; if (aget(a,ai).CompareTo(aget(a,p1)) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (aget(a,p[hi]).CompareTo(aget(a,p1)) < 0) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (aget(a,ai).CompareTo(aget(a,p1)) > 0) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, aget, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, hi + 2, r, cr); { while (aget(a,p[lo]).CompareTo(aget(a,p1)) == 0) ++lo; for (long i = lo + 1; i <= hi; i++) { if (aget(a,p[i]).CompareTo(aget(a,p1)) == 0) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (aget(a,p[hi]).CompareTo(aget(a,p2)) == 0) --hi; for (long i = hi - 1; i >= lo; i--) { if (aget(a,p[i]).CompareTo(aget(a,p2)) == 0) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, aget, lo, hi, cm); PermutationQuickSortDescending(p, a, aget, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, aget, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, aget, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, aget, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && aget(a,ai).CompareTo(aget(a,p[j])) > 0; j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this long[] p, TArray a, Func aget, long begin, long end) where T : IComparable { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (aget(a,element).CompareTo(aget(a,p[i2 + begin])) > 0) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && aget(a,p[i1 + begin]).CompareTo(aget(a,p[i2 + begin])) > 0) ? i2 : i1; // smaller child if (aget(a,p[ni + begin]).CompareTo(aget(a,element)) > 0) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this long[] p, TArray a, Func aget) where T : IComparable { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (aget(a,element).CompareTo(aget(a,p[i2])) > 0) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && aget(a,p[i1]).CompareTo(aget(a,p[i2])) > 0) ? i2 : i1; // smaller child if (aget(a,p[ni]).CompareTo(aget(a,element)) > 0) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this long[] p, TArray a, Func aget) where T : IComparable { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, 0, p.LongLength - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this long[] p, TArray a, Func aget, long beginIncl, long endExcl) where T : IComparable { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this long[] p, TArray a, Func aget, long lo, long hi) where T : IComparable { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, aget, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, aget, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, aget, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, aget, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, aget, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, aget, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this long[] p, TArray a, Func aget, int pshift, long head) where T : IComparable { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (aget(a,val).CompareTo(aget(a,p[lf])) <= 0 && aget(a,val).CompareTo(aget(a,p[rt])) <= 0) break; if (aget(a,p[lf]).CompareTo(aget(a,p[rt])) <= 0) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this long[] p, TArray a, Func aget, long pbits, int pshift, long head, bool isTrusty) where T : IComparable { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (aget(a,vstepson).CompareTo(aget(a,val)) >= 0) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (aget(a,p[rt]).CompareTo(aget(a,vstepson)) <= 0 || aget(a,p[lf]).CompareTo(aget(a,vstepson)) <= 0) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, aget, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this long[] p, TArray a, Func aget) where T : IComparable { PermutationTimSortDescending(p, a, aget, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this long[] p, TArray a, Func aget, long lo, long hi) where T : IComparable { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, aget, lo, hi); PermutationBinarySortDescending(p, a, aget, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongGet(p, a, aget, count); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderDescending(p, a, aget, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, aget, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongDesc(ti); } private static void MergeCollapsePermLongDesc(this TimSortInfoPermLongGet ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongDesc(ti, n); else break; } } private static void MergeForceCollapsePermLongDesc(this TimSortInfoPermLongGet ti) where T : IComparable { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } } private static void MergeAtPermLongDesc(this TimSortInfoPermLongGet ti, int i) where T : IComparable { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightDescending(ti.m_p, a, ti.m_aget, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_aget, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongDesc(ti, start1, len1, start2, len2); else MergeHiPermLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongDesc(this TimSortInfoPermLongGet ti, long start1, long len1, long start2, long len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (aget(a,p[idx2]).CompareTo(aget(a,t[idx1])) > 0) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, aget, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, aget, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongDesc(this TimSortInfoPermLongGet ti, long start1, long len1, long start2, long len2) where T : IComparable { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (aget(a,t[idx2]).CompareTo(aget(a,p[idx1])) > 0) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, aget, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, aget, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftDescending( this long[] p, TArray a, Func aget, long key, long start, long len, long hint) where T : IComparable { long lastOfs = 0, ofs = 1; if (aget(a,key).CompareTo(aget(a,p[start + hint])) < 0) { long maxOfs = len - hint; while (ofs < maxOfs && aget(a,key).CompareTo(aget(a,p[start + hint + ofs])) < 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && aget(a,key).CompareTo(aget(a,p[start + hint - ofs])) >= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (aget(a,key).CompareTo(aget(a,p[start + m])) < 0) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightDescending( this long[] p, TArray a, Func aget, long key, long start, long len, long hint) where T : IComparable { long ofs = 1, lastOfs = 0; if (aget(a,key).CompareTo(aget(a,p[start + hint])) > 0) { long maxOfs = hint + 1; while (ofs < maxOfs && aget(a,key).CompareTo(aget(a,p[start + hint - ofs])) > 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && aget(a,key).CompareTo(aget(a,p[start + hint + ofs])) <= 0) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (aget(a,key).CompareTo(aget(a,p[start + m])) > 0) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this long[] p, TArray a, Func aget, long beginIncl, long endExcl, long beginUnsorted) where T : IComparable { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (aget(a,pivot).CompareTo(aget(a,p[mid])) > 0) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderDescending( this long[] p, TArray a, Func aget, long beginIncl, long endExcl) where T : IComparable { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (aget(a,p[runHi++]).CompareTo(aget(a,p[beginIncl])) > 0) { while (runHi < endExcl && aget(a,p[runHi]).CompareTo(aget(a,p[runHi - 1])) > 0) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && aget(a,p[runHi]).CompareTo(aget(a,p[runHi - 1])) <= 0) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this int[] p, TArray a, Func aget, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, aget, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, TArray a, Func aget, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(aget(a,p[e1])) > selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) > selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) > selector(aget(a,p2))) { while (selector(aget(a,p[hi])) > selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) > selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(aget(a,ai)) < selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this int[] p, TArray a, Func aget, Func selector) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, aget, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, TArray a, Func aget, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(aget(a,p[e1])) > selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) > selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) > selector(aget(a,p2))) { while (selector(aget(a,p[hi])) > selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) > selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, aget, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(aget(a,ai)) < selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this int[] p, TArray a, Func aget, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(aget(a,element)) < selector(aget(a,p[i2 + begin]))) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(aget(a,p[i1 + begin])) < selector(aget(a,p[i2 + begin]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni + begin])) < selector(aget(a,element))) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this int[] p, TArray a, Func aget, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(aget(a,element)) < selector(aget(a,p[i2]))) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(aget(a,p[i1])) < selector(aget(a,p[i2]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni])) < selector(aget(a,element))) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this int[] p, TArray a, Func aget, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, selector, 0, p.Length - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, TArray a, Func aget, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, TArray a, Func aget, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(aget(a,val)) >= selector(aget(a,p[lf])) && selector(aget(a,val)) >= selector(aget(a,p[rt]))) break; if (selector(aget(a,p[lf])) >= selector(aget(a,p[rt]))) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, TArray a, Func aget, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(aget(a,vstepson)) <= selector(aget(a,val))) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(aget(a,p[rt])) >= selector(aget(a,vstepson)) || selector(aget(a,p[lf])) >= selector(aget(a,vstepson))) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); } } public class TimSortInfoPermGetIntSel { public int[] m_p; public TArray m_a; public int m_count; public Func m_aget; public Func m_sel; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoPermGetIntSel(int[] p, TArray a, Func aget, Func selector, int count) { m_p = p; m_a = a; m_count = count; m_aget = aget; m_sel = selector; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this int[] p, TArray a, Func aget, Func selector) { PermutationTimSortAscending(p, a, aget, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this int[] p, TArray a, Func aget, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, aget, selector, lo, hi); PermutationBinarySortAscending(p, a, aget, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermGetIntSel(p, a, aget, selector, count); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, aget, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, aget, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermAsc(ti); } private static void MergeCollapsePermAsc(this TimSortInfoPermGetIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermAsc(ti, n); else break; } } private static void MergeForceCollapsePermAsc(this TimSortInfoPermGetIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } } private static void MergeAtPermAsc(this TimSortInfoPermGetIntSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermAsc(ti, start1, len1, start2, len2); else MergeHiPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermAsc(this TimSortInfoPermGetIntSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(aget(a,p[idx2])) < selector(aget(a,t[idx1]))) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, aget, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, aget, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermAsc(this TimSortInfoPermGetIntSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(aget(a,t[idx2])) < selector(aget(a,p[idx1]))) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, aget, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, aget, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, TArray a, Func aget, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(aget(a,key)) > selector(aget(a,p[start + hint]))) { int maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) > selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) <= selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) > selector(aget(a,p[start + m]))) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, TArray a, Func aget, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(aget(a,key)) < selector(aget(a,p[start + hint]))) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) < selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) >= selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) < selector(aget(a,p[start + m]))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(aget(a,pivot)) < selector(aget(a,p[mid]))) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a,p[runHi++])) < selector(aget(a,p[beginIncl]))) { while (runHi < endExcl && selector(aget(a,p[runHi])) < selector(aget(a,p[runHi - 1]))) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a,p[runHi])) >= selector(aget(a,p[runHi - 1]))) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this long[] p, TArray a, Func aget, Func selector, long med) { long last = p.LongLength - 1; PermutationQuickMedianAscending(p, a, aget, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl, long med) { PermutationQuickMedianAscending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this long[] p, TArray a, Func aget, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a,p[e1])) > selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) > selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) > selector(aget(a,p2))) { while (selector(aget(a,p[hi])) > selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) > selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(aget(a,ai)) < selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this long[] p, TArray a, Func aget, Func selector) { long last = p.LongLength - 1; PermutationQuickSortAscending(p, a, aget, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { PermutationQuickSortAscending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this long[] p, TArray a, Func aget, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a,p[e1])) > selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) > selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) > selector(aget(a,p2))) { while (selector(aget(a,p[hi])) > selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) > selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, aget, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(aget(a,ai)) < selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this long[] p, TArray a, Func aget, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(aget(a,element)) < selector(aget(a,p[i2 + begin]))) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a,p[i1 + begin])) < selector(aget(a,p[i2 + begin]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni + begin])) < selector(aget(a,element))) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this long[] p, TArray a, Func aget, Func selector) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(aget(a,element)) < selector(aget(a,p[i2]))) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a,p[i1])) < selector(aget(a,p[i2]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni])) < selector(aget(a,element))) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this long[] p, TArray a, Func aget, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, selector, 0, p.LongLength - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this long[] p, TArray a, Func aget, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this long[] p, TArray a, Func aget, Func selector, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a,val)) >= selector(aget(a,p[lf])) && selector(aget(a,val)) >= selector(aget(a,p[rt]))) break; if (selector(aget(a,p[lf])) >= selector(aget(a,p[rt]))) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this long[] p, TArray a, Func aget, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (selector(aget(a,vstepson)) <= selector(aget(a,val))) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a,p[rt])) >= selector(aget(a,vstepson)) || selector(aget(a,p[lf])) >= selector(aget(a,vstepson))) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); } } public class TimSortInfoPermLongGetIntSel { public long[] m_p; public TArray m_a; public long m_count; public Func m_aget; public Func m_sel; public long m_minGallop = c_minGallop; public long[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoPermLongGetIntSel(long[] p, TArray a, Func aget, Func selector, long count) { m_p = p; m_a = a; m_count = count; m_aget = aget; m_sel = selector; m_tmp = new long[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public long[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new long[c < 0 ? cap : Math.Min(c, m_p.LongLength >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this long[] p, TArray a, Func aget, Func selector) { PermutationTimSortAscending(p, a, aget, selector, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this long[] p, TArray a, Func aget, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, aget, selector, lo, hi); PermutationBinarySortAscending(p, a, aget, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongGetIntSel(p, a, aget, selector, count); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderAscending(p, a, aget, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, aget, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongAsc(ti); } private static void MergeCollapsePermLongAsc(this TimSortInfoPermLongGetIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongAsc(ti, n); else break; } } private static void MergeForceCollapsePermLongAsc(this TimSortInfoPermLongGetIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } } private static void MergeAtPermLongAsc(this TimSortInfoPermLongGetIntSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightAscending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongAsc(ti, start1, len1, start2, len2); else MergeHiPermLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongAsc(this TimSortInfoPermLongGetIntSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a,p[idx2])) < selector(aget(a,t[idx1]))) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, aget, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, aget, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongAsc(this TimSortInfoPermLongGetIntSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a,t[idx2])) < selector(aget(a,p[idx1]))) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, aget, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, aget, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftAscending( this long[] p, TArray a, Func aget, Func selector, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(aget(a,key)) > selector(aget(a,p[start + hint]))) { long maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) > selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) <= selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) > selector(aget(a,p[start + m]))) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightAscending( this long[] p, TArray a, Func aget, Func selector, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(aget(a,key)) < selector(aget(a,p[start + hint]))) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) < selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) >= selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) < selector(aget(a,p[start + m]))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(aget(a,pivot)) < selector(aget(a,p[mid]))) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a,p[runHi++])) < selector(aget(a,p[beginIncl]))) { while (runHi < endExcl && selector(aget(a,p[runHi])) < selector(aget(a,p[runHi - 1]))) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a,p[runHi])) >= selector(aget(a,p[runHi - 1]))) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this int[] p, TArray a, Func aget, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, aget, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, TArray a, Func aget, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(aget(a,p[e1])) < selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) < selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) < selector(aget(a,p2))) { while (selector(aget(a,p[hi])) < selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) < selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(aget(a,ai)) > selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this int[] p, TArray a, Func aget, Func selector) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, aget, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, TArray a, Func aget, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(aget(a,p[e1])) < selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) < selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) < selector(aget(a,p2))) { while (selector(aget(a,p[hi])) < selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) < selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, aget, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(aget(a,ai)) > selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this int[] p, TArray a, Func aget, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(aget(a,element)) > selector(aget(a,p[i2 + begin]))) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(aget(a,p[i1 + begin])) > selector(aget(a,p[i2 + begin]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni + begin])) > selector(aget(a,element))) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this int[] p, TArray a, Func aget, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(aget(a,element)) > selector(aget(a,p[i2]))) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(aget(a,p[i1])) > selector(aget(a,p[i2]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni])) > selector(aget(a,element))) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this int[] p, TArray a, Func aget, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, selector, 0, p.Length - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, TArray a, Func aget, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, TArray a, Func aget, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(aget(a,val)) <= selector(aget(a,p[lf])) && selector(aget(a,val)) <= selector(aget(a,p[rt]))) break; if (selector(aget(a,p[lf])) <= selector(aget(a,p[rt]))) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, TArray a, Func aget, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(aget(a,vstepson)) >= selector(aget(a,val))) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(aget(a,p[rt])) <= selector(aget(a,vstepson)) || selector(aget(a,p[lf])) <= selector(aget(a,vstepson))) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this int[] p, TArray a, Func aget, Func selector) { PermutationTimSortDescending(p, a, aget, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this int[] p, TArray a, Func aget, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, aget, selector, lo, hi); PermutationBinarySortDescending(p, a, aget, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermGetIntSel(p, a, aget, selector, count); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, aget, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, aget, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermDesc(ti); } private static void MergeCollapsePermDesc(this TimSortInfoPermGetIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermDesc(ti, n); else break; } } private static void MergeForceCollapsePermDesc(this TimSortInfoPermGetIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } } private static void MergeAtPermDesc(this TimSortInfoPermGetIntSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermDesc(ti, start1, len1, start2, len2); else MergeHiPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermDesc(this TimSortInfoPermGetIntSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(aget(a,p[idx2])) > selector(aget(a,t[idx1]))) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, aget, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, aget, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermDesc(this TimSortInfoPermGetIntSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(aget(a,t[idx2])) > selector(aget(a,p[idx1]))) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, aget, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, aget, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, TArray a, Func aget, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(aget(a,key)) < selector(aget(a,p[start + hint]))) { int maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) < selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) >= selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) < selector(aget(a,p[start + m]))) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, TArray a, Func aget, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(aget(a,key)) > selector(aget(a,p[start + hint]))) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) > selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) <= selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) > selector(aget(a,p[start + m]))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(aget(a,pivot)) > selector(aget(a,p[mid]))) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a,p[runHi++])) > selector(aget(a,p[beginIncl]))) { while (runHi < endExcl && selector(aget(a,p[runHi])) > selector(aget(a,p[runHi - 1]))) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a,p[runHi])) <= selector(aget(a,p[runHi - 1]))) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this long[] p, TArray a, Func aget, Func selector, long med) { long last = p.LongLength - 1; PermutationQuickMedianDescending(p, a, aget, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl, long med) { PermutationQuickMedianDescending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this long[] p, TArray a, Func aget, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a,p[e1])) < selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) < selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) < selector(aget(a,p2))) { while (selector(aget(a,p[hi])) < selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) < selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(aget(a,ai)) > selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this long[] p, TArray a, Func aget, Func selector) { long last = p.LongLength - 1; PermutationQuickSortDescending(p, a, aget, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { PermutationQuickSortDescending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this long[] p, TArray a, Func aget, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a,p[e1])) < selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) < selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) < selector(aget(a,p2))) { while (selector(aget(a,p[hi])) < selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) < selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, aget, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(aget(a,ai)) > selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this long[] p, TArray a, Func aget, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(aget(a,element)) > selector(aget(a,p[i2 + begin]))) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a,p[i1 + begin])) > selector(aget(a,p[i2 + begin]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni + begin])) > selector(aget(a,element))) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this long[] p, TArray a, Func aget, Func selector) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(aget(a,element)) > selector(aget(a,p[i2]))) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a,p[i1])) > selector(aget(a,p[i2]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni])) > selector(aget(a,element))) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this long[] p, TArray a, Func aget, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, selector, 0, p.LongLength - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this long[] p, TArray a, Func aget, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this long[] p, TArray a, Func aget, Func selector, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a,val)) <= selector(aget(a,p[lf])) && selector(aget(a,val)) <= selector(aget(a,p[rt]))) break; if (selector(aget(a,p[lf])) <= selector(aget(a,p[rt]))) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this long[] p, TArray a, Func aget, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (selector(aget(a,vstepson)) >= selector(aget(a,val))) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a,p[rt])) <= selector(aget(a,vstepson)) || selector(aget(a,p[lf])) <= selector(aget(a,vstepson))) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this long[] p, TArray a, Func aget, Func selector) { PermutationTimSortDescending(p, a, aget, selector, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this long[] p, TArray a, Func aget, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, aget, selector, lo, hi); PermutationBinarySortDescending(p, a, aget, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongGetIntSel(p, a, aget, selector, count); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderDescending(p, a, aget, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, aget, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongDesc(ti); } private static void MergeCollapsePermLongDesc(this TimSortInfoPermLongGetIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongDesc(ti, n); else break; } } private static void MergeForceCollapsePermLongDesc(this TimSortInfoPermLongGetIntSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } } private static void MergeAtPermLongDesc(this TimSortInfoPermLongGetIntSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightDescending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongDesc(ti, start1, len1, start2, len2); else MergeHiPermLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongDesc(this TimSortInfoPermLongGetIntSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a,p[idx2])) > selector(aget(a,t[idx1]))) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, aget, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, aget, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongDesc(this TimSortInfoPermLongGetIntSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a,t[idx2])) > selector(aget(a,p[idx1]))) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, aget, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, aget, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftDescending( this long[] p, TArray a, Func aget, Func selector, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(aget(a,key)) < selector(aget(a,p[start + hint]))) { long maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) < selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) >= selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) < selector(aget(a,p[start + m]))) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightDescending( this long[] p, TArray a, Func aget, Func selector, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(aget(a,key)) > selector(aget(a,p[start + hint]))) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) > selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) <= selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) > selector(aget(a,p[start + m]))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(aget(a,pivot)) > selector(aget(a,p[mid]))) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a,p[runHi++])) > selector(aget(a,p[beginIncl]))) { while (runHi < endExcl && selector(aget(a,p[runHi])) > selector(aget(a,p[runHi - 1]))) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a,p[runHi])) <= selector(aget(a,p[runHi - 1]))) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this int[] p, TArray a, Func aget, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, aget, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, TArray a, Func aget, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(aget(a,p[e1])) > selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) > selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) > selector(aget(a,p2))) { while (selector(aget(a,p[hi])) > selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) > selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(aget(a,ai)) < selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this int[] p, TArray a, Func aget, Func selector) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, aget, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, TArray a, Func aget, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(aget(a,p[e1])) > selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) > selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) > selector(aget(a,p2))) { while (selector(aget(a,p[hi])) > selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) > selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, aget, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(aget(a,ai)) < selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this int[] p, TArray a, Func aget, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(aget(a,element)) < selector(aget(a,p[i2 + begin]))) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(aget(a,p[i1 + begin])) < selector(aget(a,p[i2 + begin]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni + begin])) < selector(aget(a,element))) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this int[] p, TArray a, Func aget, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(aget(a,element)) < selector(aget(a,p[i2]))) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(aget(a,p[i1])) < selector(aget(a,p[i2]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni])) < selector(aget(a,element))) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this int[] p, TArray a, Func aget, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, selector, 0, p.Length - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, TArray a, Func aget, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, TArray a, Func aget, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(aget(a,val)) >= selector(aget(a,p[lf])) && selector(aget(a,val)) >= selector(aget(a,p[rt]))) break; if (selector(aget(a,p[lf])) >= selector(aget(a,p[rt]))) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, TArray a, Func aget, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(aget(a,vstepson)) <= selector(aget(a,val))) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(aget(a,p[rt])) >= selector(aget(a,vstepson)) || selector(aget(a,p[lf])) >= selector(aget(a,vstepson))) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); } } public class TimSortInfoPermGetLongSel { public int[] m_p; public TArray m_a; public int m_count; public Func m_aget; public Func m_sel; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoPermGetLongSel(int[] p, TArray a, Func aget, Func selector, int count) { m_p = p; m_a = a; m_count = count; m_aget = aget; m_sel = selector; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this int[] p, TArray a, Func aget, Func selector) { PermutationTimSortAscending(p, a, aget, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this int[] p, TArray a, Func aget, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, aget, selector, lo, hi); PermutationBinarySortAscending(p, a, aget, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermGetLongSel(p, a, aget, selector, count); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, aget, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, aget, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermAsc(ti); } private static void MergeCollapsePermAsc(this TimSortInfoPermGetLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermAsc(ti, n); else break; } } private static void MergeForceCollapsePermAsc(this TimSortInfoPermGetLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } } private static void MergeAtPermAsc(this TimSortInfoPermGetLongSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermAsc(ti, start1, len1, start2, len2); else MergeHiPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermAsc(this TimSortInfoPermGetLongSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(aget(a,p[idx2])) < selector(aget(a,t[idx1]))) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, aget, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, aget, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermAsc(this TimSortInfoPermGetLongSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(aget(a,t[idx2])) < selector(aget(a,p[idx1]))) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, aget, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, aget, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, TArray a, Func aget, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(aget(a,key)) > selector(aget(a,p[start + hint]))) { int maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) > selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) <= selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) > selector(aget(a,p[start + m]))) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, TArray a, Func aget, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(aget(a,key)) < selector(aget(a,p[start + hint]))) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) < selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) >= selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) < selector(aget(a,p[start + m]))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(aget(a,pivot)) < selector(aget(a,p[mid]))) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a,p[runHi++])) < selector(aget(a,p[beginIncl]))) { while (runHi < endExcl && selector(aget(a,p[runHi])) < selector(aget(a,p[runHi - 1]))) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a,p[runHi])) >= selector(aget(a,p[runHi - 1]))) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this long[] p, TArray a, Func aget, Func selector, long med) { long last = p.LongLength - 1; PermutationQuickMedianAscending(p, a, aget, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl, long med) { PermutationQuickMedianAscending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this long[] p, TArray a, Func aget, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a,p[e1])) > selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) > selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) > selector(aget(a,p2))) { while (selector(aget(a,p[hi])) > selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) > selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(aget(a,ai)) < selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this long[] p, TArray a, Func aget, Func selector) { long last = p.LongLength - 1; PermutationQuickSortAscending(p, a, aget, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { PermutationQuickSortAscending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this long[] p, TArray a, Func aget, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a,p[e1])) > selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) > selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) > selector(aget(a,p2))) { while (selector(aget(a,p[hi])) > selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) > selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, aget, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(aget(a,ai)) < selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this long[] p, TArray a, Func aget, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(aget(a,element)) < selector(aget(a,p[i2 + begin]))) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a,p[i1 + begin])) < selector(aget(a,p[i2 + begin]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni + begin])) < selector(aget(a,element))) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this long[] p, TArray a, Func aget, Func selector) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(aget(a,element)) < selector(aget(a,p[i2]))) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a,p[i1])) < selector(aget(a,p[i2]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni])) < selector(aget(a,element))) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this long[] p, TArray a, Func aget, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, selector, 0, p.LongLength - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this long[] p, TArray a, Func aget, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this long[] p, TArray a, Func aget, Func selector, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a,val)) >= selector(aget(a,p[lf])) && selector(aget(a,val)) >= selector(aget(a,p[rt]))) break; if (selector(aget(a,p[lf])) >= selector(aget(a,p[rt]))) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this long[] p, TArray a, Func aget, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (selector(aget(a,vstepson)) <= selector(aget(a,val))) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a,p[rt])) >= selector(aget(a,vstepson)) || selector(aget(a,p[lf])) >= selector(aget(a,vstepson))) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); } } public class TimSortInfoPermLongGetLongSel { public long[] m_p; public TArray m_a; public long m_count; public Func m_aget; public Func m_sel; public long m_minGallop = c_minGallop; public long[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoPermLongGetLongSel(long[] p, TArray a, Func aget, Func selector, long count) { m_p = p; m_a = a; m_count = count; m_aget = aget; m_sel = selector; m_tmp = new long[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public long[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new long[c < 0 ? cap : Math.Min(c, m_p.LongLength >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this long[] p, TArray a, Func aget, Func selector) { PermutationTimSortAscending(p, a, aget, selector, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this long[] p, TArray a, Func aget, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, aget, selector, lo, hi); PermutationBinarySortAscending(p, a, aget, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongGetLongSel(p, a, aget, selector, count); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderAscending(p, a, aget, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, aget, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongAsc(ti); } private static void MergeCollapsePermLongAsc(this TimSortInfoPermLongGetLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongAsc(ti, n); else break; } } private static void MergeForceCollapsePermLongAsc(this TimSortInfoPermLongGetLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } } private static void MergeAtPermLongAsc(this TimSortInfoPermLongGetLongSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightAscending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongAsc(ti, start1, len1, start2, len2); else MergeHiPermLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongAsc(this TimSortInfoPermLongGetLongSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a,p[idx2])) < selector(aget(a,t[idx1]))) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, aget, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, aget, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongAsc(this TimSortInfoPermLongGetLongSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a,t[idx2])) < selector(aget(a,p[idx1]))) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, aget, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, aget, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftAscending( this long[] p, TArray a, Func aget, Func selector, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(aget(a,key)) > selector(aget(a,p[start + hint]))) { long maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) > selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) <= selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) > selector(aget(a,p[start + m]))) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightAscending( this long[] p, TArray a, Func aget, Func selector, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(aget(a,key)) < selector(aget(a,p[start + hint]))) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) < selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) >= selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) < selector(aget(a,p[start + m]))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(aget(a,pivot)) < selector(aget(a,p[mid]))) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a,p[runHi++])) < selector(aget(a,p[beginIncl]))) { while (runHi < endExcl && selector(aget(a,p[runHi])) < selector(aget(a,p[runHi - 1]))) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a,p[runHi])) >= selector(aget(a,p[runHi - 1]))) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this int[] p, TArray a, Func aget, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, aget, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, TArray a, Func aget, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(aget(a,p[e1])) < selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) < selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) < selector(aget(a,p2))) { while (selector(aget(a,p[hi])) < selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) < selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(aget(a,ai)) > selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this int[] p, TArray a, Func aget, Func selector) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, aget, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, TArray a, Func aget, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(aget(a,p[e1])) < selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) < selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) < selector(aget(a,p2))) { while (selector(aget(a,p[hi])) < selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) < selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, aget, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(aget(a,ai)) > selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this int[] p, TArray a, Func aget, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(aget(a,element)) > selector(aget(a,p[i2 + begin]))) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(aget(a,p[i1 + begin])) > selector(aget(a,p[i2 + begin]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni + begin])) > selector(aget(a,element))) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this int[] p, TArray a, Func aget, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(aget(a,element)) > selector(aget(a,p[i2]))) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(aget(a,p[i1])) > selector(aget(a,p[i2]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni])) > selector(aget(a,element))) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this int[] p, TArray a, Func aget, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, selector, 0, p.Length - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, TArray a, Func aget, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, TArray a, Func aget, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(aget(a,val)) <= selector(aget(a,p[lf])) && selector(aget(a,val)) <= selector(aget(a,p[rt]))) break; if (selector(aget(a,p[lf])) <= selector(aget(a,p[rt]))) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, TArray a, Func aget, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(aget(a,vstepson)) >= selector(aget(a,val))) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(aget(a,p[rt])) <= selector(aget(a,vstepson)) || selector(aget(a,p[lf])) <= selector(aget(a,vstepson))) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this int[] p, TArray a, Func aget, Func selector) { PermutationTimSortDescending(p, a, aget, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this int[] p, TArray a, Func aget, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, aget, selector, lo, hi); PermutationBinarySortDescending(p, a, aget, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermGetLongSel(p, a, aget, selector, count); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, aget, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, aget, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermDesc(ti); } private static void MergeCollapsePermDesc(this TimSortInfoPermGetLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermDesc(ti, n); else break; } } private static void MergeForceCollapsePermDesc(this TimSortInfoPermGetLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } } private static void MergeAtPermDesc(this TimSortInfoPermGetLongSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermDesc(ti, start1, len1, start2, len2); else MergeHiPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermDesc(this TimSortInfoPermGetLongSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(aget(a,p[idx2])) > selector(aget(a,t[idx1]))) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, aget, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, aget, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermDesc(this TimSortInfoPermGetLongSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(aget(a,t[idx2])) > selector(aget(a,p[idx1]))) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, aget, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, aget, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, TArray a, Func aget, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(aget(a,key)) < selector(aget(a,p[start + hint]))) { int maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) < selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) >= selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) < selector(aget(a,p[start + m]))) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, TArray a, Func aget, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(aget(a,key)) > selector(aget(a,p[start + hint]))) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) > selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) <= selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) > selector(aget(a,p[start + m]))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(aget(a,pivot)) > selector(aget(a,p[mid]))) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a,p[runHi++])) > selector(aget(a,p[beginIncl]))) { while (runHi < endExcl && selector(aget(a,p[runHi])) > selector(aget(a,p[runHi - 1]))) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a,p[runHi])) <= selector(aget(a,p[runHi - 1]))) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this long[] p, TArray a, Func aget, Func selector, long med) { long last = p.LongLength - 1; PermutationQuickMedianDescending(p, a, aget, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl, long med) { PermutationQuickMedianDescending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this long[] p, TArray a, Func aget, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a,p[e1])) < selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) < selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) < selector(aget(a,p2))) { while (selector(aget(a,p[hi])) < selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) < selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(aget(a,ai)) > selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this long[] p, TArray a, Func aget, Func selector) { long last = p.LongLength - 1; PermutationQuickSortDescending(p, a, aget, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { PermutationQuickSortDescending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this long[] p, TArray a, Func aget, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a,p[e1])) < selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) < selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) < selector(aget(a,p2))) { while (selector(aget(a,p[hi])) < selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) < selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, aget, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(aget(a,ai)) > selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this long[] p, TArray a, Func aget, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(aget(a,element)) > selector(aget(a,p[i2 + begin]))) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a,p[i1 + begin])) > selector(aget(a,p[i2 + begin]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni + begin])) > selector(aget(a,element))) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this long[] p, TArray a, Func aget, Func selector) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(aget(a,element)) > selector(aget(a,p[i2]))) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a,p[i1])) > selector(aget(a,p[i2]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni])) > selector(aget(a,element))) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this long[] p, TArray a, Func aget, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, selector, 0, p.LongLength - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this long[] p, TArray a, Func aget, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this long[] p, TArray a, Func aget, Func selector, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a,val)) <= selector(aget(a,p[lf])) && selector(aget(a,val)) <= selector(aget(a,p[rt]))) break; if (selector(aget(a,p[lf])) <= selector(aget(a,p[rt]))) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this long[] p, TArray a, Func aget, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (selector(aget(a,vstepson)) >= selector(aget(a,val))) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a,p[rt])) <= selector(aget(a,vstepson)) || selector(aget(a,p[lf])) <= selector(aget(a,vstepson))) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this long[] p, TArray a, Func aget, Func selector) { PermutationTimSortDescending(p, a, aget, selector, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this long[] p, TArray a, Func aget, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, aget, selector, lo, hi); PermutationBinarySortDescending(p, a, aget, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongGetLongSel(p, a, aget, selector, count); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderDescending(p, a, aget, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, aget, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongDesc(ti); } private static void MergeCollapsePermLongDesc(this TimSortInfoPermLongGetLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongDesc(ti, n); else break; } } private static void MergeForceCollapsePermLongDesc(this TimSortInfoPermLongGetLongSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } } private static void MergeAtPermLongDesc(this TimSortInfoPermLongGetLongSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightDescending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongDesc(ti, start1, len1, start2, len2); else MergeHiPermLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongDesc(this TimSortInfoPermLongGetLongSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a,p[idx2])) > selector(aget(a,t[idx1]))) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, aget, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, aget, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongDesc(this TimSortInfoPermLongGetLongSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a,t[idx2])) > selector(aget(a,p[idx1]))) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, aget, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, aget, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftDescending( this long[] p, TArray a, Func aget, Func selector, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(aget(a,key)) < selector(aget(a,p[start + hint]))) { long maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) < selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) >= selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) < selector(aget(a,p[start + m]))) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightDescending( this long[] p, TArray a, Func aget, Func selector, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(aget(a,key)) > selector(aget(a,p[start + hint]))) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) > selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) <= selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) > selector(aget(a,p[start + m]))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(aget(a,pivot)) > selector(aget(a,p[mid]))) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a,p[runHi++])) > selector(aget(a,p[beginIncl]))) { while (runHi < endExcl && selector(aget(a,p[runHi])) > selector(aget(a,p[runHi - 1]))) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a,p[runHi])) <= selector(aget(a,p[runHi - 1]))) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this int[] p, TArray a, Func aget, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, aget, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, TArray a, Func aget, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(aget(a,p[e1])) > selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) > selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) > selector(aget(a,p2))) { while (selector(aget(a,p[hi])) > selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) > selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(aget(a,ai)) < selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this int[] p, TArray a, Func aget, Func selector) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, aget, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, TArray a, Func aget, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(aget(a,p[e1])) > selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) > selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) > selector(aget(a,p2))) { while (selector(aget(a,p[hi])) > selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) > selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, aget, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(aget(a,ai)) < selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this int[] p, TArray a, Func aget, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(aget(a,element)) < selector(aget(a,p[i2 + begin]))) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(aget(a,p[i1 + begin])) < selector(aget(a,p[i2 + begin]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni + begin])) < selector(aget(a,element))) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this int[] p, TArray a, Func aget, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(aget(a,element)) < selector(aget(a,p[i2]))) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(aget(a,p[i1])) < selector(aget(a,p[i2]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni])) < selector(aget(a,element))) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this int[] p, TArray a, Func aget, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, selector, 0, p.Length - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, TArray a, Func aget, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, TArray a, Func aget, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(aget(a,val)) >= selector(aget(a,p[lf])) && selector(aget(a,val)) >= selector(aget(a,p[rt]))) break; if (selector(aget(a,p[lf])) >= selector(aget(a,p[rt]))) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, TArray a, Func aget, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(aget(a,vstepson)) <= selector(aget(a,val))) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(aget(a,p[rt])) >= selector(aget(a,vstepson)) || selector(aget(a,p[lf])) >= selector(aget(a,vstepson))) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); } } public class TimSortInfoPermGetFloatSel { public int[] m_p; public TArray m_a; public int m_count; public Func m_aget; public Func m_sel; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoPermGetFloatSel(int[] p, TArray a, Func aget, Func selector, int count) { m_p = p; m_a = a; m_count = count; m_aget = aget; m_sel = selector; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this int[] p, TArray a, Func aget, Func selector) { PermutationTimSortAscending(p, a, aget, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this int[] p, TArray a, Func aget, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, aget, selector, lo, hi); PermutationBinarySortAscending(p, a, aget, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermGetFloatSel(p, a, aget, selector, count); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, aget, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, aget, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermAsc(ti); } private static void MergeCollapsePermAsc(this TimSortInfoPermGetFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermAsc(ti, n); else break; } } private static void MergeForceCollapsePermAsc(this TimSortInfoPermGetFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } } private static void MergeAtPermAsc(this TimSortInfoPermGetFloatSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermAsc(ti, start1, len1, start2, len2); else MergeHiPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermAsc(this TimSortInfoPermGetFloatSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(aget(a,p[idx2])) < selector(aget(a,t[idx1]))) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, aget, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, aget, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermAsc(this TimSortInfoPermGetFloatSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(aget(a,t[idx2])) < selector(aget(a,p[idx1]))) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, aget, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, aget, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, TArray a, Func aget, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(aget(a,key)) > selector(aget(a,p[start + hint]))) { int maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) > selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) <= selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) > selector(aget(a,p[start + m]))) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, TArray a, Func aget, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(aget(a,key)) < selector(aget(a,p[start + hint]))) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) < selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) >= selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) < selector(aget(a,p[start + m]))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(aget(a,pivot)) < selector(aget(a,p[mid]))) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a,p[runHi++])) < selector(aget(a,p[beginIncl]))) { while (runHi < endExcl && selector(aget(a,p[runHi])) < selector(aget(a,p[runHi - 1]))) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a,p[runHi])) >= selector(aget(a,p[runHi - 1]))) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this long[] p, TArray a, Func aget, Func selector, long med) { long last = p.LongLength - 1; PermutationQuickMedianAscending(p, a, aget, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl, long med) { PermutationQuickMedianAscending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this long[] p, TArray a, Func aget, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a,p[e1])) > selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) > selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) > selector(aget(a,p2))) { while (selector(aget(a,p[hi])) > selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) > selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(aget(a,ai)) < selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this long[] p, TArray a, Func aget, Func selector) { long last = p.LongLength - 1; PermutationQuickSortAscending(p, a, aget, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { PermutationQuickSortAscending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this long[] p, TArray a, Func aget, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a,p[e1])) > selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) > selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) > selector(aget(a,p2))) { while (selector(aget(a,p[hi])) > selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) > selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, aget, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(aget(a,ai)) < selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this long[] p, TArray a, Func aget, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(aget(a,element)) < selector(aget(a,p[i2 + begin]))) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a,p[i1 + begin])) < selector(aget(a,p[i2 + begin]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni + begin])) < selector(aget(a,element))) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this long[] p, TArray a, Func aget, Func selector) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(aget(a,element)) < selector(aget(a,p[i2]))) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a,p[i1])) < selector(aget(a,p[i2]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni])) < selector(aget(a,element))) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this long[] p, TArray a, Func aget, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, selector, 0, p.LongLength - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this long[] p, TArray a, Func aget, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this long[] p, TArray a, Func aget, Func selector, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a,val)) >= selector(aget(a,p[lf])) && selector(aget(a,val)) >= selector(aget(a,p[rt]))) break; if (selector(aget(a,p[lf])) >= selector(aget(a,p[rt]))) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this long[] p, TArray a, Func aget, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (selector(aget(a,vstepson)) <= selector(aget(a,val))) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a,p[rt])) >= selector(aget(a,vstepson)) || selector(aget(a,p[lf])) >= selector(aget(a,vstepson))) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); } } public class TimSortInfoPermLongGetFloatSel { public long[] m_p; public TArray m_a; public long m_count; public Func m_aget; public Func m_sel; public long m_minGallop = c_minGallop; public long[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoPermLongGetFloatSel(long[] p, TArray a, Func aget, Func selector, long count) { m_p = p; m_a = a; m_count = count; m_aget = aget; m_sel = selector; m_tmp = new long[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public long[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new long[c < 0 ? cap : Math.Min(c, m_p.LongLength >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this long[] p, TArray a, Func aget, Func selector) { PermutationTimSortAscending(p, a, aget, selector, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this long[] p, TArray a, Func aget, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, aget, selector, lo, hi); PermutationBinarySortAscending(p, a, aget, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongGetFloatSel(p, a, aget, selector, count); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderAscending(p, a, aget, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, aget, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongAsc(ti); } private static void MergeCollapsePermLongAsc(this TimSortInfoPermLongGetFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongAsc(ti, n); else break; } } private static void MergeForceCollapsePermLongAsc(this TimSortInfoPermLongGetFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } } private static void MergeAtPermLongAsc(this TimSortInfoPermLongGetFloatSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightAscending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongAsc(ti, start1, len1, start2, len2); else MergeHiPermLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongAsc(this TimSortInfoPermLongGetFloatSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a,p[idx2])) < selector(aget(a,t[idx1]))) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, aget, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, aget, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongAsc(this TimSortInfoPermLongGetFloatSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a,t[idx2])) < selector(aget(a,p[idx1]))) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, aget, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, aget, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftAscending( this long[] p, TArray a, Func aget, Func selector, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(aget(a,key)) > selector(aget(a,p[start + hint]))) { long maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) > selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) <= selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) > selector(aget(a,p[start + m]))) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightAscending( this long[] p, TArray a, Func aget, Func selector, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(aget(a,key)) < selector(aget(a,p[start + hint]))) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) < selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) >= selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) < selector(aget(a,p[start + m]))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(aget(a,pivot)) < selector(aget(a,p[mid]))) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a,p[runHi++])) < selector(aget(a,p[beginIncl]))) { while (runHi < endExcl && selector(aget(a,p[runHi])) < selector(aget(a,p[runHi - 1]))) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a,p[runHi])) >= selector(aget(a,p[runHi - 1]))) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this int[] p, TArray a, Func aget, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, aget, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, TArray a, Func aget, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(aget(a,p[e1])) < selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) < selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) < selector(aget(a,p2))) { while (selector(aget(a,p[hi])) < selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) < selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(aget(a,ai)) > selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this int[] p, TArray a, Func aget, Func selector) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, aget, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, TArray a, Func aget, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(aget(a,p[e1])) < selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) < selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) < selector(aget(a,p2))) { while (selector(aget(a,p[hi])) < selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) < selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, aget, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(aget(a,ai)) > selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this int[] p, TArray a, Func aget, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(aget(a,element)) > selector(aget(a,p[i2 + begin]))) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(aget(a,p[i1 + begin])) > selector(aget(a,p[i2 + begin]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni + begin])) > selector(aget(a,element))) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this int[] p, TArray a, Func aget, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(aget(a,element)) > selector(aget(a,p[i2]))) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(aget(a,p[i1])) > selector(aget(a,p[i2]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni])) > selector(aget(a,element))) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this int[] p, TArray a, Func aget, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, selector, 0, p.Length - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, TArray a, Func aget, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, TArray a, Func aget, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(aget(a,val)) <= selector(aget(a,p[lf])) && selector(aget(a,val)) <= selector(aget(a,p[rt]))) break; if (selector(aget(a,p[lf])) <= selector(aget(a,p[rt]))) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, TArray a, Func aget, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(aget(a,vstepson)) >= selector(aget(a,val))) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(aget(a,p[rt])) <= selector(aget(a,vstepson)) || selector(aget(a,p[lf])) <= selector(aget(a,vstepson))) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this int[] p, TArray a, Func aget, Func selector) { PermutationTimSortDescending(p, a, aget, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this int[] p, TArray a, Func aget, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, aget, selector, lo, hi); PermutationBinarySortDescending(p, a, aget, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermGetFloatSel(p, a, aget, selector, count); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, aget, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, aget, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermDesc(ti); } private static void MergeCollapsePermDesc(this TimSortInfoPermGetFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermDesc(ti, n); else break; } } private static void MergeForceCollapsePermDesc(this TimSortInfoPermGetFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } } private static void MergeAtPermDesc(this TimSortInfoPermGetFloatSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermDesc(ti, start1, len1, start2, len2); else MergeHiPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermDesc(this TimSortInfoPermGetFloatSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(aget(a,p[idx2])) > selector(aget(a,t[idx1]))) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, aget, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, aget, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermDesc(this TimSortInfoPermGetFloatSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(aget(a,t[idx2])) > selector(aget(a,p[idx1]))) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, aget, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, aget, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, TArray a, Func aget, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(aget(a,key)) < selector(aget(a,p[start + hint]))) { int maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) < selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) >= selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) < selector(aget(a,p[start + m]))) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, TArray a, Func aget, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(aget(a,key)) > selector(aget(a,p[start + hint]))) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) > selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) <= selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) > selector(aget(a,p[start + m]))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(aget(a,pivot)) > selector(aget(a,p[mid]))) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a,p[runHi++])) > selector(aget(a,p[beginIncl]))) { while (runHi < endExcl && selector(aget(a,p[runHi])) > selector(aget(a,p[runHi - 1]))) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a,p[runHi])) <= selector(aget(a,p[runHi - 1]))) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this long[] p, TArray a, Func aget, Func selector, long med) { long last = p.LongLength - 1; PermutationQuickMedianDescending(p, a, aget, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl, long med) { PermutationQuickMedianDescending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this long[] p, TArray a, Func aget, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a,p[e1])) < selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) < selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) < selector(aget(a,p2))) { while (selector(aget(a,p[hi])) < selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) < selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(aget(a,ai)) > selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this long[] p, TArray a, Func aget, Func selector) { long last = p.LongLength - 1; PermutationQuickSortDescending(p, a, aget, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { PermutationQuickSortDescending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this long[] p, TArray a, Func aget, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a,p[e1])) < selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) < selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) < selector(aget(a,p2))) { while (selector(aget(a,p[hi])) < selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) < selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, aget, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(aget(a,ai)) > selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this long[] p, TArray a, Func aget, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(aget(a,element)) > selector(aget(a,p[i2 + begin]))) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a,p[i1 + begin])) > selector(aget(a,p[i2 + begin]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni + begin])) > selector(aget(a,element))) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this long[] p, TArray a, Func aget, Func selector) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(aget(a,element)) > selector(aget(a,p[i2]))) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a,p[i1])) > selector(aget(a,p[i2]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni])) > selector(aget(a,element))) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this long[] p, TArray a, Func aget, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, selector, 0, p.LongLength - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this long[] p, TArray a, Func aget, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this long[] p, TArray a, Func aget, Func selector, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a,val)) <= selector(aget(a,p[lf])) && selector(aget(a,val)) <= selector(aget(a,p[rt]))) break; if (selector(aget(a,p[lf])) <= selector(aget(a,p[rt]))) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this long[] p, TArray a, Func aget, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (selector(aget(a,vstepson)) >= selector(aget(a,val))) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a,p[rt])) <= selector(aget(a,vstepson)) || selector(aget(a,p[lf])) <= selector(aget(a,vstepson))) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this long[] p, TArray a, Func aget, Func selector) { PermutationTimSortDescending(p, a, aget, selector, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this long[] p, TArray a, Func aget, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, aget, selector, lo, hi); PermutationBinarySortDescending(p, a, aget, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongGetFloatSel(p, a, aget, selector, count); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderDescending(p, a, aget, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, aget, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongDesc(ti); } private static void MergeCollapsePermLongDesc(this TimSortInfoPermLongGetFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongDesc(ti, n); else break; } } private static void MergeForceCollapsePermLongDesc(this TimSortInfoPermLongGetFloatSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } } private static void MergeAtPermLongDesc(this TimSortInfoPermLongGetFloatSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightDescending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongDesc(ti, start1, len1, start2, len2); else MergeHiPermLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongDesc(this TimSortInfoPermLongGetFloatSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a,p[idx2])) > selector(aget(a,t[idx1]))) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, aget, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, aget, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongDesc(this TimSortInfoPermLongGetFloatSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a,t[idx2])) > selector(aget(a,p[idx1]))) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, aget, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, aget, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftDescending( this long[] p, TArray a, Func aget, Func selector, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(aget(a,key)) < selector(aget(a,p[start + hint]))) { long maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) < selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) >= selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) < selector(aget(a,p[start + m]))) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightDescending( this long[] p, TArray a, Func aget, Func selector, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(aget(a,key)) > selector(aget(a,p[start + hint]))) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) > selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) <= selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) > selector(aget(a,p[start + m]))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(aget(a,pivot)) > selector(aget(a,p[mid]))) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a,p[runHi++])) > selector(aget(a,p[beginIncl]))) { while (runHi < endExcl && selector(aget(a,p[runHi])) > selector(aget(a,p[runHi - 1]))) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a,p[runHi])) <= selector(aget(a,p[runHi - 1]))) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this int[] p, TArray a, Func aget, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianAscending(p, a, aget, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianAscending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this int[] p, TArray a, Func aget, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(aget(a,p[e1])) > selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) > selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) > selector(aget(a,p2))) { while (selector(aget(a,p[hi])) > selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) > selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(aget(a,ai)) < selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this int[] p, TArray a, Func aget, Func selector) { int last = p.Length - 1; PermutationQuickSortAscending(p, a, aget, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { PermutationQuickSortAscending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this int[] p, TArray a, Func aget, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(aget(a,p[e1])) > selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) > selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) > selector(aget(a,p2))) { while (selector(aget(a,p[hi])) > selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) > selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, aget, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(aget(a,ai)) < selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this int[] p, TArray a, Func aget, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(aget(a,element)) < selector(aget(a,p[i2 + begin]))) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(aget(a,p[i1 + begin])) < selector(aget(a,p[i2 + begin]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni + begin])) < selector(aget(a,element))) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this int[] p, TArray a, Func aget, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(aget(a,element)) < selector(aget(a,p[i2]))) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(aget(a,p[i1])) < selector(aget(a,p[i2]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni])) < selector(aget(a,element))) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this int[] p, TArray a, Func aget, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, selector, 0, p.Length - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this int[] p, TArray a, Func aget, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this int[] p, TArray a, Func aget, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(aget(a,val)) >= selector(aget(a,p[lf])) && selector(aget(a,val)) >= selector(aget(a,p[rt]))) break; if (selector(aget(a,p[lf])) >= selector(aget(a,p[rt]))) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this int[] p, TArray a, Func aget, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(aget(a,vstepson)) <= selector(aget(a,val))) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(aget(a,p[rt])) >= selector(aget(a,vstepson)) || selector(aget(a,p[lf])) >= selector(aget(a,vstepson))) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); } } public class TimSortInfoPermGetDoubleSel { public int[] m_p; public TArray m_a; public int m_count; public Func m_aget; public Func m_sel; public int m_minGallop = c_minGallop; public int[] m_tmp; public int m_stackSize = 0; public int[] m_runStart; public int[] m_runLen; public TimSortInfoPermGetDoubleSel(int[] p, TArray a, Func aget, Func selector, int count) { m_p = p; m_a = a; m_count = count; m_aget = aget; m_sel = selector; m_tmp = new int[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new int[stackLen]; m_runLen = new int[stackLen]; } public void PushRun(int runStart, int runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public int[] EnsureCapacity(int cap) { if (m_tmp.Length < cap) { int c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c++; m_tmp = new int[c < 0 ? cap : Math.Min(c, m_p.Length >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this int[] p, TArray a, Func aget, Func selector) { PermutationTimSortAscending(p, a, aget, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this int[] p, TArray a, Func aget, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, aget, selector, lo, hi); PermutationBinarySortAscending(p, a, aget, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermGetDoubleSel(p, a, aget, selector, count); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderAscending(p, a, aget, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, aget, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermAsc(ti); } private static void MergeCollapsePermAsc(this TimSortInfoPermGetDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermAsc(ti, n); else break; } } private static void MergeForceCollapsePermAsc(this TimSortInfoPermGetDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermAsc(ti, n); } } private static void MergeAtPermAsc(this TimSortInfoPermGetDoubleSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightAscending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermAsc(ti, start1, len1, start2, len2); else MergeHiPermAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermAsc(this TimSortInfoPermGetDoubleSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(aget(a,p[idx2])) < selector(aget(a,t[idx1]))) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, aget, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, aget, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermAsc(this TimSortInfoPermGetDoubleSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(aget(a,t[idx2])) < selector(aget(a,p[idx1]))) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, aget, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, aget, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftAscending( this int[] p, TArray a, Func aget, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(aget(a,key)) > selector(aget(a,p[start + hint]))) { int maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) > selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) <= selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) > selector(aget(a,p[start + m]))) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightAscending( this int[] p, TArray a, Func aget, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(aget(a,key)) < selector(aget(a,p[start + hint]))) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) < selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) >= selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) < selector(aget(a,p[start + m]))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(aget(a,pivot)) < selector(aget(a,p[mid]))) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderAscending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a,p[runHi++])) < selector(aget(a,p[beginIncl]))) { while (runHi < endExcl && selector(aget(a,p[runHi])) < selector(aget(a,p[runHi - 1]))) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a,p[runHi])) >= selector(aget(a,p[runHi - 1]))) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this long[] p, TArray a, Func aget, Func selector, long med) { long last = p.LongLength - 1; PermutationQuickMedianAscending(p, a, aget, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl, long med) { PermutationQuickMedianAscending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianAscending( this long[] p, TArray a, Func aget, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a,p[e1])) > selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) > selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) > selector(aget(a,p2))) { while (selector(aget(a,p[hi])) > selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) > selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(aget(a,ai)) < selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this long[] p, TArray a, Func aget, Func selector) { long last = p.LongLength - 1; PermutationQuickSortAscending(p, a, aget, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { PermutationQuickSortAscending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortAscending( this long[] p, TArray a, Func aget, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a,p[e1])) > selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) > selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) > selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) > selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) > selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) > selector(aget(a,p2))) { while (selector(aget(a,p[hi])) > selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) > selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) < selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortAscending(p, a, aget, selector, lo, hi, cm); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortAscending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortAscending(p, a, aget, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(aget(a,ai)) < selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this long[] p, TArray a, Func aget, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(aget(a,element)) < selector(aget(a,p[i2 + begin]))) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a,p[i1 + begin])) < selector(aget(a,p[i2 + begin]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni + begin])) < selector(aget(a,element))) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortAscending( this long[] p, TArray a, Func aget, Func selector) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(aget(a,element)) < selector(aget(a,p[i2]))) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a,p[i1])) < selector(aget(a,p[i2]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni])) < selector(aget(a,element))) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this long[] p, TArray a, Func aget, Func selector) { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, selector, 0, p.LongLength - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { PermutationSmoothSortAscendingInclusiveRange(p, a, aget, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortAscendingInclusiveRange( this long[] p, TArray a, Func aget, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); else PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortAscendingTrinkle(p, a, aget, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortAscendingSift( this long[] p, TArray a, Func aget, Func selector, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a,val)) >= selector(aget(a,p[lf])) && selector(aget(a,val)) >= selector(aget(a,p[rt]))) break; if (selector(aget(a,p[lf])) >= selector(aget(a,p[rt]))) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortAscendingTrinkle( this long[] p, TArray a, Func aget, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (selector(aget(a,vstepson)) <= selector(aget(a,val))) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a,p[rt])) >= selector(aget(a,vstepson)) || selector(aget(a,p[lf])) >= selector(aget(a,vstepson))) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortAscendingSift(p, a, aget, selector, pshift, head); } } public class TimSortInfoPermLongGetDoubleSel { public long[] m_p; public TArray m_a; public long m_count; public Func m_aget; public Func m_sel; public long m_minGallop = c_minGallop; public long[] m_tmp; public int m_stackSize = 0; public long[] m_runStart; public long[] m_runLen; public TimSortInfoPermLongGetDoubleSel(long[] p, TArray a, Func aget, Func selector, long count) { m_p = p; m_a = a; m_count = count; m_aget = aget; m_sel = selector; m_tmp = new long[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new long[stackLen]; m_runLen = new long[stackLen]; } public void PushRun(long runStart, long runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public long[] EnsureCapacity(long cap) { if (m_tmp.LongLength < cap) { long c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16; c |= c >> 32; c++; m_tmp = new long[c < 0 ? cap : Math.Min(c, m_p.LongLength >> 1)]; } return m_tmp; } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this long[] p, TArray a, Func aget, Func selector) { PermutationTimSortAscending(p, a, aget, selector, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortAscending( this long[] p, TArray a, Func aget, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderAscending(p, a, aget, selector, lo, hi); PermutationBinarySortAscending(p, a, aget, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongGetDoubleSel(p, a, aget, selector, count); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderAscending(p, a, aget, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortAscending(p, a, aget, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongAsc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongAsc(ti); } private static void MergeCollapsePermLongAsc(this TimSortInfoPermLongGetDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongAsc(ti, n); else break; } } private static void MergeForceCollapsePermLongAsc(this TimSortInfoPermLongGetDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongAsc(ti, n); } } private static void MergeAtPermLongAsc(this TimSortInfoPermLongGetDoubleSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightAscending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftAscending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongAsc(ti, start1, len1, start2, len2); else MergeHiPermLongAsc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongAsc(this TimSortInfoPermLongGetDoubleSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a,p[idx2])) < selector(aget(a,t[idx1]))) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightAscending(t, a, aget, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftAscending(p, a, aget, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongAsc(this TimSortInfoPermLongGetDoubleSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a,t[idx2])) < selector(aget(a,p[idx1]))) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightAscending(p, a, aget, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftAscending(t, a, aget, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftAscending( this long[] p, TArray a, Func aget, Func selector, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(aget(a,key)) > selector(aget(a,p[start + hint]))) { long maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) > selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) <= selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) > selector(aget(a,p[start + m]))) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightAscending( this long[] p, TArray a, Func aget, Func selector, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(aget(a,key)) < selector(aget(a,p[start + hint]))) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) < selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) >= selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) < selector(aget(a,p[start + m]))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(aget(a,pivot)) < selector(aget(a,p[mid]))) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderAscending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a,p[runHi++])) < selector(aget(a,p[beginIncl]))) { while (runHi < endExcl && selector(aget(a,p[runHi])) < selector(aget(a,p[runHi - 1]))) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a,p[runHi])) >= selector(aget(a,p[runHi - 1]))) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this int[] p, TArray a, Func aget, Func selector, int med) { int last = p.Length - 1; PermutationQuickMedianDescending(p, a, aget, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl, int med) { PermutationQuickMedianDescending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this int[] p, TArray a, Func aget, Func selector, int l, int r, int countSub1, int med) { while (countSub1 >= c_insertionMedianThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(aget(a,p[e1])) < selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) < selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) < selector(aget(a,p2))) { while (selector(aget(a,p[hi])) < selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) < selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(aget(a,ai)) > selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this int[] p, TArray a, Func aget, Func selector) { int last = p.Length - 1; PermutationQuickSortDescending(p, a, aget, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { PermutationQuickSortDescending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this int[] p, TArray a, Func aget, Func selector, int l, int r, int countSub1) { while (countSub1 >= c_insertionSortThreshold) { int sixth = (1 + countSub1) / 6; int e1 = l + sixth; int e5 = r - sixth; int e3 = (l + r) >> 1; int e4 = e3 + sixth; int e2 = e3 - sixth; if (selector(aget(a,p[e1])) < selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) < selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; int lo = l + 1; int hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) < selector(aget(a,p2))) { while (selector(aget(a,p[hi])) < selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (int i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) < selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; int cl = lo - 2 - l; int cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (int i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (int i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { int cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, aget, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (int i = l + 1; i <= r; i++) { var ai = p[i]; int j; for (j = i - 1; j >= l && selector(aget(a,ai)) > selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this int[] p, TArray a, Func aget, Func selector, int begin, int end) { int count = end - begin; for (int c = 1; c < count; c++) { var element = p[c + begin]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(aget(a,element)) > selector(aget(a,p[i2 + begin]))) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(aget(a,p[i1 + begin])) > selector(aget(a,p[i2 + begin]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni + begin])) > selector(aget(a,element))) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this int[] p, TArray a, Func aget, Func selector) { int count = p.Length; for (int c = 1; c < count; c++) { var element = p[c]; int i = c; while (i > 0) { int i2 = (i - 1) / 2; if (selector(aget(a,element)) > selector(aget(a,p[i2]))) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; int i = 0, i1 = 1; while (i1 < count) // at least one child { int i2 = i1 + 1; int ni = (i2 < count // two children? && selector(aget(a,p[i1])) > selector(aget(a,p[i2]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni])) > selector(aget(a,element))) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this int[] p, TArray a, Func aget, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, selector, 0, p.Length - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this int[] p, TArray a, Func aget, Func selector, int lo, int hi) { int head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LP[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits >> 1, pshift + 1, head - LP[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this int[] p, TArray a, Func aget, Func selector, int pshift, int head) { var val = p[head]; while (pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(aget(a,val)) <= selector(aget(a,p[lf])) && selector(aget(a,val)) <= selector(aget(a,p[rt]))) break; if (selector(aget(a,p[lf])) <= selector(aget(a,p[rt]))) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this int[] p, TArray a, Func aget, Func selector, long pbits, int pshift, int head, bool isTrusty) { var val = p[head]; while (pbits != 1) { int stepson = head - LP[pshift]; var vstepson = p[stepson]; if (selector(aget(a,vstepson)) >= selector(aget(a,val))) break; if (!isTrusty && pshift > 1) { int rt = head - 1; int lf = head - 1 - LP[pshift - 2]; if (selector(aget(a,p[rt])) <= selector(aget(a,vstepson)) || selector(aget(a,p[lf])) <= selector(aget(a,vstepson))) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this int[] p, TArray a, Func aget, Func selector) { PermutationTimSortDescending(p, a, aget, selector, 0, p.Length); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this int[] p, TArray a, Func aget, Func selector, int lo, int hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ int count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, aget, selector, lo, hi); PermutationBinarySortDescending(p, a, aget, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermGetDoubleSel(p, a, aget, selector, count); int minRun = TimSortMinRunLength(count); do { int runLen = PermutationCountRunAndOrderDescending(p, a, aget, selector, lo, hi); if (runLen < minRun) { int force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, aget, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermDesc(ti); } private static void MergeCollapsePermDesc(this TimSortInfoPermGetDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermDesc(ti, n); else break; } } private static void MergeForceCollapsePermDesc(this TimSortInfoPermGetDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermDesc(ti, n); } } private static void MergeAtPermDesc(this TimSortInfoPermGetDoubleSel ti, int i) { int start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; int start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; int k = PermutationGallopRightDescending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermDesc(ti, start1, len1, start2, len2); else MergeHiPermDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermDesc(this TimSortInfoPermGetDoubleSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); int idx1 = 0, idx2 = start2; int dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(aget(a,p[idx2])) > selector(aget(a,t[idx1]))) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, aget, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, aget, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermDesc(this TimSortInfoPermGetDoubleSel ti, int start1, int len1, int start2, int len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); int idx1 = start1 + len1 - 1, idx2 = len2 - 1; int dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; int minGallop = ti.m_minGallop; while (true) { int count1 = 0, count2 = 0; do { if (selector(aget(a,t[idx2])) > selector(aget(a,p[idx1]))) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, aget, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, aget, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static int PermutationGallopLeftDescending( this int[] p, TArray a, Func aget, Func selector, int key, int start, int len, int hint) { int lastOfs = 0, ofs = 1; if (selector(aget(a,key)) < selector(aget(a,p[start + hint]))) { int maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) < selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { int maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) >= selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) < selector(aget(a,p[start + m]))) lastOfs = m + 1; else ofs = m; } return ofs; } private static int PermutationGallopRightDescending( this int[] p, TArray a, Func aget, Func selector, int key, int start, int len, int hint) { int ofs = 1, lastOfs = 0; if (selector(aget(a,key)) > selector(aget(a,p[start + hint]))) { int maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) > selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; int tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { int maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) <= selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) > selector(aget(a,p[start + m]))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl, int beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; int l = beginIncl, r = beginUnsorted; while (l < r) { int mid = (l + r) >> 1; if (selector(aget(a,pivot)) > selector(aget(a,p[mid]))) r = mid; else l = mid + 1; } int n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static int PermutationCountRunAndOrderDescending( this int[] p, TArray a, Func aget, Func selector, int beginIncl, int endExcl) { int runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a,p[runHi++])) > selector(aget(a,p[beginIncl]))) { while (runHi < endExcl && selector(aget(a,p[runHi])) > selector(aget(a,p[runHi - 1]))) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a,p[runHi])) <= selector(aget(a,p[runHi - 1]))) runHi++; } return runHi - beginIncl; } /// /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this long[] p, TArray a, Func aget, Func selector, long med) { long last = p.LongLength - 1; PermutationQuickMedianDescending(p, a, aget, selector, 0, last, last, med); } /// /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickMedianDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl, long med) { PermutationQuickMedianDescending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1, med); } /* This implementation of QuickMedian is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickMedianDescending( this long[] p, TArray a, Func aget, Func selector, long l, long r, long countSub1, long med) { while (countSub1 >= c_insertionMedianThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a,p[e1])) < selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) < selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) < selector(aget(a,p2))) { while (selector(aget(a,p[hi])) < selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) < selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } if (med < lo || med > hi) return; l = lo; r = hi; countSub1 = hi - lo; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; } } else { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(aget(a,ai)) > selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this long[] p, TArray a, Func aget, Func selector) { long last = p.LongLength - 1; PermutationQuickSortDescending(p, a, aget, selector, 0, last, last); } /// /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationQuickSortDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { PermutationQuickSortDescending(p, a, aget, selector, beginIncl, endExcl - 1, endExcl - beginIncl - 1); } /* This implementation of QuickSort is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void PermutationQuickSortDescending( this long[] p, TArray a, Func aget, Func selector, long l, long r, long countSub1) { while (countSub1 >= c_insertionSortThreshold) { long sixth = (1 + countSub1) / 6; long e1 = l + sixth; long e5 = r - sixth; long e3 = (l + r) >> 1; long e4 = e3 + sixth; long e2 = e3 - sixth; if (selector(aget(a,p[e1])) < selector(aget(a,p[e2]))) { var t = p[e1]; p[e1] = p[e2]; p[e2] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e3]))) { var t = p[e1]; p[e1] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e1])) < selector(aget(a,p[e4]))) { var t = p[e1]; p[e1] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e3])) < selector(aget(a,p[e4]))) { var t = p[e3]; p[e3] = p[e4]; p[e4] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e5]))) { var t = p[e2]; p[e2] = p[e5]; p[e5] = t; } if (selector(aget(a,p[e2])) < selector(aget(a,p[e3]))) { var t = p[e2]; p[e2] = p[e3]; p[e3] = t; } if (selector(aget(a,p[e4])) < selector(aget(a,p[e5]))) { var t = p[e4]; p[e4] = p[e5]; p[e5] = t; } var p1 = p[e2]; p[e2] = p[l]; var p2 = p[e4]; p[e4] = p[r]; long lo = l + 1; long hi = r - 1; bool pivotsDiffer = selector(aget(a,p1)) != selector(aget(a,p2)); if (pivotsDiffer) { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else if (selector(aget(a,ai)) < selector(aget(a,p2))) { while (selector(aget(a,p[hi])) < selector(aget(a,p2)) && i < hi) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } else { for (long i = lo; i <= hi; i++) { var ai = p[i]; if (selector(aget(a,ai)) == selector(aget(a,p1))) continue; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } else { while (selector(aget(a,p[hi])) < selector(aget(a,p1))) --hi; p[i] = p[hi]; p[hi] = ai; --hi; ai = p[i]; if (selector(aget(a,ai)) > selector(aget(a,p1))) { p[i] = p[lo]; p[lo] = ai; ++lo; } } } } p[l] = p[lo - 1]; p[lo - 1] = p1; p[r] = p[hi + 1]; p[hi + 1] = p2; long cl = lo - 2 - l; long cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); { while (selector(aget(a,p[lo])) == selector(aget(a,p1))) ++lo; for (long i = lo + 1; i <= hi; i++) { if (selector(aget(a,p[i])) == selector(aget(a,p1))) { p1 = p[i]; p[i] = p[lo]; p[lo] = p1; ++lo; } } while (selector(aget(a,p[hi])) == selector(aget(a,p2))) --hi; for (long i = hi - 1; i >= lo; i--) { if (selector(aget(a,p[i])) == selector(aget(a,p2))) { p2 = p[i]; p[i] = p[hi]; p[hi] = p2; --hi; } } l = lo; r = hi; countSub1 = hi - lo; } } else { long cm = hi - lo; if (cl > cr) { if (cl > cm) { PermutationQuickSortDescending(p, a, aget, selector, lo, hi, cm); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, lo, hi, cm); l = hi + 2; countSub1 = cr; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } } } else { if (cl > cr) { PermutationQuickSortDescending(p, a, aget, selector, hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { PermutationQuickSortDescending(p, a, aget, selector, l, lo - 2, cl); l = hi + 2; countSub1 = cr; } } } for (long i = l + 1; i <= r; i++) { var ai = p[i]; long j; for (j = i - 1; j >= l && selector(aget(a,ai)) > selector(aget(a,p[j])); j--) p[j + 1] = p[j]; p[j + 1] = ai; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this long[] p, TArray a, Func aget, Func selector, long begin, long end) { long count = end - begin; for (long c = 1; c < count; c++) { var element = p[c + begin]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(aget(a,element)) > selector(aget(a,p[i2 + begin]))) break; p[i + begin] = p[i2 + begin]; i = i2; } p[i + begin] = element; } while (count > 1) { --count; var element = p[count + begin]; p[count + begin] = p[0 + begin]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a,p[i1 + begin])) > selector(aget(a,p[i2 + begin]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni + begin])) > selector(aget(a,element))) break; p[i + begin] = p[ni + begin]; i = ni; i1 = 2 * i + 1; } p[i + begin] = element; } } /// /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. /// It is slower than the PermutationQuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationHeapSortDescending( this long[] p, TArray a, Func aget, Func selector) { long count = p.LongLength; for (long c = 1; c < count; c++) { var element = p[c]; long i = c; while (i > 0) { long i2 = (i - 1) / 2; if (selector(aget(a,element)) > selector(aget(a,p[i2]))) break; p[i] = p[i2]; i = i2; } p[i] = element; } while (count > 1) { --count; var element = p[count]; p[count] = p[0]; long i = 0, i1 = 1; while (i1 < count) // at least one child { long i2 = i1 + 1; long ni = (i2 < count // two children? && selector(aget(a,p[i1])) > selector(aget(a,p[i2]))) ? i2 : i1; // smaller child if (selector(aget(a,p[ni])) > selector(aget(a,element))) break; p[i] = p[ni]; i = ni; i1 = 2 * i + 1; } p[i] = element; } } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this long[] p, TArray a, Func aget, Func selector) { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, selector, 0, p.LongLength - 1); } [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationSmoothSortDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { PermutationSmoothSortDescendingInclusiveRange(p, a, aget, selector, beginIncl, endExcl - 1); } private static void PermutationSmoothSortDescendingInclusiveRange( this long[] p, TArray a, Func aget, Func selector, long lo, long hi) { long head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); pbits >>= 2; pshift += 2; } else { if (LPLong[pshift - 1] >= hi - head) PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); else PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits >> 1, pshift + 1, head - LPLong[pshift] - 1, true); PermutationSmoothSortDescendingTrinkle(p, a, aget, selector, pbits, pshift, head - 1, true); } head--; } } private static void PermutationSmoothSortDescendingSift( this long[] p, TArray a, Func aget, Func selector, int pshift, long head) { var val = p[head]; while (pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a,val)) <= selector(aget(a,p[lf])) && selector(aget(a,val)) <= selector(aget(a,p[rt]))) break; if (selector(aget(a,p[lf])) <= selector(aget(a,p[rt]))) { p[head] = p[lf]; head = lf; pshift -= 1; } else { p[head] = p[rt]; head = rt; pshift -= 2; } } p[head] = val; } private static void PermutationSmoothSortDescendingTrinkle( this long[] p, TArray a, Func aget, Func selector, long pbits, int pshift, long head, bool isTrusty) { var val = p[head]; while (pbits != 1) { long stepson = head - LPLong[pshift]; var vstepson = p[stepson]; if (selector(aget(a,vstepson)) >= selector(aget(a,val))) break; if (!isTrusty && pshift > 1) { long rt = head - 1; long lf = head - 1 - LPLong[pshift - 2]; if (selector(aget(a,p[rt])) <= selector(aget(a,vstepson)) || selector(aget(a,p[lf])) <= selector(aget(a,vstepson))) break; } p[head] = vstepson; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { p[head] = val; PermutationSmoothSortDescendingSift(p, a, aget, selector, pshift, head); } } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this long[] p, TArray a, Func aget, Func selector) { PermutationTimSortDescending(p, a, aget, selector, 0, p.LongLength); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// [EditorBrowsable(EditorBrowsableState.Never)] public static void PermutationTimSortDescending( this long[] p, TArray a, Func aget, Func selector, long lo, long hi) { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ long count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = PermutationCountRunAndOrderDescending(p, a, aget, selector, lo, hi); PermutationBinarySortDescending(p, a, aget, selector, lo, hi, lo + initRunLen); return; } var ti = new TimSortInfoPermLongGetDoubleSel(p, a, aget, selector, count); long minRun = TimSortMinRunLength(count); do { long runLen = PermutationCountRunAndOrderDescending(p, a, aget, selector, lo, hi); if (runLen < minRun) { long force = count <= minRun ? count : minRun; PermutationBinarySortDescending(p, a, aget, selector, lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapsePermLongDesc(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapsePermLongDesc(ti); } private static void MergeCollapsePermLongDesc(this TimSortInfoPermLongGetDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAtPermLongDesc(ti, n); else break; } } private static void MergeForceCollapsePermLongDesc(this TimSortInfoPermLongGetDoubleSel ti) { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAtPermLongDesc(ti, n); } } private static void MergeAtPermLongDesc(this TimSortInfoPermLongGetDoubleSel ti, int i) { long start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; long start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; long k = PermutationGallopRightDescending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start2], start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = PermutationGallopLeftDescending(ti.m_p, a, ti.m_aget, ti.m_sel, ti.m_p[start1 + len1 - 1], start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLoPermLongDesc(ti, start1, len1, start2, len2); else MergeHiPermLongDesc(ti, start1, len1, start2, len2); } private static void MergeLoPermLongDesc(this TimSortInfoPermLongGetDoubleSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len1); Array.Copy(p, start1, t, 0, len1); long idx1 = 0, idx2 = start2; long dest = start1; p[dest++] = p[idx2++]; if (--len2 == 0) { Array.Copy(t, idx1, p, dest, len1); return; } if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a,p[idx2])) > selector(aget(a,t[idx1]))) { p[dest++] = p[idx2++]; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { p[dest++] = t[idx1++]; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = PermutationGallopRightDescending(t, a, aget, selector, p[idx2], idx1, len1, 0); if (count1 != 0) { Array.Copy(t, idx1, p, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } p[dest++] = p[idx2++]; if (--len2 == 0) goto breakouter; count2 = PermutationGallopLeftDescending(p, a, aget, selector, t[idx1], idx2, len2, 0); if (count2 != 0) { Array.Copy(p, idx2, p, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } p[dest++] = t[idx1++]; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { Array.Copy(p, idx2, p, dest, len2); p[dest + len2] = t[idx1]; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, idx1, p, dest, len1); } private static void MergeHiPermLongDesc(this TimSortInfoPermLongGetDoubleSel ti, long start1, long len1, long start2, long len2) { var p = ti.m_p; var a = ti.m_a; var aget = ti.m_aget; var t = ti.EnsureCapacity(len2); Array.Copy(p, start2, t, 0, len2); long idx1 = start1 + len1 - 1, idx2 = len2 - 1; long dest = start2 + len2 - 1; p[dest--] = p[idx1--]; if (--len1 == 0) { Array.Copy(t, 0, p, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; return; } Func selector = ti.m_sel; long minGallop = ti.m_minGallop; while (true) { long count1 = 0, count2 = 0; do { if (selector(aget(a,t[idx2])) > selector(aget(a,p[idx1]))) { p[dest--] = p[idx1--]; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { p[dest--] = t[idx2--]; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - PermutationGallopRightDescending(p, a, aget, selector, t[idx2], start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; Array.Copy(p, idx1 + 1, p, dest + 1, count1); if (len1 == 0) goto breakouter; } p[dest--] = t[idx2--]; if (--len2 == 1) goto breakouter; count2 = len2 - PermutationGallopLeftDescending(t, a, aget, selector, p[idx1], 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; Array.Copy(t, idx2 + 1, p, dest + 1, count2); if (len2 <= 1) goto breakouter; } p[dest--] = p[idx1--]; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; Array.Copy(p, idx1 + 1, p, dest + 1, len1); p[dest] = t[idx2]; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else Array.Copy(t, 0, p, dest - (len2 - 1), len2); } private static long PermutationGallopLeftDescending( this long[] p, TArray a, Func aget, Func selector, long key, long start, long len, long hint) { long lastOfs = 0, ofs = 1; if (selector(aget(a,key)) < selector(aget(a,p[start + hint]))) { long maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) < selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { long maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) >= selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) < selector(aget(a,p[start + m]))) lastOfs = m + 1; else ofs = m; } return ofs; } private static long PermutationGallopRightDescending( this long[] p, TArray a, Func aget, Func selector, long key, long start, long len, long hint) { long ofs = 1, lastOfs = 0; if (selector(aget(a,key)) > selector(aget(a,p[start + hint]))) { long maxOfs = hint + 1; while (ofs < maxOfs && selector(aget(a,key)) > selector(aget(a,p[start + hint - ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; long tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { long maxOfs = len - hint; while (ofs < maxOfs && selector(aget(a,key)) <= selector(aget(a,p[start + hint + ofs]))) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { long m = lastOfs + ((ofs - lastOfs) >> 1); if (selector(aget(a,key)) > selector(aget(a,p[start + m]))) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void PermutationBinarySortDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl, long beginUnsorted) { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = p[beginUnsorted]; long l = beginIncl, r = beginUnsorted; while (l < r) { long mid = (l + r) >> 1; if (selector(aget(a,pivot)) > selector(aget(a,p[mid]))) r = mid; else l = mid + 1; } long n = beginUnsorted - l; switch (n) { case 2: p[l + 2] = p[l + 1]; p[l + 1] = p[l]; break; case 1: p[l + 1] = p[l]; break; default: Array.Copy(p, l, p, l + 1, n); break; } p[l] = pivot; } } private static long PermutationCountRunAndOrderDescending( this long[] p, TArray a, Func aget, Func selector, long beginIncl, long endExcl) { long runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (selector(aget(a,p[runHi++])) > selector(aget(a,p[beginIncl]))) { while (runHi < endExcl && selector(aget(a,p[runHi])) > selector(aget(a,p[runHi - 1]))) runHi++; ReverseRange(p, beginIncl, runHi); } else { while (runHi < endExcl && selector(aget(a,p[runHi])) <= selector(aget(a,p[runHi - 1]))) runHi++; } return runHi - beginIncl; } #endregion #region Auxiliary Functions, Structures, and Data /// /// Necessary for bit-field representation of smooth sort /// Leonardo heaps. /// private static int TrailingZeroBitCount(this long x) { x &= -x; int c = (x == 0) ? 1 : 0; if ((x & 0x00000000ffffffffL) == 0) c += 32; if ((x & 0x0000ffff0000ffffL) == 0) c += 16; if ((x & 0x00ff00ff00ff00ffL) == 0) c += 8; if ((x & 0x0f0f0f0f0f0f0f0fL) == 0) c += 4; if ((x & 0x3333333333333333L) == 0) c += 2; if ((x & 0x5555555555555555L) == 0) c += 1; return c; } /// /// Int Leonardo numbers (smooth sort). /// private static readonly int[] LP = { 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, 866988873, 1402817465 }; /// /// Long Leonardo numbers (smooth sort). /// private static readonly long[] LPLong = { 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, 866988873, 1402817465, 2269806339, 3672623805, 5942430145, 9615053951, 15557484097, 25172538049, 40730022147, 65902560197, 106632582345, 172535142543, 279167724889, 451702867433, 730870592323, 1182573459757, 1913444052081, 3096017511839, 5009461563921, 8105479075761, 13114940639683, 21220419715445, 34335360355129, 55555780070575, 89891140425705, 145446920496281, 235338060921987, 380784981418269, 616123042340257, 996908023758527, 1613031066098785, 2609939089857313, 4222970155956099, 6832909245813413, 11055879401769513, 17888788647582927, 28944668049352441, 46833456696935369, 75778124746287811, 122611581443223181, 198389706189510993, 321001287632734175, 519390993822245169, 840392281454979345, 1359783275277224515, 2200175556732203861, 3559958832009428377, 5760134388741632239 }; private static int TimSortMinRunLength(int n) { // assert n >= 0; int r = 0; // Becomes 1 if any 1 bits are shifted off while (n >= c_minMerge) { r |= (n & 1); n >>= 1; } return n + r; } private static long TimSortMinRunLength(long n) { // assert n >= 0; long r = 0; // Becomes 1 if any 1 bits are shifted off while (n >= c_minMerge) { r |= (n & 1); n >>= 1; } return n + r; } #endregion } } ================================================ FILE: src/Aardvark.Base/Sorting/Sorting_template.cs ================================================ using System; using System.Collections.Generic; using System.ComponentModel; namespace Aardvark.Base.Sorting { // AUTO GENERATED CODE - DO NOT CHANGE! public static class SortingExtensions { #region Constants /// Use insertion sort if count smaller than this (quicksort, quickmedian). private const int c_insertionSortThreshold = 31; private const int c_insertionMedianThreshold = 7; private const int c_minMerge = 32; private const int c_minGallop = 7; private const int c_initialTmpStorageLength = 256; #endregion /*CLASS# public struct Opt { public bool Generic; public bool Get; public bool Fun; public bool Perm; public bool Sel; } public static string OpFilter(string s) { if (s == " < ") return " > "; if (s == " > ") return " < "; if (s == " <= ") return " >= "; if (s == " >= ") return " <= "; return s; } public static void Cmp( Opt opt, Action pr, bool asc, string c, Action a, Action o, Action b) { if (!asc) Filter = OpFilter; if (opt.Generic && !opt.Sel) { if (opt.Fun) { pr(c); pr("("); } } if (opt.Sel) pr("selector("); if (opt.Perm) { if (opt.Get) pr("aget(a,"); else pr("a["); } a(0); if (opt.Perm) { if (opt.Get) pr(")"); else pr("]"); } if (opt.Sel) pr(")"); if (opt.Generic && !opt.Sel) { if (opt.Fun) pr(", "); else { pr("."); pr(c); pr("("); } } else o(0); if (opt.Sel) pr("selector("); if (opt.Perm) { if (opt.Get) pr("aget(a,"); else pr("a["); } b(0); if (opt.Perm) { if (opt.Get) pr(")"); else pr("]"); } if (opt.Sel) pr(")"); if (opt.Generic && !opt.Sel) { pr(")"); o(0); pr("0"); } if (!asc) Filter = null; } */ //# string add = " + ", sub = " - ", inc = "++", dec = "--"; //# string add1 = " + 1", add2 = " + 2", sub1 = " - 1"; //# var mathtypes = Meta.SignedVecFieldTypes.Select(t => t.Name); //# var generictypes = new [] { "T[]", "List", "TArray" }; //# foreach (var isGeneric in new[] { false, true }) { //# var types = isGeneric ? generictypes : mathtypes; //# foreach (var isNonGenericList in new[] { false, true }) { if (isGeneric && isNonGenericList) continue; //# foreach (var type in types) { //# var etype = isGeneric ? "T" : type; //# var atype = isGeneric ? type : (isNonGenericList ? "List<" + type + ">" : type + "[]"); //# var hasGet = atype == "TArray"; //# var isArray = atype.EndsWith("[]"); //# var isList = atype.EndsWith(">"); //# foreach (var isPerm in new[] { false, true }) { //# var permStr = isPerm ? "Perm" : ""; //# var p = isPerm ? "p[" : (hasGet ? "aget(a, " : "a["); //# var pt = isPerm ? "t[" : (hasGet ? "aget(t, " : "t["); //# var q = isPerm ? "]" : (hasGet ? ")" : "]"); //# var P = isPerm ? "p[" : (hasGet ? "aset(a, " : "a["); //# var I = isPerm ? "] = " : (hasGet ? ", " : "] = "); //# var Q = isPerm ? "" : (hasGet ? ")" : ""); //# var pa = isPerm ? "p" : "a"; //# var ta = isPerm ? "a" : "t"; //# var hasSet = hasGet && !isPerm; //# var copy = (isList || hasGet) && !isPerm ? "CopyElements" : "Array.Copy"; //# var agetset = hasSet ? "aget, aset, " : ""; //# var permName = isPerm ? "Permutation" : ""; //# var permNameSpace = isPerm ? "Permutation " : ""; #region __permNameSpace__Sort/Median for __atype__ //# foreach (var hasFun in new[] { true, false }) { if (hasFun && !isGeneric) continue; //# var isComparable = isGeneric && !hasFun; //# foreach (var hasSel in new[] { false, true }) { //# if (hasSel && hasFun) continue; //# if (hasSel && !isGeneric) continue; //# if (hasSel) isComparable = false; //# foreach (var ctype in mathtypes) { if (ctype != "int" && !hasSel) continue; //# var ctypecap = ctype.Capitalized(); //# foreach (var isAsc in new[] { true, false }) { if (hasFun && !isAsc) continue; //# foreach (var itype in new[] { "int", "long" }) { if (isList && itype == "long") continue; //# if (!isList && !isPerm && itype == "int") continue; //# var itypecast = isList ? "(" + itype + ")" : ""; //# var stype = isPerm ? itype : etype; // sort type //# var tatype = hasSet ? "TArray" : stype + "[]"; // temp array type //# var pdef = isPerm ? "-1" : "default("+stype+")"; //# var isLong = itype == "long"; //# var makeCreator = isPerm && (isArray || (isList && !isLong)); //# var longStr = isLong ? "Long" : ""; //# var agetcmp = (hasGet ? "aget, " : "") + (hasFun ? "cmp, " : "") + (hasSel ? "selector, " : ""); //# var alen = isPerm ? "p." + longStr + "Length" : //# (hasGet ? "count" : (isList ? "a.Count" : "a." + longStr + "Length")); //# var getLength = isArray ? longStr + "Length" : (isList ? "Count" : ""); //# var opt = new Opt { Generic = isGeneric, Get = hasGet, Fun = hasFun, Perm = isPerm, Sel = hasSel }; //# var ext = (isGeneric && hasFun) ? "" : (isAsc ? "Ascending" : "Descending"); //# var rext = (isGeneric && hasFun) ? "" : (isAsc ? "Descending" : "Ascending"); //# var uid = (isGeneric ? "" : type.Capitalized()) + (isList ? "List" : "") + permStr + longStr //# + (hasFun ? "Cmp" : isAsc ? "Asc" : "Desc"); //# var c = hasFun ? "cmp" : "CompareTo"; //# Action,Action,Action> cmp = (a,o,b) => Cmp(opt, Out, isAsc, c, a, o, b); //# foreach (var algo in new[] { "Median", "Sort" }) { //# var isSort = algo == "Sort"; var isMedian = algo == "Median"; //# var qname = "Quick" + algo; //# var qcall = permName + qname + ext; //# if (makeCreator) { /// //# if (isSort) { /// The CreatePermutationQuickSort algorithm returns an array of /// element indices p that reference the elements in the data array /// in sorted a manner. //# } else { /// The CreatePermutationQuickMedian algorithm returns an array of /// element indices p that reference the elements in the data array /// in a partially sorted manner, such that p[med] is placed at the /// correct position, and correctly partitions the array into larger /// and smaller elements. //# } /// //# if (hasGet) { [EditorBrowsable(EditorBrowsableState.Never)] //# } public static __itype__[] Create__qcall____longStr__/*# if (isGeneric) { *//*# } */( this __atype__ a/*# if (hasGet) { */, Func aget/*# } if (hasFun) { */, Func cmp/*# } if (hasSel) { */, Func selector/*# } if (isMedian) { */, __itype__ med/*# } */) //# if (isComparable) { where T : IComparable //# } { __itype__ len = a.__getLength__; var p = new __itype__[len].SetByIndex__longStr__(i => i); __qcall__(p, a, /*# if (hasGet) { */aget, /*# } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */0, len - 1, len - 1/*# if (isMedian) { */, med/*# } */); return p; } //# } /// //# if (isSort) { //# if (isPerm) { /// The PermutationQuickSort algorithm sorts the array of element /// indices p that reference the elements in the data array. //# } else { /// The QuickSort algorithm sorts the data array. //# } //# } else { //# if (isPerm) { /// The PermutationQuickMedian algorithm partially sorts the array of /// element indices p that reference the elements in the data array /// in such a way that p[med] is placed at the correct position. //# } else { /// The QuickMedian algorithm partially sorts the data array in such /// a way that the element at position med is correctly placed, and /// correctly partitions the array into larger and smaller elements. //# } //# } /// //# if (hasGet) { [EditorBrowsable(EditorBrowsableState.Never)] //# } public static void __qcall__/*# if (isGeneric) { *//*# } */( this /*# if (isPerm) { */__itype__[] p, /*# } */__atype__ a/*# if (hasGet) { */, /*# if (!isPerm) { */__itype__ count, /*# } */Func aget/*# if (!isPerm) { */, Action aset/*# } } if (hasFun) { */, Func cmp/*# } if (hasSel) { */, Func selector/*# } if (isMedian) { */, __itype__ med/*# } */) //# if (isComparable) { where T : IComparable //# } { __itype__ last = __alen__ - 1; __qcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */0, last, last/*# if (isMedian) { */, med/*# } */); } /// //# if (isSort) { //# if (isPerm) { /// The PermutationQuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of element indices p that reference the /// elements in the data array. //# } else { /// The QuickSort algorithm sorts the range [beginIncl, /// endExcl) of the array of elements in the data array. //# } //# } else { //# if (isPerm) { /// The PermutationQuickMedian algorithm partially sorts the range /// [beginIncl, endExcl) of the array of element indices p /// that reference the elements in the data array in such a way that /// p[med] is placed at the correct position, and correctly partitions /// this array range into larger and smaller elements. //# } else { /// The QuickMedian algorithm partially sorts the range [beginIncl, /// endExcl) of the data array in such a way that the element at /// position med is correctly placed, and correctly partitions this /// array range into larger and smaller elements. //# } //# } /// //# if (hasGet) { [EditorBrowsable(EditorBrowsableState.Never)] //# } public static void __qcall__/*# if (isGeneric) { *//*# } */( this /*# if (isPerm) { */__itype__[] p, /*# } */__atype__ a,/*# if (hasGet) { */ Func aget,/*# if (!isPerm) { */ Action aset,/*# } } */ //# if (hasFun) { Func cmp, //# } //# if (hasSel) { Func selector, //# } __itype__ beginIncl, __itype__ endExcl/*# if (isMedian) { */, __itype__ med/*# } */) //# if (isComparable) { where T : IComparable //# } { __qcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */beginIncl, endExcl - 1, endExcl - beginIncl - 1/*# if (isMedian) { */, med/*# } */); } /* This implementation of __qname__ is based on the paper "Dual-Pivot Quicksort" by Vladimir Yaroslavskiy . */ private static void __qcall__/*# if (isGeneric) { *//*# } */( this /*# if (isPerm) { */__itype__[] p, /*# } */__atype__ a,/*# if (hasGet) { */ Func aget,/*# if (!isPerm) { */ Action aset,/*# } } */ //# if (hasFun) { Func cmp, //# } //# if (hasSel) { Func selector, //# } __itype__ l, __itype__ r, __itype__ countSub1/*# if (isMedian) { */, __itype__ med/*# } */) //# if (isComparable) { where T : IComparable //# } { while (countSub1 >= c_insertion__algo__Threshold) { __itype__ sixth = (1 + countSub1) / 6; __itype__ e1 = l + sixth; __itype__ e5 = r - sixth; __itype__ e3 = (l + r) >> 1; __itype__ e4 = e3 + sixth; __itype__ e2 = e3 - sixth; if (/*#cmp(a=>{*/__p__e1__q__/*#},o=>{*/ > /*#},b=>{*/__p__e2__q__/*#});*/) { var t = __p__e1__q__; __P__e1__I____p__e2__q____Q__; __P__e2__I__t__Q__; } if (/*#cmp(a=>{*/__p__e4__q__/*#},o=>{*/ > /*#},b=>{*/__p__e5__q__/*#});*/) { var t = __p__e4__q__; __P__e4__I____p__e5__q____Q__; __P__e5__I__t__Q__; } if (/*#cmp(a=>{*/__p__e1__q__/*#},o=>{*/ > /*#},b=>{*/__p__e3__q__/*#});*/) { var t = __p__e1__q__; __P__e1__I____p__e3__q____Q__; __P__e3__I__t__Q__; } if (/*#cmp(a=>{*/__p__e2__q__/*#},o=>{*/ > /*#},b=>{*/__p__e3__q__/*#});*/) { var t = __p__e2__q__; __P__e2__I____p__e3__q____Q__; __P__e3__I__t__Q__; } if (/*#cmp(a=>{*/__p__e1__q__/*#},o=>{*/ > /*#},b=>{*/__p__e4__q__/*#});*/) { var t = __p__e1__q__; __P__e1__I____p__e4__q____Q__; __P__e4__I__t__Q__; } if (/*#cmp(a=>{*/__p__e3__q__/*#},o=>{*/ > /*#},b=>{*/__p__e4__q__/*#});*/) { var t = __p__e3__q__; __P__e3__I____p__e4__q____Q__; __P__e4__I__t__Q__; } if (/*#cmp(a=>{*/__p__e2__q__/*#},o=>{*/ > /*#},b=>{*/__p__e5__q__/*#});*/) { var t = __p__e2__q__; __P__e2__I____p__e5__q____Q__; __P__e5__I__t__Q__; } if (/*#cmp(a=>{*/__p__e2__q__/*#},o=>{*/ > /*#},b=>{*/__p__e3__q__/*#});*/) { var t = __p__e2__q__; __P__e2__I____p__e3__q____Q__; __P__e3__I__t__Q__; } if (/*#cmp(a=>{*/__p__e4__q__/*#},o=>{*/ > /*#},b=>{*/__p__e5__q__/*#});*/) { var t = __p__e4__q__; __P__e4__I____p__e5__q____Q__; __P__e5__I__t__Q__; } var p1 = __p__e2__q__; __P__e2__I____p__l__q____Q__; var p2 = __p__e4__q__; __P__e4__I____p__r__q____Q__; __itype__ lo = l + 1; __itype__ hi = r - 1; bool pivotsDiffer = /*#cmp(a=>{*/p1/*#},o=>{*/ != /*#},b=>{*/p2/*#});*/; if (pivotsDiffer) { for (__itype__ i = lo; i <= hi; i++) { var ai = __p__i__q__; if (/*#cmp(a=>{*/ai/*#},o=>{*/ < /*#},b=>{*/p1/*#});*/) { __P__i__I____p__lo__q____Q__; __P__lo__I__ai__Q__; ++lo; } else if (/*#cmp(a=>{*/ai/*#},o=>{*/ > /*#},b=>{*/p2/*#});*/) { while (/*#cmp(a=>{*/__p__hi__q__/*#},o=>{*/ > /*#},b=>{*/p2/*#});*/ && i < hi) --hi; __P__i__I____p__hi__q____Q__; __P__hi__I__ai__Q__; --hi; ai = __p__i__q__; if (/*#cmp(a=>{*/ai/*#},o=>{*/ < /*#},b=>{*/p1/*#});*/) { __P__i__I____p__lo__q____Q__; __P__lo__I__ai__Q__; ++lo; } } } } else { for (__itype__ i = lo; i <= hi; i++) { var ai = __p__i__q__; if (/*#cmp(a=>{*/ai/*#},o=>{*/ == /*#},b=>{*/p1/*#});*/) continue; if (/*#cmp(a=>{*/ai/*#},o=>{*/ < /*#},b=>{*/p1/*#});*/) { __P__i__I____p__lo__q____Q__; __P__lo__I__ai__Q__; ++lo; } else { while (/*#cmp(a=>{*/__p__hi__q__/*#},o=>{*/ > /*#},b=>{*/p1/*#});*/) --hi; __P__i__I____p__hi__q____Q__; __P__hi__I__ai__Q__; --hi; ai = __p__i__q__; if (/*#cmp(a=>{*/ai/*#},o=>{*/ < /*#},b=>{*/p1/*#});*/) { __P__i__I____p__lo__q____Q__; __P__lo__I__ai__Q__; ++lo; } } } } __P__l__I____p__lo__sub__1__q____Q__; __P__lo__sub__1__I__p1__Q__; __P__r__I____p__hi__add__1__q____Q__; __P__hi__add__1__I__p2__Q__; __itype__ cl = lo - 2 - l; __itype__ cr = r - hi - 2; if (pivotsDiffer) { if (lo < e1 && e5 < hi) { //# if (isSort) { __qcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */l, lo - 2, cl); __qcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */hi + 2, r, cr); //# } // isSort //# if (isMedian) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else //# } // isMedian { while (/*#cmp(a=>{*/__p__lo__q__/*#},o=>{*/ == /*#},b=>{*/p1/*#});*/) ++lo; for (__itype__ i = lo + 1; i <= hi; i++) { if (/*#cmp(a=>{*/__p__i__q__/*#},o=>{*/ == /*#},b=>{*/p1/*#});*/) { /*# if (isGeneric || isPerm) { */p1 = __p__i__q__; /*# } */__P__i__I____p__lo__q____Q__; __P__lo__I__p1__Q__; ++lo; } } while (/*#cmp(a=>{*/__p__hi__q__/*#},o=>{*/ == /*#},b=>{*/p2/*#});*/) --hi; for (__itype__ i = hi - 1; i >= lo; i--) { if (/*#cmp(a=>{*/__p__i__q__/*#},o=>{*/ == /*#},b=>{*/p2/*#});*/) { /*# if (isGeneric || isPerm) { */p2 = __p__i__q__; /*# } */__P__i__I____p__hi__q____Q__; __P__hi__I__p2__Q__; --hi; } } //# if (isMedian) { if (med < lo || med > hi) return; //# } // isMedian l = lo; r = hi; countSub1 = hi - lo; } } else { //# if (isSort) { __itype__ cm = hi - lo; if (cl > cr) { if (cl > cm) { __qcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */lo, hi, cm); __qcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { __qcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */l, lo - 2, cl); __qcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } else { if (cr > cm) { __qcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */l, lo - 2, cl); __qcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */lo, hi, cm); l = hi + 2; countSub1 = cr; } else { __qcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */l, lo - 2, cl); __qcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */hi + 2, r, cr); l = lo; r = hi; countSub1 = cm; } } //# } // isSort //# if (isMedian) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else if (med >= lo && med <= hi) { l = lo; r = hi; countSub1 = hi - lo; } else return; //# } // isMedian } } else { //# if (isSort) { if (cl > cr) { __qcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */hi + 2, r, cr); r = lo - 2; countSub1 = cl; } else { __qcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */l, lo - 2, cl); l = hi + 2; countSub1 = cr; } //# } // isSort //# if (isMedian) { if (med <= lo - 2) { r = lo - 2; countSub1 = cl; } else if (med >= hi + 2) { l = hi + 2; countSub1 = cr; } else return; //# } // isMedian } } for (__itype__ i = l + 1; i <= r; i++) { var ai = __p__i__q__; __itype__ j; for (j = i - 1; j >= l && /*#cmp(a=>{*/ai/*#},o=>{*/ < /*#},b=>{*/__p__j__q__/*#});*/; j--) __P__j__add__1__I____p__j__q____Q__; __P__j__add__1__I__ai__Q__; } } //# } // algo //# var hcall = permName + "HeapSort" + ext; //# if (makeCreator) { /// /// The PermutationHeapSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// It is slower than the PermutationQuickSort algorithm, but /// is not affected by the data distribution in any way, even if /// there are a huge number of equal data elements. /// //# if (hasGet) { [EditorBrowsable(EditorBrowsableState.Never)] //# } public static __itype__[] Create__hcall____longStr__/*# if (isGeneric) { *//*# } */( this __atype__ a/*# if (hasGet) { */, Func aget/*# } if (hasFun) { */, Func cmp/*# } if (hasSel) { */, Func selector/*# } */) //# if (isComparable) { where T : IComparable //# } { __itype__ len = a.__getLength__; var p = new __itype__[len].SetByIndex__longStr__(i => i); __hcall__(p, a/*# if (hasGet) { */, aget/*# } if (hasFun) { */, cmp/*# } if (hasSel) { */, selector/*# } */); return p; } //# } //# foreach (var range in new[] { true, false }) { var r = range ? " + begin" : ""; /// //# if (isPerm) { /// The PermutationHeapSort algorithm sorts the array of element /// indices p that reference the elements in the data array. //# } else { /// The HeapSort algorithm sorts the data array. //# } /// It is slower than the __permName__QuickSort algorithm, /// but is not affected by the data distribution in any /// way, even if there are a huge number of equal data elements. /// //# if (hasGet) { [EditorBrowsable(EditorBrowsableState.Never)] //# } public static void __hcall__/*# if (isGeneric) { *//*# } */( this /*# if (isPerm) { */__itype__[] p, /*# } */__atype__ a/*# if (hasGet) { */, /*# if (!isPerm && !range) { */__itype__ count, /*# } */Func aget/*# if (!isPerm) { */, Action aset/*# } } if (hasFun) { */, Func cmp/*# } if (hasSel) { */, Func selector/*# } if (range) { */, __itype__ begin, __itype__ end/*# }*/) //# if (isComparable) { where T : IComparable //# } { //# if (alen != "count" && !range) { __itype__ count = __alen__; //# } //# if (range) { __itype__ count = end - begin; //# } for (__itype__ c = 1; c < count; c++) { var element = __p__c__r____q__; __itype__ i = c; while (i > 0) { __itype__ i2 = (i - 1) / 2; if (/*#cmp(a=>{*/element/*#},o=>{*/ < /*#},b=>{*/__p__i2__r____q__/*#});*/) break; __P__i__r____I____p__i2__r____q____Q__; i = i2; } __P__i__r____I__element__Q__; } while (count > 1) { --count; var element = __p__count__r____q__; __P__count__r____I____p__0__r____q____Q__; __itype__ i = 0, i1 = 1; while (i1 < count) // at least one child { __itype__ i2 = i1 + 1; __itype__ ni = (i2 < count // two children? && /*#cmp(a=>{*/__p__i1__r____q__/*#},o=>{*/ < /*#},b=>{*/__p__i2__r____q__/*#});*/) ? i2 : i1; // smaller child if (/*#cmp(a=>{*/__p__ni__r____q__/*#},o=>{*/ < /*#},b=>{*/element/*#});*/) break; __P__i__r____I____p__ni__r____q____Q__; i = ni; i1 = 2 * i + 1; } __P__i__r____I__element__Q__; } } //# } // range //# var scall = permName + "SmoothSort" + ext; //# if (makeCreator) { /// /// The PermutationSmoothSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// //# if (hasGet) { [EditorBrowsable(EditorBrowsableState.Never)] //# } public static __itype__[] Create__scall____longStr__/*# if (isGeneric) { *//*# } */( this __atype__ a/*# if (hasGet) { */, Func aget/*# } if (hasFun) { */, Func cmp/*# } if (hasSel) { */, Func selector/*# } */) //# if (isComparable) { where T : IComparable //# } { __itype__ len = a.__getLength__; var p = new __itype__[len].SetByIndex__longStr__(i => i); __scall__(p, a/*# if (hasGet) { */, aget/*# } if (hasFun) { */, cmp/*# } if (hasSel) { */, selector/*# } */); return p; } //# } //# if (hasGet) { [EditorBrowsable(EditorBrowsableState.Never)] //# } public static void __scall__/*# if (isGeneric) { *//*# } */( this /*# if (isPerm) { */__itype__[] p, /*# } */__atype__ a/*# if (hasGet) { */, /*# if (!isPerm) { */__itype__ count, /*# } */Func aget/*# if (!isPerm) { */, Action aset/*# } } if (hasFun) { */, Func cmp/*# } if (hasSel) { */, Func selector/*# } */) //# if (isComparable) { where T : IComparable //# } { __scall__InclusiveRange(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */0, __alen__ - 1); } //# if (hasGet) { [EditorBrowsable(EditorBrowsableState.Never)] //# } public static void __scall__/*# if (isGeneric) { *//*# } */( this /*# if (isPerm) { */__itype__[] p, /*# } */__atype__ a,/*# if (hasGet) { */ Func aget,/*# if (!isPerm) { */ Action aset,/*# } } */ //# if (hasFun) { Func cmp, //# } //# if (hasSel) { Func selector, //# } __itype__ beginIncl, __itype__ endExcl) //# if (isComparable) { where T : IComparable //# } { __scall__InclusiveRange(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */beginIncl, endExcl - 1); } private static void __scall__InclusiveRange/*# if (isGeneric) { *//*# } */( this /*# if (isPerm) { */__itype__[] p, /*# } */__atype__ a,/*# if (hasGet) { */ Func aget,/*# if (!isPerm) { */ Action aset,/*# } } */ //# if (hasFun) { Func cmp, //# } //# if (hasSel) { Func selector, //# } __itype__ lo, __itype__ hi) //# if (isComparable) { where T : IComparable //# } { __itype__ head = lo; long pbits = 1; int pshift = 1; while (head < hi) { if ((pbits & 3) == 3) { __scall__Sift(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */pshift, head); pbits >>= 2; pshift += 2; } else { if (LP__longStr__[pshift - 1] >= hi - head) __scall__Trinkle(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */pbits, pshift, head, false); else __scall__Sift(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */pshift, head); if (pshift == 1) { pbits <<= 1; pshift--; } else { pbits <<= (pshift - 1); pshift = 1; } } pbits |= 1; head++; } __scall__Trinkle(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */pbits, pshift, head, false); while (pshift != 1 || pbits != 1) { if (pshift <= 1) { int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; } else { pbits <<= 2; pbits ^= 7; pshift -= 2; __scall__Trinkle(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */pbits >> 1, pshift + 1, head - LP__longStr__[pshift] - 1, true); __scall__Trinkle(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */pbits, pshift, head - 1, true); } head--; } } private static void __scall__Sift/*# if (isGeneric) { *//*# } */( this /*# if (isPerm) { */__itype__[] p, /*# } */__atype__ a,/*# if (hasGet) { */ Func aget,/*# if (!isPerm) { */ Action aset,/*# } } */ //# if (hasFun) { Func cmp, //# } //# if (hasSel) { Func selector, //# } int pshift, __itype__ head) //# if (isComparable) { where T : IComparable //# } { var val = __p__head__q__; while (pshift > 1) { __itype__ rt = head - 1; __itype__ lf = head - 1 - LP__longStr__[pshift - 2]; if (/*#cmp(a=>{*/val/*#},o=>{*/ >= /*#},b=>{*/__p__lf__q__/*#});*/ && /*#cmp(a=>{*/val/*#},o=>{*/ >= /*#},b=>{*/__p__rt__q__/*#});*/) break; if (/*#cmp(a=>{*/__p__lf__q__/*#},o=>{*/ >= /*#},b=>{*/__p__rt__q__/*#});*/) { __P__head__I____p__lf__q____Q__; head = lf; pshift -= 1; } else { __P__head__I____p__rt__q____Q__; head = rt; pshift -= 2; } } __P__head__I__val__Q__; } private static void __scall__Trinkle/*# if (isGeneric) { *//*# } */( this /*# if (isPerm) { */__itype__[] p, /*# } */__atype__ a,/*# if (hasGet) { */ Func aget,/*# if (!isPerm) { */ Action aset,/*# } } */ //# if (hasFun) { Func cmp, //# } //# if (hasSel) { Func selector, //# } long pbits, int pshift, __itype__ head, bool isTrusty) //# if (isComparable) { where T : IComparable //# } { var val = __p__head__q__; while (pbits != 1) { __itype__ stepson = head - LP__longStr__[pshift]; var vstepson = __p__stepson__q__; if (/*#cmp(a=>{*/vstepson/*#},o=>{*/ <= /*#},b=>{*/val/*#});*/) break; if (!isTrusty && pshift > 1) { __itype__ rt = head - 1; __itype__ lf = head - 1 - LP__longStr__[pshift - 2]; if (/*#cmp(a=>{*/__p__rt__q__/*#},o=>{*/ >= /*#},b=>{*/vstepson/*#});*/ || /*#cmp(a=>{*/__p__lf__q__/*#},o=>{*/ >= /*#},b=>{*/vstepson/*#});*/) break; } __P__head__I__vstepson__Q__; head = stepson; int trail = TrailingZeroBitCount(pbits & ~1); pbits >>= trail; pshift += trail; isTrusty = false; } if (!isTrusty) { __P__head__I__val__Q__; __scall__Sift(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */pshift, head); } } //# var tsi = "TimSortInfo" + (isList ? "List" : "") + permStr + longStr //# + (hasGet ? "Get" : "") + (hasFun ? "Cmp" : "") + (hasSel ? ctypecap + "Sel" : ""); //# var mb = "m_"; //# if (isGeneric && (hasFun || isAsc)) { public class __tsi__ //# if (!hasFun && !hasSel) { where T : IComparable //# } { //# if (isPerm) { public __itype__[] m_p; //# } public __atype__ m_a; //# if (hasGet) { public __itype__ m_count; public Func m_aget; //# if (!isPerm) { public Action m_aset; public Func m_amake; //# } //# } //# if (hasFun) { public Func m_cmp; //# } //# if (hasSel) { public Func m_sel; //# } public __itype__ m_minGallop = c_minGallop; //# if (hasSet) { public TArray m_tmp; public long m_len; //# } else { public __stype__[] m_tmp; //# } public int m_stackSize = 0; public __itype__[] m_runStart; public __itype__[] m_runLen; public __tsi__(/*# if (isPerm) { */__itype__[] p, /*# } */__atype__ a/*# if (hasGet) { */, Func aget/*# if (!isPerm) { */, Action aset, Func amake/*# } } if (hasFun) { */, Func cmp/*# } if (hasSel) { */, Func selector/*# } if (hasGet) { */, __itype__ count/*# } */) { /*# if (isPerm) { */m_p = p; /*# } */m_a = a;/*# if (hasGet) { */ m_count = count;/*# } */ /*# if (hasGet) { */m_aget = aget; /*# if (!isPerm) { */m_aset = aset; m_amake = amake; /*# } } if (hasFun) { */m_cmp = cmp;/*# } if (hasSel) { */m_sel = selector;/*# } */ //# if (!hasGet) { __itype__ count = __alen__; //# } //# if (hasSet) { m_len = count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength; m_tmp = amake(m_len); //# } else { m_tmp = new __stype__[count < 2 * c_initialTmpStorageLength ? count >> 1 : c_initialTmpStorageLength]; //# } int stackLen = (count < 120 ? 5 : count < 1542 ? 10 : count < 119151 ? 19 : 40); m_runStart = new __itype__[stackLen]; m_runLen = new __itype__[stackLen]; } public void PushRun(__itype__ runStart, __itype__ runLen) { m_runStart[m_stackSize] = runStart; m_runLen[m_stackSize] = runLen; m_stackSize++; } public __tatype__ EnsureCapacity(__itype__ cap) { //# var tlen = hasSet ? "m_len" : "m_tmp." + longStr + "Length"; if (__tlen__ < cap) { __itype__ c = cap; c |= c >> 1; c |= c >> 2; c |= c >> 4; c |= c >> 8; c |= c >> 16;/*# if (isLong) { */ c |= c >> 32;/*# } */ c++; //# if (hasSet) { m_len = c < 0 ? cap : Math.Min(c, __mb____alen__ >> 1); m_tmp = m_amake(m_len); //# } else { m_tmp = new __stype__[c < 0 ? cap : Math.Min(c, __mb____alen__ >> 1)]; //# } } return m_tmp; } } //# } // isGeneric && (hasFun || isAsc) //# var tcall = permName + "TimSort" + ext; //# var glcall = permName + "GallopLeft" + ext; //# var grcall = permName + "GallopRight" + ext; //# var bcall = permName + "BinarySort" + ext; //# var crcall = permName + "CountRunAndOrder" + ext; //# if (makeCreator) { /// /// The PermutationTimSort algorithm returns an array of element /// indices that enumerate the array elements in sorted fashion. /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// //# if (hasGet) { [EditorBrowsable(EditorBrowsableState.Never)] //# } public static __itype__[] Create__tcall____longStr__/*# if (isGeneric) { *//*# } */( this __atype__ a/*# if (hasGet) { */, Func aget/*# } if (hasFun) { */, Func cmp/*# } if (hasSel) { */, Func selector/*# } */) //# if (isComparable) { where T : IComparable //# } { __itype__ len = a.__getLength__; var p = new __itype__[len].SetByIndex__longStr__(i => i); __tcall__(p, a/*# if (hasGet) { */, aget/*# } if (hasFun) { */, cmp/*# } if (hasSel) { */, selector/*# } */); return p; } //# } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// //# if (hasGet) { [EditorBrowsable(EditorBrowsableState.Never)] //# } public static void __tcall__/*# if (isGeneric) { *//*# } */( this /*# if (isPerm) { */__itype__[] p, /*# } */__atype__ a/*# if (hasGet) { */, /*# if (!isPerm) { */__itype__ count, /*# } */Func aget/*# if (!isPerm) { */, Action aset, Func amake/*# } } if (hasFun) { */, Func cmp/*# } if (hasSel) { */, Func selector/*# } */) //# if (isComparable) { where T : IComparable //# } { __tcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, amake, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */0, __alen__); } /// /// The TimSort algorithm is not as fast as QuickSort for completely /// randomized arrays, but is a bit faster for mostly sorted or /// mostly reversed arrays. Additionally it is a stable algorithm. /// //# if (hasGet) { [EditorBrowsable(EditorBrowsableState.Never)] //# } public static void __tcall__/*# if (isGeneric) { *//*# } */( this /*# if (isPerm) { */__itype__[] p, /*# } */__atype__ a,/*# if (hasGet) { */ Func aget,/*# if (!isPerm) { */ Action aset, Func amake,/*# } } */ //# if (hasFun) { Func cmp, //# } //# if (hasSel) { Func selector, //# } __itype__ lo, __itype__ hi) //# if (isComparable) { where T : IComparable //# } { /* An implementation of the TimSort Algorithm which was invented by Tim Peters in 2002 for use in the Python programming language. */ __itype__ count = hi - lo; if (count < 2) return; if (count < c_minMerge) { var initRunLen = __crcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */lo, hi); __bcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */lo, hi, lo + initRunLen); return; } var ti = new __tsi__(/*# if (isPerm) { */p, /*# } */a/*# if (hasGet) { */, aget/*# if (!isPerm) { */, aset, amake/*# } } if (hasFun) { */, cmp/*# } if (hasSel) { */, selector/*# } if (hasGet) { */, count/*# } */); __itype__ minRun = TimSortMinRunLength(count); do { __itype__ runLen = __crcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */lo, hi); if (runLen < minRun) { __itype__ force = count <= minRun ? count : minRun; __bcall__(/*# if (isPerm) { */p, /*# } */a, /*# if (hasGet) { */aget, /*# if (!isPerm) { */aset, /*# } } if (hasFun) { */cmp, /*# } if (hasSel) { */selector, /*# } */lo, lo + force, lo + runLen); runLen = force; } ti.PushRun(lo, runLen); MergeCollapse__uid__(ti); lo += runLen; count -= runLen; } while (count != 0); MergeForceCollapse__uid__(ti); } private static void MergeCollapse__uid__/*# if (isGeneric) { *//*# } */(this __tsi__ ti) //# if (isComparable) { where T : IComparable //# } { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] <= ti.m_runLen[n] + ti.m_runLen[n + 1]) { if (ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAt__uid__(ti, n); } else if (ti.m_runLen[n] <= ti.m_runLen[n + 1]) MergeAt__uid__(ti, n); else break; } } private static void MergeForceCollapse__uid__/*# if (isGeneric) { *//*# } */(this __tsi__ ti) //# if (isComparable) { where T : IComparable //# } { while (ti.m_stackSize > 1) { int n = ti.m_stackSize - 2; if (n > 0 && ti.m_runLen[n - 1] < ti.m_runLen[n + 1]) n--; MergeAt__uid__(ti, n); } } private static void MergeAt__uid__/*# if (isGeneric) { *//*# } */(this __tsi__ ti, int i) //# if (isComparable) { where T : IComparable //# } { __itype__ start1 = ti.m_runStart[i], len1 = ti.m_runLen[i]; __itype__ start2 = ti.m_runStart[i + 1], len2 = ti.m_runLen[i + 1]; ti.m_runLen[i] = len1 + len2; if (i == ti.m_stackSize - 3) { ti.m_runStart[i + 1] = ti.m_runStart[i + 2]; ti.m_runLen[i + 1] = ti.m_runLen[i + 2]; } ti.m_stackSize--; var a = ti.m_a; __itype__ k = __grcall__(/*# if (isPerm) { */ti.m_p, /*# } */a, /*# if (hasGet) { */ti.m_aget, /*# } if (hasFun) { */ti.m_cmp, /*# } if (hasSel) { */ti.m_sel, /*# } */ti.__mb____p__start2__q__, start1, len1, 0); len1 -= k; if (len1 == 0) return; start1 += k; len2 = __glcall__(/*# if (isPerm) { */ti.m_p, /*# } */a, /*# if (hasGet) { */ti.m_aget, /*# } if (hasFun) { */ti.m_cmp, /*# } if (hasSel) { */ti.m_sel, /*# } */ti.__mb____p__start1__add__len1__sub1____q__, start2, len2, len2 - 1); if (len2 == 0) return; if (len1 <= len2) MergeLo__uid__(ti, start1, len1, start2, len2); else MergeHi__uid__(ti, start1, len1, start2, len2); } private static void MergeLo__uid__/*# if (isGeneric) { *//*# } */(this __tsi__ ti, __itype__ start1, __itype__ len1, __itype__ start2, __itype__ len2) //# if (isComparable) { where T : IComparable //# } { //# if (isPerm) { var p = ti.m_p; //# } var a = ti.m_a; //# if (hasGet) { var aget = ti.m_aget; //# if (!isPerm) { var aset = ti.m_aset; //# } } var t = ti.EnsureCapacity(len1); __copy__(__agetset____pa__, start1, t, 0, len1); __itype__ idx1 = 0, idx2 = start2; __itype__ dest = start1; __P__dest__inc____I____p__idx2__inc____q____Q__; if (--len2 == 0) { __copy__(__agetset__t, idx1, __pa__, dest, len1); return; } if (len1 == 1) { __copy__(__agetset____pa__, idx2, __pa__, dest, len2); __P__dest__add__len2__I____pt__idx1__q____Q__; return; } //# if (hasFun) { Func cmp = ti.m_cmp; //# } //# if (hasSel) { Func selector = ti.m_sel; //# } __itype__ minGallop = ti.m_minGallop; while (true) { __itype__ count1 = 0, count2 = 0; do { if (/*#cmp(a=>{*/__p__idx2__q__/*#},o=>{*/ < /*#},b=>{*/__pt__idx1__q__/*#});*/) { __P__dest__inc____I____p__idx2__inc____q____Q__; count2++; count1 = 0; if (--len2 == 0) goto breakouter; } else { __P__dest__inc____I____pt__idx1__inc____q____Q__; count1++; count2 = 0; if (--len1 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = __itypecast____grcall__(/*# if (isPerm) { */t, /*# } */__ta__, __agetcmp____p__idx2__q__, idx1, len1, 0); if (count1 != 0) { __copy__(__agetset__t, idx1, __pa__, dest, count1); dest += count1; idx1 += count1; len1 -= count1; if (len1 <= 1) goto breakouter; } __P__dest__inc____I____p__idx2__inc____q____Q__; if (--len2 == 0) goto breakouter; count2 = __glcall__(/*# if (isPerm) { */p, /*# } */a, __agetcmp____pt__idx1__q__, idx2, len2, 0); if (count2 != 0) { __copy__(__agetset____pa__, idx2, __pa__, dest, count2); dest += count2; idx2 += count2; len2 -= count2; if (len2 == 0) goto breakouter; } __P__dest__inc____I____pt__idx1__inc____q____Q__; if (--len1 == 1) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; // Penalize for leaving gallop mode } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len1 == 1) { __copy__(__agetset____pa__, idx2, __pa__, dest, len2); __P__dest__add__len2__I____pt__idx1__q____Q__; } else if (len1 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else __copy__(__agetset__t, idx1, __pa__, dest, len1); } private static void MergeHi__uid__/*# if (isGeneric) { *//*# } */(this __tsi__ ti, __itype__ start1, __itype__ len1, __itype__ start2, __itype__ len2) //# if (isComparable) { where T : IComparable //# } { //# if (isPerm) { var p = ti.m_p; //# } var a = ti.m_a; //# if (hasGet) { var aget = ti.m_aget; //# if (!isPerm) { var aset = ti.m_aset; //# } } var t = ti.EnsureCapacity(len2); __copy__(__agetset____pa__, start2, t, 0, len2); __itype__ idx1 = start1 + len1 - 1, idx2 = len2 - 1; __itype__ dest = start2 + len2 - 1; __P__dest__dec____I____p__idx1__dec____q____Q__; if (--len1 == 0) { __copy__(__agetset__t, 0, __pa__, dest - (len2 - 1), len2); return; } if (len2 == 1) { idx1 -= len1; dest -= len1; __copy__(__agetset____pa__, idx1 + 1, __pa__, dest + 1, len1); __P__dest__I____pt__idx2__q____Q__; return; } //# if (hasFun) { Func cmp = ti.m_cmp; //# } //# if (hasSel) { Func selector = ti.m_sel; //# } __itype__ minGallop = ti.m_minGallop; while (true) { __itype__ count1 = 0, count2 = 0; do { if (/*#cmp(a=>{*/__pt__idx2__q__/*#},o=>{*/ < /*#},b=>{*/__p__idx1__q__/*#});*/) { __P__dest__dec____I____p__idx1__dec____q____Q__; count1++; count2 = 0; if (--len1 == 0) goto breakouter; } else { __P__dest__dec____I____pt__idx2__dec____q____Q__; count2++; count1 = 0; if (--len2 == 1) goto breakouter; } } while ((count1 | count2) < minGallop); do { count1 = len1 - __grcall__(/*# if (isPerm) { */p, /*# } */a, __agetcmp____pt__idx2__q__, start1, len1, len1 - 1); if (count1 != 0) { dest -= count1; idx1 -= count1; len1 -= count1; __copy__(__agetset____pa__, idx1 + 1, __pa__, dest + 1, count1); if (len1 == 0) goto breakouter; } __P__dest__dec____I____pt__idx2__dec____q____Q__; if (--len2 == 1) goto breakouter; count2 = len2 - __itypecast____glcall__(/*# if (isPerm) { */t, /*# } */__ta__, __agetcmp____p__idx1__q__, 0, len2, len2 - 1); if (count2 != 0) { dest -= count2; idx2 -= count2; len2 -= count2; __copy__(__agetset__t, idx2 + 1, __pa__, dest + 1, count2); if (len2 <= 1) goto breakouter; } __P__dest__dec____I____p__idx1__dec____q____Q__; if (--len1 == 0) goto breakouter; minGallop--; } while (count1 >= c_minGallop | count2 >= c_minGallop); if (minGallop < 0) minGallop = 0; minGallop += 2; } breakouter: ti.m_minGallop = minGallop < 1 ? 1 : minGallop; if (len2 == 1) { dest -= len1; idx1 -= len1; __copy__(__agetset____pa__, idx1 + 1, __pa__, dest + 1, len1); __P__dest__I____pt__idx2__q____Q__; } else if (len2 == 0) throw new ArgumentException( "Comparison method violates its general contract!"); else __copy__(__agetset__t, 0, __pa__, dest - (len2 - 1), len2); } private static __itype__ __glcall__/*# if (isGeneric) { *//*# } */( this /*# if (isPerm) { */__itype__[] p, /*# } */__atype__ a,/*# if (hasGet) { */ Func aget,/*# } */ //# if (hasFun) { Func cmp, //# } //# if (hasSel) { Func selector, //# } __stype__ key, __itype__ start, __itype__ len, __itype__ hint) //# if (isComparable) { where T : IComparable //# } { __itype__ lastOfs = 0, ofs = 1; if (/*#cmp(a=>{*/key/*#},o=>{*/ > /*#},b=>{*/__p__start__add__hint__q__/*#});*/) { __itype__ maxOfs = len - hint; while (ofs < maxOfs && /*#cmp(a=>{*/key/*#},o=>{*/ > /*#},b=>{*/__p__start__add__hint__add__ofs__q__/*#});*/) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } else { __itype__ maxOfs = hint + 1; while (ofs < maxOfs && /*#cmp(a=>{*/key/*#},o=>{*/ <= /*#},b=>{*/__p__start__add__hint__sub__ofs__q__/*#});*/) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; __itype__ tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } lastOfs++; while (lastOfs < ofs) { __itype__ m = lastOfs + ((ofs - lastOfs) >> 1); if (/*#cmp(a=>{*/key/*#},o=>{*/ > /*#},b=>{*/__p__start__add__m__q__/*#});*/) lastOfs = m + 1; else ofs = m; } return ofs; } private static __itype__ __grcall__/*# if (isGeneric) { *//*# } */( this /*# if (isPerm) { */__itype__[] p, /*# } */__atype__ a,/*# if (hasGet) { */ Func aget,/*# } */ //# if (hasFun) { Func cmp, //# } //# if (hasSel) { Func selector, //# } __stype__ key, __itype__ start, __itype__ len, __itype__ hint) //# if (isComparable) { where T : IComparable //# } { __itype__ ofs = 1, lastOfs = 0; if (/*#cmp(a=>{*/key/*#},o=>{*/ < /*#},b=>{*/__p__start__add__hint__q__/*#});*/) { __itype__ maxOfs = hint + 1; while (ofs < maxOfs && /*#cmp(a=>{*/key/*#},o=>{*/ < /*#},b=>{*/__p__start__add__hint__sub__ofs__q__/*#});*/) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; __itype__ tmp = lastOfs; lastOfs = hint - ofs; ofs = hint - tmp; } else { __itype__ maxOfs = len - hint; while (ofs < maxOfs && /*#cmp(a=>{*/key/*#},o=>{*/ >= /*#},b=>{*/__p__start__add__hint__add__ofs__q__/*#});*/) { lastOfs = ofs; ofs = (ofs << 1) + 1; if (ofs <= 0) ofs = maxOfs; } if (ofs > maxOfs) ofs = maxOfs; lastOfs += hint; ofs += hint; } lastOfs++; while (lastOfs < ofs) { __itype__ m = lastOfs + ((ofs - lastOfs) >> 1); if (/*#cmp(a=>{*/key/*#},o=>{*/ < /*#},b=>{*/__p__start__add__m__q__/*#});*/) ofs = m; else lastOfs = m + 1; } return ofs; } /// /// Sorts the specified portion of the specified array using a binary /// insertion sort. This is the best method for sorting small numbers /// of elements. It requires O(n log n) compares, but O(n^2) data /// movements (worst case). /// If the initial part of the specified range is already sorted, /// this method can take advantage of it: the method assumes that the /// elements in range [beginIncl, beginUnsorted) are already sorted. /// /// private static void __bcall__/*# if (isGeneric) { *//*# } */( this /*# if (isPerm) { */__itype__[] p, /*# } */__atype__ a,/*# if (hasGet) { */ Func aget,/*# if (!isPerm) { */ Action aset,/*# } } */ //# if (hasFun) { Func cmp, //# } //# if (hasSel) { Func selector, //# } __itype__ beginIncl, __itype__ endExcl, __itype__ beginUnsorted) //# if (isComparable) { where T : IComparable //# } { if (beginUnsorted == beginIncl) beginUnsorted++; for (; beginUnsorted < endExcl; beginUnsorted++) { var pivot = __p__beginUnsorted__q__; __itype__ l = beginIncl, r = beginUnsorted; while (l < r) { __itype__ mid = (l + r) >> 1; if (/*#cmp(a=>{*/pivot/*#},o=>{*/ < /*#},b=>{*/__p__mid__q__/*#});*/) r = mid; else l = mid + 1; } __itype__ n = beginUnsorted - l; switch (n) { case 2: __P__l__add2____I____p__l__add1____q____Q__; __P__l__add1____I____p__l__q____Q__; break; case 1: __P__l__add1____I____p__l__q____Q__; break; default: __copy__(__agetset____pa__, l, __pa__, l + 1, n); break; } __P__l__I__pivot__Q__; } } private static __itype__ __crcall__/*# if (isGeneric) { *//*# } */( this /*# if (isPerm) { */__itype__[] p, /*# } */__atype__ a,/*# if (hasGet) { */ Func aget,/*# if (!isPerm) { */ Action aset,/*# } } */ //# if (hasFun) { Func cmp, //# } //# if (hasSel) { Func selector, //# } __itype__ beginIncl, __itype__ endExcl) //# if (isComparable) { where T : IComparable //# } { __itype__ runHi = beginIncl + 1; if (runHi == endExcl) return 1; if (/*#cmp(a=>{*/__p__runHi__inc____q__/*#},o=>{*/ < /*#},b=>{*/__p__beginIncl__q__/*#});*/) { while (runHi < endExcl && /*#cmp(a=>{*/__p__runHi__q__/*#},o=>{*/ < /*#},b=>{*/__p__runHi__sub1____q__/*#});*/) runHi++; ReverseRange(__agetset____pa__, beginIncl, runHi); } else { while (runHi < endExcl && /*#cmp(a=>{*/__p__runHi__q__/*#},o=>{*/ >= /*#},b=>{*/__p__runHi__sub1____q__/*#});*/) runHi++; } return runHi - beginIncl; } //# if (isGeneric && hasFun && !isPerm) { //# if (hasGet) { [EditorBrowsable(EditorBrowsableState.Never)] //# } public static void ReverseRange/*# if (isGeneric) { *//*# } */( /*# if (hasGet) { */ Func aget, Action aset,/*# } */__atype__ a, __itype__ beginIncl, __itype__ endExcl) { endExcl--; // now incorrectly named while (beginIncl < endExcl) { var t = __p__beginIncl__q__; __P__beginIncl__I____p__endExcl__q____Q__; __P__endExcl__I__t__Q__; ++beginIncl; --endExcl; } } //# } // isGeneric && hasFun && !isPerm //# if (hasFun && isList && isGeneric && !isPerm) { private static void CopyElements( List src, int start, List dst, int dstStart, int count) { for (var end = start + count; start < end; start++, dstStart++) dst[dstStart] = src[start]; } private static void CopyElements( List src, int start, T[] dst, int dstStart, int count) { for (var end = start + count; start < end; start++, dstStart++) dst[dstStart] = src[start]; } private static void CopyElements( T[] src, int start, List dst, int dstStart, int count) { for (var end = start + count; start < end; start++, dstStart++) dst[dstStart] = src[start]; } //# } // hasFun && isList && isGeneric && !isPerm //# if (hasFun && hasGet && !isPerm) { private static void CopyElements( Func aget, Action aset, TArray src, long start, TArray dst, long dstStart, long count) { for (var end = start + count; start < end; start++, dstStart++) aset(dst, dstStart, aget(src, start)); } //# } // hasFun && hasGet && !isPerm //# } // itype //# } // isAsc //# } // ctype //# } // hasSel //# } // hasFun #endregion //# } // isPerm //# } // type //# } // isNonGenericList //# } // isGeneric #region Auxiliary Functions, Structures, and Data /// /// Necessary for bit-field representation of smooth sort /// Leonardo heaps. /// private static int TrailingZeroBitCount(this long x) { x &= -x; int c = (x == 0) ? 1 : 0; if ((x & 0x00000000ffffffffL) == 0) c += 32; if ((x & 0x0000ffff0000ffffL) == 0) c += 16; if ((x & 0x00ff00ff00ff00ffL) == 0) c += 8; if ((x & 0x0f0f0f0f0f0f0f0fL) == 0) c += 4; if ((x & 0x3333333333333333L) == 0) c += 2; if ((x & 0x5555555555555555L) == 0) c += 1; return c; } /// /// Int Leonardo numbers (smooth sort). /// private static readonly int[] LP = { 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, 866988873, 1402817465 }; /// /// Long Leonardo numbers (smooth sort). /// private static readonly long[] LPLong = { 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, 866988873, 1402817465, 2269806339, 3672623805, 5942430145, 9615053951, 15557484097, 25172538049, 40730022147, 65902560197, 106632582345, 172535142543, 279167724889, 451702867433, 730870592323, 1182573459757, 1913444052081, 3096017511839, 5009461563921, 8105479075761, 13114940639683, 21220419715445, 34335360355129, 55555780070575, 89891140425705, 145446920496281, 235338060921987, 380784981418269, 616123042340257, 996908023758527, 1613031066098785, 2609939089857313, 4222970155956099, 6832909245813413, 11055879401769513, 17888788647582927, 28944668049352441, 46833456696935369, 75778124746287811, 122611581443223181, 198389706189510993, 321001287632734175, 519390993822245169, 840392281454979345, 1359783275277224515, 2200175556732203861, 3559958832009428377, 5760134388741632239 }; private static int TimSortMinRunLength(int n) { // assert n >= 0; int r = 0; // Becomes 1 if any 1 bits are shifted off while (n >= c_minMerge) { r |= (n & 1); n >>= 1; } return n + r; } private static long TimSortMinRunLength(long n) { // assert n >= 0; long r = 0; // Becomes 1 if any 1 bits are shifted off while (n >= c_minMerge) { r |= (n & 1); n >>= 1; } return n + r; } #endregion } } ================================================ FILE: src/Aardvark.Base/Symbol/Dict_auto.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Text; using System.Threading; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Dict /// /// A Dict is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class Dict : IIntCountable, ICountableDict, IDict, IEnumerable, IEnumerable>, ICollection, ICollection>, IDictionary, IReadOnlyDictionary { private uint m_capacity; private NextHashKeyValue[] m_firstArray; private HashKeyValueNext[] m_extraArray; private uint m_count; private uint m_increaseThreshold; private uint m_decreaseThreshold; private readonly bool m_doNotStackDuplicateKeys; private int m_freeIndex; private int m_capacityIndex; private uint m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a Dict that autmatically grows and shrinks as necessary. /// If the optional parameter stackDuplicateKeys is set to true, the /// Dict acts as a stack for all items with the same key. /// public Dict(bool stackDuplicateKeys = false) : this(DictConstant.PrimeSizes[0], (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a Dict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// Dict acts as a stack for all items with the same key. /// public Dict(int initialCapacity) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, false) { } /// /// Create a Dict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// Dict acts as a stack for all items with the same key. /// public Dict(int initialCapacity, bool stackDuplicateKeys) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a Dict and initialize it to contain the supplied /// items. /// If the optional parameter stackDuplicateKeys is set to true, the /// Dict acts as a stack for all items with the same key. /// public Dict(IEnumerable> items, bool stackDuplicateKeys = false) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { foreach (var item in items) Add(item); } private Dict( uint firstCapacity, uint extraCapacity, bool stackDuplicateKeys = false) { m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_doNotStackDuplicateKeys = !stackDuplicateKeys; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextHashKeyValue[m_capacity]; m_extraArray = new HashKeyValueNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the Dict. /// public int Count { get { return (int)m_count; } } /// /// Returns the number of items currently contained in the Dict /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the Dict /// as long. /// public uint Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the Dict. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } } /// /// Always returns false. Part of the ICollection implementation. /// public bool IsReadOnly { get { return false; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } public IEnumerable> Items { get { return KeyValuePairs; } } /// /// Returns all keys in the dictionary. /// public IEnumerable Keys { get { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Key; while (ei > 0) { yield return m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } } public Type KeyType { get { return typeof(TKey); } } /// /// Returns all values in the Dict. /// public IEnumerable Values { get { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Value; while (ei > 0) { yield return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } } public Type ValueType { get { return typeof(TValue); } } /// /// Returns all key value pairs in the Dict. /// public IEnumerable> KeyValuePairs { get { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { yield return new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } } /// /// Returns all key value pairs in the Dict, in such a way, /// that the stack order is correct when the pairs are put into a /// new Dict in the order they are returned. /// public IEnumerable> KeyValuePairsForStorage { get { var stack = new Stack(); for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; while (ei > 0) { stack.Push(ei); ei = m_extraArray[ei].Next; } while (stack.Count > 0) { ei = stack.Pop(); yield return new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); } yield return new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); } } } public IEnumerable<(object, object)> ObjectPairs { get { foreach (var kvp in KeyValuePairsForStorage) yield return (kvp.Key, kvp.Value); } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the Dict acts as a stack. /// /// /// public TValue this[TKey key] { get { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } set { var hash = key.GetHashCode(); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { m_firstArray[fi].Item.Value = value; return; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_extraArray[ei].Item.Value = value; return; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the Dict. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the Dict /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((TKey)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the Dict. /// public void Add(TKey key, TValue value) { var hash = key.GetHashCode(); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } /// /// Add the item with the supplied key and the supplied value /// to the Dict. /// public void Add(TKey key, int hash, TValue value) { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } /// /// Add the item with the supplied key and the supplied value /// to the Dict. /// public bool TryAdd(TKey key, TValue value) { var hash = key.GetHashCode(); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } /// /// Add the item with the supplied key and the supplied value /// to the Dict. /// public bool TryAdd(TKey key, int hash, TValue value) { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } /// /// Add the supplied item to the Dict. /// public void Add(KeyValuePair item) { Add(item.Key, item.Value); } /// /// Add the supplied items to the Dict. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the Dict contains the item with the supplied /// key. /// public bool Contains(TKey key) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the Dict contains the item with the supplied /// key. /// public bool Contains(TKey key, int hash) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the Dict contains the item with the supplied /// key. /// public bool ContainsKey(TKey key) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the Dict contains the item with the supplied /// key. /// public bool ContainsKey(TKey key, int hash) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the Dict contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, TValue value) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the Dict contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, int hash, TValue value) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the Dict contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { return Contains(item.Key, item.Value); } /// /// Returns true if the Dict contains the given value. /// public bool ContainsValue(TValue value) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } return false; } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the Dict and returned. /// public TValue GetOrCreate(TKey key, Func creator) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } TValue AddCreated(TKey key, int hash, TValue value) { while (true) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ei = m_firstArray[fi].Next; ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = m_firstArray[fi].Next; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, TValue defaultValue) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key, int hash) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the Dict and returned. /// public TValue GetOrCreate(TKey key, int hash, Func creator) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, int hash, TValue defaultValue) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(TKey key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, out TValue value) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); return false; } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, int hash, out TValue value) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); return false; } /// /// Return all the value with the given key. This method is only /// useful if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// public IEnumerable ValuesWithKey(TKey key) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) yield break; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) yield return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) yield return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } /// /// Gets an enumerator for values. /// Should be preferred over Values enumeration in /// performance critical code. /// public ValueEnumerator GetValuesEnumerator() { return new ValueEnumerator(this); } public struct ValueEnumerator : IEnumerator { Dict.Enumerator m_inner; public ValueEnumerator(Dict dict) { m_inner = dict.GetEnumerator(); } public TValue Current => m_inner.Current.Value; object IEnumerator.Current => Current; public void Dispose() => m_inner.Dispose(); public bool MoveNext() => m_inner.MoveNext(); public void Reset() => m_inner.Reset(); } /// /// Gets an enumerator for values with key. It is only useful /// if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// Should be preferred over ValuesWithKey enumeration in /// performance critical code. /// public ValuesWithKeyEnumerator GetValuesWithKeyEnumerator(TKey key) { return new ValuesWithKeyEnumerator(this, key); } public struct ValuesWithKeyEnumerator : IEnumerator { readonly Dict m_dict; readonly TKey m_key; readonly int m_hash; int m_extraIndex; TValue m_current; public ValuesWithKeyEnumerator(Dict dict, TKey key) { m_dict = dict; m_key = key; m_hash = key.GetHashCode(); m_extraIndex = int.MaxValue; m_current = default(TValue); } public readonly TValue Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex == int.MaxValue) { var fa = m_dict.m_firstArray; var fi = ((uint)m_hash) % m_dict.m_capacity; m_extraIndex = fa[fi].Next; if (m_extraIndex == 0) return false; if (fa[fi].Item.Hash == m_hash && m_key.Equals(fa[fi].Item.Key)) { m_current = fa[fi].Item.Value; return true; } } if (m_extraIndex > 0) { var ea = m_dict.m_extraArray; do { var valid = ea[m_extraIndex].Item.Hash == m_hash && m_key.Equals(ea[m_extraIndex].Item.Key); if (valid) m_current = ea[m_extraIndex].Item.Value; m_extraIndex = ea[m_extraIndex].Next; if (valid) return true; } while (m_extraIndex > 0); } return false; } public void Reset() { m_extraIndex = int.MaxValue; m_current = default(TValue); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(TKey key, int skip) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (skip == 0) return m_firstArray[fi].Item.Value; --skip; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { if (skip == 0) return m_extraArray[ei].Item.Value; --skip; } ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Remove the item with the supplied key from the Dict and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(TKey key) { TValue value; if (!TryRemove(key, out value)) throw new KeyNotFoundException(); return value; } /// /// Try to remove the item with the supplied key from the Dict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key) { TValue value; return TryRemove(key, out value); } /// /// Try to remove the item with the supplied key from the Dict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key, int hash) { TValue value; return TryRemove(key, hash, out value); } /// /// Remove the item with the supplied key and the supplied value /// from the Dict. Returns true if the value was removed. /// public bool Remove(TKey key, TValue value) { return TryRemove(key, value); } /// /// Remove the item with the supplied key and the supplied value /// from the Dict. Returns true if the value was removed. /// public bool Remove(TKey key, int hash, TValue value) { return TryRemove(key, hash, value); } /// /// Remove the item with the supplied KeyValuePair from the Dict. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { return TryRemove(item.Key, item.Value); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, out TValue value) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } value = default(TValue); return false; } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, int hash, out TValue value) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } value = default(TValue); return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, TValue value) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key) && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, int hash, TValue value) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key) && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Returns all keys in the dictionary as an array. /// public TKey[] KeysToArray() { var array = new TKey[m_count]; CopyKeysTo(array, 0); return array; } /// /// Returns all values in the dictionary as an array. /// public TValue[] ValuesToArray() { var array = new TValue[m_count]; CopyValuesTo(array, 0); return array; } /// /// Returns all KeyValuePairs in the dictionary as an array. /// public KeyValuePair[] ToArray() { var array = new KeyValuePair[m_count]; CopyTo(array, 0); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { m_firstArray.Set(default(NextHashKeyValue)); m_extraArray.Set(default(HashKeyValueNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyKeysTo(TKey[] array, int index) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyValuesTo(TValue[] array, int index) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Value; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// public void CopyTo(KeyValuePair[] array, int index) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { array[index++] = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } /// /// Copy items into supplied array starting at supplied index. /// public void CopyTo(Array array, int index) { var typedArray = array as KeyValuePair[]; if (typedArray != null) CopyTo(typedArray, index); else throw new ArgumentException(); } /// /// Retuns a concurrent wrapper around the Dict to enable /// concurrent modifications. /// public ConcurrentDict AsConcurrent() { return new ConcurrentDict(this); } #endregion #region IEnumerable> Members IEnumerator> IEnumerable>.GetEnumerator() { return new Enumerator(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region IDictionary Members ICollection IDictionary.Keys => new KeyCollection(this); ICollection IDictionary.Values => new ValueCollection(this); private sealed class KeyCollection(Dict parent) : ICollection, ICollection, IReadOnlyCollection { public void CopyTo(TKey[] array, int index) => parent.CopyKeysTo(array, index); public int Count => parent.Count; bool ICollection.IsReadOnly => true; void ICollection.Add(TKey item) => throw new NotSupportedException(); void ICollection.Clear() => throw new NotSupportedException(); public bool Contains(TKey item) => parent.ContainsKey(item); bool ICollection.Remove(TKey item) => throw new NotSupportedException(); IEnumerator IEnumerable.GetEnumerator() => new Enumerator(parent); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator(); void ICollection.CopyTo(Array array, int index) { if (array is TKey[] keys) parent.CopyKeysTo(keys, index); throw new ArrayTypeMismatchException(); } bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => ((ICollection)parent).SyncRoot; private class Enumerator(Dict dictionary) : IEnumerator, IEnumerator { private Dict.Enumerator _inner = dictionary.GetEnumerator(); public void Dispose() => _inner.Dispose(); public bool MoveNext() => _inner.MoveNext(); public TKey Current => _inner.Current.Key; object IEnumerator.Current => Current; void IEnumerator.Reset() => _inner.Reset(); } } private sealed class ValueCollection(Dict parent) : ICollection, ICollection, IReadOnlyCollection { public void CopyTo(TValue[] array, int index) => parent.CopyValuesTo(array, index); public int Count => parent.Count; bool ICollection.IsReadOnly => true; void ICollection.Add(TValue item) => throw new NotSupportedException(); void ICollection.Clear() => throw new NotSupportedException(); public bool Contains(TValue item) => parent.ContainsValue(item); bool ICollection.Remove(TValue item) => throw new NotSupportedException(); IEnumerator IEnumerable.GetEnumerator() => new Enumerator(parent); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator(); void ICollection.CopyTo(Array array, int index) { if (array is TValue[] values) parent.CopyValuesTo(values, index); throw new ArrayTypeMismatchException(); } bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => ((ICollection)parent).SyncRoot; private class Enumerator(Dict dictionary) : IEnumerator, IEnumerator { private Dict.Enumerator _inner = dictionary.GetEnumerator(); public void Dispose() => _inner.Dispose(); public bool MoveNext() => _inner.MoveNext(); public TValue Current => _inner.Current.Value; object IEnumerator.Current => Current; void IEnumerator.Reset() => _inner.Reset(); } } #endregion #region Enumerator public Enumerator GetEnumerator() { return new Enumerator(this); } public struct Enumerator : IEnumerator> { readonly Dict m_dict; int m_index; int m_extraIndex; KeyValuePair m_current; public Enumerator(Dict dict) { m_dict = dict; m_index = 0; m_extraIndex = -1; m_current = default(KeyValuePair); } public readonly KeyValuePair Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex < 0) { var fa = m_dict.m_firstArray; var cap = fa.Length; while (m_index < cap) { var nxt = fa[m_index].Next; if (nxt != 0) { m_current = new KeyValuePair(fa[m_index].Item.Key, fa[m_index].Item.Value); m_extraIndex = nxt; m_index++; return true; } m_index++; } return false; } else { var ea = m_dict.m_extraArray; m_current = new KeyValuePair(ea[m_extraIndex].Item.Key, ea[m_extraIndex].Item.Value); m_extraIndex = ea[m_extraIndex].Next; return true; } } public void Reset() { m_index = 0; m_extraIndex = -1; m_current = default( KeyValuePair); } } #endregion #region Private Helper Methods private uint ComputeIncreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_maxFillFactor); } private uint ComputeDecreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_minFillFactor); } private static int AddSlotsToFreeList( HashKeyValueNext[] extraArray, int start) { var length = extraArray.Length - 1; for (int i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( HashKeyValue item, NextHashKeyValue[] firstArray, uint capacity, ref HashKeyValueNext[] extraArray, ref int freeIndex, ref uint extraCount) { var fi = ((uint)item.Hash) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(uint newCapacity, uint oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextHashKeyValue[newCapacity]; var extraArray = new HashKeyValueNext[ System.Math.Max((int)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); uint newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { uint fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((uint)m_count - m_extraCount, oldCapacity, m_extraCount, (uint)m_extraArray.Length, (uint)m_count - newExtraCount, newCapacity, newExtraCount, (uint)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( uint oldFirstCount, uint oldCapacity, uint oldExtraCount, uint oldExtraCapacity, uint newFirstCount, uint newCapacity, uint newExtraCount, uint newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region DictSet /// /// A DictSet is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class DictSet : IIntCountable, ICountableDictSet, IDictSet, IEnumerable, IEnumerable, ICollection, ICollection { private uint m_capacity; private NextHashKey[] m_firstArray; private HashKeyNext[] m_extraArray; private uint m_count; private uint m_increaseThreshold; private uint m_decreaseThreshold; private int m_freeIndex; private int m_capacityIndex; private uint m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a DictSet that autmatically grows and shrinks as necessary. /// public DictSet() : this(DictConstant.PrimeSizes[0], (uint)DictConstant.MinExtraCapacity) { } /// /// Create a DictSet that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// public DictSet(int initialCapacity) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity) { } /// /// Create a DictSet and initialize it to contain the supplied /// items. /// public DictSet(IEnumerable items) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity) { foreach (var item in items) Add(item); } private DictSet( uint firstCapacity, uint extraCapacity) { m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextHashKey[m_capacity]; m_extraArray = new HashKeyNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the DictSet. /// public int Count { get { return (int)m_count; } } /// /// Returns the number of items currently contained in the DictSet /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the DictSet /// as long. /// public uint Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the DictSet. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } } /// /// Always returns false. Part of the ICollection implementation. /// public bool IsReadOnly { get { return false; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } public IEnumerable Items { get { return Keys; } } /// /// Returns all keys in the dictionary. /// public IEnumerable Keys { get { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Key; while (ei > 0) { yield return m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } } public Type KeyType { get { return typeof(TKey); } } public IEnumerable Objects { get { foreach (object obj in Keys) yield return obj; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the DictSet. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the DictSet /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((TKey)objkey); } void ICollection.Add(TKey key) { Add(key); } /// /// Add the item with the supplied key /// to the DictSet. /// public bool Add(TKey key) { var hash = key.GetHashCode(); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } /// /// Add the item with the supplied key /// to the DictSet. /// public bool Add(TKey key, int hash) { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } /// /// Add the item with the supplied key /// to the DictSet. /// public bool TryAdd(TKey key) { var hash = key.GetHashCode(); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } /// /// Add the item with the supplied key /// to the DictSet. /// public bool TryAdd(TKey key, int hash) { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } /// /// Add the supplied keys to the DictSet. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the DictSet contains the item with the supplied /// key. /// public bool Contains(TKey key) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the DictSet contains the item with the supplied /// key. /// public bool Contains(TKey key, int hash) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Remove the item with the supplied key /// from the DictSet. Returns true if the value was removed. /// public bool Remove(TKey key) { return TryRemove(key); } /// /// Remove the item with the supplied key /// from the DictSet. Returns true if the value was removed. /// public bool Remove(TKey key, int hash) { return TryRemove(key, hash); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKey); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKey); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKey); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKey); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key, int hash) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKey); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKey); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKey); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKey); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Returns all keys in the dictionary as an array. /// public TKey[] ToArray() { var array = new TKey[m_count]; CopyTo(array, 0); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { m_firstArray.Set(default(NextHashKey)); m_extraArray.Set(default(HashKeyNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyTo(TKey[] array, int index) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } /// /// Copy items into supplied array starting at supplied index. /// public void CopyTo(Array array, int index) { var typedArray = array as TKey[]; if (typedArray != null) CopyTo(typedArray, index); else throw new ArgumentException(); } /// /// Retuns a concurrent wrapper around the DictSet to enable /// concurrent modifications. /// public ConcurrentDictSet AsConcurrent() { return new ConcurrentDictSet(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region Enumerator public Enumerator GetEnumerator() { return new Enumerator(this); } public struct Enumerator : IEnumerator { readonly DictSet m_dict; int m_index; int m_extraIndex; TKey m_current; public Enumerator(DictSet dict) { m_dict = dict; m_index = 0; m_extraIndex = -1; m_current = default(TKey); } public readonly TKey Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex < 0) { var fa = m_dict.m_firstArray; var cap = fa.Length; while (m_index < cap) { var nxt = fa[m_index].Next; if (nxt != 0) { m_current = fa[m_index].Item.Key; m_extraIndex = nxt; m_index++; return true; } m_index++; } return false; } else { var ea = m_dict.m_extraArray; m_current = ea[m_extraIndex].Item.Key; m_extraIndex = ea[m_extraIndex].Next; return true; } } public void Reset() { m_index = 0; m_extraIndex = -1; m_current = default(TKey); } } #endregion #region Private Helper Methods private uint ComputeIncreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_maxFillFactor); } private uint ComputeDecreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_minFillFactor); } private static int AddSlotsToFreeList( HashKeyNext[] extraArray, int start) { var length = extraArray.Length - 1; for (int i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( HashKey item, NextHashKey[] firstArray, uint capacity, ref HashKeyNext[] extraArray, ref int freeIndex, ref uint extraCount) { var fi = ((uint)item.Hash) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(uint newCapacity, uint oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextHashKey[newCapacity]; var extraArray = new HashKeyNext[ System.Math.Max((int)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); uint newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { uint fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((uint)m_count - m_extraCount, oldCapacity, m_extraCount, (uint)m_extraArray.Length, (uint)m_count - newExtraCount, newCapacity, newExtraCount, (uint)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( uint oldFirstCount, uint oldCapacity, uint oldExtraCount, uint oldExtraCapacity, uint newFirstCount, uint newCapacity, uint newExtraCount, uint newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region IntDict /// /// A IntDict is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class IntDict : IIntCountable, ICountableDict, IDict, IEnumerable, IEnumerable>, ICollection, ICollection>, IDictionary, IReadOnlyDictionary { private uint m_capacity; private NextIntValue[] m_firstArray; private IntValueNext[] m_extraArray; private uint m_count; private uint m_increaseThreshold; private uint m_decreaseThreshold; private readonly bool m_doNotStackDuplicateKeys; private int m_freeIndex; private int m_capacityIndex; private uint m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a IntDict that autmatically grows and shrinks as necessary. /// If the optional parameter stackDuplicateKeys is set to true, the /// IntDict acts as a stack for all items with the same key. /// public IntDict(bool stackDuplicateKeys = false) : this(DictConstant.PrimeSizes[0], (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a IntDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// IntDict acts as a stack for all items with the same key. /// public IntDict(int initialCapacity) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, false) { } /// /// Create a IntDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// IntDict acts as a stack for all items with the same key. /// public IntDict(int initialCapacity, bool stackDuplicateKeys) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a IntDict and initialize it to contain the supplied /// items. /// If the optional parameter stackDuplicateKeys is set to true, the /// IntDict acts as a stack for all items with the same key. /// public IntDict(IEnumerable> items, bool stackDuplicateKeys = false) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { foreach (var item in items) Add(item); } private IntDict( uint firstCapacity, uint extraCapacity, bool stackDuplicateKeys = false) { m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_doNotStackDuplicateKeys = !stackDuplicateKeys; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextIntValue[m_capacity]; m_extraArray = new IntValueNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the IntDict. /// public int Count { get { return (int)m_count; } } /// /// Returns the number of items currently contained in the IntDict /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the IntDict /// as long. /// public uint Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the IntDict. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } } /// /// Always returns false. Part of the ICollection implementation. /// public bool IsReadOnly { get { return false; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } public IEnumerable> Items { get { return KeyValuePairs; } } /// /// Returns all keys in the dictionary. /// public IEnumerable Keys { get { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Key; while (ei > 0) { yield return m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } } public Type KeyType { get { return typeof(int); } } /// /// Returns all values in the IntDict. /// public IEnumerable Values { get { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Value; while (ei > 0) { yield return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } } public Type ValueType { get { return typeof(TValue); } } /// /// Returns all key value pairs in the IntDict. /// public IEnumerable> KeyValuePairs { get { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { yield return new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } } /// /// Returns all key value pairs in the IntDict, in such a way, /// that the stack order is correct when the pairs are put into a /// new IntDict in the order they are returned. /// public IEnumerable> KeyValuePairsForStorage { get { var stack = new Stack(); for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; while (ei > 0) { stack.Push(ei); ei = m_extraArray[ei].Next; } while (stack.Count > 0) { ei = stack.Pop(); yield return new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); } yield return new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); } } } public IEnumerable<(object, object)> ObjectPairs { get { foreach (var kvp in KeyValuePairsForStorage) yield return (kvp.Key, kvp.Value); } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the IntDict acts as a stack. /// /// /// public TValue this[int key] { get { var hash = key; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } set { var hash = key; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { if (m_firstArray[fi].Item.Key == hash) { m_firstArray[fi].Item.Value = value; return; } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { m_extraArray[ei].Item.Value = value; return; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the IntDict. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the IntDict /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((int)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the IntDict. /// public void Add(int key, TValue value) { var hash = key; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Key == hash) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } /// /// Add the item with the supplied key and the supplied value /// to the IntDict. /// public bool TryAdd(int key, TValue value) { var hash = key; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Key == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } /// /// Add the supplied item to the IntDict. /// public void Add(KeyValuePair item) { Add(item.Key, item.Value); } /// /// Add the supplied items to the IntDict. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the IntDict contains the item with the supplied /// key. /// public bool Contains(int key) { var hash = key; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the IntDict contains the item with the supplied /// key. /// public bool ContainsKey(int key) { var hash = key; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the IntDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(int key, TValue value) { var hash = key; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key == hash && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the IntDict contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { return Contains(item.Key, item.Value); } /// /// Returns true if the IntDict contains the given value. /// public bool ContainsValue(TValue value) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } return false; } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(int key) { var hash = key; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the IntDict and returned. /// public TValue GetOrCreate(int key, Func creator) { var hash = key; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } TValue AddCreated(int key, int hash, TValue value) { while (true) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ei = m_firstArray[fi].Next; ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = m_firstArray[fi].Next; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(int key, TValue defaultValue) { var hash = key; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(int key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(int key, out TValue value) { var hash = key; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Key == hash) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); return false; } /// /// Return all the value with the given key. This method is only /// useful if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// public IEnumerable ValuesWithKey(int key) { var hash = key; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) yield break; if (m_firstArray[fi].Item.Key == hash) yield return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) yield return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } /// /// Gets an enumerator for values. /// Should be preferred over Values enumeration in /// performance critical code. /// public ValueEnumerator GetValuesEnumerator() { return new ValueEnumerator(this); } public struct ValueEnumerator : IEnumerator { IntDict.Enumerator m_inner; public ValueEnumerator(IntDict dict) { m_inner = dict.GetEnumerator(); } public TValue Current => m_inner.Current.Value; object IEnumerator.Current => Current; public void Dispose() => m_inner.Dispose(); public bool MoveNext() => m_inner.MoveNext(); public void Reset() => m_inner.Reset(); } /// /// Gets an enumerator for values with key. It is only useful /// if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// Should be preferred over ValuesWithKey enumeration in /// performance critical code. /// public ValuesWithKeyEnumerator GetValuesWithKeyEnumerator(int key) { return new ValuesWithKeyEnumerator(this, key); } public struct ValuesWithKeyEnumerator : IEnumerator { readonly IntDict m_dict; readonly int m_hash; int m_extraIndex; TValue m_current; public ValuesWithKeyEnumerator(IntDict dict, int key) { m_dict = dict; m_hash = key; m_extraIndex = int.MaxValue; m_current = default(TValue); } public readonly TValue Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex == int.MaxValue) { var fa = m_dict.m_firstArray; var fi = ((uint)m_hash) % m_dict.m_capacity; m_extraIndex = fa[fi].Next; if (m_extraIndex == 0) return false; if (fa[fi].Item.Key == m_hash) { m_current = fa[fi].Item.Value; return true; } } if (m_extraIndex > 0) { var ea = m_dict.m_extraArray; do { var valid = ea[m_extraIndex].Item.Key == m_hash; if (valid) m_current = ea[m_extraIndex].Item.Value; m_extraIndex = ea[m_extraIndex].Next; if (valid) return true; } while (m_extraIndex > 0); } return false; } public void Reset() { m_extraIndex = int.MaxValue; m_current = default(TValue); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(int key, int skip) { var hash = key; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key == hash) { if (skip == 0) return m_firstArray[fi].Item.Value; --skip; } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { if (skip == 0) return m_extraArray[ei].Item.Value; --skip; } ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Remove the item with the supplied key from the IntDict and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(int key) { TValue value; if (!TryRemove(key, out value)) throw new KeyNotFoundException(); return value; } /// /// Try to remove the item with the supplied key from the IntDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(int key) { TValue value; return TryRemove(key, out value); } /// /// Remove the item with the supplied key and the supplied value /// from the IntDict. Returns true if the value was removed. /// public bool Remove(int key, TValue value) { return TryRemove(key, value); } /// /// Remove the item with the supplied KeyValuePair from the IntDict. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { return TryRemove(item.Key, item.Value); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(int key, out TValue value) { var hash = key; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Key == hash) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(IntValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(IntValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(IntValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Key == hash) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(IntValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } value = default(TValue); return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(int key, TValue value) { var hash = key; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key == hash && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(IntValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(IntValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Key == hash && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(IntValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Key == hash && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(IntValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Returns all keys in the dictionary as an array. /// public int[] KeysToArray() { var array = new int[m_count]; CopyKeysTo(array, 0); return array; } /// /// Returns all values in the dictionary as an array. /// public TValue[] ValuesToArray() { var array = new TValue[m_count]; CopyValuesTo(array, 0); return array; } /// /// Returns all KeyValuePairs in the dictionary as an array. /// public KeyValuePair[] ToArray() { var array = new KeyValuePair[m_count]; CopyTo(array, 0); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { m_firstArray.Set(default(NextIntValue)); m_extraArray.Set(default(IntValueNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyKeysTo(int[] array, int index) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyValuesTo(TValue[] array, int index) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Value; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// public void CopyTo(KeyValuePair[] array, int index) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { array[index++] = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } /// /// Copy items into supplied array starting at supplied index. /// public void CopyTo(Array array, int index) { var typedArray = array as KeyValuePair[]; if (typedArray != null) CopyTo(typedArray, index); else throw new ArgumentException(); } /// /// Retuns a concurrent wrapper around the IntDict to enable /// concurrent modifications. /// public ConcurrentIntDict AsConcurrent() { return new ConcurrentIntDict(this); } #endregion #region IEnumerable> Members IEnumerator> IEnumerable>.GetEnumerator() { return new Enumerator(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region IDictionary Members ICollection IDictionary.Keys => new KeyCollection(this); ICollection IDictionary.Values => new ValueCollection(this); private sealed class KeyCollection(IntDict parent) : ICollection, ICollection, IReadOnlyCollection { public void CopyTo(int[] array, int index) => parent.CopyKeysTo(array, index); public int Count => parent.Count; bool ICollection.IsReadOnly => true; void ICollection.Add(int item) => throw new NotSupportedException(); void ICollection.Clear() => throw new NotSupportedException(); public bool Contains(int item) => parent.ContainsKey(item); bool ICollection.Remove(int item) => throw new NotSupportedException(); IEnumerator IEnumerable.GetEnumerator() => new Enumerator(parent); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator(); void ICollection.CopyTo(Array array, int index) { if (array is int[] keys) parent.CopyKeysTo(keys, index); throw new ArrayTypeMismatchException(); } bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => ((ICollection)parent).SyncRoot; private class Enumerator(IntDict dictionary) : IEnumerator, IEnumerator { private IntDict.Enumerator _inner = dictionary.GetEnumerator(); public void Dispose() => _inner.Dispose(); public bool MoveNext() => _inner.MoveNext(); public int Current => _inner.Current.Key; object IEnumerator.Current => Current; void IEnumerator.Reset() => _inner.Reset(); } } private sealed class ValueCollection(IntDict parent) : ICollection, ICollection, IReadOnlyCollection { public void CopyTo(TValue[] array, int index) => parent.CopyValuesTo(array, index); public int Count => parent.Count; bool ICollection.IsReadOnly => true; void ICollection.Add(TValue item) => throw new NotSupportedException(); void ICollection.Clear() => throw new NotSupportedException(); public bool Contains(TValue item) => parent.ContainsValue(item); bool ICollection.Remove(TValue item) => throw new NotSupportedException(); IEnumerator IEnumerable.GetEnumerator() => new Enumerator(parent); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator(); void ICollection.CopyTo(Array array, int index) { if (array is TValue[] values) parent.CopyValuesTo(values, index); throw new ArrayTypeMismatchException(); } bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => ((ICollection)parent).SyncRoot; private class Enumerator(IntDict dictionary) : IEnumerator, IEnumerator { private IntDict.Enumerator _inner = dictionary.GetEnumerator(); public void Dispose() => _inner.Dispose(); public bool MoveNext() => _inner.MoveNext(); public TValue Current => _inner.Current.Value; object IEnumerator.Current => Current; void IEnumerator.Reset() => _inner.Reset(); } } #endregion #region Enumerator public Enumerator GetEnumerator() { return new Enumerator(this); } public struct Enumerator : IEnumerator> { readonly IntDict m_dict; int m_index; int m_extraIndex; KeyValuePair m_current; public Enumerator(IntDict dict) { m_dict = dict; m_index = 0; m_extraIndex = -1; m_current = default(KeyValuePair); } public readonly KeyValuePair Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex < 0) { var fa = m_dict.m_firstArray; var cap = fa.Length; while (m_index < cap) { var nxt = fa[m_index].Next; if (nxt != 0) { m_current = new KeyValuePair(fa[m_index].Item.Key, fa[m_index].Item.Value); m_extraIndex = nxt; m_index++; return true; } m_index++; } return false; } else { var ea = m_dict.m_extraArray; m_current = new KeyValuePair(ea[m_extraIndex].Item.Key, ea[m_extraIndex].Item.Value); m_extraIndex = ea[m_extraIndex].Next; return true; } } public void Reset() { m_index = 0; m_extraIndex = -1; m_current = default( KeyValuePair); } } #endregion #region Private Helper Methods private uint ComputeIncreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_maxFillFactor); } private uint ComputeDecreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_minFillFactor); } private static int AddSlotsToFreeList( IntValueNext[] extraArray, int start) { var length = extraArray.Length - 1; for (int i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( IntValue item, NextIntValue[] firstArray, uint capacity, ref IntValueNext[] extraArray, ref int freeIndex, ref uint extraCount) { var fi = ((uint)item.Key) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(uint newCapacity, uint oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextIntValue[newCapacity]; var extraArray = new IntValueNext[ System.Math.Max((int)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); uint newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { uint fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((uint)m_count - m_extraCount, oldCapacity, m_extraCount, (uint)m_extraArray.Length, (uint)m_count - newExtraCount, newCapacity, newExtraCount, (uint)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( uint oldFirstCount, uint oldCapacity, uint oldExtraCount, uint oldExtraCapacity, uint newFirstCount, uint newCapacity, uint newExtraCount, uint newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region IntSet /// /// A IntSet is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class IntSet : IIntCountable, ICountableDictSet, IDictSet, IEnumerable, IEnumerable, ICollection, ICollection { private uint m_capacity; private NextInt[] m_firstArray; private IntNext[] m_extraArray; private uint m_count; private uint m_increaseThreshold; private uint m_decreaseThreshold; private int m_freeIndex; private int m_capacityIndex; private uint m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a IntSet that autmatically grows and shrinks as necessary. /// public IntSet() : this(DictConstant.PrimeSizes[0], (uint)DictConstant.MinExtraCapacity) { } /// /// Create a IntSet that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// public IntSet(int initialCapacity) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity) { } /// /// Create a IntSet and initialize it to contain the supplied /// items. /// public IntSet(IEnumerable items) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity) { foreach (var item in items) Add(item); } private IntSet( uint firstCapacity, uint extraCapacity) { m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextInt[m_capacity]; m_extraArray = new IntNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the IntSet. /// public int Count { get { return (int)m_count; } } /// /// Returns the number of items currently contained in the IntSet /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the IntSet /// as long. /// public uint Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the IntSet. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } } /// /// Always returns false. Part of the ICollection implementation. /// public bool IsReadOnly { get { return false; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } public IEnumerable Items { get { return Keys; } } /// /// Returns all keys in the dictionary. /// public IEnumerable Keys { get { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item; while (ei > 0) { yield return m_extraArray[ei].Item; ei = m_extraArray[ei].Next; } } } } public Type KeyType { get { return typeof(int); } } public IEnumerable Objects { get { foreach (object obj in Keys) yield return obj; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the IntSet. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the IntSet /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((int)objkey); } void ICollection.Add(int key) { Add(key); } /// /// Add the item with the supplied key /// to the IntSet. /// public bool Add(int key) { var hash = key; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item = key; return true; } /// /// Add the item with the supplied key /// to the IntSet. /// public bool TryAdd(int key) { var hash = key; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item = key; return true; } /// /// Add the supplied keys to the IntSet. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the IntSet contains the item with the supplied /// key. /// public bool Contains(int key) { var hash = key; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item == hash) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Remove the item with the supplied key /// from the IntSet. Returns true if the value was removed. /// public bool Remove(int key) { return TryRemove(key); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(int key) { var hash = key; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item == hash) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(int); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(int); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item == hash) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(int); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item == hash) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(int); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Returns all keys in the dictionary as an array. /// public int[] ToArray() { var array = new int[m_count]; CopyTo(array, 0); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { m_firstArray.Set(default(NextInt)); m_extraArray.Set(default(IntNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyTo(int[] array, int index) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item; while (ei > 0) { array[index++] = m_extraArray[ei].Item; ei = m_extraArray[ei].Next; } } } /// /// Copy items into supplied array starting at supplied index. /// public void CopyTo(Array array, int index) { var typedArray = array as int[]; if (typedArray != null) CopyTo(typedArray, index); else throw new ArgumentException(); } /// /// Retuns a concurrent wrapper around the IntSet to enable /// concurrent modifications. /// public ConcurrentIntSet AsConcurrent() { return new ConcurrentIntSet(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region Enumerator public Enumerator GetEnumerator() { return new Enumerator(this); } public struct Enumerator : IEnumerator { readonly IntSet m_dict; int m_index; int m_extraIndex; int m_current; public Enumerator(IntSet dict) { m_dict = dict; m_index = 0; m_extraIndex = -1; m_current = default(int); } public readonly int Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex < 0) { var fa = m_dict.m_firstArray; var cap = fa.Length; while (m_index < cap) { var nxt = fa[m_index].Next; if (nxt != 0) { m_current = fa[m_index].Item; m_extraIndex = nxt; m_index++; return true; } m_index++; } return false; } else { var ea = m_dict.m_extraArray; m_current = ea[m_extraIndex].Item; m_extraIndex = ea[m_extraIndex].Next; return true; } } public void Reset() { m_index = 0; m_extraIndex = -1; m_current = default(int); } } #endregion #region Private Helper Methods private uint ComputeIncreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_maxFillFactor); } private uint ComputeDecreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_minFillFactor); } private static int AddSlotsToFreeList( IntNext[] extraArray, int start) { var length = extraArray.Length - 1; for (int i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( int item, NextInt[] firstArray, uint capacity, ref IntNext[] extraArray, ref int freeIndex, ref uint extraCount) { var fi = ((uint)item) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(uint newCapacity, uint oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextInt[newCapacity]; var extraArray = new IntNext[ System.Math.Max((int)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); uint newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { uint fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((uint)m_count - m_extraCount, oldCapacity, m_extraCount, (uint)m_extraArray.Length, (uint)m_count - newExtraCount, newCapacity, newExtraCount, (uint)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( uint oldFirstCount, uint oldCapacity, uint oldExtraCount, uint oldExtraCapacity, uint newFirstCount, uint newCapacity, uint newExtraCount, uint newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region SymbolDict /// /// A SymbolDict is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class SymbolDict : IIntCountable, ICountableDict, IDict, IEnumerable, IEnumerable>, ICollection, ICollection>, IDictionary, IReadOnlyDictionary { private uint m_capacity; private NextSymbolValue[] m_firstArray; private SymbolValueNext[] m_extraArray; private uint m_count; private uint m_increaseThreshold; private uint m_decreaseThreshold; private readonly bool m_doNotStackDuplicateKeys; private int m_freeIndex; private int m_capacityIndex; private uint m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a SymbolDict that autmatically grows and shrinks as necessary. /// If the optional parameter stackDuplicateKeys is set to true, the /// SymbolDict acts as a stack for all items with the same key. /// public SymbolDict(bool stackDuplicateKeys = false) : this(DictConstant.PrimeSizes[0], (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a SymbolDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// SymbolDict acts as a stack for all items with the same key. /// public SymbolDict(int initialCapacity) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, false) { } /// /// Create a SymbolDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// SymbolDict acts as a stack for all items with the same key. /// public SymbolDict(int initialCapacity, bool stackDuplicateKeys) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a SymbolDict and initialize it to contain the supplied /// items. /// If the optional parameter stackDuplicateKeys is set to true, the /// SymbolDict acts as a stack for all items with the same key. /// public SymbolDict(IEnumerable> items, bool stackDuplicateKeys = false) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { foreach (var item in items) Add(item); } /// /// Create a SymbolDict and initialize to contain the supplied items. /// Note hat this incurs the overhead of converting all string keys /// to symbols. /// If the optional parameter stackDuplicateKeys is set to true, the /// SymbolDict acts as a stack for all items with the same key. /// public SymbolDict(IEnumerable> items, bool stackDuplicateKeys = false) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), DictConstant.MinExtraCapacity, stackDuplicateKeys) { foreach (var item in items) Add(item); } private SymbolDict( uint firstCapacity, uint extraCapacity, bool stackDuplicateKeys = false) { m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_doNotStackDuplicateKeys = !stackDuplicateKeys; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextSymbolValue[m_capacity]; m_extraArray = new SymbolValueNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the SymbolDict. /// public int Count { get { return (int)m_count; } } /// /// Returns the number of items currently contained in the SymbolDict /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the SymbolDict /// as long. /// public uint Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the SymbolDict. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } } /// /// Always returns false. Part of the ICollection implementation. /// public bool IsReadOnly { get { return false; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } public IEnumerable> Items { get { return KeyValuePairs; } } /// /// Returns all keys in the dictionary. /// public IEnumerable Keys { get { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Key; while (ei > 0) { yield return m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } } public Type KeyType { get { return typeof(Symbol); } } /// /// Returns all values in the SymbolDict. /// public IEnumerable Values { get { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Value; while (ei > 0) { yield return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } } public Type ValueType { get { return typeof(TValue); } } /// /// Returns all key value pairs in the SymbolDict. /// public IEnumerable> KeyValuePairs { get { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { yield return new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } } /// /// Returns all key value pairs in the SymbolDict, in such a way, /// that the stack order is correct when the pairs are put into a /// new SymbolDict in the order they are returned. /// public IEnumerable> KeyValuePairsForStorage { get { var stack = new Stack(); for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; while (ei > 0) { stack.Push(ei); ei = m_extraArray[ei].Next; } while (stack.Count > 0) { ei = stack.Pop(); yield return new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); } yield return new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); } } } public IEnumerable<(object, object)> ObjectPairs { get { foreach (var kvp in KeyValuePairsForStorage) yield return (kvp.Key, kvp.Value); } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the SymbolDict acts as a stack. /// /// /// public TValue this[Symbol key] { get { var hash = key.Id; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key.Id == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } set { var hash = key.Id; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { if (m_firstArray[fi].Item.Key.Id == hash) { m_firstArray[fi].Item.Value = value; return; } while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) { m_extraArray[ei].Item.Value = value; return; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the SymbolDict. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the SymbolDict /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((Symbol)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the SymbolDict. /// public void Add(Symbol key, TValue value) { var hash = key.Id; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Key.Id == hash) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } /// /// Add the item with the supplied key and the supplied value /// to the SymbolDict. /// public bool TryAdd(Symbol key, TValue value) { var hash = key.Id; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Key.Id == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } /// /// Adds the supplied item to the SymbolDict. Note that this incurs the /// overhead of converting the string key to a symbol. /// public void Add(string key, TValue value) { Add(key.ToSymbol(), value); } /// /// Add the supplied item to the SymbolDict. Note that this incurs the /// overhead of converting the string key to a symbol. /// public void Add(KeyValuePair item) { Add(item.Key.ToSymbol(), item.Value); } /// /// Add the supplied item to the SymbolDict. /// public void Add(KeyValuePair item) { Add(item.Key, item.Value); } /// /// Add the supplied items to the SymbolDict. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the SymbolDict contains the item with the supplied /// key. /// public bool Contains(Symbol key) { var hash = key.Id; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key.Id == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the SymbolDict contains the item with the supplied /// key. /// public bool ContainsKey(Symbol key) { var hash = key.Id; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key.Id == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the SymbolDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(Symbol key, TValue value) { var hash = key.Id; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key.Id == hash && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the SymbolDict contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { return Contains(item.Key, item.Value); } /// /// Returns true if the SymbolDict contains the given value. /// public bool ContainsValue(TValue value) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } return false; } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(Symbol key) { var hash = key.Id; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key.Id == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the SymbolDict and returned. /// public TValue GetOrCreate(Symbol key, Func creator) { var hash = key.Id; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Key.Id == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } TValue AddCreated(Symbol key, int hash, TValue value) { while (true) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } if (m_firstArray[fi].Item.Key.Id == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ei = m_firstArray[fi].Next; ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = m_firstArray[fi].Next; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(Symbol key, TValue defaultValue) { var hash = key.Id; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Key.Id == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(Symbol key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(Symbol key, out TValue value) { var hash = key.Id; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Key.Id == hash) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); return false; } /// /// Return all the value with the given key. This method is only /// useful if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// public IEnumerable ValuesWithKey(Symbol key) { var hash = key.Id; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) yield break; if (m_firstArray[fi].Item.Key.Id == hash) yield return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) yield return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } /// /// Gets an enumerator for values. /// Should be preferred over Values enumeration in /// performance critical code. /// public ValueEnumerator GetValuesEnumerator() { return new ValueEnumerator(this); } public struct ValueEnumerator : IEnumerator { SymbolDict.Enumerator m_inner; public ValueEnumerator(SymbolDict dict) { m_inner = dict.GetEnumerator(); } public TValue Current => m_inner.Current.Value; object IEnumerator.Current => Current; public void Dispose() => m_inner.Dispose(); public bool MoveNext() => m_inner.MoveNext(); public void Reset() => m_inner.Reset(); } /// /// Gets an enumerator for values with key. It is only useful /// if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// Should be preferred over ValuesWithKey enumeration in /// performance critical code. /// public ValuesWithKeyEnumerator GetValuesWithKeyEnumerator(Symbol key) { return new ValuesWithKeyEnumerator(this, key); } public struct ValuesWithKeyEnumerator : IEnumerator { readonly SymbolDict m_dict; readonly int m_hash; int m_extraIndex; TValue m_current; public ValuesWithKeyEnumerator(SymbolDict dict, Symbol key) { m_dict = dict; m_hash = key.Id; m_extraIndex = int.MaxValue; m_current = default(TValue); } public readonly TValue Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex == int.MaxValue) { var fa = m_dict.m_firstArray; var fi = ((uint)m_hash) % m_dict.m_capacity; m_extraIndex = fa[fi].Next; if (m_extraIndex == 0) return false; if (fa[fi].Item.Key.Id == m_hash) { m_current = fa[fi].Item.Value; return true; } } if (m_extraIndex > 0) { var ea = m_dict.m_extraArray; do { var valid = ea[m_extraIndex].Item.Key.Id == m_hash; if (valid) m_current = ea[m_extraIndex].Item.Value; m_extraIndex = ea[m_extraIndex].Next; if (valid) return true; } while (m_extraIndex > 0); } return false; } public void Reset() { m_extraIndex = int.MaxValue; m_current = default(TValue); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(Symbol key, int skip) { var hash = key.Id; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key.Id == hash) { if (skip == 0) return m_firstArray[fi].Item.Value; --skip; } while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) { if (skip == 0) return m_extraArray[ei].Item.Value; --skip; } ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Remove the item with the supplied key from the SymbolDict and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(Symbol key) { TValue value; if (!TryRemove(key, out value)) throw new KeyNotFoundException(); return value; } /// /// Try to remove the item with the supplied key from the SymbolDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(Symbol key) { TValue value; return TryRemove(key, out value); } /// /// Remove the item with the supplied key and the supplied value /// from the SymbolDict. Returns true if the value was removed. /// public bool Remove(Symbol key, TValue value) { return TryRemove(key, value); } /// /// Remove the item with the supplied KeyValuePair from the SymbolDict. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { return TryRemove(item.Key, item.Value); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(Symbol key, out TValue value) { var hash = key.Id; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Key.Id == hash) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(SymbolValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(SymbolValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(SymbolValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Key.Id == hash) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(SymbolValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } value = default(TValue); return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(Symbol key, TValue value) { var hash = key.Id; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key.Id == hash && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(SymbolValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(SymbolValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(SymbolValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Key.Id == hash && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(SymbolValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Returns all keys in the dictionary as an array. /// public Symbol[] KeysToArray() { var array = new Symbol[m_count]; CopyKeysTo(array, 0); return array; } /// /// Returns all values in the dictionary as an array. /// public TValue[] ValuesToArray() { var array = new TValue[m_count]; CopyValuesTo(array, 0); return array; } /// /// Returns all KeyValuePairs in the dictionary as an array. /// public KeyValuePair[] ToArray() { var array = new KeyValuePair[m_count]; CopyTo(array, 0); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { m_firstArray.Set(default(NextSymbolValue)); m_extraArray.Set(default(SymbolValueNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyKeysTo(Symbol[] array, int index) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyValuesTo(TValue[] array, int index) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Value; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// public void CopyTo(KeyValuePair[] array, int index) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { array[index++] = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } /// /// Copy items into supplied array starting at supplied index. /// public void CopyTo(Array array, int index) { var typedArray = array as KeyValuePair[]; if (typedArray != null) CopyTo(typedArray, index); else throw new ArgumentException(); } /// /// Retuns a concurrent wrapper around the SymbolDict to enable /// concurrent modifications. /// public ConcurrentSymbolDict AsConcurrent() { return new ConcurrentSymbolDict(this); } public void Add(TypedSymbol key, TType value) where TType : TValue { this.Add(key.Symbol, value); } public bool Contains(TypedSymbol key) where TType : TValue { return Contains(key.Symbol); } public bool ContainsKey(TypedSymbol key) where TType : TValue { return ContainsKey(key.Symbol); } public TType Get(TypedSymbol key) where TType : TValue { return (TType)this[key.Symbol]; } public TType Get(TypedSymbol key, TType defaultValue) where TType : TValue { TType value; if (TryGetValue(key, out value)) return value; return defaultValue; } public TType GetOrDefault(TypedSymbol key) where TType : TValue { TType value; if (TryGetValue(key, out value)) return value; return default(TType); } public bool Remove(TypedSymbol key) where TType : TValue { return Remove(key.Symbol); } public void Set(TypedSymbol key, TType value) where TType : TValue { this[key.Symbol] = value; } public bool TryGetValue(TypedSymbol key, out TType value) where TType : TValue { TValue val; if (TryGetValue(key.Symbol, out val)) { value = (TType)val; return true; } value = default(TType); return false; } public TType GetAs(Symbol key) where TType : TValue { return (TType)this[key]; } public TType GetAs(Symbol key, TType defaultValue) where TType : TValue { TValue value; if (TryGetValue(key, out value)) return (TType)value; return defaultValue; } public TType GetAsOrDefault(Symbol key) where TType : TValue { TValue value; if (TryGetValue(key, out value)) return (TType)value; return default(TType); } #endregion #region IEnumerable> Members IEnumerator> IEnumerable>.GetEnumerator() { return new Enumerator(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region IDictionary Members ICollection IDictionary.Keys => new KeyCollection(this); ICollection IDictionary.Values => new ValueCollection(this); private sealed class KeyCollection(SymbolDict parent) : ICollection, ICollection, IReadOnlyCollection { public void CopyTo(Symbol[] array, int index) => parent.CopyKeysTo(array, index); public int Count => parent.Count; bool ICollection.IsReadOnly => true; void ICollection.Add(Symbol item) => throw new NotSupportedException(); void ICollection.Clear() => throw new NotSupportedException(); public bool Contains(Symbol item) => parent.ContainsKey(item); bool ICollection.Remove(Symbol item) => throw new NotSupportedException(); IEnumerator IEnumerable.GetEnumerator() => new Enumerator(parent); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator(); void ICollection.CopyTo(Array array, int index) { if (array is Symbol[] keys) parent.CopyKeysTo(keys, index); throw new ArrayTypeMismatchException(); } bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => ((ICollection)parent).SyncRoot; private class Enumerator(SymbolDict dictionary) : IEnumerator, IEnumerator { private SymbolDict.Enumerator _inner = dictionary.GetEnumerator(); public void Dispose() => _inner.Dispose(); public bool MoveNext() => _inner.MoveNext(); public Symbol Current => _inner.Current.Key; object IEnumerator.Current => Current; void IEnumerator.Reset() => _inner.Reset(); } } private sealed class ValueCollection(SymbolDict parent) : ICollection, ICollection, IReadOnlyCollection { public void CopyTo(TValue[] array, int index) => parent.CopyValuesTo(array, index); public int Count => parent.Count; bool ICollection.IsReadOnly => true; void ICollection.Add(TValue item) => throw new NotSupportedException(); void ICollection.Clear() => throw new NotSupportedException(); public bool Contains(TValue item) => parent.ContainsValue(item); bool ICollection.Remove(TValue item) => throw new NotSupportedException(); IEnumerator IEnumerable.GetEnumerator() => new Enumerator(parent); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator(); void ICollection.CopyTo(Array array, int index) { if (array is TValue[] values) parent.CopyValuesTo(values, index); throw new ArrayTypeMismatchException(); } bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => ((ICollection)parent).SyncRoot; private class Enumerator(SymbolDict dictionary) : IEnumerator, IEnumerator { private SymbolDict.Enumerator _inner = dictionary.GetEnumerator(); public void Dispose() => _inner.Dispose(); public bool MoveNext() => _inner.MoveNext(); public TValue Current => _inner.Current.Value; object IEnumerator.Current => Current; void IEnumerator.Reset() => _inner.Reset(); } } #endregion #region Enumerator public Enumerator GetEnumerator() { return new Enumerator(this); } public struct Enumerator : IEnumerator> { readonly SymbolDict m_dict; int m_index; int m_extraIndex; KeyValuePair m_current; public Enumerator(SymbolDict dict) { m_dict = dict; m_index = 0; m_extraIndex = -1; m_current = default(KeyValuePair); } public readonly KeyValuePair Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex < 0) { var fa = m_dict.m_firstArray; var cap = fa.Length; while (m_index < cap) { var nxt = fa[m_index].Next; if (nxt != 0) { m_current = new KeyValuePair(fa[m_index].Item.Key, fa[m_index].Item.Value); m_extraIndex = nxt; m_index++; return true; } m_index++; } return false; } else { var ea = m_dict.m_extraArray; m_current = new KeyValuePair(ea[m_extraIndex].Item.Key, ea[m_extraIndex].Item.Value); m_extraIndex = ea[m_extraIndex].Next; return true; } } public void Reset() { m_index = 0; m_extraIndex = -1; m_current = default( KeyValuePair); } } #endregion #region Private Helper Methods private uint ComputeIncreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_maxFillFactor); } private uint ComputeDecreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_minFillFactor); } private static int AddSlotsToFreeList( SymbolValueNext[] extraArray, int start) { var length = extraArray.Length - 1; for (int i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( SymbolValue item, NextSymbolValue[] firstArray, uint capacity, ref SymbolValueNext[] extraArray, ref int freeIndex, ref uint extraCount) { var fi = ((uint)item.Key.Id) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(uint newCapacity, uint oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextSymbolValue[newCapacity]; var extraArray = new SymbolValueNext[ System.Math.Max((int)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); uint newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { uint fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((uint)m_count - m_extraCount, oldCapacity, m_extraCount, (uint)m_extraArray.Length, (uint)m_count - newExtraCount, newCapacity, newExtraCount, (uint)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( uint oldFirstCount, uint oldCapacity, uint oldExtraCount, uint oldExtraCapacity, uint newFirstCount, uint newCapacity, uint newExtraCount, uint newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region SymbolSet /// /// A SymbolSet is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class SymbolSet : IIntCountable, ICountableDictSet, IDictSet, IEnumerable, IEnumerable, ICollection, ICollection { private uint m_capacity; private NextSymbol[] m_firstArray; private SymbolNext[] m_extraArray; private uint m_count; private uint m_increaseThreshold; private uint m_decreaseThreshold; private int m_freeIndex; private int m_capacityIndex; private uint m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a SymbolSet that autmatically grows and shrinks as necessary. /// public SymbolSet() : this(DictConstant.PrimeSizes[0], (uint)DictConstant.MinExtraCapacity) { } /// /// Create a SymbolSet that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// public SymbolSet(int initialCapacity) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity) { } /// /// Create a SymbolSet and initialize it to contain the supplied /// items. /// public SymbolSet(IEnumerable items) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity) { foreach (var item in items) Add(item); } /// /// Create a SymbolSet and initialize to contain the supplied items. /// Note hat this incurs the overhead of converting all string keys /// to symbols. /// public SymbolSet(IEnumerable items) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), DictConstant.MinExtraCapacity) { foreach (var item in items) Add(item); } private SymbolSet( uint firstCapacity, uint extraCapacity) { m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextSymbol[m_capacity]; m_extraArray = new SymbolNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the SymbolSet. /// public int Count { get { return (int)m_count; } } /// /// Returns the number of items currently contained in the SymbolSet /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the SymbolSet /// as long. /// public uint Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the SymbolSet. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } } /// /// Always returns false. Part of the ICollection implementation. /// public bool IsReadOnly { get { return false; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } public IEnumerable Items { get { return Keys; } } /// /// Returns all keys in the dictionary. /// public IEnumerable Keys { get { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item; while (ei > 0) { yield return m_extraArray[ei].Item; ei = m_extraArray[ei].Next; } } } } public Type KeyType { get { return typeof(Symbol); } } public IEnumerable Objects { get { foreach (object obj in Keys) yield return obj; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the SymbolSet. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the SymbolSet /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((Symbol)objkey); } void ICollection.Add(Symbol key) { Add(key); } /// /// Add the item with the supplied key /// to the SymbolSet. /// public bool Add(Symbol key) { var hash = key.Id; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Id == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Id == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item = key; return true; } /// /// Add the item with the supplied key /// to the SymbolSet. /// public bool TryAdd(Symbol key) { var hash = key.Id; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Id == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Id == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item = key; return true; } /// /// Adds the supplied item to the SymbolSet. Note that this incurs the /// overhead of converting the string key to a symbol. /// public void Add(string key) { Add(key.ToSymbol()); } /// /// Add the supplied keys to the SymbolSet. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the SymbolSet contains the item with the supplied /// key. /// public bool Contains(Symbol key) { var hash = key.Id; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Id == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item.Id == hash) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Remove the item with the supplied key /// from the SymbolSet. Returns true if the value was removed. /// public bool Remove(Symbol key) { return TryRemove(key); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(Symbol key) { var hash = key.Id; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Id == hash) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(Symbol); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(Symbol); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Id == hash) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(Symbol); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Id == hash) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(Symbol); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Returns all keys in the dictionary as an array. /// public Symbol[] ToArray() { var array = new Symbol[m_count]; CopyTo(array, 0); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { m_firstArray.Set(default(NextSymbol)); m_extraArray.Set(default(SymbolNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyTo(Symbol[] array, int index) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item; while (ei > 0) { array[index++] = m_extraArray[ei].Item; ei = m_extraArray[ei].Next; } } } /// /// Copy items into supplied array starting at supplied index. /// public void CopyTo(Array array, int index) { var typedArray = array as Symbol[]; if (typedArray != null) CopyTo(typedArray, index); else throw new ArgumentException(); } /// /// Retuns a concurrent wrapper around the SymbolSet to enable /// concurrent modifications. /// public ConcurrentSymbolSet AsConcurrent() { return new ConcurrentSymbolSet(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region Enumerator public Enumerator GetEnumerator() { return new Enumerator(this); } public struct Enumerator : IEnumerator { readonly SymbolSet m_dict; int m_index; int m_extraIndex; Symbol m_current; public Enumerator(SymbolSet dict) { m_dict = dict; m_index = 0; m_extraIndex = -1; m_current = default(Symbol); } public readonly Symbol Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex < 0) { var fa = m_dict.m_firstArray; var cap = fa.Length; while (m_index < cap) { var nxt = fa[m_index].Next; if (nxt != 0) { m_current = fa[m_index].Item; m_extraIndex = nxt; m_index++; return true; } m_index++; } return false; } else { var ea = m_dict.m_extraArray; m_current = ea[m_extraIndex].Item; m_extraIndex = ea[m_extraIndex].Next; return true; } } public void Reset() { m_index = 0; m_extraIndex = -1; m_current = default(Symbol); } } #endregion #region Private Helper Methods private uint ComputeIncreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_maxFillFactor); } private uint ComputeDecreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_minFillFactor); } private static int AddSlotsToFreeList( SymbolNext[] extraArray, int start) { var length = extraArray.Length - 1; for (int i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( Symbol item, NextSymbol[] firstArray, uint capacity, ref SymbolNext[] extraArray, ref int freeIndex, ref uint extraCount) { var fi = ((uint)item.Id) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(uint newCapacity, uint oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextSymbol[newCapacity]; var extraArray = new SymbolNext[ System.Math.Max((int)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); uint newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { uint fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((uint)m_count - m_extraCount, oldCapacity, m_extraCount, (uint)m_extraArray.Length, (uint)m_count - newExtraCount, newCapacity, newExtraCount, (uint)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( uint oldFirstCount, uint oldCapacity, uint oldExtraCount, uint oldExtraCapacity, uint newFirstCount, uint newCapacity, uint newExtraCount, uint newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region BigDict /// /// A BigDict is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class BigDict : ICountableDict, IDict, IEnumerable, IEnumerable> { private readonly Func m_hfun; private ulong m_capacity; private NextHashKeyValueLong[] m_firstArray; private HashKeyValueNextLong[] m_extraArray; private ulong m_count; private ulong m_increaseThreshold; private ulong m_decreaseThreshold; private readonly bool m_doNotStackDuplicateKeys; private long m_freeIndex; private int m_capacityIndex; private ulong m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a BigDict that autmatically grows and shrinks as necessary. /// If the optional parameter stackDuplicateKeys is set to true, the /// BigDict acts as a stack for all items with the same key. /// public BigDict(Func hfun, bool stackDuplicateKeys = false) : this(hfun, DictConstant.PrimeSizesLong[0], (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a BigDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// BigDict acts as a stack for all items with the same key. /// public BigDict(Func hfun, long initialCapacity) : this(hfun, System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity, false) { } /// /// Create a BigDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// BigDict acts as a stack for all items with the same key. /// public BigDict(Func hfun, long initialCapacity, bool stackDuplicateKeys) : this(hfun, System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a BigDict and initialize it to contain the supplied /// items. /// If the optional parameter stackDuplicateKeys is set to true, the /// BigDict acts as a stack for all items with the same key. /// public BigDict(Func hfun, IEnumerable> items, bool stackDuplicateKeys = false) : this(hfun, Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { foreach (var item in items) Add(item); } private BigDict( Func hfun, ulong firstCapacity, ulong extraCapacity, bool stackDuplicateKeys = false) { m_hfun = hfun; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_doNotStackDuplicateKeys = !stackDuplicateKeys; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizesLong[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizesLong[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextHashKeyValueLong[m_capacity]; m_extraArray = new HashKeyValueNextLong[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the BigDict /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the BigDict /// as long. /// public ulong Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the BigDict. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } } /// /// Always returns false. Part of the ICollection implementation. /// public bool IsReadOnly { get { return false; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } public IEnumerable> Items { get { return KeyValuePairs; } } /// /// Returns all keys in the dictionary. /// public IEnumerable Keys { get { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Key; while (ei > 0) { yield return m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } } public Type KeyType { get { return typeof(TKey); } } /// /// Returns all values in the BigDict. /// public IEnumerable Values { get { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Value; while (ei > 0) { yield return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } } public Type ValueType { get { return typeof(TValue); } } /// /// Returns all key value pairs in the BigDict. /// public IEnumerable> KeyValuePairs { get { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { yield return new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } } /// /// Returns all key value pairs in the BigDict, in such a way, /// that the stack order is correct when the pairs are put into a /// new BigDict in the order they are returned. /// public IEnumerable> KeyValuePairsForStorage { get { var stack = new Stack(); for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; while (ei > 0) { stack.Push(ei); ei = m_extraArray[ei].Next; } while (stack.Count > 0) { ei = stack.Pop(); yield return new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); } yield return new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); } } } public IEnumerable<(object, object)> ObjectPairs { get { foreach (var kvp in KeyValuePairsForStorage) yield return (kvp.Key, kvp.Value); } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the BigDict acts as a stack. /// /// /// public TValue this[TKey key] { get { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } set { var hash = m_hfun(key); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { m_firstArray[fi].Item.Value = value; return; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_extraArray[ei].Item.Value = value; return; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.LongLength; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the BigDict. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the BigDict /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((TKey)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the BigDict. /// public void Add(TKey key, TValue value) { var hash = m_hfun(key); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } /// /// Add the item with the supplied key and the supplied value /// to the BigDict. /// public void Add(TKey key, long hash, TValue value) { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } /// /// Add the item with the supplied key and the supplied value /// to the BigDict. /// public bool TryAdd(TKey key, TValue value) { var hash = m_hfun(key); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } /// /// Add the item with the supplied key and the supplied value /// to the BigDict. /// public bool TryAdd(TKey key, long hash, TValue value) { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } /// /// Add the supplied item to the BigDict. /// public void Add(KeyValuePair item) { Add(item.Key, item.Value); } /// /// Add the supplied items to the BigDict. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the BigDict contains the item with the supplied /// key. /// public bool Contains(TKey key) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the BigDict contains the item with the supplied /// key. /// public bool Contains(TKey key, long hash) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the BigDict contains the item with the supplied /// key. /// public bool ContainsKey(TKey key) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the BigDict contains the item with the supplied /// key. /// public bool ContainsKey(TKey key, long hash) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the BigDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, TValue value) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the BigDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, long hash, TValue value) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the BigDict contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { return Contains(item.Key, item.Value); } /// /// Returns true if the BigDict contains the given value. /// public bool ContainsValue(TValue value) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } return false; } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the BigDict and returned. /// public TValue GetOrCreate(TKey key, Func creator) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } TValue AddCreated(TKey key, long hash, TValue value) { while (true) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ei = m_firstArray[fi].Next; ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = m_firstArray[fi].Next; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, TValue defaultValue) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key, long hash) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the BigDict and returned. /// public TValue GetOrCreate(TKey key, long hash, Func creator) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, long hash, TValue defaultValue) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(TKey key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, out TValue value) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); return false; } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, long hash, out TValue value) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); return false; } /// /// Return all the value with the given key. This method is only /// useful if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// public IEnumerable ValuesWithKey(TKey key) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) yield break; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) yield return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) yield return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } /// /// Gets an enumerator for values. /// Should be preferred over Values enumeration in /// performance critical code. /// public ValueEnumerator GetValuesEnumerator() { return new ValueEnumerator(this); } public struct ValueEnumerator : IEnumerator { BigDict.Enumerator m_inner; public ValueEnumerator(BigDict dict) { m_inner = dict.GetEnumerator(); } public TValue Current => m_inner.Current.Value; object IEnumerator.Current => Current; public void Dispose() => m_inner.Dispose(); public bool MoveNext() => m_inner.MoveNext(); public void Reset() => m_inner.Reset(); } /// /// Gets an enumerator for values with key. It is only useful /// if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// Should be preferred over ValuesWithKey enumeration in /// performance critical code. /// public ValuesWithKeyEnumerator GetValuesWithKeyEnumerator(TKey key) { return new ValuesWithKeyEnumerator(this, key); } public struct ValuesWithKeyEnumerator : IEnumerator { readonly BigDict m_dict; readonly TKey m_key; readonly long m_hash; long m_extraIndex; TValue m_current; public ValuesWithKeyEnumerator(BigDict dict, TKey key) { m_dict = dict; m_key = key; m_hash = dict.m_hfun(key); m_extraIndex = int.MaxValue; m_current = default(TValue); } public readonly TValue Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex == int.MaxValue) { var fa = m_dict.m_firstArray; var fi = ((uint)m_hash) % m_dict.m_capacity; m_extraIndex = fa[fi].Next; if (m_extraIndex == 0) return false; if (fa[fi].Item.Hash == m_hash && m_key.Equals(fa[fi].Item.Key)) { m_current = fa[fi].Item.Value; return true; } } if (m_extraIndex > 0) { var ea = m_dict.m_extraArray; do { var valid = ea[m_extraIndex].Item.Hash == m_hash && m_key.Equals(ea[m_extraIndex].Item.Key); if (valid) m_current = ea[m_extraIndex].Item.Value; m_extraIndex = ea[m_extraIndex].Next; if (valid) return true; } while (m_extraIndex > 0); } return false; } public void Reset() { m_extraIndex = int.MaxValue; m_current = default(TValue); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(TKey key, long skip) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (skip == 0) return m_firstArray[fi].Item.Value; --skip; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { if (skip == 0) return m_extraArray[ei].Item.Value; --skip; } ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Remove the item with the supplied key from the BigDict and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(TKey key) { TValue value; if (!TryRemove(key, out value)) throw new KeyNotFoundException(); return value; } /// /// Try to remove the item with the supplied key from the BigDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key) { TValue value; return TryRemove(key, out value); } /// /// Try to remove the item with the supplied key from the BigDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key, long hash) { TValue value; return TryRemove(key, hash, out value); } /// /// Remove the item with the supplied key and the supplied value /// from the BigDict. Returns true if the value was removed. /// public bool Remove(TKey key, TValue value) { return TryRemove(key, value); } /// /// Remove the item with the supplied key and the supplied value /// from the BigDict. Returns true if the value was removed. /// public bool Remove(TKey key, long hash, TValue value) { return TryRemove(key, hash, value); } /// /// Remove the item with the supplied KeyValuePair from the BigDict. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { return TryRemove(item.Key, item.Value); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, out TValue value) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValueLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValueLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } value = default(TValue); return false; } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, long hash, out TValue value) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValueLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValueLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } value = default(TValue); return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, TValue value) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValueLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key) && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValueLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, long hash, TValue value) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValueLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key) && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValueLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Returns all keys in the dictionary as an array. /// public TKey[] KeysToArray() { var array = new TKey[m_count]; CopyKeysTo(array, 0L); return array; } /// /// Returns all values in the dictionary as an array. /// public TValue[] ValuesToArray() { var array = new TValue[m_count]; CopyValuesTo(array, 0L); return array; } /// /// Returns all KeyValuePairs in the dictionary as an array. /// public KeyValuePair[] ToArray() { var array = new KeyValuePair[m_count]; CopyTo(array, 0L); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { m_firstArray.Set(default(NextHashKeyValueLong)); m_extraArray.Set(default(HashKeyValueNextLong)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyKeysTo(TKey[] array, long index) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyValuesTo(TValue[] array, long index) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Value; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// public void CopyTo(KeyValuePair[] array, long index) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { array[index++] = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } /// /// Copy items into supplied array starting at supplied index. /// public void CopyTo(Array array, int index) { var typedArray = array as KeyValuePair[]; if (typedArray != null) CopyTo(typedArray, (long)index); else throw new ArgumentException(); } /// /// Retuns a concurrent wrapper around the BigDict to enable /// concurrent modifications. /// public ConcurrentBigDict AsConcurrent() { return new ConcurrentBigDict(this); } #endregion #region IEnumerable> Members IEnumerator> IEnumerable>.GetEnumerator() { return new Enumerator(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region Enumerator public Enumerator GetEnumerator() { return new Enumerator(this); } public struct Enumerator : IEnumerator> { readonly BigDict m_dict; long m_index; long m_extraIndex; KeyValuePair m_current; public Enumerator(BigDict dict) { m_dict = dict; m_index = 0; m_extraIndex = -1; m_current = default(KeyValuePair); } public readonly KeyValuePair Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex < 0) { var fa = m_dict.m_firstArray; var cap = fa.Length; while (m_index < cap) { var nxt = fa[m_index].Next; if (nxt != 0) { m_current = new KeyValuePair(fa[m_index].Item.Key, fa[m_index].Item.Value); m_extraIndex = nxt; m_index++; return true; } m_index++; } return false; } else { var ea = m_dict.m_extraArray; m_current = new KeyValuePair(ea[m_extraIndex].Item.Key, ea[m_extraIndex].Item.Value); m_extraIndex = ea[m_extraIndex].Next; return true; } } public void Reset() { m_index = 0; m_extraIndex = -1; m_current = default( KeyValuePair); } } #endregion #region Private Helper Methods private ulong ComputeIncreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_maxFillFactor); } private ulong ComputeDecreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_minFillFactor); } private static long AddSlotsToFreeList( HashKeyValueNextLong[] extraArray, long start) { var length = extraArray.Length - 1; for (long i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizesLong[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizesLong[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( HashKeyValueLong item, NextHashKeyValueLong[] firstArray, ulong capacity, ref HashKeyValueNextLong[] extraArray, ref long freeIndex, ref ulong extraCount) { var fi = ((ulong)item.Hash) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(ulong newCapacity, ulong oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextHashKeyValueLong[newCapacity]; var extraArray = new HashKeyValueNextLong[ System.Math.Max((long)DictConstant.MinExtraCapacity, m_extraArray.LongLength / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); ulong newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { ulong fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((ulong)m_count - m_extraCount, oldCapacity, m_extraCount, (ulong)m_extraArray.Length, (ulong)m_count - newExtraCount, newCapacity, newExtraCount, (ulong)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( ulong oldFirstCount, ulong oldCapacity, ulong oldExtraCount, ulong oldExtraCapacity, ulong newFirstCount, ulong newCapacity, ulong newExtraCount, ulong newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region BigDictSet /// /// A BigDictSet is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class BigDictSet : ICountableDictSet, IDictSet, IEnumerable, IEnumerable { private readonly Func m_hfun; private ulong m_capacity; private NextHashKeyLong[] m_firstArray; private HashKeyNextLong[] m_extraArray; private ulong m_count; private ulong m_increaseThreshold; private ulong m_decreaseThreshold; private long m_freeIndex; private int m_capacityIndex; private ulong m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a BigDictSet that autmatically grows and shrinks as necessary. /// public BigDictSet(Func hfun) : this(hfun, DictConstant.PrimeSizesLong[0], (ulong)DictConstant.MinExtraCapacity) { } /// /// Create a BigDictSet that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// public BigDictSet(Func hfun, long initialCapacity) : this(hfun, System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity) { } /// /// Create a BigDictSet and initialize it to contain the supplied /// items. /// public BigDictSet(Func hfun, IEnumerable items) : this(hfun, Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity) { foreach (var item in items) Add(item); } private BigDictSet( Func hfun, ulong firstCapacity, ulong extraCapacity) { m_hfun = hfun; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizesLong[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizesLong[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextHashKeyLong[m_capacity]; m_extraArray = new HashKeyNextLong[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the BigDictSet /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the BigDictSet /// as long. /// public ulong Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the BigDictSet. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } } /// /// Always returns false. Part of the ICollection implementation. /// public bool IsReadOnly { get { return false; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } public IEnumerable Items { get { return Keys; } } /// /// Returns all keys in the dictionary. /// public IEnumerable Keys { get { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Key; while (ei > 0) { yield return m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } } public Type KeyType { get { return typeof(TKey); } } public IEnumerable Objects { get { foreach (object obj in Keys) yield return obj; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the BigDictSet. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the BigDictSet /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((TKey)objkey); } /// /// Add the item with the supplied key /// to the BigDictSet. /// public bool Add(TKey key) { var hash = m_hfun(key); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } /// /// Add the item with the supplied key /// to the BigDictSet. /// public bool Add(TKey key, long hash) { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } /// /// Add the item with the supplied key /// to the BigDictSet. /// public bool TryAdd(TKey key) { var hash = m_hfun(key); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } /// /// Add the item with the supplied key /// to the BigDictSet. /// public bool TryAdd(TKey key, long hash) { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } /// /// Add the supplied keys to the BigDictSet. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the BigDictSet contains the item with the supplied /// key. /// public bool Contains(TKey key) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the BigDictSet contains the item with the supplied /// key. /// public bool Contains(TKey key, long hash) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Remove the item with the supplied key /// from the BigDictSet. Returns true if the value was removed. /// public bool Remove(TKey key) { return TryRemove(key); } /// /// Remove the item with the supplied key /// from the BigDictSet. Returns true if the value was removed. /// public bool Remove(TKey key, long hash) { return TryRemove(key, hash); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key, long hash) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Returns all keys in the dictionary as an array. /// public TKey[] ToArray() { var array = new TKey[m_count]; CopyTo(array, 0L); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { m_firstArray.Set(default(NextHashKeyLong)); m_extraArray.Set(default(HashKeyNextLong)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyTo(TKey[] array, long index) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } /// /// Copy items into supplied array starting at supplied index. /// public void CopyTo(Array array, int index) { var typedArray = array as TKey[]; if (typedArray != null) CopyTo(typedArray, (long)index); else throw new ArgumentException(); } /// /// Retuns a concurrent wrapper around the BigDictSet to enable /// concurrent modifications. /// public ConcurrentBigDictSet AsConcurrent() { return new ConcurrentBigDictSet(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region Enumerator public Enumerator GetEnumerator() { return new Enumerator(this); } public struct Enumerator : IEnumerator { readonly BigDictSet m_dict; long m_index; long m_extraIndex; TKey m_current; public Enumerator(BigDictSet dict) { m_dict = dict; m_index = 0; m_extraIndex = -1; m_current = default(TKey); } public readonly TKey Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex < 0) { var fa = m_dict.m_firstArray; var cap = fa.Length; while (m_index < cap) { var nxt = fa[m_index].Next; if (nxt != 0) { m_current = fa[m_index].Item.Key; m_extraIndex = nxt; m_index++; return true; } m_index++; } return false; } else { var ea = m_dict.m_extraArray; m_current = ea[m_extraIndex].Item.Key; m_extraIndex = ea[m_extraIndex].Next; return true; } } public void Reset() { m_index = 0; m_extraIndex = -1; m_current = default(TKey); } } #endregion #region Private Helper Methods private ulong ComputeIncreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_maxFillFactor); } private ulong ComputeDecreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_minFillFactor); } private static long AddSlotsToFreeList( HashKeyNextLong[] extraArray, long start) { var length = extraArray.Length - 1; for (long i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizesLong[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizesLong[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( HashKeyLong item, NextHashKeyLong[] firstArray, ulong capacity, ref HashKeyNextLong[] extraArray, ref long freeIndex, ref ulong extraCount) { var fi = ((ulong)item.Hash) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(ulong newCapacity, ulong oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextHashKeyLong[newCapacity]; var extraArray = new HashKeyNextLong[ System.Math.Max((long)DictConstant.MinExtraCapacity, m_extraArray.LongLength / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); ulong newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { ulong fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((ulong)m_count - m_extraCount, oldCapacity, m_extraCount, (ulong)m_extraArray.Length, (ulong)m_count - newExtraCount, newCapacity, newExtraCount, (ulong)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( ulong oldFirstCount, ulong oldCapacity, ulong oldExtraCount, ulong oldExtraCapacity, ulong newFirstCount, ulong newCapacity, ulong newExtraCount, ulong newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region LongDict /// /// A LongDict is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class LongDict : ICountableDict, IDict, IEnumerable, IEnumerable> { private ulong m_capacity; private NextLongValue[] m_firstArray; private LongValueNext[] m_extraArray; private ulong m_count; private ulong m_increaseThreshold; private ulong m_decreaseThreshold; private readonly bool m_doNotStackDuplicateKeys; private long m_freeIndex; private int m_capacityIndex; private ulong m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a LongDict that autmatically grows and shrinks as necessary. /// If the optional parameter stackDuplicateKeys is set to true, the /// LongDict acts as a stack for all items with the same key. /// public LongDict(bool stackDuplicateKeys = false) : this(DictConstant.PrimeSizes[0], (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a LongDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// LongDict acts as a stack for all items with the same key. /// public LongDict(long initialCapacity) : this(System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizes[0]), (ulong)DictConstant.MinExtraCapacity, false) { } /// /// Create a LongDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// LongDict acts as a stack for all items with the same key. /// public LongDict(long initialCapacity, bool stackDuplicateKeys) : this(System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizes[0]), (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a LongDict and initialize it to contain the supplied /// items. /// If the optional parameter stackDuplicateKeys is set to true, the /// LongDict acts as a stack for all items with the same key. /// public LongDict(IEnumerable> items, bool stackDuplicateKeys = false) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { foreach (var item in items) Add(item); } private LongDict( ulong firstCapacity, ulong extraCapacity, bool stackDuplicateKeys = false) { m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_doNotStackDuplicateKeys = !stackDuplicateKeys; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextLongValue[m_capacity]; m_extraArray = new LongValueNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the LongDict /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the LongDict /// as long. /// public ulong Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the LongDict. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } } /// /// Always returns false. Part of the ICollection implementation. /// public bool IsReadOnly { get { return false; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } public IEnumerable> Items { get { return KeyValuePairs; } } /// /// Returns all keys in the dictionary. /// public IEnumerable Keys { get { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Key; while (ei > 0) { yield return m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } } public Type KeyType { get { return typeof(long); } } /// /// Returns all values in the LongDict. /// public IEnumerable Values { get { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Value; while (ei > 0) { yield return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } } public Type ValueType { get { return typeof(TValue); } } /// /// Returns all key value pairs in the LongDict. /// public IEnumerable> KeyValuePairs { get { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { yield return new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } } /// /// Returns all key value pairs in the LongDict, in such a way, /// that the stack order is correct when the pairs are put into a /// new LongDict in the order they are returned. /// public IEnumerable> KeyValuePairsForStorage { get { var stack = new Stack(); for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; while (ei > 0) { stack.Push(ei); ei = m_extraArray[ei].Next; } while (stack.Count > 0) { ei = stack.Pop(); yield return new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); } yield return new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); } } } public IEnumerable<(object, object)> ObjectPairs { get { foreach (var kvp in KeyValuePairsForStorage) yield return (kvp.Key, kvp.Value); } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the LongDict acts as a stack. /// /// /// public TValue this[long key] { get { var hash = key; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } set { var hash = key; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { if (m_firstArray[fi].Item.Key == hash) { m_firstArray[fi].Item.Value = value; return; } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { m_extraArray[ei].Item.Value = value; return; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the LongDict. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the LongDict /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((long)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the LongDict. /// public void Add(long key, TValue value) { var hash = key; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Key == hash) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } /// /// Add the item with the supplied key and the supplied value /// to the LongDict. /// public bool TryAdd(long key, TValue value) { var hash = key; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Key == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } /// /// Add the supplied item to the LongDict. /// public void Add(KeyValuePair item) { Add(item.Key, item.Value); } /// /// Add the supplied items to the LongDict. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the LongDict contains the item with the supplied /// key. /// public bool Contains(long key) { var hash = key; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the LongDict contains the item with the supplied /// key. /// public bool ContainsKey(long key) { var hash = key; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the LongDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(long key, TValue value) { var hash = key; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key == hash && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the LongDict contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { return Contains(item.Key, item.Value); } /// /// Returns true if the LongDict contains the given value. /// public bool ContainsValue(TValue value) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } return false; } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(long key) { var hash = key; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the LongDict and returned. /// public TValue GetOrCreate(long key, Func creator) { var hash = key; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } TValue AddCreated(long key, long hash, TValue value) { while (true) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ei = m_firstArray[fi].Next; ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = m_firstArray[fi].Next; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(long key, TValue defaultValue) { var hash = key; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(long key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(long key, out TValue value) { var hash = key; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Key == hash) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); return false; } /// /// Return all the value with the given key. This method is only /// useful if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// public IEnumerable ValuesWithKey(long key) { var hash = key; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) yield break; if (m_firstArray[fi].Item.Key == hash) yield return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) yield return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } /// /// Gets an enumerator for values. /// Should be preferred over Values enumeration in /// performance critical code. /// public ValueEnumerator GetValuesEnumerator() { return new ValueEnumerator(this); } public struct ValueEnumerator : IEnumerator { LongDict.Enumerator m_inner; public ValueEnumerator(LongDict dict) { m_inner = dict.GetEnumerator(); } public TValue Current => m_inner.Current.Value; object IEnumerator.Current => Current; public void Dispose() => m_inner.Dispose(); public bool MoveNext() => m_inner.MoveNext(); public void Reset() => m_inner.Reset(); } /// /// Gets an enumerator for values with key. It is only useful /// if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// Should be preferred over ValuesWithKey enumeration in /// performance critical code. /// public ValuesWithKeyEnumerator GetValuesWithKeyEnumerator(long key) { return new ValuesWithKeyEnumerator(this, key); } public struct ValuesWithKeyEnumerator : IEnumerator { readonly LongDict m_dict; readonly long m_hash; long m_extraIndex; TValue m_current; public ValuesWithKeyEnumerator(LongDict dict, long key) { m_dict = dict; m_hash = key; m_extraIndex = int.MaxValue; m_current = default(TValue); } public readonly TValue Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex == int.MaxValue) { var fa = m_dict.m_firstArray; var fi = ((uint)m_hash) % m_dict.m_capacity; m_extraIndex = fa[fi].Next; if (m_extraIndex == 0) return false; if (fa[fi].Item.Key == m_hash) { m_current = fa[fi].Item.Value; return true; } } if (m_extraIndex > 0) { var ea = m_dict.m_extraArray; do { var valid = ea[m_extraIndex].Item.Key == m_hash; if (valid) m_current = ea[m_extraIndex].Item.Value; m_extraIndex = ea[m_extraIndex].Next; if (valid) return true; } while (m_extraIndex > 0); } return false; } public void Reset() { m_extraIndex = int.MaxValue; m_current = default(TValue); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(long key, long skip) { var hash = key; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key == hash) { if (skip == 0) return m_firstArray[fi].Item.Value; --skip; } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { if (skip == 0) return m_extraArray[ei].Item.Value; --skip; } ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Remove the item with the supplied key from the LongDict and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(long key) { TValue value; if (!TryRemove(key, out value)) throw new KeyNotFoundException(); return value; } /// /// Try to remove the item with the supplied key from the LongDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(long key) { TValue value; return TryRemove(key, out value); } /// /// Remove the item with the supplied key and the supplied value /// from the LongDict. Returns true if the value was removed. /// public bool Remove(long key, TValue value) { return TryRemove(key, value); } /// /// Remove the item with the supplied KeyValuePair from the LongDict. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { return TryRemove(item.Key, item.Value); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(long key, out TValue value) { var hash = key; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Key == hash) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(LongValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(LongValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(LongValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Key == hash) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(LongValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } value = default(TValue); return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(long key, TValue value) { var hash = key; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key == hash && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(LongValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(LongValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Key == hash && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(LongValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Key == hash && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(LongValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Returns all keys in the dictionary as an array. /// public long[] KeysToArray() { var array = new long[m_count]; CopyKeysTo(array, 0L); return array; } /// /// Returns all values in the dictionary as an array. /// public TValue[] ValuesToArray() { var array = new TValue[m_count]; CopyValuesTo(array, 0L); return array; } /// /// Returns all KeyValuePairs in the dictionary as an array. /// public KeyValuePair[] ToArray() { var array = new KeyValuePair[m_count]; CopyTo(array, 0L); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { m_firstArray.Set(default(NextLongValue)); m_extraArray.Set(default(LongValueNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyKeysTo(long[] array, long index) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyValuesTo(TValue[] array, long index) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Value; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// public void CopyTo(KeyValuePair[] array, long index) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { array[index++] = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } /// /// Copy items into supplied array starting at supplied index. /// public void CopyTo(Array array, int index) { var typedArray = array as KeyValuePair[]; if (typedArray != null) CopyTo(typedArray, (long)index); else throw new ArgumentException(); } /// /// Retuns a concurrent wrapper around the LongDict to enable /// concurrent modifications. /// public ConcurrentLongDict AsConcurrent() { return new ConcurrentLongDict(this); } #endregion #region IEnumerable> Members IEnumerator> IEnumerable>.GetEnumerator() { return new Enumerator(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region Enumerator public Enumerator GetEnumerator() { return new Enumerator(this); } public struct Enumerator : IEnumerator> { readonly LongDict m_dict; long m_index; long m_extraIndex; KeyValuePair m_current; public Enumerator(LongDict dict) { m_dict = dict; m_index = 0; m_extraIndex = -1; m_current = default(KeyValuePair); } public readonly KeyValuePair Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex < 0) { var fa = m_dict.m_firstArray; var cap = fa.Length; while (m_index < cap) { var nxt = fa[m_index].Next; if (nxt != 0) { m_current = new KeyValuePair(fa[m_index].Item.Key, fa[m_index].Item.Value); m_extraIndex = nxt; m_index++; return true; } m_index++; } return false; } else { var ea = m_dict.m_extraArray; m_current = new KeyValuePair(ea[m_extraIndex].Item.Key, ea[m_extraIndex].Item.Value); m_extraIndex = ea[m_extraIndex].Next; return true; } } public void Reset() { m_index = 0; m_extraIndex = -1; m_current = default( KeyValuePair); } } #endregion #region Private Helper Methods private ulong ComputeIncreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_maxFillFactor); } private ulong ComputeDecreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_minFillFactor); } private static long AddSlotsToFreeList( LongValueNext[] extraArray, long start) { var length = extraArray.Length - 1; for (long i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( LongValue item, NextLongValue[] firstArray, ulong capacity, ref LongValueNext[] extraArray, ref long freeIndex, ref ulong extraCount) { var fi = ((ulong)item.Key) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(ulong newCapacity, ulong oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextLongValue[newCapacity]; var extraArray = new LongValueNext[ System.Math.Max((long)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); ulong newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { ulong fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((ulong)m_count - m_extraCount, oldCapacity, m_extraCount, (ulong)m_extraArray.Length, (ulong)m_count - newExtraCount, newCapacity, newExtraCount, (ulong)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( ulong oldFirstCount, ulong oldCapacity, ulong oldExtraCount, ulong oldExtraCapacity, ulong newFirstCount, ulong newCapacity, ulong newExtraCount, ulong newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region LongSet /// /// A LongSet is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class LongSet : ICountableDictSet, IDictSet, IEnumerable, IEnumerable { private ulong m_capacity; private NextLong[] m_firstArray; private LongNext[] m_extraArray; private ulong m_count; private ulong m_increaseThreshold; private ulong m_decreaseThreshold; private long m_freeIndex; private int m_capacityIndex; private ulong m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a LongSet that autmatically grows and shrinks as necessary. /// public LongSet() : this(DictConstant.PrimeSizes[0], (ulong)DictConstant.MinExtraCapacity) { } /// /// Create a LongSet that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// public LongSet(long initialCapacity) : this(System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizes[0]), (ulong)DictConstant.MinExtraCapacity) { } /// /// Create a LongSet and initialize it to contain the supplied /// items. /// public LongSet(IEnumerable items) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (ulong)DictConstant.MinExtraCapacity) { foreach (var item in items) Add(item); } private LongSet( ulong firstCapacity, ulong extraCapacity) { m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextLong[m_capacity]; m_extraArray = new LongNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the LongSet /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the LongSet /// as long. /// public ulong Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the LongSet. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } } /// /// Always returns false. Part of the ICollection implementation. /// public bool IsReadOnly { get { return false; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } public IEnumerable Items { get { return Keys; } } /// /// Returns all keys in the dictionary. /// public IEnumerable Keys { get { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item; while (ei > 0) { yield return m_extraArray[ei].Item; ei = m_extraArray[ei].Next; } } } } public Type KeyType { get { return typeof(long); } } public IEnumerable Objects { get { foreach (object obj in Keys) yield return obj; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the LongSet. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the LongSet /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((long)objkey); } /// /// Add the item with the supplied key /// to the LongSet. /// public bool Add(long key) { var hash = key; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item = key; return true; } /// /// Add the item with the supplied key /// to the LongSet. /// public bool TryAdd(long key) { var hash = key; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item = key; return true; } /// /// Add the supplied keys to the LongSet. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the LongSet contains the item with the supplied /// key. /// public bool Contains(long key) { var hash = key; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item == hash) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Remove the item with the supplied key /// from the LongSet. Returns true if the value was removed. /// public bool Remove(long key) { return TryRemove(key); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(long key) { var hash = key; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item == hash) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(long); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(long); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item == hash) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(long); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item == hash) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(long); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Returns all keys in the dictionary as an array. /// public long[] ToArray() { var array = new long[m_count]; CopyTo(array, 0L); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { m_firstArray.Set(default(NextLong)); m_extraArray.Set(default(LongNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyTo(long[] array, long index) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item; while (ei > 0) { array[index++] = m_extraArray[ei].Item; ei = m_extraArray[ei].Next; } } } /// /// Copy items into supplied array starting at supplied index. /// public void CopyTo(Array array, int index) { var typedArray = array as long[]; if (typedArray != null) CopyTo(typedArray, (long)index); else throw new ArgumentException(); } /// /// Retuns a concurrent wrapper around the LongSet to enable /// concurrent modifications. /// public ConcurrentLongSet AsConcurrent() { return new ConcurrentLongSet(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region Enumerator public Enumerator GetEnumerator() { return new Enumerator(this); } public struct Enumerator : IEnumerator { readonly LongSet m_dict; long m_index; long m_extraIndex; long m_current; public Enumerator(LongSet dict) { m_dict = dict; m_index = 0; m_extraIndex = -1; m_current = default(long); } public readonly long Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex < 0) { var fa = m_dict.m_firstArray; var cap = fa.Length; while (m_index < cap) { var nxt = fa[m_index].Next; if (nxt != 0) { m_current = fa[m_index].Item; m_extraIndex = nxt; m_index++; return true; } m_index++; } return false; } else { var ea = m_dict.m_extraArray; m_current = ea[m_extraIndex].Item; m_extraIndex = ea[m_extraIndex].Next; return true; } } public void Reset() { m_index = 0; m_extraIndex = -1; m_current = default(long); } } #endregion #region Private Helper Methods private ulong ComputeIncreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_maxFillFactor); } private ulong ComputeDecreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_minFillFactor); } private static long AddSlotsToFreeList( LongNext[] extraArray, long start) { var length = extraArray.Length - 1; for (long i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( long item, NextLong[] firstArray, ulong capacity, ref LongNext[] extraArray, ref long freeIndex, ref ulong extraCount) { var fi = ((ulong)item) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(ulong newCapacity, ulong oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextLong[newCapacity]; var extraArray = new LongNext[ System.Math.Max((long)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); ulong newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { ulong fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((ulong)m_count - m_extraCount, oldCapacity, m_extraCount, (ulong)m_extraArray.Length, (ulong)m_count - newExtraCount, newCapacity, newExtraCount, (ulong)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( ulong oldFirstCount, ulong oldCapacity, ulong oldExtraCount, ulong oldExtraCapacity, ulong newFirstCount, ulong newCapacity, ulong newExtraCount, ulong newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region ConcurrentDict /// /// A ConcurrentDict is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class ConcurrentDict { private readonly Dict m_dict; #region Constructors /// /// A ConcurrentDict can only be concstructed by wrapping its non-concurrent /// counterpart. /// public ConcurrentDict(Dict dict) { m_dict = dict; } #endregion #region Properties /// /// Returns the number of items currently contained in the ConcurrentDict. /// public int Count { get { return m_dict.Count; } } /// /// Returns the number of items currently contained in the ConcurrentDict /// as long. /// public long LongCount { get { return m_dict.LongCount; } } /// /// Returns the number of items currently contained in the ConcurrentDict /// as long. /// public uint Capacity { get { return m_dict.Capacity; } set { m_dict.Capacity = value; } } /// /// Return the non-concurrent contained ConcurrentDict. /// public Dict NonConcurrent { get { return m_dict; } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the ConcurrentDict acts as a stack. /// /// /// public TValue this[TKey key] { get { Monitor.Enter(this); try { return m_dict[key]; } finally { Monitor.Exit(this); } } set { Monitor.Enter(this); try { m_dict[key] = value; } finally { Monitor.Exit(this); } } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the ConcurrentDict. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the ConcurrentDict /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((TKey)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentDict. /// public void Add(TKey key, TValue value) { Monitor.Enter(this); try { m_dict.Add(key, value); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentDict. /// public void Add(TKey key, int hash, TValue value) { Monitor.Enter(this); try { m_dict.Add(key, hash, value); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentDict. /// public bool TryAdd(TKey key, TValue value) { Monitor.Enter(this); try { return m_dict.TryAdd(key, value); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentDict. /// public bool TryAdd(TKey key, int hash, TValue value) { Monitor.Enter(this); try { return m_dict.TryAdd(key, hash, value); } finally { Monitor.Exit(this); } } /// /// Add the supplied item to the ConcurrentDict. /// public void Add(KeyValuePair item) { Monitor.Enter(this); try { m_dict.Add(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Add the supplied items to the ConcurrentDict. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the ConcurrentDict contains the item with the supplied /// key. /// public bool Contains(TKey key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentDict contains the item with the supplied /// key. /// public bool Contains(TKey key, int hash) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentDict contains the item with the supplied /// key. /// public bool ContainsKey(TKey key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentDict contains the item with the supplied /// key. /// public bool ContainsKey(TKey key, int hash) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, TValue value) { Monitor.Enter(this); try { return m_dict.Contains(key, value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, int hash, TValue value) { Monitor.Enter(this); try { return m_dict.Contains(key, value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentDict contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { Monitor.Enter(this); try { return m_dict.Contains(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentDict contains the given value. /// public bool ContainsValue(TValue value) { Monitor.Enter(this); try { return m_dict.ContainsValue(value); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key) { Monitor.Enter(this); try { return m_dict.Get(key); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the ConcurrentDict and returned. /// public TValue GetOrCreate(TKey key, Func creator) { Monitor.Enter(this); try { return m_dict.GetOrCreate(key, creator); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, TValue defaultValue) { Monitor.Enter(this); try { return m_dict.Get(key); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key, int hash) { Monitor.Enter(this); try { return m_dict.Get(key, hash); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the ConcurrentDict and returned. /// public TValue GetOrCreate(TKey key, int hash, Func creator) { Monitor.Enter(this); try { return m_dict.GetOrCreate(key, hash, creator); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, int hash, TValue defaultValue) { Monitor.Enter(this); try { return m_dict.Get(key, hash); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(TKey key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, out TValue value) { Monitor.Enter(this); try { return m_dict.TryGetValue(key, out value); } finally { Monitor.Exit(this); } } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, int hash, out TValue value) { Monitor.Enter(this); try { return m_dict.TryGetValue(key, hash, out value); } finally { Monitor.Exit(this); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(TKey key, int skip) { Monitor.Enter(this); try { return m_dict.ValueWithKeySkip(key, skip); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key from the ConcurrentDict and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(TKey key) { Monitor.Enter(this); try { return m_dict.GetAndRemove(key); } finally { Monitor.Exit(this); } } /// /// Try to remove the item with the supplied key from the ConcurrentDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key) { TValue value; Monitor.Enter(this); try { return m_dict.TryRemove(key, out value); } finally { Monitor.Exit(this); } } /// /// Try to remove the item with the supplied key from the ConcurrentDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key, int hash) { TValue value; Monitor.Enter(this); try { return m_dict.TryRemove(key, hash, out value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key and the supplied value /// from the ConcurrentDict. Returns true if the value was removed. /// public bool Remove(TKey key, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key and the supplied value /// from the ConcurrentDict. Returns true if the value was removed. /// public bool Remove(TKey key, int hash, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash, value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied KeyValuePair from the ConcurrentDict. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { Monitor.Enter(this); try { return m_dict.TryRemove(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, out TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, out value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, int hash, out TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash, out value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, int hash, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash, value); } finally { Monitor.Exit(this); } } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TKey[] KeysToArray() { return m_dict.KeysToArray(); } /// /// Returns all values in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TValue[] ValuesToArray() { return m_dict.ValuesToArray(); } /// /// Returns all KeyValuePairs in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public KeyValuePair[] ToArray() { return m_dict.ToArray(); } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { m_dict.Clear(); } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyKeysTo(TKey[] array, int index) { Monitor.Enter(this); try { m_dict.CopyKeysTo(array, index); } finally { Monitor.Exit(this); } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyValuesTo(TValue[] array, int index) { Monitor.Enter(this); try { m_dict.CopyValuesTo(array, index); } finally { Monitor.Exit(this); } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(KeyValuePair[] array, int index) { Monitor.Enter(this); try { m_dict.CopyTo(array, index); } finally { Monitor.Exit(this); } } #endregion } #endregion #region ConcurrentDictSet /// /// A ConcurrentDictSet is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class ConcurrentDictSet { private readonly DictSet m_dict; #region Constructors /// /// A ConcurrentDictSet can only be concstructed by wrapping its non-concurrent /// counterpart. /// public ConcurrentDictSet(DictSet dict) { m_dict = dict; } #endregion #region Properties /// /// Returns the number of items currently contained in the ConcurrentDictSet. /// public int Count { get { return m_dict.Count; } } /// /// Returns the number of items currently contained in the ConcurrentDictSet /// as long. /// public long LongCount { get { return m_dict.LongCount; } } /// /// Returns the number of items currently contained in the ConcurrentDictSet /// as long. /// public uint Capacity { get { return m_dict.Capacity; } set { m_dict.Capacity = value; } } /// /// Return the non-concurrent contained ConcurrentDictSet. /// public DictSet NonConcurrent { get { return m_dict; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the ConcurrentDictSet. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the ConcurrentDictSet /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((TKey)objkey); } /// /// Add the item with the supplied key /// to the ConcurrentDictSet. /// public bool Add(TKey key) { Monitor.Enter(this); try { return m_dict.Add(key); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key /// to the ConcurrentDictSet. /// public bool Add(TKey key, int hash) { Monitor.Enter(this); try { return m_dict.Add(key, hash); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key /// to the ConcurrentDictSet. /// public bool TryAdd(TKey key) { Monitor.Enter(this); try { return m_dict.TryAdd(key); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key /// to the ConcurrentDictSet. /// public bool TryAdd(TKey key, int hash) { Monitor.Enter(this); try { return m_dict.TryAdd(key, hash); } finally { Monitor.Exit(this); } } /// /// Add the supplied keys to the ConcurrentDictSet. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the ConcurrentDictSet contains the item with the supplied /// key. /// public bool Contains(TKey key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentDictSet contains the item with the supplied /// key. /// public bool Contains(TKey key, int hash) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key /// from the ConcurrentDictSet. Returns true if the value was removed. /// public bool Remove(TKey key) { Monitor.Enter(this); try { return m_dict.TryRemove(key); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key /// from the ConcurrentDictSet. Returns true if the value was removed. /// public bool Remove(TKey key, int hash) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key) { Monitor.Enter(this); try { return m_dict.TryRemove(key); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key, int hash) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash); } finally { Monitor.Exit(this); } } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TKey[] ToArray() { return m_dict.ToArray(); } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { m_dict.Clear(); } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(TKey[] array, int index) { Monitor.Enter(this); try { m_dict.CopyTo(array, index); } finally { Monitor.Exit(this); } } #endregion } #endregion #region ConcurrentIntDict /// /// A ConcurrentIntDict is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class ConcurrentIntDict { private readonly IntDict m_dict; #region Constructors /// /// A ConcurrentIntDict can only be concstructed by wrapping its non-concurrent /// counterpart. /// public ConcurrentIntDict(IntDict dict) { m_dict = dict; } #endregion #region Properties /// /// Returns the number of items currently contained in the ConcurrentIntDict. /// public int Count { get { return m_dict.Count; } } /// /// Returns the number of items currently contained in the ConcurrentIntDict /// as long. /// public long LongCount { get { return m_dict.LongCount; } } /// /// Returns the number of items currently contained in the ConcurrentIntDict /// as long. /// public uint Capacity { get { return m_dict.Capacity; } set { m_dict.Capacity = value; } } /// /// Return the non-concurrent contained ConcurrentIntDict. /// public IntDict NonConcurrent { get { return m_dict; } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the ConcurrentIntDict acts as a stack. /// /// /// public TValue this[int key] { get { Monitor.Enter(this); try { return m_dict[key]; } finally { Monitor.Exit(this); } } set { Monitor.Enter(this); try { m_dict[key] = value; } finally { Monitor.Exit(this); } } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the ConcurrentIntDict. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the ConcurrentIntDict /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((int)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentIntDict. /// public void Add(int key, TValue value) { Monitor.Enter(this); try { m_dict.Add(key, value); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentIntDict. /// public bool TryAdd(int key, TValue value) { Monitor.Enter(this); try { return m_dict.TryAdd(key, value); } finally { Monitor.Exit(this); } } /// /// Add the supplied item to the ConcurrentIntDict. /// public void Add(KeyValuePair item) { Monitor.Enter(this); try { m_dict.Add(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Add the supplied items to the ConcurrentIntDict. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the ConcurrentIntDict contains the item with the supplied /// key. /// public bool Contains(int key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentIntDict contains the item with the supplied /// key. /// public bool ContainsKey(int key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentIntDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(int key, TValue value) { Monitor.Enter(this); try { return m_dict.Contains(key, value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentIntDict contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { Monitor.Enter(this); try { return m_dict.Contains(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentIntDict contains the given value. /// public bool ContainsValue(TValue value) { Monitor.Enter(this); try { return m_dict.ContainsValue(value); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(int key) { Monitor.Enter(this); try { return m_dict.Get(key); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the ConcurrentIntDict and returned. /// public TValue GetOrCreate(int key, Func creator) { Monitor.Enter(this); try { return m_dict.GetOrCreate(key, creator); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(int key, TValue defaultValue) { Monitor.Enter(this); try { return m_dict.Get(key); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(int key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(int key, out TValue value) { Monitor.Enter(this); try { return m_dict.TryGetValue(key, out value); } finally { Monitor.Exit(this); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(int key, int skip) { Monitor.Enter(this); try { return m_dict.ValueWithKeySkip(key, skip); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key from the ConcurrentIntDict and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(int key) { Monitor.Enter(this); try { return m_dict.GetAndRemove(key); } finally { Monitor.Exit(this); } } /// /// Try to remove the item with the supplied key from the ConcurrentIntDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(int key) { TValue value; Monitor.Enter(this); try { return m_dict.TryRemove(key, out value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key and the supplied value /// from the ConcurrentIntDict. Returns true if the value was removed. /// public bool Remove(int key, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied KeyValuePair from the ConcurrentIntDict. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { Monitor.Enter(this); try { return m_dict.TryRemove(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(int key, out TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, out value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(int key, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, value); } finally { Monitor.Exit(this); } } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public int[] KeysToArray() { return m_dict.KeysToArray(); } /// /// Returns all values in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TValue[] ValuesToArray() { return m_dict.ValuesToArray(); } /// /// Returns all KeyValuePairs in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public KeyValuePair[] ToArray() { return m_dict.ToArray(); } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { m_dict.Clear(); } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyKeysTo(int[] array, int index) { Monitor.Enter(this); try { m_dict.CopyKeysTo(array, index); } finally { Monitor.Exit(this); } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyValuesTo(TValue[] array, int index) { Monitor.Enter(this); try { m_dict.CopyValuesTo(array, index); } finally { Monitor.Exit(this); } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(KeyValuePair[] array, int index) { Monitor.Enter(this); try { m_dict.CopyTo(array, index); } finally { Monitor.Exit(this); } } #endregion } #endregion #region ConcurrentIntSet /// /// A ConcurrentIntSet is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class ConcurrentIntSet { private readonly IntSet m_dict; #region Constructors /// /// A ConcurrentIntSet can only be concstructed by wrapping its non-concurrent /// counterpart. /// public ConcurrentIntSet(IntSet dict) { m_dict = dict; } #endregion #region Properties /// /// Returns the number of items currently contained in the ConcurrentIntSet. /// public int Count { get { return m_dict.Count; } } /// /// Returns the number of items currently contained in the ConcurrentIntSet /// as long. /// public long LongCount { get { return m_dict.LongCount; } } /// /// Returns the number of items currently contained in the ConcurrentIntSet /// as long. /// public uint Capacity { get { return m_dict.Capacity; } set { m_dict.Capacity = value; } } /// /// Return the non-concurrent contained ConcurrentIntSet. /// public IntSet NonConcurrent { get { return m_dict; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the ConcurrentIntSet. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the ConcurrentIntSet /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((int)objkey); } /// /// Add the item with the supplied key /// to the ConcurrentIntSet. /// public bool Add(int key) { Monitor.Enter(this); try { return m_dict.Add(key); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key /// to the ConcurrentIntSet. /// public bool TryAdd(int key) { Monitor.Enter(this); try { return m_dict.TryAdd(key); } finally { Monitor.Exit(this); } } /// /// Add the supplied keys to the ConcurrentIntSet. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the ConcurrentIntSet contains the item with the supplied /// key. /// public bool Contains(int key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key /// from the ConcurrentIntSet. Returns true if the value was removed. /// public bool Remove(int key) { Monitor.Enter(this); try { return m_dict.TryRemove(key); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(int key) { Monitor.Enter(this); try { return m_dict.TryRemove(key); } finally { Monitor.Exit(this); } } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public int[] ToArray() { return m_dict.ToArray(); } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { m_dict.Clear(); } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(int[] array, int index) { Monitor.Enter(this); try { m_dict.CopyTo(array, index); } finally { Monitor.Exit(this); } } #endregion } #endregion #region ConcurrentSymbolDict /// /// A ConcurrentSymbolDict is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class ConcurrentSymbolDict { private readonly SymbolDict m_dict; #region Constructors /// /// A ConcurrentSymbolDict can only be concstructed by wrapping its non-concurrent /// counterpart. /// public ConcurrentSymbolDict(SymbolDict dict) { m_dict = dict; } #endregion #region Properties /// /// Returns the number of items currently contained in the ConcurrentSymbolDict. /// public int Count { get { return m_dict.Count; } } /// /// Returns the number of items currently contained in the ConcurrentSymbolDict /// as long. /// public long LongCount { get { return m_dict.LongCount; } } /// /// Returns the number of items currently contained in the ConcurrentSymbolDict /// as long. /// public uint Capacity { get { return m_dict.Capacity; } set { m_dict.Capacity = value; } } /// /// Return the non-concurrent contained ConcurrentSymbolDict. /// public SymbolDict NonConcurrent { get { return m_dict; } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the ConcurrentSymbolDict acts as a stack. /// /// /// public TValue this[Symbol key] { get { Monitor.Enter(this); try { return m_dict[key]; } finally { Monitor.Exit(this); } } set { Monitor.Enter(this); try { m_dict[key] = value; } finally { Monitor.Exit(this); } } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the ConcurrentSymbolDict. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the ConcurrentSymbolDict /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((Symbol)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentSymbolDict. /// public void Add(Symbol key, TValue value) { Monitor.Enter(this); try { m_dict.Add(key, value); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentSymbolDict. /// public bool TryAdd(Symbol key, TValue value) { Monitor.Enter(this); try { return m_dict.TryAdd(key, value); } finally { Monitor.Exit(this); } } /// /// Adds the supplied item to the ConcurrentSymbolDict. Note that this incurs the /// overhead of converting the string key to a symbol. /// public void Add(string key, TValue value) { Monitor.Enter(this); try { m_dict.Add(key.ToSymbol(), value); } finally { Monitor.Exit(this); } } /// /// Add the supplied item to the ConcurrentSymbolDict. Note that this incurs the /// overhead of converting the string key to a symbol. /// public void Add(KeyValuePair item) { Monitor.Enter(this); try { m_dict.Add(item.Key.ToSymbol(), item.Value); } finally { Monitor.Exit(this); } } /// /// Add the supplied item to the ConcurrentSymbolDict. /// public void Add(KeyValuePair item) { Monitor.Enter(this); try { m_dict.Add(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Add the supplied items to the ConcurrentSymbolDict. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the ConcurrentSymbolDict contains the item with the supplied /// key. /// public bool Contains(Symbol key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentSymbolDict contains the item with the supplied /// key. /// public bool ContainsKey(Symbol key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentSymbolDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(Symbol key, TValue value) { Monitor.Enter(this); try { return m_dict.Contains(key, value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentSymbolDict contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { Monitor.Enter(this); try { return m_dict.Contains(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentSymbolDict contains the given value. /// public bool ContainsValue(TValue value) { Monitor.Enter(this); try { return m_dict.ContainsValue(value); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(Symbol key) { Monitor.Enter(this); try { return m_dict.Get(key); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the ConcurrentSymbolDict and returned. /// public TValue GetOrCreate(Symbol key, Func creator) { Monitor.Enter(this); try { return m_dict.GetOrCreate(key, creator); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(Symbol key, TValue defaultValue) { Monitor.Enter(this); try { return m_dict.Get(key); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(Symbol key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(Symbol key, out TValue value) { Monitor.Enter(this); try { return m_dict.TryGetValue(key, out value); } finally { Monitor.Exit(this); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(Symbol key, int skip) { Monitor.Enter(this); try { return m_dict.ValueWithKeySkip(key, skip); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key from the ConcurrentSymbolDict and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(Symbol key) { Monitor.Enter(this); try { return m_dict.GetAndRemove(key); } finally { Monitor.Exit(this); } } /// /// Try to remove the item with the supplied key from the ConcurrentSymbolDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(Symbol key) { TValue value; Monitor.Enter(this); try { return m_dict.TryRemove(key, out value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key and the supplied value /// from the ConcurrentSymbolDict. Returns true if the value was removed. /// public bool Remove(Symbol key, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied KeyValuePair from the ConcurrentSymbolDict. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { Monitor.Enter(this); try { return m_dict.TryRemove(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(Symbol key, out TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, out value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(Symbol key, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, value); } finally { Monitor.Exit(this); } } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public Symbol[] KeysToArray() { return m_dict.KeysToArray(); } /// /// Returns all values in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TValue[] ValuesToArray() { return m_dict.ValuesToArray(); } /// /// Returns all KeyValuePairs in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public KeyValuePair[] ToArray() { return m_dict.ToArray(); } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { m_dict.Clear(); } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyKeysTo(Symbol[] array, int index) { Monitor.Enter(this); try { m_dict.CopyKeysTo(array, index); } finally { Monitor.Exit(this); } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyValuesTo(TValue[] array, int index) { Monitor.Enter(this); try { m_dict.CopyValuesTo(array, index); } finally { Monitor.Exit(this); } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(KeyValuePair[] array, int index) { Monitor.Enter(this); try { m_dict.CopyTo(array, index); } finally { Monitor.Exit(this); } } public void Add(TypedSymbol key, TType value) where TType : TValue { this.Add(key.Symbol, value); } public bool Contains(TypedSymbol key) where TType : TValue { return Contains(key.Symbol); } public bool ContainsKey(TypedSymbol key) where TType : TValue { return ContainsKey(key.Symbol); } public TType Get(TypedSymbol key) where TType : TValue { return (TType)this[key.Symbol]; } public TType Get(TypedSymbol key, TType defaultValue) where TType : TValue { TType value; if (TryGetValue(key, out value)) return value; return defaultValue; } public TType GetOrDefault(TypedSymbol key) where TType : TValue { TType value; if (TryGetValue(key, out value)) return value; return default(TType); } public bool Remove(TypedSymbol key) where TType : TValue { return Remove(key.Symbol); } public void Set(TypedSymbol key, TType value) where TType : TValue { this[key.Symbol] = value; } public bool TryGetValue(TypedSymbol key, out TType value) where TType : TValue { TValue val; if (TryGetValue(key.Symbol, out val)) { value = (TType)val; return true; } value = default(TType); return false; } public TType GetAs(Symbol key) where TType : TValue { return (TType)this[key]; } public TType GetAs(Symbol key, TType defaultValue) where TType : TValue { TValue value; if (TryGetValue(key, out value)) return (TType)value; return defaultValue; } public TType GetAsOrDefault(Symbol key) where TType : TValue { TValue value; if (TryGetValue(key, out value)) return (TType)value; return default(TType); } #endregion } #endregion #region ConcurrentSymbolSet /// /// A ConcurrentSymbolSet is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class ConcurrentSymbolSet { private readonly SymbolSet m_dict; #region Constructors /// /// A ConcurrentSymbolSet can only be concstructed by wrapping its non-concurrent /// counterpart. /// public ConcurrentSymbolSet(SymbolSet dict) { m_dict = dict; } #endregion #region Properties /// /// Returns the number of items currently contained in the ConcurrentSymbolSet. /// public int Count { get { return m_dict.Count; } } /// /// Returns the number of items currently contained in the ConcurrentSymbolSet /// as long. /// public long LongCount { get { return m_dict.LongCount; } } /// /// Returns the number of items currently contained in the ConcurrentSymbolSet /// as long. /// public uint Capacity { get { return m_dict.Capacity; } set { m_dict.Capacity = value; } } /// /// Return the non-concurrent contained ConcurrentSymbolSet. /// public SymbolSet NonConcurrent { get { return m_dict; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the ConcurrentSymbolSet. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the ConcurrentSymbolSet /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((Symbol)objkey); } /// /// Add the item with the supplied key /// to the ConcurrentSymbolSet. /// public bool Add(Symbol key) { Monitor.Enter(this); try { return m_dict.Add(key); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key /// to the ConcurrentSymbolSet. /// public bool TryAdd(Symbol key) { Monitor.Enter(this); try { return m_dict.TryAdd(key); } finally { Monitor.Exit(this); } } /// /// Adds the supplied item to the ConcurrentSymbolSet. Note that this incurs the /// overhead of converting the string key to a symbol. /// public void Add(string key) { Monitor.Enter(this); try { m_dict.Add(key.ToSymbol()); } finally { Monitor.Exit(this); } } /// /// Add the supplied keys to the ConcurrentSymbolSet. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the ConcurrentSymbolSet contains the item with the supplied /// key. /// public bool Contains(Symbol key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key /// from the ConcurrentSymbolSet. Returns true if the value was removed. /// public bool Remove(Symbol key) { Monitor.Enter(this); try { return m_dict.TryRemove(key); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(Symbol key) { Monitor.Enter(this); try { return m_dict.TryRemove(key); } finally { Monitor.Exit(this); } } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public Symbol[] ToArray() { return m_dict.ToArray(); } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { m_dict.Clear(); } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(Symbol[] array, int index) { Monitor.Enter(this); try { m_dict.CopyTo(array, index); } finally { Monitor.Exit(this); } } #endregion } #endregion #region ConcurrentBigDict /// /// A ConcurrentBigDict is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class ConcurrentBigDict { private readonly BigDict m_dict; #region Constructors /// /// A ConcurrentBigDict can only be concstructed by wrapping its non-concurrent /// counterpart. /// public ConcurrentBigDict(BigDict dict) { m_dict = dict; } #endregion #region Properties /// /// Returns the number of items currently contained in the ConcurrentBigDict /// as long. /// public long LongCount { get { return m_dict.LongCount; } } /// /// Returns the number of items currently contained in the ConcurrentBigDict /// as long. /// public ulong Capacity { get { return m_dict.Capacity; } set { m_dict.Capacity = value; } } /// /// Return the non-concurrent contained ConcurrentBigDict. /// public BigDict NonConcurrent { get { return m_dict; } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the ConcurrentBigDict acts as a stack. /// /// /// public TValue this[TKey key] { get { Monitor.Enter(this); try { return m_dict[key]; } finally { Monitor.Exit(this); } } set { Monitor.Enter(this); try { m_dict[key] = value; } finally { Monitor.Exit(this); } } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the ConcurrentBigDict. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the ConcurrentBigDict /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((TKey)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentBigDict. /// public void Add(TKey key, TValue value) { Monitor.Enter(this); try { m_dict.Add(key, value); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentBigDict. /// public void Add(TKey key, long hash, TValue value) { Monitor.Enter(this); try { m_dict.Add(key, hash, value); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentBigDict. /// public bool TryAdd(TKey key, TValue value) { Monitor.Enter(this); try { return m_dict.TryAdd(key, value); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentBigDict. /// public bool TryAdd(TKey key, long hash, TValue value) { Monitor.Enter(this); try { return m_dict.TryAdd(key, hash, value); } finally { Monitor.Exit(this); } } /// /// Add the supplied item to the ConcurrentBigDict. /// public void Add(KeyValuePair item) { Monitor.Enter(this); try { m_dict.Add(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Add the supplied items to the ConcurrentBigDict. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the ConcurrentBigDict contains the item with the supplied /// key. /// public bool Contains(TKey key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentBigDict contains the item with the supplied /// key. /// public bool Contains(TKey key, long hash) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentBigDict contains the item with the supplied /// key. /// public bool ContainsKey(TKey key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentBigDict contains the item with the supplied /// key. /// public bool ContainsKey(TKey key, long hash) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentBigDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, TValue value) { Monitor.Enter(this); try { return m_dict.Contains(key, value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentBigDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, long hash, TValue value) { Monitor.Enter(this); try { return m_dict.Contains(key, value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentBigDict contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { Monitor.Enter(this); try { return m_dict.Contains(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentBigDict contains the given value. /// public bool ContainsValue(TValue value) { Monitor.Enter(this); try { return m_dict.ContainsValue(value); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key) { Monitor.Enter(this); try { return m_dict.Get(key); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the ConcurrentBigDict and returned. /// public TValue GetOrCreate(TKey key, Func creator) { Monitor.Enter(this); try { return m_dict.GetOrCreate(key, creator); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, TValue defaultValue) { Monitor.Enter(this); try { return m_dict.Get(key); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key, long hash) { Monitor.Enter(this); try { return m_dict.Get(key, hash); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the ConcurrentBigDict and returned. /// public TValue GetOrCreate(TKey key, long hash, Func creator) { Monitor.Enter(this); try { return m_dict.GetOrCreate(key, hash, creator); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, long hash, TValue defaultValue) { Monitor.Enter(this); try { return m_dict.Get(key, hash); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(TKey key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, out TValue value) { Monitor.Enter(this); try { return m_dict.TryGetValue(key, out value); } finally { Monitor.Exit(this); } } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, long hash, out TValue value) { Monitor.Enter(this); try { return m_dict.TryGetValue(key, hash, out value); } finally { Monitor.Exit(this); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(TKey key, long skip) { Monitor.Enter(this); try { return m_dict.ValueWithKeySkip(key, skip); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key from the ConcurrentBigDict and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(TKey key) { Monitor.Enter(this); try { return m_dict.GetAndRemove(key); } finally { Monitor.Exit(this); } } /// /// Try to remove the item with the supplied key from the ConcurrentBigDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key) { TValue value; Monitor.Enter(this); try { return m_dict.TryRemove(key, out value); } finally { Monitor.Exit(this); } } /// /// Try to remove the item with the supplied key from the ConcurrentBigDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key, long hash) { TValue value; Monitor.Enter(this); try { return m_dict.TryRemove(key, hash, out value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key and the supplied value /// from the ConcurrentBigDict. Returns true if the value was removed. /// public bool Remove(TKey key, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key and the supplied value /// from the ConcurrentBigDict. Returns true if the value was removed. /// public bool Remove(TKey key, long hash, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash, value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied KeyValuePair from the ConcurrentBigDict. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { Monitor.Enter(this); try { return m_dict.TryRemove(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, out TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, out value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, long hash, out TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash, out value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, long hash, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash, value); } finally { Monitor.Exit(this); } } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TKey[] KeysToArray() { return m_dict.KeysToArray(); } /// /// Returns all values in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TValue[] ValuesToArray() { return m_dict.ValuesToArray(); } /// /// Returns all KeyValuePairs in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public KeyValuePair[] ToArray() { return m_dict.ToArray(); } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { m_dict.Clear(); } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyKeysTo(TKey[] array, long index) { Monitor.Enter(this); try { m_dict.CopyKeysTo(array, index); } finally { Monitor.Exit(this); } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyValuesTo(TValue[] array, long index) { Monitor.Enter(this); try { m_dict.CopyValuesTo(array, index); } finally { Monitor.Exit(this); } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(KeyValuePair[] array, long index) { Monitor.Enter(this); try { m_dict.CopyTo(array, index); } finally { Monitor.Exit(this); } } #endregion } #endregion #region ConcurrentBigDictSet /// /// A ConcurrentBigDictSet is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class ConcurrentBigDictSet { private readonly BigDictSet m_dict; #region Constructors /// /// A ConcurrentBigDictSet can only be concstructed by wrapping its non-concurrent /// counterpart. /// public ConcurrentBigDictSet(BigDictSet dict) { m_dict = dict; } #endregion #region Properties /// /// Returns the number of items currently contained in the ConcurrentBigDictSet /// as long. /// public long LongCount { get { return m_dict.LongCount; } } /// /// Returns the number of items currently contained in the ConcurrentBigDictSet /// as long. /// public ulong Capacity { get { return m_dict.Capacity; } set { m_dict.Capacity = value; } } /// /// Return the non-concurrent contained ConcurrentBigDictSet. /// public BigDictSet NonConcurrent { get { return m_dict; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the ConcurrentBigDictSet. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the ConcurrentBigDictSet /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((TKey)objkey); } /// /// Add the item with the supplied key /// to the ConcurrentBigDictSet. /// public bool Add(TKey key) { Monitor.Enter(this); try { return m_dict.Add(key); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key /// to the ConcurrentBigDictSet. /// public bool Add(TKey key, long hash) { Monitor.Enter(this); try { return m_dict.Add(key, hash); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key /// to the ConcurrentBigDictSet. /// public bool TryAdd(TKey key) { Monitor.Enter(this); try { return m_dict.TryAdd(key); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key /// to the ConcurrentBigDictSet. /// public bool TryAdd(TKey key, long hash) { Monitor.Enter(this); try { return m_dict.TryAdd(key, hash); } finally { Monitor.Exit(this); } } /// /// Add the supplied keys to the ConcurrentBigDictSet. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the ConcurrentBigDictSet contains the item with the supplied /// key. /// public bool Contains(TKey key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentBigDictSet contains the item with the supplied /// key. /// public bool Contains(TKey key, long hash) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key /// from the ConcurrentBigDictSet. Returns true if the value was removed. /// public bool Remove(TKey key) { Monitor.Enter(this); try { return m_dict.TryRemove(key); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key /// from the ConcurrentBigDictSet. Returns true if the value was removed. /// public bool Remove(TKey key, long hash) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key) { Monitor.Enter(this); try { return m_dict.TryRemove(key); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key, long hash) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash); } finally { Monitor.Exit(this); } } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TKey[] ToArray() { return m_dict.ToArray(); } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { m_dict.Clear(); } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(TKey[] array, long index) { Monitor.Enter(this); try { m_dict.CopyTo(array, index); } finally { Monitor.Exit(this); } } #endregion } #endregion #region ConcurrentLongDict /// /// A ConcurrentLongDict is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class ConcurrentLongDict { private readonly LongDict m_dict; #region Constructors /// /// A ConcurrentLongDict can only be concstructed by wrapping its non-concurrent /// counterpart. /// public ConcurrentLongDict(LongDict dict) { m_dict = dict; } #endregion #region Properties /// /// Returns the number of items currently contained in the ConcurrentLongDict /// as long. /// public long LongCount { get { return m_dict.LongCount; } } /// /// Returns the number of items currently contained in the ConcurrentLongDict /// as long. /// public ulong Capacity { get { return m_dict.Capacity; } set { m_dict.Capacity = value; } } /// /// Return the non-concurrent contained ConcurrentLongDict. /// public LongDict NonConcurrent { get { return m_dict; } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the ConcurrentLongDict acts as a stack. /// /// /// public TValue this[long key] { get { Monitor.Enter(this); try { return m_dict[key]; } finally { Monitor.Exit(this); } } set { Monitor.Enter(this); try { m_dict[key] = value; } finally { Monitor.Exit(this); } } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the ConcurrentLongDict. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the ConcurrentLongDict /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((long)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentLongDict. /// public void Add(long key, TValue value) { Monitor.Enter(this); try { m_dict.Add(key, value); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentLongDict. /// public bool TryAdd(long key, TValue value) { Monitor.Enter(this); try { return m_dict.TryAdd(key, value); } finally { Monitor.Exit(this); } } /// /// Add the supplied item to the ConcurrentLongDict. /// public void Add(KeyValuePair item) { Monitor.Enter(this); try { m_dict.Add(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Add the supplied items to the ConcurrentLongDict. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the ConcurrentLongDict contains the item with the supplied /// key. /// public bool Contains(long key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentLongDict contains the item with the supplied /// key. /// public bool ContainsKey(long key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentLongDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(long key, TValue value) { Monitor.Enter(this); try { return m_dict.Contains(key, value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentLongDict contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { Monitor.Enter(this); try { return m_dict.Contains(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentLongDict contains the given value. /// public bool ContainsValue(TValue value) { Monitor.Enter(this); try { return m_dict.ContainsValue(value); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(long key) { Monitor.Enter(this); try { return m_dict.Get(key); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the ConcurrentLongDict and returned. /// public TValue GetOrCreate(long key, Func creator) { Monitor.Enter(this); try { return m_dict.GetOrCreate(key, creator); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(long key, TValue defaultValue) { Monitor.Enter(this); try { return m_dict.Get(key); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(long key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(long key, out TValue value) { Monitor.Enter(this); try { return m_dict.TryGetValue(key, out value); } finally { Monitor.Exit(this); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(long key, long skip) { Monitor.Enter(this); try { return m_dict.ValueWithKeySkip(key, skip); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key from the ConcurrentLongDict and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(long key) { Monitor.Enter(this); try { return m_dict.GetAndRemove(key); } finally { Monitor.Exit(this); } } /// /// Try to remove the item with the supplied key from the ConcurrentLongDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(long key) { TValue value; Monitor.Enter(this); try { return m_dict.TryRemove(key, out value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key and the supplied value /// from the ConcurrentLongDict. Returns true if the value was removed. /// public bool Remove(long key, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied KeyValuePair from the ConcurrentLongDict. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { Monitor.Enter(this); try { return m_dict.TryRemove(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(long key, out TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, out value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(long key, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, value); } finally { Monitor.Exit(this); } } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public long[] KeysToArray() { return m_dict.KeysToArray(); } /// /// Returns all values in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TValue[] ValuesToArray() { return m_dict.ValuesToArray(); } /// /// Returns all KeyValuePairs in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public KeyValuePair[] ToArray() { return m_dict.ToArray(); } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { m_dict.Clear(); } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyKeysTo(long[] array, long index) { Monitor.Enter(this); try { m_dict.CopyKeysTo(array, index); } finally { Monitor.Exit(this); } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyValuesTo(TValue[] array, long index) { Monitor.Enter(this); try { m_dict.CopyValuesTo(array, index); } finally { Monitor.Exit(this); } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(KeyValuePair[] array, long index) { Monitor.Enter(this); try { m_dict.CopyTo(array, index); } finally { Monitor.Exit(this); } } #endregion } #endregion #region ConcurrentLongSet /// /// A ConcurrentLongSet is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class ConcurrentLongSet { private readonly LongSet m_dict; #region Constructors /// /// A ConcurrentLongSet can only be concstructed by wrapping its non-concurrent /// counterpart. /// public ConcurrentLongSet(LongSet dict) { m_dict = dict; } #endregion #region Properties /// /// Returns the number of items currently contained in the ConcurrentLongSet /// as long. /// public long LongCount { get { return m_dict.LongCount; } } /// /// Returns the number of items currently contained in the ConcurrentLongSet /// as long. /// public ulong Capacity { get { return m_dict.Capacity; } set { m_dict.Capacity = value; } } /// /// Return the non-concurrent contained ConcurrentLongSet. /// public LongSet NonConcurrent { get { return m_dict; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the ConcurrentLongSet. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the ConcurrentLongSet /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((long)objkey); } /// /// Add the item with the supplied key /// to the ConcurrentLongSet. /// public bool Add(long key) { Monitor.Enter(this); try { return m_dict.Add(key); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key /// to the ConcurrentLongSet. /// public bool TryAdd(long key) { Monitor.Enter(this); try { return m_dict.TryAdd(key); } finally { Monitor.Exit(this); } } /// /// Add the supplied keys to the ConcurrentLongSet. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the ConcurrentLongSet contains the item with the supplied /// key. /// public bool Contains(long key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key /// from the ConcurrentLongSet. Returns true if the value was removed. /// public bool Remove(long key) { Monitor.Enter(this); try { return m_dict.TryRemove(key); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(long key) { Monitor.Enter(this); try { return m_dict.TryRemove(key); } finally { Monitor.Exit(this); } } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public long[] ToArray() { return m_dict.ToArray(); } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { m_dict.Clear(); } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(long[] array, long index) { Monitor.Enter(this); try { m_dict.CopyTo(array, index); } finally { Monitor.Exit(this); } } #endregion } #endregion #region FastConcurrentDict /// /// A FastConcurrentDict is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class FastConcurrentDict : IIntCountable, ICountableDict, IDict, IEnumerable, IEnumerable> { private long m_version; private uint m_capacity; private NextHashKeyValue[] m_firstArray; private HashKeyValueNext[] m_extraArray; private uint m_count; private uint m_increaseThreshold; private uint m_decreaseThreshold; private readonly bool m_doNotStackDuplicateKeys; private int m_freeIndex; private int m_capacityIndex; private uint m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a FastConcurrentDict that autmatically grows and shrinks as necessary. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentDict acts as a stack for all items with the same key. /// public FastConcurrentDict(bool stackDuplicateKeys = false) : this(DictConstant.PrimeSizes[0], (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a FastConcurrentDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentDict acts as a stack for all items with the same key. /// public FastConcurrentDict(int initialCapacity) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, false) { } /// /// Create a FastConcurrentDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentDict acts as a stack for all items with the same key. /// public FastConcurrentDict(int initialCapacity, bool stackDuplicateKeys) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a FastConcurrentDict and initialize it to contain the supplied /// items. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentDict acts as a stack for all items with the same key. /// public FastConcurrentDict(IEnumerable> items, bool stackDuplicateKeys = false) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { foreach (var item in items) Add(item); } private FastConcurrentDict( uint firstCapacity, uint extraCapacity, bool stackDuplicateKeys = false) { m_version = 0; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_doNotStackDuplicateKeys = !stackDuplicateKeys; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextHashKeyValue[m_capacity]; m_extraArray = new HashKeyValueNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the FastConcurrentDict. /// public int Count { get { return (int)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentDict /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentDict /// as long. /// public uint Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { Monitor.Enter(this); try { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the FastConcurrentDict. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { Monitor.Enter(this); try { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } public IEnumerable> Items { get { return KeyValuePairs; } } /// /// Returns all keys in the dictionary. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Keys { get { Monitor.Enter(this); try { var version = m_version; for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var k = m_firstArray[fi].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { k = m_extraArray[ei].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type KeyType { get { return typeof(TKey); } } /// /// Returns all values in the FastConcurrentDict. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Values { get { Monitor.Enter(this); try { var version = m_version; for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var v = m_firstArray[fi].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { v = m_extraArray[ei].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type ValueType { get { return typeof(TValue); } } /// /// Returns all key value pairs in the FastConcurrentDict. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable> KeyValuePairs { get { Monitor.Enter(this); try { var version = m_version; for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var kvp = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { kvp = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } /// /// Returns all key value pairs in the FastConcurrentDict, in such a way, /// that the stack order is correct when the pairs are put into a /// new FastConcurrentDict in the order they are returned. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable> KeyValuePairsForStorage { get { Monitor.Enter(this); try { var version = m_version; var stack = new Stack(); for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; while (ei > 0) { stack.Push(ei); ei = m_extraArray[ei].Next; } var kvp = default(KeyValuePair); while (stack.Count > 0) { ei = stack.Pop(); kvp = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } kvp = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } } finally { Monitor.Exit(this); } } } public IEnumerable<(object, object)> ObjectPairs { get { foreach (var kvp in KeyValuePairsForStorage) yield return (kvp.Key, kvp.Value); } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the FastConcurrentDict acts as a stack. /// /// /// public TValue this[TKey key] { get { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } set { var hash = key.GetHashCode(); Monitor.Enter(this); try { ++m_version; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { m_firstArray[fi].Item.Value = value; return; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_extraArray[ei].Item.Value = value; return; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the FastConcurrentDict. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the FastConcurrentDict /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((TKey)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentDict. /// public void Add(TKey key, TValue value) { var hash = key.GetHashCode(); Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentDict. /// public void Add(TKey key, int hash, TValue value) { Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentDict. /// public bool TryAdd(TKey key, TValue value) { var hash = key.GetHashCode(); Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentDict. /// public bool TryAdd(TKey key, int hash, TValue value) { Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } return true; } /// /// Add the supplied item to the FastConcurrentDict. /// public void Add(KeyValuePair item) { Add(item.Key, item.Value); } /// /// Add the supplied items to the FastConcurrentDict. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the FastConcurrentDict contains the item with the supplied /// key. /// public bool Contains(TKey key) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentDict contains the item with the supplied /// key. /// public bool Contains(TKey key, int hash) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentDict contains the item with the supplied /// key. /// public bool ContainsKey(TKey key) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentDict contains the item with the supplied /// key. /// public bool ContainsKey(TKey key, int hash) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, TValue value) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, int hash, TValue value) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentDict contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { return Contains(item.Key, item.Value); } /// /// Returns true if the FastConcurrentDict contains the given value. /// public bool ContainsValue(TValue value) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } return false; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the FastConcurrentDict and returned. /// public TValue GetOrCreate(TKey key, Func creator) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } finally { Monitor.Exit(this); } } TValue AddCreated(TKey key, int hash, TValue value) { while (true) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ei = m_firstArray[fi].Next; ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = m_firstArray[fi].Next; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, TValue defaultValue) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key, int hash) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the FastConcurrentDict and returned. /// public TValue GetOrCreate(TKey key, int hash, Func creator) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, int hash, TValue defaultValue) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(TKey key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, out TValue value) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, int hash, out TValue value) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Return all the value with the given key. This method is only /// useful if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// public IEnumerable ValuesWithKey(TKey key) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var version = m_version; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) yield break; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { var v = m_firstArray[fi].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { var v = m_extraArray[ei].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(TKey key, int skip) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (skip == 0) return m_firstArray[fi].Item.Value; --skip; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { if (skip == 0) return m_extraArray[ei].Item.Value; --skip; } ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Remove the item with the supplied key from the FastConcurrentDict and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(TKey key) { TValue value; if (!TryRemove(key, out value)) throw new KeyNotFoundException(); return value; } /// /// Try to remove the item with the supplied key from the FastConcurrentDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key) { TValue value; return TryRemove(key, out value); } /// /// Try to remove the item with the supplied key from the FastConcurrentDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key, int hash) { TValue value; return TryRemove(key, hash, out value); } /// /// Remove the item with the supplied key and the supplied value /// from the FastConcurrentDict. Returns true if the value was removed. /// public bool Remove(TKey key, TValue value) { return TryRemove(key, value); } /// /// Remove the item with the supplied key and the supplied value /// from the FastConcurrentDict. Returns true if the value was removed. /// public bool Remove(TKey key, int hash, TValue value) { return TryRemove(key, hash, value); } /// /// Remove the item with the supplied KeyValuePair from the FastConcurrentDict. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { return TryRemove(item.Key, item.Value); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, out TValue value) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, int hash, out TValue value) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, TValue value) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key) && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, int hash, TValue value) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key) && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TKey[] KeysToArray() { var array = new TKey[m_count]; CopyKeysTo(array, 0); return array; } /// /// Returns all values in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TValue[] ValuesToArray() { var array = new TValue[m_count]; CopyValuesTo(array, 0); return array; } /// /// Returns all KeyValuePairs in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public KeyValuePair[] ToArray() { var array = new KeyValuePair[m_count]; CopyTo(array, 0); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { ++m_version; m_firstArray.Set(default(NextHashKeyValue)); m_extraArray.Set(default(HashKeyValueNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyKeysTo(TKey[] array, int index) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyValuesTo(TValue[] array, int index) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Value; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(KeyValuePair[] array, int index) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { array[index++] = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } #endregion #region IEnumerable> Members IEnumerator> IEnumerable>.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region Private Helper Methods private uint ComputeIncreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_maxFillFactor); } private uint ComputeDecreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_minFillFactor); } private static int AddSlotsToFreeList( HashKeyValueNext[] extraArray, int start) { var length = extraArray.Length - 1; for (int i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( HashKeyValue item, NextHashKeyValue[] firstArray, uint capacity, ref HashKeyValueNext[] extraArray, ref int freeIndex, ref uint extraCount) { var fi = ((uint)item.Hash) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(uint newCapacity, uint oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextHashKeyValue[newCapacity]; var extraArray = new HashKeyValueNext[ System.Math.Max((int)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); uint newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { uint fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((uint)m_count - m_extraCount, oldCapacity, m_extraCount, (uint)m_extraArray.Length, (uint)m_count - newExtraCount, newCapacity, newExtraCount, (uint)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( uint oldFirstCount, uint oldCapacity, uint oldExtraCount, uint oldExtraCapacity, uint newFirstCount, uint newCapacity, uint newExtraCount, uint newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region FastConcurrentDictSet /// /// A FastConcurrentDictSet is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class FastConcurrentDictSet : IIntCountable, ICountableDictSet, IDictSet, IEnumerable, IEnumerable { private long m_version; private uint m_capacity; private NextHashKey[] m_firstArray; private HashKeyNext[] m_extraArray; private uint m_count; private uint m_increaseThreshold; private uint m_decreaseThreshold; private int m_freeIndex; private int m_capacityIndex; private uint m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a FastConcurrentDictSet that autmatically grows and shrinks as necessary. /// public FastConcurrentDictSet() : this(DictConstant.PrimeSizes[0], (uint)DictConstant.MinExtraCapacity) { } /// /// Create a FastConcurrentDictSet that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// public FastConcurrentDictSet(int initialCapacity) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity) { } /// /// Create a FastConcurrentDictSet and initialize it to contain the supplied /// items. /// public FastConcurrentDictSet(IEnumerable items) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity) { foreach (var item in items) Add(item); } private FastConcurrentDictSet( uint firstCapacity, uint extraCapacity) { m_version = 0; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextHashKey[m_capacity]; m_extraArray = new HashKeyNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the FastConcurrentDictSet. /// public int Count { get { return (int)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentDictSet /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentDictSet /// as long. /// public uint Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { Monitor.Enter(this); try { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the FastConcurrentDictSet. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { Monitor.Enter(this); try { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } public IEnumerable Items { get { return Keys; } } /// /// Returns all keys in the dictionary. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Keys { get { Monitor.Enter(this); try { var version = m_version; for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var k = m_firstArray[fi].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { k = m_extraArray[ei].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type KeyType { get { return typeof(TKey); } } public IEnumerable Objects { get { foreach (object obj in Keys) yield return obj; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the FastConcurrentDictSet. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the FastConcurrentDictSet /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((TKey)objkey); } /// /// Add the item with the supplied key /// to the FastConcurrentDictSet. /// public bool Add(TKey key) { var hash = key.GetHashCode(); Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key /// to the FastConcurrentDictSet. /// public bool Add(TKey key, int hash) { Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key /// to the FastConcurrentDictSet. /// public bool TryAdd(TKey key) { var hash = key.GetHashCode(); Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key /// to the FastConcurrentDictSet. /// public bool TryAdd(TKey key, int hash) { Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the supplied keys to the FastConcurrentDictSet. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the FastConcurrentDictSet contains the item with the supplied /// key. /// public bool Contains(TKey key) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentDictSet contains the item with the supplied /// key. /// public bool Contains(TKey key, int hash) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Remove the item with the supplied key /// from the FastConcurrentDictSet. Returns true if the value was removed. /// public bool Remove(TKey key) { return TryRemove(key); } /// /// Remove the item with the supplied key /// from the FastConcurrentDictSet. Returns true if the value was removed. /// public bool Remove(TKey key, int hash) { return TryRemove(key, hash); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKey); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKey); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKey); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKey); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key, int hash) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKey); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKey); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKey); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKey); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TKey[] ToArray() { var array = new TKey[m_count]; CopyTo(array, 0); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { ++m_version; m_firstArray.Set(default(NextHashKey)); m_extraArray.Set(default(HashKeyNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(TKey[] array, int index) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return Keys.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return Keys.GetEnumerator(); } #endregion #region Private Helper Methods private uint ComputeIncreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_maxFillFactor); } private uint ComputeDecreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_minFillFactor); } private static int AddSlotsToFreeList( HashKeyNext[] extraArray, int start) { var length = extraArray.Length - 1; for (int i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( HashKey item, NextHashKey[] firstArray, uint capacity, ref HashKeyNext[] extraArray, ref int freeIndex, ref uint extraCount) { var fi = ((uint)item.Hash) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(uint newCapacity, uint oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextHashKey[newCapacity]; var extraArray = new HashKeyNext[ System.Math.Max((int)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); uint newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { uint fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((uint)m_count - m_extraCount, oldCapacity, m_extraCount, (uint)m_extraArray.Length, (uint)m_count - newExtraCount, newCapacity, newExtraCount, (uint)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( uint oldFirstCount, uint oldCapacity, uint oldExtraCount, uint oldExtraCapacity, uint newFirstCount, uint newCapacity, uint newExtraCount, uint newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region FastConcurrentIntDict /// /// A FastConcurrentIntDict is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class FastConcurrentIntDict : IIntCountable, ICountableDict, IDict, IEnumerable, IEnumerable> { private long m_version; private uint m_capacity; private NextIntValue[] m_firstArray; private IntValueNext[] m_extraArray; private uint m_count; private uint m_increaseThreshold; private uint m_decreaseThreshold; private readonly bool m_doNotStackDuplicateKeys; private int m_freeIndex; private int m_capacityIndex; private uint m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a FastConcurrentIntDict that autmatically grows and shrinks as necessary. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentIntDict acts as a stack for all items with the same key. /// public FastConcurrentIntDict(bool stackDuplicateKeys = false) : this(DictConstant.PrimeSizes[0], (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a FastConcurrentIntDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentIntDict acts as a stack for all items with the same key. /// public FastConcurrentIntDict(int initialCapacity) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, false) { } /// /// Create a FastConcurrentIntDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentIntDict acts as a stack for all items with the same key. /// public FastConcurrentIntDict(int initialCapacity, bool stackDuplicateKeys) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a FastConcurrentIntDict and initialize it to contain the supplied /// items. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentIntDict acts as a stack for all items with the same key. /// public FastConcurrentIntDict(IEnumerable> items, bool stackDuplicateKeys = false) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { foreach (var item in items) Add(item); } private FastConcurrentIntDict( uint firstCapacity, uint extraCapacity, bool stackDuplicateKeys = false) { m_version = 0; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_doNotStackDuplicateKeys = !stackDuplicateKeys; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextIntValue[m_capacity]; m_extraArray = new IntValueNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the FastConcurrentIntDict. /// public int Count { get { return (int)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentIntDict /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentIntDict /// as long. /// public uint Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { Monitor.Enter(this); try { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the FastConcurrentIntDict. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { Monitor.Enter(this); try { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } public IEnumerable> Items { get { return KeyValuePairs; } } /// /// Returns all keys in the dictionary. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Keys { get { Monitor.Enter(this); try { var version = m_version; for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var k = m_firstArray[fi].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { k = m_extraArray[ei].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type KeyType { get { return typeof(int); } } /// /// Returns all values in the FastConcurrentIntDict. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Values { get { Monitor.Enter(this); try { var version = m_version; for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var v = m_firstArray[fi].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { v = m_extraArray[ei].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type ValueType { get { return typeof(TValue); } } /// /// Returns all key value pairs in the FastConcurrentIntDict. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable> KeyValuePairs { get { Monitor.Enter(this); try { var version = m_version; for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var kvp = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { kvp = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } /// /// Returns all key value pairs in the FastConcurrentIntDict, in such a way, /// that the stack order is correct when the pairs are put into a /// new FastConcurrentIntDict in the order they are returned. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable> KeyValuePairsForStorage { get { Monitor.Enter(this); try { var version = m_version; var stack = new Stack(); for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; while (ei > 0) { stack.Push(ei); ei = m_extraArray[ei].Next; } var kvp = default(KeyValuePair); while (stack.Count > 0) { ei = stack.Pop(); kvp = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } kvp = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } } finally { Monitor.Exit(this); } } } public IEnumerable<(object, object)> ObjectPairs { get { foreach (var kvp in KeyValuePairsForStorage) yield return (kvp.Key, kvp.Value); } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the FastConcurrentIntDict acts as a stack. /// /// /// public TValue this[int key] { get { var hash = key; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } set { var hash = key; Monitor.Enter(this); try { ++m_version; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { if (m_firstArray[fi].Item.Key == hash) { m_firstArray[fi].Item.Value = value; return; } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { m_extraArray[ei].Item.Value = value; return; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the FastConcurrentIntDict. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the FastConcurrentIntDict /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((int)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentIntDict. /// public void Add(int key, TValue value) { var hash = key; Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Key == hash) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentIntDict. /// public bool TryAdd(int key, TValue value) { var hash = key; Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Key == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } return true; } /// /// Add the supplied item to the FastConcurrentIntDict. /// public void Add(KeyValuePair item) { Add(item.Key, item.Value); } /// /// Add the supplied items to the FastConcurrentIntDict. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the FastConcurrentIntDict contains the item with the supplied /// key. /// public bool Contains(int key) { var hash = key; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentIntDict contains the item with the supplied /// key. /// public bool ContainsKey(int key) { var hash = key; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentIntDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(int key, TValue value) { var hash = key; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key == hash && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentIntDict contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { return Contains(item.Key, item.Value); } /// /// Returns true if the FastConcurrentIntDict contains the given value. /// public bool ContainsValue(TValue value) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } return false; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(int key) { var hash = key; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the FastConcurrentIntDict and returned. /// public TValue GetOrCreate(int key, Func creator) { var hash = key; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } finally { Monitor.Exit(this); } } TValue AddCreated(int key, int hash, TValue value) { while (true) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ei = m_firstArray[fi].Next; ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = m_firstArray[fi].Next; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(int key, TValue defaultValue) { var hash = key; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(int key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(int key, out TValue value) { var hash = key; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Key == hash) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Return all the value with the given key. This method is only /// useful if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// public IEnumerable ValuesWithKey(int key) { var hash = key; Monitor.Enter(this); try { var version = m_version; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) yield break; if (m_firstArray[fi].Item.Key == hash) { var v = m_firstArray[fi].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { var v = m_extraArray[ei].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(int key, int skip) { var hash = key; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key == hash) { if (skip == 0) return m_firstArray[fi].Item.Value; --skip; } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { if (skip == 0) return m_extraArray[ei].Item.Value; --skip; } ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Remove the item with the supplied key from the FastConcurrentIntDict and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(int key) { TValue value; if (!TryRemove(key, out value)) throw new KeyNotFoundException(); return value; } /// /// Try to remove the item with the supplied key from the FastConcurrentIntDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(int key) { TValue value; return TryRemove(key, out value); } /// /// Remove the item with the supplied key and the supplied value /// from the FastConcurrentIntDict. Returns true if the value was removed. /// public bool Remove(int key, TValue value) { return TryRemove(key, value); } /// /// Remove the item with the supplied KeyValuePair from the FastConcurrentIntDict. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { return TryRemove(item.Key, item.Value); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(int key, out TValue value) { var hash = key; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Key == hash) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(IntValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(IntValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(IntValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Key == hash) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(IntValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(int key, TValue value) { var hash = key; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key == hash && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(IntValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(IntValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Key == hash && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(IntValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Key == hash && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(IntValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public int[] KeysToArray() { var array = new int[m_count]; CopyKeysTo(array, 0); return array; } /// /// Returns all values in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TValue[] ValuesToArray() { var array = new TValue[m_count]; CopyValuesTo(array, 0); return array; } /// /// Returns all KeyValuePairs in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public KeyValuePair[] ToArray() { var array = new KeyValuePair[m_count]; CopyTo(array, 0); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { ++m_version; m_firstArray.Set(default(NextIntValue)); m_extraArray.Set(default(IntValueNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyKeysTo(int[] array, int index) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyValuesTo(TValue[] array, int index) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Value; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(KeyValuePair[] array, int index) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { array[index++] = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } #endregion #region IEnumerable> Members IEnumerator> IEnumerable>.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region Private Helper Methods private uint ComputeIncreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_maxFillFactor); } private uint ComputeDecreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_minFillFactor); } private static int AddSlotsToFreeList( IntValueNext[] extraArray, int start) { var length = extraArray.Length - 1; for (int i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( IntValue item, NextIntValue[] firstArray, uint capacity, ref IntValueNext[] extraArray, ref int freeIndex, ref uint extraCount) { var fi = ((uint)item.Key) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(uint newCapacity, uint oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextIntValue[newCapacity]; var extraArray = new IntValueNext[ System.Math.Max((int)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); uint newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { uint fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((uint)m_count - m_extraCount, oldCapacity, m_extraCount, (uint)m_extraArray.Length, (uint)m_count - newExtraCount, newCapacity, newExtraCount, (uint)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( uint oldFirstCount, uint oldCapacity, uint oldExtraCount, uint oldExtraCapacity, uint newFirstCount, uint newCapacity, uint newExtraCount, uint newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region FastConcurrentIntSet /// /// A FastConcurrentIntSet is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class FastConcurrentIntSet : IIntCountable, ICountableDictSet, IDictSet, IEnumerable, IEnumerable { private long m_version; private uint m_capacity; private NextInt[] m_firstArray; private IntNext[] m_extraArray; private uint m_count; private uint m_increaseThreshold; private uint m_decreaseThreshold; private int m_freeIndex; private int m_capacityIndex; private uint m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a FastConcurrentIntSet that autmatically grows and shrinks as necessary. /// public FastConcurrentIntSet() : this(DictConstant.PrimeSizes[0], (uint)DictConstant.MinExtraCapacity) { } /// /// Create a FastConcurrentIntSet that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// public FastConcurrentIntSet(int initialCapacity) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity) { } /// /// Create a FastConcurrentIntSet and initialize it to contain the supplied /// items. /// public FastConcurrentIntSet(IEnumerable items) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity) { foreach (var item in items) Add(item); } private FastConcurrentIntSet( uint firstCapacity, uint extraCapacity) { m_version = 0; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextInt[m_capacity]; m_extraArray = new IntNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the FastConcurrentIntSet. /// public int Count { get { return (int)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentIntSet /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentIntSet /// as long. /// public uint Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { Monitor.Enter(this); try { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the FastConcurrentIntSet. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { Monitor.Enter(this); try { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } public IEnumerable Items { get { return Keys; } } /// /// Returns all keys in the dictionary. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Keys { get { Monitor.Enter(this); try { var version = m_version; for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var k = m_firstArray[fi].Item; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { k = m_extraArray[ei].Item; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type KeyType { get { return typeof(int); } } public IEnumerable Objects { get { foreach (object obj in Keys) yield return obj; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the FastConcurrentIntSet. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the FastConcurrentIntSet /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((int)objkey); } /// /// Add the item with the supplied key /// to the FastConcurrentIntSet. /// public bool Add(int key) { var hash = key; Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key /// to the FastConcurrentIntSet. /// public bool TryAdd(int key) { var hash = key; Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the supplied keys to the FastConcurrentIntSet. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the FastConcurrentIntSet contains the item with the supplied /// key. /// public bool Contains(int key) { var hash = key; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item == hash) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Remove the item with the supplied key /// from the FastConcurrentIntSet. Returns true if the value was removed. /// public bool Remove(int key) { return TryRemove(key); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(int key) { var hash = key; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item == hash) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(int); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(int); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item == hash) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(int); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item == hash) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(int); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public int[] ToArray() { var array = new int[m_count]; CopyTo(array, 0); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { ++m_version; m_firstArray.Set(default(NextInt)); m_extraArray.Set(default(IntNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(int[] array, int index) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item; while (ei > 0) { array[index++] = m_extraArray[ei].Item; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return Keys.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return Keys.GetEnumerator(); } #endregion #region Private Helper Methods private uint ComputeIncreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_maxFillFactor); } private uint ComputeDecreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_minFillFactor); } private static int AddSlotsToFreeList( IntNext[] extraArray, int start) { var length = extraArray.Length - 1; for (int i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( int item, NextInt[] firstArray, uint capacity, ref IntNext[] extraArray, ref int freeIndex, ref uint extraCount) { var fi = ((uint)item) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(uint newCapacity, uint oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextInt[newCapacity]; var extraArray = new IntNext[ System.Math.Max((int)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); uint newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { uint fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((uint)m_count - m_extraCount, oldCapacity, m_extraCount, (uint)m_extraArray.Length, (uint)m_count - newExtraCount, newCapacity, newExtraCount, (uint)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( uint oldFirstCount, uint oldCapacity, uint oldExtraCount, uint oldExtraCapacity, uint newFirstCount, uint newCapacity, uint newExtraCount, uint newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region FastConcurrentSymbolDict /// /// A FastConcurrentSymbolDict is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class FastConcurrentSymbolDict : IIntCountable, ICountableDict, IDict, IEnumerable, IEnumerable> { private long m_version; private uint m_capacity; private NextSymbolValue[] m_firstArray; private SymbolValueNext[] m_extraArray; private uint m_count; private uint m_increaseThreshold; private uint m_decreaseThreshold; private readonly bool m_doNotStackDuplicateKeys; private int m_freeIndex; private int m_capacityIndex; private uint m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a FastConcurrentSymbolDict that autmatically grows and shrinks as necessary. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentSymbolDict acts as a stack for all items with the same key. /// public FastConcurrentSymbolDict(bool stackDuplicateKeys = false) : this(DictConstant.PrimeSizes[0], (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a FastConcurrentSymbolDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentSymbolDict acts as a stack for all items with the same key. /// public FastConcurrentSymbolDict(int initialCapacity) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, false) { } /// /// Create a FastConcurrentSymbolDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentSymbolDict acts as a stack for all items with the same key. /// public FastConcurrentSymbolDict(int initialCapacity, bool stackDuplicateKeys) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a FastConcurrentSymbolDict and initialize it to contain the supplied /// items. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentSymbolDict acts as a stack for all items with the same key. /// public FastConcurrentSymbolDict(IEnumerable> items, bool stackDuplicateKeys = false) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { foreach (var item in items) Add(item); } /// /// Create a FastConcurrentSymbolDict and initialize to contain the supplied items. /// Note hat this incurs the overhead of converting all string keys /// to symbols. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentSymbolDict acts as a stack for all items with the same key. /// public FastConcurrentSymbolDict(IEnumerable> items, bool stackDuplicateKeys = false) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), DictConstant.MinExtraCapacity, stackDuplicateKeys) { foreach (var item in items) Add(item); } private FastConcurrentSymbolDict( uint firstCapacity, uint extraCapacity, bool stackDuplicateKeys = false) { m_version = 0; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_doNotStackDuplicateKeys = !stackDuplicateKeys; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextSymbolValue[m_capacity]; m_extraArray = new SymbolValueNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the FastConcurrentSymbolDict. /// public int Count { get { return (int)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentSymbolDict /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentSymbolDict /// as long. /// public uint Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { Monitor.Enter(this); try { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the FastConcurrentSymbolDict. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { Monitor.Enter(this); try { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } public IEnumerable> Items { get { return KeyValuePairs; } } /// /// Returns all keys in the dictionary. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Keys { get { Monitor.Enter(this); try { var version = m_version; for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var k = m_firstArray[fi].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { k = m_extraArray[ei].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type KeyType { get { return typeof(Symbol); } } /// /// Returns all values in the FastConcurrentSymbolDict. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Values { get { Monitor.Enter(this); try { var version = m_version; for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var v = m_firstArray[fi].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { v = m_extraArray[ei].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type ValueType { get { return typeof(TValue); } } /// /// Returns all key value pairs in the FastConcurrentSymbolDict. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable> KeyValuePairs { get { Monitor.Enter(this); try { var version = m_version; for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var kvp = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { kvp = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } /// /// Returns all key value pairs in the FastConcurrentSymbolDict, in such a way, /// that the stack order is correct when the pairs are put into a /// new FastConcurrentSymbolDict in the order they are returned. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable> KeyValuePairsForStorage { get { Monitor.Enter(this); try { var version = m_version; var stack = new Stack(); for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; while (ei > 0) { stack.Push(ei); ei = m_extraArray[ei].Next; } var kvp = default(KeyValuePair); while (stack.Count > 0) { ei = stack.Pop(); kvp = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } kvp = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } } finally { Monitor.Exit(this); } } } public IEnumerable<(object, object)> ObjectPairs { get { foreach (var kvp in KeyValuePairsForStorage) yield return (kvp.Key, kvp.Value); } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the FastConcurrentSymbolDict acts as a stack. /// /// /// public TValue this[Symbol key] { get { var hash = key.Id; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key.Id == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } set { var hash = key.Id; Monitor.Enter(this); try { ++m_version; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { if (m_firstArray[fi].Item.Key.Id == hash) { m_firstArray[fi].Item.Value = value; return; } while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) { m_extraArray[ei].Item.Value = value; return; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the FastConcurrentSymbolDict. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the FastConcurrentSymbolDict /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((Symbol)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentSymbolDict. /// public void Add(Symbol key, TValue value) { var hash = key.Id; Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Key.Id == hash) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentSymbolDict. /// public bool TryAdd(Symbol key, TValue value) { var hash = key.Id; Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Key.Id == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } return true; } /// /// Adds the supplied item to the FastConcurrentSymbolDict. Note that this incurs the /// overhead of converting the string key to a symbol. /// public void Add(string key, TValue value) { Add(key.ToSymbol(), value); } /// /// Add the supplied item to the FastConcurrentSymbolDict. Note that this incurs the /// overhead of converting the string key to a symbol. /// public void Add(KeyValuePair item) { Add(item.Key.ToSymbol(), item.Value); } /// /// Add the supplied item to the FastConcurrentSymbolDict. /// public void Add(KeyValuePair item) { Add(item.Key, item.Value); } /// /// Add the supplied items to the FastConcurrentSymbolDict. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the FastConcurrentSymbolDict contains the item with the supplied /// key. /// public bool Contains(Symbol key) { var hash = key.Id; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key.Id == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentSymbolDict contains the item with the supplied /// key. /// public bool ContainsKey(Symbol key) { var hash = key.Id; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key.Id == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentSymbolDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(Symbol key, TValue value) { var hash = key.Id; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key.Id == hash && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentSymbolDict contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { return Contains(item.Key, item.Value); } /// /// Returns true if the FastConcurrentSymbolDict contains the given value. /// public bool ContainsValue(TValue value) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } return false; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(Symbol key) { var hash = key.Id; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key.Id == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the FastConcurrentSymbolDict and returned. /// public TValue GetOrCreate(Symbol key, Func creator) { var hash = key.Id; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Key.Id == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } finally { Monitor.Exit(this); } } TValue AddCreated(Symbol key, int hash, TValue value) { while (true) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } if (m_firstArray[fi].Item.Key.Id == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ei = m_firstArray[fi].Next; ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = m_firstArray[fi].Next; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(Symbol key, TValue defaultValue) { var hash = key.Id; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Key.Id == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(Symbol key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(Symbol key, out TValue value) { var hash = key.Id; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Key.Id == hash) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Return all the value with the given key. This method is only /// useful if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// public IEnumerable ValuesWithKey(Symbol key) { var hash = key.Id; Monitor.Enter(this); try { var version = m_version; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) yield break; if (m_firstArray[fi].Item.Key.Id == hash) { var v = m_firstArray[fi].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) { var v = m_extraArray[ei].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(Symbol key, int skip) { var hash = key.Id; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key.Id == hash) { if (skip == 0) return m_firstArray[fi].Item.Value; --skip; } while (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) { if (skip == 0) return m_extraArray[ei].Item.Value; --skip; } ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Remove the item with the supplied key from the FastConcurrentSymbolDict and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(Symbol key) { TValue value; if (!TryRemove(key, out value)) throw new KeyNotFoundException(); return value; } /// /// Try to remove the item with the supplied key from the FastConcurrentSymbolDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(Symbol key) { TValue value; return TryRemove(key, out value); } /// /// Remove the item with the supplied key and the supplied value /// from the FastConcurrentSymbolDict. Returns true if the value was removed. /// public bool Remove(Symbol key, TValue value) { return TryRemove(key, value); } /// /// Remove the item with the supplied KeyValuePair from the FastConcurrentSymbolDict. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { return TryRemove(item.Key, item.Value); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(Symbol key, out TValue value) { var hash = key.Id; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Key.Id == hash) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(SymbolValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(SymbolValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(SymbolValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Key.Id == hash) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(SymbolValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(Symbol key, TValue value) { var hash = key.Id; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key.Id == hash && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(SymbolValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(SymbolValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Key.Id == hash && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(SymbolValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Key.Id == hash && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(SymbolValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public Symbol[] KeysToArray() { var array = new Symbol[m_count]; CopyKeysTo(array, 0); return array; } /// /// Returns all values in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TValue[] ValuesToArray() { var array = new TValue[m_count]; CopyValuesTo(array, 0); return array; } /// /// Returns all KeyValuePairs in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public KeyValuePair[] ToArray() { var array = new KeyValuePair[m_count]; CopyTo(array, 0); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { ++m_version; m_firstArray.Set(default(NextSymbolValue)); m_extraArray.Set(default(SymbolValueNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyKeysTo(Symbol[] array, int index) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyValuesTo(TValue[] array, int index) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Value; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(KeyValuePair[] array, int index) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { array[index++] = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } public void Add(TypedSymbol key, TType value) where TType : TValue { this.Add(key.Symbol, value); } public bool Contains(TypedSymbol key) where TType : TValue { return Contains(key.Symbol); } public bool ContainsKey(TypedSymbol key) where TType : TValue { return ContainsKey(key.Symbol); } public TType Get(TypedSymbol key) where TType : TValue { return (TType)this[key.Symbol]; } public TType Get(TypedSymbol key, TType defaultValue) where TType : TValue { TType value; if (TryGetValue(key, out value)) return value; return defaultValue; } public TType GetOrDefault(TypedSymbol key) where TType : TValue { TType value; if (TryGetValue(key, out value)) return value; return default(TType); } public bool Remove(TypedSymbol key) where TType : TValue { return Remove(key.Symbol); } public void Set(TypedSymbol key, TType value) where TType : TValue { this[key.Symbol] = value; } public bool TryGetValue(TypedSymbol key, out TType value) where TType : TValue { TValue val; if (TryGetValue(key.Symbol, out val)) { value = (TType)val; return true; } value = default(TType); return false; } public TType GetAs(Symbol key) where TType : TValue { return (TType)this[key]; } public TType GetAs(Symbol key, TType defaultValue) where TType : TValue { TValue value; if (TryGetValue(key, out value)) return (TType)value; return defaultValue; } public TType GetAsOrDefault(Symbol key) where TType : TValue { TValue value; if (TryGetValue(key, out value)) return (TType)value; return default(TType); } #endregion #region IEnumerable> Members IEnumerator> IEnumerable>.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region Private Helper Methods private uint ComputeIncreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_maxFillFactor); } private uint ComputeDecreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_minFillFactor); } private static int AddSlotsToFreeList( SymbolValueNext[] extraArray, int start) { var length = extraArray.Length - 1; for (int i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( SymbolValue item, NextSymbolValue[] firstArray, uint capacity, ref SymbolValueNext[] extraArray, ref int freeIndex, ref uint extraCount) { var fi = ((uint)item.Key.Id) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(uint newCapacity, uint oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextSymbolValue[newCapacity]; var extraArray = new SymbolValueNext[ System.Math.Max((int)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); uint newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { uint fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((uint)m_count - m_extraCount, oldCapacity, m_extraCount, (uint)m_extraArray.Length, (uint)m_count - newExtraCount, newCapacity, newExtraCount, (uint)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( uint oldFirstCount, uint oldCapacity, uint oldExtraCount, uint oldExtraCapacity, uint newFirstCount, uint newCapacity, uint newExtraCount, uint newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region FastConcurrentSymbolSet /// /// A FastConcurrentSymbolSet is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class FastConcurrentSymbolSet : IIntCountable, ICountableDictSet, IDictSet, IEnumerable, IEnumerable { private long m_version; private uint m_capacity; private NextSymbol[] m_firstArray; private SymbolNext[] m_extraArray; private uint m_count; private uint m_increaseThreshold; private uint m_decreaseThreshold; private int m_freeIndex; private int m_capacityIndex; private uint m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a FastConcurrentSymbolSet that autmatically grows and shrinks as necessary. /// public FastConcurrentSymbolSet() : this(DictConstant.PrimeSizes[0], (uint)DictConstant.MinExtraCapacity) { } /// /// Create a FastConcurrentSymbolSet that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// public FastConcurrentSymbolSet(int initialCapacity) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity) { } /// /// Create a FastConcurrentSymbolSet and initialize it to contain the supplied /// items. /// public FastConcurrentSymbolSet(IEnumerable items) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity) { foreach (var item in items) Add(item); } /// /// Create a FastConcurrentSymbolSet and initialize to contain the supplied items. /// Note hat this incurs the overhead of converting all string keys /// to symbols. /// public FastConcurrentSymbolSet(IEnumerable items) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), DictConstant.MinExtraCapacity) { foreach (var item in items) Add(item); } private FastConcurrentSymbolSet( uint firstCapacity, uint extraCapacity) { m_version = 0; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextSymbol[m_capacity]; m_extraArray = new SymbolNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the FastConcurrentSymbolSet. /// public int Count { get { return (int)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentSymbolSet /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentSymbolSet /// as long. /// public uint Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { Monitor.Enter(this); try { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the FastConcurrentSymbolSet. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { Monitor.Enter(this); try { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } public IEnumerable Items { get { return Keys; } } /// /// Returns all keys in the dictionary. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Keys { get { Monitor.Enter(this); try { var version = m_version; for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var k = m_firstArray[fi].Item; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { k = m_extraArray[ei].Item; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type KeyType { get { return typeof(Symbol); } } public IEnumerable Objects { get { foreach (object obj in Keys) yield return obj; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the FastConcurrentSymbolSet. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the FastConcurrentSymbolSet /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((Symbol)objkey); } /// /// Add the item with the supplied key /// to the FastConcurrentSymbolSet. /// public bool Add(Symbol key) { var hash = key.Id; Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Id == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Id == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key /// to the FastConcurrentSymbolSet. /// public bool TryAdd(Symbol key) { var hash = key.Id; Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Id == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Id == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item = key; } finally { Monitor.Exit(this); } return true; } /// /// Adds the supplied item to the FastConcurrentSymbolSet. Note that this incurs the /// overhead of converting the string key to a symbol. /// public void Add(string key) { Add(key.ToSymbol()); } /// /// Add the supplied keys to the FastConcurrentSymbolSet. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the FastConcurrentSymbolSet contains the item with the supplied /// key. /// public bool Contains(Symbol key) { var hash = key.Id; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Id == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item.Id == hash) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Remove the item with the supplied key /// from the FastConcurrentSymbolSet. Returns true if the value was removed. /// public bool Remove(Symbol key) { return TryRemove(key); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(Symbol key) { var hash = key.Id; Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Id == hash) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(Symbol); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(Symbol); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Id == hash) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(Symbol); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Id == hash) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(Symbol); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public Symbol[] ToArray() { var array = new Symbol[m_count]; CopyTo(array, 0); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { ++m_version; m_firstArray.Set(default(NextSymbol)); m_extraArray.Set(default(SymbolNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(Symbol[] array, int index) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item; while (ei > 0) { array[index++] = m_extraArray[ei].Item; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return Keys.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return Keys.GetEnumerator(); } #endregion #region Private Helper Methods private uint ComputeIncreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_maxFillFactor); } private uint ComputeDecreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_minFillFactor); } private static int AddSlotsToFreeList( SymbolNext[] extraArray, int start) { var length = extraArray.Length - 1; for (int i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( Symbol item, NextSymbol[] firstArray, uint capacity, ref SymbolNext[] extraArray, ref int freeIndex, ref uint extraCount) { var fi = ((uint)item.Id) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(uint newCapacity, uint oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextSymbol[newCapacity]; var extraArray = new SymbolNext[ System.Math.Max((int)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); uint newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { uint fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((uint)m_count - m_extraCount, oldCapacity, m_extraCount, (uint)m_extraArray.Length, (uint)m_count - newExtraCount, newCapacity, newExtraCount, (uint)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( uint oldFirstCount, uint oldCapacity, uint oldExtraCount, uint oldExtraCapacity, uint newFirstCount, uint newCapacity, uint newExtraCount, uint newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region FastConcurrentBigDict /// /// A FastConcurrentBigDict is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class FastConcurrentBigDict : ICountableDict, IDict, IEnumerable, IEnumerable> { private long m_version; private readonly Func m_hfun; private ulong m_capacity; private NextHashKeyValueLong[] m_firstArray; private HashKeyValueNextLong[] m_extraArray; private ulong m_count; private ulong m_increaseThreshold; private ulong m_decreaseThreshold; private readonly bool m_doNotStackDuplicateKeys; private long m_freeIndex; private int m_capacityIndex; private ulong m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a FastConcurrentBigDict that autmatically grows and shrinks as necessary. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentBigDict acts as a stack for all items with the same key. /// public FastConcurrentBigDict(Func hfun, bool stackDuplicateKeys = false) : this(hfun, DictConstant.PrimeSizesLong[0], (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a FastConcurrentBigDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentBigDict acts as a stack for all items with the same key. /// public FastConcurrentBigDict(Func hfun, long initialCapacity) : this(hfun, System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity, false) { } /// /// Create a FastConcurrentBigDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentBigDict acts as a stack for all items with the same key. /// public FastConcurrentBigDict(Func hfun, long initialCapacity, bool stackDuplicateKeys) : this(hfun, System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a FastConcurrentBigDict and initialize it to contain the supplied /// items. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentBigDict acts as a stack for all items with the same key. /// public FastConcurrentBigDict(Func hfun, IEnumerable> items, bool stackDuplicateKeys = false) : this(hfun, Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { foreach (var item in items) Add(item); } private FastConcurrentBigDict( Func hfun, ulong firstCapacity, ulong extraCapacity, bool stackDuplicateKeys = false) { m_version = 0; m_hfun = hfun; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_doNotStackDuplicateKeys = !stackDuplicateKeys; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizesLong[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizesLong[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextHashKeyValueLong[m_capacity]; m_extraArray = new HashKeyValueNextLong[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the FastConcurrentBigDict /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentBigDict /// as long. /// public ulong Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { Monitor.Enter(this); try { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the FastConcurrentBigDict. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { Monitor.Enter(this); try { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } public IEnumerable> Items { get { return KeyValuePairs; } } /// /// Returns all keys in the dictionary. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Keys { get { Monitor.Enter(this); try { var version = m_version; for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var k = m_firstArray[fi].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { k = m_extraArray[ei].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type KeyType { get { return typeof(TKey); } } /// /// Returns all values in the FastConcurrentBigDict. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Values { get { Monitor.Enter(this); try { var version = m_version; for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var v = m_firstArray[fi].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { v = m_extraArray[ei].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type ValueType { get { return typeof(TValue); } } /// /// Returns all key value pairs in the FastConcurrentBigDict. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable> KeyValuePairs { get { Monitor.Enter(this); try { var version = m_version; for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var kvp = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { kvp = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } /// /// Returns all key value pairs in the FastConcurrentBigDict, in such a way, /// that the stack order is correct when the pairs are put into a /// new FastConcurrentBigDict in the order they are returned. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable> KeyValuePairsForStorage { get { Monitor.Enter(this); try { var version = m_version; var stack = new Stack(); for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; while (ei > 0) { stack.Push(ei); ei = m_extraArray[ei].Next; } var kvp = default(KeyValuePair); while (stack.Count > 0) { ei = stack.Pop(); kvp = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } kvp = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } } finally { Monitor.Exit(this); } } } public IEnumerable<(object, object)> ObjectPairs { get { foreach (var kvp in KeyValuePairsForStorage) yield return (kvp.Key, kvp.Value); } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the FastConcurrentBigDict acts as a stack. /// /// /// public TValue this[TKey key] { get { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } set { var hash = m_hfun(key); Monitor.Enter(this); try { ++m_version; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { m_firstArray[fi].Item.Value = value; return; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_extraArray[ei].Item.Value = value; return; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.LongLength; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the FastConcurrentBigDict. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the FastConcurrentBigDict /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((TKey)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentBigDict. /// public void Add(TKey key, TValue value) { var hash = m_hfun(key); Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentBigDict. /// public void Add(TKey key, long hash, TValue value) { Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentBigDict. /// public bool TryAdd(TKey key, TValue value) { var hash = m_hfun(key); Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentBigDict. /// public bool TryAdd(TKey key, long hash, TValue value) { Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } return true; } /// /// Add the supplied item to the FastConcurrentBigDict. /// public void Add(KeyValuePair item) { Add(item.Key, item.Value); } /// /// Add the supplied items to the FastConcurrentBigDict. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the FastConcurrentBigDict contains the item with the supplied /// key. /// public bool Contains(TKey key) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentBigDict contains the item with the supplied /// key. /// public bool Contains(TKey key, long hash) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentBigDict contains the item with the supplied /// key. /// public bool ContainsKey(TKey key) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentBigDict contains the item with the supplied /// key. /// public bool ContainsKey(TKey key, long hash) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentBigDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, TValue value) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentBigDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, long hash, TValue value) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentBigDict contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { return Contains(item.Key, item.Value); } /// /// Returns true if the FastConcurrentBigDict contains the given value. /// public bool ContainsValue(TValue value) { Monitor.Enter(this); try { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } return false; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the FastConcurrentBigDict and returned. /// public TValue GetOrCreate(TKey key, Func creator) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } finally { Monitor.Exit(this); } } TValue AddCreated(TKey key, long hash, TValue value) { while (true) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ei = m_firstArray[fi].Next; ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = m_firstArray[fi].Next; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, TValue defaultValue) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key, long hash) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the FastConcurrentBigDict and returned. /// public TValue GetOrCreate(TKey key, long hash, Func creator) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, long hash, TValue defaultValue) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(TKey key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, out TValue value) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, long hash, out TValue value) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Return all the value with the given key. This method is only /// useful if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// public IEnumerable ValuesWithKey(TKey key) { var hash = m_hfun(key); Monitor.Enter(this); try { var version = m_version; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) yield break; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { var v = m_firstArray[fi].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { var v = m_extraArray[ei].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(TKey key, long skip) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (skip == 0) return m_firstArray[fi].Item.Value; --skip; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { if (skip == 0) return m_extraArray[ei].Item.Value; --skip; } ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Remove the item with the supplied key from the FastConcurrentBigDict and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(TKey key) { TValue value; if (!TryRemove(key, out value)) throw new KeyNotFoundException(); return value; } /// /// Try to remove the item with the supplied key from the FastConcurrentBigDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key) { TValue value; return TryRemove(key, out value); } /// /// Try to remove the item with the supplied key from the FastConcurrentBigDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key, long hash) { TValue value; return TryRemove(key, hash, out value); } /// /// Remove the item with the supplied key and the supplied value /// from the FastConcurrentBigDict. Returns true if the value was removed. /// public bool Remove(TKey key, TValue value) { return TryRemove(key, value); } /// /// Remove the item with the supplied key and the supplied value /// from the FastConcurrentBigDict. Returns true if the value was removed. /// public bool Remove(TKey key, long hash, TValue value) { return TryRemove(key, hash, value); } /// /// Remove the item with the supplied KeyValuePair from the FastConcurrentBigDict. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { return TryRemove(item.Key, item.Value); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, out TValue value) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValueLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValueLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, long hash, out TValue value) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValueLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValueLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, TValue value) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValueLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key) && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValueLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, long hash, TValue value) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValueLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key) && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValueLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TKey[] KeysToArray() { var array = new TKey[m_count]; CopyKeysTo(array, 0L); return array; } /// /// Returns all values in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TValue[] ValuesToArray() { var array = new TValue[m_count]; CopyValuesTo(array, 0L); return array; } /// /// Returns all KeyValuePairs in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public KeyValuePair[] ToArray() { var array = new KeyValuePair[m_count]; CopyTo(array, 0L); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { ++m_version; m_firstArray.Set(default(NextHashKeyValueLong)); m_extraArray.Set(default(HashKeyValueNextLong)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyKeysTo(TKey[] array, long index) { Monitor.Enter(this); try { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyValuesTo(TValue[] array, long index) { Monitor.Enter(this); try { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Value; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(KeyValuePair[] array, long index) { Monitor.Enter(this); try { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { array[index++] = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } #endregion #region IEnumerable> Members IEnumerator> IEnumerable>.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region Private Helper Methods private ulong ComputeIncreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_maxFillFactor); } private ulong ComputeDecreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_minFillFactor); } private static long AddSlotsToFreeList( HashKeyValueNextLong[] extraArray, long start) { var length = extraArray.Length - 1; for (long i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizesLong[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizesLong[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( HashKeyValueLong item, NextHashKeyValueLong[] firstArray, ulong capacity, ref HashKeyValueNextLong[] extraArray, ref long freeIndex, ref ulong extraCount) { var fi = ((ulong)item.Hash) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(ulong newCapacity, ulong oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextHashKeyValueLong[newCapacity]; var extraArray = new HashKeyValueNextLong[ System.Math.Max((long)DictConstant.MinExtraCapacity, m_extraArray.LongLength / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); ulong newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { ulong fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((ulong)m_count - m_extraCount, oldCapacity, m_extraCount, (ulong)m_extraArray.Length, (ulong)m_count - newExtraCount, newCapacity, newExtraCount, (ulong)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( ulong oldFirstCount, ulong oldCapacity, ulong oldExtraCount, ulong oldExtraCapacity, ulong newFirstCount, ulong newCapacity, ulong newExtraCount, ulong newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region FastConcurrentBigDictSet /// /// A FastConcurrentBigDictSet is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class FastConcurrentBigDictSet : ICountableDictSet, IDictSet, IEnumerable, IEnumerable { private long m_version; private readonly Func m_hfun; private ulong m_capacity; private NextHashKeyLong[] m_firstArray; private HashKeyNextLong[] m_extraArray; private ulong m_count; private ulong m_increaseThreshold; private ulong m_decreaseThreshold; private long m_freeIndex; private int m_capacityIndex; private ulong m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a FastConcurrentBigDictSet that autmatically grows and shrinks as necessary. /// public FastConcurrentBigDictSet(Func hfun) : this(hfun, DictConstant.PrimeSizesLong[0], (ulong)DictConstant.MinExtraCapacity) { } /// /// Create a FastConcurrentBigDictSet that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// public FastConcurrentBigDictSet(Func hfun, long initialCapacity) : this(hfun, System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity) { } /// /// Create a FastConcurrentBigDictSet and initialize it to contain the supplied /// items. /// public FastConcurrentBigDictSet(Func hfun, IEnumerable items) : this(hfun, Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity) { foreach (var item in items) Add(item); } private FastConcurrentBigDictSet( Func hfun, ulong firstCapacity, ulong extraCapacity) { m_version = 0; m_hfun = hfun; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizesLong[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizesLong[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextHashKeyLong[m_capacity]; m_extraArray = new HashKeyNextLong[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the FastConcurrentBigDictSet /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentBigDictSet /// as long. /// public ulong Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { Monitor.Enter(this); try { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the FastConcurrentBigDictSet. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { Monitor.Enter(this); try { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } public IEnumerable Items { get { return Keys; } } /// /// Returns all keys in the dictionary. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Keys { get { Monitor.Enter(this); try { var version = m_version; for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var k = m_firstArray[fi].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { k = m_extraArray[ei].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type KeyType { get { return typeof(TKey); } } public IEnumerable Objects { get { foreach (object obj in Keys) yield return obj; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the FastConcurrentBigDictSet. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the FastConcurrentBigDictSet /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((TKey)objkey); } /// /// Add the item with the supplied key /// to the FastConcurrentBigDictSet. /// public bool Add(TKey key) { var hash = m_hfun(key); Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key /// to the FastConcurrentBigDictSet. /// public bool Add(TKey key, long hash) { Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key /// to the FastConcurrentBigDictSet. /// public bool TryAdd(TKey key) { var hash = m_hfun(key); Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key /// to the FastConcurrentBigDictSet. /// public bool TryAdd(TKey key, long hash) { Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the supplied keys to the FastConcurrentBigDictSet. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the FastConcurrentBigDictSet contains the item with the supplied /// key. /// public bool Contains(TKey key) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentBigDictSet contains the item with the supplied /// key. /// public bool Contains(TKey key, long hash) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Remove the item with the supplied key /// from the FastConcurrentBigDictSet. Returns true if the value was removed. /// public bool Remove(TKey key) { return TryRemove(key); } /// /// Remove the item with the supplied key /// from the FastConcurrentBigDictSet. Returns true if the value was removed. /// public bool Remove(TKey key, long hash) { return TryRemove(key, hash); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key, long hash) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TKey[] ToArray() { var array = new TKey[m_count]; CopyTo(array, 0L); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { ++m_version; m_firstArray.Set(default(NextHashKeyLong)); m_extraArray.Set(default(HashKeyNextLong)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(TKey[] array, long index) { Monitor.Enter(this); try { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return Keys.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return Keys.GetEnumerator(); } #endregion #region Private Helper Methods private ulong ComputeIncreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_maxFillFactor); } private ulong ComputeDecreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_minFillFactor); } private static long AddSlotsToFreeList( HashKeyNextLong[] extraArray, long start) { var length = extraArray.Length - 1; for (long i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizesLong[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizesLong[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( HashKeyLong item, NextHashKeyLong[] firstArray, ulong capacity, ref HashKeyNextLong[] extraArray, ref long freeIndex, ref ulong extraCount) { var fi = ((ulong)item.Hash) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(ulong newCapacity, ulong oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextHashKeyLong[newCapacity]; var extraArray = new HashKeyNextLong[ System.Math.Max((long)DictConstant.MinExtraCapacity, m_extraArray.LongLength / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); ulong newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { ulong fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((ulong)m_count - m_extraCount, oldCapacity, m_extraCount, (ulong)m_extraArray.Length, (ulong)m_count - newExtraCount, newCapacity, newExtraCount, (ulong)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( ulong oldFirstCount, ulong oldCapacity, ulong oldExtraCount, ulong oldExtraCapacity, ulong newFirstCount, ulong newCapacity, ulong newExtraCount, ulong newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region FastConcurrentLongDict /// /// A FastConcurrentLongDict is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class FastConcurrentLongDict : ICountableDict, IDict, IEnumerable, IEnumerable> { private long m_version; private ulong m_capacity; private NextLongValue[] m_firstArray; private LongValueNext[] m_extraArray; private ulong m_count; private ulong m_increaseThreshold; private ulong m_decreaseThreshold; private readonly bool m_doNotStackDuplicateKeys; private long m_freeIndex; private int m_capacityIndex; private ulong m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a FastConcurrentLongDict that autmatically grows and shrinks as necessary. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentLongDict acts as a stack for all items with the same key. /// public FastConcurrentLongDict(bool stackDuplicateKeys = false) : this(DictConstant.PrimeSizes[0], (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a FastConcurrentLongDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentLongDict acts as a stack for all items with the same key. /// public FastConcurrentLongDict(long initialCapacity) : this(System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizes[0]), (ulong)DictConstant.MinExtraCapacity, false) { } /// /// Create a FastConcurrentLongDict that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentLongDict acts as a stack for all items with the same key. /// public FastConcurrentLongDict(long initialCapacity, bool stackDuplicateKeys) : this(System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizes[0]), (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a FastConcurrentLongDict and initialize it to contain the supplied /// items. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentLongDict acts as a stack for all items with the same key. /// public FastConcurrentLongDict(IEnumerable> items, bool stackDuplicateKeys = false) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { foreach (var item in items) Add(item); } private FastConcurrentLongDict( ulong firstCapacity, ulong extraCapacity, bool stackDuplicateKeys = false) { m_version = 0; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_doNotStackDuplicateKeys = !stackDuplicateKeys; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextLongValue[m_capacity]; m_extraArray = new LongValueNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the FastConcurrentLongDict /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentLongDict /// as long. /// public ulong Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { Monitor.Enter(this); try { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the FastConcurrentLongDict. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { Monitor.Enter(this); try { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } public IEnumerable> Items { get { return KeyValuePairs; } } /// /// Returns all keys in the dictionary. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Keys { get { Monitor.Enter(this); try { var version = m_version; for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var k = m_firstArray[fi].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { k = m_extraArray[ei].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type KeyType { get { return typeof(long); } } /// /// Returns all values in the FastConcurrentLongDict. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Values { get { Monitor.Enter(this); try { var version = m_version; for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var v = m_firstArray[fi].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { v = m_extraArray[ei].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type ValueType { get { return typeof(TValue); } } /// /// Returns all key value pairs in the FastConcurrentLongDict. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable> KeyValuePairs { get { Monitor.Enter(this); try { var version = m_version; for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var kvp = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { kvp = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } /// /// Returns all key value pairs in the FastConcurrentLongDict, in such a way, /// that the stack order is correct when the pairs are put into a /// new FastConcurrentLongDict in the order they are returned. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable> KeyValuePairsForStorage { get { Monitor.Enter(this); try { var version = m_version; var stack = new Stack(); for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; while (ei > 0) { stack.Push(ei); ei = m_extraArray[ei].Next; } var kvp = default(KeyValuePair); while (stack.Count > 0) { ei = stack.Pop(); kvp = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } kvp = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } } finally { Monitor.Exit(this); } } } public IEnumerable<(object, object)> ObjectPairs { get { foreach (var kvp in KeyValuePairsForStorage) yield return (kvp.Key, kvp.Value); } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the FastConcurrentLongDict acts as a stack. /// /// /// public TValue this[long key] { get { var hash = key; Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } set { var hash = key; Monitor.Enter(this); try { ++m_version; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { if (m_firstArray[fi].Item.Key == hash) { m_firstArray[fi].Item.Value = value; return; } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { m_extraArray[ei].Item.Value = value; return; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the FastConcurrentLongDict. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the FastConcurrentLongDict /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((long)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentLongDict. /// public void Add(long key, TValue value) { var hash = key; Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Key == hash) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentLongDict. /// public bool TryAdd(long key, TValue value) { var hash = key; Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Key == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } return true; } /// /// Add the supplied item to the FastConcurrentLongDict. /// public void Add(KeyValuePair item) { Add(item.Key, item.Value); } /// /// Add the supplied items to the FastConcurrentLongDict. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the FastConcurrentLongDict contains the item with the supplied /// key. /// public bool Contains(long key) { var hash = key; Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentLongDict contains the item with the supplied /// key. /// public bool ContainsKey(long key) { var hash = key; Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentLongDict contains the item with the supplied /// key and the supplied value. /// public bool Contains(long key, TValue value) { var hash = key; Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key == hash && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentLongDict contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { return Contains(item.Key, item.Value); } /// /// Returns true if the FastConcurrentLongDict contains the given value. /// public bool ContainsValue(TValue value) { Monitor.Enter(this); try { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } return false; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(long key) { var hash = key; Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the FastConcurrentLongDict and returned. /// public TValue GetOrCreate(long key, Func creator) { var hash = key; Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } finally { Monitor.Exit(this); } } TValue AddCreated(long key, long hash, TValue value) { while (true) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ei = m_firstArray[fi].Next; ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = m_firstArray[fi].Next; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(long key, TValue defaultValue) { var hash = key; Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Key == hash) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(long key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(long key, out TValue value) { var hash = key; Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Key == hash) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Return all the value with the given key. This method is only /// useful if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// public IEnumerable ValuesWithKey(long key) { var hash = key; Monitor.Enter(this); try { var version = m_version; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) yield break; if (m_firstArray[fi].Item.Key == hash) { var v = m_firstArray[fi].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { var v = m_extraArray[ei].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(long key, long skip) { var hash = key; Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Key == hash) { if (skip == 0) return m_firstArray[fi].Item.Value; --skip; } while (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { if (skip == 0) return m_extraArray[ei].Item.Value; --skip; } ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Remove the item with the supplied key from the FastConcurrentLongDict and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(long key) { TValue value; if (!TryRemove(key, out value)) throw new KeyNotFoundException(); return value; } /// /// Try to remove the item with the supplied key from the FastConcurrentLongDict. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(long key) { TValue value; return TryRemove(key, out value); } /// /// Remove the item with the supplied key and the supplied value /// from the FastConcurrentLongDict. Returns true if the value was removed. /// public bool Remove(long key, TValue value) { return TryRemove(key, value); } /// /// Remove the item with the supplied KeyValuePair from the FastConcurrentLongDict. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { return TryRemove(item.Key, item.Value); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(long key, out TValue value) { var hash = key; Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Key == hash) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(LongValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(LongValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Key == hash) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(LongValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Key == hash) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(LongValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(long key, TValue value) { var hash = key; Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Key == hash && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(LongValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(LongValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Key == hash && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(LongValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Key == hash && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(LongValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public long[] KeysToArray() { var array = new long[m_count]; CopyKeysTo(array, 0L); return array; } /// /// Returns all values in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TValue[] ValuesToArray() { var array = new TValue[m_count]; CopyValuesTo(array, 0L); return array; } /// /// Returns all KeyValuePairs in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public KeyValuePair[] ToArray() { var array = new KeyValuePair[m_count]; CopyTo(array, 0L); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { ++m_version; m_firstArray.Set(default(NextLongValue)); m_extraArray.Set(default(LongValueNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyKeysTo(long[] array, long index) { Monitor.Enter(this); try { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyValuesTo(TValue[] array, long index) { Monitor.Enter(this); try { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Value; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(KeyValuePair[] array, long index) { Monitor.Enter(this); try { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { array[index++] = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } #endregion #region IEnumerable> Members IEnumerator> IEnumerable>.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region Private Helper Methods private ulong ComputeIncreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_maxFillFactor); } private ulong ComputeDecreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_minFillFactor); } private static long AddSlotsToFreeList( LongValueNext[] extraArray, long start) { var length = extraArray.Length - 1; for (long i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( LongValue item, NextLongValue[] firstArray, ulong capacity, ref LongValueNext[] extraArray, ref long freeIndex, ref ulong extraCount) { var fi = ((ulong)item.Key) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(ulong newCapacity, ulong oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextLongValue[newCapacity]; var extraArray = new LongValueNext[ System.Math.Max((long)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); ulong newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { ulong fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((ulong)m_count - m_extraCount, oldCapacity, m_extraCount, (ulong)m_extraArray.Length, (ulong)m_count - newExtraCount, newCapacity, newExtraCount, (ulong)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( ulong oldFirstCount, ulong oldCapacity, ulong oldExtraCount, ulong oldExtraCapacity, ulong newFirstCount, ulong newCapacity, ulong newExtraCount, ulong newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region FastConcurrentLongSet /// /// A FastConcurrentLongSet is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class FastConcurrentLongSet : ICountableDictSet, IDictSet, IEnumerable, IEnumerable { private long m_version; private ulong m_capacity; private NextLong[] m_firstArray; private LongNext[] m_extraArray; private ulong m_count; private ulong m_increaseThreshold; private ulong m_decreaseThreshold; private long m_freeIndex; private int m_capacityIndex; private ulong m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a FastConcurrentLongSet that autmatically grows and shrinks as necessary. /// public FastConcurrentLongSet() : this(DictConstant.PrimeSizes[0], (ulong)DictConstant.MinExtraCapacity) { } /// /// Create a FastConcurrentLongSet that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// public FastConcurrentLongSet(long initialCapacity) : this(System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizes[0]), (ulong)DictConstant.MinExtraCapacity) { } /// /// Create a FastConcurrentLongSet and initialize it to contain the supplied /// items. /// public FastConcurrentLongSet(IEnumerable items) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (ulong)DictConstant.MinExtraCapacity) { foreach (var item in items) Add(item); } private FastConcurrentLongSet( ulong firstCapacity, ulong extraCapacity) { m_version = 0; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextLong[m_capacity]; m_extraArray = new LongNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the FastConcurrentLongSet /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentLongSet /// as long. /// public ulong Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { Monitor.Enter(this); try { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the FastConcurrentLongSet. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { Monitor.Enter(this); try { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } public IEnumerable Items { get { return Keys; } } /// /// Returns all keys in the dictionary. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Keys { get { Monitor.Enter(this); try { var version = m_version; for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var k = m_firstArray[fi].Item; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { k = m_extraArray[ei].Item; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type KeyType { get { return typeof(long); } } public IEnumerable Objects { get { foreach (object obj in Keys) yield return obj; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the FastConcurrentLongSet. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the FastConcurrentLongSet /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((long)objkey); } /// /// Add the item with the supplied key /// to the FastConcurrentLongSet. /// public bool Add(long key) { var hash = key; Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key /// to the FastConcurrentLongSet. /// public bool TryAdd(long key) { var hash = key; Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item == hash) { return false; } while (ei > 0) { if (m_extraArray[ei].Item == hash) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the supplied keys to the FastConcurrentLongSet. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the FastConcurrentLongSet contains the item with the supplied /// key. /// public bool Contains(long key) { var hash = key; Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item == hash) return true; while (ei > 0) { if (m_extraArray[ei].Item == hash) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Remove the item with the supplied key /// from the FastConcurrentLongSet. Returns true if the value was removed. /// public bool Remove(long key) { return TryRemove(key); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(long key) { var hash = key; Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item == hash) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(long); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(long); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item == hash) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(long); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item == hash) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(long); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public long[] ToArray() { var array = new long[m_count]; CopyTo(array, 0L); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { ++m_version; m_firstArray.Set(default(NextLong)); m_extraArray.Set(default(LongNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(long[] array, long index) { Monitor.Enter(this); try { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item; while (ei > 0) { array[index++] = m_extraArray[ei].Item; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return Keys.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return Keys.GetEnumerator(); } #endregion #region Private Helper Methods private ulong ComputeIncreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_maxFillFactor); } private ulong ComputeDecreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_minFillFactor); } private static long AddSlotsToFreeList( LongNext[] extraArray, long start) { var length = extraArray.Length - 1; for (long i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( long item, NextLong[] firstArray, ulong capacity, ref LongNext[] extraArray, ref long freeIndex, ref ulong extraCount) { var fi = ((ulong)item) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(ulong newCapacity, ulong oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextLong[newCapacity]; var extraArray = new LongNext[ System.Math.Max((long)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); ulong newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { ulong fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((ulong)m_count - m_extraCount, oldCapacity, m_extraCount, (ulong)m_extraArray.Length, (ulong)m_count - newExtraCount, newCapacity, newExtraCount, (ulong)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( ulong oldFirstCount, ulong oldCapacity, ulong oldExtraCount, ulong oldExtraCapacity, ulong newFirstCount, ulong newCapacity, ulong newExtraCount, ulong newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region DictIEq /// /// A DictIEq is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class DictIEq : IIntCountable, ICountableDict, IDict, IEnumerable, IEnumerable>, ICollection, ICollection>, IDictionary, IReadOnlyDictionary where TKey : IEquatable { private uint m_capacity; private NextHashKeyValue[] m_firstArray; private HashKeyValueNext[] m_extraArray; private uint m_count; private uint m_increaseThreshold; private uint m_decreaseThreshold; private readonly bool m_doNotStackDuplicateKeys; private int m_freeIndex; private int m_capacityIndex; private uint m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a DictIEq that autmatically grows and shrinks as necessary. /// If the optional parameter stackDuplicateKeys is set to true, the /// DictIEq acts as a stack for all items with the same key. /// public DictIEq(bool stackDuplicateKeys = false) : this(DictConstant.PrimeSizes[0], (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a DictIEq that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// DictIEq acts as a stack for all items with the same key. /// public DictIEq(int initialCapacity) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, false) { } /// /// Create a DictIEq that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// DictIEq acts as a stack for all items with the same key. /// public DictIEq(int initialCapacity, bool stackDuplicateKeys) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a DictIEq and initialize it to contain the supplied /// items. /// If the optional parameter stackDuplicateKeys is set to true, the /// DictIEq acts as a stack for all items with the same key. /// public DictIEq(IEnumerable> items, bool stackDuplicateKeys = false) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { foreach (var item in items) Add(item); } private DictIEq( uint firstCapacity, uint extraCapacity, bool stackDuplicateKeys = false) { m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_doNotStackDuplicateKeys = !stackDuplicateKeys; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextHashKeyValue[m_capacity]; m_extraArray = new HashKeyValueNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the DictIEq. /// public int Count { get { return (int)m_count; } } /// /// Returns the number of items currently contained in the DictIEq /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the DictIEq /// as long. /// public uint Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the DictIEq. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } } /// /// Always returns false. Part of the ICollection implementation. /// public bool IsReadOnly { get { return false; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } public IEnumerable> Items { get { return KeyValuePairs; } } /// /// Returns all keys in the dictionary. /// public IEnumerable Keys { get { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Key; while (ei > 0) { yield return m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } } public Type KeyType { get { return typeof(TKey); } } /// /// Returns all values in the DictIEq. /// public IEnumerable Values { get { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Value; while (ei > 0) { yield return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } } public Type ValueType { get { return typeof(TValue); } } /// /// Returns all key value pairs in the DictIEq. /// public IEnumerable> KeyValuePairs { get { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { yield return new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } } /// /// Returns all key value pairs in the DictIEq, in such a way, /// that the stack order is correct when the pairs are put into a /// new DictIEq in the order they are returned. /// public IEnumerable> KeyValuePairsForStorage { get { var stack = new Stack(); for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; while (ei > 0) { stack.Push(ei); ei = m_extraArray[ei].Next; } while (stack.Count > 0) { ei = stack.Pop(); yield return new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); } yield return new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); } } } public IEnumerable<(object, object)> ObjectPairs { get { foreach (var kvp in KeyValuePairsForStorage) yield return (kvp.Key, kvp.Value); } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the DictIEq acts as a stack. /// /// /// public TValue this[TKey key] { get { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } set { var hash = key.GetHashCode(); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { m_firstArray[fi].Item.Value = value; return; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_extraArray[ei].Item.Value = value; return; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the DictIEq. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the DictIEq /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((TKey)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the DictIEq. /// public void Add(TKey key, TValue value) { var hash = key.GetHashCode(); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } /// /// Add the item with the supplied key and the supplied value /// to the DictIEq. /// public void Add(TKey key, int hash, TValue value) { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } /// /// Add the item with the supplied key and the supplied value /// to the DictIEq. /// public bool TryAdd(TKey key, TValue value) { var hash = key.GetHashCode(); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } /// /// Add the item with the supplied key and the supplied value /// to the DictIEq. /// public bool TryAdd(TKey key, int hash, TValue value) { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } /// /// Add the supplied item to the DictIEq. /// public void Add(KeyValuePair item) { Add(item.Key, item.Value); } /// /// Add the supplied items to the DictIEq. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the DictIEq contains the item with the supplied /// key. /// public bool Contains(TKey key) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the DictIEq contains the item with the supplied /// key. /// public bool Contains(TKey key, int hash) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the DictIEq contains the item with the supplied /// key. /// public bool ContainsKey(TKey key) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the DictIEq contains the item with the supplied /// key. /// public bool ContainsKey(TKey key, int hash) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the DictIEq contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, TValue value) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the DictIEq contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, int hash, TValue value) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the DictIEq contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { return Contains(item.Key, item.Value); } /// /// Returns true if the DictIEq contains the given value. /// public bool ContainsValue(TValue value) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } return false; } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the DictIEq and returned. /// public TValue GetOrCreate(TKey key, Func creator) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } TValue AddCreated(TKey key, int hash, TValue value) { while (true) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ei = m_firstArray[fi].Next; ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = m_firstArray[fi].Next; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, TValue defaultValue) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key, int hash) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the DictIEq and returned. /// public TValue GetOrCreate(TKey key, int hash, Func creator) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, int hash, TValue defaultValue) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(TKey key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, out TValue value) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); return false; } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, int hash, out TValue value) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); return false; } /// /// Return all the value with the given key. This method is only /// useful if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// public IEnumerable ValuesWithKey(TKey key) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) yield break; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) yield return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) yield return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } /// /// Gets an enumerator for values. /// Should be preferred over Values enumeration in /// performance critical code. /// public ValueEnumerator GetValuesEnumerator() { return new ValueEnumerator(this); } public struct ValueEnumerator : IEnumerator { DictIEq.Enumerator m_inner; public ValueEnumerator(DictIEq dict) { m_inner = dict.GetEnumerator(); } public TValue Current => m_inner.Current.Value; object IEnumerator.Current => Current; public void Dispose() => m_inner.Dispose(); public bool MoveNext() => m_inner.MoveNext(); public void Reset() => m_inner.Reset(); } /// /// Gets an enumerator for values with key. It is only useful /// if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// Should be preferred over ValuesWithKey enumeration in /// performance critical code. /// public ValuesWithKeyEnumerator GetValuesWithKeyEnumerator(TKey key) { return new ValuesWithKeyEnumerator(this, key); } public struct ValuesWithKeyEnumerator : IEnumerator { readonly DictIEq m_dict; readonly TKey m_key; readonly int m_hash; int m_extraIndex; TValue m_current; public ValuesWithKeyEnumerator(DictIEq dict, TKey key) { m_dict = dict; m_key = key; m_hash = key.GetHashCode(); m_extraIndex = int.MaxValue; m_current = default(TValue); } public readonly TValue Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex == int.MaxValue) { var fa = m_dict.m_firstArray; var fi = ((uint)m_hash) % m_dict.m_capacity; m_extraIndex = fa[fi].Next; if (m_extraIndex == 0) return false; if (fa[fi].Item.Hash == m_hash && m_key.Equals(fa[fi].Item.Key)) { m_current = fa[fi].Item.Value; return true; } } if (m_extraIndex > 0) { var ea = m_dict.m_extraArray; do { var valid = ea[m_extraIndex].Item.Hash == m_hash && m_key.Equals(ea[m_extraIndex].Item.Key); if (valid) m_current = ea[m_extraIndex].Item.Value; m_extraIndex = ea[m_extraIndex].Next; if (valid) return true; } while (m_extraIndex > 0); } return false; } public void Reset() { m_extraIndex = int.MaxValue; m_current = default(TValue); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(TKey key, int skip) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (skip == 0) return m_firstArray[fi].Item.Value; --skip; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { if (skip == 0) return m_extraArray[ei].Item.Value; --skip; } ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Remove the item with the supplied key from the DictIEq and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(TKey key) { TValue value; if (!TryRemove(key, out value)) throw new KeyNotFoundException(); return value; } /// /// Try to remove the item with the supplied key from the DictIEq. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key) { TValue value; return TryRemove(key, out value); } /// /// Try to remove the item with the supplied key from the DictIEq. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key, int hash) { TValue value; return TryRemove(key, hash, out value); } /// /// Remove the item with the supplied key and the supplied value /// from the DictIEq. Returns true if the value was removed. /// public bool Remove(TKey key, TValue value) { return TryRemove(key, value); } /// /// Remove the item with the supplied key and the supplied value /// from the DictIEq. Returns true if the value was removed. /// public bool Remove(TKey key, int hash, TValue value) { return TryRemove(key, hash, value); } /// /// Remove the item with the supplied KeyValuePair from the DictIEq. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { return TryRemove(item.Key, item.Value); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, out TValue value) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } value = default(TValue); return false; } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, int hash, out TValue value) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } value = default(TValue); return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, TValue value) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key) && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, int hash, TValue value) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key) && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Returns all keys in the dictionary as an array. /// public TKey[] KeysToArray() { var array = new TKey[m_count]; CopyKeysTo(array, 0); return array; } /// /// Returns all values in the dictionary as an array. /// public TValue[] ValuesToArray() { var array = new TValue[m_count]; CopyValuesTo(array, 0); return array; } /// /// Returns all KeyValuePairs in the dictionary as an array. /// public KeyValuePair[] ToArray() { var array = new KeyValuePair[m_count]; CopyTo(array, 0); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { m_firstArray.Set(default(NextHashKeyValue)); m_extraArray.Set(default(HashKeyValueNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyKeysTo(TKey[] array, int index) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyValuesTo(TValue[] array, int index) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Value; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// public void CopyTo(KeyValuePair[] array, int index) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { array[index++] = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } /// /// Copy items into supplied array starting at supplied index. /// public void CopyTo(Array array, int index) { var typedArray = array as KeyValuePair[]; if (typedArray != null) CopyTo(typedArray, index); else throw new ArgumentException(); } /// /// Retuns a concurrent wrapper around the DictIEq to enable /// concurrent modifications. /// public ConcurrentDictIEq AsConcurrent() { return new ConcurrentDictIEq(this); } #endregion #region IEnumerable> Members IEnumerator> IEnumerable>.GetEnumerator() { return new Enumerator(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region IDictionary Members ICollection IDictionary.Keys => new KeyCollection(this); ICollection IDictionary.Values => new ValueCollection(this); private sealed class KeyCollection(DictIEq parent) : ICollection, ICollection, IReadOnlyCollection { public void CopyTo(TKey[] array, int index) => parent.CopyKeysTo(array, index); public int Count => parent.Count; bool ICollection.IsReadOnly => true; void ICollection.Add(TKey item) => throw new NotSupportedException(); void ICollection.Clear() => throw new NotSupportedException(); public bool Contains(TKey item) => parent.ContainsKey(item); bool ICollection.Remove(TKey item) => throw new NotSupportedException(); IEnumerator IEnumerable.GetEnumerator() => new Enumerator(parent); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator(); void ICollection.CopyTo(Array array, int index) { if (array is TKey[] keys) parent.CopyKeysTo(keys, index); throw new ArrayTypeMismatchException(); } bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => ((ICollection)parent).SyncRoot; private class Enumerator(DictIEq dictionary) : IEnumerator, IEnumerator { private DictIEq.Enumerator _inner = dictionary.GetEnumerator(); public void Dispose() => _inner.Dispose(); public bool MoveNext() => _inner.MoveNext(); public TKey Current => _inner.Current.Key; object IEnumerator.Current => Current; void IEnumerator.Reset() => _inner.Reset(); } } private sealed class ValueCollection(DictIEq parent) : ICollection, ICollection, IReadOnlyCollection { public void CopyTo(TValue[] array, int index) => parent.CopyValuesTo(array, index); public int Count => parent.Count; bool ICollection.IsReadOnly => true; void ICollection.Add(TValue item) => throw new NotSupportedException(); void ICollection.Clear() => throw new NotSupportedException(); public bool Contains(TValue item) => parent.ContainsValue(item); bool ICollection.Remove(TValue item) => throw new NotSupportedException(); IEnumerator IEnumerable.GetEnumerator() => new Enumerator(parent); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator(); void ICollection.CopyTo(Array array, int index) { if (array is TValue[] values) parent.CopyValuesTo(values, index); throw new ArrayTypeMismatchException(); } bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => ((ICollection)parent).SyncRoot; private class Enumerator(DictIEq dictionary) : IEnumerator, IEnumerator { private DictIEq.Enumerator _inner = dictionary.GetEnumerator(); public void Dispose() => _inner.Dispose(); public bool MoveNext() => _inner.MoveNext(); public TValue Current => _inner.Current.Value; object IEnumerator.Current => Current; void IEnumerator.Reset() => _inner.Reset(); } } #endregion #region Enumerator public Enumerator GetEnumerator() { return new Enumerator(this); } public struct Enumerator : IEnumerator> { readonly DictIEq m_dict; int m_index; int m_extraIndex; KeyValuePair m_current; public Enumerator(DictIEq dict) { m_dict = dict; m_index = 0; m_extraIndex = -1; m_current = default(KeyValuePair); } public readonly KeyValuePair Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex < 0) { var fa = m_dict.m_firstArray; var cap = fa.Length; while (m_index < cap) { var nxt = fa[m_index].Next; if (nxt != 0) { m_current = new KeyValuePair(fa[m_index].Item.Key, fa[m_index].Item.Value); m_extraIndex = nxt; m_index++; return true; } m_index++; } return false; } else { var ea = m_dict.m_extraArray; m_current = new KeyValuePair(ea[m_extraIndex].Item.Key, ea[m_extraIndex].Item.Value); m_extraIndex = ea[m_extraIndex].Next; return true; } } public void Reset() { m_index = 0; m_extraIndex = -1; m_current = default( KeyValuePair); } } #endregion #region Private Helper Methods private uint ComputeIncreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_maxFillFactor); } private uint ComputeDecreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_minFillFactor); } private static int AddSlotsToFreeList( HashKeyValueNext[] extraArray, int start) { var length = extraArray.Length - 1; for (int i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( HashKeyValue item, NextHashKeyValue[] firstArray, uint capacity, ref HashKeyValueNext[] extraArray, ref int freeIndex, ref uint extraCount) { var fi = ((uint)item.Hash) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(uint newCapacity, uint oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextHashKeyValue[newCapacity]; var extraArray = new HashKeyValueNext[ System.Math.Max((int)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); uint newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { uint fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((uint)m_count - m_extraCount, oldCapacity, m_extraCount, (uint)m_extraArray.Length, (uint)m_count - newExtraCount, newCapacity, newExtraCount, (uint)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( uint oldFirstCount, uint oldCapacity, uint oldExtraCount, uint oldExtraCapacity, uint newFirstCount, uint newCapacity, uint newExtraCount, uint newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region DictSetIEq /// /// A DictSetIEq is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class DictSetIEq : IIntCountable, ICountableDictSet, IDictSet, IEnumerable, IEnumerable, ICollection, ICollection where TKey : IEquatable { private uint m_capacity; private NextHashKey[] m_firstArray; private HashKeyNext[] m_extraArray; private uint m_count; private uint m_increaseThreshold; private uint m_decreaseThreshold; private int m_freeIndex; private int m_capacityIndex; private uint m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a DictSetIEq that autmatically grows and shrinks as necessary. /// public DictSetIEq() : this(DictConstant.PrimeSizes[0], (uint)DictConstant.MinExtraCapacity) { } /// /// Create a DictSetIEq that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// public DictSetIEq(int initialCapacity) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity) { } /// /// Create a DictSetIEq and initialize it to contain the supplied /// items. /// public DictSetIEq(IEnumerable items) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity) { foreach (var item in items) Add(item); } private DictSetIEq( uint firstCapacity, uint extraCapacity) { m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextHashKey[m_capacity]; m_extraArray = new HashKeyNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the DictSetIEq. /// public int Count { get { return (int)m_count; } } /// /// Returns the number of items currently contained in the DictSetIEq /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the DictSetIEq /// as long. /// public uint Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the DictSetIEq. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } } /// /// Always returns false. Part of the ICollection implementation. /// public bool IsReadOnly { get { return false; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } public IEnumerable Items { get { return Keys; } } /// /// Returns all keys in the dictionary. /// public IEnumerable Keys { get { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Key; while (ei > 0) { yield return m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } } public Type KeyType { get { return typeof(TKey); } } public IEnumerable Objects { get { foreach (object obj in Keys) yield return obj; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the DictSetIEq. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the DictSetIEq /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((TKey)objkey); } void ICollection.Add(TKey key) { Add(key); } /// /// Add the item with the supplied key /// to the DictSetIEq. /// public bool Add(TKey key) { var hash = key.GetHashCode(); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } /// /// Add the item with the supplied key /// to the DictSetIEq. /// public bool Add(TKey key, int hash) { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } /// /// Add the item with the supplied key /// to the DictSetIEq. /// public bool TryAdd(TKey key) { var hash = key.GetHashCode(); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } /// /// Add the item with the supplied key /// to the DictSetIEq. /// public bool TryAdd(TKey key, int hash) { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } /// /// Add the supplied keys to the DictSetIEq. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the DictSetIEq contains the item with the supplied /// key. /// public bool Contains(TKey key) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the DictSetIEq contains the item with the supplied /// key. /// public bool Contains(TKey key, int hash) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Remove the item with the supplied key /// from the DictSetIEq. Returns true if the value was removed. /// public bool Remove(TKey key) { return TryRemove(key); } /// /// Remove the item with the supplied key /// from the DictSetIEq. Returns true if the value was removed. /// public bool Remove(TKey key, int hash) { return TryRemove(key, hash); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key) { var hash = key.GetHashCode(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKey); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKey); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKey); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKey); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key, int hash) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKey); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKey); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKey); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKey); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Returns all keys in the dictionary as an array. /// public TKey[] ToArray() { var array = new TKey[m_count]; CopyTo(array, 0); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { m_firstArray.Set(default(NextHashKey)); m_extraArray.Set(default(HashKeyNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyTo(TKey[] array, int index) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } /// /// Copy items into supplied array starting at supplied index. /// public void CopyTo(Array array, int index) { var typedArray = array as TKey[]; if (typedArray != null) CopyTo(typedArray, index); else throw new ArgumentException(); } /// /// Retuns a concurrent wrapper around the DictSetIEq to enable /// concurrent modifications. /// public ConcurrentDictSetIEq AsConcurrent() { return new ConcurrentDictSetIEq(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region Enumerator public Enumerator GetEnumerator() { return new Enumerator(this); } public struct Enumerator : IEnumerator { readonly DictSetIEq m_dict; int m_index; int m_extraIndex; TKey m_current; public Enumerator(DictSetIEq dict) { m_dict = dict; m_index = 0; m_extraIndex = -1; m_current = default(TKey); } public readonly TKey Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex < 0) { var fa = m_dict.m_firstArray; var cap = fa.Length; while (m_index < cap) { var nxt = fa[m_index].Next; if (nxt != 0) { m_current = fa[m_index].Item.Key; m_extraIndex = nxt; m_index++; return true; } m_index++; } return false; } else { var ea = m_dict.m_extraArray; m_current = ea[m_extraIndex].Item.Key; m_extraIndex = ea[m_extraIndex].Next; return true; } } public void Reset() { m_index = 0; m_extraIndex = -1; m_current = default(TKey); } } #endregion #region Private Helper Methods private uint ComputeIncreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_maxFillFactor); } private uint ComputeDecreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_minFillFactor); } private static int AddSlotsToFreeList( HashKeyNext[] extraArray, int start) { var length = extraArray.Length - 1; for (int i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( HashKey item, NextHashKey[] firstArray, uint capacity, ref HashKeyNext[] extraArray, ref int freeIndex, ref uint extraCount) { var fi = ((uint)item.Hash) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(uint newCapacity, uint oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextHashKey[newCapacity]; var extraArray = new HashKeyNext[ System.Math.Max((int)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); uint newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { uint fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((uint)m_count - m_extraCount, oldCapacity, m_extraCount, (uint)m_extraArray.Length, (uint)m_count - newExtraCount, newCapacity, newExtraCount, (uint)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( uint oldFirstCount, uint oldCapacity, uint oldExtraCount, uint oldExtraCapacity, uint newFirstCount, uint newCapacity, uint newExtraCount, uint newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region BigDictIEq /// /// A BigDictIEq is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class BigDictIEq : ICountableDict, IDict, IEnumerable, IEnumerable> where TKey : IEquatable { private readonly Func m_hfun; private ulong m_capacity; private NextHashKeyValueLong[] m_firstArray; private HashKeyValueNextLong[] m_extraArray; private ulong m_count; private ulong m_increaseThreshold; private ulong m_decreaseThreshold; private readonly bool m_doNotStackDuplicateKeys; private long m_freeIndex; private int m_capacityIndex; private ulong m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a BigDictIEq that autmatically grows and shrinks as necessary. /// If the optional parameter stackDuplicateKeys is set to true, the /// BigDictIEq acts as a stack for all items with the same key. /// public BigDictIEq(Func hfun, bool stackDuplicateKeys = false) : this(hfun, DictConstant.PrimeSizesLong[0], (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a BigDictIEq that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// BigDictIEq acts as a stack for all items with the same key. /// public BigDictIEq(Func hfun, long initialCapacity) : this(hfun, System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity, false) { } /// /// Create a BigDictIEq that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// BigDictIEq acts as a stack for all items with the same key. /// public BigDictIEq(Func hfun, long initialCapacity, bool stackDuplicateKeys) : this(hfun, System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a BigDictIEq and initialize it to contain the supplied /// items. /// If the optional parameter stackDuplicateKeys is set to true, the /// BigDictIEq acts as a stack for all items with the same key. /// public BigDictIEq(Func hfun, IEnumerable> items, bool stackDuplicateKeys = false) : this(hfun, Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { foreach (var item in items) Add(item); } private BigDictIEq( Func hfun, ulong firstCapacity, ulong extraCapacity, bool stackDuplicateKeys = false) { m_hfun = hfun; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_doNotStackDuplicateKeys = !stackDuplicateKeys; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizesLong[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizesLong[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextHashKeyValueLong[m_capacity]; m_extraArray = new HashKeyValueNextLong[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the BigDictIEq /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the BigDictIEq /// as long. /// public ulong Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the BigDictIEq. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } } /// /// Always returns false. Part of the ICollection implementation. /// public bool IsReadOnly { get { return false; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } public IEnumerable> Items { get { return KeyValuePairs; } } /// /// Returns all keys in the dictionary. /// public IEnumerable Keys { get { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Key; while (ei > 0) { yield return m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } } public Type KeyType { get { return typeof(TKey); } } /// /// Returns all values in the BigDictIEq. /// public IEnumerable Values { get { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Value; while (ei > 0) { yield return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } } public Type ValueType { get { return typeof(TValue); } } /// /// Returns all key value pairs in the BigDictIEq. /// public IEnumerable> KeyValuePairs { get { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { yield return new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } } /// /// Returns all key value pairs in the BigDictIEq, in such a way, /// that the stack order is correct when the pairs are put into a /// new BigDictIEq in the order they are returned. /// public IEnumerable> KeyValuePairsForStorage { get { var stack = new Stack(); for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; while (ei > 0) { stack.Push(ei); ei = m_extraArray[ei].Next; } while (stack.Count > 0) { ei = stack.Pop(); yield return new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); } yield return new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); } } } public IEnumerable<(object, object)> ObjectPairs { get { foreach (var kvp in KeyValuePairsForStorage) yield return (kvp.Key, kvp.Value); } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the BigDictIEq acts as a stack. /// /// /// public TValue this[TKey key] { get { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } set { var hash = m_hfun(key); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { m_firstArray[fi].Item.Value = value; return; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_extraArray[ei].Item.Value = value; return; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.LongLength; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the BigDictIEq. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the BigDictIEq /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((TKey)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the BigDictIEq. /// public void Add(TKey key, TValue value) { var hash = m_hfun(key); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } /// /// Add the item with the supplied key and the supplied value /// to the BigDictIEq. /// public void Add(TKey key, long hash, TValue value) { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } /// /// Add the item with the supplied key and the supplied value /// to the BigDictIEq. /// public bool TryAdd(TKey key, TValue value) { var hash = m_hfun(key); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } /// /// Add the item with the supplied key and the supplied value /// to the BigDictIEq. /// public bool TryAdd(TKey key, long hash, TValue value) { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } /// /// Add the supplied item to the BigDictIEq. /// public void Add(KeyValuePair item) { Add(item.Key, item.Value); } /// /// Add the supplied items to the BigDictIEq. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the BigDictIEq contains the item with the supplied /// key. /// public bool Contains(TKey key) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the BigDictIEq contains the item with the supplied /// key. /// public bool Contains(TKey key, long hash) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the BigDictIEq contains the item with the supplied /// key. /// public bool ContainsKey(TKey key) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the BigDictIEq contains the item with the supplied /// key. /// public bool ContainsKey(TKey key, long hash) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the BigDictIEq contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, TValue value) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the BigDictIEq contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, long hash, TValue value) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the BigDictIEq contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { return Contains(item.Key, item.Value); } /// /// Returns true if the BigDictIEq contains the given value. /// public bool ContainsValue(TValue value) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } return false; } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the BigDictIEq and returned. /// public TValue GetOrCreate(TKey key, Func creator) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } TValue AddCreated(TKey key, long hash, TValue value) { while (true) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ei = m_firstArray[fi].Next; ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = m_firstArray[fi].Next; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, TValue defaultValue) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key, long hash) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the BigDictIEq and returned. /// public TValue GetOrCreate(TKey key, long hash, Func creator) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, long hash, TValue defaultValue) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(TKey key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, out TValue value) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); return false; } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, long hash, out TValue value) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); return false; } /// /// Return all the value with the given key. This method is only /// useful if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// public IEnumerable ValuesWithKey(TKey key) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) yield break; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) yield return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) yield return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } /// /// Gets an enumerator for values. /// Should be preferred over Values enumeration in /// performance critical code. /// public ValueEnumerator GetValuesEnumerator() { return new ValueEnumerator(this); } public struct ValueEnumerator : IEnumerator { BigDictIEq.Enumerator m_inner; public ValueEnumerator(BigDictIEq dict) { m_inner = dict.GetEnumerator(); } public TValue Current => m_inner.Current.Value; object IEnumerator.Current => Current; public void Dispose() => m_inner.Dispose(); public bool MoveNext() => m_inner.MoveNext(); public void Reset() => m_inner.Reset(); } /// /// Gets an enumerator for values with key. It is only useful /// if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// Should be preferred over ValuesWithKey enumeration in /// performance critical code. /// public ValuesWithKeyEnumerator GetValuesWithKeyEnumerator(TKey key) { return new ValuesWithKeyEnumerator(this, key); } public struct ValuesWithKeyEnumerator : IEnumerator { readonly BigDictIEq m_dict; readonly TKey m_key; readonly long m_hash; long m_extraIndex; TValue m_current; public ValuesWithKeyEnumerator(BigDictIEq dict, TKey key) { m_dict = dict; m_key = key; m_hash = dict.m_hfun(key); m_extraIndex = int.MaxValue; m_current = default(TValue); } public readonly TValue Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex == int.MaxValue) { var fa = m_dict.m_firstArray; var fi = ((uint)m_hash) % m_dict.m_capacity; m_extraIndex = fa[fi].Next; if (m_extraIndex == 0) return false; if (fa[fi].Item.Hash == m_hash && m_key.Equals(fa[fi].Item.Key)) { m_current = fa[fi].Item.Value; return true; } } if (m_extraIndex > 0) { var ea = m_dict.m_extraArray; do { var valid = ea[m_extraIndex].Item.Hash == m_hash && m_key.Equals(ea[m_extraIndex].Item.Key); if (valid) m_current = ea[m_extraIndex].Item.Value; m_extraIndex = ea[m_extraIndex].Next; if (valid) return true; } while (m_extraIndex > 0); } return false; } public void Reset() { m_extraIndex = int.MaxValue; m_current = default(TValue); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(TKey key, long skip) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (skip == 0) return m_firstArray[fi].Item.Value; --skip; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { if (skip == 0) return m_extraArray[ei].Item.Value; --skip; } ei = m_extraArray[ei].Next; } throw new KeyNotFoundException(); } /// /// Remove the item with the supplied key from the BigDictIEq and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(TKey key) { TValue value; if (!TryRemove(key, out value)) throw new KeyNotFoundException(); return value; } /// /// Try to remove the item with the supplied key from the BigDictIEq. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key) { TValue value; return TryRemove(key, out value); } /// /// Try to remove the item with the supplied key from the BigDictIEq. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key, long hash) { TValue value; return TryRemove(key, hash, out value); } /// /// Remove the item with the supplied key and the supplied value /// from the BigDictIEq. Returns true if the value was removed. /// public bool Remove(TKey key, TValue value) { return TryRemove(key, value); } /// /// Remove the item with the supplied key and the supplied value /// from the BigDictIEq. Returns true if the value was removed. /// public bool Remove(TKey key, long hash, TValue value) { return TryRemove(key, hash, value); } /// /// Remove the item with the supplied KeyValuePair from the BigDictIEq. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { return TryRemove(item.Key, item.Value); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, out TValue value) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValueLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValueLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } value = default(TValue); return false; } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, long hash, out TValue value) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValueLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValueLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } value = default(TValue); return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, TValue value) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValueLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key) && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValueLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, long hash, TValue value) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValueLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key) && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValueLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Returns all keys in the dictionary as an array. /// public TKey[] KeysToArray() { var array = new TKey[m_count]; CopyKeysTo(array, 0L); return array; } /// /// Returns all values in the dictionary as an array. /// public TValue[] ValuesToArray() { var array = new TValue[m_count]; CopyValuesTo(array, 0L); return array; } /// /// Returns all KeyValuePairs in the dictionary as an array. /// public KeyValuePair[] ToArray() { var array = new KeyValuePair[m_count]; CopyTo(array, 0L); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { m_firstArray.Set(default(NextHashKeyValueLong)); m_extraArray.Set(default(HashKeyValueNextLong)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyKeysTo(TKey[] array, long index) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyValuesTo(TValue[] array, long index) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Value; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// public void CopyTo(KeyValuePair[] array, long index) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { array[index++] = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } /// /// Copy items into supplied array starting at supplied index. /// public void CopyTo(Array array, int index) { var typedArray = array as KeyValuePair[]; if (typedArray != null) CopyTo(typedArray, (long)index); else throw new ArgumentException(); } /// /// Retuns a concurrent wrapper around the BigDictIEq to enable /// concurrent modifications. /// public ConcurrentBigDictIEq AsConcurrent() { return new ConcurrentBigDictIEq(this); } #endregion #region IEnumerable> Members IEnumerator> IEnumerable>.GetEnumerator() { return new Enumerator(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region Enumerator public Enumerator GetEnumerator() { return new Enumerator(this); } public struct Enumerator : IEnumerator> { readonly BigDictIEq m_dict; long m_index; long m_extraIndex; KeyValuePair m_current; public Enumerator(BigDictIEq dict) { m_dict = dict; m_index = 0; m_extraIndex = -1; m_current = default(KeyValuePair); } public readonly KeyValuePair Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex < 0) { var fa = m_dict.m_firstArray; var cap = fa.Length; while (m_index < cap) { var nxt = fa[m_index].Next; if (nxt != 0) { m_current = new KeyValuePair(fa[m_index].Item.Key, fa[m_index].Item.Value); m_extraIndex = nxt; m_index++; return true; } m_index++; } return false; } else { var ea = m_dict.m_extraArray; m_current = new KeyValuePair(ea[m_extraIndex].Item.Key, ea[m_extraIndex].Item.Value); m_extraIndex = ea[m_extraIndex].Next; return true; } } public void Reset() { m_index = 0; m_extraIndex = -1; m_current = default( KeyValuePair); } } #endregion #region Private Helper Methods private ulong ComputeIncreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_maxFillFactor); } private ulong ComputeDecreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_minFillFactor); } private static long AddSlotsToFreeList( HashKeyValueNextLong[] extraArray, long start) { var length = extraArray.Length - 1; for (long i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizesLong[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizesLong[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( HashKeyValueLong item, NextHashKeyValueLong[] firstArray, ulong capacity, ref HashKeyValueNextLong[] extraArray, ref long freeIndex, ref ulong extraCount) { var fi = ((ulong)item.Hash) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(ulong newCapacity, ulong oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextHashKeyValueLong[newCapacity]; var extraArray = new HashKeyValueNextLong[ System.Math.Max((long)DictConstant.MinExtraCapacity, m_extraArray.LongLength / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); ulong newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { ulong fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((ulong)m_count - m_extraCount, oldCapacity, m_extraCount, (ulong)m_extraArray.Length, (ulong)m_count - newExtraCount, newCapacity, newExtraCount, (ulong)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( ulong oldFirstCount, ulong oldCapacity, ulong oldExtraCount, ulong oldExtraCapacity, ulong newFirstCount, ulong newCapacity, ulong newExtraCount, ulong newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region BigDictSetIEq /// /// A BigDictSetIEq is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class BigDictSetIEq : ICountableDictSet, IDictSet, IEnumerable, IEnumerable where TKey : IEquatable { private readonly Func m_hfun; private ulong m_capacity; private NextHashKeyLong[] m_firstArray; private HashKeyNextLong[] m_extraArray; private ulong m_count; private ulong m_increaseThreshold; private ulong m_decreaseThreshold; private long m_freeIndex; private int m_capacityIndex; private ulong m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a BigDictSetIEq that autmatically grows and shrinks as necessary. /// public BigDictSetIEq(Func hfun) : this(hfun, DictConstant.PrimeSizesLong[0], (ulong)DictConstant.MinExtraCapacity) { } /// /// Create a BigDictSetIEq that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// public BigDictSetIEq(Func hfun, long initialCapacity) : this(hfun, System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity) { } /// /// Create a BigDictSetIEq and initialize it to contain the supplied /// items. /// public BigDictSetIEq(Func hfun, IEnumerable items) : this(hfun, Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity) { foreach (var item in items) Add(item); } private BigDictSetIEq( Func hfun, ulong firstCapacity, ulong extraCapacity) { m_hfun = hfun; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizesLong[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizesLong[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextHashKeyLong[m_capacity]; m_extraArray = new HashKeyNextLong[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the BigDictSetIEq /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the BigDictSetIEq /// as long. /// public ulong Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the BigDictSetIEq. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } } /// /// Always returns false. Part of the ICollection implementation. /// public bool IsReadOnly { get { return false; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } public IEnumerable Items { get { return Keys; } } /// /// Returns all keys in the dictionary. /// public IEnumerable Keys { get { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; yield return m_firstArray[fi].Item.Key; while (ei > 0) { yield return m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } } public Type KeyType { get { return typeof(TKey); } } public IEnumerable Objects { get { foreach (object obj in Keys) yield return obj; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the BigDictSetIEq. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the BigDictSetIEq /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((TKey)objkey); } /// /// Add the item with the supplied key /// to the BigDictSetIEq. /// public bool Add(TKey key) { var hash = m_hfun(key); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } /// /// Add the item with the supplied key /// to the BigDictSetIEq. /// public bool Add(TKey key, long hash) { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } /// /// Add the item with the supplied key /// to the BigDictSetIEq. /// public bool TryAdd(TKey key) { var hash = m_hfun(key); if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } /// /// Add the item with the supplied key /// to the BigDictSetIEq. /// public bool TryAdd(TKey key, long hash) { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } /// /// Add the supplied keys to the BigDictSetIEq. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the BigDictSetIEq contains the item with the supplied /// key. /// public bool Contains(TKey key) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Returns true if the BigDictSetIEq contains the item with the supplied /// key. /// public bool Contains(TKey key, long hash) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } return false; } /// /// Remove the item with the supplied key /// from the BigDictSetIEq. Returns true if the value was removed. /// public bool Remove(TKey key) { return TryRemove(key); } /// /// Remove the item with the supplied key /// from the BigDictSetIEq. Returns true if the value was removed. /// public bool Remove(TKey key, long hash) { return TryRemove(key, hash); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key) { var hash = m_hfun(key); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key, long hash) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); return true; } } } return false; } /// /// Returns all keys in the dictionary as an array. /// public TKey[] ToArray() { var array = new TKey[m_count]; CopyTo(array, 0L); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { m_firstArray.Set(default(NextHashKeyLong)); m_extraArray.Set(default(HashKeyNextLong)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// public void CopyTo(TKey[] array, long index) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } /// /// Copy items into supplied array starting at supplied index. /// public void CopyTo(Array array, int index) { var typedArray = array as TKey[]; if (typedArray != null) CopyTo(typedArray, (long)index); else throw new ArgumentException(); } /// /// Retuns a concurrent wrapper around the BigDictSetIEq to enable /// concurrent modifications. /// public ConcurrentBigDictSetIEq AsConcurrent() { return new ConcurrentBigDictSetIEq(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region Enumerator public Enumerator GetEnumerator() { return new Enumerator(this); } public struct Enumerator : IEnumerator { readonly BigDictSetIEq m_dict; long m_index; long m_extraIndex; TKey m_current; public Enumerator(BigDictSetIEq dict) { m_dict = dict; m_index = 0; m_extraIndex = -1; m_current = default(TKey); } public readonly TKey Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex < 0) { var fa = m_dict.m_firstArray; var cap = fa.Length; while (m_index < cap) { var nxt = fa[m_index].Next; if (nxt != 0) { m_current = fa[m_index].Item.Key; m_extraIndex = nxt; m_index++; return true; } m_index++; } return false; } else { var ea = m_dict.m_extraArray; m_current = ea[m_extraIndex].Item.Key; m_extraIndex = ea[m_extraIndex].Next; return true; } } public void Reset() { m_index = 0; m_extraIndex = -1; m_current = default(TKey); } } #endregion #region Private Helper Methods private ulong ComputeIncreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_maxFillFactor); } private ulong ComputeDecreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_minFillFactor); } private static long AddSlotsToFreeList( HashKeyNextLong[] extraArray, long start) { var length = extraArray.Length - 1; for (long i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizesLong[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizesLong[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( HashKeyLong item, NextHashKeyLong[] firstArray, ulong capacity, ref HashKeyNextLong[] extraArray, ref long freeIndex, ref ulong extraCount) { var fi = ((ulong)item.Hash) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(ulong newCapacity, ulong oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextHashKeyLong[newCapacity]; var extraArray = new HashKeyNextLong[ System.Math.Max((long)DictConstant.MinExtraCapacity, m_extraArray.LongLength / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); ulong newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { ulong fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((ulong)m_count - m_extraCount, oldCapacity, m_extraCount, (ulong)m_extraArray.Length, (ulong)m_count - newExtraCount, newCapacity, newExtraCount, (ulong)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( ulong oldFirstCount, ulong oldCapacity, ulong oldExtraCount, ulong oldExtraCapacity, ulong newFirstCount, ulong newCapacity, ulong newExtraCount, ulong newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region ConcurrentDictIEq /// /// A ConcurrentDictIEq is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class ConcurrentDictIEq where TKey : IEquatable { private readonly DictIEq m_dict; #region Constructors /// /// A ConcurrentDictIEq can only be concstructed by wrapping its non-concurrent /// counterpart. /// public ConcurrentDictIEq(DictIEq dict) { m_dict = dict; } #endregion #region Properties /// /// Returns the number of items currently contained in the ConcurrentDictIEq. /// public int Count { get { return m_dict.Count; } } /// /// Returns the number of items currently contained in the ConcurrentDictIEq /// as long. /// public long LongCount { get { return m_dict.LongCount; } } /// /// Returns the number of items currently contained in the ConcurrentDictIEq /// as long. /// public uint Capacity { get { return m_dict.Capacity; } set { m_dict.Capacity = value; } } /// /// Return the non-concurrent contained ConcurrentDictIEq. /// public DictIEq NonConcurrent { get { return m_dict; } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the ConcurrentDictIEq acts as a stack. /// /// /// public TValue this[TKey key] { get { Monitor.Enter(this); try { return m_dict[key]; } finally { Monitor.Exit(this); } } set { Monitor.Enter(this); try { m_dict[key] = value; } finally { Monitor.Exit(this); } } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the ConcurrentDictIEq. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the ConcurrentDictIEq /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((TKey)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentDictIEq. /// public void Add(TKey key, TValue value) { Monitor.Enter(this); try { m_dict.Add(key, value); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentDictIEq. /// public void Add(TKey key, int hash, TValue value) { Monitor.Enter(this); try { m_dict.Add(key, hash, value); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentDictIEq. /// public bool TryAdd(TKey key, TValue value) { Monitor.Enter(this); try { return m_dict.TryAdd(key, value); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentDictIEq. /// public bool TryAdd(TKey key, int hash, TValue value) { Monitor.Enter(this); try { return m_dict.TryAdd(key, hash, value); } finally { Monitor.Exit(this); } } /// /// Add the supplied item to the ConcurrentDictIEq. /// public void Add(KeyValuePair item) { Monitor.Enter(this); try { m_dict.Add(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Add the supplied items to the ConcurrentDictIEq. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the ConcurrentDictIEq contains the item with the supplied /// key. /// public bool Contains(TKey key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentDictIEq contains the item with the supplied /// key. /// public bool Contains(TKey key, int hash) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentDictIEq contains the item with the supplied /// key. /// public bool ContainsKey(TKey key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentDictIEq contains the item with the supplied /// key. /// public bool ContainsKey(TKey key, int hash) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentDictIEq contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, TValue value) { Monitor.Enter(this); try { return m_dict.Contains(key, value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentDictIEq contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, int hash, TValue value) { Monitor.Enter(this); try { return m_dict.Contains(key, value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentDictIEq contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { Monitor.Enter(this); try { return m_dict.Contains(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentDictIEq contains the given value. /// public bool ContainsValue(TValue value) { Monitor.Enter(this); try { return m_dict.ContainsValue(value); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key) { Monitor.Enter(this); try { return m_dict.Get(key); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the ConcurrentDictIEq and returned. /// public TValue GetOrCreate(TKey key, Func creator) { Monitor.Enter(this); try { return m_dict.GetOrCreate(key, creator); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, TValue defaultValue) { Monitor.Enter(this); try { return m_dict.Get(key); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key, int hash) { Monitor.Enter(this); try { return m_dict.Get(key, hash); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the ConcurrentDictIEq and returned. /// public TValue GetOrCreate(TKey key, int hash, Func creator) { Monitor.Enter(this); try { return m_dict.GetOrCreate(key, hash, creator); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, int hash, TValue defaultValue) { Monitor.Enter(this); try { return m_dict.Get(key, hash); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(TKey key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, out TValue value) { Monitor.Enter(this); try { return m_dict.TryGetValue(key, out value); } finally { Monitor.Exit(this); } } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, int hash, out TValue value) { Monitor.Enter(this); try { return m_dict.TryGetValue(key, hash, out value); } finally { Monitor.Exit(this); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(TKey key, int skip) { Monitor.Enter(this); try { return m_dict.ValueWithKeySkip(key, skip); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key from the ConcurrentDictIEq and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(TKey key) { Monitor.Enter(this); try { return m_dict.GetAndRemove(key); } finally { Monitor.Exit(this); } } /// /// Try to remove the item with the supplied key from the ConcurrentDictIEq. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key) { TValue value; Monitor.Enter(this); try { return m_dict.TryRemove(key, out value); } finally { Monitor.Exit(this); } } /// /// Try to remove the item with the supplied key from the ConcurrentDictIEq. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key, int hash) { TValue value; Monitor.Enter(this); try { return m_dict.TryRemove(key, hash, out value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key and the supplied value /// from the ConcurrentDictIEq. Returns true if the value was removed. /// public bool Remove(TKey key, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key and the supplied value /// from the ConcurrentDictIEq. Returns true if the value was removed. /// public bool Remove(TKey key, int hash, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash, value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied KeyValuePair from the ConcurrentDictIEq. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { Monitor.Enter(this); try { return m_dict.TryRemove(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, out TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, out value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, int hash, out TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash, out value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, int hash, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash, value); } finally { Monitor.Exit(this); } } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TKey[] KeysToArray() { return m_dict.KeysToArray(); } /// /// Returns all values in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TValue[] ValuesToArray() { return m_dict.ValuesToArray(); } /// /// Returns all KeyValuePairs in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public KeyValuePair[] ToArray() { return m_dict.ToArray(); } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { m_dict.Clear(); } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyKeysTo(TKey[] array, int index) { Monitor.Enter(this); try { m_dict.CopyKeysTo(array, index); } finally { Monitor.Exit(this); } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyValuesTo(TValue[] array, int index) { Monitor.Enter(this); try { m_dict.CopyValuesTo(array, index); } finally { Monitor.Exit(this); } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(KeyValuePair[] array, int index) { Monitor.Enter(this); try { m_dict.CopyTo(array, index); } finally { Monitor.Exit(this); } } #endregion } #endregion #region ConcurrentDictSetIEq /// /// A ConcurrentDictSetIEq is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class ConcurrentDictSetIEq where TKey : IEquatable { private readonly DictSetIEq m_dict; #region Constructors /// /// A ConcurrentDictSetIEq can only be concstructed by wrapping its non-concurrent /// counterpart. /// public ConcurrentDictSetIEq(DictSetIEq dict) { m_dict = dict; } #endregion #region Properties /// /// Returns the number of items currently contained in the ConcurrentDictSetIEq. /// public int Count { get { return m_dict.Count; } } /// /// Returns the number of items currently contained in the ConcurrentDictSetIEq /// as long. /// public long LongCount { get { return m_dict.LongCount; } } /// /// Returns the number of items currently contained in the ConcurrentDictSetIEq /// as long. /// public uint Capacity { get { return m_dict.Capacity; } set { m_dict.Capacity = value; } } /// /// Return the non-concurrent contained ConcurrentDictSetIEq. /// public DictSetIEq NonConcurrent { get { return m_dict; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the ConcurrentDictSetIEq. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the ConcurrentDictSetIEq /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((TKey)objkey); } /// /// Add the item with the supplied key /// to the ConcurrentDictSetIEq. /// public bool Add(TKey key) { Monitor.Enter(this); try { return m_dict.Add(key); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key /// to the ConcurrentDictSetIEq. /// public bool Add(TKey key, int hash) { Monitor.Enter(this); try { return m_dict.Add(key, hash); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key /// to the ConcurrentDictSetIEq. /// public bool TryAdd(TKey key) { Monitor.Enter(this); try { return m_dict.TryAdd(key); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key /// to the ConcurrentDictSetIEq. /// public bool TryAdd(TKey key, int hash) { Monitor.Enter(this); try { return m_dict.TryAdd(key, hash); } finally { Monitor.Exit(this); } } /// /// Add the supplied keys to the ConcurrentDictSetIEq. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the ConcurrentDictSetIEq contains the item with the supplied /// key. /// public bool Contains(TKey key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentDictSetIEq contains the item with the supplied /// key. /// public bool Contains(TKey key, int hash) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key /// from the ConcurrentDictSetIEq. Returns true if the value was removed. /// public bool Remove(TKey key) { Monitor.Enter(this); try { return m_dict.TryRemove(key); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key /// from the ConcurrentDictSetIEq. Returns true if the value was removed. /// public bool Remove(TKey key, int hash) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key) { Monitor.Enter(this); try { return m_dict.TryRemove(key); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key, int hash) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash); } finally { Monitor.Exit(this); } } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TKey[] ToArray() { return m_dict.ToArray(); } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { m_dict.Clear(); } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(TKey[] array, int index) { Monitor.Enter(this); try { m_dict.CopyTo(array, index); } finally { Monitor.Exit(this); } } #endregion } #endregion #region ConcurrentBigDictIEq /// /// A ConcurrentBigDictIEq is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class ConcurrentBigDictIEq where TKey : IEquatable { private readonly BigDictIEq m_dict; #region Constructors /// /// A ConcurrentBigDictIEq can only be concstructed by wrapping its non-concurrent /// counterpart. /// public ConcurrentBigDictIEq(BigDictIEq dict) { m_dict = dict; } #endregion #region Properties /// /// Returns the number of items currently contained in the ConcurrentBigDictIEq /// as long. /// public long LongCount { get { return m_dict.LongCount; } } /// /// Returns the number of items currently contained in the ConcurrentBigDictIEq /// as long. /// public ulong Capacity { get { return m_dict.Capacity; } set { m_dict.Capacity = value; } } /// /// Return the non-concurrent contained ConcurrentBigDictIEq. /// public BigDictIEq NonConcurrent { get { return m_dict; } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the ConcurrentBigDictIEq acts as a stack. /// /// /// public TValue this[TKey key] { get { Monitor.Enter(this); try { return m_dict[key]; } finally { Monitor.Exit(this); } } set { Monitor.Enter(this); try { m_dict[key] = value; } finally { Monitor.Exit(this); } } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the ConcurrentBigDictIEq. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the ConcurrentBigDictIEq /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((TKey)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentBigDictIEq. /// public void Add(TKey key, TValue value) { Monitor.Enter(this); try { m_dict.Add(key, value); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentBigDictIEq. /// public void Add(TKey key, long hash, TValue value) { Monitor.Enter(this); try { m_dict.Add(key, hash, value); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentBigDictIEq. /// public bool TryAdd(TKey key, TValue value) { Monitor.Enter(this); try { return m_dict.TryAdd(key, value); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the ConcurrentBigDictIEq. /// public bool TryAdd(TKey key, long hash, TValue value) { Monitor.Enter(this); try { return m_dict.TryAdd(key, hash, value); } finally { Monitor.Exit(this); } } /// /// Add the supplied item to the ConcurrentBigDictIEq. /// public void Add(KeyValuePair item) { Monitor.Enter(this); try { m_dict.Add(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Add the supplied items to the ConcurrentBigDictIEq. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the ConcurrentBigDictIEq contains the item with the supplied /// key. /// public bool Contains(TKey key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentBigDictIEq contains the item with the supplied /// key. /// public bool Contains(TKey key, long hash) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentBigDictIEq contains the item with the supplied /// key. /// public bool ContainsKey(TKey key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentBigDictIEq contains the item with the supplied /// key. /// public bool ContainsKey(TKey key, long hash) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentBigDictIEq contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, TValue value) { Monitor.Enter(this); try { return m_dict.Contains(key, value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentBigDictIEq contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, long hash, TValue value) { Monitor.Enter(this); try { return m_dict.Contains(key, value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentBigDictIEq contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { Monitor.Enter(this); try { return m_dict.Contains(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentBigDictIEq contains the given value. /// public bool ContainsValue(TValue value) { Monitor.Enter(this); try { return m_dict.ContainsValue(value); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key) { Monitor.Enter(this); try { return m_dict.Get(key); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the ConcurrentBigDictIEq and returned. /// public TValue GetOrCreate(TKey key, Func creator) { Monitor.Enter(this); try { return m_dict.GetOrCreate(key, creator); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, TValue defaultValue) { Monitor.Enter(this); try { return m_dict.Get(key); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key, long hash) { Monitor.Enter(this); try { return m_dict.Get(key, hash); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the ConcurrentBigDictIEq and returned. /// public TValue GetOrCreate(TKey key, long hash, Func creator) { Monitor.Enter(this); try { return m_dict.GetOrCreate(key, hash, creator); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, long hash, TValue defaultValue) { Monitor.Enter(this); try { return m_dict.Get(key, hash); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(TKey key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, out TValue value) { Monitor.Enter(this); try { return m_dict.TryGetValue(key, out value); } finally { Monitor.Exit(this); } } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, long hash, out TValue value) { Monitor.Enter(this); try { return m_dict.TryGetValue(key, hash, out value); } finally { Monitor.Exit(this); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(TKey key, long skip) { Monitor.Enter(this); try { return m_dict.ValueWithKeySkip(key, skip); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key from the ConcurrentBigDictIEq and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(TKey key) { Monitor.Enter(this); try { return m_dict.GetAndRemove(key); } finally { Monitor.Exit(this); } } /// /// Try to remove the item with the supplied key from the ConcurrentBigDictIEq. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key) { TValue value; Monitor.Enter(this); try { return m_dict.TryRemove(key, out value); } finally { Monitor.Exit(this); } } /// /// Try to remove the item with the supplied key from the ConcurrentBigDictIEq. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key, long hash) { TValue value; Monitor.Enter(this); try { return m_dict.TryRemove(key, hash, out value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key and the supplied value /// from the ConcurrentBigDictIEq. Returns true if the value was removed. /// public bool Remove(TKey key, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key and the supplied value /// from the ConcurrentBigDictIEq. Returns true if the value was removed. /// public bool Remove(TKey key, long hash, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash, value); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied KeyValuePair from the ConcurrentBigDictIEq. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { Monitor.Enter(this); try { return m_dict.TryRemove(item.Key, item.Value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, out TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, out value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, long hash, out TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash, out value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, value); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, long hash, TValue value) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash, value); } finally { Monitor.Exit(this); } } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TKey[] KeysToArray() { return m_dict.KeysToArray(); } /// /// Returns all values in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TValue[] ValuesToArray() { return m_dict.ValuesToArray(); } /// /// Returns all KeyValuePairs in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public KeyValuePair[] ToArray() { return m_dict.ToArray(); } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { m_dict.Clear(); } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyKeysTo(TKey[] array, long index) { Monitor.Enter(this); try { m_dict.CopyKeysTo(array, index); } finally { Monitor.Exit(this); } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyValuesTo(TValue[] array, long index) { Monitor.Enter(this); try { m_dict.CopyValuesTo(array, index); } finally { Monitor.Exit(this); } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(KeyValuePair[] array, long index) { Monitor.Enter(this); try { m_dict.CopyTo(array, index); } finally { Monitor.Exit(this); } } #endregion } #endregion #region ConcurrentBigDictSetIEq /// /// A ConcurrentBigDictSetIEq is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class ConcurrentBigDictSetIEq where TKey : IEquatable { private readonly BigDictSetIEq m_dict; #region Constructors /// /// A ConcurrentBigDictSetIEq can only be concstructed by wrapping its non-concurrent /// counterpart. /// public ConcurrentBigDictSetIEq(BigDictSetIEq dict) { m_dict = dict; } #endregion #region Properties /// /// Returns the number of items currently contained in the ConcurrentBigDictSetIEq /// as long. /// public long LongCount { get { return m_dict.LongCount; } } /// /// Returns the number of items currently contained in the ConcurrentBigDictSetIEq /// as long. /// public ulong Capacity { get { return m_dict.Capacity; } set { m_dict.Capacity = value; } } /// /// Return the non-concurrent contained ConcurrentBigDictSetIEq. /// public BigDictSetIEq NonConcurrent { get { return m_dict; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the ConcurrentBigDictSetIEq. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the ConcurrentBigDictSetIEq /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((TKey)objkey); } /// /// Add the item with the supplied key /// to the ConcurrentBigDictSetIEq. /// public bool Add(TKey key) { Monitor.Enter(this); try { return m_dict.Add(key); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key /// to the ConcurrentBigDictSetIEq. /// public bool Add(TKey key, long hash) { Monitor.Enter(this); try { return m_dict.Add(key, hash); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key /// to the ConcurrentBigDictSetIEq. /// public bool TryAdd(TKey key) { Monitor.Enter(this); try { return m_dict.TryAdd(key); } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key /// to the ConcurrentBigDictSetIEq. /// public bool TryAdd(TKey key, long hash) { Monitor.Enter(this); try { return m_dict.TryAdd(key, hash); } finally { Monitor.Exit(this); } } /// /// Add the supplied keys to the ConcurrentBigDictSetIEq. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the ConcurrentBigDictSetIEq contains the item with the supplied /// key. /// public bool Contains(TKey key) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Returns true if the ConcurrentBigDictSetIEq contains the item with the supplied /// key. /// public bool Contains(TKey key, long hash) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key /// from the ConcurrentBigDictSetIEq. Returns true if the value was removed. /// public bool Remove(TKey key) { Monitor.Enter(this); try { return m_dict.TryRemove(key); } finally { Monitor.Exit(this); } } /// /// Remove the item with the supplied key /// from the ConcurrentBigDictSetIEq. Returns true if the value was removed. /// public bool Remove(TKey key, long hash) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key) { Monitor.Enter(this); try { return m_dict.TryRemove(key); } finally { Monitor.Exit(this); } } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key, long hash) { Monitor.Enter(this); try { return m_dict.TryRemove(key, hash); } finally { Monitor.Exit(this); } } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TKey[] ToArray() { return m_dict.ToArray(); } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { m_dict.Clear(); } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(TKey[] array, long index) { Monitor.Enter(this); try { m_dict.CopyTo(array, index); } finally { Monitor.Exit(this); } } #endregion } #endregion #region FastConcurrentDictIEq /// /// A FastConcurrentDictIEq is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class FastConcurrentDictIEq : IIntCountable, ICountableDict, IDict, IEnumerable, IEnumerable> where TKey : IEquatable { private long m_version; private uint m_capacity; private NextHashKeyValue[] m_firstArray; private HashKeyValueNext[] m_extraArray; private uint m_count; private uint m_increaseThreshold; private uint m_decreaseThreshold; private readonly bool m_doNotStackDuplicateKeys; private int m_freeIndex; private int m_capacityIndex; private uint m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a FastConcurrentDictIEq that autmatically grows and shrinks as necessary. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentDictIEq acts as a stack for all items with the same key. /// public FastConcurrentDictIEq(bool stackDuplicateKeys = false) : this(DictConstant.PrimeSizes[0], (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a FastConcurrentDictIEq that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentDictIEq acts as a stack for all items with the same key. /// public FastConcurrentDictIEq(int initialCapacity) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, false) { } /// /// Create a FastConcurrentDictIEq that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentDictIEq acts as a stack for all items with the same key. /// public FastConcurrentDictIEq(int initialCapacity, bool stackDuplicateKeys) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a FastConcurrentDictIEq and initialize it to contain the supplied /// items. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentDictIEq acts as a stack for all items with the same key. /// public FastConcurrentDictIEq(IEnumerable> items, bool stackDuplicateKeys = false) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity, stackDuplicateKeys) { foreach (var item in items) Add(item); } private FastConcurrentDictIEq( uint firstCapacity, uint extraCapacity, bool stackDuplicateKeys = false) { m_version = 0; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_doNotStackDuplicateKeys = !stackDuplicateKeys; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextHashKeyValue[m_capacity]; m_extraArray = new HashKeyValueNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the FastConcurrentDictIEq. /// public int Count { get { return (int)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentDictIEq /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentDictIEq /// as long. /// public uint Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { Monitor.Enter(this); try { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the FastConcurrentDictIEq. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { Monitor.Enter(this); try { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } public IEnumerable> Items { get { return KeyValuePairs; } } /// /// Returns all keys in the dictionary. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Keys { get { Monitor.Enter(this); try { var version = m_version; for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var k = m_firstArray[fi].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { k = m_extraArray[ei].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type KeyType { get { return typeof(TKey); } } /// /// Returns all values in the FastConcurrentDictIEq. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Values { get { Monitor.Enter(this); try { var version = m_version; for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var v = m_firstArray[fi].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { v = m_extraArray[ei].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type ValueType { get { return typeof(TValue); } } /// /// Returns all key value pairs in the FastConcurrentDictIEq. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable> KeyValuePairs { get { Monitor.Enter(this); try { var version = m_version; for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var kvp = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { kvp = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } /// /// Returns all key value pairs in the FastConcurrentDictIEq, in such a way, /// that the stack order is correct when the pairs are put into a /// new FastConcurrentDictIEq in the order they are returned. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable> KeyValuePairsForStorage { get { Monitor.Enter(this); try { var version = m_version; var stack = new Stack(); for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; while (ei > 0) { stack.Push(ei); ei = m_extraArray[ei].Next; } var kvp = default(KeyValuePair); while (stack.Count > 0) { ei = stack.Pop(); kvp = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } kvp = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } } finally { Monitor.Exit(this); } } } public IEnumerable<(object, object)> ObjectPairs { get { foreach (var kvp in KeyValuePairsForStorage) yield return (kvp.Key, kvp.Value); } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the FastConcurrentDictIEq acts as a stack. /// /// /// public TValue this[TKey key] { get { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } set { var hash = key.GetHashCode(); Monitor.Enter(this); try { ++m_version; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { m_firstArray[fi].Item.Value = value; return; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_extraArray[ei].Item.Value = value; return; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the FastConcurrentDictIEq. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the FastConcurrentDictIEq /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((TKey)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentDictIEq. /// public void Add(TKey key, TValue value) { var hash = key.GetHashCode(); Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentDictIEq. /// public void Add(TKey key, int hash, TValue value) { Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentDictIEq. /// public bool TryAdd(TKey key, TValue value) { var hash = key.GetHashCode(); Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentDictIEq. /// public bool TryAdd(TKey key, int hash, TValue value) { Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } return true; } /// /// Add the supplied item to the FastConcurrentDictIEq. /// public void Add(KeyValuePair item) { Add(item.Key, item.Value); } /// /// Add the supplied items to the FastConcurrentDictIEq. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the FastConcurrentDictIEq contains the item with the supplied /// key. /// public bool Contains(TKey key) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentDictIEq contains the item with the supplied /// key. /// public bool Contains(TKey key, int hash) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentDictIEq contains the item with the supplied /// key. /// public bool ContainsKey(TKey key) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentDictIEq contains the item with the supplied /// key. /// public bool ContainsKey(TKey key, int hash) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentDictIEq contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, TValue value) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentDictIEq contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, int hash, TValue value) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentDictIEq contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { return Contains(item.Key, item.Value); } /// /// Returns true if the FastConcurrentDictIEq contains the given value. /// public bool ContainsValue(TValue value) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } return false; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the FastConcurrentDictIEq and returned. /// public TValue GetOrCreate(TKey key, Func creator) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } finally { Monitor.Exit(this); } } TValue AddCreated(TKey key, int hash, TValue value) { while (true) { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ei = m_firstArray[fi].Next; ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = m_firstArray[fi].Next; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, TValue defaultValue) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key, int hash) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the FastConcurrentDictIEq and returned. /// public TValue GetOrCreate(TKey key, int hash, Func creator) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, int hash, TValue defaultValue) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(TKey key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, out TValue value) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, int hash, out TValue value) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Return all the value with the given key. This method is only /// useful if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// public IEnumerable ValuesWithKey(TKey key) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var version = m_version; var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) yield break; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { var v = m_firstArray[fi].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { var v = m_extraArray[ei].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(TKey key, int skip) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (skip == 0) return m_firstArray[fi].Item.Value; --skip; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { if (skip == 0) return m_extraArray[ei].Item.Value; --skip; } ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Remove the item with the supplied key from the FastConcurrentDictIEq and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(TKey key) { TValue value; if (!TryRemove(key, out value)) throw new KeyNotFoundException(); return value; } /// /// Try to remove the item with the supplied key from the FastConcurrentDictIEq. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key) { TValue value; return TryRemove(key, out value); } /// /// Try to remove the item with the supplied key from the FastConcurrentDictIEq. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key, int hash) { TValue value; return TryRemove(key, hash, out value); } /// /// Remove the item with the supplied key and the supplied value /// from the FastConcurrentDictIEq. Returns true if the value was removed. /// public bool Remove(TKey key, TValue value) { return TryRemove(key, value); } /// /// Remove the item with the supplied key and the supplied value /// from the FastConcurrentDictIEq. Returns true if the value was removed. /// public bool Remove(TKey key, int hash, TValue value) { return TryRemove(key, hash, value); } /// /// Remove the item with the supplied KeyValuePair from the FastConcurrentDictIEq. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { return TryRemove(item.Key, item.Value); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, out TValue value) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, int hash, out TValue value) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, TValue value) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key) && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, int hash, TValue value) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValue); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValue); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key) && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValue); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TKey[] KeysToArray() { var array = new TKey[m_count]; CopyKeysTo(array, 0); return array; } /// /// Returns all values in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TValue[] ValuesToArray() { var array = new TValue[m_count]; CopyValuesTo(array, 0); return array; } /// /// Returns all KeyValuePairs in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public KeyValuePair[] ToArray() { var array = new KeyValuePair[m_count]; CopyTo(array, 0); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { ++m_version; m_firstArray.Set(default(NextHashKeyValue)); m_extraArray.Set(default(HashKeyValueNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyKeysTo(TKey[] array, int index) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyValuesTo(TValue[] array, int index) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Value; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(KeyValuePair[] array, int index) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { array[index++] = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } #endregion #region IEnumerable> Members IEnumerator> IEnumerable>.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region Private Helper Methods private uint ComputeIncreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_maxFillFactor); } private uint ComputeDecreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_minFillFactor); } private static int AddSlotsToFreeList( HashKeyValueNext[] extraArray, int start) { var length = extraArray.Length - 1; for (int i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( HashKeyValue item, NextHashKeyValue[] firstArray, uint capacity, ref HashKeyValueNext[] extraArray, ref int freeIndex, ref uint extraCount) { var fi = ((uint)item.Hash) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(uint newCapacity, uint oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextHashKeyValue[newCapacity]; var extraArray = new HashKeyValueNext[ System.Math.Max((int)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); uint newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { uint fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((uint)m_count - m_extraCount, oldCapacity, m_extraCount, (uint)m_extraArray.Length, (uint)m_count - newExtraCount, newCapacity, newExtraCount, (uint)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( uint oldFirstCount, uint oldCapacity, uint oldExtraCount, uint oldExtraCapacity, uint newFirstCount, uint newCapacity, uint newExtraCount, uint newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region FastConcurrentDictSetIEq /// /// A FastConcurrentDictSetIEq is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class FastConcurrentDictSetIEq : IIntCountable, ICountableDictSet, IDictSet, IEnumerable, IEnumerable where TKey : IEquatable { private long m_version; private uint m_capacity; private NextHashKey[] m_firstArray; private HashKeyNext[] m_extraArray; private uint m_count; private uint m_increaseThreshold; private uint m_decreaseThreshold; private int m_freeIndex; private int m_capacityIndex; private uint m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a FastConcurrentDictSetIEq that autmatically grows and shrinks as necessary. /// public FastConcurrentDictSetIEq() : this(DictConstant.PrimeSizes[0], (uint)DictConstant.MinExtraCapacity) { } /// /// Create a FastConcurrentDictSetIEq that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// public FastConcurrentDictSetIEq(int initialCapacity) : this(System.Math.Max((uint)initialCapacity, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity) { } /// /// Create a FastConcurrentDictSetIEq and initialize it to contain the supplied /// items. /// public FastConcurrentDictSetIEq(IEnumerable items) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes[0]), (uint)DictConstant.MinExtraCapacity) { foreach (var item in items) Add(item); } private FastConcurrentDictSetIEq( uint firstCapacity, uint extraCapacity) { m_version = 0; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextHashKey[m_capacity]; m_extraArray = new HashKeyNext[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the FastConcurrentDictSetIEq. /// public int Count { get { return (int)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentDictSetIEq /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentDictSetIEq /// as long. /// public uint Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { Monitor.Enter(this); try { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the FastConcurrentDictSetIEq. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { Monitor.Enter(this); try { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } public IEnumerable Items { get { return Keys; } } /// /// Returns all keys in the dictionary. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Keys { get { Monitor.Enter(this); try { var version = m_version; for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var k = m_firstArray[fi].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { k = m_extraArray[ei].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type KeyType { get { return typeof(TKey); } } public IEnumerable Objects { get { foreach (object obj in Keys) yield return obj; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the FastConcurrentDictSetIEq. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the FastConcurrentDictSetIEq /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((TKey)objkey); } /// /// Add the item with the supplied key /// to the FastConcurrentDictSetIEq. /// public bool Add(TKey key) { var hash = key.GetHashCode(); Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key /// to the FastConcurrentDictSetIEq. /// public bool Add(TKey key, int hash) { Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key /// to the FastConcurrentDictSetIEq. /// public bool TryAdd(TKey key) { var hash = key.GetHashCode(); Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key /// to the FastConcurrentDictSetIEq. /// public bool TryAdd(TKey key, int hash) { Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the supplied keys to the FastConcurrentDictSetIEq. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the FastConcurrentDictSetIEq contains the item with the supplied /// key. /// public bool Contains(TKey key) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentDictSetIEq contains the item with the supplied /// key. /// public bool Contains(TKey key, int hash) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Remove the item with the supplied key /// from the FastConcurrentDictSetIEq. Returns true if the value was removed. /// public bool Remove(TKey key) { return TryRemove(key); } /// /// Remove the item with the supplied key /// from the FastConcurrentDictSetIEq. Returns true if the value was removed. /// public bool Remove(TKey key, int hash) { return TryRemove(key, hash); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key) { var hash = key.GetHashCode(); Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKey); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKey); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKey); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKey); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key, int hash) { Monitor.Enter(this); try { var fi = ((uint)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKey); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKey); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKey); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKey); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TKey[] ToArray() { var array = new TKey[m_count]; CopyTo(array, 0); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { ++m_version; m_firstArray.Set(default(NextHashKey)); m_extraArray.Set(default(HashKeyNext)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(TKey[] array, int index) { Monitor.Enter(this); try { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return Keys.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return Keys.GetEnumerator(); } #endregion #region Private Helper Methods private uint ComputeIncreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_maxFillFactor); } private uint ComputeDecreaseThreshold(uint capacity) { return (uint)(capacity * (double)m_minFillFactor); } private static int AddSlotsToFreeList( HashKeyNext[] extraArray, int start) { var length = extraArray.Length - 1; for (int i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( HashKey item, NextHashKey[] firstArray, uint capacity, ref HashKeyNext[] extraArray, ref int freeIndex, ref uint extraCount) { var fi = ((uint)item.Hash) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(uint newCapacity, uint oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextHashKey[newCapacity]; var extraArray = new HashKeyNext[ System.Math.Max((int)DictConstant.MinExtraCapacity, m_extraArray.Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); uint newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (uint fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { uint fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list int head = -1; do { int next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((uint)m_count - m_extraCount, oldCapacity, m_extraCount, (uint)m_extraArray.Length, (uint)m_count - newExtraCount, newCapacity, newExtraCount, (uint)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( uint oldFirstCount, uint oldCapacity, uint oldExtraCount, uint oldExtraCapacity, uint newFirstCount, uint newCapacity, uint newExtraCount, uint newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region FastConcurrentBigDictIEq /// /// A FastConcurrentBigDictIEq is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class FastConcurrentBigDictIEq : ICountableDict, IDict, IEnumerable, IEnumerable> where TKey : IEquatable { private long m_version; private readonly Func m_hfun; private ulong m_capacity; private NextHashKeyValueLong[] m_firstArray; private HashKeyValueNextLong[] m_extraArray; private ulong m_count; private ulong m_increaseThreshold; private ulong m_decreaseThreshold; private readonly bool m_doNotStackDuplicateKeys; private long m_freeIndex; private int m_capacityIndex; private ulong m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a FastConcurrentBigDictIEq that autmatically grows and shrinks as necessary. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentBigDictIEq acts as a stack for all items with the same key. /// public FastConcurrentBigDictIEq(Func hfun, bool stackDuplicateKeys = false) : this(hfun, DictConstant.PrimeSizesLong[0], (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a FastConcurrentBigDictIEq that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentBigDictIEq acts as a stack for all items with the same key. /// public FastConcurrentBigDictIEq(Func hfun, long initialCapacity) : this(hfun, System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity, false) { } /// /// Create a FastConcurrentBigDictIEq that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentBigDictIEq acts as a stack for all items with the same key. /// public FastConcurrentBigDictIEq(Func hfun, long initialCapacity, bool stackDuplicateKeys) : this(hfun, System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } /// /// Create a FastConcurrentBigDictIEq and initialize it to contain the supplied /// items. /// If the optional parameter stackDuplicateKeys is set to true, the /// FastConcurrentBigDictIEq acts as a stack for all items with the same key. /// public FastConcurrentBigDictIEq(Func hfun, IEnumerable> items, bool stackDuplicateKeys = false) : this(hfun, Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity, stackDuplicateKeys) { foreach (var item in items) Add(item); } private FastConcurrentBigDictIEq( Func hfun, ulong firstCapacity, ulong extraCapacity, bool stackDuplicateKeys = false) { m_version = 0; m_hfun = hfun; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_doNotStackDuplicateKeys = !stackDuplicateKeys; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizesLong[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizesLong[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextHashKeyValueLong[m_capacity]; m_extraArray = new HashKeyValueNextLong[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the FastConcurrentBigDictIEq /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentBigDictIEq /// as long. /// public ulong Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { Monitor.Enter(this); try { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the FastConcurrentBigDictIEq. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { Monitor.Enter(this); try { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } public IEnumerable> Items { get { return KeyValuePairs; } } /// /// Returns all keys in the dictionary. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Keys { get { Monitor.Enter(this); try { var version = m_version; for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var k = m_firstArray[fi].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { k = m_extraArray[ei].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type KeyType { get { return typeof(TKey); } } /// /// Returns all values in the FastConcurrentBigDictIEq. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Values { get { Monitor.Enter(this); try { var version = m_version; for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var v = m_firstArray[fi].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { v = m_extraArray[ei].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type ValueType { get { return typeof(TValue); } } /// /// Returns all key value pairs in the FastConcurrentBigDictIEq. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable> KeyValuePairs { get { Monitor.Enter(this); try { var version = m_version; for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var kvp = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { kvp = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } /// /// Returns all key value pairs in the FastConcurrentBigDictIEq, in such a way, /// that the stack order is correct when the pairs are put into a /// new FastConcurrentBigDictIEq in the order they are returned. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable> KeyValuePairsForStorage { get { Monitor.Enter(this); try { var version = m_version; var stack = new Stack(); for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; while (ei > 0) { stack.Push(ei); ei = m_extraArray[ei].Next; } var kvp = default(KeyValuePair); while (stack.Count > 0) { ei = stack.Pop(); kvp = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } kvp = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } } finally { Monitor.Exit(this); } } } public IEnumerable<(object, object)> ObjectPairs { get { foreach (var kvp in KeyValuePairsForStorage) yield return (kvp.Key, kvp.Value); } } #endregion #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the FastConcurrentBigDictIEq acts as a stack. /// /// /// public TValue this[TKey key] { get { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } set { var hash = m_hfun(key); Monitor.Enter(this); try { ++m_version; if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { m_firstArray[fi].Item.Value = value; return; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_extraArray[ei].Item.Value = value; return; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.LongLength; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } } #endregion #region Public Methods /// /// Add the item with supplied key and the supplied value /// both supplied as generic objects, to the FastConcurrentBigDictIEq. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the FastConcurrentBigDictIEq /// and this will fail if they are of different types. /// public void AddObject(object objkey, object objvalue) { Add((TKey)objkey, (TValue)objvalue); } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentBigDictIEq. /// public void Add(TKey key, TValue value) { var hash = m_hfun(key); Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentBigDictIEq. /// public void Add(TKey key, long hash, TValue value) { Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { throw new ArgumentException("duplicate key"); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { throw new ArgumentException("duplicate key"); } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentBigDictIEq. /// public bool TryAdd(TKey key, TValue value) { var hash = m_hfun(key); Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key and the supplied value /// to the FastConcurrentBigDictIEq. /// public bool TryAdd(TKey key, long hash, TValue value) { Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return true; } if (m_doNotStackDuplicateKeys) { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; } finally { Monitor.Exit(this); } return true; } /// /// Add the supplied item to the FastConcurrentBigDictIEq. /// public void Add(KeyValuePair item) { Add(item.Key, item.Value); } /// /// Add the supplied items to the FastConcurrentBigDictIEq. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } /// /// Returns true if the FastConcurrentBigDictIEq contains the item with the supplied /// key. /// public bool Contains(TKey key) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentBigDictIEq contains the item with the supplied /// key. /// public bool Contains(TKey key, long hash) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentBigDictIEq contains the item with the supplied /// key. /// public bool ContainsKey(TKey key) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentBigDictIEq contains the item with the supplied /// key. /// public bool ContainsKey(TKey key, long hash) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentBigDictIEq contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, TValue value) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentBigDictIEq contains the item with the supplied /// key and the supplied value. /// public bool Contains(TKey key, long hash, TValue value) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentBigDictIEq contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair item) { return Contains(item.Key, item.Value); } /// /// Returns true if the FastConcurrentBigDictIEq contains the given value. /// public bool ContainsValue(TValue value) { Monitor.Enter(this); try { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } return false; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the FastConcurrentBigDictIEq and returned. /// public TValue GetOrCreate(TKey key, Func creator) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } finally { Monitor.Exit(this); } } TValue AddCreated(TKey key, long hash, TValue value) { while (true) { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ei = m_firstArray[fi].Next; ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = m_firstArray[fi].Next; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; m_firstArray[fi].Item.Value = value; return value; } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, TValue defaultValue) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Throws an exception if the element is not found. This is an alias of the indexer. /// public TValue Get(TKey key, long hash) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Get the element with the supplied key. /// If the element is not found, the supplied creator is called to create /// a new element that is added to the FastConcurrentBigDictIEq and returned. /// public TValue GetOrCreate(TKey key, long hash, Func creator) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { var value = creator(key); return AddCreated(key, hash, value); } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } var val = creator(key); return AddCreated(key, hash, val); } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. /// Returns the supplied default value if the element is not found. /// public TValue Get(TKey key, long hash, TValue defaultValue) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return defaultValue; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } return defaultValue; } finally { Monitor.Exit(this); } } /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(TKey key) { return Get(key, default(TValue)); } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, out TValue value) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(TKey key, long hash, out TValue value) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Return all the value with the given key. This method is only /// useful if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// public IEnumerable ValuesWithKey(TKey key) { var hash = m_hfun(key); Monitor.Enter(this); try { var version = m_version; var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) yield break; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { var v = m_firstArray[fi].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { var v = m_extraArray[ei].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } } /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(TKey key, long skip) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (skip == 0) return m_firstArray[fi].Item.Value; --skip; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { if (skip == 0) return m_extraArray[ei].Item.Value; --skip; } ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } throw new KeyNotFoundException(); } /// /// Remove the item with the supplied key from the FastConcurrentBigDictIEq and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(TKey key) { TValue value; if (!TryRemove(key, out value)) throw new KeyNotFoundException(); return value; } /// /// Try to remove the item with the supplied key from the FastConcurrentBigDictIEq. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key) { TValue value; return TryRemove(key, out value); } /// /// Try to remove the item with the supplied key from the FastConcurrentBigDictIEq. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(TKey key, long hash) { TValue value; return TryRemove(key, hash, out value); } /// /// Remove the item with the supplied key and the supplied value /// from the FastConcurrentBigDictIEq. Returns true if the value was removed. /// public bool Remove(TKey key, TValue value) { return TryRemove(key, value); } /// /// Remove the item with the supplied key and the supplied value /// from the FastConcurrentBigDictIEq. Returns true if the value was removed. /// public bool Remove(TKey key, long hash, TValue value) { return TryRemove(key, hash, value); } /// /// Remove the item with the supplied KeyValuePair from the FastConcurrentBigDictIEq. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair item) { return TryRemove(item.Key, item.Value); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, out TValue value) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValueLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValueLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found, which is returned via the out /// parameter. /// public bool TryRemove(TKey key, long hash, out TValue value) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { value = m_firstArray[fi].Item.Value; if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValueLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { value = m_extraArray[ei].Item.Value; m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { value = m_extraArray[ni].Item.Value; m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValueLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } value = default(TValue); } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, TValue value) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValueLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key) && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValueLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(TKey key, long hash, TValue value) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key) && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyValueLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key) && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyValueLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key) && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyValueLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TKey[] KeysToArray() { var array = new TKey[m_count]; CopyKeysTo(array, 0L); return array; } /// /// Returns all values in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TValue[] ValuesToArray() { var array = new TValue[m_count]; CopyValuesTo(array, 0L); return array; } /// /// Returns all KeyValuePairs in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public KeyValuePair[] ToArray() { var array = new KeyValuePair[m_count]; CopyTo(array, 0L); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { ++m_version; m_firstArray.Set(default(NextHashKeyValueLong)); m_extraArray.Set(default(HashKeyValueNextLong)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyKeysTo(TKey[] array, long index) { Monitor.Enter(this); try { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } /// /// Copies all values in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyValuesTo(TValue[] array, long index) { Monitor.Enter(this); try { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Value; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(KeyValuePair[] array, long index) { Monitor.Enter(this); try { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = new KeyValuePair( m_firstArray[fi].Item.Key, m_firstArray[fi].Item.Value); while (ei > 0) { array[index++] = new KeyValuePair( m_extraArray[ei].Item.Key, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } #endregion #region IEnumerable> Members IEnumerator> IEnumerable>.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region Private Helper Methods private ulong ComputeIncreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_maxFillFactor); } private ulong ComputeDecreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_minFillFactor); } private static long AddSlotsToFreeList( HashKeyValueNextLong[] extraArray, long start) { var length = extraArray.Length - 1; for (long i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizesLong[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizesLong[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( HashKeyValueLong item, NextHashKeyValueLong[] firstArray, ulong capacity, ref HashKeyValueNextLong[] extraArray, ref long freeIndex, ref ulong extraCount) { var fi = ((ulong)item.Hash) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(ulong newCapacity, ulong oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextHashKeyValueLong[newCapacity]; var extraArray = new HashKeyValueNextLong[ System.Math.Max((long)DictConstant.MinExtraCapacity, m_extraArray.LongLength / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); ulong newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { ulong fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((ulong)m_count - m_extraCount, oldCapacity, m_extraCount, (ulong)m_extraArray.Length, (ulong)m_count - newExtraCount, newCapacity, newExtraCount, (ulong)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( ulong oldFirstCount, ulong oldCapacity, ulong oldExtraCount, ulong oldExtraCapacity, ulong newFirstCount, ulong newCapacity, ulong newExtraCount, ulong newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region FastConcurrentBigDictSetIEq /// /// A FastConcurrentBigDictSetIEq is an alternate implementation of a HashSet. /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class FastConcurrentBigDictSetIEq : ICountableDictSet, IDictSet, IEnumerable, IEnumerable where TKey : IEquatable { private long m_version; private readonly Func m_hfun; private ulong m_capacity; private NextHashKeyLong[] m_firstArray; private HashKeyNextLong[] m_extraArray; private ulong m_count; private ulong m_increaseThreshold; private ulong m_decreaseThreshold; private long m_freeIndex; private int m_capacityIndex; private ulong m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; #region Constructors /// /// Create a FastConcurrentBigDictSetIEq that autmatically grows and shrinks as necessary. /// public FastConcurrentBigDictSetIEq(Func hfun) : this(hfun, DictConstant.PrimeSizesLong[0], (ulong)DictConstant.MinExtraCapacity) { } /// /// Create a FastConcurrentBigDictSetIEq that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. /// public FastConcurrentBigDictSetIEq(Func hfun, long initialCapacity) : this(hfun, System.Math.Max((ulong)initialCapacity, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity) { } /// /// Create a FastConcurrentBigDictSetIEq and initialize it to contain the supplied /// items. /// public FastConcurrentBigDictSetIEq(Func hfun, IEnumerable items) : this(hfun, Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizesLong[0]), (ulong)DictConstant.MinExtraCapacity) { foreach (var item in items) Add(item); } private FastConcurrentBigDictSetIEq( Func hfun, ulong firstCapacity, ulong extraCapacity) { m_version = 0; m_hfun = hfun; m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizesLong[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizesLong[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new NextHashKeyLong[m_capacity]; m_extraArray = new HashKeyNextLong[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } #endregion #region Properties /// /// Returns the number of items currently contained in the FastConcurrentBigDictSetIEq /// as long. /// public long LongCount { get { return (long)m_count; } } /// /// Returns the number of items currently contained in the FastConcurrentBigDictSetIEq /// as long. /// public ulong Capacity { get { return m_capacity; } set { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); } } /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { Monitor.Enter(this); try { m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the FastConcurrentBigDictSetIEq. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { Monitor.Enter(this); try { m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); } finally { Monitor.Exit(this); } } } public IEnumerable Items { get { return Keys; } } /// /// Returns all keys in the dictionary. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. /// public IEnumerable Keys { get { Monitor.Enter(this); try { var version = m_version; for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; var k = m_firstArray[fi].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); while (ei > 0) { k = m_extraArray[ei].Item.Key; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } } public Type KeyType { get { return typeof(TKey); } } public IEnumerable Objects { get { foreach (object obj in Keys) yield return obj; } } #endregion #region Public Methods /// /// Add the item with supplied key /// both supplied as generic objects, to the FastConcurrentBigDictSetIEq. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the FastConcurrentBigDictSetIEq /// and this will fail if they are of different types. /// public bool AddObject(object objkey) { return Add((TKey)objkey); } /// /// Add the item with the supplied key /// to the FastConcurrentBigDictSetIEq. /// public bool Add(TKey key) { var hash = m_hfun(key); Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key /// to the FastConcurrentBigDictSetIEq. /// public bool Add(TKey key, long hash) { Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key /// to the FastConcurrentBigDictSetIEq. /// public bool TryAdd(TKey key) { var hash = m_hfun(key); Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the item with the supplied key /// to the FastConcurrentBigDictSetIEq. /// public bool TryAdd(TKey key, long hash) { Monitor.Enter(this); try { if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; ++m_version; m_firstArray[fi].Next = -1; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; return true; } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { return false; } while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { return false; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_version; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; m_firstArray[fi].Item.Hash = hash; m_firstArray[fi].Item.Key = key; } finally { Monitor.Exit(this); } return true; } /// /// Add the supplied keys to the FastConcurrentBigDictSetIEq. /// public void AddRange(IEnumerable keys) { foreach (var key in keys) Add(key); } /// /// Returns true if the FastConcurrentBigDictSetIEq contains the item with the supplied /// key. /// public bool Contains(TKey key) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Returns true if the FastConcurrentBigDictSetIEq contains the item with the supplied /// key. /// public bool Contains(TKey key, long hash) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) return true; while (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) return true; ei = m_extraArray[ei].Next; } } finally { Monitor.Exit(this); } return false; } /// /// Remove the item with the supplied key /// from the FastConcurrentBigDictSetIEq. Returns true if the value was removed. /// public bool Remove(TKey key) { return TryRemove(key); } /// /// Remove the item with the supplied key /// from the FastConcurrentBigDictSetIEq. Returns true if the value was removed. /// public bool Remove(TKey key, long hash) { return TryRemove(key, hash); } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key) { var hash = m_hfun(key); Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found. /// public bool TryRemove(TKey key, long hash) { Monitor.Enter(this); try { var fi = ((ulong)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { return false; } if (m_firstArray[fi].Item.Hash == hash && key.Equals(m_firstArray[fi].Item.Key)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(HashKeyLong); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyLong); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } if (ei > 0) { if (m_extraArray[ei].Item.Hash == hash && key.Equals(m_extraArray[ei].Item.Key)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(HashKeyLong); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item.Hash == hash && key.Equals(m_extraArray[ni].Item.Key)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(HashKeyLong); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); ++m_version; return true; } } } } finally { Monitor.Exit(this); } return false; } /// /// Returns all keys in the dictionary as an array. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public TKey[] ToArray() { var array = new TKey[m_count]; CopyTo(array, 0L); return array; } /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { Monitor.Enter(this); try { ++m_version; m_firstArray.Set(default(NextHashKeyLong)); m_extraArray.Set(default(HashKeyNextLong)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; } finally { Monitor.Exit(this); } } /// /// Copies all keys in the dictionary to the supplied /// array starting at the supplied index. /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. /// public void CopyTo(TKey[] array, long index) { Monitor.Enter(this); try { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item.Key; while (ei > 0) { array[index++] = m_extraArray[ei].Item.Key; ei = m_extraArray[ei].Next; } } } finally { Monitor.Exit(this); } } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return Keys.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return Keys.GetEnumerator(); } #endregion #region Private Helper Methods private ulong ComputeIncreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_maxFillFactor); } private ulong ComputeDecreaseThreshold(ulong capacity) { return (ulong)(capacity * (double)m_minFillFactor); } private static long AddSlotsToFreeList( HashKeyNextLong[] extraArray, long start) { var length = extraArray.Length - 1; for (long i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizesLong[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizesLong[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( HashKeyLong item, NextHashKeyLong[] firstArray, ulong capacity, ref HashKeyNextLong[] extraArray, ref long freeIndex, ref ulong extraCount) { var fi = ((ulong)item.Hash) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(ulong newCapacity, ulong oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new NextHashKeyLong[newCapacity]; var extraArray = new HashKeyNextLong[ System.Math.Max((long)DictConstant.MinExtraCapacity, m_extraArray.LongLength / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); ulong newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (ulong fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { ulong fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list long head = -1; do { long next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((ulong)m_count - m_extraCount, oldCapacity, m_extraCount, (ulong)m_extraArray.Length, (ulong)m_count - newExtraCount, newCapacity, newExtraCount, (ulong)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( ulong oldFirstCount, ulong oldCapacity, ulong oldExtraCount, ulong oldExtraCapacity, ulong newFirstCount, ulong newCapacity, ulong newExtraCount, ulong newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion } #endregion #region Support Data Structures [Flags] public enum DictReport { Resize = 0x0001, } public class ConcurrentDataModifiedException : Exception { public ConcurrentDataModifiedException() { } } #endregion #region Internal Helper Structures [StructLayout(LayoutKind.Sequential)] internal struct HashKeyValue { public int Hash; public TKey Key; public Tvalue Value; } [StructLayout(LayoutKind.Sequential)] internal struct NextHashKeyValue { public int Next; public HashKeyValue Item; } [StructLayout(LayoutKind.Sequential)] internal struct HashKeyValueNext { public HashKeyValue Item; public int Next; } [StructLayout(LayoutKind.Sequential)] internal struct HashKey { public int Hash; public TKey Key; } [StructLayout(LayoutKind.Sequential)] internal struct NextHashKey { public int Next; public HashKey Item; } [StructLayout(LayoutKind.Sequential)] internal struct HashKeyNext { public HashKey Item; public int Next; } [StructLayout(LayoutKind.Sequential)] internal struct IntValue { public int Key; public Tvalue Value; } [StructLayout(LayoutKind.Sequential)] internal struct NextIntValue { public int Next; public IntValue Item; } [StructLayout(LayoutKind.Sequential)] internal struct IntValueNext { public IntValue Item; public int Next; } [StructLayout(LayoutKind.Sequential)] internal struct NextInt { public int Next; public int Item; } [StructLayout(LayoutKind.Sequential)] internal struct IntNext { public int Item; public int Next; } [StructLayout(LayoutKind.Sequential)] internal struct HashKeyValueLong { public long Hash; public TKey Key; public Tvalue Value; } [StructLayout(LayoutKind.Sequential)] internal struct NextHashKeyValueLong { public long Next; public HashKeyValueLong Item; } [StructLayout(LayoutKind.Sequential)] internal struct HashKeyValueNextLong { public HashKeyValueLong Item; public long Next; } [StructLayout(LayoutKind.Sequential)] internal struct HashKeyLong { public long Hash; public TKey Key; } [StructLayout(LayoutKind.Sequential)] internal struct NextHashKeyLong { public long Next; public HashKeyLong Item; } [StructLayout(LayoutKind.Sequential)] internal struct HashKeyNextLong { public HashKeyLong Item; public long Next; } [StructLayout(LayoutKind.Sequential)] internal struct LongValue { public long Key; public Tvalue Value; } [StructLayout(LayoutKind.Sequential)] internal struct NextLongValue { public long Next; public LongValue Item; } [StructLayout(LayoutKind.Sequential)] internal struct LongValueNext { public LongValue Item; public long Next; } [StructLayout(LayoutKind.Sequential)] internal struct NextLong { public long Next; public long Item; } [StructLayout(LayoutKind.Sequential)] internal struct LongNext { public long Item; public long Next; } [StructLayout(LayoutKind.Sequential)] internal struct SymbolValue { public Symbol Key; public Tvalue Value; } [StructLayout(LayoutKind.Sequential)] internal struct NextSymbolValue { public int Next; public SymbolValue Item; } [StructLayout(LayoutKind.Sequential)] internal struct SymbolValueNext { public SymbolValue Item; public int Next; } [StructLayout(LayoutKind.Sequential)] internal struct NextSymbol { public int Next; public Symbol Item; } [StructLayout(LayoutKind.Sequential)] internal struct SymbolNext { public Symbol Item; public int Next; } public static class DictConstant { #region Constants public const float MaxFillFactorDefault = 0.8f; // growing avg: (0.8 + 0.4)/2 = 0.6 public const float MinFillFactorDefault = 0.2f; // shrinking avg: (0.4 + 0.2)/2 = 0.3 public const int MinExtraCapacity = 4; public readonly static uint[] PrimeSizes = { /* prime no. prime */ /* 2 3, + 1 = 2^2 */ /* 4 */ 7, // + 1 = 2^3, minimal size /* 6 */ 13, // + 3 = 2^4 /* 11 */ 31, // + 1 = 2^5 /* 18 */ 61, // + 3 = 2^6 /* 31 */ 127, // + 1 = 2^7 /* 54 */ 251, // + 5 = 2^8 /* 97 */ 509, // + 3 = 2^9 /* 172 */ 1021, // + 3 = 2^10 /* 309 */ 2039, // + 9 = 2^11 /* 564 */ 4093, // + 3 = 2^12 /* 1028 */ 8191, // + 1 = 2^13 /* 1900 */ 16381, // + 3 = 2^14 /* 3512 */ 32749, // + 19 = 2^15 /* 6542 */ 65521, // + 15 = 2^16 /* 12251 */ 131071, // + 1 = 2^17 /* 23000 */ 262139, // + 5 = 2^18 /* 43390 */ 524287, // + 1 = 2^19 /* 82025 */ 1048573, // + 3 = 2^20 /* 155611 */ 2097143, // + 9 = 2^21 /* 295947 */ 4194301, // + 3 = 2^22 /* 564163 */ 8388593, // + 15 = 2^23 /* 1077871 */ 16777213, // + 3 = 2^24 /* 2063689 */ 33554393, // + 39 = 2^25 /* 3957809 */ 67108859, // + 5 = 2^26 /* 7603553 */ 134217689, // + 39 = 2^27 /* 14630843 */ 268435399, // + 57 = 2^28 /* 28192750 */ 536870909, // + 3 = 2^29 /* 54400028 */ 1073741789, // + 35 = 2^30 /* 105097565 */ 2147483647, // + 1 = 2^31 /* 203280221 */ 4294967291, // + 5 = 2^32 }; public readonly static ulong[] PrimeSizesLong = { /* prime no. prime */ /* 2 3, + 1 = 2^2 */ /* 4 */ 7, // + 1 = 2^3, minimal size /* 6 */ 13, // + 3 = 2^4 /* 11 */ 31, // + 1 = 2^5 /* 18 */ 61, // + 3 = 2^6 /* 31 */ 127, // + 1 = 2^7 /* 54 */ 251, // + 5 = 2^8 /* 97 */ 509, // + 3 = 2^9 /* 172 */ 1021, // + 3 = 2^10 /* 309 */ 2039, // + 9 = 2^11 /* 564 */ 4093, // + 3 = 2^12 /* 1028 */ 8191, // + 1 = 2^13 /* 1900 */ 16381, // + 3 = 2^14 /* 3512 */ 32749, // + 19 = 2^15 /* 6542 */ 65521, // + 15 = 2^16 /* 12251 */ 131071, // + 1 = 2^17 /* 23000 */ 262139, // + 5 = 2^18 /* 43390 */ 524287, // + 1 = 2^19 /* 82025 */ 1048573, // + 3 = 2^20 /* 155611 */ 2097143, // + 9 = 2^21 /* 295947 */ 4194301, // + 3 = 2^22 /* 564163 */ 8388593, // + 15 = 2^23 /* 1077871 */ 16777213, // + 3 = 2^24 /* 2063689 */ 33554393, // + 39 = 2^25 /* 3957809 */ 67108859, // + 5 = 2^26 /* 7603553 */ 134217689, // + 39 = 2^27 /* 14630843 */ 268435399, // + 57 = 2^28 /* 28192750 */ 536870909, // + 3 = 2^29 /* 54400028 */ 1073741789, // + 35 = 2^30 /* 105097565 */ 2147483647, // + 1 = 2^31 /* 203280221 */ 4294967291, // + 5 = 2^32 /* 393615806 */ 8589934583, // + 9 = 2^33 /* 762939111 */ 17179869143, // + 41 = 2^34 /* 1480206279 */ 34359738337, // + 31 = 2^35 /* 2874398515 */ 68719476731, // + 5 = 2^36 /* 5586502348 */ 137438953447, // + 25 = 2^37 /* 10866266172 */ 274877906899, // + 45 = 2^38 /* 21151907950 */ 549755813881, // + 7 = 2^39 /* 41203088796 */ 1099511627689, // + 87 = 2^40 /* 80316571436 */ 2199023255531, // + 21 = 2^41 /* 156661034233 */ 4398046511093, // + 11 = 2^42 /* 305761713237 */ 8796093022151, // + 57 = 2^43 /* 597116381732 */ 17592186044399, // + 17 = 2^44 }; #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Symbol/Dict_template.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Text; using System.Threading; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# var typea = new[] { "Dict", "DictSet", "IntDict", "IntSet", "SymbolDict", "SymbolSet", //# "BigDict", "BigDictSet", "LongDict", "LongSet" }; //# var tka = new[] { "TKey", "TKey", "int", "int", "Symbol", "Symbol", //# "TKey", "TKey", "long", "long" }; //# var tva = new[] { "TValue", "", "TValue", "", "TValue", "", //# "TValue", "", "TValue", "" }; //# var kia = new[] { 0, 0, 1, 1, 2, 2, 3, 3, 1, 1 }; //# var hfa = new[] { "", "", "", "m_hfun(" }; //# var gha = new[] { ".GetHashCode()", "", ".Id", ")" }; //# var hia = new[] { "HashKeyValue", "HashKey", "IntValue", "int", "SymbolValue", "Symbol", //# "HashKeyValue", "HashKey", "LongValue", "long" }; //# var ha = new[] { ".Hash", ".Hash", ".Key", "", ".Key.Id", ".Id", //# ".Hash", ".Hash", ".Key", "" }; //# var ka = new[] { ".Key", ".Key", ".Key", "", ".Key", "", ".Key", ".Key", ".Key", "" }; //# foreach (var equatable in new bool[] { false, true }) { var eqString = (equatable ? "IEq" : ""); //# foreach (var fast in new bool[] { false, true }) { //# foreach (var concurrent in new bool[] { false, true }) { if (fast && !concurrent) continue; //# for (int ti = 0; ti < typea.Length; ti++) { //# var big = ti >= 6; //# var izero = big ? "0L" : "0"; //# var wrapped = concurrent && !fast; //# var concurrentString = (fast ? "Fast" : "") + (concurrent ? "Concurrent" : ""); //# var type = concurrentString + typea[ti] + eqString; var ki = kia[ti]; //# var itype = big ? "long" : "int"; //# var icast = big ? "(long)" : ""; //# var uitype = big ? "ulong" : "uint"; //# var nctype = typea[ti] + eqString; //# var ctype = "Concurrent" + nctype; //# var hasKey = tka[ti] == "TKey"; //# if (equatable && !hasKey) continue; //# var hasValue = tva[ti] == "TValue"; //# var isGeneric = hasKey || hasValue; //# var tpar = (isGeneric ? "<" : "") //# + (hasKey ? tka[ti] : "") //# + (hasKey && hasValue ? ", " : "") //# + (hasValue ? tva[ti] : "") //# + (isGeneric ? ">" : ""); //# var isSym = tka[ti] == "Symbol"; //# var hitem = hia[ti]; //# var fun = big && hasKey; //# var ext = fun ? "Long" : ""; //# var HashItem = hitem + ext + tpar; //# var NextHashItem = "Next" + hitem.Capitalized() + ext + tpar; //# var HashItemNext = hitem.Capitalized() + "Next" + ext + tpar; //# var HashFun = hfa[ki]; //# var GetHash = gha[ki]; //# var Hash = ha[ti]; //# var Key = ka[ti]; //# var tkey = tka[ti]; //# var tvalue = tva[ti]; //# var uintCast = hasKey ? "" : "(uint)"; //# var ValuePair = hasValue ? "ValuePair" : ""; //# var idict = "ICountableDict" + (hasValue ? "" : "Set"); #region __type____tpar__ /// //# if (hasValue) { /// A __type__ is an alternate implementation of a Dictionary that can /// optionally act as a stack for all items with the same key. //# } else { /// A __type__ is an alternate implementation of a HashSet. //# } /// It is implemented as a hashtable with external linking, that uses /// primes as the table size in order to reduce the danger of funneling. /// public class __type__/*# if (isGeneric) { *//*# } */ //# if (!wrapped) { : /*# if (!big) { */IIntCountable, /*# } */__idict__,/*# if (!hasValue) { */ IDictSet<__tkey__>,/*# } else { */ IDict<__tkey__, TValue>,/*# } */ IEnumerable, IEnumerable/*# } */>/*# if (!big && !concurrent) { */, ICollection, ICollection/*# } */>/*# if (hasValue) { */, IDictionary<__tkey__, TValue>, IReadOnlyDictionary<__tkey__, TValue>/*# } }*/ //# } //# if (equatable) { where TKey : IEquatable //# } { //# if (wrapped) { private readonly __nctype____tpar__ m_dict; //# } else { // !wrapped //# if (concurrent) { private long m_version; //# } //# if (fun) { private readonly Func<__tkey__, __itype__> m_hfun; //# } private __uitype__ m_capacity; private __NextHashItem__[] m_firstArray; private __HashItemNext__[] m_extraArray; private __uitype__ m_count; private __uitype__ m_increaseThreshold; private __uitype__ m_decreaseThreshold; //# if (hasValue) { private readonly bool m_doNotStackDuplicateKeys; //# } private __itype__ m_freeIndex; private int m_capacityIndex; private __uitype__ m_extraCount; private float m_maxFillFactor; private float m_minFillFactor; public DictReport Report; //# } // !wrapped #region Constructors //# if (wrapped) { /// /// A __ctype__ can only be concstructed by wrapping its non-concurrent /// counterpart. /// public __type__(__nctype____tpar__ dict) { m_dict = dict; } //# } else { // !wrapped /// /// Create a __type__ that autmatically grows and shrinks as necessary. //# if (hasValue) { /// If the optional parameter stackDuplicateKeys is set to true, the /// __type__ acts as a stack for all items with the same key. //# } /// public __type__(/*# if (fun) { */Func<__tkey__, __itype__> hfun/*# } if (fun && hasValue) { */, /*# } if (hasValue) { */bool stackDuplicateKeys = false/*# } */) : this(/*# if (fun) { */hfun, /*# } */DictConstant.PrimeSizes__ext__[0], (__uitype__)DictConstant.MinExtraCapacity/*# if (hasValue) { */, stackDuplicateKeys/*# } */) { } /// /// Create a __type__ that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. //# if (hasValue) { /// If the optional parameter stackDuplicateKeys is set to true, the /// __type__ acts as a stack for all items with the same key. //# } /// public __type__(/*# if (fun) { */Func<__tkey__, __itype__> hfun, /*# } */__itype__ initialCapacity) : this(/*# if (fun) { */hfun, /*# } */System.Math.Max((__uitype__)initialCapacity, DictConstant.PrimeSizes__ext__[0]), (__uitype__)DictConstant.MinExtraCapacity/*# if (hasValue) { */, false/*# } */) { } //# if (hasValue) { /// /// Create a __type__ that autmatically grows and shrinks as necessary, /// but also specify an initial capacity. //# if (hasValue) { /// If the optional parameter stackDuplicateKeys is set to true, the /// __type__ acts as a stack for all items with the same key. //# } /// public __type__(/*# if (fun) { */Func<__tkey__, __itype__> hfun, /*# } */__itype__ initialCapacity, bool stackDuplicateKeys) : this(/*# if (fun) { */hfun, /*# } */System.Math.Max((__uitype__)initialCapacity, DictConstant.PrimeSizes__ext__[0]), (__uitype__)DictConstant.MinExtraCapacity, stackDuplicateKeys) { } //# } /// /// Create a __type__ and initialize it to contain the supplied /// items. //# if (hasValue) { /// If the optional parameter stackDuplicateKeys is set to true, the /// __type__ acts as a stack for all items with the same key. //# } /// public __type__(/*# if (fun) { */Func<__tkey__, __itype__> hfun, /*# } */IEnumerable/*# } */> items/*# if (hasValue) { */, bool stackDuplicateKeys = false/*# } */) : this(/*# if (fun) { */hfun, /*# } */Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes__ext__[0]), (__uitype__)DictConstant.MinExtraCapacity/*# if (hasValue) { */, stackDuplicateKeys/*# } */) { foreach (var item in items) Add(item); } //# if (isSym) { /// /// Create a __type__ and initialize to contain the supplied items. /// Note hat this incurs the overhead of converting all string keys /// to symbols. //# if (hasValue) { /// If the optional parameter stackDuplicateKeys is set to true, the /// __type__ acts as a stack for all items with the same key. //# } /// public __type__(IEnumerable/*# } */> items/*# if (hasValue) { */, bool stackDuplicateKeys = false/*# } */) : this(Math.Max(items is ICollection c ? (uint)c.Count : 0u, DictConstant.PrimeSizes__ext__[0]), DictConstant.MinExtraCapacity/*# if (hasValue) { */, stackDuplicateKeys/*# } */) { foreach (var item in items) Add(item); } //# } // isSym private __type__( /*# if (fun) { */Func<__tkey__, __itype__> hfun, /*# } */__uitype__ firstCapacity, __uitype__ extraCapacity/*# if (hasValue) { */, bool stackDuplicateKeys = false/*# } */) { //# if (concurrent) { m_version = 0; //# } //# if (fun) { m_hfun = hfun; //# } m_maxFillFactor = DictConstant.MaxFillFactorDefault; m_minFillFactor = DictConstant.MinFillFactorDefault; //# if (hasValue) { m_doNotStackDuplicateKeys = !stackDuplicateKeys; //# } m_capacityIndex = 0; m_capacity = DictConstant.PrimeSizes__ext__[m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); while (firstCapacity >= m_increaseThreshold) { m_capacity = DictConstant.PrimeSizes__ext__[++m_capacityIndex]; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); } firstCapacity /= 4; while (firstCapacity >= extraCapacity) extraCapacity *= 2; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); m_firstArray = new __NextHashItem__[m_capacity]; m_extraArray = new __HashItemNext__[extraCapacity]; m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; Report = 0; } //# } // !wrapped #endregion #region Properties //# if (!big) { /// /// Returns the number of items currently contained in the __type__. /// public int Count { get { //# if (wrapped) { return m_dict.Count; //# } else { return (int)m_count; //# } } } //# } // !big /// /// Returns the number of items currently contained in the __type__ /// as long. /// public long LongCount { get { //# if (wrapped) { return m_dict.LongCount; //# } else { return (long)m_count; //# } } } /// /// Returns the number of items currently contained in the __type__ /// as long. /// public __uitype__ Capacity { get { //# if (wrapped) { return m_dict.Capacity; //# } else { return m_capacity; //# } } set { //# if (wrapped) { m_dict.Capacity = value; //# } else { if (value < m_count) throw new System.ArgumentOutOfRangeException("The new capacity is less than the current number of elements."); Resize(value, m_capacity); //# } } } //# if (!wrapped) { /// /// Setting the maximal fill factor makes it possible to fine-tune /// the performance for certain applications. Normally this should /// not be necessary. /// public float MaxFillFactor { get { return m_maxFillFactor; } set { //# if (concurrent) { Monitor.Enter(this); try { //# } m_maxFillFactor = value; m_increaseThreshold = ComputeIncreaseThreshold(m_capacity); //# if (concurrent) { } finally { Monitor.Exit(this); } //# } } } /// /// Setting the minimal fill factor makes it possible to influence /// the shrinking behaviour of the __type__. Normally this should /// be set to a quater of the maximal fill factor. In order to /// completely prevent shrinking it can also be set to 0.0f. /// public float MinFillFactor { get { return m_minFillFactor; } set { //# if (concurrent) { Monitor.Enter(this); try { //# } m_minFillFactor = value; m_decreaseThreshold = ComputeDecreaseThreshold(m_capacity); //# if (concurrent) { } finally { Monitor.Exit(this); } //# } } } //# if (!concurrent) { /// /// Always returns false. Part of the ICollection implementation. /// public bool IsReadOnly { get { return false; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } //# } //# if (!hasValue) { public IEnumerable<__tkey__> Items { get { return Keys; } } //# } else { // hasValue public IEnumerable> Items { get { return KeyValuePairs; } } //# } /// /// Returns all keys in the dictionary. //# if (concurrent) { /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. //# } /// public IEnumerable<__tkey__> Keys { get { //# if (concurrent) { Monitor.Enter(this); try { var version = m_version; //# } for (__uitype__ fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; //# if (!concurrent) { yield return m_firstArray[fi].Item__Key__; //# } else { var k = m_firstArray[fi].Item__Key__; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); //# } while (ei > 0) { //# if (!concurrent) { yield return m_extraArray[ei].Item__Key__; //# } else { k = m_extraArray[ei].Item__Key__; Monitor.Exit(this); yield return k; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); //# } ei = m_extraArray[ei].Next; } } //# if (concurrent) { } finally { Monitor.Exit(this); } //# } } } public Type KeyType { get { return typeof(__tkey__); } } //# if (!hasValue) { public IEnumerable Objects { get { foreach (object obj in Keys) yield return obj; } } //# } //# if (hasValue) { /// /// Returns all values in the __type__. //# if (concurrent) { /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. //# } /// public IEnumerable Values { get { //# if (concurrent) { Monitor.Enter(this); try { var version = m_version; //# } for (__uitype__ fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; //# if (!concurrent) { yield return m_firstArray[fi].Item.Value; //# } else { var v = m_firstArray[fi].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); //# } while (ei > 0) { //# if (!concurrent) { yield return m_extraArray[ei].Item.Value; //# } else { v = m_extraArray[ei].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); //# } ei = m_extraArray[ei].Next; } } //# if (concurrent) { } finally { Monitor.Exit(this); } //# } } } public Type ValueType { get { return typeof(TValue); } } /// /// Returns all key value pairs in the __type__. //# if (concurrent) { /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. //# } /// public IEnumerable> KeyValuePairs { get { //# if (concurrent) { Monitor.Enter(this); try { var version = m_version; //# } for (__uitype__ fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; //# if (!concurrent) { yield return new KeyValuePair<__tkey__, TValue>( m_firstArray[fi].Item__Key__, m_firstArray[fi].Item.Value); //# } else { var kvp = new KeyValuePair<__tkey__, TValue>( m_firstArray[fi].Item__Key__, m_firstArray[fi].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); //# } while (ei > 0) { //# if (!concurrent) { yield return new KeyValuePair<__tkey__, TValue>( m_extraArray[ei].Item__Key__, m_extraArray[ei].Item.Value); //# } else { kvp = new KeyValuePair<__tkey__, TValue>( m_extraArray[ei].Item__Key__, m_extraArray[ei].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); //# } ei = m_extraArray[ei].Next; } } //# if (concurrent) { } finally { Monitor.Exit(this); } //# } } } /// /// Returns all key value pairs in the __type__, in such a way, /// that the stack order is correct when the pairs are put into a /// new __type__ in the order they are returned. //# if (concurrent) { /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the enumeration. //# } /// public IEnumerable> KeyValuePairsForStorage { get { //# if (concurrent) { Monitor.Enter(this); try { var version = m_version; //# } var stack = new Stack<__itype__>(); for (__uitype__ fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; while (ei > 0) { stack.Push(ei); ei = m_extraArray[ei].Next; } //# if (concurrent) { var kvp = default(KeyValuePair<__tkey__, TValue>); //# } while (stack.Count > 0) { ei = stack.Pop(); //# if (!concurrent) { yield return new KeyValuePair<__tkey__, TValue>( m_extraArray[ei].Item__Key__, m_extraArray[ei].Item.Value); //# } else { kvp = new KeyValuePair<__tkey__, TValue>( m_extraArray[ei].Item__Key__, m_extraArray[ei].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); //# } } //# if (!concurrent) { yield return new KeyValuePair<__tkey__, TValue>( m_firstArray[fi].Item__Key__, m_firstArray[fi].Item.Value); //# } else { kvp = new KeyValuePair<__tkey__, TValue>( m_firstArray[fi].Item__Key__, m_firstArray[fi].Item.Value); Monitor.Exit(this); yield return kvp; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); //# } } //# if (concurrent) { } finally { Monitor.Exit(this); } //# } } } public IEnumerable<(object, object)> ObjectPairs { get { foreach (var kvp in KeyValuePairsForStorage) yield return (kvp.Key, kvp.Value); } } //# } // hasValue //# } // !wrapped //# if (wrapped) { /// /// Return the non-concurrent contained __type__. /// public __nctype____tpar__ NonConcurrent { get { return m_dict; } } //# } #endregion //# if (hasValue) { #region Indexer /// /// Get or set the item with the supplied key. If multiple items with /// the same key are allowed, the __type__ acts as a stack. /// /// /// public TValue this[__tkey__ key] { get { //# if (wrapped) { Monitor.Enter(this); try { return m_dict[key]; } finally { Monitor.Exit(this); } //# } else { // !wrapped var hash = __HashFun__key__GetHash__; //# if (concurrent) { Monitor.Enter(this); try { //# } var fi = ((__uitype__)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_firstArray[fi].Item__Key__)/*# } */) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_extraArray[ei].Item__Key__)/*# } */) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } //# if (concurrent) { } finally { Monitor.Exit(this); } //# } throw new KeyNotFoundException(); //# } // !wrapped } set { //# if (wrapped) { Monitor.Enter(this); try { m_dict[key] = value; } finally { Monitor.Exit(this); } //# } else { // !wrapped var hash = __HashFun__key__GetHash__; //# if (concurrent) { Monitor.Enter(this); try { ++m_version; //# } if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((__uitype__)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; m_firstArray[fi].Next = -1; //# if (hasKey) { m_firstArray[fi].Item.Hash = hash; //# } m_firstArray[fi].Item__Key__ = key; m_firstArray[fi].Item.Value = value; return; } if (m_doNotStackDuplicateKeys) { if (m_firstArray[fi].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_firstArray[fi].Item__Key__)/*# } */) { m_firstArray[fi].Item.Value = value; return; } while (ei > 0) { if (m_extraArray[ei].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_extraArray[ei].Item__Key__)/*# } */) { m_extraArray[ei].Item.Value = value; return; } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.__ext__Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; //# if (hasKey) { m_firstArray[fi].Item.Hash = hash; //# } m_firstArray[fi].Item__Key__ = key; m_firstArray[fi].Item.Value = value; //# if (concurrent) { } finally { Monitor.Exit(this); } //# } //# } // !wrapped } } #endregion //# } // hasValue #region Public Methods //# var aortype = hasValue ? "void" : "bool"; /// /// Add the item with supplied key/*# if (hasValue) { */ and the supplied value/*# } */ /// both supplied as generic objects, to the __type__. Note that the supplied key /// and value are cast to the concrete type of the keys and values used in the __type__ /// and this will fail if they are of different types. /// public __aortype__ AddObject(object objkey/*# if (hasValue) { */, object objvalue/*# } */) { /*# if (!hasValue) { */return /*# } */Add((__tkey__)objkey/*# if (hasValue) { */, (__tvalue__)objvalue/*# } */); } //# if (!hasValue && !big && !concurrent) { void ICollection<__tkey__>.Add(__tkey__ key) { Add(key); } //# } //# foreach (var isTry in new[] { false, true }) { //# var rtype = (isTry || !hasValue) ? "bool" : "void"; //# var tryPrefix = isTry ? "Try" : ""; //# foreach (var hasHashPar in new[] { false, true }) { if (hasHashPar && !hasKey) continue; /// /// Add the item with the supplied key/*# if (hasValue) { */ and the supplied value/*# } */ /// to the __type__. /// public __rtype__ __tryPrefix__Add(__tkey__ key/*# if (hasHashPar) { */, __itype__ hash/*# } if (hasValue) { */, __tvalue__ value/*# } */) { //# if (wrapped) { Monitor.Enter(this); try { /*# if (isTry || !hasValue) { */return /*# } */m_dict.__tryPrefix__Add(key/*# if (hasHashPar) { */, hash/*# } if (hasValue) { */, value/*# } */); } finally { Monitor.Exit(this); } //# } else { // !wrapped //# if (!hasHashPar) { var hash = __HashFun__key__GetHash__; //# } //# if (concurrent) { Monitor.Enter(this); try { //# } if (m_count >= m_increaseThreshold) IncreaseCapacity(); var fi = ((__uitype__)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { ++m_count; //# if (concurrent) { ++m_version; //# } m_firstArray[fi].Next = -1; //# if (hasKey) { m_firstArray[fi].Item.Hash = hash; //# } m_firstArray[fi].Item__Key__ = key; //# if (hasValue) { m_firstArray[fi].Item.Value = value; //# } return/*# if (isTry || !hasValue) { */ true/*# } */; } //# if (hasValue) { if (m_doNotStackDuplicateKeys) //# } { // no duplicate keys, check for existing entries if (m_firstArray[fi].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_firstArray[fi].Item__Key__)/*# } */) { //# if (hasValue && !isTry) { throw new ArgumentException("duplicate key"); //# } else { return/*# if (isTry || !hasValue) { */ false/*# } */; //# } } while (ei > 0) { if (m_extraArray[ei].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_extraArray[ei].Item__Key__)/*# } */) { //# if (hasValue && !isTry) { throw new ArgumentException("duplicate key"); //# } else { return/*# if (isTry || !hasValue) { */ false/*# } */; //# } } ei = m_extraArray[ei].Next; } ei = m_firstArray[fi].Next; } ++m_count; //# if (concurrent) { ++m_version; //# } ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = ei; m_firstArray[fi].Next = ni; //# if (hasKey) { m_firstArray[fi].Item.Hash = hash; //# } m_firstArray[fi].Item__Key__ = key; //# if (hasValue) { m_firstArray[fi].Item.Value = value; //# } //# if (concurrent) { } finally { Monitor.Exit(this); } //# } //# if (isTry || !hasValue) { return true; //# } //# } // !wrapped } //# } // hasHashPar //# } // isTry //# if (isSym) { /// /// Adds the supplied item to the __type__. Note that this incurs the /// overhead of converting the string key to a symbol. /// public void Add(string key/*# if (hasValue) { */, __tvalue__ value/*# } */) { //# if (wrapped) { Monitor.Enter(this); try { m_dict.Add(key.ToSymbol()/*# if (hasValue) { */, value/*# } */); } finally { Monitor.Exit(this); } //# } else { // !wrapped Add(key.ToSymbol()/*# if (hasValue) { */, value/*# } */); //# } // !wrapped } //# if (hasValue) { /// /// Add the supplied item to the __type__. Note that this incurs the /// overhead of converting the string key to a symbol. /// public void Add(KeyValuePair item) { //# if (wrapped) { Monitor.Enter(this); try { m_dict.Add(item.Key.ToSymbol(), item.Value); } finally { Monitor.Exit(this); } //# } else { // !wrapped Add(item.Key.ToSymbol(), item.Value); //# } // !wrapped } //# } // hasValue //# } // isSym //# if (hasValue) { /// /// Add the supplied item to the __type__. /// public void Add(KeyValuePair<__tkey__, TValue> item) { //# if (wrapped) { Monitor.Enter(this); try { m_dict.Add(item.Key, item.Value); } finally { Monitor.Exit(this); } //# } else { // !wrapped Add(item.Key, item.Value); //# } // !wrapped } /// /// Add the supplied items to the __type__. /// public void AddRange(IEnumerable> items) { foreach (var item in items) Add(item); } //# } else { // !hasValue /// /// Add the supplied keys to the __type__. /// public void AddRange(IEnumerable<__tkey__> keys) { foreach (var key in keys) Add(key); } //# } // !hasValue //# foreach (var keyStr in new string[] { "", "Key" }) { if (keyStr != "" && !hasValue) continue; //# foreach (var hasHashPar in new[] { false, true }) { if (hasHashPar && !hasKey) continue; /// /// Returns true if the __type__ contains the item with the supplied /// key. /// public bool Contains__keyStr__(__tkey__ key/*# if (hasHashPar) { */, __itype__ hash/*# } */) { //# if (wrapped) { Monitor.Enter(this); try { return m_dict.Contains(key); } finally { Monitor.Exit(this); } //# } else { // !wrapped //# if (!hasHashPar) { var hash = __HashFun__key__GetHash__; //# } //# if (concurrent) { Monitor.Enter(this); try { //# } var fi = ((__uitype__)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_firstArray[fi].Item__Key__)/*# } */) return true; while (ei > 0) { if (m_extraArray[ei].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_extraArray[ei].Item__Key__)/*# } */) return true; ei = m_extraArray[ei].Next; } //# if (concurrent) { } finally { Monitor.Exit(this); } //# } return false; //# } // !wrapped } //# } // hasHashPar //# } // keyStr //# if (hasValue) { //# foreach (var hasHashPar in new[] { false, true }) { if (hasHashPar && !hasKey) continue; /// /// Returns true if the __type__ contains the item with the supplied /// key and the supplied value. /// public bool Contains(__tkey__ key/*# if (hasHashPar) { */, __itype__ hash/*# } */, TValue value) { //# if (wrapped) { Monitor.Enter(this); try { return m_dict.Contains(key, value); } finally { Monitor.Exit(this); } //# } else { // !wrapped //# if (!hasHashPar) { var hash = __HashFun__key__GetHash__; //# } //# if (concurrent) { Monitor.Enter(this); try { //# } var fi = ((__uitype__)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_firstArray[fi].Item__Key__)/*# } */ && EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (m_extraArray[ei].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_extraArray[ei].Item__Key__)/*# } */ && EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } //# if (concurrent) { } finally { Monitor.Exit(this); } //# } return false; //# } // !wrapped } //# } // hasHashPar /// /// Returns true if the __type__ contains the item with the supplied /// KeyValuePair. /// public bool Contains(KeyValuePair<__tkey__, TValue> item) { //# if (wrapped) { Monitor.Enter(this); try { return m_dict.Contains(item.Key, item.Value); } finally { Monitor.Exit(this); } //# } else { // !wrapped return Contains(item.Key, item.Value); //# } // !wrapped } //# if (hasValue) { /// /// Returns true if the __type__ contains the given value. /// public bool ContainsValue(TValue value) { //# if (concurrent) { Monitor.Enter(this); try { //# } //# if (wrapped) { return m_dict.ContainsValue(value); //# } else { // wrapped for (__uitype__ fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (EqualityComparer.Default.Equals(value, m_firstArray[fi].Item.Value)) return true; while (ei > 0) { if (EqualityComparer.Default.Equals(value, m_extraArray[ei].Item.Value)) return true; ei = m_extraArray[ei].Next; } } return false; //# } // !wrapped //# if (concurrent) { } finally { Monitor.Exit(this); } //# } } //# } // hasValue //# foreach (var hasHashPar in new[] { false, true }) { if (hasHashPar && !hasKey) continue; //# foreach (var hasDefault in new[] { false, true }) { //# foreach (var isCreate in new[] { false, true }) { //# if (hasDefault && isCreate) continue; //# var orCreate = isCreate ? "OrCreate" : ""; /// /// Get the element with the supplied key. //# if (isCreate) { /// If the element is not found, the supplied creator is called to create /// a new element that is added to the __type__ and returned. //# } else if (hasDefault) { /// Returns the supplied default value if the element is not found. //# } else { /// Throws an exception if the element is not found. This is an alias of the indexer. //# } /// public TValue Get__orCreate__(__tkey__ key/*# if (hasHashPar) { */, __itype__ hash/*# } if (isCreate) { */, Func<__tkey__, TValue> creator/*# } if (hasDefault) { */, TValue defaultValue/*# } */) { //# if (wrapped) { Monitor.Enter(this); try { return m_dict.Get__orCreate__(key/*# if (hasHashPar) { */, hash/*# } if (isCreate) { */, creator/*# } */); } finally { Monitor.Exit(this); } //# } else { // !wrapped //# if (!hasHashPar) { var hash = __HashFun__key__GetHash__; //# } //# if (concurrent) { Monitor.Enter(this); try { //# } var fi = ((__uitype__)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) //# if (isCreate) { { var value = creator(key); return AddCreated(key, hash, value); } //# } else if (hasDefault) { return defaultValue; //# } else { // !isCreate && ! isDefault throw new KeyNotFoundException(); //# } if (m_firstArray[fi].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_firstArray[fi].Item__Key__)/*# } */) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_extraArray[ei].Item__Key__)/*# } */) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } //# if (isCreate) { var val = creator(key); return AddCreated(key, hash, val); //# } else if (hasDefault) { return defaultValue; //# } //# if (concurrent) { } finally { Monitor.Exit(this); } //# } //# if (!isCreate && !hasDefault) { throw new KeyNotFoundException(); //# } //# } // !wrapped } //# if (!wrapped && isCreate && !hasHashPar) { __tvalue__ AddCreated(__tkey__ key, __itype__ hash, __tvalue__ value) { while (true) { var fi = ((__uitype__)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ++m_count; //# if (concurrent) { ++m_version; //# } m_firstArray[fi].Next = -1; //# if (hasKey) { m_firstArray[fi].Item.Hash = hash; //# } m_firstArray[fi].Item__Key__ = key; m_firstArray[fi].Item.Value = value; return value; } if (m_firstArray[fi].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_firstArray[fi].Item__Key__)/*# } */) return m_firstArray[fi].Item.Value; while (ei > 0) { if (m_extraArray[ei].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_extraArray[ei].Item__Key__)/*# } */) return m_extraArray[ei].Item.Value; ei = m_extraArray[ei].Next; } if (m_count >= m_increaseThreshold) { IncreaseCapacity(); continue; } ei = m_firstArray[fi].Next; ++m_count; //# if (concurrent) { ++m_version; //# } ++m_extraCount; if (m_freeIndex < 0) { var length = m_extraArray.Length; m_extraArray = m_extraArray.Resized(length * 2); m_freeIndex = AddSlotsToFreeList(m_extraArray, length); } var ni = m_freeIndex; m_freeIndex = m_extraArray[ni].Next; m_extraArray[ni].Item = m_firstArray[fi].Item; m_extraArray[ni].Next = m_firstArray[fi].Next; m_firstArray[fi].Next = ni; //# if (hasKey) { m_firstArray[fi].Item.Hash = hash; //# } m_firstArray[fi].Item__Key__ = key; m_firstArray[fi].Item.Value = value; return value; } } //# } // !wrapped && isCreate && hasHashPar //# } // isCreate //# } // hasDefault //# } // hasHashPar /// /// Get the element with the supplied key. Returns the default /// value of the value type if the element is not found. /// public TValue GetOrDefault(__tkey__ key) { return Get(key, default(TValue)); } //# foreach (var hasHashPar in new[] { false, true }) { if (hasHashPar && !hasKey) continue; /// /// Try to retrieve the value with the supplied key, return true if /// successful and return the value via the out parameter. /// public bool TryGetValue(__tkey__ key, /*# if (hasHashPar) { */__itype__ hash, /*# } */out TValue value) { //# if (wrapped) { Monitor.Enter(this); try { return m_dict.TryGetValue(key, /*# if (hasHashPar) { */hash, /*# } */out value); } finally { Monitor.Exit(this); } //# } else { // !wrapped //# if (!hasHashPar) { var hash = __HashFun__key__GetHash__; //# } //# if (concurrent) { Monitor.Enter(this); try { //# } var fi = ((__uitype__)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { value = default(TValue); return false; } if (m_firstArray[fi].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_firstArray[fi].Item__Key__)/*# } */) { value = m_firstArray[fi].Item.Value; return true; } while (ei > 0) { if (m_extraArray[ei].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_extraArray[ei].Item__Key__)/*# } */) { value = m_extraArray[ei].Item.Value; return true; } ei = m_extraArray[ei].Next; } value = default(TValue); //# if (concurrent) { } finally { Monitor.Exit(this); } //# } return false; //# } // !wrapped } //# } //# if (!wrapped) { /// /// Return all the value with the given key. This method is only /// useful if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// public IEnumerable ValuesWithKey(__tkey__ key) { var hash = __HashFun__key__GetHash__; //# if (concurrent) { Monitor.Enter(this); try { var version = m_version; //# } var fi = ((__uitype__)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) yield break; if (m_firstArray[fi].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_firstArray[fi].Item__Key__)/*# } */) //# if (!concurrent) { yield return m_firstArray[fi].Item.Value; //# } else { { var v = m_firstArray[fi].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } //# } while (ei > 0) { if (m_extraArray[ei].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_extraArray[ei].Item__Key__)/*# } */) //# if (!concurrent) { yield return m_extraArray[ei].Item.Value; //# } else { { var v = m_extraArray[ei].Item.Value; Monitor.Exit(this); yield return v; Monitor.Enter(this); if (version != m_version) throw new ConcurrentDataModifiedException(); } //# } ei = m_extraArray[ei].Next; } //# if (concurrent) { } finally { Monitor.Exit(this); } //# } } //# if (!concurrent) { /// /// Gets an enumerator for values. /// Should be preferred over Values enumeration in /// performance critical code. /// public ValueEnumerator GetValuesEnumerator() { return new ValueEnumerator(this); } public struct ValueEnumerator : IEnumerator { __type__/*# if (isGeneric) { *//*# } */.Enumerator m_inner; public ValueEnumerator(__type__/*# if (isGeneric) { *//*# } */ dict) { m_inner = dict.GetEnumerator(); } public TValue Current => m_inner.Current.Value; object IEnumerator.Current => Current; public void Dispose() => m_inner.Dispose(); public bool MoveNext() => m_inner.MoveNext(); public void Reset() => m_inner.Reset(); } /// /// Gets an enumerator for values with key. It is only useful /// if multiple item with the same key are allowed (stackDuplicateKeys=true). /// The order of the values is reversed to their additions (like a stack). /// Should be preferred over ValuesWithKey enumeration in /// performance critical code. /// public ValuesWithKeyEnumerator GetValuesWithKeyEnumerator(__tkey__ key) { return new ValuesWithKeyEnumerator(this, key); } public struct ValuesWithKeyEnumerator : IEnumerator { readonly __type__/*# if (isGeneric) { *//*# } */ m_dict;/*# if (hasKey) { */ readonly TKey m_key;/*# } */ readonly __itype__ m_hash; __itype__ m_extraIndex; TValue m_current; public ValuesWithKeyEnumerator(__type__/*# if (isGeneric) { *//*# } */ dict, __tkey__ key) { m_dict = dict;/*# if (hasKey) { */ m_key = key;/*# } */ m_hash = /*# if (fun) {*/dict./*# } */__HashFun__key__GetHash__; m_extraIndex = int.MaxValue; m_current = default(TValue); } public readonly TValue Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex == int.MaxValue) { var fa = m_dict.m_firstArray; var fi = ((uint)m_hash) % m_dict.m_capacity; m_extraIndex = fa[fi].Next; if (m_extraIndex == 0) return false; if (fa[fi].Item__Hash__ == m_hash/*# if (hasKey) { */ && m_key.Equals(fa[fi].Item__Key__)/*# } */) { m_current = fa[fi].Item.Value; return true; } } if (m_extraIndex > 0) { var ea = m_dict.m_extraArray; do { var valid = ea[m_extraIndex].Item__Hash__ == m_hash/*# if (hasKey) { */ && m_key.Equals(ea[m_extraIndex].Item__Key__)/*# } */; if (valid) m_current = ea[m_extraIndex].Item.Value; m_extraIndex = ea[m_extraIndex].Next; if (valid) return true; } while (m_extraIndex > 0); } return false; } public void Reset() { m_extraIndex = int.MaxValue; m_current = default(TValue); } } //# } // !concurrent //# } // !wrapped /// /// Return the value with the given key, but skip a supplied number /// of entries with this key. This method is only useful if multiple /// item with the same key are allowed. /// public TValue ValueWithKeySkip(__tkey__ key, __itype__ skip) { //# if (wrapped) { Monitor.Enter(this); try { return m_dict.ValueWithKeySkip(key, skip); } finally { Monitor.Exit(this); } //# } else { // !wrapped var hash = __HashFun__key__GetHash__; //# if (concurrent) { Monitor.Enter(this); try { //# } var fi = ((__uitype__)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) throw new KeyNotFoundException(); if (m_firstArray[fi].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_firstArray[fi].Item__Key__)/*# } */) { if (skip == 0) return m_firstArray[fi].Item.Value; --skip; } while (ei > 0) { if (m_extraArray[ei].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_extraArray[ei].Item__Key__)/*# } */) { if (skip == 0) return m_extraArray[ei].Item.Value; --skip; } ei = m_extraArray[ei].Next; } //# if (concurrent) { } finally { Monitor.Exit(this); } //# } throw new KeyNotFoundException(); //# } // !wrapped } /// /// Remove the item with the supplied key from the __type__ and /// return it. If multipe entries have the same key, the one that /// was inserted last is removed. /// If the item is not found, a KeyNotFoundException is thrown. /// public TValue GetAndRemove(__tkey__ key) { //# if (wrapped) { Monitor.Enter(this); try { return m_dict.GetAndRemove(key); } finally { Monitor.Exit(this); } //# } else { // !wrapped TValue value; if (!TryRemove(key, out value)) throw new KeyNotFoundException(); return value; //# } // !wrapped } //# foreach (var hasHashPar in new[] { false, true }) { if (hasHashPar && !hasKey) continue; /// /// Try to remove the item with the supplied key from the __type__. /// and return true if it was succesfully removed. If multipe /// entries have the same key, the one that was inserted last is /// removed. If the item is not found, false is returned. /// public bool Remove(__tkey__ key/*# if (hasHashPar) { */, __itype__ hash/*# } */) { TValue value; //# if (wrapped) { Monitor.Enter(this); try { return m_dict.TryRemove(key/*# if (hasHashPar) { */, hash/*# } */, out value); } finally { Monitor.Exit(this); } //# } else { // !wrapped return TryRemove(key/*# if (hasHashPar) { */, hash/*# } */, out value); //# } // !wrapped } //# } // hasHashPar //# } //# foreach (var hasHashPar in new[] { false, true }) { if (hasHashPar && !hasKey) continue; /// /// Remove the item with the supplied key/*# if (hasValue) { */ and the supplied value/*# } */ /// from the __type__. Returns true if the value was removed. /// public bool Remove(__tkey__ key/*# if (hasHashPar) { */, __itype__ hash/*# } if (hasValue) { */, TValue value/*# } */) { //# if (wrapped) { Monitor.Enter(this); try { return m_dict.TryRemove(key/*# if (hasHashPar) { */, hash/*# } if (hasValue) { */, value/*# } */); } finally { Monitor.Exit(this); } //# } else { // !wrapped return TryRemove(key/*# if (hasHashPar) { */, hash/*# } if (hasValue) { */, value/*# } */); //# } // !wrapped } //# } // hasHashPar //# if (hasValue) { /// /// Remove the item with the supplied KeyValuePair from the __type__. /// If the item is not found, a KeyNotFoundException is thrown. /// public bool Remove(KeyValuePair<__tkey__, TValue> item) { //# if (wrapped) { Monitor.Enter(this); try { return m_dict.TryRemove(item.Key, item.Value); } finally { Monitor.Exit(this); } //# } else { // !wrapped return TryRemove(item.Key, item.Value); //# } // !wrapped } //# } // hasValue //# foreach (var hasHashPar in new[] { false, true }) { if (hasHashPar && !hasKey) continue; /// /// Try to reomve the item with the supplied key. If multipe entries /// have the same key, the one that was inserted last is removed. /// Returns true if the item was found/*# if (hasValue) { */, which is returned via the out /// parameter/*# } */. /// public bool TryRemove(__tkey__ key/*# if (hasHashPar) { */, __itype__ hash/*# } if (hasValue) { */, out TValue value/*# } */) { //# if (wrapped) { Monitor.Enter(this); try { return m_dict.TryRemove(key/*# if (hasHashPar) { */, hash/*# } if (hasValue) { */, out value/*# } */); } finally { Monitor.Exit(this); } //# } else { // !wrapped //# if (!hasHashPar) { var hash = __HashFun__key__GetHash__; //# } //# if (concurrent) { Monitor.Enter(this); try { //# } var fi = ((__uitype__)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) { /*# if (hasValue) { */value = default(TValue); /*# } */return false; } if (m_firstArray[fi].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_firstArray[fi].Item__Key__)/*# } */) { //# if (hasValue) { value = m_firstArray[fi].Item.Value; //# } if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(__HashItem__); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(__HashItem__); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); //# if (concurrent) { ++m_version; //# } return true; } if (ei > 0) { if (m_extraArray[ei].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_extraArray[ei].Item__Key__)/*# } */) { //# if (hasValue) { value = m_extraArray[ei].Item.Value; //# } m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(__HashItem__); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); //# if (concurrent) { ++m_version; //# } return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_extraArray[ni].Item__Key__)/*# } */) { //# if (hasValue) { value = m_extraArray[ni].Item.Value; //# } m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(__HashItem__); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); //# if (concurrent) { ++m_version; //# } return true; } } } //# if (hasValue) { value = default(TValue); //# } //# if (concurrent) { } finally { Monitor.Exit(this); } //# } return false; //# } // !wrapped } //# } // hasHashPar //# if (hasValue) { //# foreach (var hasHashPar in new[] { false, true }) { if (hasHashPar && !hasKey) continue; /// /// Try to reomve the item with the supplied key and the supplied /// value. If multipe entries match, the one that was inserted last /// is removed. Returns true if the item was found. /// public bool TryRemove(__tkey__ key/*# if (hasHashPar) { */, __itype__ hash/*# } */, TValue value) { //# if (wrapped) { Monitor.Enter(this); try { return m_dict.TryRemove(key/*# if (hasHashPar) { */, hash/*# } */, value); } finally { Monitor.Exit(this); } //# } else { // !wrapped //# if (!hasHashPar) { var hash = __HashFun__key__GetHash__; //# } //# if (concurrent) { Monitor.Enter(this); try { //# } var fi = ((__uitype__)hash) % m_capacity; var ei = m_firstArray[fi].Next; if (ei == 0) return false; if (m_firstArray[fi].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_firstArray[fi].Item__Key__)/*# } */ && value.Equals(m_firstArray[fi].Item.Value)) { if (ei < 0) { m_firstArray[fi].Next = 0; m_firstArray[fi].Item = default(__HashItem__); } else { m_firstArray[fi].Next = m_extraArray[ei].Next; m_firstArray[fi].Item = m_extraArray[ei].Item; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(__HashItem__); m_freeIndex = ei; --m_extraCount; } if (--m_count < m_decreaseThreshold) DecreaseCapacity(); //# if (concurrent) { ++m_version; //# } return true; } if (ei > 0) { if (m_extraArray[ei].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_extraArray[ei].Item__Key__)/*# } */ && value.Equals(m_extraArray[ei].Item.Value)) { m_firstArray[fi].Next = m_extraArray[ei].Next; m_extraArray[ei].Next = m_freeIndex; m_extraArray[ei].Item = default(__HashItem__); m_freeIndex = ei; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); //# if (concurrent) { ++m_version; //# } return true; } for (var ni = m_extraArray[ei].Next; ni > 0; ei = ni, ni = m_extraArray[ei].Next) { if (m_extraArray[ni].Item__Hash__ == hash/*# if (hasKey) { */ && key.Equals(m_extraArray[ni].Item__Key__)/*# } */ && value.Equals(m_extraArray[ni].Item.Value)) { m_extraArray[ei].Next = m_extraArray[ni].Next; m_extraArray[ni].Next = m_freeIndex; m_extraArray[ni].Item = default(__HashItem__); m_freeIndex = ni; --m_extraCount; if (--m_count < m_decreaseThreshold) DecreaseCapacity(); //# if (concurrent) { ++m_version; //# } return true; } } } //# if (concurrent) { } finally { Monitor.Exit(this); } //# } return false; //# } // !wrapped } //# } // hasHashPar //# } // hasValue //# foreach (var toaKeys in new[] { true, false }) { //# if (!hasValue && !toaKeys) continue; //# var KeysValues = hasValue ? (toaKeys ? "Keys" : "Values") : ""; //# var tkeyvalue = toaKeys ? tkey : "TValue"; //# var KeyValue = toaKeys ? Key : ".Value"; //# var keysvalues = toaKeys ? "keys" : "values"; /// /// Returns all __keysvalues__ in the dictionary as an array. //# if (concurrent) { /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. //# } /// public __tkeyvalue__[] __KeysValues__ToArray() { //# if (wrapped) { return m_dict.__KeysValues__ToArray(); //# } else { var array = new __tkeyvalue__[m_count]; Copy__KeysValues__To(array, __izero__); return array; //# } } //# } // toaKeys //# if (hasValue) { /// /// Returns all KeyValuePairs in the dictionary as an array. //# if (concurrent) { /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. //# } /// public KeyValuePair<__tkey__, TValue>[] ToArray() { //# if (wrapped) { return m_dict.ToArray(); //# } else { var array = new KeyValuePair<__tkey__, TValue>[m_count]; CopyTo(array, __izero__); return array; //# } } //# } // hasValue /// /// Remove all items. Capacity remains unchanged. /// public void Clear() { //# if (wrapped) { Monitor.Enter(this); try { m_dict.Clear(); } finally { Monitor.Exit(this); } //# } else { // !wrapped //# if (concurrent) { Monitor.Enter(this); try { ++m_version; //# } m_firstArray.Set(default(__NextHashItem__)); m_extraArray.Set(default(__HashItemNext__)); m_freeIndex = AddSlotsToFreeList(m_extraArray, 1); m_count = 0; m_extraCount = 0; //# if (concurrent) { } finally { Monitor.Exit(this); } //# } //# } // !wrapped } //# foreach (var toaKeys in new[] { true, false }) { //# if (!hasValue && !toaKeys) continue; //# var KeysValues = hasValue ? (toaKeys ? "Keys" : "Values") : ""; //# var tkeyvalue = toaKeys ? tkey : "TValue"; //# var KeyValue = toaKeys ? Key : ".Value"; //# var keysvalues = toaKeys ? "keys" : "values"; /// /// Copies all __keysvalues__ in the dictionary to the supplied /// array starting at the supplied index. //# if (concurrent) { /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. //# } /// public void Copy__KeysValues__To(__tkeyvalue__[] array, __itype__ index) { //# if (wrapped) { Monitor.Enter(this); try { m_dict.Copy__KeysValues__To(array, index); } finally { Monitor.Exit(this); } //# } else { // !wrapped //# if (concurrent) { Monitor.Enter(this); try { //# } for (__uitype__ fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = m_firstArray[fi].Item__KeyValue__; while (ei > 0) { array[index++] = m_extraArray[ei].Item__KeyValue__; ei = m_extraArray[ei].Next; } } //# if (concurrent) { } finally { Monitor.Exit(this); } //# } //# } // !wrapped } //# } // toaKeys //# if (hasValue) { /// /// Copies all KeyValuePairs in the dictionary into the supplied /// array starting at the supplied index. //# if (concurrent) { /// This may throw a ConcurrentDataModifiedException if data is /// modified by another task during the operation. //# } /// public void CopyTo(KeyValuePair<__tkey__, TValue>[] array, __itype__ index) { //# if (wrapped) { Monitor.Enter(this); try { m_dict.CopyTo(array, index); } finally { Monitor.Exit(this); } //# } else { // !wrapped //# if (concurrent) { Monitor.Enter(this); try { //# } for (__uitype__ fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; array[index++] = new KeyValuePair<__tkey__, TValue>( m_firstArray[fi].Item__Key__, m_firstArray[fi].Item.Value); while (ei > 0) { array[index++] = new KeyValuePair<__tkey__, TValue>( m_extraArray[ei].Item__Key__, m_extraArray[ei].Item.Value); ei = m_extraArray[ei].Next; } } //# if (concurrent) { } finally { Monitor.Exit(this); } //# } //# } // !wrapped } //# } // hasValue //# if (!concurrent) { /// /// Copy items into supplied array starting at supplied index. /// public void CopyTo(Array array, int index) { var typedArray = array as /*# if (hasValue) { */KeyValuePair/*# } */[]; if (typedArray != null) CopyTo(typedArray, __icast__index); else throw new ArgumentException(); } /// /// Retuns a concurrent wrapper around the __type__ to enable /// concurrent modifications. /// public __ctype____tpar__ AsConcurrent() { return new __ctype____tpar__(this); } //# } //# if (isSym && hasValue) { public void Add(TypedSymbol key, TType value) where TType : TValue { this.Add(key.Symbol, value); } public bool Contains(TypedSymbol key) where TType : TValue { return Contains(key.Symbol); } public bool ContainsKey(TypedSymbol key) where TType : TValue { return ContainsKey(key.Symbol); } public TType Get(TypedSymbol key) where TType : TValue { return (TType)this[key.Symbol]; } public TType Get(TypedSymbol key, TType defaultValue) where TType : TValue { TType value; if (TryGetValue(key, out value)) return value; return defaultValue; } public TType GetOrDefault(TypedSymbol key) where TType : TValue { TType value; if (TryGetValue(key, out value)) return value; return default(TType); } public bool Remove(TypedSymbol key) where TType : TValue { return Remove(key.Symbol); } public void Set(TypedSymbol key, TType value) where TType : TValue { this[key.Symbol] = value; } public bool TryGetValue(TypedSymbol key, out TType value) where TType : TValue { TValue val; if (TryGetValue(key.Symbol, out val)) { value = (TType)val; return true; } value = default(TType); return false; } public TType GetAs(__tkey__ key) where TType : TValue { return (TType)this[key]; } public TType GetAs(__tkey__ key, TType defaultValue) where TType : TValue { TValue value; if (TryGetValue(key, out value)) return (TType)value; return defaultValue; } public TType GetAsOrDefault(__tkey__ key) where TType : TValue { TValue value; if (TryGetValue(key, out value)) return (TType)value; return default(TType); } //# } // isSym #endregion //# if (!wrapped) { #region IEnumerable/*# } */> Members IEnumerator/*# } */> IEnumerable/*# } */>.GetEnumerator() { /*# if (!concurrent) { */ return new Enumerator(this); /*# } else { */ return Key__ValuePair__s.GetEnumerator(); /*# } */ } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { /*# if (!concurrent) { */ return new Enumerator(this); /*# } else { */ return Key__ValuePair__s.GetEnumerator(); /*# } */ } #endregion /*# if (hasValue && !big && !concurrent) { */ #region IDictionary<__tkey__, TValue> Members ICollection<__tkey__> IDictionary<__tkey__, TValue>.Keys => new KeyCollection(this); ICollection IDictionary<__tkey__, TValue>.Values => new ValueCollection(this); private sealed class KeyCollection(__type____tpar__ parent) : ICollection<__tkey__>, ICollection, IReadOnlyCollection<__tkey__> { public void CopyTo(__tkey__[] array, int index) => parent.CopyKeysTo(array, index); public int Count => parent.Count; bool ICollection<__tkey__>.IsReadOnly => true; void ICollection<__tkey__>.Add(__tkey__ item) => throw new NotSupportedException(); void ICollection<__tkey__>.Clear() => throw new NotSupportedException(); public bool Contains(__tkey__ item) => parent.ContainsKey(item); bool ICollection<__tkey__>.Remove(__tkey__ item) => throw new NotSupportedException(); IEnumerator<__tkey__> IEnumerable<__tkey__>.GetEnumerator() => new Enumerator(parent); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<__tkey__>)this).GetEnumerator(); void ICollection.CopyTo(Array array, int index) { if (array is __tkey__[] keys) parent.CopyKeysTo(keys, index); throw new ArrayTypeMismatchException(); } bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => ((ICollection)parent).SyncRoot; private class Enumerator(__type____tpar__ dictionary) : IEnumerator<__tkey__>, IEnumerator { private __type____tpar__.Enumerator _inner = dictionary.GetEnumerator(); public void Dispose() => _inner.Dispose(); public bool MoveNext() => _inner.MoveNext(); public __tkey__ Current => _inner.Current.Key; object IEnumerator.Current => Current; void IEnumerator.Reset() => _inner.Reset(); } } private sealed class ValueCollection(__type____tpar__ parent) : ICollection, ICollection, IReadOnlyCollection { public void CopyTo(TValue[] array, int index) => parent.CopyValuesTo(array, index); public int Count => parent.Count; bool ICollection.IsReadOnly => true; void ICollection.Add(TValue item) => throw new NotSupportedException(); void ICollection.Clear() => throw new NotSupportedException(); public bool Contains(TValue item) => parent.ContainsValue(item); bool ICollection.Remove(TValue item) => throw new NotSupportedException(); IEnumerator IEnumerable.GetEnumerator() => new Enumerator(parent); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator(); void ICollection.CopyTo(Array array, int index) { if (array is TValue[] values) parent.CopyValuesTo(values, index); throw new ArrayTypeMismatchException(); } bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => ((ICollection)parent).SyncRoot; private class Enumerator(__type____tpar__ dictionary) : IEnumerator, IEnumerator { private __type____tpar__.Enumerator _inner = dictionary.GetEnumerator(); public void Dispose() => _inner.Dispose(); public bool MoveNext() => _inner.MoveNext(); public TValue Current => _inner.Current.Value; object IEnumerator.Current => Current; void IEnumerator.Reset() => _inner.Reset(); } } #endregion //# } // hasValue && !big && !concurrent /*# if (!concurrent) { */ #region Enumerator public Enumerator GetEnumerator() { return new Enumerator(this); } public struct Enumerator : IEnumerator/*# } */> { readonly __type__/*# if (isGeneric) { *//*# } */ m_dict; __itype__ m_index; __itype__ m_extraIndex; /*# if (hasValue) { */KeyValuePair/*# } */ m_current; public Enumerator(__type__/*# if (isGeneric) { *//*# } */ dict) { m_dict = dict; m_index = 0; m_extraIndex = -1; m_current = default(/*# if (hasValue) { */KeyValuePair/*# } */); } public readonly /*# if (hasValue) { */KeyValuePair/*# } */ Current => m_current; readonly object IEnumerator.Current => m_current; public readonly void Dispose() { } public bool MoveNext() { if (m_extraIndex < 0) { var fa = m_dict.m_firstArray; var cap = fa.Length; while (m_index < cap) { var nxt = fa[m_index].Next; if (nxt != 0) { m_current = /*# if (hasValue) { */new KeyValuePair<__tkey__, TValue>(/*# } */fa[m_index].Item__Key__/*# if (hasValue) { */, fa[m_index].Item.Value)/*# } */; m_extraIndex = nxt; m_index++; return true; } m_index++; } return false; } else { var ea = m_dict.m_extraArray; m_current = /*# if (hasValue) { */new KeyValuePair<__tkey__, TValue>(/*# } */ea[m_extraIndex].Item__Key__/*# if (hasValue) { */, ea[m_extraIndex].Item.Value)/*# } */; m_extraIndex = ea[m_extraIndex].Next; return true; } } public void Reset() { m_index = 0; m_extraIndex = -1; m_current = default(/*# if (hasValue) { */ KeyValuePair/*# } */); } } #endregion /*# } */ #region Private Helper Methods private __uitype__ ComputeIncreaseThreshold(__uitype__ capacity) { return (__uitype__)(capacity * (double)m_maxFillFactor); } private __uitype__ ComputeDecreaseThreshold(__uitype__ capacity) { return (__uitype__)(capacity * (double)m_minFillFactor); } private static __itype__ AddSlotsToFreeList( __HashItemNext__[] extraArray, __itype__ start) { var length = extraArray.Length - 1; for (__itype__ i = start; i < length; i++) extraArray[i].Next = i + 1; extraArray[length].Next = -1; return start; } private void IncreaseCapacity() { Resize(DictConstant.PrimeSizes__ext__[++m_capacityIndex], m_capacity); } private void DecreaseCapacity() { if (m_capacityIndex > 0) Resize(DictConstant.PrimeSizes__ext__[--m_capacityIndex], m_capacity); } /// /// Add item to the hashtable supplied in the parameters. /// This is used in resizing, therefore no size check is done. /// private static void Add( __HashItem__ item, __NextHashItem__[] firstArray, __uitype__ capacity, ref __HashItemNext__[] extraArray, ref __itype__ freeIndex, ref __uitype__ extraCount) { var fi = ((__uitype__)item__Hash__) % capacity; var ei = firstArray[fi].Next; if (ei == 0) { firstArray[fi].Next = -1; firstArray[fi].Item = item; return; } if (freeIndex < 0) { var length = extraArray.Length; extraArray = extraArray.Resized(length * 2); freeIndex = AddSlotsToFreeList(extraArray, length); } var ni = freeIndex; freeIndex = extraArray[ni].Next; extraArray[ni].Item = firstArray[fi].Item; extraArray[ni].Next = ei; firstArray[fi].Next = ni; firstArray[fi].Item = item; ++extraCount; } /// /// The resize method has to maintain the stack order of the lists in /// the extra array. Therefore one list reversal is necessary. /// private void Resize(__uitype__ newCapacity, __uitype__ oldCapacity) { m_increaseThreshold = ComputeIncreaseThreshold(newCapacity); m_decreaseThreshold = ComputeDecreaseThreshold(newCapacity); var firstArray = new __NextHashItem__[newCapacity]; var extraArray = new __HashItemNext__[ System.Math.Max((__itype__)DictConstant.MinExtraCapacity, m_extraArray.__ext__Length / 2)]; var freeIndex = AddSlotsToFreeList(extraArray, 1); __uitype__ newExtraCount = 0; if ((m_capacityIndex & 1) != 0) { for (__uitype__ fi = 0; fi < m_capacity; fi++) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list __itype__ head = -1; do { __itype__ next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } else { __uitype__ fi = m_capacity; while (fi-- > 0) { var ei = m_firstArray[fi].Next; if (ei == 0) continue; if (ei > 0) { // reverse the extra list __itype__ head = -1; do { __itype__ next = m_extraArray[ei].Next; m_extraArray[ei].Next = head; head = ei; ei = next; } while (ei > 0); // insert the extras into the new table do { Add(m_extraArray[head].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); head = m_extraArray[head].Next; } while (head > 0); } Add(m_firstArray[fi].Item, firstArray, newCapacity, ref extraArray, ref freeIndex, ref newExtraCount); } } if ((Report & DictReport.Resize) != 0) ReportStats((__uitype__)m_count - m_extraCount, oldCapacity, m_extraCount, (__uitype__)m_extraArray.Length, (__uitype__)m_count - newExtraCount, newCapacity, newExtraCount, (__uitype__)extraArray.Length); m_firstArray = firstArray; m_capacity = newCapacity; m_extraArray = extraArray; m_freeIndex = freeIndex; m_extraCount = newExtraCount; } private void ReportStats( __uitype__ oldFirstCount, __uitype__ oldCapacity, __uitype__ oldExtraCount, __uitype__ oldExtraCapacity, __uitype__ newFirstCount, __uitype__ newCapacity, __uitype__ newExtraCount, __uitype__ newExtraCapacity) { Base.Report.Line("\nresize at {0}:", m_count); Base.Report.Line(" old: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", oldFirstCount, oldCapacity, (100.0 * oldFirstCount) / (double)oldCapacity, oldExtraCount, oldExtraCapacity, (100.0 * oldExtraCount) / (double)oldExtraCapacity); Base.Report.Line(" new: first {0,9}/{1,-9} [{2:00.0}%] - extra {3,9}/{4,-9} [{5:00.0}%]", newFirstCount, newCapacity, (100.0 * oldFirstCount) / (double)newCapacity, newExtraCount, newExtraCapacity, (100.0 * newExtraCount) / (double)newExtraCapacity); } #endregion //# } // !wrapped } #endregion //# } // ti //# } // concurrent //# } // fast //# } // equatable #region Support Data Structures [Flags] public enum DictReport { Resize = 0x0001, } public class ConcurrentDataModifiedException : Exception { public ConcurrentDataModifiedException() { } } #endregion #region Internal Helper Structures //# foreach (var itype in new[] { "int", "long" }) { //# var Long = itype == "int" ? "" : "Long"; //# var Int = itype == "int" ? "Int" : "Long"; [StructLayout(LayoutKind.Sequential)] internal struct HashKeyValue__Long__ { public __itype__ Hash; public TKey Key; public Tvalue Value; } [StructLayout(LayoutKind.Sequential)] internal struct NextHashKeyValue__Long__ { public __itype__ Next; public HashKeyValue__Long__ Item; } [StructLayout(LayoutKind.Sequential)] internal struct HashKeyValueNext__Long__ { public HashKeyValue__Long__ Item; public __itype__ Next; } [StructLayout(LayoutKind.Sequential)] internal struct HashKey__Long__ { public __itype__ Hash; public TKey Key; } [StructLayout(LayoutKind.Sequential)] internal struct NextHashKey__Long__ { public __itype__ Next; public HashKey__Long__ Item; } [StructLayout(LayoutKind.Sequential)] internal struct HashKeyNext__Long__ { public HashKey__Long__ Item; public __itype__ Next; } [StructLayout(LayoutKind.Sequential)] internal struct __Int__Value { public __itype__ Key; public Tvalue Value; } [StructLayout(LayoutKind.Sequential)] internal struct Next__Int__Value { public __itype__ Next; public __Int__Value Item; } [StructLayout(LayoutKind.Sequential)] internal struct __Int__ValueNext { public __Int__Value Item; public __itype__ Next; } [StructLayout(LayoutKind.Sequential)] internal struct Next__Int__ { public __itype__ Next; public __itype__ Item; } [StructLayout(LayoutKind.Sequential)] internal struct __Int__Next { public __itype__ Item; public __itype__ Next; } //# } // itype [StructLayout(LayoutKind.Sequential)] internal struct SymbolValue { public Symbol Key; public Tvalue Value; } [StructLayout(LayoutKind.Sequential)] internal struct NextSymbolValue { public int Next; public SymbolValue Item; } [StructLayout(LayoutKind.Sequential)] internal struct SymbolValueNext { public SymbolValue Item; public int Next; } [StructLayout(LayoutKind.Sequential)] internal struct NextSymbol { public int Next; public Symbol Item; } [StructLayout(LayoutKind.Sequential)] internal struct SymbolNext { public Symbol Item; public int Next; } public static class DictConstant { #region Constants public const float MaxFillFactorDefault = 0.8f; // growing avg: (0.8 + 0.4)/2 = 0.6 public const float MinFillFactorDefault = 0.2f; // shrinking avg: (0.4 + 0.2)/2 = 0.3 public const int MinExtraCapacity = 4; public readonly static uint[] PrimeSizes = { /* prime no. prime */ /* 2 3, + 1 = 2^2 */ /* 4 */ 7, // + 1 = 2^3, minimal size /* 6 */ 13, // + 3 = 2^4 /* 11 */ 31, // + 1 = 2^5 /* 18 */ 61, // + 3 = 2^6 /* 31 */ 127, // + 1 = 2^7 /* 54 */ 251, // + 5 = 2^8 /* 97 */ 509, // + 3 = 2^9 /* 172 */ 1021, // + 3 = 2^10 /* 309 */ 2039, // + 9 = 2^11 /* 564 */ 4093, // + 3 = 2^12 /* 1028 */ 8191, // + 1 = 2^13 /* 1900 */ 16381, // + 3 = 2^14 /* 3512 */ 32749, // + 19 = 2^15 /* 6542 */ 65521, // + 15 = 2^16 /* 12251 */ 131071, // + 1 = 2^17 /* 23000 */ 262139, // + 5 = 2^18 /* 43390 */ 524287, // + 1 = 2^19 /* 82025 */ 1048573, // + 3 = 2^20 /* 155611 */ 2097143, // + 9 = 2^21 /* 295947 */ 4194301, // + 3 = 2^22 /* 564163 */ 8388593, // + 15 = 2^23 /* 1077871 */ 16777213, // + 3 = 2^24 /* 2063689 */ 33554393, // + 39 = 2^25 /* 3957809 */ 67108859, // + 5 = 2^26 /* 7603553 */ 134217689, // + 39 = 2^27 /* 14630843 */ 268435399, // + 57 = 2^28 /* 28192750 */ 536870909, // + 3 = 2^29 /* 54400028 */ 1073741789, // + 35 = 2^30 /* 105097565 */ 2147483647, // + 1 = 2^31 /* 203280221 */ 4294967291, // + 5 = 2^32 }; public readonly static ulong[] PrimeSizesLong = { /* prime no. prime */ /* 2 3, + 1 = 2^2 */ /* 4 */ 7, // + 1 = 2^3, minimal size /* 6 */ 13, // + 3 = 2^4 /* 11 */ 31, // + 1 = 2^5 /* 18 */ 61, // + 3 = 2^6 /* 31 */ 127, // + 1 = 2^7 /* 54 */ 251, // + 5 = 2^8 /* 97 */ 509, // + 3 = 2^9 /* 172 */ 1021, // + 3 = 2^10 /* 309 */ 2039, // + 9 = 2^11 /* 564 */ 4093, // + 3 = 2^12 /* 1028 */ 8191, // + 1 = 2^13 /* 1900 */ 16381, // + 3 = 2^14 /* 3512 */ 32749, // + 19 = 2^15 /* 6542 */ 65521, // + 15 = 2^16 /* 12251 */ 131071, // + 1 = 2^17 /* 23000 */ 262139, // + 5 = 2^18 /* 43390 */ 524287, // + 1 = 2^19 /* 82025 */ 1048573, // + 3 = 2^20 /* 155611 */ 2097143, // + 9 = 2^21 /* 295947 */ 4194301, // + 3 = 2^22 /* 564163 */ 8388593, // + 15 = 2^23 /* 1077871 */ 16777213, // + 3 = 2^24 /* 2063689 */ 33554393, // + 39 = 2^25 /* 3957809 */ 67108859, // + 5 = 2^26 /* 7603553 */ 134217689, // + 39 = 2^27 /* 14630843 */ 268435399, // + 57 = 2^28 /* 28192750 */ 536870909, // + 3 = 2^29 /* 54400028 */ 1073741789, // + 35 = 2^30 /* 105097565 */ 2147483647, // + 1 = 2^31 /* 203280221 */ 4294967291, // + 5 = 2^32 /* 393615806 */ 8589934583, // + 9 = 2^33 /* 762939111 */ 17179869143, // + 41 = 2^34 /* 1480206279 */ 34359738337, // + 31 = 2^35 /* 2874398515 */ 68719476731, // + 5 = 2^36 /* 5586502348 */ 137438953447, // + 25 = 2^37 /* 10866266172 */ 274877906899, // + 45 = 2^38 /* 21151907950 */ 549755813881, // + 7 = 2^39 /* 41203088796 */ 1099511627689, // + 87 = 2^40 /* 80316571436 */ 2199023255531, // + 21 = 2^41 /* 156661034233 */ 4398046511093, // + 11 = 2^42 /* 305761713237 */ 8796093022151, // + 57 = 2^43 /* 597116381732 */ 17592186044399, // + 17 = 2^44 }; #endregion } #endregion } ================================================ FILE: src/Aardvark.Base/Symbol/Dicts.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Aardvark.Base { #region Special Dicts public class SingleEntryDict : IDict { readonly TKey m_key; TValue m_value; bool m_hasEntry; #region Constructors public SingleEntryDict(TKey key, TValue value) { m_key = key; m_value = value; m_hasEntry = true; } #endregion #region IDict public IEnumerable Keys { get { if (m_hasEntry) yield return m_key; } } public IEnumerable Values { get { if (m_hasEntry) yield return m_value; } } public IEnumerable> KeyValuePairs { get { if (m_hasEntry) yield return new KeyValuePair(m_key, m_value); } } public TValue this[TKey key] { get { if (ContainsKey(key)) return m_value; throw new KeyNotFoundException(); } set { if (EqualityComparer.Default.Equals(key, m_key)) { m_value = value; m_hasEntry = true; return; } throw new ArgumentException(); } } public void Add(TKey key, TValue value) { if (!EqualityComparer.Default.Equals(key, m_key)) throw new ArgumentException(); if (m_hasEntry) throw new ArgumentException(); m_value = value; m_hasEntry = true; } public bool ContainsKey(TKey key) { return m_hasEntry && EqualityComparer.Default.Equals(key, m_key); } public bool Remove(TKey key) { if (!ContainsKey(key)) return false; m_hasEntry = false; m_value = default(TValue); return true; } public bool TryGetValue(TKey key, out TValue value) { if (ContainsKey(key)) { value = m_value; return true; } value = default(TValue); return false; } #endregion } /// /// An IDict where all contained keys return the same specified value. /// public class SingleValueDict : IDict, IEnumerable> { private readonly IDictSet m_keys; private readonly TValue m_value; #region Constructors public SingleValueDict(TValue value) { m_keys = new DictSet(); m_value = value; } public SingleValueDict(IDictSet keySet, TValue value) { m_keys = keySet; m_value = value; } #endregion #region IDict Members public IEnumerable Keys { get { return m_keys.Items; } } public IEnumerable Values { get { yield return m_value; } } public IEnumerable> KeyValuePairs { get { return m_keys.Items.Select(k => new KeyValuePair(k, m_value)); } } public TValue this[TKey key] { get { if (m_keys.Contains(key)) return m_value; throw new KeyNotFoundException(); } set { if (EqualityComparer.Default.Equals(value, m_value)) { m_keys.Add(key); return; } throw new ArgumentException(); } } public void Add(TKey key, TValue value) { if (EqualityComparer.Default.Equals(value, m_value)) { m_keys.Add(key); return; } throw new ArgumentException(); } public bool ContainsKey(TKey key) { return m_keys.Contains(key); } public bool Remove(TKey key) { return m_keys.Remove(key); } public bool TryGetValue(TKey key, out TValue value) { if (m_keys.Contains(key)) { value = m_value; return true; } else { value = default(TValue); return false; } } #endregion #region IEnumerable> Members public IEnumerator> GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion } /// /// An IDict where all possible keys return the same specified value. /// public class UniversalDict : IDict { private readonly TValue m_value; #region Constructor public UniversalDict(TValue value) { m_value = value; } #endregion #region IDict Members public IEnumerable Keys { get { throw new NotImplementedException(); } } public IEnumerable Values { get { yield return m_value; } } public IEnumerable> KeyValuePairs { get { throw new NotImplementedException(); } } public TValue this[TKey key] { get { return m_value; } set { if (!EqualityComparer.Default.Equals(value, m_value)) throw new ArgumentException(); } } public void Add(TKey key, TValue value) { if (!EqualityComparer.Default.Equals(value, m_value)) throw new ArgumentException(); } public bool ContainsKey(TKey key) { return true; } public bool Remove(TKey key) { throw new NotImplementedException(); } public bool TryGetValue(TKey key, out TValue value) { value = m_value; return true; } #endregion } /// /// A union of IDicts with left priority. /// public class UnionDict : IDict, IEnumerable> { readonly List> m_dictList; #region Constructors public UnionDict() { m_dictList = new List>(); } public UnionDict(IEnumerable> dicts) { m_dictList = dicts.ToList(); } public UnionDict(params IDict[] dictArray) : this((IEnumerable>)dictArray) { } #endregion #region Properties public IEnumerable> Dicts { get { return m_dictList; } } #endregion #region Manipulation Methods public void Add(IDict dict) { m_dictList.Add(dict); } #endregion #region IDict Members public IEnumerable Keys { get { return (from d in m_dictList from k in d.Keys select k) .GroupBy(k => k).Select(g => g.Key); } } public IEnumerable Values { get { return (from d in m_dictList from k in d.Keys select k) .GroupBy(k => k).Select(g => this[g.Key]); } } public IEnumerable> KeyValuePairs { get { return (from d in m_dictList from k in d.Keys select k) .GroupBy(k => k).Select(g => new KeyValuePair(g.Key, this[g.Key])); } } public TValue this[TKey key] { get { TValue value; foreach (var d in m_dictList) if (d.TryGetValue(key, out value)) return value; throw new KeyNotFoundException(); } set { throw new NotImplementedException(); } } public void Add(TKey key, TValue value) { throw new NotImplementedException(); } public bool ContainsKey(TKey key) { foreach (var d in m_dictList) if (d.ContainsKey(key)) return true; return false; } public bool Remove(TKey key) { throw new NotImplementedException(); } public bool TryGetValue(TKey key, out TValue value) { foreach (var d in m_dictList) if (d.TryGetValue(key, out value)) return true; value = default(TValue); return false; } #endregion #region IEnumerable> Members public IEnumerator> GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion } /// /// A Dict that overrides a single value of a supplied /// base Dict. /// public class SingleDeltaDict : IDict, IDictDepth, IEnumerable> { internal IDict m_baseDict; internal TKey m_key; internal TValue m_value; internal int m_depth; #region Constructors public SingleDeltaDict(IDict baseDict, TKey key, TValue value) { m_baseDict = baseDict; m_key = key; m_value = value; var dictDepth = baseDict as IDictDepth; m_depth = dictDepth != null ? dictDepth.Depth + 1 : 1; } #endregion #region IDict Members public IEnumerable Keys { get { yield return m_key; foreach (var k in m_baseDict.Keys) if (!k.Equals(m_key)) yield return k; } } public IEnumerable Values { get { yield return m_value; foreach (var kvp in m_baseDict.KeyValuePairs) if (!kvp.Key.Equals(m_key)) yield return kvp.Value; } } public IEnumerable> KeyValuePairs { get { yield return new KeyValuePair(m_key, m_value); foreach (var kvp in m_baseDict.KeyValuePairs) if (!kvp.Key.Equals(m_key)) yield return kvp; } } public TValue this[TKey key] { get { if (key.Equals(m_key)) return m_value; return m_baseDict[key]; } set { throw new NotImplementedException(); } } public void Add(TKey key, TValue value) { throw new NotImplementedException(); } public bool ContainsKey(TKey key) { if (key.Equals(m_key)) return true; return m_baseDict.ContainsKey(key); } public bool Remove(TKey key) { throw new NotImplementedException(); } public bool TryGetValue(TKey key, out TValue value) { if (key.Equals(m_key)) { value = m_value; return true; } return m_baseDict.TryGetValue(key, out value); } #endregion #region IDictDepth public int Depth { get { return m_depth; } } #endregion #region IEnumerable> Members public IEnumerator> GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion } /// /// A Dict that overrides all values contained in a delta /// Dict with respect to a supplied base Dict. /// public class DeltaDict : IDict, IDictDepth, IEnumerable> { readonly IDict m_baseDict; readonly Dict m_deltaDict; readonly int m_depth; #region Constructors public DeltaDict(IDict baseDict, Dict deltaDict) { m_baseDict = baseDict; m_deltaDict = deltaDict; var dictDepth = baseDict as IDictDepth; m_depth = dictDepth != null ? dictDepth.Depth + 1 : 1; } #endregion #region IDict Members public IEnumerable Keys { get { return m_deltaDict.Keys.Concat(m_baseDict.Keys.Where(k => !m_deltaDict.ContainsKey(k))); } } public IEnumerable Values { get { return m_deltaDict.Values.Concat(m_baseDict.KeyValuePairs.Where(kvp => !m_deltaDict.ContainsKey(kvp.Key)) .Select(kvp => kvp.Value)); } } public IEnumerable> KeyValuePairs { get { return m_deltaDict.KeyValuePairs.Concat(m_baseDict.KeyValuePairs.Where(kvp => !m_deltaDict.ContainsKey(kvp.Key))); } } public TValue this[TKey key] { get { TValue value; if (m_deltaDict.TryGetValue(key, out value)) return value; return m_baseDict[key]; } set { throw new NotImplementedException(); } } public void Add(TKey key, TValue value) { throw new NotImplementedException(); } public bool ContainsKey(TKey key) { if (m_deltaDict.ContainsKey(key)) return true; return m_baseDict.ContainsKey(key); } public bool Remove(TKey key) { throw new NotImplementedException(); } public bool TryGetValue(TKey key, out TValue value) { if (m_deltaDict.TryGetValue(key, out value)) return true; return m_baseDict.TryGetValue(key, out value); } #endregion #region IDictDepth public int Depth { get { return m_depth; } } #endregion #region IEnumerable> Members public IEnumerator> GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion } /// /// An IDict with Symbol keys where all contained keys return the same /// specified value. /// public class SingleValueSymbolDict : IDict, IEnumerable> { private readonly IDictSet m_keys; private readonly TValue m_value; #region Constructors public SingleValueSymbolDict(IDictSet keySet, TValue value) { m_keys = keySet; m_value = value; } public SingleValueSymbolDict(TValue value) { m_keys = new SymbolSet(); m_value = value; } #endregion #region IDict Members public IEnumerable Keys { get { return m_keys.Items; } } public IEnumerable Values { get { yield return m_value; } } public IEnumerable> KeyValuePairs { get { return m_keys.Items.Select(k => new KeyValuePair(k, m_value)); } } public TValue this[Symbol key] { get { if (m_keys.Contains(key)) return m_value; throw new KeyNotFoundException(); } set { if (EqualityComparer.Default.Equals(value, m_value)) { m_keys.Add(key); return; } throw new ArgumentException(); } } public void Add(Symbol key, TValue value) { if (EqualityComparer.Default.Equals(value, m_value)) { m_keys.Add(key); return; } throw new ArgumentException(); } public bool ContainsKey(Symbol key) { return m_keys.Contains(key); } public bool Remove(Symbol key) { return m_keys.Remove(key); } public bool TryGetValue(Symbol key, out TValue value) { if (m_keys.Contains(key)) { value = m_value; return true; } else { value = default(TValue); return false; } } #endregion #region IEnumerable> Members public IEnumerator> GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion } /// /// An IDict with Symbol keys where all possible keys return the same /// specified value. /// public class UniversalSymbolDict : IDict { private readonly TValue m_value; #region Constructor public UniversalSymbolDict(TValue value) { m_value = value; } #endregion #region IDict Members public IEnumerable Keys { get { throw new NotImplementedException(); } } public IEnumerable Values { get { yield return m_value; } } public IEnumerable> KeyValuePairs { get { throw new NotImplementedException(); } } public TValue this[Symbol key] { get { return m_value; } set { if (!EqualityComparer.Default.Equals(value, m_value)) throw new ArgumentException(); } } public void Add(Symbol key, TValue value) { if (!EqualityComparer.Default.Equals(value, m_value)) throw new ArgumentException(); } public bool ContainsKey(Symbol key) { return true; } public bool Remove(Symbol key) { throw new NotImplementedException(); } public bool TryGetValue(Symbol key, out TValue value) { value = m_value; return true; } #endregion } /// /// A union of IDicts with Symbol keys with left priority. /// public class UnionSymbolDict : IDict, IEnumerable> { readonly List> m_dictList; #region Constructors public UnionSymbolDict() { m_dictList = new List>(); } public UnionSymbolDict(IEnumerable> dicts) { m_dictList = dicts.ToList(); } public UnionSymbolDict(params IDict[] dictArray) : this((IEnumerable>)dictArray) { } #endregion #region Properties public IEnumerable> Dicts { get { return m_dictList; } } #endregion #region Manipulation Methods public void Add(IDict dict) { m_dictList.Add(dict); } #endregion #region IDict Members public IEnumerable Keys { get { return (from d in m_dictList from k in d.Keys select k) .GroupBy(k => k).Select(g => g.Key); } } public IEnumerable Values { get { return (from d in m_dictList from k in d.Keys select k) .GroupBy(k => k).Select(g => this[g.Key]); } } public IEnumerable> KeyValuePairs { get { return (from d in m_dictList from k in d.Keys select k) .GroupBy(k => k).Select(g => new KeyValuePair(g.Key, this[g.Key])); } } public TValue this[Symbol key] { get { TValue value; foreach (var d in m_dictList) if (d.TryGetValue(key, out value)) return value; throw new KeyNotFoundException(); } set { throw new NotImplementedException(); } } public void Add(Symbol key, TValue value) { throw new NotImplementedException(); } public bool ContainsKey(Symbol key) { foreach (var d in m_dictList) if (d.ContainsKey(key)) return true; return false; } public bool Remove(Symbol key) { throw new NotImplementedException(); } public bool TryGetValue(Symbol key, out TValue value) { foreach (var d in m_dictList) if (d.TryGetValue(key, out value)) return true; value = default(TValue); return false; } #endregion #region IEnumerable> Members public IEnumerator> GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion } /// /// A SymbolDict that overrides a single value of a supplied /// base SymbolDict. /// public class SingleDeltaSymbolDict : IDict, IEnumerable> { internal IDict m_baseDict; internal Symbol m_key; internal TValue m_value; #region Constructors public SingleDeltaSymbolDict(IDict baseDict, Symbol key, TValue value) { m_baseDict = baseDict; m_key = key; m_value = value; } #endregion #region IDict Members public IEnumerable Keys { get { yield return m_key; foreach (var k in m_baseDict.Keys) if (k != m_key) yield return k; } } public IEnumerable Values { get { yield return m_value; foreach (var kvp in m_baseDict.KeyValuePairs) if (kvp.Key != m_key) yield return kvp.Value; } } public IEnumerable> KeyValuePairs { get { yield return new KeyValuePair(m_key, m_value); foreach (var kvp in m_baseDict.KeyValuePairs) if (kvp.Key != m_key) yield return kvp; } } public TValue this[Symbol key] { get { if (key == m_key) return m_value; return m_baseDict[key]; } set { throw new NotImplementedException(); } } public void Add(Symbol key, TValue value) { throw new NotImplementedException(); } public bool ContainsKey(Symbol key) { if (key == m_key) return true; return m_baseDict.ContainsKey(key); } public bool Remove(Symbol key) { throw new NotImplementedException(); } public bool TryGetValue(Symbol key, out TValue value) { if (key == m_key) { value = m_value; return true; } return m_baseDict.TryGetValue(key, out value); } #endregion #region IEnumerable> Members public IEnumerator> GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion } /// /// A SymbolDict that overrides all values contained in a delta /// SymbolDict with respect to a supplied base SymbolDict. /// public class DeltaSymbolDict : IDict, IEnumerable> { readonly IDict m_baseDict; readonly IDict m_deltaDict; #region Constructors public DeltaSymbolDict(IDict baseDict, IDict deltaDict) { m_baseDict = baseDict; m_deltaDict = deltaDict; } #endregion #region IDict Members public IEnumerable Keys { get { return m_deltaDict.Keys.Concat(m_baseDict.Keys.Where(k => !m_deltaDict.ContainsKey(k))); } } public IEnumerable Values { get { return m_deltaDict.Values.Concat(m_baseDict.KeyValuePairs.Where(kvp => !m_deltaDict.ContainsKey(kvp.Key)) .Select(kvp => kvp.Value)); } } public IEnumerable> KeyValuePairs { get { return m_deltaDict.KeyValuePairs.Concat(m_baseDict.KeyValuePairs.Where(kvp => !m_deltaDict.ContainsKey(kvp.Key))); } } public TValue this[Symbol key] { get { TValue value; if (m_deltaDict.TryGetValue(key, out value)) return value; return m_baseDict[key]; } set { throw new NotImplementedException(); } } public void Add(Symbol key, TValue value) { throw new NotImplementedException(); } public bool ContainsKey(Symbol key) { if (m_deltaDict.ContainsKey(key)) return true; return m_baseDict.ContainsKey(key); } public bool Remove(Symbol key) { throw new NotImplementedException(); } public bool TryGetValue(Symbol key, out TValue value) { if (m_deltaDict.TryGetValue(key, out value)) return true; return m_baseDict.TryGetValue(key, out value); } #endregion #region IEnumerable> Members public IEnumerator> GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return KeyValuePairs.GetEnumerator(); } #endregion } public static class IDictExtensions { /// /// Returns an IDict with the supplied key/value pair added. Internally /// the supplied dict is not modified, but referenced, and a suitable /// DeltaDict is built that contains only the changes. /// public static IDict WithAdded( this IDict dict, TKey key, TValue value) { var sd = dict as SingleDeltaDict; if (sd != null && key.Equals(sd.m_key)) return new SingleDeltaDict(sd.m_baseDict, key, value); return new SingleDeltaDict(dict, key, value); } /// /// Return an IDict with the supplied Dict added as deltas. Internally /// the supplied dicts are not modified, but referenced, and a suitable /// DeltaDict is built. /// public static IDict WithAdded( this IDict dict, Dict deltaDict) { return new DeltaDict(dict, deltaDict); } /// /// Returns an IDict with the supplied key/value pair added. Internally /// the supplied dict is not modified, but referenced, and a suitable /// DeltaDict is built that contains only the changes. /// public static IDict WithAdded( this IDict dict, Symbol key, TValue value) { var sd = dict as SingleDeltaSymbolDict; if (sd != null && key == sd.m_key) return new SingleDeltaSymbolDict(sd.m_baseDict, key, value); return new SingleDeltaSymbolDict(dict, key, value); } /// /// Return an IDict with the supplied Dict added as deltas. Internally /// the supplied dicts are not modified, but referenced, and a suitable /// DeltaDict is built. /// public static IDict WithAdded( this IDict dict, SymbolDict deltaDict) { return new DeltaSymbolDict(dict, deltaDict); } public static bool ContainsKey( this IDict dict, TypedSymbol key) where TType : TValue { return dict.ContainsKey(key.Symbol); } public static TType Get( this IDict dict, TypedSymbol key) where TType : TValue { return (TType)dict[key.Symbol]; } public static TType Get( this IDict dict, TypedSymbol key, TType defaultValue) where TType : TValue { TValue value; if (dict.TryGetValue(key.Symbol, out value)) return (TType)value; return defaultValue; } public static TType GetOrDefault( this IDict dict, TypedSymbol key) where TType : TValue { TValue value; if (dict.TryGetValue(key.Symbol, out value)) return (TType)value; return default(TType); } public static bool TryGetValue( this IDict dict, TypedSymbol key, out TType typedValue) where TType : TValue { TValue value; if (dict.TryGetValue(key.Symbol, out value)) { typedValue = (TType)value; return true; } typedValue = default(TType); return false; } } #endregion #region Dict Extensions public static class DictFun { public static T[] GetArray(this SymbolDict dict, Symbol name) { Array array; if (dict.TryGetValue(name, out array)) return (T[])array; throw new ArgumentException( String.Format("symbol \"{0}\" not found in dictionary", name)); } public static T[] GetArray(this SymbolDict dict, Symbol name, T[] defaultArray) { Array array; if (dict.TryGetValue(name, out array)) return (T[])array; return defaultArray; } public static SymbolDict Copy( this SymbolDict self) { var r = new SymbolDict(self.Count); foreach (var kvp in self) r[kvp.Key] = kvp.Value; return r; } public static SymbolDict Copy( this SymbolDict self, Func fun) { var r = new SymbolDict(self.Count); foreach (var kvp in self) r[kvp.Key] = fun(kvp.Key, kvp.Value); return r; } public static SymbolDict Copy( this SymbolDict self, Func, KeyValuePair> fun) { var r = new SymbolDict(self.Count); foreach (var kvp in self) { var nkvp = fun(kvp); r[nkvp.Key] = nkvp.Value; } return r; } public static SymbolDict Copy( this SymbolDict self, SymbolDict> funMap, Func defaultFun) { var r = new SymbolDict(self.Count); foreach (var kvp in self) { Func fun; if (funMap.TryGetValue(kvp.Key, out fun)) r[kvp.Key] = fun(kvp.Value); else if (defaultFun != null) r[kvp.Key] = defaultFun(kvp.Value); } return r; } public static IEnumerable> KeyValueParisWith(this Dict dict, Tk key) where Tk : IEquatable { return dict.ValuesWithKey(key).Select(v => new KeyValuePair(key, v)); } public static void RemoveAll(this Dict dict, Tk key) { while (dict.Remove(key)) ; } public static void RemoveWithValue(this Dict dict, Tk key, Func remove) where Tk : IEquatable { var values = dict.ValuesWithKey(key).ToArray(); dict.RemoveAll(key); dict.AddRange(values.Where(v => !remove(v)).Select(v => new KeyValuePair(key, v))); } public static IEnumerable PopWithValue(this Dict dict, Tk key, Func remove) where Tk : IEquatable { var values = dict.ValuesWithKey(key).ToArray(); dict.RemoveAll(key); foreach (var v in values) { if (remove(v)) yield return v; else dict.Add(new KeyValuePair(key, v)); } } public static IEnumerable PopAll(this Dict dict, Tk key) where Tk : IEquatable { while (true) { Tv value; if (dict.TryGetValue(key, out value)) yield return value; else yield break; dict.Remove(key); } } public static int Pop(this IntSet self) { if (self.Count == 0) throw new InvalidOperationException(); int result = self.First(); self.Remove(result); return result; } public static T TryPop(this SymbolDict self, Symbol key) { T value = default(T); if (self.TryGetValue(key, out value)) self.Remove(key); return value; } } #endregion } ================================================ FILE: src/Aardvark.Base/Symbol/IDict.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Aardvark.Base { public interface IIntCountable { int Count { get; } } public interface ICountable { long LongCount { get; } } public interface IDict { Type KeyType { get; } Type ValueType { get; } IEnumerable<(object, object)> ObjectPairs { get; } void AddObject(object key, object value); void Clear(); } public interface ICountableDict : ICountable, IDict { } public interface IDict { IEnumerable Keys { get; } IEnumerable Values { get; } IEnumerable> KeyValuePairs { get; } TValue this[TKey key] { get; set; } void Add(TKey key, TValue value); bool ContainsKey(TKey key); bool Remove(TKey key); bool TryGetValue(TKey key, out TValue value); } public interface IDictDepth { int Depth { get; } } public interface IDictSet { Type KeyType { get; } IEnumerable Objects { get; } bool AddObject(object obj); void Clear(); } public interface ICountableDictSet : ICountable, IDictSet { } public interface IDictSet { IEnumerable Items { get; } bool Add(TKey item); bool Contains(TKey item); bool Remove(TKey item); } } ================================================ FILE: src/Aardvark.Base/Symbol/SymMapBase.cs ================================================ using System.Collections.Generic; namespace Aardvark.Base { public class SymMapBase { protected SymbolDict m_ht; protected Symbol m_typeName; #region Constructors public SymMapBase(Symbol typeName, SymbolDict ht) { m_typeName = typeName; m_ht = ht; } public SymMapBase() : this(Symbol.Empty, new SymbolDict()) { } public SymMapBase(Symbol typeName) : this(typeName, new SymbolDict()) { } public SymMapBase(SymMapBase map) : this(map.m_typeName, map.m_ht.Copy()) { } /// /// Creates a shallow copy of the supplied map, but uses entries /// in the supplied override dictionary instead of map entries /// where they exist. /// public SymMapBase(SymMapBase map, SymbolDict overrides) : this(map.m_typeName, overrides != null ? overrides.Copy() : new SymbolDict()) { if (overrides != null) { foreach (var item in map.m_ht) { if (overrides.Contains(item.Key)) continue; m_ht[item.Key] = item.Value; } } else { foreach (var item in map.m_ht) m_ht[item.Key] = item.Value; } } #endregion #region Indexer public object this[string key] { get { return m_ht[Symbol.Create(key)]; } set { m_ht[Symbol.Create(key)] = value; } } public object this[Symbol key] { get { return m_ht[key]; } set { m_ht[key] = value; } } #endregion #region Properties public Symbol TypeName { get { return m_typeName; } set { m_typeName = value; } } public IEnumerable> MapItems { get { foreach (var kvp in m_ht) yield return kvp; } } #endregion #region Typed Access public T Get(TypedSymbol key) => m_ht.Get(key); public T GetOrDefault(TypedSymbol key) => m_ht.GetOrDefault(key); public T Get(TypedSymbol key, T defaultValue) => m_ht.Get(key, defaultValue); public T Get(Symbol key) => m_ht.TryGetValue(key, out object r) ? (T)r : default; public T Get(Symbol key, T defaultValue) => m_ht.TryGetValue(key, out object r) ? (T)r : defaultValue; public void Set(TypedSymbol key, T value) => m_ht.Set(key, value); #endregion #region Queries /// /// Checks if key exists. /// public bool Contains(Symbol key) => m_ht.Contains(key); #endregion } } ================================================ FILE: src/Aardvark.Base/Symbol/SymMapBaseTraversal.cs ================================================ using System; using System.Collections.Generic; using System.IO; namespace Aardvark.Base { public delegate SymMapBase SymMapBaseVisitor(SymMapBase map, SymMapBaseTraversal.Visit visit); public class SymMapBaseTraversal { public enum Mode { NonModifying = 0x0000, Modifying = 0x0001, } [Flags] public enum Visit { Pre = 0x0001, Post = 0x0002, PreAndPost = Pre | Post, } /// /// This event fires once for each node, . /// public event SymMapBaseVisitor OnDefaultVisit; #region Constructors public SymMapBaseTraversal() { ModifyMode = Mode.Modifying; VisitMode = Visit.Pre; } public SymMapBaseTraversal(Mode mode) { ModifyMode = mode; VisitMode = Visit.Pre; } public SymMapBaseTraversal(Visit visit) { ModifyMode = Mode.NonModifying; VisitMode = visit; } public SymMapBaseTraversal(Mode mode, Visit visit) { ModifyMode = mode; VisitMode = visit; } #endregion #region Properties public Mode ModifyMode { get; set; } public Visit VisitMode { get; set; } public SymbolDict PerNameVisitors { get; } = new SymbolDict(); #endregion public SymMapBase Traverse(SymMapBase map) { // choose visitor SymMapBaseVisitor visitor = OnDefaultVisit; if (map.TypeName != null && PerNameVisitors.ContainsKey(map.TypeName)) { visitor = PerNameVisitors[map.TypeName]; } // pre visit if ((VisitMode & Visit.Pre) != 0) { if (visitor != null) { if (ModifyMode == Mode.Modifying) { map = visitor(map, Visit.Pre); } else { SymMapBase tmp = visitor(map, Visit.Pre); if (tmp != map) { throw new ArgumentException( "The node returned by a non-modifying pre-visit is " + "different from the node that has been visited. " + "This makes no sense!" ); } } } } // traverse children if (ModifyMode == Mode.Modifying) { SymbolDict tmp = new SymbolDict(); foreach (var e in map.MapItems) { tmp[e.Key] = e.Value; } foreach (var e in tmp) { object o = e.Value; if (o is SymMapBase) map[e.Key] = Traverse((SymMapBase)o); else if (o is SymMapBase[] array) { for (int i = 0; i < array.Length; i++) array[i] = Traverse(array[i]); } else if (o is List list) { for (int i = 0; i < list.Count; i++) list[i] = Traverse(list[i]); } else if (o is Dict) { var dict = new Dict(); foreach (var kvp in (Dict)o) { dict[kvp.Key] = Traverse(kvp.Value); } map[e.Key] = dict; } else if (o is SymbolDict) { var dict = new SymbolDict(); foreach (var kvp in (SymbolDict)o) { dict[kvp.Key] = Traverse(kvp.Value); } map[e.Key] = dict; } else if (o is DictSet) { var set = new DictSet(); foreach (var m in (DictSet)o) set.Add(Traverse(m)); map[e.Key] = set; } } } else { foreach (var e in map.MapItems) { object o = e.Value; if (o is SymMapBase) { Traverse((SymMapBase)o); } else if (o is SymMapBase[]) { foreach (var m in (SymMapBase[])o) Traverse(m); } else if (o is List) { foreach (var m in (List)o) Traverse(m); } else if (o is Dict) { foreach (var m in ((Dict)o).Values) Traverse(m); } else if (o is SymbolDict) { foreach (var m in ((SymbolDict)o).Values) Traverse(m); } else if (o is DictSet) { foreach (var m in (DictSet)o) Traverse(m); } } } // post visit if ((VisitMode & Visit.Post) != 0) { if (visitor != null) { if (ModifyMode == Mode.Modifying) { map = visitor(map, Visit.Post); } else { var tmp = visitor(map, Visit.Post); if (tmp != map) { throw new ArgumentException( "The node returned by a non-modifying post-visit is " + "different from the node that has been visited. " + "This makes no sense!" ); } } } } return map; } } public class SymMapBaseCollectionTraversal { [Obsolete("Use Symbol overload")] public static List Collect(SymMapBase root, string typenameToCollect) => new SymMapBaseCollectionTraversal(root).Collect((Symbol)typenameToCollect); public static List Collect(SymMapBase root, Symbol typenameToCollect) => new SymMapBaseCollectionTraversal(root).Collect(typenameToCollect); public SymMapBaseCollectionTraversal(SymMapBase root) => m_root = root; public SymMapBaseCollectionTraversal(SymMapBase root, TextWriter debugOutput) { m_root = root; m_out = debugOutput; } private readonly TextWriter m_out = null; [Obsolete("Use Symbol overload")] public List Collect(string typenameToCollect) { return Collect((Symbol)typenameToCollect); } public List Collect(Symbol typenameToCollect) { if (m_out != null) { m_out.WriteLine("SymMapBaseCollectionTraversal START"); } m_visited = new Dictionary(); m_name = typenameToCollect; m_result = new List(); SymMapBaseTraversal trav = new SymMapBaseTraversal( SymMapBaseTraversal.Mode.NonModifying, SymMapBaseTraversal.Visit.Pre ); trav.OnDefaultVisit += new SymMapBaseVisitor(Visit); trav.Traverse(m_root); if (m_out != null) { m_out.WriteLine("SymMapBaseCollectionTraversal END"); } return m_result; } private SymMapBase Visit(SymMapBase m, SymMapBaseTraversal.Visit visit) { if (m_out != null) { m_out.WriteLine("visiting {0}", m.TypeName); } if (m_visited.ContainsKey(m)) { //throw new InvalidOperationException(m.TypeName); m_visited[m] += 1; //Console.WriteLine( // "cycle detected: map {0}, {1} visits", m.TypeName, m_visited[m] // ); } else { m_visited[m] = 1; } if (m.TypeName == m_name) { m_result.Add(m); } return m; } private readonly SymMapBase m_root; private Symbol m_name; private List m_result; private Dictionary m_visited; } } ================================================ FILE: src/Aardvark.Base/Symbol/Symbol.cs ================================================ using System; using System.Collections.Generic; using System.Threading; namespace Aardvark.Base { public readonly struct Symbol : IEquatable, IComparable, IComparable { public readonly int Id; #region Internal Constructor /// /// DO NOT USE THIS CONSTRUCTOR! /// Use Create(...) instead. /// internal Symbol(int id) => Id = id; #endregion #region Static Creators public static Symbol Create(string str) => SymbolManager.GetSymbol(str); public static Symbol CreateNewGuid() => SymbolManager.GetSymbol(Guid.NewGuid()); public static Symbol Create(Guid guid) => SymbolManager.GetSymbol(guid); public static readonly Symbol Empty = default; #endregion #region Properties /// /// Returns true if the Symbol is negative. /// For details on negative symbols see the /// unary minus operator. /// public bool IsNegative => Id < 0; /// /// Returns true if the Symbol is not negative. /// For details on negative symbols see the /// unary minus operator. /// public bool IsPositive => Id > 0; public bool IsNotEmpty => Id != 0; public bool IsEmpty => Id == 0; #endregion #region Overrides public override int GetHashCode() => Id; public override bool Equals(object obj) => (obj is Symbol symbol) ? (Id == symbol.Id) : false; public override string ToString() => SymbolManager.GetString(Id); public Guid ToGuid() => SymbolManager.GetGuid(Id); #endregion #region IEquatable Members public bool Equals(Symbol other) => Id == other.Id; #endregion #region IComparable Members public int CompareTo(object obj) { if (obj is Symbol) return Id.CompareTo(((Symbol)obj).Id); else throw new NotSupportedException(string.Format("Cannot compare symbol to {0}", obj)); } #endregion #region IComparable Members public int CompareTo(Symbol other) => Id.CompareTo(other.Id); #endregion #region Operators public static bool operator ==(Symbol a, Symbol b) => a.Id == b.Id; public static bool operator !=(Symbol a, Symbol b) => a.Id != b.Id; /// /// Creates a negative symbol from an ordinary symbol. /// Negative symbols have no string representation, they /// are however useful to store a second value in a /// dictionary. /// public static Symbol operator -(Symbol symbol) => new Symbol(-symbol.Id); #endregion #region Conversion public static implicit operator Symbol(string str) => Create(str); #endregion } public interface ITypedSymbol { Symbol GetSymbol(); Type GetSymbolType(); } /// /// A typed symbol is a symbol that is associated with /// a type at compile time. This can be used in Dicts /// to associate each key with a value type. /// public readonly struct TypedSymbol : ITypedSymbol { public readonly Symbol Symbol; #region Constructor public TypedSymbol(string str) => Symbol = str; public TypedSymbol(Symbol symbol) => Symbol = symbol; #endregion #region ITypedSymbol Members public Symbol GetSymbol() => Symbol; public Type GetSymbolType() => typeof(T); #endregion #region Conversion public static implicit operator TypedSymbol(string str) => new TypedSymbol(str); #endregion } public static class SymbolExtensions { public static Symbol ToSymbol(this string str) => Symbol.Create(str); public static TypedSymbol WithType(this Symbol symbol) => new TypedSymbol(symbol); /// /// Returns the result of .ToString() of an objects as Symbol. /// public static Symbol ToSymbol(this object self) => Symbol.Create(self.ToString()); } internal static class SymbolManager { private static readonly Dict s_stringDict = new Dict(1024); private static readonly Dict s_guidDict = new Dict(1024); private static readonly List s_allStrings = new List(1024); private static readonly List s_allGuids = new List(1024); private static SpinLock s_lock = new SpinLock(); static SymbolManager() { s_allStrings.Add(string.Empty); s_allGuids.Add(Guid.Empty); } internal static Symbol GetSymbol(Guid guid) { int id; var locked = false; try { s_lock.Enter(ref locked); if (!s_guidDict.TryGetValue(guid, out id)) { id = s_allStrings.Count; var str = guid.ToString(); s_guidDict.Add(guid, id); s_stringDict.Add(str, id); s_allStrings.Add(str); s_allGuids.Add(guid); } } finally { if (locked) s_lock.Exit(); } return new Symbol(id); } internal static Symbol GetSymbol(string str) { if (string.IsNullOrEmpty(str)) return default; int id; int hash = str.GetHashCode(); // hashcode computation outside spinlock var locked = false; try { s_lock.Enter(ref locked); if (!s_stringDict.TryGetValue(str, hash, out id)) { id = s_allStrings.Count; s_stringDict.Add(str, hash, id); s_allStrings.Add(str); s_allGuids.Add(Guid.Empty); } } finally { if (locked) s_lock.Exit(); } return new Symbol(id); } internal static Guid GetGuid(int id) { if (id > 0) { var locked = false; try { s_lock.Enter(ref locked); return s_allGuids[id]; } finally { if (locked) s_lock.Exit(); } } return Guid.Empty; } internal static string GetString(int id) { var locked = false; if (id > 0) { try { s_lock.Enter(ref locked); return s_allStrings[id]; } finally { if (locked) s_lock.Exit(); } } else if (id < 0) { string str; try { s_lock.Enter(ref locked); str = s_allStrings[-id]; } finally { if (locked) s_lock.Exit(); } return "-" + str; } return string.Empty; } } } ================================================ FILE: src/Aardvark.Base/Text/Text.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Text; using System.Text.RegularExpressions; namespace Aardvark.Base { /// /// A facade structure that represents a part of a string. /// This can be used to do string manipulations without copying /// too many strings. /// public struct Text : IEquatable { public readonly int Start; public readonly int End; public readonly string String; #region Constructors public Text(string str) { Start = 0; End = str.Length; String = str; } public Text(string str, int start) { Start = start; End = str.Length; String = str; } public Text(string str, int start, int count) { Start = start; End = start + count; String = str; } public Text(int start, int end, string str) { Start = start; End = end; String = str; } #endregion #region Constants public static readonly Text Empty = new Text(null, 0, 0); #endregion #region Properties public readonly int Count => End - Start; public readonly bool IsEmpty => Count <= 0; public readonly bool IsWhiteSpace => IsOnly(CharFun.IsWhiteSpace); public readonly Text WhiteSpaceAtStartTrimmed => TrimmedAtStart(CharFun.IsWhiteSpace); public readonly Text WhiteSpaceAtEndTrimmed => TrimmedAtEnd(CharFun.IsWhiteSpace); public readonly Text WhiteSpaceTrimmed => Trimmed(CharFun.IsWhiteSpace); #endregion #region Indexer public readonly char this[int index] => String[Start + index]; #endregion #region Processing Methods public readonly int IndexOf(char ch) { var index = String.IndexOf(ch, Start, Count); return index < 0 ? -1 : index - Start; } public readonly int IndexOf(string str) { var index = String.IndexOf(str, Start, Count); return index < 0 ? -1 : index - Start; } public readonly int IndexOf(char ch, int start) { if (start >= 0) { start += Start; if (start >= End) return -1; } else start = Math.Max(Start, start + End); var index = String.IndexOf(ch, start, End - start); return index < 0 ? -1 : index - Start; } public readonly int IndexOf(string str, int start) { if (start >= 0) { start += Start; if (start >= End) return -1; } else start = Math.Max(Start, start + End); var index = String.IndexOf(str, start, End - start); return index < 0 ? -1 : index - Start; } public readonly int IndexOf(char ch, int start, int count) { if (start >= 0) { start += Start; if (start >= End) return -1; } else start = Math.Max(Start, start + End); var index = String.IndexOf(ch, start, Math.Min(count, End - start)); return index < 0 ? -1 : index - Start; } public readonly int IndexOf(string str, int start, int count) { if (start >= 0) { start += Start; if (start >= End) return -1; } else start = Math.Max(Start, start + End); var index = String.IndexOf(str, start, Math.Min(count, End - start)); return index < 0 ? -1 : index - Start; } public readonly int LastIndexOf(char ch) { var index = String.LastIndexOf(ch, Start, Count); return index < 0 ? -1 : index - Start; } public readonly int LastIndexOf(string str) { var index = String.LastIndexOf(str, Start, Count); return index < 0 ? -1 : index - Start; } public readonly int LastIndexOf(char ch, int start) { if (start >= 0) { start += Start; if (start >= End) return -1; } else start = Math.Max(Start, start + End); var index = String.LastIndexOf(ch, start, End - start); return index < 0 ? -1 : index - Start; } public readonly int LastIndexOf(string str, int start) { if (start >= 0) { start += Start; if (start >= End) return -1; } else start = Math.Max(Start, start + End); var index = String.LastIndexOf(str, start, End - start); return index < 0 ? -1 : index - Start; } public readonly int LastIndexOf(char ch, int start, int count) { if (start >= 0) { start += Start; if (start >= End) return -1; } else start = Math.Max(Start, start + End); var index = String.LastIndexOf(ch, start, Math.Min(count, End - start)); return index < 0 ? -1 : index - Start; } public readonly int LastIndexOf(string str, int start, int count) { if (start >= 0) { start += Start; if (start >= End) return -1; } else start = Math.Max(Start, start + End); var index = String.LastIndexOf(str, start, Math.Min(count, End - start)); return index < 0 ? -1 : index - Start; } /// /// Return the subtext in the range [start, end). For the start /// index, negative indices count from the end. For the end index, /// negative indices and the index 0 count from the end. The ranges /// are clamped to the input text so that no exceptions can occur. /// If the the start and end index are crossed, the empty text is /// returned. As an example the call t.Sub(-3, 0) returns a text /// containing the last 3 characters t or the complete text t, if /// its length is less than 3 characters. /// public readonly Text Sub(int start, int end) { start = start < 0 ? Math.Max(Start, End + start) : Math.Min(Start + start, End); end = end <= 0 ? Math.Max(Start, End + end) : Math.Min(Start + end, End); return start < end ? new Text(start, end, String) : Empty; } public readonly string SubString(int start, int count) { start += Start; return start < End ? String.Substring(start, Math.Min(count, End - start)) : ""; } public readonly Text SubText(int start) { start += Start; return start < End ? new Text(start, End, String) : Empty; } public readonly Text SubText(int start, int count) { start += Start; return start < End ? new Text(start, Math.Min(start + count, End), String) : Empty; } public readonly bool StartsWith(string prefix) { int c = prefix.Length; if (c > Count) return false; for (int i = 0, p = Start; i < c; i++, p++) if (prefix[i] != String[p]) return false; return true; } public readonly bool EndsWith(string postfix) { int c = postfix.Length; if (c > Count) return false; for (int i = 0, p = End - c; i < c; i++, p++) if (postfix[i] != String[p]) return false; return true; } public readonly bool StartsWith(Text prefix) { int c = prefix.Count; if (c > Count) return false; for (int p = Start, e = Start + c, q = prefix.Start; p < e; p++, q++) if (prefix.String[q] != String[p]) return false; return true; } public readonly bool EndsWith(Text postfix) { int c = postfix.Count; if (c > Count) return false; for (int p = End - c, e = End, q = postfix.Start; p < e; p++, q++) if (postfix.String[q] != String[p]) return false; return true; } /// /// Returns true if the supplied predicate is true for all characters /// of the text. /// public readonly bool IsOnly(Func charPredicate) { for (int i = Start, e = End; i < e; i++) { if (charPredicate(String[i])) continue; return false; } return true; } /// /// Returns the text without the characters at the start, for which /// the supplied predicate is true. /// public readonly Text TrimmedAtStart(Func trimIfTrue) { for (int s = Start, e = End; s < e; s++) { if (trimIfTrue(String[s])) continue; return new Text(s, e, String); } return Empty; } /// /// Returns the text without the characters at the end, for which /// the supplied predicate is true. /// public readonly Text TrimmedAtEnd(Func trimIfTrue) { for (int s = Start, e = End - 1; s <= e; e--) { if (trimIfTrue(String[e])) continue; return new Text(s, 1 + e, String); } return Empty; } /// /// Returns the text without the caracters at the start and at the /// end, for which the supplied predicate is true. /// /// public readonly Text Trimmed(Func trimIfTrue) { for (int s = Start, e = End; s < e; s++) { if (trimIfTrue(String[s])) continue; for (--e; s < e; e--) // String[s] already tested { if (trimIfTrue(String[e])) continue; return new Text(s, 1 + e, String); } } return Empty; } #endregion #region Overrides public override readonly string ToString() => String.Substring(Start, Count); public override readonly int GetHashCode() { int hc = Count; for (int i = Start, e = End; i < e; i++) hc = hc * 31 + String[i]; return hc; } public override readonly bool Equals(object obj) => obj is Text ? this == (Text)obj : false; #endregion #region Operators public static bool operator ==(Text t, Text t1) { if (t.Count != t1.Count) return false; string s = t.String, s1 = t1.String; if (s == s1 && t.Start == t1.Start) return true; for (int i = t.Start, e = t.End, i1 = t1.Start; i < e; i++, i1++) if (s[i] != s1[i1]) return false; return true; } public static bool operator !=(Text t, Text t1) { if (t.Count != t1.Count) return true; string s = t.String, s1 = t1.String; if (s == s1 && t.Start == t1.Start) return false; for (int i = t.Start, e = t.End, i1 = t1.Start; i < e; i++, i1++) if (s[i] != s1[i1]) return true; return false; } public static bool operator ==(Text t, string s1) { if (t.Count != s1.Length) return false; string s = t.String; if (s == s1 && t.Start == 0) return true; for (int i = t.Start, e = t.End, i1 = 0; i < e; i++, i1++) if (s[i] != s1[i1]) return false; return true; } public static bool operator !=(Text t, string s1) { if (t.Count != s1.Length) return true; string s = t.String; if (s == s1 && t.Start == 0) return false; for (int i = t.Start, e = t.End, i1 = 0; i < e; i++, i1++) if (s[i] != s1[i1]) return true; return false; } #endregion #region Various Operations public static Regex IdentifierRegex = new Regex(@"\b[A-Za-z_][0-9A-Za-z_]*\b"); public readonly Text ReplaceIdentifiers(Dictionary changeMap) => ReplaceParts(IdentifierRegex, changeMap); public readonly Text ReplaceParts( Regex partRegex, Dictionary changeMap) { StringBuilder newText = new StringBuilder(); var str = String; int pos = Start, end = End; Match match = partRegex.Match(str, pos, end - pos); while (match.Success) { Group group = match.Groups[1]; newText.Append(str, pos, match.Index - pos); var unchanged = match.Value; if (changeMap.TryGetValue(unchanged, out string changed)) newText.Append(changed); else newText.Append(unchanged); pos = match.Index + match.Length; if (pos >= end) break; match = partRegex.Match(str, pos, end - pos); } if (pos > 0) { if (pos < end) newText.Append(str, pos, end - pos); return new Text(newText.ToString()); } return this; } /// /// Splits a nested structure of comma-separated square bracked /// delimited lists at a specified split level. Level 0 means that /// the split is performed outside the outermost square brackets. /// Level 1 means that the split is peformed inside the outermost /// square brackets. /// NOTE: The resulting parts are not trimmed. Use the Trim extension /// to trim all resulting strings. /// public readonly IEnumerable NestedBracketSplit(int splitLevel) { int level = 0; int begin = Start; int end = End; for (int pos = Start; pos < end; pos++) { switch (String[pos]) { case '[': ++level; if (level == splitLevel) begin = pos + 1; break; case ']': if (level == splitLevel) yield return new Text(begin, pos, String); --level; break; case ',': if (level == splitLevel) { yield return new Text(begin, pos, String); begin = pos + 1; } break; } } if (level == splitLevel && begin < end) yield return new Text(begin, end, String); } #endregion #region Parsing /// /// This structure holds info about where the line with the number /// (Index - 1) starts. /// public struct Line { public int Index; public int Start; public Line(int count, int start) { Index = count; Start = start; } } /// /// Given a known previous line, get the line at the current position. /// public readonly Line GetLineOfPos(Line line, int pos) { int i = line.Start; while (i < pos) { if (String[Start + i] == '\n') { ++i; ++line.Index; line.Start = i; } else ++i; } return line; } /// /// Get the line of the current position without knowledge of any /// pervious line. /// public readonly Line GetLineOfPos(int pos) => GetLineOfPos(new Line(0, 0), pos); /// /// Returns the first position after position start in the text, that /// does not contain a whitespace character, or the length of the text /// if it is all whitespace. /// public readonly int SkipWhiteSpace(int start = 0) => Skip(CharFun.IsWhiteSpace, start); public readonly int Skip(Func skipFun, int start = 0) { for (int i = Start + start, e = End; i < e; i++) { if (skipFun(String[i])) continue; return i - Start; } return End - Start; } public readonly bool ParseBool() { int i = SkipWhiteSpace(), c = Count; if (i == c) throw new ArgumentException(); var pv = ParsedValueOfBoolAt(i); if (pv.Error != ParseError.None) throw new ArgumentException(); i += pv.Length; if (i < c && SkipWhiteSpace(i) < c) throw new ArgumentException(); return pv.Value; } public readonly byte ParseByte() { int i = SkipWhiteSpace(), c = Count; if (i == c) throw new ArgumentException(); var pv = ParsedValueOfByteAt(i); if (pv.Error != ParseError.None) throw new ArgumentException(); i += pv.Length; if (i < c && SkipWhiteSpace(i) < c) throw new ArgumentException(); return pv.Value; } public readonly sbyte ParseSByte() { int i = SkipWhiteSpace(), c = Count; if (i == c) throw new ArgumentException(); var pv = ParsedValueOfSByteAt(i); if (pv.Error != ParseError.None) throw new ArgumentException(); i += pv.Length; if (i < c && SkipWhiteSpace(i) < c) throw new ArgumentException(); return pv.Value; } public readonly short ParseShort() { int i = SkipWhiteSpace(), c = Count; if (i == c) throw new ArgumentException(); var pv = ParsedValueOfShortAt(i); if (pv.Error != ParseError.None) throw new ArgumentException(); i += pv.Length; if (i < c && SkipWhiteSpace(i) < c) throw new ArgumentException(); return pv.Value; } public readonly ushort ParseUShort() { int i = SkipWhiteSpace(), c = Count; if (i == c) throw new ArgumentException(); var pv = ParsedValueOfUShortAt(i); if (pv.Error != ParseError.None) throw new ArgumentException(); i += pv.Length; if (i < c && SkipWhiteSpace(i) < c) throw new ArgumentException(); return pv.Value; } public readonly int ParseInt() { int i = SkipWhiteSpace(), c = Count; if (i == c) throw new ArgumentException(); var pv = ParsedValueOfIntAt(i); if (pv.Error != ParseError.None) throw new ArgumentException(); i += pv.Length; if (i < c && SkipWhiteSpace(i) < c) throw new ArgumentException(); return pv.Value; } public readonly uint ParseUInt() { int i = SkipWhiteSpace(), c = Count; if (i == c) throw new ArgumentException(); var pv = ParsedValueOfUIntAt(i); if (pv.Error != ParseError.None) throw new ArgumentException(); i += pv.Length; if (i < c && SkipWhiteSpace(i) < c) throw new ArgumentException(); return pv.Value; } public readonly long ParseLong() { int i = SkipWhiteSpace(), c = Count; if (i == c) throw new ArgumentException(); var pv = ParsedValueOfLongAt(i); if (pv.Error != ParseError.None) throw new ArgumentException(); i += pv.Length; if (i < c && SkipWhiteSpace(i) < c) throw new ArgumentException(); return pv.Value; } public readonly ulong ParseULong() { int i = SkipWhiteSpace(), c = Count; if (i == c) throw new ArgumentException(); var pv = ParsedValueOfULongAt(i); if (pv.Error != ParseError.None) throw new ArgumentException(); i += pv.Length; if (i < c && SkipWhiteSpace(i) < c) throw new ArgumentException(); return pv.Value; } public readonly float ParseFloat() { int i = SkipWhiteSpace(), c = Count; if (i == c) throw new ArgumentException(); var pv = ParsedValueOfFloatAt(i); if (pv.Error != ParseError.None) throw new ArgumentException(); i += pv.Length; if (i < c && SkipWhiteSpace(i) < c) throw new ArgumentException(); return pv.Value; } public readonly double ParseDouble() { int i = SkipWhiteSpace(), c = Count; if (i == c) throw new ArgumentException(); var pv = ParsedValueOfDoubleAt(i); if (pv.Error != ParseError.None) throw new ArgumentException(); i += pv.Length; if (i < c && SkipWhiteSpace(i) < c) throw new ArgumentException(); return pv.Value; } public readonly decimal ParseDecimal() { int i = SkipWhiteSpace(), c = Count; if (i == c) throw new ArgumentException(); var pv = ParsedValueOfDecimalAt(i); if (pv.Error != ParseError.None) throw new ArgumentException(); i += pv.Length; if (i < c && SkipWhiteSpace(i) < c) throw new ArgumentException(); return pv.Value; } private static readonly Regex s_boolRegex = new Regex(@"(?<1>false|f)|(?<2>true|t)|(?<3>.|\r)", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.Compiled); public readonly ParsedValue ParsedValueOfBoolAt(int start) { start += Start; if (start >= End) return new ParsedValue(ParseError.EndOfText, 0); var match = s_boolRegex.Match(String, start, 5); if (!match.Success) return new ParsedValue(ParseError.OutOfRange, 0); if (match.Groups[1].Success) return new ParsedValue(false, match.Length); if (match.Groups[2].Success) return new ParsedValue(true, match.Length); return new ParsedValue(ParseError.OutOfRange, 0); } public readonly ParsedValue ParsedValueOfByteAt(int start) { start += Start; int pos = start; int end = End; int ch = 0; if (pos >= end) return new ParsedValue(ParseError.EndOfText, 0); if ((ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { ++pos; byte v = (byte)ch; int c = 1; while (pos < end && (ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { byte v1 = (byte)(v * 10 + ch); if (++c > 2 && v != v1 / 10) return new ParsedValue(ParseError.OutOfRange, pos - start); v = v1; ++pos; } return new ParsedValue(v, pos - start); } return new ParsedValue(ParseError.IllegalCharacter, pos - start); } public readonly ParsedValue ParsedValueOfSByteAt(int start) { start += Start; int pos = start; int end = End; int ch = 0; if (pos >= end) return new ParsedValue(ParseError.EndOfText, 0); if (String[pos] == '-') { if (++pos == end) return new ParsedValue(ParseError.EndOfText, 1); if ((ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { ++pos; sbyte v = (sbyte)(-ch); int c = 1; while (pos < end && (ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { sbyte v1 = (sbyte)(v * 10 - ch); if (++c > 2 && v != v1 / 10L) return new ParsedValue(ParseError.OutOfRange, pos - start); v = v1; ++pos; } return new ParsedValue(v, pos - start); } } else { if (String[pos] == '+') { if (++pos == end) return new ParsedValue(ParseError.EndOfText, 1); } if ((ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { ++pos; sbyte v = (sbyte)ch; int c = 1; while (pos < end && (ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { sbyte v1 = (sbyte)(v * 10 + ch); if (++c > 2 && v != v1 / 10L) return new ParsedValue(ParseError.OutOfRange, pos - start); v = v1; ++pos; } return new ParsedValue(v, pos - start); } } return new ParsedValue(ParseError.IllegalCharacter, pos - start); } public readonly ParsedValue ParsedValueOfShortAt(int start) { start += Start; int pos = start; int end = End; int ch = 0; if (pos >= end) return new ParsedValue(ParseError.EndOfText, 0); if (String[pos] == '-') { if (++pos == end) return new ParsedValue(ParseError.EndOfText, 1); if ((ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { ++pos; short v = (short)(-ch); int c = 1; while (pos < end && (ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { short v1 = (short)(v * 10 - ch); if (++c > 4 && v != v1 / 10L) return new ParsedValue(ParseError.OutOfRange, pos - start); v = v1; ++pos; } return new ParsedValue(v, pos - start); } } else { if (String[pos] == '+') { if (++pos == end) return new ParsedValue(ParseError.EndOfText, 1); } if ((ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { ++pos; short v = (short)ch; int c = 1; while (pos < end && (ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { short v1 = (short)(v * 10 + ch); if (++c > 4 && v != v1 / 10L) return new ParsedValue(ParseError.OutOfRange, pos - start); v = v1; ++pos; } return new ParsedValue(v, pos - start); } } return new ParsedValue(ParseError.IllegalCharacter, pos - start); } public readonly ParsedValue ParsedValueOfUShortAt(int start) { start += Start; int pos = start; int end = End; int ch = 0; if (pos >= end) return new ParsedValue(ParseError.EndOfText, 0); if ((ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { ++pos; ushort v = (ushort)ch; int c = 1; while (pos < end && (ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { ushort v1 = (ushort)(v * 10 + ch); if (++c > 4 && v != v1 / 10L) return new ParsedValue(ParseError.OutOfRange, pos - start); v = v1; ++pos; } return new ParsedValue(v, pos - start); } return new ParsedValue(ParseError.IllegalCharacter, pos - start); } public readonly ParsedValue ParsedValueOfIntAt(int start) { start += Start; int pos = start; int end = End; int ch = 0; if (pos >= end) return new ParsedValue(ParseError.EndOfText, 0); if (String[pos] == '-') { if (++pos == end) return new ParsedValue(ParseError.EndOfText, 1); if ((ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { ++pos; int v = -ch; int c = 1; while (pos < end && (ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { int v1 = v * 10 - ch; if (++c > 9 && v != v1 / 10L) return new ParsedValue(ParseError.OutOfRange, pos - start); v = v1; ++pos; } return new ParsedValue(v, pos - start); } } else { if (String[pos] == '+') { if (++pos == end) return new ParsedValue(ParseError.EndOfText, 1); } if ((ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { ++pos; int v = ch; int c = 1; while (pos < end && (ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { int v1 = v * 10 + ch; if (++c > 9 && v != v1 / 10L) return new ParsedValue(ParseError.OutOfRange, pos - start); v = v1; ++pos; } return new ParsedValue(v, pos - start); } } return new ParsedValue(ParseError.IllegalCharacter, pos - start); } public readonly ParsedValue ParsedValueOfUIntAt(int start) { start += Start; int pos = start; int end = End; int ch = 0; if (pos >= end) return new ParsedValue(ParseError.EndOfText, 0); if ((ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { ++pos; uint v = (uint)ch; int c = 1; while (pos < end && (ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { uint v1 = v * 10 + (uint)ch; if (++c > 9 && v != v1 / 10L) return new ParsedValue(ParseError.OutOfRange, pos - start); v = v1; ++pos; } return new ParsedValue(v, pos - start); } return new ParsedValue(ParseError.IllegalCharacter, pos - start); } public readonly ParsedValue ParsedValueOfLongAt(int start) { start += Start; int pos = start; int end = End; int ch = 0; if (pos >= end) return new ParsedValue(ParseError.EndOfText, 0); if (String[pos] == '-') { if (++pos == end) return new ParsedValue(ParseError.EndOfText, 1); if ((ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { ++pos; long v = -ch; int c = 1; while (pos < end && (ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { long v1 = v * 10 - ch; if (++c > 18 && v != v1 / 10L) return new ParsedValue(ParseError.OutOfRange, pos - start); v = v1; ++pos; } return new ParsedValue(v, pos - start); } } else { if (String[pos] == '+') { if (++pos == end) return new ParsedValue(ParseError.EndOfText, 1); } if ((ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { ++pos; long v = ch; int c = 1; while (pos < end && (ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { long v1 = v * 10 + ch; if (++c > 18 && v != v1 / 10L) return new ParsedValue(ParseError.OutOfRange, pos - start); v = v1; ++pos; } return new ParsedValue(v, pos - start); } } return new ParsedValue(ParseError.IllegalCharacter, pos - start); } public readonly ParsedValue ParsedValueOfULongAt(int start) { start += Start; int pos = start; int end = End; int ch = 0; if (pos >= end) return new ParsedValue(ParseError.EndOfText, 0); if ((ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { ++pos; ulong v = (ulong)ch; int c = 1; while (pos < end && (ch = (int)(String[pos] - '0')) >= 0 && ch < 10) { ulong v1 = v * 10 + (ulong)ch; if (++c > 18 && v != v1 / 10L) return new ParsedValue(ParseError.OutOfRange, pos - start); v = v1; ++pos; } return new ParsedValue(v, pos - start); } return new ParsedValue(ParseError.IllegalCharacter, pos - start); } public readonly ParsedValue ParsedValueOfFloatAt(int start) { start += Start; int pos = start; int end = End; if (pos >= end) return new ParsedValue(ParseError.EndOfText, 0); char ch; if ((ch = String[pos]) == '-' || ch == '+') { pos++; if (pos == end) return new ParsedValue(ParseError.EndOfText, pos - start); } if ((ch = String[pos]) < '0' || ch > '9') return new ParsedValue(ParseError.IllegalCharacter, pos - start); while (pos < end && (ch = String[pos]) >= '0' && ch <= '9') pos++; if (pos < end && ch == '.') { ++pos; while (pos < end && (ch = String[pos]) >= '0' && ch <= '9') pos++; } if (pos < end && (ch == 'e' || ch == 'E')) { ++pos; if (pos == end) return new ParsedValue(ParseError.EndOfText, pos - start); if ((ch = String[pos]) == '-' || ch == '+') { pos++; if (pos == end) return new ParsedValue(ParseError.EndOfText, pos - start); } if ((ch = String[pos]) < '0' || ch > '9') return new ParsedValue(ParseError.IllegalCharacter, pos - start); ++pos; while (pos < end && (ch = String[pos]) >= '0' && ch <= '9') pos++; } int len = pos - start; try { return new ParsedValue(float.Parse(String.Substring(start, len), CultureInfo.InvariantCulture), len); } catch { return new ParsedValue(ParseError.OutOfRange, len); } } public readonly ParsedValue ParsedValueOfDoubleAt(int start) { start += Start; int pos = start; int end = End; if (pos >= end) return new ParsedValue(ParseError.EndOfText, 0); char ch; if ((ch = String[pos]) == '-' || ch == '+') { pos++; if (pos == end) return new ParsedValue(ParseError.EndOfText, pos - start); } if ((ch = String[pos]) < '0' || ch > '9') return new ParsedValue(ParseError.IllegalCharacter, pos - start); while (pos < end && (ch = String[pos]) >= '0' && ch <= '9') pos++; if (pos < end && ch == '.') { ++pos; while (pos < end && (ch = String[pos]) >= '0' && ch <= '9') pos++; } if (pos < end && (ch == 'e' || ch == 'E')) { ++pos; if (pos == end) return new ParsedValue(ParseError.EndOfText, pos - start); if ((ch = String[pos]) == '-' || ch == '+') { pos++; if (pos == end) return new ParsedValue(ParseError.EndOfText, pos - start); } if ((ch = String[pos]) < '0' || ch > '9') return new ParsedValue(ParseError.IllegalCharacter, pos - start); ++pos; while (pos < end && (ch = String[pos]) >= '0' && ch <= '9') pos++; } int len = pos - start; try { return new ParsedValue(double.Parse(String.Substring(start, len), CultureInfo.InvariantCulture), len); } catch { return new ParsedValue(ParseError.OutOfRange, len); } } public readonly ParsedValue ParsedValueOfDecimalAt(int start) { start += Start; int pos = start; int end = End; if (pos >= end) return new ParsedValue(ParseError.EndOfText, 0); char ch; if ((ch = String[pos]) == '-' || ch == '+') { pos++; if (pos == end) return new ParsedValue(ParseError.EndOfText, pos - start); } if ((ch = String[pos]) < '0' || ch > '9') return new ParsedValue(ParseError.IllegalCharacter, pos - start); while (pos < end && (ch = String[pos]) >= '0' && ch <= '9') pos++; if (pos < end && ch == '.') { ++pos; while (pos < end && (ch = String[pos]) >= '0' && ch <= '9') pos++; } int len = pos - start; try { return new ParsedValue(decimal.Parse(String.Substring(start, len), CultureInfo.InvariantCulture), len); } catch { return new ParsedValue(ParseError.OutOfRange, len); } } #endregion #region IEquatable Members public readonly bool Equals(Text other) => this == other; #endregion } public readonly struct Rx { public readonly string Pattern; public readonly Regex Regex; /// /// A second regex is built if the match has to be anchored at the /// start of the search (sub-)string (the caret only works for non- /// sub strings). This is done by adding an always matching second /// group of one character. Thus if the second group succeeds, the /// regex did not match anchored at the start of the search string. /// public readonly Regex AnchoredRegex; #region Constructor public Rx(string pattern) { Pattern = pattern; Regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled); AnchoredRegex = new Regex("(?<1>" + pattern + ")|(?<2>.|\r)", RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled); } public Rx(string pattern, RegexOptions options) { Pattern = pattern; Regex = new Regex(pattern, options | RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled); AnchoredRegex = new Regex("(?<1>" + pattern + ")|(?<2>.|\r)", options | RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled); } #endregion } public enum ParseError { None = 0, EndOfText, IllegalCharacter, OutOfRange, } /// /// A parsed value contains the actual value, the number of characters /// that have been parsed in Length, and an error value of the parse /// operation. /// public readonly struct ParsedValue { public readonly ParseError Error; public readonly T Value; public readonly int Length; #region Constructors public ParsedValue(T value, int count) { Value = value; Error = ParseError.None; Length = count; } public ParsedValue(ParseError error, int count) { Value = default; Error = error; Length = count; } #endregion #region Properties public bool IsValid => Error == ParseError.None; public bool IsInValid => Error != ParseError.None; #endregion } public static class Text { public static readonly Func Parse; public static readonly Func> ParsedValueAt; #region Constructor static Text() { if (typeof(T) == typeof(byte)) { Parse = (Func)(object)(Func)(t => t.ParseByte()); ParsedValueAt = (Func>)(object)(Func>)((t, i) => t.ParsedValueOfByteAt(i)); } else if (typeof(T) == typeof(sbyte)) { Parse = (Func)(object)(Func)(t => t.ParseSByte()); ParsedValueAt = (Func>)(object)(Func>)((t, i) => t.ParsedValueOfSByteAt(i)); } else if (typeof(T) == typeof(short)) { Parse = (Func)(object)(Func)(t => t.ParseShort()); ParsedValueAt = (Func>)(object)(Func>)((t, i) => t.ParsedValueOfShortAt(i)); } else if (typeof(T) == typeof(ushort)) { Parse = (Func)(object)(Func)(t => t.ParseUShort()); ParsedValueAt = (Func>)(object)(Func>)((t, i) => t.ParsedValueOfUShortAt(i)); } else if (typeof(T) == typeof(int)) { Parse = (Func)(object)(Func)(t =>t.ParseInt()); ParsedValueAt = (Func>)(object)(Func>)((t, i) => t.ParsedValueOfIntAt(i)); } else if (typeof(T) == typeof(uint)) { Parse = (Func)(object)(Func)(t => t.ParseUInt()); ParsedValueAt = (Func>)(object)(Func>)((t, i) => t.ParsedValueOfUIntAt(i)); } else if (typeof(T) == typeof(long)) { Parse = (Func)(object)(Func)(t => t.ParseLong()); ParsedValueAt = (Func>)(object)(Func>)((t, i) => t.ParsedValueOfLongAt(i)); } else if (typeof(T) == typeof(ulong)) { Parse = (Func)(object)(Func)(t => t.ParseULong()); ParsedValueAt = (Func>)(object)(Func>)((t, i) => t.ParsedValueOfULongAt(i)); } else if (typeof(T) == typeof(float)) { Parse = (Func)(object)(Func)(t => t.ParseFloat()); ParsedValueAt = (Func>)(object)(Func>)((t, i) => t.ParsedValueOfFloatAt(i)); } else if (typeof(T) == typeof(double)) { Parse = (Func)(object)(Func)(t => t.ParseDouble()); ParsedValueAt = (Func>)(object)(Func>)((t, i) => t.ParsedValueOfDoubleAt(i)); } else if (typeof(T) == typeof(decimal)) { Parse = (Func)(object)(Func)(t => t.ParseDecimal()); ParsedValueAt = (Func>)(object)(Func>)((t, i) => t.ParsedValueOfDecimalAt(i)); } } #endregion } public static class TextExtensions { #region String Extension public static Text ToText(this String str) => new Text(str); public static string ReplaceIdentifiers(this string str, Dictionary changeMap) => str.ToText().ReplaceIdentifiers(changeMap).ToString(); #endregion #region StringBuilder Extension public static StringBuilder Append(this StringBuilder builder, Text text) => builder.Append(text.String, text.Start, text.Count); public static Text ToText(this StringBuilder builder) => new Text(builder.ToString()); #endregion #region List Extensions public static List ToListOfString(this List textList) => textList.Map(t => t.ToString()); public static string[] ToStringArray(this List textList) => textList.MapToArray(t => t.ToString()); public static string JoinToString(this List textList, string delimiter) => textList.Map(t => t.ToString()).Join(delimiter); #endregion #region TextArray Extensions public static string[] ToStringArray(this Text[] textArray) => textArray.Map(t => t.ToString()); public static List ToListOfString(this Text[] textArray) => textArray.MapToList(t => t.ToString()); [Obsolete("Does not always return the same count as NestedBracketSplit() result length. Use NestedBracketSplitCount2 instead.")] public static int NestedBracketSplitCount(this Text text, int splitLevel) { int count = 0; int level = 0; for (int i = text.Start, e = text.End; i < e; i++) { switch (text.String[i]) { case '[': ++level; break; case ']': --level; break; case ',': if (level == splitLevel) ++count; break; } } if (level == splitLevel) ++count; return count; } public static int NestedBracketSplitCount2(this Text text, int splitLevel) { int count = 0; int level = 0; int begin = text.Start; int end = text.End; for (int pos = text.Start; pos < end; pos++) { switch (text.String[pos]) { case '[': ++level; if (level == splitLevel) begin = pos + 1; break; case ']': if (level == splitLevel) ++count; --level; break; case ',': if (level == splitLevel) { ++count; begin = pos + 1; } break; } } if (level == splitLevel && begin < end) ++count; return count; } #endregion #region Text Extensions public static TArray NestedBracketSplit( this Text text, int splitLevel, Func parse, Func creator, Action setter) { int level = 0; int start = text.Start; int end = text.End; long ai = 0; var array = creator(); for (int i = start; i < end; i++) { switch (text.String[i]) { case '[': ++level; if (level == splitLevel) start = i + 1; break; case ']': if (level == splitLevel) setter(array, ai++, parse(new Text(start, i, text.String))); --level; break; case ',': if (level == splitLevel) { setter(array, ai++, parse(new Text(start, i, text.String))); start = i + 1; } break; } } if (level == splitLevel && start < end) setter(array, ai, parse(new Text(start, end, text.String))); return array; } public static TStruct NestedBracketSplit( this Text text, int splitLevel, Func parse, ActionRefValVal setter) { int level = 0; int start = text.Start; int end = text.End; int ai = 0; var str = default(TStruct); for (int i = start; i < end; i++) { switch (text.String[i]) { case '[': ++level; if (level == splitLevel) start = i + 1; break; case ']': if (level == splitLevel) setter(ref str, ai++, parse(new Text(start, i, text.String))); --level; break; case ',': if (level == splitLevel) { setter(ref str, ai++, parse(new Text(start, i, text.String))); start = i + 1; } break; } } if (level == splitLevel && start < end) setter(ref str, ai, parse(new Text(start, end, text.String))); return str; } public static T[] NestedBracketSplit( this Text text, int splitLevel, Func parse, Func creator) { int level = 0; int start = text.Start; int end = text.End; int ai = 0; var array = creator(); for (int i = start; i < end; i++) { switch (text.String[i]) { case '[': ++level; if (level == splitLevel) start = i + 1; break; case ']': if (level == splitLevel) array[ai++] = parse(new Text(start, i, text.String)); --level; break; case ',': if (level == splitLevel) { array[ai++] = parse(new Text(start, i, text.String)); start = i + 1; } break; } } if (level == splitLevel && start < end) array[ai] = parse(new Text(start, end, text.String)); return array; } public static IEnumerable Split(this Text text, char c) { int start = text.Start; int end = text.Start; while (end < text.End) { if (text.String[end++] == c) { yield return new Text(start, end - 1, text.String); start = end; } } yield return new Text(start, end, text.String); } #endregion } } ================================================ FILE: src/Aardvark.Base/Text/TextParser.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; namespace Aardvark.Base { #region State with Parser as Generic Parameter /// /// State of a generic recursive descent parser. /// /// Parser class containing static state variables. /// Node class for building parse trees. public class State : IEnumerable> where TPar : TextParser { public readonly Action TextAct; public readonly Case[] Cases; public readonly Func, TNode, int> Match; #region Constructors public State(Cases cases) : this(cases.Array, null) { } public State(Case[] cases) : this(cases, null) { } public State(Cases cases, Action textAct) : this(cases.Array, textAct) { } public State(Case[] cases, Action textAct) { Cases = cases; TextAct = textAct; var pattern = cases.Map( (c, i) => c.Pattern != null ? "(?<" + (i + 1) + ">" + c.Pattern + ")" : "(?<" + (i + 1) + ">.|\r)" ).Join("|"); var regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled); var caseCount = cases.Length; if (textAct != null) { Match = (par, state, node) => { var m = regex.Match(par.Text.String, par.Pos, par.Text.End - par.Pos); if (m.Success) for (int i = 1; i <= caseCount; i++) if (m.Groups[i].Success) { var c = i - 1; var index = m.Groups[i].Index; if (par.Pos < index) { var t = par.PeekToPos(index); var adj = state.Cases[c].AdjustFun; if (adj != null) t = adj(par, node, t); state.TextAct(par, node, t); par.SetPosAndCountLines(index); } par.LastEnd = index + m.Groups[i].Length; par.LastCase = c; return c; } if (par.Pos < par.Text.End) { state.TextAct(par, node, par.PeekToPos(par.Text.End)); par.SetPosAndCountLines(par.Text.End); } return -1; }; } else { if (cases[caseCount - 1].Pattern != null) throw new ArgumentException( "either a text action or a default case needs to be specified"); Match = (par, state, node) => { var m = regex.Match(par.Text.String, par.Pos, par.Text.End - par.Pos); if (m.Success) for (int i = 1; i <= caseCount; i++) if (m.Groups[i].Success) { par.LastEnd = m.Groups[i].Index + m.Groups[i].Length; return par.LastCase = i - 1; } return -1; }; } } #endregion public IEnumerable> Items { get { foreach (var c in Cases) yield return c; } } #region IEnumerable implementation public IEnumerator> GetEnumerator() => Items.GetEnumerator(); #endregion #region IEnumerable implementation System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => Items.GetEnumerator(); #endregion } #endregion #region Case with Parser as Generic Parameter /// /// Case represents a state transition of a generic recursive descent parser. /// /// Parser class containing static state variables. /// Node class for building parse trees. public readonly struct Case where TPar : TextParser { public readonly Func> MatchedFun; public readonly Func AdjustFun; public readonly string Pattern; #region Constructors /// /// A supplied adjustFun can modify the text preceeding the match /// of the case in a searching state, before it is handed to the /// TextAct of the state. /// public Case(string pattern, Func> matchedFun, Func adjustFun = null) { MatchedFun = matchedFun; AdjustFun = adjustFun; Pattern = pattern; } public Case(Func> matchedFun, Func adjustFun = null) : this((string)null, matchedFun, adjustFun) { } public Case(Regex regex, Func> matchedFun, Func adjustFun = null) : this(regex.ToString(), matchedFun, adjustFun) { } public Case(Rx rx, Func> matchedFun, Func adjustFun = null) : this(rx.Pattern, matchedFun, adjustFun) { } #endregion } #endregion #region Cases with Parser as Generic Parameter /// /// The Cases class makes it possible to build a single state transition /// table by combining already defined case arrays. This makes it possible /// to avoid re-specifying cases that appear in multiple states. /// public class Cases : IEnumerable> where TPar : TextParser { private readonly List> CaseList; public Case[] Array => CaseList.ToArray(); public Cases() => CaseList = new List>(); public Cases(Rx[] rxs, Func> matchedFun) : this() { foreach (var rx in rxs) CaseList.Add(new Case(rx, matchedFun)); } public void Add(Case singleCase) => CaseList.Add(singleCase); public void Add(Case[] caseArray) { foreach (var c in caseArray) CaseList.Add(c); } public void Add(Cases cases) { foreach (var c in cases.Array) CaseList.Add(c); } public void Add(string pattern, Func> matchedFun, Func adjustFun = null) { CaseList.Add(new Case(pattern, matchedFun, adjustFun)); } public void Add(Regex regex, Func> matchedFun, Func adjustFun = null) { CaseList.Add(new Case(regex.ToString(), matchedFun, adjustFun)); } public void Add(Rx rx, Func> matchedFun, Func adjustFun = null) { CaseList.Add(new Case(rx.Pattern, matchedFun, adjustFun)); } public void Add(Func> matchedFun, Func adjustFun = null) { CaseList.Add(new Case(matchedFun, adjustFun)); } public State ToState(Action textAct = null) => new State(this, textAct); #region IEnumerable> Members public IEnumerator> GetEnumerator() => CaseList.GetEnumerator(); #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => CaseList.GetEnumerator(); #endregion } #endregion #region ParserState /// /// State of a generic recursive descent parser. /// /// Node class for building parse trees. public class ParserState : IEnumerable> { public readonly Action TextAct; public readonly ParserCase[] Cases; public readonly Func, TNode, int> Match; #region Constructors public ParserState(ParserCases cases) : this(cases.Array, null) { } public ParserState(ParserCase[] cases) : this(cases, null) { } public ParserState(ParserCases cases, Action textAct) : this(cases.Array, textAct) { } public ParserState(ParserCase[] cases, Action textAct) { Cases = cases; TextAct = textAct; var pattern = cases.Map( (c, i) => c.Pattern != null ? "(?<" + (i + 1) + ">" + c.Pattern + ")" : "(?<" + (i + 1) + ">.|\r)" ).Join("|"); var regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled); var caseCount = cases.Length; if (textAct != null) { Match = (par, state, node) => { var m = regex.Match(par.Text.String, par.Pos, par.Text.End - par.Pos); if (m.Success) for (int i = 1; i <= caseCount; i++) if (m.Groups[i].Success) { var c = i - 1; var index = m.Groups[i].Index; if (par.Pos < index) { var t = par.PeekToPos(index); var adj = state.Cases[c].AdjustFun; if (adj != null) t = adj(par, node, t); state.TextAct(par, node, t); par.SetPosAndCountLines(index); } par.LastEnd = index + m.Groups[i].Length; par.LastCase = c; return c; } if (par.Pos < par.Text.End) { state.TextAct(par, node, par.PeekToPos(par.Text.End)); par.SetPosAndCountLines(par.Text.End); } return -1; }; } else { if (cases[caseCount - 1].Pattern != null) throw new ArgumentException( "either a text action or a default case needs to be specified"); Match = (par, state, node) => { var m = regex.Match(par.Text.String, par.Pos, par.Text.End - par.Pos); if (m.Success) for (int i = 1; i <= caseCount; i++) if (m.Groups[i].Success) { par.LastEnd = m.Groups[i].Index + m.Groups[i].Length; return par.LastCase = i - 1; } return -1; }; } } #endregion public IEnumerable> Items { get { foreach (var c in Cases) yield return c; } } #region IEnumerable implementation public IEnumerator> GetEnumerator() => Items.GetEnumerator(); #endregion #region IEnumerable implementation System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => Items.GetEnumerator(); #endregion } #endregion #region ParserCase /// /// Case represents a state transition of a generic recursive descent parser. /// /// Node class for building parse trees. public readonly struct ParserCase { public readonly Func> MatchedFun; public readonly Func AdjustFun; public readonly string Pattern; #region Constructors /// /// A supplied adjustFun can modify the text preceeding the match /// of the case in a searching state, before it is handed to the /// TextAct of the state. /// public ParserCase(string pattern, Func> matchedFun, Func adjustFun = null) { MatchedFun = matchedFun; AdjustFun = adjustFun; Pattern = pattern; } public ParserCase(Func> matchedFun, Func adjustFun = null) : this((string)null, matchedFun, adjustFun) { } public ParserCase(Regex regex, Func> matchedFun, Func adjustFun = null) : this(regex.ToString(), matchedFun, adjustFun) { } public ParserCase(Rx rx, Func> matchedFun, Func adjustFun = null) : this(rx.Pattern, matchedFun, adjustFun) { } #endregion } #endregion #region ParserCases /// /// The Cases class makes it possible to build a single state transition /// table by combining already defined case arrays. This makes it possible /// to avoid re-specifying cases that appear in multiple states. /// public class ParserCases : IEnumerable> { private readonly List> CaseList; public ParserCase[] Array => CaseList.ToArray(); public ParserCases() => CaseList = new List>(); public ParserCases(Rx[] rxs, Func> matchedFun) : this() { foreach (var rx in rxs) CaseList.Add(new ParserCase(rx, matchedFun)); } public void Add(ParserCase singleCase) => CaseList.Add(singleCase); public void Add(ParserCase[] caseArray) { foreach (var c in caseArray) CaseList.Add(c); } public void Add(ParserCases cases) { foreach (var c in cases.Array) CaseList.Add(c); } public void Add(string pattern, Func> matchedFun, Func adjustFun = null) { CaseList.Add(new ParserCase(pattern, matchedFun, adjustFun)); } public void Add(Regex regex, Func> matchedFun, Func adjustFun = null) { CaseList.Add(new ParserCase(regex.ToString(), matchedFun, adjustFun)); } public void Add(Rx rx, Func> matchedFun, Func adjustFun = null) { CaseList.Add(new ParserCase(rx.Pattern, matchedFun, adjustFun)); } public void Add(Func> matchedFun, Func adjustFun = null) { CaseList.Add(new ParserCase(matchedFun, adjustFun)); } public ParserState ToState(Action textAct = null) { return new ParserState(this, textAct); } #region IEnumerable> Members public IEnumerator> GetEnumerator() => CaseList.GetEnumerator(); #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => CaseList.GetEnumerator(); #endregion } #endregion #region TextParser /// /// The recursive descent parser class contains parsing state and serves /// as a base class for specific parser implementations. The specific /// derived parser class needs to be specified as type parameter. It /// should also contain the state transition table as static member /// variables. /// /// A concrete parser class derived from /// this generic parser class. public class TextParser where TPar : TextParser { public Text Text; public int Pos; public int LastEnd; public int LastCase; public Text.Line Line; public int LastWhiteSpace; protected int m_currentCaseIndex; #region Static Parsing Methods /// /// Parse the supplied text into the supplied node, starting the /// parser in the supplied root state. This function is the entry /// call to the parser, it returns when the text has been fully /// parsed, or throws a ParserException. /// public static TPar Parse( Text text, TPar parser, State rootState, TNode rootNode) { parser.Text = text; parser.Pos = text.Start; parser.LastEnd = text.Start; parser.Line = new Text.Line(0, text.Start); parser.LastWhiteSpace = -1; parser.LastCase = -1; parser.m_currentCaseIndex = -1; return Parse(parser, rootState, rootNode); } /// /// Parse a part of the input into the supplied node. /// This function can be called to implement recursive descent. /// public static TPar Parse( TPar parser, State state, TNode node) { int end = parser.Text.End; var match = state.Match(parser, state, node); while (parser.Pos < end) { parser.m_currentCaseIndex = match; state = state.Cases[match].MatchedFun(parser, node); if (state == null) break; match = state.Match(parser, state, node); } return parser; } #endregion #region Properties /// /// True if parsing has consumed all input. /// public bool EndOfText => Pos == Text.End; /// /// Users start counting at 1. /// public int UserLine => 1 + Line.Index; /// /// Users start counting at 1. /// public int UserColumn => Pos - Line.Start; /// /// The index of the current case within the state table. /// This is only valid as long as no recursive parse function /// has been called. /// public int CurrentCaseIndex => m_currentCaseIndex; #endregion #region Current State Query Methods /// /// The current case within the supplied state table. /// This is only valid as long as no recursive parse function /// has been called. /// public Case CurrentCase(State state) => state.Cases[m_currentCaseIndex]; /// /// The current pattern within the supplied state table. /// This is only valid as long as no recursive parse function /// has been called. /// public string CurrentPattern(State state) => state.Cases[m_currentCaseIndex].Pattern; #endregion #region Skipping Text public void SkipToEnd() => Pos = Text.End; /// /// Skip the last pattern that was matched up to its start. This can /// either be the pattern of the case, or the pattern that is left /// by one of the GetToStartOf(...) methods. /// public void Skip() => Pos = LastEnd; /// /// Skip exactly count characters. /// public void Skip(int count) => Pos += count; public void SkipAndCountLines() => SetPosAndCountLines(LastEnd); public void SkipAndCountLines(int count) => SetPosAndCountLines(Pos + count); public bool TrySkip(int count) { var pos = Pos + count; if (pos > Text.End) return false; SetPosAndCountLines(pos); return true; } public void Skip(char skipCh) { if (!TrySkip(skipCh)) ThrowCouldNotSkip("'" + skipCh + "'"); } public void Skip(string skipStr) { if (!TrySkip(skipStr)) ThrowCouldNotSkip('"' + skipStr + '"'); } public void Skip(Rx skipRx) { if (!TrySkip(skipRx)) ThrowCouldNotSkip("pattern \"" + skipRx.Pattern + '"'); } public bool TrySkip(char skipCh) { var index = Math.Max(Pos, LastEnd); var end = index + 1; if (end >= Text.End) return false; if (Text[index] != skipCh) return false; SetPosAndCountLines(end); return true; } public bool TrySkip(string skipStr) { var index = Math.Max(Pos, LastEnd); var end = index + skipStr.Length; if (end > Text.End) return false; for (int i = 0; index < end; index++, i++) if (Text[index] != skipStr[i]) return false; SetPosAndCountLines(index); return true; } public bool TrySkip(Rx skipRx) { var index = Math.Max(Pos, LastEnd); var m = skipRx.AnchoredRegex.Match(Text.String, index, Text.End - index); if (!m.Success || m.Groups[2].Success) return false; SetPosAndCountLines(index); LastEnd = index + m.Length; return true; } /// /// Skip as much white space characters as possible. Returns the /// actual number skipped. /// public int SkipWhiteSpace() { var start = Pos; while (Pos < Text.End) { var c = Text.String[Pos]; switch (c) { case ' ': case '\t': case '\r': ++Pos; break; case '\n': ++Pos; Line.Index++; Line.Start = Pos; break; default: return Pos - start; } } return Pos - start; } /// /// Skip at least minimalCount white space characters. /// Throws a ParserException if less white space is available. /// public void SkipWhiteSpaceAtLeast(int minimalCount) { if (SkipWhiteSpace() < minimalCount) throw new ParserException((TPar)this, "not enough white space"); } public void SkipWhiteSpaceAndCheckProgress() { if (Pos == LastWhiteSpace) // stall detected throw new ParserException((TPar)this, "illegal character"); SkipWhiteSpace(); LastWhiteSpace = Pos; } public void SkipToStartOf(char searchChar) { if (!TrySkipToStartOf(searchChar)) ThrowCouldNotFind("'" + searchChar + "'"); } public void SkipToStartOf(string searchString) { if (!TrySkipToStartOf(searchString)) ThrowCouldNotFind('"' + searchString + '"'); } public void SkipToStartOf(Rx searchRx) { if (!TrySkipToStartOf(searchRx)) ThrowCouldNotFind("pattern \"" + searchRx.Pattern + '"'); } public void SkipToEndOf(char searchChar) { if (!TrySkipToEndOf(searchChar)) ThrowCouldNotFind("'" + searchChar + "'"); } public void SkipToEndOf(string searchString) { if (!TrySkipToEndOf(searchString)) ThrowCouldNotFind('"' + searchString + '"'); } public void SkipToEndOf(Rx searchRx) { if (!TrySkipToEndOf(searchRx)) ThrowCouldNotFind("pattern \"" + searchRx.Pattern + '"'); } public void SkipToEndOfOrEnd(char searchChar) { if (!TrySkipToEndOf(searchChar)) SkipToEnd(); } public void SkipToEndOfOrEnd(string searchString) { if (!TrySkipToEndOf(searchString)) SkipToEnd(); } public void SkipToEndOfOrEnd(Rx searchRx) { if (!TrySkipToEndOf(searchRx)) SkipToEnd(); } public bool TrySkipToStartOf(char searchChar) { var index = Math.Max(Pos, LastEnd); index = Text.String.IndexOf(searchChar, index, Text.End - index); if (index < 0) return false; SetPosAndCountLines(index); LastEnd = index + 1; return true; } public bool TrySkipToStartOf(string searchString) { var index = Math.Max(Pos, LastEnd); index = Text.String.IndexOf(searchString, index, Text.End - index); if (index < 0) return false; SetPosAndCountLines(index); LastEnd = index + searchString.Length; return true; } public bool TrySkipToStartOf(Rx searchRx) { var index = Math.Max(Pos, LastEnd); var m = searchRx.Regex.Match(Text.String, index, Text.End - index); if (!m.Success) return false; index = m.Index; SetPosAndCountLines(index); LastEnd = index + m.Length; return true; } public bool TrySkipToEndOf(char searchChar) { var index = Math.Max(Pos, LastEnd); index = Text.String.IndexOf(searchChar, index, Text.End - index); if (index < 0) return false; SetPosAndCountLines(++index); return true; } public bool TrySkipToEndOf(string searchString) { var index = Math.Max(Pos, LastEnd); index = Text.String.IndexOf(searchString, index, Text.End - index); if (index < 0) return false; index += searchString.Length; SetPosAndCountLines(index); return true; } public bool TrySkipToEndOf(Rx searchRx) { var index = Math.Max(Pos, LastEnd); var m = searchRx.Regex.Match(Text.String, index, Text.End - index); if (!m.Success) return false; index = m.Index + m.Length; SetPosAndCountLines(index); return true; } #endregion #region Getting Text /// /// Get one character of input. /// public char GetChar() { if (Pos >= Text.End) throw new ParserException((TPar)this, "end of text"); return Text.String[Pos++]; } public bool TryGet(char ch) { if (Pos >= Text.End) return false; if (Text.String[Pos] != ch) return false; ++Pos; return true; } public bool TryGet(string str) { var len = str.Length; if (Pos + len > Text.End) return false; for (int i = 0, p = Pos; i < len; i++, p++) if (str[i] != Text.String[p]) return false; Pos += len; return true; } /// /// Get the text up to the end of the last pattern that was matched /// up to its start. This can either be the pattern of the case, /// the pattern that is left by one of the GetToStartOf(...), or /// the pattern that was left by one of the SkipToStartOf(...) /// methods. /// public Text Get() { var text = new Text(Pos, LastEnd, Text.String); Pos = LastEnd; return text; } /// /// Get the text from the supplied start up to the current parsing /// position. This can be used, if a number of patterns have been /// skipped before and need to be combined into a single text. /// public Text GetFrom(int start) { var text = new Text(start, Pos, Text.String); return text; } /// /// Get text that matches the supplied regular expression (it must /// start at the current position). If the text does not match, an /// exception is thrown. /// public Text Get(Rx rx) { return Get(rx, p => p.ThrowCouldNotFind( "pattern \"" + rx.Pattern + '"')); } /// /// Get text that matches the supplied regular expression (it must /// start at the current position). If the text does not match, the /// supplied function is executed and its result is returned. /// public Text Get(Rx rx, Func notMatchedFun) { var m = rx.AnchoredRegex.Match(Text.String, Pos); if (!m.Success || m.Groups[2].Success) return notMatchedFun((TPar)this); Pos += m.Length; return new Text(Text.String, m.Index, m.Length); } /// /// Get text [pos, pos + offset) if offset is greater than 0, and /// text [pos, end + offset) if offset is lower or equal to 0. /// public Text GetTo(int offset) => GetToPos(offset <= 0 ? Math.Max(Pos, Text.End + offset) : Math.Min(Pos + offset, Text.End)); public Text GetToPos(int pos) { var text = new Text(Pos, pos, Text.String); SetPosAndCountLines(pos); return text; } public Text GetToEnd() => GetToPos(Text.End); public List GetList(Rx item, Rx sep) { var idx = Math.Max(Pos, LastEnd); var list = new List(); var m = item.AnchoredRegex.Match(Text.String, idx); if (!m.Success || m.Groups[2].Success || idx + m.Length > Text.End) throw new ParserException((TPar)this, idx, "could not get list item with pattern \"" + item.Pattern + '"'); list.Add(new Text(Text.String, m.Index, m.Length)); idx += m.Length; while ((m = sep.AnchoredRegex.Match(Text.String, idx)).Success && m.Groups[1].Success && idx + m.Length < Text.End) { idx += m.Length; m = item.Regex.Match(Text.String, idx); if (!m.Success || m.Groups[2].Success || idx + m.Length > Text.End) throw new ParserException((TPar)this, idx, "could not get list item with pattern \"" + item.Pattern + '"'); list.Add(new Text(Text.String, m.Index, m.Length)); idx = m.Index + m.Length; } SetPosAndCountLines(idx); return list; } public Text GetToStartOf(char searchChar) => GetToStartOf( searchChar, p => p.ThrowCouldNotFind("'" + searchChar + "'") ); public Text GetToStartOf(char searchChar, Func notFoundAction) { var index = Math.Max(Pos, LastEnd); index = Text.String.IndexOf(searchChar, index, Text.End - index); if (index < 0) return notFoundAction((TPar)this); var text = new Text(Pos, index, Text.String); SetPosAndCountLines(index); LastEnd = index + 1; return text; } public Text GetToStartOf(string searchString) => GetToStartOf( searchString, p => p.ThrowCouldNotFind('"' + searchString + '"') ); public Text GetToStartOf(string searchString, Func notFoundAction) { var index = Math.Max(Pos, LastEnd); index = Text.String.IndexOf(searchString, index, Text.End - index); if (index < 0) return notFoundAction((TPar)this); var text = new Text(Pos, index, Text.String); SetPosAndCountLines(index); LastEnd = index + searchString.Length; return text; } public Text GetToStartOf(Rx searchRx) => GetToStartOf( searchRx, p => p.ThrowCouldNotFind("pattern \"" + searchRx.Pattern + '"') ); public Text GetToStartOf(Rx searchRx, Func notFoundAction) { var index = Math.Max(Pos, LastEnd); var m = searchRx.Regex.Match(Text.String, index, Text.End - index); if (!m.Success) return notFoundAction((TPar)this); index = m.Index; var text = new Text(Pos, index, Text.String); SetPosAndCountLines(index); LastEnd = index + m.Length; return text; } public Text GetToEndOf(char searchChar) => GetToEndOf( searchChar, p => p.ThrowCouldNotFind("'" + searchChar + "'") ); public Text GetToEndOf(char searchChar, Func notFoundFun) { var index = Math.Max(Pos, LastEnd); index = Text.String.IndexOf(searchChar, index, Text.End - index); if (index < 0) return notFoundFun((TPar)this); index++; var text = new Text(Pos, index, Text.String); SetPosAndCountLines(index); return text; } public Text GetToEndOf(string searchString) => GetToEndOf( searchString, p => p.ThrowCouldNotFind('"' + searchString + '"') ); public Text GetToEndOf(string searchString, Func notFoundFun) { var index = Math.Max(Pos, LastEnd); index = Text.String.IndexOf(searchString, index, Text.End - index); if (index < 0) return notFoundFun((TPar)this); index += searchString.Length; var text = new Text(Pos, index, Text.String); SetPosAndCountLines(index); return text; } public Text GetToEndOf(Rx searchRx) => GetToEndOf( searchRx, p => p.ThrowCouldNotFind("pattern \"" + searchRx.Pattern + '"') ); public Text GetToEndOf(Rx searchRx, Func notFoundFun) { var index = Math.Max(Pos, LastEnd); var m = searchRx.Regex.Match(Text.String, index, Text.End - index); if (!m.Success) return notFoundFun((TPar)this); index = m.Index + m.Length; var text = new Text(Pos, index, Text.String); SetPosAndCountLines(index); return text; } public Text GetToStartOfOrEnd(char searchChar) => GetToStartOf(searchChar, p => p.GetToPos(Text.End)); public Text GetToStartOfOrEnd(string searchString) => GetToStartOf(searchString, p => p.GetToPos(Text.End)); public Text GetToStartOfOrEnd(Rx searchRx) => GetToStartOf(searchRx, p => p.GetToPos(Text.End)); public Text GetToEndOfOrEnd(char searchChar) => GetToEndOf(searchChar, p => p.GetToPos(Text.End)); public Text GetToEndOfOrEnd(string searchString) => GetToEndOf(searchString, p => p.GetToPos(Text.End)); public Text GetToEndOfOrEnd(Rx searchRx) => GetToEndOf(searchRx, p => p.GetToPos(Text.End)); public Text GetToWhiteSpace() { var start = Pos; while (Pos < Text.End && !IsWhiteSpace(Text.String[Pos])) Pos++; return new Text(start, Pos, Text.String); bool IsWhiteSpace(char ch) => ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; } public bool TryGetByte(ref ParsedValue parsedValue) { parsedValue = Text.ParsedValueOfByteAt(Pos - Text.Start); if (parsedValue.Error != ParseError.None) return false; Pos += parsedValue.Length; return true; } public bool TryGetSByte(ref ParsedValue parsedValue) { parsedValue = Text.ParsedValueOfSByteAt(Pos - Text.Start); if (parsedValue.Error != ParseError.None) return false; Pos += parsedValue.Length; return true; } public bool TryGetShort(ref ParsedValue parsedValue) { parsedValue = Text.ParsedValueOfShortAt(Pos - Text.Start); if (parsedValue.Error != ParseError.None) return false; Pos += parsedValue.Length; return true; } public bool TryGetUShort(ref ParsedValue parsedValue) { parsedValue = Text.ParsedValueOfUShortAt(Pos - Text.Start); if (parsedValue.Error != ParseError.None) return false; Pos += parsedValue.Length; return true; } public bool TryGetInt(ref ParsedValue parsedValue) { parsedValue = Text.ParsedValueOfIntAt(Pos - Text.Start); if (parsedValue.Error != ParseError.None) return false; Pos += parsedValue.Length; return true; } public bool TryGetUInt(ref ParsedValue parsedValue) { parsedValue = Text.ParsedValueOfUIntAt(Pos - Text.Start); if (parsedValue.Error != ParseError.None) return false; Pos += parsedValue.Length; return true; } public bool TryGetLong(ref ParsedValue parsedValue) { parsedValue = Text.ParsedValueOfLongAt(Pos - Text.Start); if (parsedValue.Error != ParseError.None) return false; Pos += parsedValue.Length; return true; } public bool TryGetULong(ref ParsedValue parsedValue) { parsedValue = Text.ParsedValueOfULongAt(Pos - Text.Start); if (parsedValue.Error != ParseError.None) return false; Pos += parsedValue.Length; return true; } public bool TryGetFloat(ref ParsedValue parsedValue) { parsedValue = Text.ParsedValueOfFloatAt(Pos - Text.Start); if (parsedValue.Error != ParseError.None) return false; Pos += parsedValue.Length; return true; } public bool TryGetDouble(ref ParsedValue parsedValue) { parsedValue = Text.ParsedValueOfDoubleAt(Pos - Text.Start); if (parsedValue.Error != ParseError.None) return false; Pos += parsedValue.Length; return true; } public bool TryGetDecimal(ref ParsedValue parsedValue) { parsedValue = Text.ParsedValueOfDecimalAt(Pos - Text.Start); if (parsedValue.Error != ParseError.None) return false; Pos += parsedValue.Length; return true; } #endregion #region Peeking public char Peek => Text.String[Pos]; public Text PeekGet() => new Text(Pos, LastEnd, Text.String); public Text PeekFromStart => PeekFromPos(Text.Start); public Text PeekLastLine => PeekFromPos(Line.Start); public Text PeekToEnd => PeekToPos(Text.End); /// /// Returns the text [pos + offset, pos) if offset is lower than 0, /// and the text [start + offset, pos) if offset is greater or equal /// to 0. /// public Text PeekFrom(int offset) => PeekFromPos(offset < 0 ? Math.Max(Text.Start, Pos + offset) : Math.Min(Text.Start + offset, Pos)); /// /// Returns the text [pos, pos + offset) if offset is greater than 0, /// and the text [pos, end + offset) if offset is lower or equal to 0. /// public Text PeekTo(int offset) => PeekToPos(offset <= 0 ? Math.Max(Pos, Text.End + offset) : Math.Min(Pos + offset, Text.End)); public Text PeekFromPos(int pos) => new Text(pos, Pos, Text.String); public Text PeekToPos(int pos) => new Text(Pos, pos, Text.String); #endregion #region Mostly Internal Methods public void SetPosAndCountLines(int pos) { int i = Pos; while (i < pos) { if (Text.String[i] == '\n') { ++i; Line.Index++; Line.Start = i; } else ++i; } Pos = pos; } #endregion #region Throwing Exceptions public void ThrowEndOfText() => throw new ParserException((TPar)this, "end of text"); public void ThrowOutOfRange(string typeName) => throw new ParserException((TPar)this, "value out of " + typeName + " range"); public Text ThrowCouldNotFind(string str) => throw new ParserException((TPar)this, "could not find " + str); public Text ThrowCouldNotSkip(string str) => throw new ParserException((TPar)this, "could not skip " + str); #endregion } public class TextParser : TextParser { public void Parse(Text text, ParserState rootState, TNode rootNode) { Text = text; Pos = text.Start; LastEnd = text.Start; Line = new Text.Line(0, text.Start); LastWhiteSpace = -1; LastCase = -1; m_currentCaseIndex = -1; Parse(rootState, rootNode); } /// /// Parse a part of the input into the supplied node. /// This function can be called to implement recursive descent. /// public void Parse(ParserState state, TNode node) { int end = Text.End; var match = state.Match(this, state, node); while (Pos < end) { m_currentCaseIndex = match; state = state.Cases[match].MatchedFun(this, node); if (state == null) break; match = state.Match(this, state, node); } } } #endregion #region ParserException /// /// The generic recursive descent parser throws this type of exception. /// public class ParserException : ApplicationException where TPar : TextParser { public readonly TPar Parser; #region Constructors public ParserException(TPar parser, string message) : base(message) { Parser = parser; } public ParserException(TPar parser, int pos, string message) : base(message) { parser.SetPosAndCountLines(pos); Parser = parser; } public ParserException(TPar parser, string message, Exception inner) : base(message, inner) { Parser = parser; } #endregion } public class ParserException : ParserException { #region Constructors public ParserException(TextParser parser, string message) : base(parser, message) { } public ParserException(TextParser parser, int pos, string message) : base(parser, pos, message) { } public ParserException(TextParser parser, string message, Exception inner) : base(parser, message, inner) { } #endregion } #endregion #region VerbatimString TextParser Extension public static class VerbatimStringTextParserExtension { public static string GetVerbatimString(this TextParser parser, bool alreadyInside = false) { var sb = new StringBuilder(); parser.Parse(alreadyInside ? s_stringState : s_quoteState, sb); return sb.ToString(); } private static readonly ParserState s_quoteState = new ParserCases { { "@\"", (p, b) => { p.Skip(); return s_stringState; } }, { /* def. */(p, b) => { throw new ParserException(p, "no @\" at start of verbatim string"); } } }.ToState(); private static readonly ParserState s_stringState = new ParserCases { { "\"\"", (p, b) => { p.Skip(); b.Append('"'); return s_stringState; } }, // escape { "\"", (p, b) => { p.Skip(); return null; } }, // string end }.ToState((p, b, t) => { b.Append(t.String, t.Start, t.Count); }); // process } #endregion #region CSharpString TextParser Extension internal readonly struct Esc { public readonly string Pattern; public readonly Func EscFun; public Esc(string pattern, Func escFun) { Pattern = pattern; EscFun = escFun; } } internal static class EscDictExtension { public static void Add(this Dictionary escMap, char escStart, string pattern, Func escFun) { escMap.Add(escStart, new Esc(pattern, escFun)); } } public static class CSharpStringTextParserExtension { public static string GetCSharpString(this TextParser parser, bool alreadyInside = false) { var sb = new StringBuilder(); parser.Parse(alreadyInside ? s_strState : s_quoteState, sb); return sb.ToString(); } private static readonly ParserState s_quoteState = new ParserCases { { "\"", (p, b) => { p.Skip(); return s_strState; } }, { (p, b) => { throw new ParserException(p, "no \" at start of string"); } } }.ToState(); private static readonly ParserState s_strState = new ParserCases { { "\"", (p, b) => { p.Skip(); return null; } }, // search string end { @"\\", (p, b) => { p.Skip(); return s_escState; } }, // search escape { @"\n|\r", (p, b) => { throw new ParserException(p, "newline in string"); } } }.ToState((p, b, t) => { b.Append(t.String, t.Start, t.Count); }); // process text inbetween private const int c_a = (int)'a', c_A = (int)'A', c_0 = (int)'0'; private static readonly Esc s_octalEsc = new Esc( "[0-3][0-7][0-7]", str => (char)(((((int)str[0]) - c_0) * 8 + (((int)str[1]) - c_0)) * 8 + (((int)str[2]) - c_0)) ); private static int HexOfOrd(int ord) => ord >= c_a ? 10 + ord - c_a : ord >= c_A ? ord - c_A : ord - c_0; private static char HexOfEscString(string str) => (char)(HexOfOrd((int)str[1]) * 16 + HexOfOrd((int)str[2])); // Decide what to do, based on the first character of the escape sequence. private static readonly Dictionary s_escMap = new Dictionary { { 'a', "a", str => '\a' }, { 'b', "b", str => '\b' }, { 'f', "f", str => '\f' }, { 'n', "n", str => '\n' }, { 'r', "r", str => '\r' }, { 't', "t", str => '\t' }, { 'v', "v", str => '\v' }, { '\'', "\'", str => '\'' }, { '\"', "\"", str => '\"' }, { '\\', @"\\", str => '\\' }, { '0', s_octalEsc }, { '1', s_octalEsc }, { '2', s_octalEsc }, { '3', s_octalEsc }, { 'x', "x[0-9a-fA-F][0-9a-fA-F]", HexOfEscString }, }; private static readonly string s_escapes = String.Join("|", s_escMap.Values.Select(e => e.Pattern).Distinct()); private static readonly ParserState s_escState = new ParserCases { { s_escapes, (p, b) => { var esc = p.Get().ToString(); b.Append(s_escMap[esc[0]].EscFun(esc)); return s_strState; }}, { /* def. */ (p, b) => { throw new ParserException(p, "invalid escape sequence in string"); }} }.ToState(); } #endregion } ================================================ FILE: src/Aardvark.Base/Tup/Tuples_auto.cs ================================================ using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! #region Simple Tuples of uniform type #region Tup2 public struct Tup2 { public T E0, E1; #region Constructors public Tup2(T e) { E0 = e; E1 = e; } public Tup2(T e0, T e1) { E0 = e0; E1 = e1; } #endregion } #endregion #region Tup3 public struct Tup3 { public T E0, E1, E2; #region Constructors public Tup3(T e) { E0 = e; E1 = e; E2 = e; } public Tup3(T e0, T e1, T e2) { E0 = e0; E1 = e1; E2 = e2; } #endregion } #endregion #region Tup4 public struct Tup4 { public T E0, E1, E2, E3; #region Constructors public Tup4(T e) { E0 = e; E1 = e; E2 = e; E3 = e; } public Tup4(T e0, T e1, T e2, T e3) { E0 = e0; E1 = e1; E2 = e2; E3 = e3; } #endregion } #endregion #region Tup5 public struct Tup5 { public T E0, E1, E2, E3, E4; #region Constructors public Tup5(T e) { E0 = e; E1 = e; E2 = e; E3 = e; E4 = e; } public Tup5(T e0, T e1, T e2, T e3, T e4) { E0 = e0; E1 = e1; E2 = e2; E3 = e3; E4 = e4; } #endregion } #endregion #region Tup6 public struct Tup6 { public T E0, E1, E2, E3, E4, E5; #region Constructors public Tup6(T e) { E0 = e; E1 = e; E2 = e; E3 = e; E4 = e; E5 = e; } public Tup6(T e0, T e1, T e2, T e3, T e4, T e5) { E0 = e0; E1 = e1; E2 = e2; E3 = e3; E4 = e4; E5 = e5; } #endregion } #endregion #region Tup7 public struct Tup7 { public T E0, E1, E2, E3, E4, E5, E6; #region Constructors public Tup7(T e) { E0 = e; E1 = e; E2 = e; E3 = e; E4 = e; E5 = e; E6 = e; } public Tup7(T e0, T e1, T e2, T e3, T e4, T e5, T e6) { E0 = e0; E1 = e1; E2 = e2; E3 = e3; E4 = e4; E5 = e5; E6 = e6; } #endregion } #endregion #region Tup8 public struct Tup8 { public T E0, E1, E2, E3, E4, E5, E6, E7; #region Constructors public Tup8(T e) { E0 = e; E1 = e; E2 = e; E3 = e; E4 = e; E5 = e; E6 = e; E7 = e; } public Tup8(T e0, T e1, T e2, T e3, T e4, T e5, T e6, T e7) { E0 = e0; E1 = e1; E2 = e2; E3 = e3; E4 = e4; E5 = e5; E6 = e6; E7 = e7; } #endregion } #endregion #region Tup9 public struct Tup9 { public T E0, E1, E2, E3, E4, E5, E6, E7, E8; #region Constructors public Tup9(T e) { E0 = e; E1 = e; E2 = e; E3 = e; E4 = e; E5 = e; E6 = e; E7 = e; E8 = e; } public Tup9(T e0, T e1, T e2, T e3, T e4, T e5, T e6, T e7, T e8) { E0 = e0; E1 = e1; E2 = e2; E3 = e3; E4 = e4; E5 = e5; E6 = e6; E7 = e7; E8 = e8; } #endregion } #endregion #region Tup10 public struct Tup10 { public T E00, E01, E02, E03, E04, E05, E06, E07, E08, E09; #region Constructors public Tup10(T e) { E00 = e; E01 = e; E02 = e; E03 = e; E04 = e; E05 = e; E06 = e; E07 = e; E08 = e; E09 = e; } public Tup10(T e00, T e01, T e02, T e03, T e04, T e05, T e06, T e07, T e08, T e09) { E00 = e00; E01 = e01; E02 = e02; E03 = e03; E04 = e04; E05 = e05; E06 = e06; E07 = e07; E08 = e08; E09 = e09; } #endregion } #endregion #region Tup11 public struct Tup11 { public T E00, E01, E02, E03, E04, E05, E06, E07, E08, E09, E10; #region Constructors public Tup11(T e) { E00 = e; E01 = e; E02 = e; E03 = e; E04 = e; E05 = e; E06 = e; E07 = e; E08 = e; E09 = e; E10 = e; } public Tup11(T e00, T e01, T e02, T e03, T e04, T e05, T e06, T e07, T e08, T e09, T e10) { E00 = e00; E01 = e01; E02 = e02; E03 = e03; E04 = e04; E05 = e05; E06 = e06; E07 = e07; E08 = e08; E09 = e09; E10 = e10; } #endregion } #endregion #region Tup12 public struct Tup12 { public T E00, E01, E02, E03, E04, E05, E06, E07, E08, E09, E10, E11; #region Constructors public Tup12(T e) { E00 = e; E01 = e; E02 = e; E03 = e; E04 = e; E05 = e; E06 = e; E07 = e; E08 = e; E09 = e; E10 = e; E11 = e; } public Tup12(T e00, T e01, T e02, T e03, T e04, T e05, T e06, T e07, T e08, T e09, T e10, T e11) { E00 = e00; E01 = e01; E02 = e02; E03 = e03; E04 = e04; E05 = e05; E06 = e06; E07 = e07; E08 = e08; E09 = e09; E10 = e10; E11 = e11; } #endregion } #endregion #region Tup13 public struct Tup13 { public T E00, E01, E02, E03, E04, E05, E06, E07, E08, E09, E10, E11, E12; #region Constructors public Tup13(T e) { E00 = e; E01 = e; E02 = e; E03 = e; E04 = e; E05 = e; E06 = e; E07 = e; E08 = e; E09 = e; E10 = e; E11 = e; E12 = e; } public Tup13(T e00, T e01, T e02, T e03, T e04, T e05, T e06, T e07, T e08, T e09, T e10, T e11, T e12) { E00 = e00; E01 = e01; E02 = e02; E03 = e03; E04 = e04; E05 = e05; E06 = e06; E07 = e07; E08 = e08; E09 = e09; E10 = e10; E11 = e11; E12 = e12; } #endregion } #endregion #region Tup14 public struct Tup14 { public T E00, E01, E02, E03, E04, E05, E06, E07, E08, E09, E10, E11, E12, E13; #region Constructors public Tup14(T e) { E00 = e; E01 = e; E02 = e; E03 = e; E04 = e; E05 = e; E06 = e; E07 = e; E08 = e; E09 = e; E10 = e; E11 = e; E12 = e; E13 = e; } public Tup14(T e00, T e01, T e02, T e03, T e04, T e05, T e06, T e07, T e08, T e09, T e10, T e11, T e12, T e13) { E00 = e00; E01 = e01; E02 = e02; E03 = e03; E04 = e04; E05 = e05; E06 = e06; E07 = e07; E08 = e08; E09 = e09; E10 = e10; E11 = e11; E12 = e12; E13 = e13; } #endregion } #endregion #region Tup15 public struct Tup15 { public T E00, E01, E02, E03, E04, E05, E06, E07, E08, E09, E10, E11, E12, E13, E14; #region Constructors public Tup15(T e) { E00 = e; E01 = e; E02 = e; E03 = e; E04 = e; E05 = e; E06 = e; E07 = e; E08 = e; E09 = e; E10 = e; E11 = e; E12 = e; E13 = e; E14 = e; } public Tup15(T e00, T e01, T e02, T e03, T e04, T e05, T e06, T e07, T e08, T e09, T e10, T e11, T e12, T e13, T e14) { E00 = e00; E01 = e01; E02 = e02; E03 = e03; E04 = e04; E05 = e05; E06 = e06; E07 = e07; E08 = e08; E09 = e09; E10 = e10; E11 = e11; E12 = e12; E13 = e13; E14 = e14; } #endregion } #endregion #region Tup16 public struct Tup16 { public T E00, E01, E02, E03, E04, E05, E06, E07, E08, E09, E10, E11, E12, E13, E14, E15; #region Constructors public Tup16(T e) { E00 = e; E01 = e; E02 = e; E03 = e; E04 = e; E05 = e; E06 = e; E07 = e; E08 = e; E09 = e; E10 = e; E11 = e; E12 = e; E13 = e; E14 = e; E15 = e; } public Tup16(T e00, T e01, T e02, T e03, T e04, T e05, T e06, T e07, T e08, T e09, T e10, T e11, T e12, T e13, T e14, T e15) { E00 = e00; E01 = e01; E02 = e02; E03 = e03; E04 = e04; E05 = e05; E06 = e06; E07 = e07; E08 = e08; E09 = e09; E10 = e10; E11 = e11; E12 = e12; E13 = e13; E14 = e14; E15 = e15; } #endregion } #endregion #endregion #region Tuple of 2 Elements /// /// A tuple is a structure containing three elements of different types, /// that can be accessed using the fields E0, E1. /// public struct Tup { /// /// Element 0 of the tuple. /// public T0 E0; /// /// Element 1 of the tuple. /// public T1 E1; public Tup(T0 e0, T1 e1) { E0 = e0; E1 = e1; } public override readonly string ToString() { return string.Format("({0}, {1})", E0, E1); } } #endregion #region Tuple of 3 Elements /// /// A tuple is a structure containing three elements of different types, /// that can be accessed using the fields E0, E1, E2. /// public struct Tup { /// /// Element 0 of the tuple. /// public T0 E0; /// /// Element 1 of the tuple. /// public T1 E1; /// /// Element 2 of the tuple. /// public T2 E2; public Tup(T0 e0, T1 e1, T2 e2) { E0 = e0; E1 = e1; E2 = e2; } public override readonly string ToString() { return string.Format("({0}, {1}, {2})", E0, E1, E2); } } #endregion #region Tuple of 4 Elements /// /// A tuple is a structure containing three elements of different types, /// that can be accessed using the fields E0, E1, E2, E3. /// public struct Tup { /// /// Element 0 of the tuple. /// public T0 E0; /// /// Element 1 of the tuple. /// public T1 E1; /// /// Element 2 of the tuple. /// public T2 E2; /// /// Element 3 of the tuple. /// public T3 E3; public Tup(T0 e0, T1 e1, T2 e2, T3 e3) { E0 = e0; E1 = e1; E2 = e2; E3 = e3; } public override readonly string ToString() { return string.Format("({0}, {1}, {2}, {3})", E0, E1, E2, E3); } } #endregion #region Tuple of 5 Elements /// /// A tuple is a structure containing three elements of different types, /// that can be accessed using the fields E0, E1, E2, E3, E4. /// public struct Tup { /// /// Element 0 of the tuple. /// public T0 E0; /// /// Element 1 of the tuple. /// public T1 E1; /// /// Element 2 of the tuple. /// public T2 E2; /// /// Element 3 of the tuple. /// public T3 E3; /// /// Element 4 of the tuple. /// public T4 E4; public Tup(T0 e0, T1 e1, T2 e2, T3 e3, T4 e4) { E0 = e0; E1 = e1; E2 = e2; E3 = e3; E4 = e4; } public override readonly string ToString() { return string.Format("({0}, {1}, {2}, {3}, {4})", E0, E1, E2, E3, E4); } } #endregion #region Tuple of 6 Elements /// /// A tuple is a structure containing three elements of different types, /// that can be accessed using the fields E0, E1, E2, E3, E4, E5. /// public struct Tup { /// /// Element 0 of the tuple. /// public T0 E0; /// /// Element 1 of the tuple. /// public T1 E1; /// /// Element 2 of the tuple. /// public T2 E2; /// /// Element 3 of the tuple. /// public T3 E3; /// /// Element 4 of the tuple. /// public T4 E4; /// /// Element 5 of the tuple. /// public T5 E5; public Tup(T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5) { E0 = e0; E1 = e1; E2 = e2; E3 = e3; E4 = e4; E5 = e5; } public override readonly string ToString() { return string.Format("({0}, {1}, {2}, {3}, {4}, {5})", E0, E1, E2, E3, E4, E5); } } #endregion #region Tuple of 7 Elements /// /// A tuple is a structure containing three elements of different types, /// that can be accessed using the fields E0, E1, E2, E3, E4, E5, E6. /// public struct Tup { /// /// Element 0 of the tuple. /// public T0 E0; /// /// Element 1 of the tuple. /// public T1 E1; /// /// Element 2 of the tuple. /// public T2 E2; /// /// Element 3 of the tuple. /// public T3 E3; /// /// Element 4 of the tuple. /// public T4 E4; /// /// Element 5 of the tuple. /// public T5 E5; /// /// Element 6 of the tuple. /// public T6 E6; public Tup(T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6) { E0 = e0; E1 = e1; E2 = e2; E3 = e3; E4 = e4; E5 = e5; E6 = e6; } public override readonly string ToString() { return string.Format("({0}, {1}, {2}, {3}, {4}, {5}, {6})", E0, E1, E2, E3, E4, E5, E6); } } #endregion #region Tuple of 8 Elements /// /// A tuple is a structure containing three elements of different types, /// that can be accessed using the fields E0, E1, E2, E3, E4, E5, E6, E7. /// public struct Tup { /// /// Element 0 of the tuple. /// public T0 E0; /// /// Element 1 of the tuple. /// public T1 E1; /// /// Element 2 of the tuple. /// public T2 E2; /// /// Element 3 of the tuple. /// public T3 E3; /// /// Element 4 of the tuple. /// public T4 E4; /// /// Element 5 of the tuple. /// public T5 E5; /// /// Element 6 of the tuple. /// public T6 E6; /// /// Element 7 of the tuple. /// public T7 E7; public Tup(T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7) { E0 = e0; E1 = e1; E2 = e2; E3 = e3; E4 = e4; E5 = e5; E6 = e6; E7 = e7; } public override readonly string ToString() { return string.Format("({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7})", E0, E1, E2, E3, E4, E5, E6, E7); } } #endregion #region Tuple of 9 Elements /// /// A tuple is a structure containing three elements of different types, /// that can be accessed using the fields E0, E1, E2, E3, E4, E5, E6, E7, E8. /// public struct Tup { /// /// Element 0 of the tuple. /// public T0 E0; /// /// Element 1 of the tuple. /// public T1 E1; /// /// Element 2 of the tuple. /// public T2 E2; /// /// Element 3 of the tuple. /// public T3 E3; /// /// Element 4 of the tuple. /// public T4 E4; /// /// Element 5 of the tuple. /// public T5 E5; /// /// Element 6 of the tuple. /// public T6 E6; /// /// Element 7 of the tuple. /// public T7 E7; /// /// Element 8 of the tuple. /// public T8 E8; public Tup(T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8) { E0 = e0; E1 = e1; E2 = e2; E3 = e3; E4 = e4; E5 = e5; E6 = e6; E7 = e7; E8 = e8; } public override readonly string ToString() { return string.Format("({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8})", E0, E1, E2, E3, E4, E5, E6, E7, E8); } } #endregion #region Tuple of 10 Elements /// /// A tuple is a structure containing three elements of different types, /// that can be accessed using the fields E0, E1, E2, E3, E4, E5, E6, E7, E8, E9. /// public struct Tup { /// /// Element 0 of the tuple. /// public T0 E0; /// /// Element 1 of the tuple. /// public T1 E1; /// /// Element 2 of the tuple. /// public T2 E2; /// /// Element 3 of the tuple. /// public T3 E3; /// /// Element 4 of the tuple. /// public T4 E4; /// /// Element 5 of the tuple. /// public T5 E5; /// /// Element 6 of the tuple. /// public T6 E6; /// /// Element 7 of the tuple. /// public T7 E7; /// /// Element 8 of the tuple. /// public T8 E8; /// /// Element 9 of the tuple. /// public T9 E9; public Tup(T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9) { E0 = e0; E1 = e1; E2 = e2; E3 = e3; E4 = e4; E5 = e5; E6 = e6; E7 = e7; E8 = e8; E9 = e9; } public override readonly string ToString() { return string.Format("({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9})", E0, E1, E2, E3, E4, E5, E6, E7, E8, E9); } } #endregion #region Static Tuple Create Methods /// /// This static class allows the creation of tuples without specifying /// the types in angle brackets. /// public static class Tup { public static Tup Create(T0 e0, T1 e1) { return new Tup(e0, e1); } public static Tup Create(T0 e0, T1 e1, T2 e2) { return new Tup(e0, e1, e2); } public static Tup Create(T0 e0, T1 e1, T2 e2, T3 e3) { return new Tup(e0, e1, e2, e3); } public static Tup Create(T0 e0, T1 e1, T2 e2, T3 e3, T4 e4) { return new Tup(e0, e1, e2, e3, e4); } public static Tup Create(T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5) { return new Tup(e0, e1, e2, e3, e4, e5); } public static Tup Create(T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6) { return new Tup(e0, e1, e2, e3, e4, e5, e6); } public static Tup Create(T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7) { return new Tup(e0, e1, e2, e3, e4, e5, e6, e7); } public static Tup Create(T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8) { return new Tup(e0, e1, e2, e3, e4, e5, e6, e7, e8); } public static Tup Create(T0 e0, T1 e1, T2 e2, T3 e3, T4 e4, T5 e5, T6 e6, T7 e7, T8 e8, T9 e9) { return new Tup(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9); } } #endregion } ================================================ FILE: src/Aardvark.Base/Tup/Tuples_template.cs ================================================ using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; namespace Aardvark.Base { // AUTO GENERATED CODE - DO NOT CHANGE! //# Action comma = () => Out(", "); //# Action space = () => Out(" "); //# int MaxTupleCount = 10; //# int MaxSimpleTupleCount = 16; #region Simple Tuples of uniform type //# for (int tc = 2; tc <= MaxSimpleTupleCount; tc++) { //# Func ename = i => tc < 10 ? i.ToString() : i.ToString("00"); #region Tup__tc__ public struct Tup__tc__ { public T /*# tc.ForEach(i => { var e = ename(i); */E__e__/*# }, comma); */; #region Constructors public Tup__tc__(T e) {/*# tc.ForEach(i => { var e = ename(i); */ E__e__ = e;/*# }); */ } public Tup__tc__(/*# tc.ForEach(i => { var e = ename(i); */T e__e__/*# }, comma); */) {/*# tc.ForEach(i => { var e = ename(i); */ E__e__ = e__e__;/*# }); */ } #endregion } #endregion //# } // tc #endregion //# for (int tc = 2; tc <= MaxTupleCount; tc++) { #region Tuple of __tc__ Elements /// /// A tuple is a structure containing three elements of different types, /// that can be accessed using the fields /*# tc.ForEach(i => { */E__i__/*# }, comma); */. /// public struct Tup { */T__i__/*# }, comma); */> { //# for (int i = 0; i < tc; i++) { /// /// Element __i__ of the tuple. /// public T__i__ E__i__; //# } // i public Tup(/*# tc.ForEach(i => { */T__i__ e__i__/*# }, comma); */) {/*# tc.ForEach(i => { */ E__i__ = e__i__;/*# }); */ } public override readonly string ToString() { return string.Format("(/*# tc.ForEach(i => { */{__i__}/*# }, comma); */)", /*# tc.ForEach(i => { */E__i__/*# }, comma); */); } } #endregion //# } // tc #region Static Tuple Create Methods /// /// This static class allows the creation of tuples without specifying /// the types in angle brackets. /// public static class Tup { //# for (int tc = 2; tc <= MaxTupleCount; tc++) { //# var tpar = tc.Range().Select(i => "T" + i).Join(", "); public static Tup<__tpar__> Create<__tpar__>(/*# tc.ForEach(i => { */T__i__ e__i__/*# }, comma); */) { return new Tup<__tpar__>(/*# tc.ForEach(i => { */e__i__/*# }, comma); */); } //# } // tc } #endregion } ================================================ FILE: src/Aardvark.Base/paket.references ================================================ Aardvark.Build System.Collections.Immutable System.Reflection.Metadata System.Text.Json SingleFileExtractor.Core ================================================ FILE: src/Aardvark.Base/paket.template ================================================ type project id Aardvark.Base authors Aardvark Platform Team owners Aardvark Platform Team projectUrl http://github.com/aardvark-platform licenseUrl http://www.apache.org/licenses/LICENSE-2.0.txt repositoryType git repositoryUrl https://github.com/aardvark-platform/aardvark.base description Aardvark is an open-source platform for visual computing, real-time graphics and visualization. include-pdbs true ================================================ FILE: src/Aardvark.Base.Essentials/Aardvark.Base.Essentials.csproj ================================================ netstandard2.0 true 1701;1702;1705;1591 ..\..\bin\Debug ..\..\bin\Release ================================================ FILE: src/Aardvark.Base.Essentials/Camera/CameraProjectionOrtho.cs ================================================  using System; namespace Aardvark.Base { public class CameraProjectionOrtho : ICameraProjection { private Trafo3d m_trafo; private readonly EventSource m_trafoChanges = new EventSource(); private Box3d m_box; public CameraProjectionOrtho(double left, double right, double bottom, double top, double near, double far) { SetClippingParams(left, right, bottom, top, near, far); } public Trafo3d ProjectionTrafo => m_trafo; public IEvent ProjectionTrafos => m_trafoChanges; public Ray3d Unproject(V2d xyOnNearPlane) => new Ray3d(new V3d(xyOnNearPlane, 0.0), new V3d(xyOnNearPlane, -m_box.Min.Z)); public void SetClippingParams(double left, double right, double bottom, double top, double near, double far) { m_box.Min.X = left; m_box.Max.X = right; m_box.Min.Y = bottom; m_box.Max.Y = top; m_box.Min.Z = near; m_box.Max.Z = far; UpdateProjectionTrafo(); } public double Near { get { return m_box.Min.Z; } set { if (!(value > 0.0 && value < Far)) throw new ArgumentOutOfRangeException(); m_box.Min.Z = value; UpdateProjectionTrafo(); } } public double Far { get { return m_box.Max.Z; } set { if (!(value > 0.0 && value > Near)) throw new ArgumentOutOfRangeException(); m_box.Max.Z = value; UpdateProjectionTrafo(); } } public Box2d ClippingWindow { get { return m_box.XY; } set { if (m_box.IsInvalid) throw new ArgumentOutOfRangeException(); m_box.Min.X = value.Min.X; m_box.Min.Y = value.Min.Y; m_box.Max.X = value.Max.X; m_box.Max.Y = value.Max.Y; UpdateProjectionTrafo(); } } public double AspectRatio { get { return (m_box.Max.X - m_box.Min.X) / (m_box.Max.Y - m_box.Min.Y); } set { if (value <= 0.0) throw new ArgumentOutOfRangeException(); var w = m_box.Max.X - m_box.Min.X; var hOld = m_box.Max.Y - m_box.Min.Y; var hNew = w / value; var f = hNew / hOld; var c = (m_box.Min.Y + m_box.Max.Y) * 0.5; m_box.Min.Y = (m_box.Min.Y - c) * f + c; m_box.Max.Y = (m_box.Max.Y - c) * f + c; UpdateProjectionTrafo(); } } /// /// Scales clipping window by given factor. /// public void Zoom(V2d center, double factor) { if (factor <= 0.0) throw new ArgumentException("Factor needs to be greater than 0.0, but is " + factor + ".", "factor"); m_box.Min.X = (m_box.Min.X - center.X) * factor + center.X; m_box.Min.Y = (m_box.Min.Y - center.Y) * factor + center.Y; m_box.Max.X = (m_box.Max.X - center.X) * factor + center.X; m_box.Max.Y = (m_box.Max.Y - center.Y) * factor + center.Y; UpdateProjectionTrafo(); } private void UpdateProjectionTrafo() { var l = m_box.Min.X; var r = m_box.Max.X; var b = m_box.Min.Y; var t = m_box.Max.Y; var n = m_box.Min.Z; var f = m_box.Max.Z; m_trafo = new Trafo3d( new M44d( 2 / (r - l), 0, 0, (l + r) / (l - r), 0, 2 / (t - b), 0, (b + t) / (b - t), 0, 0, 1 / (n - f), n / (n - f), 0, 0, 0, 1 ), new M44d( (r - l) / 2, 0, 0, (l + r) / 2, 0, (t - b) / 2, 0, (b + t) / 2, 0, 0, n - f, -n, 0, 0, 0, 1 ) ); m_trafoChanges.Emit(m_trafo); } } } ================================================ FILE: src/Aardvark.Base.Essentials/Camera/CameraProjectionPerspective.cs ================================================  using System; namespace Aardvark.Base { public class CameraProjectionPerspective : ICameraProjectionPerspective { private Trafo3d m_trafo; private readonly EventSource m_trafoChanges = new EventSource(); private Box3d m_box; public CameraProjectionPerspective(double horizontalFovInDegrees, double near, double far, double aspectRatio = 1.0) { SetClippingParams(horizontalFovInDegrees, near, far, aspectRatio); } public CameraProjectionPerspective(double left, double right, double bottom, double top, double near, double far) { SetClippingParams(left, right, bottom, top, near, far); } public Trafo3d ProjectionTrafo => m_trafo; public IEvent ProjectionTrafos => m_trafoChanges; public Ray3d Unproject(V2d xyOnNearPlane) => new Ray3d(V3d.Zero, new V3d(xyOnNearPlane, -m_box.Min.Z)); public void SetClippingParams(double left, double right, double bottom, double top, double near, double far) { m_box.Min.X = left; m_box.Max.X = right; m_box.Min.Y = bottom; m_box.Max.Y = top; m_box.Min.Z = near; m_box.Max.Z = far; UpdateProjectionTrafo(); } public void SetClippingParams(double horizontalFovInDegrees, double near, double far, double aspectRatio = 1.0) { var d = System.Math.Tan(Conversion.RadiansFromDegrees(horizontalFovInDegrees) * 0.5) * near; m_box.Min.X = -d; m_box.Max.X = +d; m_box.Min.Y = -d / aspectRatio; m_box.Max.Y = +d / aspectRatio; m_box.Min.Z = near; m_box.Max.Z = far; UpdateProjectionTrafo(); } public double Near { get { return m_box.Min.Z; } set { if (!(value > 0.0 && value < Far)) throw new ArgumentOutOfRangeException(); var s = value / m_box.Min.Z; m_box.Min.X *= s; m_box.Max.X *= s; m_box.Min.Y *= s; m_box.Max.Y *= s; m_box.Min.Z = value; UpdateProjectionTrafo(); } } public double Far { get { return m_box.Max.Z; } set { if (!(value > 0.0 && value > Near)) throw new ArgumentOutOfRangeException(); m_box.Max.Z = value; UpdateProjectionTrafo(); } } public Box2d ClippingWindow { get { return m_box.XY; } set { if (m_box.IsInvalid) throw new ArgumentException(); m_box.Min.X = value.Min.X; m_box.Min.Y = value.Min.Y; m_box.Max.X = value.Max.X; m_box.Max.Y = value.Max.Y; UpdateProjectionTrafo(); } } public double AspectRatio { get { return (m_box.Max.X - m_box.Min.X) / (m_box.Max.Y - m_box.Min.Y); } set { if (value <= 0.0) throw new ArgumentOutOfRangeException(); m_box.Min.Y = m_box.Min.X / value; m_box.Max.Y = m_box.Max.X / value; UpdateProjectionTrafo(); } } public double HorizontalFieldOfViewInDegrees { get { var l = System.Math.Atan2(m_box.Min.X, m_box.Min.Z); var r = System.Math.Atan2(m_box.Max.X, m_box.Min.Z); return Conversion.DegreesFromRadians(-l + r); } } private void UpdateProjectionTrafo() { var l = m_box.Min.X; var r = m_box.Max.X; var b = m_box.Min.Y; var t = m_box.Max.Y; var n = m_box.Min.Z; var f = m_box.Max.Z; m_trafo = Trafo3d.PerspectiveProjectionRH(l, r, b, t, n, f); m_trafoChanges.Emit(m_trafo); } } } ================================================ FILE: src/Aardvark.Base.Essentials/Camera/CameraViewRaw.cs ================================================  namespace Aardvark.Base { public class CameraViewRaw : ICameraView { private Trafo3d m_trafo = Trafo3d.ViewTrafo(V3d.Zero, V3d.XAxis, V3d.ZAxis, -V3d.YAxis); private readonly EventSource m_trafoChanges; public CameraViewRaw() { m_trafoChanges = EventSource.Create(m_trafo); } /// /// Gets or sets view trafo, which transforms world space into camera space. /// /// In camera space the camera is placed at the origin looking /// down the negative z-axis, with the y-axis pointing upwards /// and the x-axis pointing to the right. /// public Trafo3d ViewTrafo { get { return m_trafo; } set { m_trafo = value; m_trafoChanges.Emit(m_trafo); } } /// /// Changes of ViewTrafo. /// public IEvent ViewTrafos => m_trafoChanges; /// /// Gets or sets camera location in world space (origin in camera space). /// public V3d Location { get { return m_trafo.Backward.C3.XYZ; } set { m_trafo = Trafo3d.ViewTrafo(value, Right, Up, -Forward); m_trafoChanges.Emit(m_trafo); } } /// /// Gets or sets camera right vector in world space (+x in camera space). /// public V3d Right { get { return m_trafo.Backward.C0.XYZ; } set { m_trafo = Trafo3d.ViewTrafo(Location, value, Up, -Forward); m_trafoChanges.Emit(m_trafo); } } /// /// Gets or sets camera up vector in world space (+y in camera space). /// public V3d Up { get { return m_trafo.Backward.C1.XYZ; } set { m_trafo = Trafo3d.ViewTrafo(Location, Right, value, -Forward); m_trafoChanges.Emit(m_trafo); } } /// /// Gets or sets camera forward direction in world space (-z in camera space). /// public V3d Forward { get { return -m_trafo.Backward.C2.XYZ; } set { m_trafo = Trafo3d.ViewTrafo(Location, Right, Up, -value); m_trafoChanges.Emit(m_trafo); } } /// /// Sets location and axes in a single transaction. /// public void Set(V3d location, V3d right, V3d up, V3d forward) { m_trafo = Trafo3d.ViewTrafo(location, right, up, -forward); m_trafoChanges.Emit(m_trafo); } } } ================================================ FILE: src/Aardvark.Base.Essentials/Camera/CameraViewWithSky.cs ================================================  using System; namespace Aardvark.Base { public class CameraViewWithSky : ICameraView { private V3d m_sky = V3d.OOI; private Trafo3d m_trafo = Trafo3d.ViewTrafo(V3d.Zero, V3d.XAxis, V3d.ZAxis, -V3d.YAxis); private readonly EventSource m_trafoChanges = new EventSource(); /// /// Sky direction (normalized). /// public V3d Sky { get { return m_sky; } set { m_sky = value.Normalized; if (m_sky == V3d.Zero) throw new ArgumentException("Sky direction must not be V3d.Zero."); var r = Vec.Cross(Forward, m_sky).Normalized; var u = Vec.Cross(r, Forward); m_trafo = Trafo3d.ViewTrafo(Location, r, u, -Forward); m_trafoChanges.Emit(m_trafo); } } /// /// Gets or sets view trafo, which transforms world space into camera space. /// /// In camera space the camera is placed at the origin looking /// down the negative z-axis, with the y-axis pointing upwards /// and the x-axis pointing to the right. /// public Trafo3d ViewTrafo { get { return m_trafo; } set { m_trafo = value; m_trafoChanges.Emit(m_trafo); } } /// /// Changes of ViewTrafo. /// public IEvent ViewTrafos => m_trafoChanges; /// /// Gets or sets camera location in world space (origin in camera space). /// public V3d Location { get { return m_trafo.Backward.C3.XYZ; } set { //Report.Line("{0:0.00}", value); m_trafo = Trafo3d.ViewTrafo(value, Right, Up, -Forward); m_trafoChanges.Emit(m_trafo); } } /// /// Gets or sets camera right vector in world space (+x in camera space). /// public V3d Right { get { return m_trafo.Backward.C0.XYZ; } set { var r = value.Normalized; var f = Vec.Cross(m_sky, r).Normalized; var u = Vec.Cross(r, f); m_trafo = Trafo3d.ViewTrafo(Location, r, u, -f); m_trafoChanges.Emit(m_trafo); } } /// /// Gets or sets camera up vector in world space (+y in camera space). /// public V3d Up { get { return m_trafo.Backward.C1.XYZ; } set { var u = value.Normalized; var r = Vec.Cross(u, m_sky).Normalized; var f = Vec.Cross(u, r); m_trafo = Trafo3d.ViewTrafo(Location, r, u, -f); m_trafoChanges.Emit(m_trafo); } } /// /// Gets or sets camera forward direction in world space (-z in camera space). /// public V3d Forward { get { return -m_trafo.Backward.C2.XYZ; } set { var f = value.Normalized; var r = Vec.Cross(f, m_sky).Normalized; var u = Vec.Cross(r, f); m_trafo = Trafo3d.ViewTrafo(Location, r, u, -f); m_trafoChanges.Emit(m_trafo); } } /// /// Sets location and axes in a single transaction. /// public void Set(V3d location, V3d right, V3d up, V3d forward) { m_trafo = Trafo3d.ViewTrafo(location, right, up, -forward); m_trafoChanges.Emit(m_trafo); } } } ================================================ FILE: src/Aardvark.Base.Essentials/Camera/ICameraProjection.cs ================================================ using Aardvark.Base; namespace Aardvark.Base { public interface ICameraProjection { /// /// Transforms the right-handed camera space (looking down the negative z-axis) /// to left-handed normalized device coordinates of the canonical view volume /// defined as [(-1, -1, 0), (+1, +1, +1)]. /// Here the x-axis goes to the right, the y-axis goes up, and the z-axis goes /// into the viewport, with near plane mapped to z = 0 and far plane to z = 1. /// Trafo3d ProjectionTrafo { get; } /// /// Changes of ProjectionTrafo. /// IEvent ProjectionTrafos { get; } /// /// E.g. SetClippingParams(-1, +1, -0.75, +0.75, 1.0, 1000.0) /// will create 90° horizontal field-of-view, with aspect ratio 4:3, /// near distance at 1.0, and far distance at 1000.0. /// void SetClippingParams(double left, double right, double bottom, double top, double near, double far); /// /// Gets or sets distance of near clipping plane. /// Same as 'near' argument in SetClippingParams. /// double Near { get; set; } /// /// Gets or sets distance of far clipping plane. /// Same as 'far' argument in SetClippingParams. /// double Far { get; set; } /// /// Gets or sets clipping window on near plane [(left, bottom), (right, top)]. /// Same as 'left', 'right', 'bottom', 'top' arguments in SetClippingParams. /// Box2d ClippingWindow { get; set; } /// /// Width / Height. /// double AspectRatio { get; set; } } public interface ICameraProjectionPerspective : ICameraProjection { double HorizontalFieldOfViewInDegrees { get; } } } ================================================ FILE: src/Aardvark.Base.Essentials/Camera/ICameraProjectionExtensions.cs ================================================ using Aardvark.Base; using System; namespace Aardvark.Base { public static class ICameraProjectionExtensions { /// /// Gets line (in camera space) from point on near plane to corresponding point on far plane. /// public static Line3d Unproject(this ICameraProjection self, Ndc2d p) => new Line3d( self.UnprojectPointOnNearPlane(p), self.UnprojectPointOnFarPlane(p) ); /// /// Gets point (in camera space) from point in normalized device coordinates. /// public static V3d Unproject(this ICameraProjection self, Ndc3d p) => self.ProjectionTrafo.Backward.TransformPosProj(p.Position); /// /// Gets point on near plane (in camera space) from point in normalized device coordinates. /// public static V3d UnprojectPointOnNearPlane(this ICameraProjection self, Ndc2d p) => self.ProjectionTrafo.Backward.TransformPosProj(new V3d(p.Position, 0.0)); /// /// Gets point on far plane (in camera space) from point in normalized device coordinates. /// public static V3d UnprojectPointOnFarPlane(this ICameraProjection self, Ndc2d p) => self.ProjectionTrafo.Backward.TransformPosProj(new V3d(p.Position, 1.0)); /// /// Gets normalized device coordinates from point in camera space. /// public static Ndc3d TransformPos(this ICameraProjection self, V3d posInCameraSpace) => new Ndc3d(self.ProjectionTrafo.Forward.TransformPosProj(posInCameraSpace)); /// /// Scales clipping window by given factor. /// public static void Zoom(this ICameraProjection self, V2d center, double factor) { if (factor <= 0.0) throw new ArgumentException("Factor needs to be greater than 0.0, but is " + factor + ".", "factor"); var box = self.ClippingWindow; box.Min.X = (box.Min.X - center.X) * factor + center.X; box.Min.Y = (box.Min.Y - center.Y) * factor + center.Y; box.Max.X = (box.Max.X - center.X) * factor + center.X; box.Max.Y = (box.Max.Y - center.Y) * factor + center.Y; self.ClippingWindow = box; } } } ================================================ FILE: src/Aardvark.Base.Essentials/Camera/ICameraView.cs ================================================ using Aardvark.Base; namespace Aardvark.Base { public interface ICameraView { /// /// Gets or sets view trafo, which transforms world space into camera space. /// /// In camera space the camera is placed at the origin looking /// down the negative z-axis, with the y-axis pointing upwards /// and the x-axis pointing to the right. /// Trafo3d ViewTrafo { get; set; } /// /// Changes of ViewTrafo. /// IEvent ViewTrafos { get; } /// /// Gets or sets camera location in world space (origin in camera space). /// V3d Location { get; set; } /// /// Gets or sets camera right vector in world space (+x in camera space). /// V3d Right { get; set; } /// /// Gets or sets camera up vector in world space (+y in camera space). /// V3d Up { get; set; } /// /// Gets or sets camera forward direction in world space (-z in camera space). /// V3d Forward { get; set; } /// /// Sets location and axes in a single transaction. /// void Set(V3d location, V3d right, V3d up, V3d forward); } } ================================================ FILE: src/Aardvark.Base.Essentials/Camera/ICameraViewExtensions.cs ================================================ using Aardvark.Base; using System; using System.Threading; using System.Threading.Tasks; namespace Aardvark.Base { public static class ICameraViewExtensions { /// /// Turns camera to look at given point p. /// public static void LookAt(this ICameraView self, V3d p) => self.Forward = (p - self.Location).Normalized; } } ================================================ FILE: src/Aardvark.Base.Essentials/Camera/IRenderView.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Aardvark.Base { public interface IViewProjection { /// /// The view transformation /// ICameraView View { get; } /// /// The projection transformation /// ICameraProjection Projection { get; } } public interface IRenderView: IViewProjection { /// /// Region of the RenderBuffer or Control /// Box2i Region { get; } } } ================================================ FILE: src/Aardvark.Base.Essentials/Camera/IRenderViewExtensions.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Aardvark.Base { public static class IRenderViewExtensions { /// /// Projects a point from world-space to normalized device coordinates. /// public static Ndc3d Project(this IRenderView rv, V3d point) { var viewPoint = rv.View.ViewTrafo.Forward.TransformPos(point); return rv.Projection.TransformPos(viewPoint); } /// /// Project a point from world-space to a pixel position. /// public static PixelPosition ProjectPixel(this IRenderView rv, V3d point) { var ndcPoint = rv.Project(point); return new PixelPosition(ndcPoint, rv.Region); } /// /// Returns the number of pixels per unit on the near plane. /// ISSUE: Does not consider ClippingWindow of projection /// public static V2d PixelsPerUnitOnNearPlane(this IRenderView rv) { if (rv.Projection is ICameraProjectionPerspective) { var unitsOnNearPlane = Fun.Tan(((ICameraProjectionPerspective)rv.Projection).HorizontalFieldOfViewInDegrees.RadiansFromDegrees() * 0.5) * 2 * rv.Projection.Near; return (V2d)rv.Region.Size / new V2d(unitsOnNearPlane, unitsOnNearPlane / rv.Projection.AspectRatio); } else { return (V2d)rv.Region.Size / rv.Projection.ClippingWindow.Size; } } /// /// Returns the multiplied View-Projection transformation. /// public static Trafo3d ViewProjTrafo(this IViewProjection vp) => vp.View.ViewTrafo * vp.Projection.ProjectionTrafo; /// /// Builds a hull from the given view-projection (left, right, top, bottom, near, far). /// The normals of the hull planes point to the outside. /// A point inside the visual hull will have positive height to all planes. /// public static Hull3d GetVisualHull(this IViewProjection vp) => vp.ViewProjTrafo().GetVisualHull(); /// /// Returns the ray-direction towards the center of the view. /// public static V3d CentralDirection(this IViewProjection vp) { var trafo = vp.View.ViewTrafo.Backward * vp.Projection.ProjectionTrafo.Backward; var nearPoint = trafo.TransformPosProj(V3d.OOO); var farPoint = trafo.TransformPosProj(V3d.OOI); return (farPoint - nearPoint).Normalized; } } } ================================================ FILE: src/Aardvark.Base.Essentials/Editing/BehaviorDragAbsolute.cs ================================================ using System; using System.Threading; using System.Threading.Tasks; namespace Aardvark.Base { /// /// Behavior extension DragAbsolute. /// public static class BehaviorDragAbsolute { /// /// Updates position until stopDragging completes. /// public static async Task DragAbsolute(this IBehavior self, IEvent positions, IAwaitable stopDragging, CancellationToken ct ) { var obj = self as IBehaviorPosition2d; if (obj == null) throw new InvalidOperationException("DragAbsolute requires IBehaviorPosition2d."); await stopDragging.RepeatUntilCompleted(async delegate { var p = await positions.Next.WithCancellation(ct); if (stopDragging.IsCompleted) return; obj.Position = p; }); return self; } } } ================================================ FILE: src/Aardvark.Base.Essentials/Editing/BehaviorDragRelative.cs ================================================ using System; using System.Threading; using System.Threading.Tasks; namespace Aardvark.Base { /// /// Behavior extension DragRelative. /// public static class BehaviorDragRelative { /// /// Updates position until stopDragging completes. /// public static async Task DragRelative(this IBehavior self, V2d initialPosition, IEvent moves, IAwaitable stopDragging, CancellationToken ct ) { var obj = self as IBehaviorTransform2d; if (obj == null) throw new InvalidOperationException("DragRelative requires IBehaviorTransform2d."); var lastPos = initialPosition; await stopDragging.RepeatUntilCompleted( async delegate { var p = await moves.Next.WithCancellation(ct); obj.Transform(M33d.Translation(p - lastPos)); lastPos = p; }); return self; } } } ================================================ FILE: src/Aardvark.Base.Essentials/Editing/IBehavior.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Aardvark.Base { /// /// Marker interface fort all behaviors. /// public interface IBehavior { } } ================================================ FILE: src/Aardvark.Base.Essentials/Editing/IBehaviorDeletable.cs ================================================ namespace Aardvark.Base { /// /// Editable object can be deleted. /// public interface IBehaviorDeletable : IBehavior { /// /// Deletes editable object. /// void Delete(); } } ================================================ FILE: src/Aardvark.Base.Essentials/Editing/IBehaviorPosition2d.cs ================================================ namespace Aardvark.Base { /// /// Editable object has a position in 2d. /// public interface IBehaviorPosition2d : IBehavior { /// /// Gets or sets 2d position. /// V2d Position { get; set; } } } ================================================ FILE: src/Aardvark.Base.Essentials/Editing/IBehaviorSplittableEdge2d.cs ================================================ namespace Aardvark.Base { /// /// Editable edge that can be splitted. /// public interface IBehaviorSplittableEdge2d : IBehavior { /// /// Splits edge at position nearest to given split position. /// void Split(V2d splitPosition); } } ================================================ FILE: src/Aardvark.Base.Essentials/Editing/IBehaviorTransform2d.cs ================================================ namespace Aardvark.Base { /// /// Editable object can be transformed in 2d. /// public interface IBehaviorTransform2d : IBehavior { /// /// Transform in 2d. /// void Transform(M33d trafo); } } ================================================ FILE: src/Aardvark.Base.Essentials/Editing/IEditableEdge2d.cs ================================================ namespace Aardvark.Base { /// /// An editable edge. /// public interface IEditableEdge2d : IBehaviorPosition2d, IBehaviorTransform2d, IBehaviorSplittableEdge2d, IBehaviorDeletable, IEditableSequence { } } ================================================ FILE: src/Aardvark.Base.Essentials/Editing/IEditableFace2d.cs ================================================ namespace Aardvark.Base { /// /// An editable face. /// public interface IEditableFace2d : IBehaviorPosition2d, IBehaviorTransform2d, IBehaviorDeletable { /// /// Returns index-th vertex as editable vertex. /// IEditableVertex2d GetEditableVertex(int index); /// /// Returns index-th edge as editable edge. /// IEditableEdge2d GetEditableEdge(int index); } } ================================================ FILE: src/Aardvark.Base.Essentials/Editing/IEditableSequence.cs ================================================ namespace Aardvark.Base { /// /// Exposes sequence of editing steps. /// public interface IEditableSequence { /// /// Sets or gets current version of editable object. /// T Current { get; set; } /// /// Sequence of editing steps. /// IEvent EditingSteps { get; } } } ================================================ FILE: src/Aardvark.Base.Essentials/Editing/IEditableVertex2d.cs ================================================ namespace Aardvark.Base { /// /// An editable vertex. /// public interface IEditableVertex2d : IBehaviorPosition2d, IBehaviorTransform2d, IBehaviorDeletable, IEditableSequence { } } ================================================ FILE: src/Aardvark.Base.Essentials/NormalizedDeviceCoordinates.cs ================================================ using Aardvark.Base; namespace Aardvark.Base { /// /// Position (x,y) in normalized device coordinates. /// The canonical view volume is defined as [(-1, -1, 0), (+1, +1, 1)]. /// public readonly struct Ndc2d { /// /// Normalized device coordinates. /// public readonly V2d Position; /// /// Position (xy) in normalized device coordinates. /// public Ndc2d(V2d position) { Position = position; } /// /// Position (xy) in normalized device coordinates. /// public Ndc2d(double x, double y) { Position = new V2d(x, y); } /// /// Position (xy) in normalized device coordinates. /// public Ndc2d(PixelPosition p) { var np = p.NormalizedPosition; Position = new V2d( -1.0 + np.X * 2.0, +1.0 - np.Y * 2.0 ); } /// /// Transform the normalized device coordinate to a [0, 1] texture coordinate (flipping Y). /// public V2d TextureCoordinate { get { return new V2d(Position.X * 0.5 + 0.5, -Position.Y * 0.5 + 0.5); } } } /// /// Position (xyz) in normalized device coordinates. /// The canonical view volume is defined as [(-1, -1, 0), (+1, +1, 1)]. /// public readonly struct Ndc3d { /// /// Normalized device coordinates. /// public readonly V3d Position; /// /// Position (xyz) in normalized device coordinates. /// public Ndc3d(V3d position) { Position = position; } /// /// Position (xy) in normalized device coordinates. /// public Ndc3d(double x, double y, double z) { Position = new V3d(x, y, z); } /// /// Transform the normalized device coordinate to a [0, 1] texture coordinate (flipping Y) with depth. /// public V3d TextureCoordinate { get { return new V3d(Position.X * 0.5 + 0.5, -Position.Y * 0.5 + 0.5, Position.Z); } } } } ================================================ FILE: src/Aardvark.Base.Essentials/PixelPosition.cs ================================================ using Aardvark.Base; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Aardvark.Base { /// /// An integral pixel position relative to specified bounds. /// The x-axis goes from left to right and y-axis from top to bottom. /// public readonly struct PixelPosition { /// /// X goes from left to right and y from top to bottom. /// Integral pixel positions correspond to pixel centers. /// public readonly V2i Position; /// /// Minimum is top left pixel (inclusive) and maximum is bottom right pixel (exclusive). /// E.g. with bounds [(0, 0), (800, 600)] the top left pixel is (0,0) and the bottom /// right pixel is (799,599). /// public readonly Box2i Bounds; /// /// Pixel position relative to specified bounds. /// For example, a typical render window has bounds [(0, 0), (width, height)]. /// public PixelPosition(V2i position, Box2i bounds) { Position = position; Bounds = bounds; } /// /// Pixel position relative to specified bounds. /// For example, a typical render window has bounds [(0, 0), (width, height)]. /// public PixelPosition(V2i position, int width, int height) { Position = position; Bounds = Box2i.FromSize(width, height); } /// /// Pixel position relative to specified bounds. /// For example, a typical render window has bounds [(0, 0), (width, height)]. /// public PixelPosition(int x, int y, int width, int height) { Position = new V2i(x, y); Bounds = Box2i.FromSize(width, height); } /// /// PixelPosition from normalized device coordinates. /// public PixelPosition(Ndc2d ndc, V2i renderTargetSize) : this(ndc, Box2i.FromSize(renderTargetSize)) { } /// /// PixelPosition from normalized device coordinates. /// public PixelPosition(Ndc2d ndc, Box2i renderTargetRegion) { Position = new V2i(ndc.TextureCoordinate * (V2d)renderTargetRegion.Size); Bounds = renderTargetRegion; } /// /// PixelPosition from normalized device coordinates. /// public PixelPosition(Ndc3d ndc, V2i renderTargetSize) : this(ndc, Box2i.FromSize(renderTargetSize)) { } /// /// PixelPosition from normalized device coordinates. /// public PixelPosition(Ndc3d ndc, Box2i renderTargetRegion) : this(new Ndc2d(ndc.Position.XY), renderTargetRegion) { } /// /// Maps integral pixel position to range ](0,0), (1,1)[, /// where integral pixel positions correspond to pixel centers. /// E.g. all pixel mappings for Bounds [(0,0), (3,2)] are as follows: /// (0,0) -> (0.17, 0.25) /// (1,0) -> (0.50, 0.25) /// (2,0) -> (0.83, 0.25) /// (0,1) -> (0.17, 0.75) /// (0,2) -> (0.50, 0.75) /// (0,3) -> (0.83, 0.75) /// public V2d NormalizedPosition => new V2d( (Position.X - Bounds.Min.X + 0.5) / (Bounds.Max.X - Bounds.Min.X), (Position.Y - Bounds.Min.Y + 0.5) / (Bounds.Max.Y - Bounds.Min.Y) ); } } ================================================ FILE: src/Aardvark.Base.Essentials/Screenshot.cs ================================================ using System; using System.IO; using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; using Aardvark.Base; using System.Net; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net.Sockets; namespace Aardvark.Rendering { public class HttpServer2Route { private enum Mode { Literal, Variable, Mixed, } private readonly Http.Verb m_verb; private readonly string m_route; private readonly Action m_handler; private readonly string[] m_tokens; private readonly Mode[] m_modes; public Action Handler { get { return m_handler; } } public string Route { get { return m_route; } } public Http.Verb Verb { get { return m_verb; } } public bool Matches(string s, Dictionary variables) { var matchedVariables = new List<(string, string)>(); var tokens = s.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); if (tokens.Length != m_tokens.Length) return false; for (int i = 0; i < tokens.Length; i++) { switch (m_modes[i]) { case Mode.Literal: if (!m_tokens[i].Equals(tokens[i])) return false; break; case Mode.Variable: matchedVariables.Add((m_tokens[i], tokens[i])); break; case Mode.Mixed: { int start = m_tokens[i].IndexOf('['); int end = m_tokens[i].IndexOf(']'); if (end != m_tokens[i].Length - 1) return false; var pre = m_tokens[i].Left(start); if (!tokens[i].StartsWith(pre)) return false; matchedVariables.Add( ( m_tokens[i].Substring(start + 1, end - start - 1), tokens[i].Substring(pre.Length) )); } break; default: throw new NotImplementedException(); } } foreach (var mv in matchedVariables) variables[mv.Item1] = mv.Item2; return true; } public HttpServer2Route(string route, Http.Verb verb, Action handler) { m_verb = verb; m_route = route; m_handler = handler; m_tokens = route.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); m_modes = new Mode[m_tokens.Length]; for (int i = 0; i < m_tokens.Length; i++) { var token = m_tokens[i]; var length = token.Length; if (token.Contains("[")) { if (token[0] == '[' && token[length - 1] == ']') { m_modes[i] = Mode.Variable; m_tokens[i] = token.Substring(1, length - 2); } else { m_modes[i] = Mode.Mixed; } } else { m_modes[i] = Mode.Literal; } } } } public class HttpServer2Dispatcher { private readonly List m_routes = new List(); public void AddRoutes(params HttpServer2Route[] routes) { AddRoutes((IEnumerable)routes); } public void AddRoutes(IEnumerable routes) { m_routes.AddRange(routes); } public void AddRoute(HttpServer2Route route) { m_routes.Add(route); } public HttpServer2Dispatcher() { } public HttpServer2Dispatcher(params HttpServer2Route[] routes) : this((IEnumerable)routes) { } public HttpServer2Dispatcher(IEnumerable routes) { m_routes.AddRange(routes); } public HttpServer2Route Dispatch(string uri, Http.Verb verb, Dictionary variables) { return m_routes .Where(r => r.Verb == verb) .Where(r => r.Matches(uri, variables)) .FirstOrDefault(); } } public class HttpServerRequestInfo { private HttpListenerContext m_context; private string m_head; private string m_route; private Http.Verb m_verb; private readonly Dictionary m_query = new Dictionary(); public string Head { get { return m_head; } internal set { m_head = value; } } public string Route { get { return m_route; } internal set { m_route = value; } } public HttpListenerContext Context { get { return m_context; } internal set { m_context = value; } } public Http.Verb Verb { get { return m_verb; } internal set { m_verb = value; } } public Dictionary Query { get { return m_query; } } public string Get(string paramName, string defaultValue) { return m_query.ContainsKey(paramName) ? m_query[paramName] : defaultValue; } public int Get(string paramName, int defaultValue) { try { return m_query.ContainsKey(paramName) ? m_query[paramName].ToInt() : defaultValue; } catch { return defaultValue; } } public double Get(string paramName, double defaultValue) { try { return m_query.ContainsKey(paramName) ? m_query[paramName].ToDouble() : defaultValue; } catch { return defaultValue; } } } public class HttpServerDispatcher { private readonly Dictionary>> m_handlers = new Dictionary>>(); private readonly Dictionary> m_dispatchers = new Dictionary>(); public void Register(Func handler) { Register("", handler); } public void Register(string prefix, Func handler) { prefix = prefix ?? ""; if (!m_handlers.ContainsKey(prefix)) { m_handlers[prefix] = new List>(); } m_handlers[prefix].Add(handler); } public void Register(Http.Verb verb, Func handler) { Register("", verb, handler); } public void Register(string prefix, Http.Verb verb, Func handler) { prefix = prefix ?? ""; prefix += "." + verb.ToString(); Register(prefix, handler); } public void Register(HttpServerDispatcher dispatcher) { Register("", dispatcher); } public void Register(string prefix, HttpServerDispatcher dispatcher) { prefix = prefix ?? ""; if (!m_dispatchers.ContainsKey(prefix)) { m_dispatchers[prefix] = new List(); } m_dispatchers[prefix].Add(dispatcher); } public IEnumerable Prefixes { get { return m_handlers.Keys.Select(x => x.ToString()).Concat( m_dispatchers.Keys.Select(x => x.ToString()) ); } } /// /// Returns true if route has been handled. /// internal bool Dispatch(HttpServerRequestInfo info) { string route = info.Route; bool routeHasBeenHandled = false; // 0. preconditions // (e.g. "/foo/bar/woohoo" -> "foo/bar/woohoo") if (route != null && route.Length > 0 && route[0] == '/') route = route.Substring(1); // 1. split route into head and tail string head, tail; int separatorIndex = route.IndexOf('/'); if (separatorIndex < 0) { head = route; tail = ""; } else { head = route.Substring(0, separatorIndex); tail = route.Substring(separatorIndex + 1); } // 2. call handlers & dispatchers List> handlers; if (m_handlers.TryGetValue("", out handlers)) { foreach (var handler in handlers) { routeHasBeenHandled |= handler(info); } } var storeRoute = info.Route; var storeHead = info.Head; info.Route = tail; info.Head = head; if (m_handlers.TryGetValue(head, out handlers)) { foreach (var handler in handlers) { routeHasBeenHandled |= handler(info); } } if (m_handlers.TryGetValue(head + "." + info.Verb.ToString(), out handlers)) { foreach (var handler in handlers) { routeHasBeenHandled |= handler(info); } } List dispatchers; if (m_dispatchers.TryGetValue(head, out dispatchers)) { foreach (var dispatcher in dispatchers) { routeHasBeenHandled |= dispatcher.Dispatch(info); } } info.Head = storeHead; info.Route = storeRoute; return routeHasBeenHandled; } public HttpServerDispatcher() { Register("help", DefaultHelpHandler); } private bool DefaultHelpHandler(HttpServerRequestInfo info) { var items = new List(); foreach (var p in Prefixes) { if (p == null || p == "" || p == "help") continue; if (p.EndsWith(".GET")) { items.Add(p.Sub(0, -4)); continue; } if (p.EndsWith(".POST")) { items.Add(p.Sub(0, -5)); continue; } if (p.EndsWith(".PUT")) { items.Add(p.Sub(0, -4)); continue; } if (p.EndsWith(".DELETE")) { items.Add(p.Sub(0, -7)); continue; } items.Add(p); } info.Context.SendReply(items.Distinct().Join(", ")); return true; } } public static class Http { public enum Verb { GET, POST, PUT, DELETE, } public static WebResponse Get(string uri, Dictionary query) { return Send("GET", uri, query, null, null); } public static WebResponse Get(string uri) { return Send("GET", uri, null, null, null); } public static WebResponse Post( string uri, Dictionary query, string contentType, byte[] data) { return Send("POST", uri, query, data, contentType); } public static WebResponse Post( string uri, Dictionary query, string contentType, string data) { return Send("POST", uri, query, new UTF8Encoding().GetBytes(data), contentType); } public static WebResponse Post( string uri, string contentType, byte[] data) { return Send("POST", uri, null, data, contentType); } public static WebResponse Post( string uri, string contentType, string data) { return Send("POST", uri, null, new UTF8Encoding().GetBytes(data), contentType); } public static WebResponse Delete(string uri) { return Send("DELETE", uri, null, null, null); } public static WebResponse Put(string uri) { return Send("PUT", uri, null, null, null); } //public static WebResponse Put( // string uri, Dictionary query, // string contentType, byte[] data) //{ // return Send("PUT", uri, query, data, contentType); //} //public static WebResponse Delete( // string uri, Dictionary query) //{ // return Send("DELETE", uri, query, null, null); //} public static WebResponse Send( string verb, string uri, Dictionary query, byte[] postData, string contentType) { if (uri.Right(1) == "/") uri = uri.Substring(0, uri.Length - 1); if (query != null) { uri += "?" + query .Select(x => string.Format("{0}={1}", x.Key, x.Value.ToString())) .Join("&"); } var finalUri = new Uri(uri); var httpRequest = (HttpWebRequest)WebRequest.Create(finalUri); httpRequest.Method = verb; if (postData != null) { httpRequest.ContentType = contentType; httpRequest.ContentLength = postData.Length; using (var s = httpRequest.GetRequestStream()) { s.Write(postData, 0, postData.Length); } } return httpRequest.GetResponse(); } } public class HttpServer { private static string s_defaultPrefix = null; private readonly HttpListener m_listener = new HttpListener(); private readonly HttpServerDispatcher m_dispatcher = new HttpServerDispatcher(); private HttpServer2Dispatcher m_dispatcher2 = null; private volatile bool m_isRunning = false; private volatile bool m_stop = false; private readonly object m_lock = new object(); public void SwitchToNewStyle() { m_dispatcher2 = new HttpServer2Dispatcher(); } /// /// Old-style dispatcher. /// public HttpServerDispatcher Dispatcher { get { return m_dispatcher; } } /// /// New-style dispatcher. /// public HttpServer2Dispatcher Dispatcher2 { get { return m_dispatcher2; } } public bool IsRunning { get { return m_isRunning; } } /// /// Gets underlying HttpListener for fine-grained control. /// public HttpListener HttpListener { get { return m_listener; } } public void Stop() { if (!m_isRunning) return; m_stop = true; m_listener.Close(); while (m_isRunning) ;// Report.Warn("stopping"); } public void Start() { lock (m_lock) { if (m_isRunning) { Report.Line(5, "WARNING: HttpServer already running - doing nothing"); return; } m_isRunning = true; } // listen on default uri if no user-specified prefix is given // default is: http:\\:4242/ if (m_listener.Prefixes.Count == 0) { if (s_defaultPrefix == null) { var localIP = Dns.GetHostAddresses(Dns.GetHostName()) .Where(x => x.AddressFamily == AddressFamily.InterNetwork) .FirstOrDefault() ; if (localIP != null) { s_defaultPrefix = string.Format("http://{0}:4242/", localIP.ToString()); } else { s_defaultPrefix = "http://localhost:4242/"; } } m_listener.Prefixes.Add(s_defaultPrefix); } try { Report.Line(4, "[starting] kernel http server"); m_listener.Start(); Report.Line(4, "[started ] kernel http server"); Report.Line(4, " listening on {0}", m_listener.Prefixes.Select(x => x).Join(", ") ); } catch (Exception e) { // catch all - if listening fails for any reason // then report exception and continue without kernel http server Report.Line("[info] failed to listen on {0}", s_defaultPrefix); Report.Line(" {0}", e.ToString()); lock (m_lock) m_isRunning = false; return; // do not start server loop } // http server loop Task.Factory.StartNew(delegate { while (!m_stop) { try { var context = m_listener.GetContext(); if (m_stop) break; #region Init HttpServerRequestInfo var info = new HttpServerRequestInfo() { Context = context }; // init route var route = context.Request.RawUrl; var queryStartIndex = route.IndexOf('?'); if (queryStartIndex >= 0) { // cut off query part of uri route = route.Substring(0, queryStartIndex); } if (route.Length > 0 && route.Right(1) == "/") { // cut off trailing '/' route = route.Substring(0, route.Length - 1); } info.Route = route; // init verb switch (context.Request.HttpMethod) { case "GET": info.Verb = Http.Verb.GET; break; case "POST": info.Verb = Http.Verb.POST; break; case "PUT": info.Verb = Http.Verb.PUT; break; case "DELETE": info.Verb = Http.Verb.DELETE; break; } // init query var query = context.Request.QueryString; for (int i = 0; i < query.Count; i++) { info.Query[query.GetKey(i)] = query.GetValues(i).Join(";"); } #endregion if (m_dispatcher2 == null) { // dispatch (old-style) Task.Factory.StartNew(delegate { try { bool handled = m_dispatcher.Dispatch(info); // if no handler matches reply "not found" if (!handled) { context.SendReply(s_notFoundReply, HttpStatusCode.NotFound); } } catch (Exception e) { Report.Warn("HttpServer: {0}", e.ToString()); } }); } else { // dispatch new-style var match = m_dispatcher2.Dispatch(info.Route, info.Verb, info.Query); if (match == null) { Task.Factory.StartNew(delegate { context.SendReply(s_notFoundReply, HttpStatusCode.NotFound); }); } else { Task.Factory.StartNew(delegate { match.Handler(info); }); } } } catch (Exception e) { // catch all - the server loop must not end // [ISSUE 20080715 sm> handle case when the thread itself dies // -> has to be resurrected by the kernel Report.Line(4, "HttpServer: {0}", e.ToString()); Thread.Sleep(100); } } m_stop = false; lock (m_lock) m_isRunning = false; }); } private static readonly string s_notFoundReply = new XElement("html", new XElement("body", new XElement("div", "Not found!"), new XElement("br"), new XElement("div", "Copyright (c) 2008-2017. Aardvark Platform Team.") ) ) .ToString(); private void ReportRequestProperties(HttpListenerRequest request) { Report.Begin(4, "Request"); // Display the MIME types that can be used in the response. string[] types = request.AcceptTypes; if (types != null) { Report.Begin(4, "acceptable mime types"); foreach (string s in types) { Report.Line(4, "{0}", s); } Report.End(); } // Display the language preferences for the response. types = request.UserLanguages; if (types != null) { Report.Begin(4, "acceptable natural languages"); foreach (string l in types) { Report.Line(4, "{0}", l); } Report.End(); } Report.Begin(4, "query"); foreach (var x in request.QueryString.AllKeys) { Report.Line(4, "{0} = {1}", x.ToString(), request.QueryString[x].ToString()); } Report.End(); Report.Line(4, "url : {0}", request.Url.OriginalString); Report.Line(4, "raw url : {0}", request.RawUrl); Report.Line(4, "referred by : {0}", request.UrlReferrer); Report.Line(4, "http method : {0}", request.HttpMethod); Report.Line(4, "host name : {0}", request.UserHostName); Report.Line(4, "host address: {0}", request.UserHostAddress); Report.Line(4, "user agent : {0}", request.UserAgent); Report.End(); } } public static class WebReponseExtensions { public static string GetResponseAsString(this WebResponse response) { return new StreamReader(response.GetResponseStream()).ReadToEnd(); } public static byte[] GetResponseAsBytes(this WebResponse response) { return new BinaryReader(response.GetResponseStream()).ReadBytes( (int)response.ContentLength ); } } public static class HttpListenerContextExtensions { public static void SendReply(this HttpListenerContext context) { SendReply(context, "", HttpStatusCode.OK); } public static void SendReply(this HttpListenerContext context, string message) { SendReply(context, message, HttpStatusCode.OK); } public static void SendReply(this HttpListenerContext context, string message, HttpStatusCode httpStatusCode) { context.Response.ContentLength64 = Encoding.UTF8.GetByteCount(message); context.Response.StatusCode = (int)httpStatusCode; using (var s = context.Response.OutputStream) { using (var writer = new StreamWriter(s)) { writer.Write(message); } } } public static void SendReply(this HttpListenerContext context, byte[] message) { SendReply(context, message, HttpStatusCode.OK); } public static void SendReply(this HttpListenerContext context, byte[] message, HttpStatusCode httpStatusCode) { context.Response.ContentLength64 = message.Length; context.Response.StatusCode = (int)httpStatusCode; using (var s = context.Response.OutputStream) { s.Write(message, 0, message.Length); } } } public static class Screenshot { public static string CreateImageDesktopFilename() { var now = DateTime.Now; return Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.Desktop), string.Format( "screenshot_{0:0000}{1:00}{2:00}_{3:00}{4:00}{5:00}.png", now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second ) ); } public static string CreateScreenShotFilePath(string path) { var now = DateTime.Now; return Path.Combine( path, string.Format( "screenshot_{0:0000}{1:00}{2:00}_{3:00}{4:00}{5:00}.png", now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second ) ); } /// /// Saves the image to a file on the desktop. /// public static void SaveToDesktop(PixImage image) { SaveToFile(image, CreateImageDesktopFilename()); } public static void SaveToFileInPath(PixImage image, string path) { SaveToFile(image, CreateScreenShotFilePath(path)); } /// /// Saves the image to a given filename. /// public static void SaveToFile(PixImage image, string fileName) { image.Save(fileName, PixFileFormat.Png); Report.Line(5, "saved screenshot: {0}", fileName); } public static string UploadImageDataToServer(MemoryStream stream, string tags) { try { var data = stream.ToArray(); var response = Http.Post( "http://tracker.vrvis.lan:4242/Screenshots", "image/png", data); //"http://localhost:4242/Screenshots", "image/png", data); var key = response.GetResponseAsString(); Report.Line("uploaded screenshot to server"); Report.Line("tags: {0}", tags); Http.Post(String.Format( "http://tracker.vrvis.lan:4242/ScreenshotTag?screenshotUri={0}", Path.GetFileName(key)), //"http://localhost:4242/ScreenshotTag?screenshotUri={0}", Path.GetFileName(key)), "text/xml", tags); return key; } catch (Exception e) { // fail (almost) silently if upload does not work Report.Line("screenshot upload failed: {0}", e.ToString()); return null; } } /// /// Starts the image upload and returns an image key which /// is generated by the server to identify the image. /// public static string UploadImageToServer(PixImage image, string tags = null) { try { using (var stream = new MemoryStream()) { image.Save(stream, PixFileFormat.Png); tags = tags ?? Environment.UserName + " " + Assembly.GetEntryAssembly().GetName().Name; tags = "aardvark.rendering " + tags; return UploadImageDataToServer(stream, tags); } } catch (Exception e) { // fail (almost) silently if upload does not work Report.Line("screenshot upload failed: {0}", e.ToString()); return null; } } /// /// Uploads the meta information, which is stored in an XElement hierarchy /// to the server. /// public static void UploadMetaInfoToServer(XElement metaInfo) { try { byte[] data; using (var stream = new MemoryStream()) { var streamWriter = new StreamWriter(stream); metaInfo.Save(streamWriter); data = stream.ToArray(); } Http.Post("http://tracker.vrvis.lan:4242/ScreenshotInfo", "text/xml", data); Report.Line("uploaded meta info to server"); } catch (Exception e) { // fail (almost) silently if upload does not work Report.Line("metainfo upload failed: {0}", e.ToString()); } } private static XElement BuildCompleteMetaInfo(XElement metaDataFromForm, string imageKey, PixImage image) { string[] parts = imageKey.Split('\\'); string fileName = parts[3]; var created = DateTime.Now; var thumbFileName = fileName + ".thumb.jpg"; //var infoFileName = fileName + ".xml"; var size = image.Size; var metaInfo = new XElement("ScreenshotInfo", new XAttribute("Created", created.ToString()), new XElement("FileName", fileName), new XElement("ThumbFileName", thumbFileName), new XElement("Size", size.ToString()), new XElement("Tag", "", new XAttribute("Created", created.ToString())), new XElement("Tag", metaDataFromForm.Element("Tag").Value, new XAttribute("Created", created.ToString())), new XElement("Kategorie", "", new XAttribute("Created", created.ToString())), new XElement("Kategorie", metaDataFromForm.Element("Kategorie").Value, new XAttribute("Created", created.ToString())), new XElement("Comment", "Screenshot erstellt", new XAttribute("Created", created.ToString())), new XElement("Comment", metaDataFromForm.Element("Comment").Value, new XAttribute("Created", created.ToString())) ); return metaInfo; } public static void SaveAndUpload(PixImage image, bool uploadToServer, string tags = null) { // need to clone the image; original will be disposed afterwards Task.Factory.StartNew(delegate { // 1. save file locally SaveToDesktop(image); // 2. upload if (uploadToServer) { UploadImageToServer(image, tags); } } //, Kernel.TaskManager.CpuBoundLowPriority ); } } } ================================================ FILE: src/Aardvark.Base.Essentials/System/Awaitable.cs ================================================ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace Aardvark.Base { /// /// Represents an awaitable with clear-push semantics. /// Since Task/TaskCompletionSource are likely to spawn new threads /// and execute the respective continuations on haphazardous threads /// we implemeted our own awaitable executing all continuations on /// the thread which they were triggered on. /// public class Awaitable : IAwaitable, IEventEmitter { private int m_isCompleted; private List m_continuations; private SpinLock m_continuationLock; private CancellationToken? m_ct; private CancellationTokenRegistration m_ctRegistration; private readonly Awaiter m_awaiter; #region Constructors /// /// public Awaitable(CancellationToken? ct = null) { m_isCompleted = 0; m_continuations = new List(); m_continuationLock = new SpinLock(); m_ct = ct; if (m_ct.HasValue) { if (m_ct.Value.CanBeCanceled) { m_ctRegistration = m_ct.Value.Register(Emit); } } m_awaiter = new Awaiter(this); } #endregion #region Properties /// /// public bool IsCompleted { get { return m_isCompleted == 1; } } #endregion #region Methods /// /// public void Emit() { var old = Interlocked.Exchange(ref m_isCompleted, 1); if (old == 0) { //If the Awaitable has a CancellationToken release the registration if (m_ct.HasValue) m_ctRegistration.Dispose(); List actions = null; bool taken = false; try { m_continuationLock.Enter(ref taken); actions = m_continuations; m_continuations = null; } finally { if (taken) m_continuationLock.Exit(); } if (actions != null) { var acts = Interlocked.Exchange(ref actions, new List()); foreach (var c in acts) { try { c(); } catch { } } } } } /// /// public void Emit(Unit value) { Emit(); } /// /// public void Subscribe(Action continuation) { bool execute = false; bool taken = false; try { m_continuationLock.Enter(ref taken); if (m_isCompleted == 1) execute = true; else m_continuations.Add(continuation); } finally { if (taken) m_continuationLock.Exit(); } if (execute) continuation(); } #endregion #region IAwaitable Members /// /// public IAwaiter GetAwaiter() { return m_awaiter; } #endregion private readonly struct Awaiter : IAwaiter { private readonly Awaitable m_source; #region Constructors public Awaiter(Awaitable source) { m_source = source; } #endregion #region IAwaiter Members public bool IsCompleted { get { return m_source.m_isCompleted == 1; } } public void GetResult() { //since we're here in the waiting code again the exception will occur where expected if (m_source.m_ct.HasValue && m_source.m_ct.Value.IsCancellationRequested) throw new TaskCanceledException(); } public void OnCompleted(Action continuation) { m_source.Subscribe(continuation); } #endregion } } /// /// Represents an awaitable with clear-push semantics. /// Since Task/TaskCompletionSource are likely to spawn new threads /// and execute the respective continuations on haphazardous threads /// we implemeted our own awaitable executing all continuations on /// the thread which they were triggered on. /// public class Awaitable : IAwaitable, IEventEmitter { private int m_isCompleted; private T m_result; private List m_continuations; private SpinLock m_continuationLock; private CancellationToken? m_ct; private CancellationTokenRegistration m_ctRegistration; private readonly Awaiter m_awaiter; private ManualResetEventSlim m_onPush = null; #region Constructors /// /// public Awaitable(CancellationToken? ct = null) { m_isCompleted = 0; m_result = default(T); m_continuations = new List(); m_continuationLock = new SpinLock(); m_ct = ct; if (m_ct.HasValue) { if (m_ct.Value.CanBeCanceled) { m_ctRegistration = m_ct.Value.Register(() => Emit(default(T))); } } m_awaiter = new Awaiter(this); } #endregion #region Properties /// /// public bool IsCompleted { get { return m_isCompleted == 1; } } /// /// public T Result { get { if (m_isCompleted == 1) return m_result; else { if (m_onPush == null) { Interlocked.CompareExchange(ref m_onPush, new ManualResetEventSlim(), null); } m_onPush.Wait(); return m_result; } } } #endregion #region Methods /// /// public void Emit(T value) { var old = Interlocked.Exchange(ref m_isCompleted, 1); if (old == 0) { m_result = value; //If the Awaitable has a CancellationToken release the registration if (m_ct.HasValue) m_ctRegistration.Dispose(); List actions = null; bool taken = false; try { m_continuationLock.Enter(ref taken); actions = m_continuations; m_continuations = null; } finally { if (taken) m_continuationLock.Exit(); } if (actions != null) { //Run all registered Continuations var acts = Interlocked.Exchange(ref actions, new List()); foreach (var c in acts) { try { c(); } catch { } } } if (m_onPush != null) { m_onPush.Set(); m_onPush = null; } } } /// /// public void Subscribe(Action continuation) { bool execute = false; bool taken = false; try { m_continuationLock.Enter(ref taken); if (m_isCompleted == 1) execute = true; else m_continuations.Add(continuation); } finally { if (taken) m_continuationLock.Exit(); } if (execute) continuation(); } /// /// public void Subscribe(Action continuation) { if (m_isCompleted == 1) { Report.Warn("awaiting already completed Awaitable"); continuation(m_result); } else { bool taken = false; try { m_continuationLock.Enter(ref taken); m_continuations.Add(() => continuation(m_result)); } finally { if (taken) m_continuationLock.Exit(); } } } #endregion #region IAwaitable Members /// /// public IAwaiter GetAwaiter() { return m_awaiter; } IAwaiter IAwaitable.GetAwaiter() { return m_awaiter; } #endregion #region IEventEmitter /// /// public void Emit() { Emit(default(T)); } #endregion private readonly struct Awaiter : IAwaiter { private readonly Awaitable m_source; #region Constructors public Awaiter(Awaitable source) { m_source = source; } #endregion #region IAwaiter Members public bool IsCompleted { get { return m_source.m_isCompleted == 1; } } public T GetResult() { //since we're here in the waiting code again the exception will occur where expected if (m_source.m_ct.HasValue && m_source.m_ct.Value.IsCancellationRequested) throw new TaskCanceledException(); return m_source.m_result; } public void OnCompleted(Action continuation) { m_source.Subscribe(continuation); } void IAwaiter.GetResult() { //since we're here in the waiting code again the exception will occur where expected if (m_source.m_ct.HasValue) m_source.m_ct.Value.ThrowIfCancellationRequested(); } #endregion } } /// /// Contains various combinators for Awaitables (e.g. WhenAny, WhenAll, WithCancellation) since the Task-combinators cannot be used for Awaitables. /// public static class Await { /// /// public static readonly Clock GlobalClock = new Clock(120); #region WithCancellation /// /// Creates a task that completes (or cancels) when either the input task completes or the cancellation token is signalled. /// On cancellation, the original task still runs to completion because there is no way to preemptively cancel it. /// public static IAwaitable WithCancellation(this IAwaitable input, CancellationToken ct) { var result = new Awaitable(ct); input.Subscribe(v => result.Emit(v)); return result; } /// /// Creates a task that completes (or cancels) when either the input task completes or the cancellation token is signalled. /// On cancellation, the original task still runs to completion because there is no way to preemptively cancel it. /// public static IAwaitable WithCancellation(this IAwaitable input, CancellationToken ct) { var result = new Awaitable(ct); input.Subscribe(() => result.Emit()); return result; } #endregion #region WhenAny /// /// Creates a task that will complete when any of the supplied tasks have completed. /// public static IAwaitable WhenAny(params IAwaitable[] inputs) { var result = new Awaitable(); foreach (var i in inputs) { i.Subscribe(() => { if (!result.IsCompleted) result.Emit(i); }); } return result; } /// /// Creates a task that will complete when any of the supplied tasks have completed. /// public static IAwaitable> WhenAny(params IAwaitable[] inputs) { var result = new Awaitable>(); foreach (var i in inputs) { i.Subscribe(v => { if (!result.IsCompleted) result.Emit(i); }); } return result; } #endregion #region WhenAll /// /// Creates a task that will complete when all of the supplied tasks have completed. /// public static IAwaitable WhenAll(params IAwaitable[] inputs) { var result = new Awaitable(); var set = new HashSet>(inputs); var output = new T[inputs.Length]; var i = 0; foreach (var input in set) { var index = i; var ip = input; ip.Subscribe(v => { output[index] = v; if (set.Remove(ip) && set.Count == 0) { if (!result.IsCompleted) result.Emit(output); } }); i++; } return result; } /// /// Creates a task that will complete when all of the supplied tasks have completed. /// public static IAwaitable WhenAll(params IAwaitable[] inputs) { var result = new Awaitable(); var set = new HashSet(inputs); foreach (var input in set) { var ip = input; ip.Subscribe(() => { if (set.Remove(ip) && set.Count == 0) { if (!result.IsCompleted) result.Emit(); } }); } return result; } #endregion #region Select /// /// Projects the result of the task into a new form. /// public static IAwaitable Select(this IAwaitable input, Func f) { var result = new Awaitable(); input.Subscribe(v => result.Emit(f(v))); return result; } /// /// Projects the result of the task into a new form. /// public static IAwaitable Select(this IAwaitable input, Func f) { var result = new Awaitable(); input.Subscribe(() => result.Emit(f())); return result; } #endregion #region ContinueWith /// /// Creates a continuation that executes when the target task completes. /// public static IAwaitable ContinueWith(this IAwaitable awaitable, Func fun) { var result = new Awaitable(); awaitable.Subscribe(v => { result.Emit(fun(v)); }); return result; } /// /// Creates a continuation that executes when the target task completes. /// public static IAwaitable ContinueWith(this IAwaitable awaitable, Action action) { var result = new Awaitable(); awaitable.Subscribe(v => { action(v); result.Emit(); }); return result; } /// /// Creates a continuation that executes when the target task completes. /// public static IAwaitable ContinueWith(this IAwaitable awaitable, Func fun) { var result = new Awaitable(); awaitable.Subscribe(() => { result.Emit(fun()); }); return result; } /// /// Creates a continuation that executes when the target task completes. /// public static IAwaitable ContinueWith(this IAwaitable awaitable, Action fun) { var result = new Awaitable(); awaitable.Subscribe(() => { fun(); result.Emit(); }); return result; } #endregion #region Delay /// /// Creates a task that will complete after a time delay. /// public static IAwaitable Delay(uint milliseconds, CancellationToken ct) { return GlobalClock.Future((int)milliseconds).WithCancellation(ct); } /// /// Creates a task that will complete after a time delay. /// public static IAwaitable Delay(uint milliseconds) { return GlobalClock.Future((int)milliseconds); } /// /// Creates a task that will complete after a time delay. /// public static IAwaitable Delay(TimeSpan delay, CancellationToken ct) { return Delay((uint)delay.TotalMilliseconds, ct); } /// /// Creates a task that will complete after a time delay. /// public static IAwaitable Delay(TimeSpan delay) { return Delay((uint)delay.TotalMilliseconds); } /// /// Creates a task that will complete after the shortest possible time delay. /// public static IAwaitable Tick { get { return GlobalClock.Tick(); } } #endregion } /// /// public static class AwaitableTest { static async void Run(Awaitable a, Awaitable b, CancellationToken ct) { try { var i = await Await.WhenAny(a, b).WithCancellation(ct); Console.WriteLine("got: {0}", i); } catch (OperationCanceledException) { Report.Line("cancelled"); } } /// /// public static void Run() { var c = new CancellationTokenSource(); var ct = c.Token; var a = new Awaitable(); var b = new Awaitable(); Run(a, b, ct); //c.Cancel(); a.Emit(1); b.Emit(2); Console.ReadLine(); } } /// /// public class TaskAwaiter : IAwaiter { private System.Runtime.CompilerServices.TaskAwaiter m_awaiter; /// /// public TaskAwaiter(System.Runtime.CompilerServices.TaskAwaiter awaiter) { m_awaiter = awaiter; } /// /// public void OnCompleted(Action continuation) { m_awaiter.OnCompleted(continuation); } /// /// public bool IsCompleted { get { return m_awaiter.IsCompleted; } } /// /// public T GetResult() { return m_awaiter.GetResult(); } /// /// void IAwaiter.GetResult() { m_awaiter.GetResult(); } } /// /// public class TaskAwaiter : IAwaiter { private System.Runtime.CompilerServices.TaskAwaiter m_awaiter; /// /// public TaskAwaiter(System.Runtime.CompilerServices.TaskAwaiter awaiter) { m_awaiter = awaiter; } /// /// public void OnCompleted(Action continuation) { m_awaiter.OnCompleted(continuation); } /// /// public bool IsCompleted { get { return m_awaiter.IsCompleted; } } void IAwaiter.GetResult() { m_awaiter.GetResult(); } } /// /// public class TaskAwaitable : IAwaitable { private readonly Task m_task; /// /// public TaskAwaitable(Task task) { m_task = task; } /// /// public IAwaiter GetAwaiter() { return new TaskAwaiter(m_task.GetAwaiter()); } /// /// public T Result { get { return m_task.Result; } } /// /// IAwaiter IAwaitable.GetAwaiter() { return new TaskAwaiter(m_task.GetAwaiter()); } /// /// public bool IsCompleted { get { return m_task.IsCompleted; } } } /// /// public class TaskAwaitable : IAwaitable { private readonly Task m_task; /// /// public TaskAwaitable(Task task) { m_task = task; } /// /// public IAwaiter GetAwaiter() { return new TaskAwaiter(m_task.GetAwaiter()); } bool IAwaitable.IsCompleted { get { return m_task.IsCompleted; } } } /// /// public static class TaskAwaitableExtensions { /// /// public static TaskAwaitable AsAwaitable(this Task task) { return new TaskAwaitable(task); } /// /// public static TaskAwaitable AsAwaitable(this Task task) { return new TaskAwaitable(task); } } } ================================================ FILE: src/Aardvark.Base.Essentials/System/Clock.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; namespace Aardvark.Base { /// /// public class Clock : IDisposable { private Task m_timeThread; private List m_waiters; private object m_queueLock; private SemaphoreSlim m_waitersEnqueued; private int m_frequency; private int m_minimalUpdateTime; private CancellationTokenSource m_source; private readonly Dictionary m_lastTime; #region Constructors /// /// public Clock(int maxUpdateFrequency = 0) { m_waiters = new List(); m_queueLock = new object(); m_waitersEnqueued = new SemaphoreSlim(0); m_frequency = maxUpdateFrequency; m_minimalUpdateTime = m_frequency == 0 ? 0 : (int)(1000.0 / (double)m_frequency); m_source = new CancellationTokenSource(); m_lastTime = new Dictionary(); m_timeThread = new Task(Run, TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler); //m_timeThread.Priority = ThreadPriority.Highest; //m_timeThread.Name = "ClockThread"; //m_timeThread.IsBackground = true; m_timeThread.Start(); } #endregion #region Properties /// /// public int MaximalFrequency { get { return m_frequency; } set { m_frequency = value; m_minimalUpdateTime = m_frequency == 0 ? 0 : (int)(1000.0 / (double)m_frequency); } } /// /// public int MinimalUpdateTime { get { return m_minimalUpdateTime; } } /// /// public TimeSpan GetTimeSpanForContinuation(Action continuation, out DateTime now) { var current = DateTime.Now; DateTime last; if (!m_lastTime.TryGetValue(continuation, out last)) { last = current; m_lastTime[continuation] = last; } m_lastTime[continuation] = current; now = current; return current - last; } #endregion #region Methods /// /// public void Enqueue(Action a) { lock (m_queueLock) { m_waiters.Add(a); m_waitersEnqueued.Release(); } } private void Run() { var w = new Stopwatch(); var token = m_source.Token; try { while (true) { w.Stop(); m_waitersEnqueued.Wait(); token.ThrowIfCancellationRequested(); var wait = System.Math.Max(0, m_minimalUpdateTime - (int)w.Elapsed.TotalMilliseconds); if (wait > 0) Thread.Sleep(wait); token.ThrowIfCancellationRequested(); w.Restart(); List current = null; lock (m_queueLock) { current = m_waiters; m_waiters = new List(); } for (int i = 1; i < current.Count; i++) m_waitersEnqueued.Wait(); foreach (var a in current) { a(); } token.ThrowIfCancellationRequested(); } } catch (OperationCanceledException) { Report.Warn("clock cancelled"); } catch (Exception e) { Report.Warn("clock faulted: {0}", e); } } #endregion #region IDisposable Members /// /// public void Dispose() { if (m_timeThread != null) { m_source.Cancel(); m_waitersEnqueued.Release(); m_timeThread.Wait(); m_timeThread = null; m_waiters = null; m_queueLock = null; m_waitersEnqueued = null; m_frequency = 0; m_minimalUpdateTime = 0; m_source = null; } } #endregion } /// /// public static class ClockExtensions { /// /// public static double SanityThreshold = 10; #region Awaitable private struct FutureAwaiter : IAwaiter { private readonly FutureAwaitable m_future; private Action m_continuation; public FutureAwaiter(FutureAwaitable f) { m_future = f; m_continuation = null; } public bool IsCompleted { get { return false; } } private void MakeSane(ref TimeSpan span) { if (m_future.TimeOut > 0) { var cap = SanityThreshold * m_future.TimeOut; if (span.TotalMilliseconds > cap) span = TimeSpan.FromMilliseconds(cap); } else if (m_future.Clock.MinimalUpdateTime != 0) { var cap = SanityThreshold * m_future.Clock.MinimalUpdateTime; if (span.TotalMilliseconds > SanityThreshold * m_future.Clock.MinimalUpdateTime) span = TimeSpan.FromMilliseconds(cap); } } public TimeValue GetResult() { DateTime current; var span = m_future.Clock.GetTimeSpanForContinuation(m_continuation, out current); MakeSane(ref span); return new TimeValue(current, span.TotalSeconds); } public void OnCompleted(Action continuation) { m_continuation = continuation; var timeOut = m_future.TimeOut; if (timeOut == 0) { m_future.Clock.Enqueue(continuation); } else { var time = m_future.Clock; Task.Factory.StartNew(() => { Thread.Sleep(timeOut); time.Enqueue(continuation); }); } } void IAwaiter.GetResult() { DateTime current; m_future.Clock.GetTimeSpanForContinuation(m_continuation, out current); } } private class FutureAwaitable : IAwaitable { private readonly Clock m_time; private readonly int m_timeOut; public FutureAwaitable(Clock time, int timeout = 0) { m_time = time; m_timeOut = timeout; } public int TimeOut { get { return m_timeOut; } } public Clock Clock { get { return m_time; } } public IAwaiter GetAwaiter() { return new FutureAwaiter(this); } IAwaiter IAwaitable.GetAwaiter() { return new FutureAwaiter(this); } public TimeValue Result { get { throw new NotSupportedException(); } } public bool IsCompleted { get { return false; } } } #endregion #region Extensions /// /// Awaits a time being approximately "timeout" milliseconds in the future. /// If timeout is zero the maximal clock frequency limits the execution. /// public static IAwaitable Future(this Clock clock, int timeoutInMilliSeconds = 0) { return new FutureAwaitable(clock, timeoutInMilliSeconds); } /// /// public static IAwaitable Tick(this Clock clock) { return new FutureAwaitable(clock, 0); } /// /// public static IEvent TickEvent(this Clock clock) { var evt = new EventSource(0.0); var w = new Stopwatch(); w.Start(); Action a = null; a = () => { evt.Emit(w.Elapsed.TotalSeconds); //w.Restart(); clock.Enqueue(a); }; clock.Enqueue(a); return evt; } #endregion } } ================================================ FILE: src/Aardvark.Base.Essentials/System/Disposable.cs ================================================ using System; using System.Collections.Generic; namespace Aardvark.Base { /// /// public static class IDisposableExtensions { /// /// Calls Dispose() and returns true if not null, /// returns false otherwise. /// public static bool TryDispose(this IDisposable self) { if (self == null) return false; self.Dispose(); return true; } /// /// Checks if the objects impelemtns the IDisposable interface, /// performs Dispose() in case and returns true, otherwise false. /// public static bool TryDispose(this object obj) { var d = obj as IDisposable; if (d == null) return false; d.Dispose(); return true; } /// /// Disposes a sequence of IDisposables. /// public static void DisposeAll(this IEnumerable disposables) { foreach (var d in disposables) d.Dispose(); } /// /// Disposes a list of IDisposables. /// public static void DisposeAll(this List disposables) { foreach (var d in disposables) d.Dispose(); } /// /// Disposes an array of IDisposables. /// public static void DisposeAll(this IDisposable[] disposables) { foreach (var d in disposables) d.Dispose(); } /// /// Disposes all valid disposables of a sequence. /// public static void TryDisposeAll(this IEnumerable disposables) { disposables.WhereNotNull().ForEach(x => x.Dispose()); } /// /// Disposes all disposables in a collections and clears the collection afterwards. /// public static void DisposeAllAndClear(this ICollection disposables) { if (disposables.IsReadOnly) throw new Exception("The collection is read-only... it cannot be cleared."); foreach (var d in disposables) d.Dispose(); disposables.Clear(); } /// /// Disposes all disposables in the list and clears it afterwards. /// public static void DisposeAllAndClear(this List disposables) { foreach (var d in disposables) d.Dispose(); disposables.Clear(); } } /// /// public static class Try { /// /// Disposes the Disposable if not null and sets its reference to null. /// NOTE: needs to be generic since refs somehow do not work with interfaces. /// public static void Dispose(ref T x) where T : IDisposable { if (x != null) { x.Dispose(); x = default(T); } } } } ================================================ FILE: src/Aardvark.Base.Essentials/System/EventSource.cs ================================================ using System; using System.Threading; namespace Aardvark.Base { public class EventSourceSlim : IEvent { private readonly Subject m_subject; private Awaitable m_awaitable; private T m_latest; public EventSourceSlim(T defaultValue) { m_subject = new Subject(); m_awaitable = new Awaitable(); m_latest = defaultValue; } public void Emit(T v) { lock(this) { var currentAwaitable = m_awaitable; m_awaitable = new Awaitable(); m_latest = v; currentAwaitable.Emit(v); m_subject.OnNext(v); } } public T Latest { get { lock(this) { return m_latest; } } } public IAwaitable Next { get { lock(this) { return m_awaitable; } } } public IObservable Values { get { return m_subject; } } IAwaitable IEvent.Next { get { return Next; } } IObservable IEvent.Values { get { return new MapObservable(Values, _ => Unit.Default); } } } /// /// public static class EventSource { /// /// The type used for the Values property in non-generic event sources. /// public static readonly Type UnitEventType = typeof(Unit); /// /// Creates new EventSource with given initial value. /// public static EventSource Create(T initialValue) { return new EventSource(initialValue); } /// /// Creates new EventSource with tuple of given initial values. /// public static EventSource> Create(T0 initialValue0, T1 initialValue1) { return new EventSource>(Tuple.Create(initialValue0, initialValue1)); } /// /// Creates new EventSource with tuple of given initial values. /// public static EventSource> Create(T0 initialValue0, T1 initialValue1, T2 initialValue2) { return new EventSource>(Tuple.Create(initialValue0, initialValue1, initialValue2)); } /// /// Creates new EventSource with tuple of given initial values. /// public static EventSource> Create(T0 initialValue0, T1 initialValue1, T2 initialValue2, T3 initialValue3) { return new EventSource>(Tuple.Create(initialValue0, initialValue1, initialValue2, initialValue3)); } /// /// Creates new EventSource with tuple of given initial values. /// public static EventSource> Create(T0 initialValue0, T1 initialValue1, T2 initialValue2, T3 initialValue3, T4 initialValue4) { return new EventSource>(Tuple.Create(initialValue0, initialValue1, initialValue2, initialValue3, initialValue4)); } } /// /// public class EventSource : IEvent, IEventEmitter { private readonly ThreadLocal m_currentThreadDoesNotOwnLock = new ThreadLocal(() => true); private SpinLock m_lock = new SpinLock(true); private T m_latest; private Awaitable m_awaitable = new Awaitable(); private readonly Lazy> m_eventStream = new Lazy>(); /// /// Creates an EventSource with default initial value. /// public EventSource() { EventSourceTelemetry.CountConstructorDefault.Increment(); } /// /// Creates a new EventSource with specified initial value. /// public EventSource(T initialValue) { EventSourceTelemetry.CountConstructorInitialValue.Increment(); m_latest = initialValue; } /// /// Wraps an observable as an event source. /// public EventSource(IObservable fromObservable) { EventSourceTelemetry.CountConstructorFromObservable.Increment(); fromObservable.Subscribe(new LambdaObserver(x => Emit(x))); } /// /// Wraps an observable as an event source and sets its initial value. /// public EventSource(T initialValue, IObservable fromObservable) { m_latest = initialValue; EventSourceTelemetry.CountConstructorInitialValue.Increment(); EventSourceTelemetry.CountConstructorFromObservable.Increment(); fromObservable.Subscribe(new LambdaObserver(x => Emit(x))); } /// /// Gets latest value emitted by this event source, /// or default(T) if no value has been emitted so far. /// Do not set this value! Unless you have multiple /// related event sources you want to 'update' /// simultanously. In this case first set Latest for /// all related event sources to their respective new /// value, and then Emit the same values. A subscriber /// of such an event source which accesses the Latest /// property of a related event source then sees the /// correct value (independent of emit order). /// public T Latest { get { EventSourceTelemetry.CountLatestGet.Increment(); return m_latest; } set { m_latest = value; } } /// /// Gets next value that will be emitted by this event source. /// public IAwaitable Next { get { EventSourceTelemetry.CountNextGet.Increment(); bool lockTaken = false; try { if (m_currentThreadDoesNotOwnLock.Value) { m_lock.Enter(ref lockTaken); m_currentThreadDoesNotOwnLock.Value = false; } return m_awaitable; } finally { if (lockTaken) { m_currentThreadDoesNotOwnLock.Value = true; m_lock.Exit(true); } } } } /// /// Gets observable stream of values emitted by this event source. /// public IObservable Values { get { EventSourceTelemetry.CountValuesGet.Increment(); return m_eventStream.Value; } } /// /// Emits given value from this event source. /// public virtual void Emit(T value) { EventSourceTelemetry.CountEmit.Increment(); bool lockTaken = false; try { if (m_currentThreadDoesNotOwnLock.Value) { m_currentThreadDoesNotOwnLock.Value = false; m_lock.Enter(ref lockTaken); } var currentAwaitable = m_awaitable; // update Latest and Next // (before emitting, such that a listener immediately coming back to us already sees the updated state) m_awaitable = new Awaitable(); m_latest = value; // emit value currentAwaitable.Emit(value); if (m_eventStream.IsValueCreated) m_eventStream.Value.OnNext(value); } finally { if (lockTaken) { m_currentThreadDoesNotOwnLock.Value = true; m_lock.Exit(true); } } } #region IEvent /// /// Observable notifications for all values that are emitted. /// IObservable IEvent.Values { get { return new MapObservable(Values, _ => Unit.Default); } } IAwaitable IEvent.Next { get { return Next; } } #endregion #region IEventEmitter /// /// Emits default T. /// public void Emit() { Emit(default(T)); } #endregion } internal static class EventSourceTelemetry { public static readonly Telemetry.Counter CountConstructorDefault = new Telemetry.Counter(); public static readonly Telemetry.Counter CountConstructorInitialValue = new Telemetry.Counter(); public static readonly Telemetry.Counter CountConstructorFromObservable = new Telemetry.Counter(); public static readonly Telemetry.Counter CountEmit = new Telemetry.Counter(); public static readonly Telemetry.Counter CountNextGet = new Telemetry.Counter(); public static readonly Telemetry.Counter CountLatestGet = new Telemetry.Counter(); public static readonly Telemetry.Counter CountValuesGet = new Telemetry.Counter(); } } ================================================ FILE: src/Aardvark.Base.Essentials/System/EventSourceExtensions.cs ================================================ using System; using System.Threading.Tasks; namespace Aardvark.Base { /// /// public static class EventSourceExtensions { /// /// Wraps an observable as an event source. /// public static EventSource ToEventSource(this IObservable self) { return new EventSource(self); } /// /// Executes action when next value arrives. /// public static void ExecuteOnNextValue(this IEvent self, Action action) { self.Next.ContinueWith(t => action(t)); } /// /// Executes action when next value arrives. /// public static void ExecuteOnNextValue(this IEvent self, Action action) { self.Next.ContinueWith(t => action()); } /// /// Repeats given action until the next value of this event source arrives. /// The optional final action gets called with this newly arrived value. /// public static async Task RepeatUntilNext(this IEvent self, Func action, Func finallyAction = null) { var next = self.Next; while (!next.IsCompleted) { await Await.WhenAny(action().AsAwaitable(), next); } if (finallyAction != null) await finallyAction(next.Result); } /// /// Repeats given action until the task completes. /// The optional final action gets called with the task's result. /// public static async Task RepeatUntilNext(this Task self, Func action, Func finallyAction = null) { while (!self.IsCompleted) { await Task.WhenAny(action(), self); } if (finallyAction != null) await finallyAction(self.Result); } /// /// Repeats given action until the next value of this event source arrives. /// The optional final action gets called with this newly arrived value. /// public static async Task RepeatUntilNext(this IEvent self, Func action, Action finallyAction) { var next = self.Next; while (!next.IsCompleted) { await Await.WhenAny(action().AsAwaitable(), next); } if (finallyAction != null) finallyAction(next.Result); } /// /// Repeats given action until the task completes. /// The optional final action gets called with the task's result. /// public static async Task RepeatUntilNext(this Task self, Func action, Action finallyAction) { while (!self.IsCompleted) { await Task.WhenAny(action(), self); } if (finallyAction != null) finallyAction(self.Result); } /// /// Repeats given action until the given task/awaitable completes. /// The optional final action gets called with the task's result. /// public static async Task RepeatUntilCompleted(this IAwaitable self, Func action, Func finallyAction = null) { while (!self.IsCompleted) { await Await.WhenAny(action().AsAwaitable(), self); } if (finallyAction != null) await finallyAction(self.Result); } /// /// Repeats given action until the given task completes. /// The optional final action gets called with the task's result. /// public static async Task RepeatUntilCompleted(this Task self, Func action, Func finallyAction = null) { while (!self.IsCompleted) { await Task.WhenAny(action(), self); } if (finallyAction != null) await finallyAction(self.Result); } /// /// Repeats given action until the given task/awaitable completes. /// The optional final action gets called with the task's result. /// public static async Task RepeatUntilCompleted(this IAwaitable self, Func action, Action finallyAction) { while (!self.IsCompleted) { await Await.WhenAny(action().AsAwaitable(), self); } if (finallyAction != null) finallyAction(self.Result); } /// /// Repeats given action until the given task completes. /// The optional final action gets called with the task's result. /// public static async Task RepeatUntilCompleted(this Task self, Func action, Action finallyAction) { while (!self.IsCompleted) { await Task.WhenAny(action(), self); } if (finallyAction != null) finallyAction(self.Result); } /// /// Repeats given action until the given task/awaitable completes. /// public static async Task RepeatUntilCompleted(this IAwaitable self, Func action, Func finallyAction = null) { while (!self.IsCompleted) { await Await.WhenAny(action().AsAwaitable(), self); } if (finallyAction != null) await finallyAction(); } /// /// Repeats given action until the given task completes. /// public static async Task RepeatUntilCompleted(this Task self, Func action, Func finallyAction = null) { while (!self.IsCompleted) { await Task.WhenAny(action(), self); } if (finallyAction != null) await finallyAction(); } /// /// Repeats given action until the given task/awaitable completes. /// public static async Task RepeatUntilCompleted(this IAwaitable self, Func action, Action finallyAction) { while (!self.IsCompleted) { await Await.WhenAny(action().AsAwaitable(), self); } if (finallyAction != null) finallyAction(); } /// /// Repeats given action until the given task completes. /// public static async Task RepeatUntilCompleted(this Task self, Func action, Action finallyAction) { while (!self.IsCompleted) { await Task.WhenAny(action(), self); } if (finallyAction != null) finallyAction(); } } } ================================================ FILE: src/Aardvark.Base.Essentials/System/EventSourceInterfaces.cs ================================================ using System; namespace Aardvark.Base { /// /// The receiving side of an event source. /// public interface IEvent : IEvent { /// /// The latest value that has been emitted. /// This will return default(T) if no value has been emitted yet. /// T Latest { get; } /// /// The next value that will be emitted. /// new IAwaitable Next { get; } /// /// Observable sequence of emitted values. /// new IObservable Values { get; } } /// /// The sending side of an event source. /// public interface IEventEmitter : IEventEmitter { /// /// Pushes next event value. /// void Emit(T value); } /// /// The receiving side of an event source. /// public interface IEvent { /// /// The next value that will be emitted. /// IAwaitable Next { get; } /// /// Observable notifications for all values that are emitted. /// IObservable Values { get; } } /// /// The sending side of an event source. /// public interface IEventEmitter { /// /// Pushes next event. /// void Emit(); } } ================================================ FILE: src/Aardvark.Base.Essentials/System/EventSourceSpecials.cs ================================================ using System; namespace Aardvark.Base { /// /// public class ConstEventSource { /// /// Creates new ConstEventSource with given value. /// public static ConstEventSource Create(T value) { return new ConstEventSource(value); } /// /// Creates new ConstEventSource with tuple of given values. /// public static ConstEventSource> Create(T0 initialValue0, T1 initialValue1) { return new ConstEventSource>(Tuple.Create(initialValue0, initialValue1)); } /// /// Creates new ConstEventSource with tuple of given values. /// public static ConstEventSource> Create(T0 initialValue0, T1 initialValue1, T2 initialValue2) { return new ConstEventSource>(Tuple.Create(initialValue0, initialValue1, initialValue2)); } /// /// Creates new ConstEventSource with tuple of given values. /// public static ConstEventSource> Create(T0 initialValue0, T1 initialValue1, T2 initialValue2, T3 initialValue3) { return new ConstEventSource>(Tuple.Create(initialValue0, initialValue1, initialValue2, initialValue3)); } /// /// Creates new ConstEventSource with tuple of given values. /// public static ConstEventSource> Create(T0 initialValue0, T1 initialValue1, T2 initialValue2, T3 initialValue3, T4 initialValue4) { return new ConstEventSource>(Tuple.Create(initialValue0, initialValue1, initialValue2, initialValue3, initialValue4)); } } /// /// A ConstEventSource has its initial value and will never emit new values. /// public class ConstEventSource : IEvent { private static readonly Awaitable s_awaitableNonGeneric = new Awaitable(); private static readonly Awaitable s_awaitable = new Awaitable(); private readonly T m_value; /// /// public ConstEventSource(T constValue) { m_value = constValue; } /// /// public T Latest { get { return m_value; } } /// /// public IAwaitable Next { get { return s_awaitable; } } /// /// public IObservable Values { get { return new NeverObservable(); } } IAwaitable IEvent.Next { get { return s_awaitableNonGeneric; } } IObservable IEvent.Values { get { return new NeverObservable(); } } } } ================================================ FILE: src/Aardvark.Base.Essentials/System/FilteredEventSource.cs ================================================ using System; namespace Aardvark.Base { /// /// public class FilteredEventSource : EventSource { private readonly Func m_predicate; /// /// public FilteredEventSource(Func predicate) { if (predicate == null) throw new ArgumentNullException(); m_predicate = predicate; } /// /// public override void Emit(T value) { if (m_predicate(value)) base.Emit(value); } } } ================================================ FILE: src/Aardvark.Base.Essentials/System/IAwaitable.cs ================================================ using System; using System.Runtime.CompilerServices; namespace Aardvark.Base { //These are the interfaces needed to be awaitable (which are not exposed by the .NET) //Here's a little example to make it easier to understand its behaviour. // // Consider the follwing function: // // async void Foo() // { // await x; // Bar(); // } // // Which will be translated to something like (it's actually more complicated but this will give you the basic idea) // Basically all the continuations call Foo itself and Foo contains something like a jump table (at least using the current .NET framework) // // async void Foo() // { // var xAwaiter = x.GetAwaiter(); // if(xAwaiter.IsCompleted) Bar(); // else // { // xAwaiter.OnCompleted(() => // { // xAwaiter.GetResult(); // Bar(); // } // } // } /// /// Represents the required interface for using the async/await syntax. /// every class implementing IAwaitable can be 'awaited' like tasks /// for an awaitable returning a value see IAwaitable[T]. /// public interface IAwaitable { /// /// IAwaiter GetAwaiter(); /// /// bool IsCompleted { get; } } /// /// public interface IAwaiter : INotifyCompletion { /// /// When IsCompleted returns true the the awaiting code will simply keep running without subscribing itself /// bool IsCompleted { get; } /// /// GetResult is always the first function called in the continuation (even for void) /// and is therefore the only point where one can throw exceptions which will occur in user-code /// void GetResult(); } /// /// represents the required interface for using the async/await syntax /// every class implementing IAwaitable can be 'awaited' like tasks /// for an awaitable returning no value see IAwaitable /// public interface IAwaitable : IAwaitable { /// /// new IAwaiter GetAwaiter(); /// /// T Result { get; } } /// /// public interface IAwaiter : INotifyCompletion, IAwaiter { /// /// GetResult is always the first function called in the continuation (even for void) /// and is therefore the only point where one can throw exceptions which will occur in user-code /// new T GetResult(); } /// /// public static class IAwaitableExtensions { /// /// public static void Subscribe(this IAwaitable awaitable, Action action) { var awaiter = awaitable.GetAwaiter(); awaiter.OnCompleted(() => { try { action(awaiter.GetResult()); } catch (OperationCanceledException) { } }); } /// /// public static void Subscribe(this IAwaitable awaitable, Action action) { var awaiter = awaitable.GetAwaiter(); awaiter.OnCompleted(() => { try { awaiter.GetResult(); action(); } catch (OperationCanceledException) { } }); } } } ================================================ FILE: src/Aardvark.Base.Essentials/System/Reactive.cs ================================================ using System; using System.Collections.Generic; using System.Text; namespace Aardvark.Base { public sealed class Unit { private Unit() { } public static Unit Default { get { return null; } } } internal class SubjectDisposable : IDisposable { private Dictionary, int> m_store; private IObserver m_self; public SubjectDisposable(Dictionary, int> store, IObserver self) { m_store = store; m_self = self; } public void Dispose() { if (m_self == null) return; lock(m_store) { if(m_store.TryGetValue(m_self, out var cnt)) { cnt--; if (cnt > 0) m_store[m_self] = cnt; else m_store.Remove(m_self); } m_store = null; m_self = null; } } } internal class Subject : IObservable, IObserver { private readonly Dictionary, int> m_observers; public Subject() { m_observers = new Dictionary, int>(); } public void OnCompleted() { IObserver[] arr = null; lock (m_observers) { arr = m_observers.Keys.ToArray(m_observers.Count); } foreach (var obs in arr) { obs.OnCompleted(); } } public void OnNext(T value) { IObserver[] arr = null; lock (m_observers) { arr = m_observers.Keys.ToArray(m_observers.Count); } foreach (var obs in arr) { obs.OnNext(value); } } public void OnError(Exception e) { IObserver[] arr = null; lock (m_observers) { arr = m_observers.Keys.ToArray(m_observers.Count); } foreach (var obs in arr) { obs.OnError(e); } } public IDisposable Subscribe(IObserver obs) { lock (m_observers) { if(m_observers.TryGetValue(obs, out var cnt)) { m_observers[obs] = cnt + 1; } else { m_observers[obs] = 1; } return new SubjectDisposable(m_observers, obs); } } } internal class LambdaObserver : IObserver { private readonly Action m_action; public LambdaObserver(Action action) { m_action = action; } public void OnNext(T value) { m_action(value); } public void OnCompleted() { } public void OnError(Exception e) { } } internal class MapObserver : IObserver { private readonly Func m_mapping; private readonly IObserver m_target; public MapObserver(IObserver target, Func mapping) { m_mapping = mapping; m_target = target; } public void OnNext(T1 value) { m_target.OnNext(m_mapping(value)); } public void OnCompleted() { m_target.OnCompleted(); } public void OnError(Exception error) { m_target.OnError(error); } } internal class MapObservable : IObservable { private readonly IObservable m_input; private readonly Func m_mapping; public MapObservable(IObservable input, Func mapping) { m_input = input; m_mapping = mapping; } public IDisposable Subscribe(IObserver obs) { return m_input.Subscribe(new MapObserver(obs, m_mapping)); } } internal class NoDisposable : IDisposable { public NoDisposable() { } public void Dispose() {} } internal class NeverObservable : IObservable { public NeverObservable() { } public IDisposable Subscribe(IObserver observer) { return new NoDisposable(); } } } ================================================ FILE: src/Aardvark.Base.Essentials/System/Time.cs ================================================ using System; namespace Aardvark.Base { /// /// public readonly struct TimeValue { /// /// public readonly DateTime T; /// /// public readonly double Delta; #region Constructors /// /// public TimeValue(DateTime t, double delta) { T = t; Delta = delta; } #endregion #region Creators /// /// public static TimeValue Now { get { return new TimeValue(DateTime.Now, 0.0); } } #endregion } } ================================================ FILE: src/Aardvark.Base.Essentials/System/WithCancellationExtension.cs ================================================ using System; using System.Threading; using System.Threading.Tasks; namespace Aardvark.Base { /// /// Implementation based on /// http://blogs.msdn.com/b/dotnet/archive/2013/04/04/net-memory-allocation-profiling-with-visual-studio-2012.aspx /// http://blogs.msdn.com/b/pfxteam/archive/2012/10/05/how-do-i-cancel-non-cancelable-async-operations.aspx /// public static class TaskWithCancellationExtensions { /// /// Creates a task that completes (or cancels) when either the input task completes or the cancellation token is signalled. /// On cancellation, the original task still runs to completion because there is no way to preemptively cancel it. /// public static Task WithCancellation(this Task task, CancellationToken ct) { if (task.IsCompleted || !ct.CanBeCanceled) return task; else if (ct.IsCancellationRequested) return Task.FromCanceled(ct); else return task.WithCancellationInternal(ct); } /// /// Creates a task that completes (or cancels) when either the input task completes or the cancellation token is signalled. /// On cancellation, the original task still runs to completion because there is no way to preemptively cancel it. /// public static Task WithCancellation(this Task task, CancellationToken? ct) { if (task.IsCompleted || !ct.HasValue || !ct.Value.CanBeCanceled) return task; else if (ct.Value.IsCancellationRequested) return Task.FromCanceled(ct.Value); else return task.WithCancellationInternal(ct.Value); } private static readonly Action s_cancellationRegistration = s => ((TaskCompletionSource)s).TrySetResult(true); private static async Task WithCancellationInternal(this Task task, CancellationToken ct) { var tcs = new TaskCompletionSource(); using (ct.Register(s_cancellationRegistration, tcs)) { if (task != await Task.WhenAny(task, tcs.Task)) { throw new TaskCanceledException(task); } } return await task; } } } ================================================ FILE: src/Aardvark.Base.Essentials/paket.references ================================================ Aardvark.Build System.Collections.Immutable ================================================ FILE: src/Aardvark.Base.Essentials/paket.template ================================================ type project id Aardvark.Base.Essentials authors Aardvark Platform Team owners Aardvark Platform Team projectUrl http://github.com/aardvark-platform licenseUrl http://www.apache.org/licenses/LICENSE-2.0.txt repositoryType git repositoryUrl https://github.com/aardvark-platform/aardvark.base description Aardvark is an open-source platform for visual computing, real-time graphics and visualization. include-pdbs true ================================================ FILE: src/Aardvark.Base.FSharp/Aardvark.Base.FSharp.fsproj ================================================  net8.0;netstandard2.0 Aardvark.Base.FSharp Library true true 3389;3390;3395 ..\..\bin\Debug\ ..\..\bin\Release ================================================ FILE: src/Aardvark.Base.FSharp/Ag.fs ================================================ namespace Aardvark.Base open System open System.Runtime.CompilerServices open System.Collections.Generic open Aardvark.Base open System.Reflection open System.Runtime.InteropServices #nowarn "1337" [] type RuleAttribute() = inherit Attribute() [] type CacheSynthesizedAttribute() = inherit Attribute() module Ag = let internal anyObj = obj() let private globalValues = ConditionalWeakTable>() [] module private TypeHelpers = open Microsoft.FSharp.Reflection let private genRx = System.Text.RegularExpressions.Regex @"^([^`]*)`[0-9]+$" let withBrackets (str : string) = if str.Contains " " && not (str.StartsWith "(") then "(" + str + ")" else str let rec prettyName (t : Type) : string = if t.IsByRef then let t = prettyName (t.GetElementType()) sprintf "byref<%s>" t elif t.IsArray then let d = t.GetArrayRank() let t = prettyName (t.GetElementType()) if d = 1 then sprintf "array<%s>" t else sprintf "array%dd<%s>" d t elif FSharpType.IsTuple(t) then let elems = FSharpType.GetTupleElements t |> Seq.map (prettyName >> withBrackets) |> String.concat " * " if t.IsValueType then sprintf "struct(%s)" elems else sprintf "%s" elems elif FSharpType.IsFunction(t) then let a, b = FSharpType.GetFunctionElements t sprintf "%s -> %s" (prettyName a) (prettyName b) elif t.IsGenericType then let def = t.GetGenericTypeDefinition().Name let m = genRx.Match def let clean = if m.Success then m.Groups.[1].Value else def sprintf "%s<%s>" clean (t.GetGenericArguments() |> Seq.map prettyName |> String.concat ", ") else t.Name type Scope private(parent : option, node : obj, childScopes : ConditionalWeakTable) = let inherited = Dictionary() let anyChild = Dictionary() let name = lazy ( match parent with | None -> "Root" | Some p -> let self = sprintf "%s[H%X]" (prettyName(node.GetType())) (node.GetHashCode()) p.Name + "/" + self ) [] static val mutable private CurrentScope_ : option static let root = Scope(None, null, ConditionalWeakTable()) static member internal CurrentScope with get() = Scope.CurrentScope_ and set v = Scope.CurrentScope_ <- v member x.Node = node member x.Parent = parent member private x.TryGetAnyChildValue(name : string) = lock inherited (fun () -> match anyChild.TryGetValue(name) with | (true, v) -> ValueSome v | _ -> ValueNone ) static member internal Pseudo(node : obj, childScope : Scope) = let cwt = ConditionalWeakTable() cwt.Add(childScope.Node, childScope) Scope(None, node, cwt) member internal x.SetInherited(name : string, value : obj voption) = lock inherited (fun () -> inherited.[name] <- value ) member internal x.SetInheritedForChild(child : obj, name : string, value : obj voption) = lock inherited (fun () -> if child = anyObj then anyChild.[name] <- value else let c = x.GetChildScope(child) c.SetInherited(name, value) ) member private x.TryGetGlobalValue(name : string) = match lock globalValues (fun () -> globalValues.TryGetValue(node)) with | (true, d) -> match lock d (fun () -> d.TryGetValue(name)) with | (true, v) -> ValueSome v | _ -> ValueNone | _ -> ValueNone member internal x.Locked (action : unit -> 'T) = lock inherited action member internal x.Enter () = System.Threading.Monitor.Enter inherited member internal x.Exit () = if System.Threading.Monitor.IsEntered inherited then System.Threading.Monitor.Exit inherited member internal x.TryGetCacheValue(name : string) = lock inherited (fun () -> match inherited.TryGetValue name with | (true, v) -> ValueSome v | _ -> ValueNone ) member internal x.SetCacheValue(name : string, value : obj voption) = lock inherited (fun () -> inherited.[name] <- value ) member internal x.GetOrCreateCache(name : string, create : string -> 'a voption) = lock inherited (fun () -> match inherited.TryGetValue name with | (true, v) -> match v with | ValueSome (:? 'a as v) -> ValueSome v | _ -> ValueNone | _ -> let res = create name match res with | ValueSome v -> inherited.[name] <- ValueSome (v :> obj) | ValueNone -> inherited.[name] <- ValueNone res ) member internal x.TryGetInheritedCache(name : string) : obj voption voption = lock inherited (fun () -> match x.TryGetGlobalValue(name) with | ValueSome v -> ValueSome (ValueSome v) | ValueNone -> match inherited.TryGetValue name with | (true, v) -> ValueSome v | _ -> match parent with | Some p -> match p.TryGetAnyChildValue(name) with | ValueSome v -> inherited.[name] <- v ValueSome v | ValueNone -> ValueNone | None -> ValueNone ) member x.Name : string = name.Value override x.ToString() = name.Value /// the root scope static member Root = root /// get a (possibly cached) child scope for the given node member x.GetChildScope<'a when 'a : not struct>(node : 'a) : Scope = lock childScopes (fun () -> if typeof<'a>.IsValueType then Scope(Some x, node :> obj, ConditionalWeakTable()) else match childScopes.TryGetValue(node :> obj) with | (true, s) -> s | _ -> let s = Scope(Some x, node :> obj, ConditionalWeakTable()) childScopes.Add(node :> obj, s) s ) /// attach a global inherited value to a node (overrides any other inheritance mechanisms). static member SetGlobalValue<'a when 'a : not struct>(node : 'a, name : string, value : obj) : unit = let dict = lock globalValues (fun () -> match globalValues.TryGetValue node with | (true, d) -> d | _ -> let d = Dictionary() globalValues.Add(node, d) d ) lock dict (fun () -> dict.[name] <- value ) type Root<'a>(child : 'a) = member x.Child = child [] module private Helpers = open System.Reflection.Emit type NewRootDelegate = delegate of obj -> obj type SynDelegateStatic = delegate of obj * Scope -> obj type SynDelegateInstance = delegate of obj * obj * Scope -> obj type InhDelegateStatic = delegate of obj * Scope -> unit type InhDelegateInstance = delegate of obj * obj * Scope -> unit [] type InheritMethod(mi : MethodInfo, invoke : obj -> Scope -> unit) = member x.MethodInfo = mi member x.Invoke = invoke member private x.AsString = x.ToString() override x.ToString() = let decl = prettyName mi.DeclaringType let nodeType = prettyName (mi.GetParameters().[0].ParameterType) sprintf "%s.%s(node : %s, _)" decl mi.Name nodeType [] type SynMethod(mi : MethodInfo, invoke : obj -> Scope -> obj) = let cache = mi.GetCustomAttributes() |> Seq.isEmpty |> not member x.MethodInfo = mi member x.Invoke = invoke member x.Cache = cache member private x.AsString = x.ToString() override x.ToString() = let decl = prettyName mi.DeclaringType let ret = prettyName mi.ReturnType let nodeType = prettyName (mi.GetParameters().[0].ParameterType) sprintf "%s %s.%s(node : %s, _)" ret decl mi.Name nodeType let createSynMethod (self : obj) (mi : MethodInfo) (nodeType : Type) : SynMethod = let name = sprintf "Syn%s_%s" mi.Name nodeType.Name let dyn = DynamicMethod( name, MethodAttributes.Public ||| MethodAttributes.Static, CallingConventions.Standard, typeof, [| if not mi.IsStatic then yield typeof yield typeof yield typeof |], typeof, true ) let il = dyn.GetILGenerator() if mi.IsStatic then il.Emit(OpCodes.Ldarg, 0) if nodeType.IsValueType then il.Emit(OpCodes.Unbox, nodeType) il.Emit(OpCodes.Ldind_Ref) il.Emit(OpCodes.Ldarg, 1) il.EmitCall(OpCodes.Call, mi, null) if mi.ReturnType.IsValueType then il.Emit(OpCodes.Box, mi.ReturnType) il.Emit(OpCodes.Ret) let del = dyn.CreateDelegate(typeof) |> unbox SynMethod(mi, fun (node : obj) (scope : Scope) -> del.Invoke(node, scope)) else il.Emit(OpCodes.Ldarg, 0) if mi.DeclaringType.IsValueType then il.Emit(OpCodes.Unbox, mi.DeclaringType) il.Emit(OpCodes.Ldind_Ref) il.Emit(OpCodes.Ldarg, 1) if nodeType.IsValueType then il.Emit(OpCodes.Unbox, nodeType) il.Emit(OpCodes.Ldind_Ref) il.Emit(OpCodes.Ldarg, 2) if mi.IsVirtual then il.EmitCall(OpCodes.Callvirt, mi, null) else il.EmitCall(OpCodes.Call, mi, null) if mi.ReturnType.IsValueType then il.Emit(OpCodes.Box, mi.ReturnType) il.Emit(OpCodes.Ret) let del = dyn.CreateDelegate(typeof) |> unbox SynMethod(mi, fun (node : obj) (scope : Scope) -> del.Invoke(self, node, scope)) let createInhMethod (self : obj) (mi : MethodInfo) (nodeType : Type) : InheritMethod = let name = sprintf "Inh%s_%s" mi.Name nodeType.Name let dyn = DynamicMethod( name, MethodAttributes.Public ||| MethodAttributes.Static, CallingConventions.Standard, typeof, [| if not mi.IsStatic then yield typeof yield typeof yield typeof |], typeof, true ) let il = dyn.GetILGenerator() if mi.IsStatic then il.Emit(OpCodes.Ldarg, 0) if nodeType.IsValueType then il.Emit(OpCodes.Unbox, nodeType) il.Emit(OpCodes.Ldind_Ref) il.Emit(OpCodes.Ldarg, 1) il.EmitCall(OpCodes.Call, mi, null) il.Emit(OpCodes.Ret) let del = dyn.CreateDelegate(typeof) |> unbox InheritMethod(mi, fun (node : obj) (scope : Scope) -> del.Invoke(node, scope)) else il.Emit(OpCodes.Ldarg, 0) if mi.DeclaringType.IsValueType then il.Emit(OpCodes.Unbox, mi.DeclaringType) il.Emit(OpCodes.Ldind_Ref) il.Emit(OpCodes.Ldarg, 1) if nodeType.IsValueType then il.Emit(OpCodes.Unbox, nodeType) il.Emit(OpCodes.Ldind_Ref) il.Emit(OpCodes.Ldarg, 2) if mi.IsVirtual then il.EmitCall(OpCodes.Callvirt, mi, null) else il.EmitCall(OpCodes.Call, mi, null) il.Emit(OpCodes.Ret) let del = dyn.CreateDelegate(typeof) |> unbox InheritMethod(mi, fun (node : obj) (scope : Scope) -> del.Invoke(self, node, scope)) let private rootCreators = System.Collections.Concurrent.ConcurrentDictionary obj>() let getRootCreator (t : Type) = rootCreators.GetOrAdd(t, System.Func(fun nodeType -> let name = sprintf "NewRoot%s" nodeType.Name let res = typedefof>.MakeGenericType [| nodeType |] let ctor = res.GetConstructor([| nodeType |]) let dyn = DynamicMethod( name, MethodAttributes.Public ||| MethodAttributes.Static, CallingConventions.Standard, typeof, [| typeof |], typeof, true ) let il = dyn.GetILGenerator() il.Emit(OpCodes.Ldarg, 0) il.Emit(OpCodes.Newobj, ctor) il.Emit(OpCodes.Ret) let del = dyn.CreateDelegate(typeof) |> unbox del.Invoke )) let private instances = ConcurrentDict(Dict()) let tryCreateInstance (t : Type) = instances.GetOrCreate(t, fun t -> let ctor = t.GetConstructor(BindingFlags.NonPublic ||| BindingFlags.Public ||| BindingFlags.Instance, Type.DefaultBinder, [||], null) if isNull ctor then ValueNone else let v = ctor.Invoke([||]) ValueSome v ) let isSynMethod (mi : MethodInfo) = let pars = mi.GetParameters() if pars.Length = 2 && mi.ReturnType <> typeof && mi.ReturnType <> typeof then pars.[1].ParameterType.IsAssignableFrom typeof else false let isInhMethod (mi : MethodInfo) = let pars = mi.GetParameters() if pars.Length = 2 && (mi.ReturnType = typeof || mi.ReturnType = typeof) then pars.[1].ParameterType.IsAssignableFrom typeof else false type RuleTable() = let all = let semTypes = Introspection.GetAllTypesWithAttribute() |> Seq.collect (fun struct (t,_) -> t.GetMethods(BindingFlags.Static ||| BindingFlags.Instance ||| BindingFlags.NonPublic ||| BindingFlags.Public ||| BindingFlags.DeclaredOnly)) let semMeths = Introspection.GetAllMethodsWithAttribute() |> Seq.map (fun struct (m,_) -> m) Seq.append semTypes semMeths |> Seq.filter (fun m -> let decl = m.DeclaringType let ps = m.GetParameters() let generated = m.GetCustomAttribute() if not (isNull generated) then false elif decl.ContainsGenericParameters then Log.warn "unexpected generic rule-type: %A" decl false elif ps.Length <> 2 || (ps.Length = 2 && ps.[1].ParameterType <> typeof) then Log.warn "unexpected rule: %A" m false elif not m.IsStatic then let ctor = decl.GetConstructor(BindingFlags.NonPublic ||| BindingFlags.Public ||| BindingFlags.Instance, Type.DefaultBinder, [||], null) if isNull ctor then Log.warn "cannot construct rule type: %A" decl false else true else true ) |> Seq.toArray let synRules : Dictionary = all |> Seq.filter isSynMethod |> Seq.groupBy _.Name |> Seq.map (fun (g, meths) -> g, meths |> Seq.toArray) |> Dictionary.ofSeq let inhRules : Dictionary = all |> Seq.filter isInhMethod |> Seq.groupBy _.Name |> Seq.map (fun (g, meths) -> g, meths |> Seq.toArray) |> Dictionary.ofSeq let synCache = ConcurrentDict(Dict()) let inhCache = ConcurrentDict(Dict()) member x.TryGetSynRule(name : string, nodeType : Type, expectedType : Type) : SynMethod voption = synCache.GetOrCreate((name, nodeType, expectedType), fun (name, nodeType, expectedType) -> match synRules.TryGetValue name with | (true, rules) -> let argTypes = [| nodeType; typeof |] let applicable = rules |> Array.choose (fun m -> m.TrySpecialize(argTypes, expectedType)) if applicable.Length = 0 then ValueNone elif applicable.Length = 1 then let m = applicable.[0] let instance = if m.IsStatic then ValueSome null else tryCreateInstance m.DeclaringType match instance with | ValueSome instance -> createSynMethod instance m nodeType |> ValueSome | ValueNone -> ValueNone else let mb = applicable |> Array.map (fun m -> m :> MethodBase) try let selected = Type.DefaultBinder.SelectMethod( BindingFlags.NonPublic ||| BindingFlags.Public ||| BindingFlags.Instance ||| BindingFlags.Static, mb, argTypes, null ) match selected with | null -> ValueNone | :? MethodInfo as m -> let instance = if m.IsStatic then ValueSome null else tryCreateInstance m.DeclaringType match instance with | ValueSome instance ->createSynMethod instance m nodeType |> ValueSome | ValueNone -> ValueNone | _ -> ValueNone with _ -> ValueNone | _ -> ValueNone ) member x.TryGetInhRule(name : string, nodeType : Type) : InheritMethod voption = inhCache.GetOrCreate((name, nodeType), fun (name, nodeType) -> match inhRules.TryGetValue name with | (true, rules) -> let argTypes = [| nodeType; typeof |] let applicable = rules |> Array.choose (fun m -> m.TrySpecialize(argTypes, typeof)) if applicable.Length = 0 then ValueNone elif applicable.Length = 1 then let m = applicable.[0] let instance = if m.IsStatic then ValueSome null else tryCreateInstance m.DeclaringType match instance with | ValueSome instance -> createInhMethod instance m nodeType |> ValueSome | ValueNone -> ValueNone else let mb = applicable |> Array.map (fun m -> m :> MethodBase) try let selected = Type.DefaultBinder.SelectMethod( BindingFlags.NonPublic ||| BindingFlags.Public ||| BindingFlags.Instance ||| BindingFlags.Static, mb, argTypes, null ) match selected with | null -> ValueNone | :? MethodInfo as m -> let instance = if m.IsStatic then ValueSome null else tryCreateInstance m.DeclaringType match instance with | ValueSome instance -> createInhMethod instance m nodeType |> ValueSome | ValueNone -> ValueNone | _ -> ValueNone with _ -> ValueNone | _ -> ValueNone ) let table = lazy (RuleTable()) let hasSynRule (nodeType : Type) (expected : Type) (name : string) = match table.Value.TryGetSynRule(name, nodeType, expected) with | ValueSome _ -> true | ValueNone -> false let rec internal runinh (scope : Scope) (name : string) = match scope.TryGetInheritedCache(name) with | ValueSome v -> v | ValueNone -> match scope.Parent with | Some p -> if isNull p.Node then let self = scope.Node.GetType().GetBaseTypesAndSelf() let meth = self |> Array.tryPickV (fun t -> let pseudo = typedefof>.MakeGenericType [| t |] match table.Value.TryGetInhRule(name, pseudo) with | ValueSome m -> ValueSome (t, m) | ValueNone -> ValueNone ) match meth with | ValueSome (t, inh) -> let root = getRootCreator t scope.Node let pseudo = Scope.Pseudo(root, scope) let o = Scope.CurrentScope Scope.CurrentScope <- Some pseudo inh.Invoke root pseudo Scope.CurrentScope <- o match scope.TryGetInheritedCache(name) with | ValueSome v -> v | ValueNone -> Log.warn "[Ag] bad root inherit method: %A" inh ValueNone | ValueNone -> // root ValueNone else match table.Value.TryGetInhRule(name, p.Node.GetType()) with | ValueSome inh -> let o = Scope.CurrentScope Scope.CurrentScope <- Some p inh.Invoke p.Node p Scope.CurrentScope <- o match scope.TryGetInheritedCache(name) with | ValueSome v -> v | ValueNone -> Log.warn "[Ag] bad inherit method: %A" inh ValueNone | ValueNone -> let res = runinh p name scope.SetInherited(name, res) res | None -> ValueNone let internal syn (node : 'a) (scope : Scope) (name : string) (expectedType : Type) = if isNull (node :> obj) then ValueNone else let cacheName = "syn." + name scope.Enter() try let t = node.GetType() match table.Value.TryGetSynRule(name, t, expectedType) with | ValueSome syn -> let newScope = scope.GetChildScope(node) if syn.Cache then match newScope.TryGetCacheValue cacheName with | ValueSome v -> v | ValueNone -> let result = syn.Invoke (node :> obj) newScope |> ValueSome newScope.SetCacheValue(cacheName, result) result else scope.Exit() syn.Invoke (node :> obj) newScope |> ValueSome | _ -> ValueNone finally scope.Exit() type System.Object with member x.AllChildren = anyObj let internal set<'a, 'b when 'a : not struct> (target : 'a) (name : string) (value : 'b) = let node = match target :> obj with | :? FSharp.Data.Adaptive.IAdaptiveValue as v -> v.GetValueUntyped(FSharp.Data.Adaptive.AdaptiveToken.Top) | n -> n match Scope.CurrentScope with | Some s -> // classic aval unpacking here s.SetInheritedForChild(node, name, ValueSome (value :> obj)) | None -> Scope.SetGlobalValue(node, name, value :> obj) let (?<-) (target : 'a) (name : string) (value : 'b) = set target name value type Operators private() = static member Get(scope : Scope, name : string) : 'a = match runinh scope name with | ValueSome (:? 'a as v) -> v | _ -> failwithf "[Ag] could not get inh attribute %s in scope %A" name scope static member Get(node : 'a, name : string) : Scope -> 'b = fun s -> match syn (node :> obj) s name typeof<'b> with | ValueSome (:? 'b as v) -> v | ValueSome v -> failwithf "[Ag] invalid result for syn attribute %s on node %A: %A" name node v | ValueNone -> failwithf "[Ag] could not get syn attribute %s on node %A" name node let inline private opAux (_d : 'd) (a : 'a) (b : 'b) : 'c = ((^a or ^b or ^d) : (static member Get : ^a * ^b -> ^c) (a, b)) let inline (?) a b = opAux Unchecked.defaultof a b [] type AgScopeExtensions private() = [] static member TryGetInherited(this : Ag.Scope, name : string) = Ag.runinh this name |> ValueOption.toOption [] static member TryGetInheritedV(this : Ag.Scope, name : string) = Ag.runinh this name [] static member TryGetInherited<'a>(this : Ag.Scope, name : string) = match Ag.runinh this name with | ValueSome (:? 'a as res) -> Some res | _ -> None [] static member TryGetInheritedV<'a>(this : Ag.Scope, name : string) = match Ag.runinh this name with | ValueSome (:? 'a as res) -> ValueSome res | _ -> ValueNone [] static member GetInherted(this : Ag.Scope, name : string) = match Ag.runinh this name with | ValueSome v -> v | ValueNone -> failwithf "[Ag] could not get inh attribute %s in scope %A" name this [] static member GetInherted<'a>(this : Ag.Scope, name : string) = match Ag.runinh this name with | ValueSome (:? 'a as res) -> res | _ -> failwithf "[Ag] could not get inh attribute %s in scope %A" name this [] static member TryGetSynthesized<'a>(node : obj, name : string, scope : Ag.Scope) = match Ag.syn node scope name typeof<'a> with | ValueSome (:? 'a as res) -> Some res | _ -> None [] static member TryGetSynthesizedV<'a>(node : obj, name : string, scope : Ag.Scope) = match Ag.syn node scope name typeof<'a> with | ValueSome (:? 'a as res) -> ValueSome res | _ -> ValueNone [] static member TryGetSynthesized<'a>(scope : Ag.Scope, name : string) = if isNull scope.Node then failwithf "[Ag] cannot get syn attribute for scope with no node: %A" scope match scope.Parent with | Some p -> scope.Node.TryGetSynthesized<'a>(name, p) | None -> scope.Node.TryGetSynthesized<'a>(name, Ag.Scope.Root) [] static member TryGetSynthesizedV<'a>(scope : Ag.Scope, name : string) = if isNull scope.Node then failwithf "[Ag] cannot get syn attribute for scope with no node: %A" scope match scope.Parent with | Some p -> scope.Node.TryGetSynthesizedV<'a>(name, p) | None -> scope.Node.TryGetSynthesizedV<'a>(name, Ag.Scope.Root) [] static member GetSynthesized<'a>(node : obj, name : string, scope : Ag.Scope) = match Ag.syn node scope name typeof<'a> with | ValueSome (:? 'a as res) -> res | _ -> failwithf "[Ag] could not get syn attribute %s on node %A" name node [] static member TryGetAttributeValue(scope : Ag.Scope, name : string) = match scope.TryGetSynthesized(name) with | None -> scope.TryGetInherited(name) | r -> r [] static member TryGetAttributeValueV(scope : Ag.Scope, name : string) = match scope.TryGetSynthesizedV(name) with | ValueNone -> scope.TryGetInheritedV(name) | r -> r [] static member TryGetAttributeValue<'a>(scope : Ag.Scope, name : string) = match scope.TryGetSynthesized<'a>(name) with | None -> scope.TryGetInherited<'a>(name) | r -> r [] static member TryGetAttributeValueV<'a>(scope : Ag.Scope, name : string) = match scope.TryGetSynthesizedV<'a>(name) with | ValueNone -> scope.TryGetInheritedV<'a>(name) | r -> r ================================================ FILE: src/Aardvark.Base.FSharp/Algorithms/PolygonSimplification.fs ================================================ namespace Aardvark.Base open System.Runtime.CompilerServices [] type PolygonExtensions private() = [] static member Simplify(x : Polygon2d, eps : float) = if eps <= 0.0 || x.PointCount <= 3 then x else // find two points with maximum curvature let mutable angle0 = 0.0 let mutable angle1 = 0.0 let mutable id0 = -1 let mutable id1 = -1 let mutable i0 = x.PointCount - 2 let mutable i1 = x.PointCount - 1 let mutable d01 = Vec.normalize (x.[i1] - x.[i0]) for i2 in 0 .. x.PointCount - 1 do let d12 = Vec.normalize (x.[i2] - x.[i1]) let angle = Vec.AngleBetween(d01, d12) |> abs if angle > angle0 then angle1 <- angle0 id1 <- id0 angle0 <- angle id0 <- i1 elif angle > angle1 then angle1 <- angle id1 <- i1 i0 <- i1 i1 <- i2 d01 <- d12 // if there are at least two points with curvature > 0 if id0 >= 0 && id1 >= 0 then let inline iter (s : int) (e : int) (action : int -> unit) = let mutable i = (s + x.PointCount) % x.PointCount let e = (e + 1) % x.PointCount while i <> e do action i i <- i + 1 if i >= x.PointCount then i <- i - x.PointCount let rec simplify (set : System.Collections.Generic.SortedSet) (l : int) (r : int) = set.Add l |> ignore if l <> r then let p0 = x.[l] let p1 = x.[r] let d = Vec.normalize (p1 - p0) let n = V2d(-d.Y, d.X) // find the worst point (max height) let mutable hMax = 0.0 let mutable max = -1 iter (l+1) (r-1) (fun i -> let h = Vec.dot n (x.[i] - p0) |> abs if h > hMax then hMax <- h max <- i ) // if not within tolerance continue recursively if hMax > eps then simplify set l max simplify set max r let set = System.Collections.Generic.SortedSet() // simplify both curves simplify set id0 id1 simplify set id1 id0 let arr = Array.zeroCreate set.Count let mutable i = 0 for i0 in set do arr.[i] <- x.[i0] i <- i + 1 Polygon2d arr else x [] static member Simplify(x : Polygon3d, eps : float) = if eps <= 0.0 || x.PointCount <= 3 then x else // find two points with maximum curvature let mutable angle0 = 0.0 let mutable angle1 = 0.0 let mutable id0 = -1 let mutable id1 = -1 let mutable i0 = x.PointCount - 2 let mutable i1 = x.PointCount - 1 let mutable d01 = Vec.normalize (x.[i1] - x.[i0]) for i2 in 0 .. x.PointCount - 1 do let d12 = Vec.normalize (x.[i2] - x.[i1]) let angle = Vec.AngleBetween(d01, d12) |> abs if angle > angle0 then angle1 <- angle0 id1 <- id0 angle0 <- angle id0 <- i1 elif angle > angle1 then angle1 <- angle id1 <- i1 i0 <- i1 i1 <- i2 d01 <- d12 // if there are at least two points with curvature > 0 if id0 >= 0 && id1 >= 0 then let inline iter (s : int) (e : int) (action : int -> unit) = let mutable i = (s + x.PointCount) % x.PointCount let e = (e + 1) % x.PointCount while i <> e do action i i <- i + 1 if i >= x.PointCount then i <- i - x.PointCount let rec simplify (set : System.Collections.Generic.SortedSet) (l : int) (r : int) = set.Add l |> ignore if l <> r then let p0 = x.[l] let p1 = x.[r] let d = Vec.normalize (p1 - p0) let n = V2d(-d.Y, d.X) // find the worst point (max height) let mutable hMax = 0.0 let mutable max = -1 iter (l+1) (r-1) (fun i -> let h = x.[i].DistanceToInfiniteLine(p0, p1) if h > hMax then hMax <- h max <- i ) // if not within tolerance continue recursively if hMax > eps then simplify set l max simplify set max r let set = System.Collections.Generic.SortedSet() // simplify both curves simplify set id0 id1 simplify set id1 id0 let arr = Array.zeroCreate set.Count let mutable i = 0 for i0 in set do arr.[i] <- x.[i0] i <- i + 1 Polygon3d arr else x ================================================ FILE: src/Aardvark.Base.FSharp/Color/ColorBrewer.fs ================================================ namespace Aardvark.Base open System open System.Collections open System.Collections.Generic /// Brewer color schemes designed for choropleth map visualizations. module ColorBrewer = [] type PaletteUsage = | None = 0 /// Does not confuse people with red-green color blindness. | ColorBlind = 1 /// Suitable for desktop color printing. | Print = 2 /// Suitable for viewing on a laptop LCD display. /// Small, portable LCD monitors tend to wash-out colors which results in noticeable differences from computer-to-computer. | LCD = 4 /// Withstands black and white photocopying. /// Diverging schemes can not be photocopied successfully. /// Differences in lightness should be preserved with sequential schemes. | PhotoCopy = 8 [] type Palette = { /// The color values of the palette. Colors : C3b[] /// Usage properties of the palette. Usage : PaletteUsage } member inline x.Length = x.Colors.Length member inline x.Item (index : int) = x.Colors.[index] interface IEnumerable with member x.GetEnumerator() = x.Colors.GetEnumerator() interface IEnumerable with member x.GetEnumerator() = (x.Colors :> IEnumerable).GetEnumerator() type SchemeType = /// Diverging schemes put equal emphasis on mid-range critical values and extremes at both ends of the data range. /// The critical class or break in the middle of the legend is emphasized with light colors and low and high extremes are /// emphasized with dark colors that have contrasting hues. | Diverging = 0 /// Qualitative schemes do not imply magnitude differences between legend classes, and hues are used to /// create the primary visual differences between classes. Qualitative schemes are best suited to representing nominal or categorical data. | Qualitative = 1 /// Sequential schemes are suited to ordered data that progress from low to high. /// Lightness steps dominate the look of these schemes, with light colors for low data values to dark colors for high data values. | Sequential = 2 /// A color scheme containing palettes of various size. [] type Scheme = { /// Name of the scheme. Name : Symbol /// Type of the scheme. Type : SchemeType /// The palettes of the scheme according to their size. Palettes : MapExt } /// Returns whether the scheme is empty (i.e. has no palettes). member inline x.IsEmpty = x.Palettes.IsEmpty /// Size of the smallest palette. member inline x.MinSize = x.Palettes.TryMinKeyV |> ValueOption.defaultValue 0 /// Size of the largest palette. member inline x.MaxSize = x.Palettes.TryMaxKeyV |> ValueOption.defaultValue 0 /// Gets the palette with the given size. /// If the scheme is not defined for the requested size, gets the next larger palette. /// Throws an exception if the requested size is greater than the maximum size. member inline x.Item (requestedSize : int) = match x.Palettes |> MapExt.neighboursV requestedSize with | struct (_, ValueSome (struct (_, palette)), _) | struct (_, _, ValueSome (struct (_, palette))) -> palette | struct (ValueSome (struct (max, _)), _, _) -> raise <| ArgumentOutOfRangeException("requestedSize", $"Scheme {x.Name} has a maximum palette size of {max} (requested {requestedSize}).") | struct (ValueNone, ValueNone, ValueNone) -> raise <| ArgumentException($"Scheme {x.Name} is empty.") [] module Scheme = /// Returns whether the scheme is empty (i.e. has no palettes). let inline isEmpty (scheme : Scheme) = scheme.IsEmpty /// Return the size of the smallest palette for the given scheme. let inline minSize (scheme : Scheme) = scheme.MinSize /// Return the size of the largest palette for the given scheme. let inline maxSize (scheme : Scheme) = scheme.MaxSize /// Gets the palette with the given size. /// If the scheme is not defined for the requested size, gets the next larger palette. /// Throws an exception if the requested size is greater than the maximum size. let inline getPalette (requestedSize : int) (scheme : Scheme) = scheme.[requestedSize] /// Returns a new scheme containing only the palettes for which the predicate returns true. let inline filter (predicate : Palette -> bool) (scheme : Scheme) = { scheme with Palettes = scheme.Palettes |> MapExt.filter (fun _ -> predicate) } /// Returns a new scheme containing only the palettes with the given usage flags. let inline filterUsage (usage : PaletteUsage) (scheme : Scheme) = scheme |> filter (fun p -> p.Usage &&& usage = usage) ================================================ FILE: src/Aardvark.Base.FSharp/Color/ColorBrewerSchemes.fs ================================================ namespace Aardvark.Base [] module ColorBrewerSchemes = open ColorBrewer /// Brewer color schemes designed for choropleth map visualizations. module ColorBrewer = module Scheme = /// Diverging schemes put equal emphasis on mid-range critical values and extremes at both ends of the data range. /// The critical class or break in the middle of the legend is emphasized with light colors and low and high extremes are /// emphasized with dark colors that have contrasting hues. module Diverging = let Spectral = { Name = Sym.ofString "Spectral" Type = SchemeType.Diverging Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(252uy,141uy,89uy); C3b(255uy,255uy,191uy); C3b(153uy,213uy,148uy) |] } 4, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(215uy,25uy,28uy); C3b(253uy,174uy,97uy); C3b(171uy,221uy,164uy); C3b(43uy,131uy,186uy) |] } 5, { Usage = PaletteUsage.Print ||| PaletteUsage.PhotoCopy Colors = [| C3b(215uy,25uy,28uy); C3b(253uy,174uy,97uy); C3b(255uy,255uy,191uy); C3b(171uy,221uy,164uy) C3b(43uy,131uy,186uy) |] } 6, { Usage = PaletteUsage.None Colors = [| C3b(213uy,62uy,79uy); C3b(252uy,141uy,89uy); C3b(254uy,224uy,139uy); C3b(230uy,245uy,152uy) C3b(153uy,213uy,148uy); C3b(50uy,136uy,189uy) |] } 7, { Usage = PaletteUsage.None Colors = [| C3b(213uy,62uy,79uy); C3b(252uy,141uy,89uy); C3b(254uy,224uy,139uy); C3b(255uy,255uy,191uy) C3b(230uy,245uy,152uy); C3b(153uy,213uy,148uy); C3b(50uy,136uy,189uy) |] } 8, { Usage = PaletteUsage.None Colors = [| C3b(213uy,62uy,79uy); C3b(244uy,109uy,67uy); C3b(253uy,174uy,97uy); C3b(254uy,224uy,139uy) C3b(230uy,245uy,152uy); C3b(171uy,221uy,164uy); C3b(102uy,194uy,165uy); C3b(50uy,136uy,189uy) |] } 9, { Usage = PaletteUsage.None Colors = [| C3b(213uy,62uy,79uy); C3b(244uy,109uy,67uy); C3b(253uy,174uy,97uy); C3b(254uy,224uy,139uy) C3b(255uy,255uy,191uy); C3b(230uy,245uy,152uy); C3b(171uy,221uy,164uy); C3b(102uy,194uy,165uy) C3b(50uy,136uy,189uy) |] } 10, { Usage = PaletteUsage.None Colors = [| C3b(158uy,1uy,66uy); C3b(213uy,62uy,79uy); C3b(244uy,109uy,67uy); C3b(253uy,174uy,97uy) C3b(254uy,224uy,139uy); C3b(230uy,245uy,152uy); C3b(171uy,221uy,164uy); C3b(102uy,194uy,165uy) C3b(50uy,136uy,189uy); C3b(94uy,79uy,162uy) |] } 11, { Usage = PaletteUsage.None Colors = [| C3b(158uy,1uy,66uy); C3b(213uy,62uy,79uy); C3b(244uy,109uy,67uy); C3b(253uy,174uy,97uy) C3b(254uy,224uy,139uy); C3b(255uy,255uy,191uy); C3b(230uy,245uy,152uy); C3b(171uy,221uy,164uy) C3b(102uy,194uy,165uy); C3b(50uy,136uy,189uy); C3b(94uy,79uy,162uy) |] } ] } let RdYlGn = { Name = Sym.ofString "RdYlGn" Type = SchemeType.Diverging Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(252uy,141uy,89uy); C3b(255uy,255uy,191uy); C3b(145uy,207uy,96uy) |] } 4, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(215uy,25uy,28uy); C3b(253uy,174uy,97uy); C3b(166uy,217uy,106uy); C3b(26uy,150uy,65uy) |] } 5, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(215uy,25uy,28uy); C3b(253uy,174uy,97uy); C3b(255uy,255uy,191uy); C3b(166uy,217uy,106uy) C3b(26uy,150uy,65uy) |] } 6, { Usage = PaletteUsage.None Colors = [| C3b(215uy,48uy,39uy); C3b(252uy,141uy,89uy); C3b(254uy,224uy,139uy); C3b(217uy,239uy,139uy) C3b(145uy,207uy,96uy); C3b(26uy,152uy,80uy) |] } 7, { Usage = PaletteUsage.None Colors = [| C3b(215uy,48uy,39uy); C3b(252uy,141uy,89uy); C3b(254uy,224uy,139uy); C3b(255uy,255uy,191uy) C3b(217uy,239uy,139uy); C3b(145uy,207uy,96uy); C3b(26uy,152uy,80uy) |] } 8, { Usage = PaletteUsage.None Colors = [| C3b(215uy,48uy,39uy); C3b(244uy,109uy,67uy); C3b(253uy,174uy,97uy); C3b(254uy,224uy,139uy) C3b(217uy,239uy,139uy); C3b(166uy,217uy,106uy); C3b(102uy,189uy,99uy); C3b(26uy,152uy,80uy) |] } 9, { Usage = PaletteUsage.None Colors = [| C3b(215uy,48uy,39uy); C3b(244uy,109uy,67uy); C3b(253uy,174uy,97uy); C3b(254uy,224uy,139uy) C3b(255uy,255uy,191uy); C3b(217uy,239uy,139uy); C3b(166uy,217uy,106uy); C3b(102uy,189uy,99uy) C3b(26uy,152uy,80uy) |] } 10, { Usage = PaletteUsage.None Colors = [| C3b(165uy,0uy,38uy); C3b(215uy,48uy,39uy); C3b(244uy,109uy,67uy); C3b(253uy,174uy,97uy) C3b(254uy,224uy,139uy); C3b(217uy,239uy,139uy); C3b(166uy,217uy,106uy); C3b(102uy,189uy,99uy) C3b(26uy,152uy,80uy); C3b(0uy,104uy,55uy) |] } 11, { Usage = PaletteUsage.None Colors = [| C3b(165uy,0uy,38uy); C3b(215uy,48uy,39uy); C3b(244uy,109uy,67uy); C3b(253uy,174uy,97uy) C3b(254uy,224uy,139uy); C3b(255uy,255uy,191uy); C3b(217uy,239uy,139uy); C3b(166uy,217uy,106uy) C3b(102uy,189uy,99uy); C3b(26uy,152uy,80uy); C3b(0uy,104uy,55uy) |] } ] } let RdBu = { Name = Sym.ofString "RdBu" Type = SchemeType.Diverging Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(239uy,138uy,98uy); C3b(247uy,247uy,247uy); C3b(103uy,169uy,207uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(202uy,0uy,32uy); C3b(244uy,165uy,130uy); C3b(146uy,197uy,222uy); C3b(5uy,113uy,176uy) |] } 5, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(202uy,0uy,32uy); C3b(244uy,165uy,130uy); C3b(247uy,247uy,247uy); C3b(146uy,197uy,222uy) C3b(5uy,113uy,176uy) |] } 6, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print Colors = [| C3b(178uy,24uy,43uy); C3b(239uy,138uy,98uy); C3b(253uy,219uy,199uy); C3b(209uy,229uy,240uy) C3b(103uy,169uy,207uy); C3b(33uy,102uy,172uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(178uy,24uy,43uy); C3b(239uy,138uy,98uy); C3b(253uy,219uy,199uy); C3b(247uy,247uy,247uy) C3b(209uy,229uy,240uy); C3b(103uy,169uy,207uy); C3b(33uy,102uy,172uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(178uy,24uy,43uy); C3b(214uy,96uy,77uy); C3b(244uy,165uy,130uy); C3b(253uy,219uy,199uy) C3b(209uy,229uy,240uy); C3b(146uy,197uy,222uy); C3b(67uy,147uy,195uy); C3b(33uy,102uy,172uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(178uy,24uy,43uy); C3b(214uy,96uy,77uy); C3b(244uy,165uy,130uy); C3b(253uy,219uy,199uy) C3b(247uy,247uy,247uy); C3b(209uy,229uy,240uy); C3b(146uy,197uy,222uy); C3b(67uy,147uy,195uy) C3b(33uy,102uy,172uy) |] } 10, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(103uy,0uy,31uy); C3b(178uy,24uy,43uy); C3b(214uy,96uy,77uy); C3b(244uy,165uy,130uy) C3b(253uy,219uy,199uy); C3b(209uy,229uy,240uy); C3b(146uy,197uy,222uy); C3b(67uy,147uy,195uy) C3b(33uy,102uy,172uy); C3b(5uy,48uy,97uy) |] } 11, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(103uy,0uy,31uy); C3b(178uy,24uy,43uy); C3b(214uy,96uy,77uy); C3b(244uy,165uy,130uy) C3b(253uy,219uy,199uy); C3b(247uy,247uy,247uy); C3b(209uy,229uy,240uy); C3b(146uy,197uy,222uy) C3b(67uy,147uy,195uy); C3b(33uy,102uy,172uy); C3b(5uy,48uy,97uy) |] } ] } let PiYG = { Name = Sym.ofString "PiYG" Type = SchemeType.Diverging Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(233uy,163uy,201uy); C3b(247uy,247uy,247uy); C3b(161uy,215uy,106uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(208uy,28uy,139uy); C3b(241uy,182uy,218uy); C3b(184uy,225uy,134uy); C3b(77uy,172uy,38uy) |] } 5, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(208uy,28uy,139uy); C3b(241uy,182uy,218uy); C3b(247uy,247uy,247uy); C3b(184uy,225uy,134uy) C3b(77uy,172uy,38uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(197uy,27uy,125uy); C3b(233uy,163uy,201uy); C3b(253uy,224uy,239uy); C3b(230uy,245uy,208uy) C3b(161uy,215uy,106uy); C3b(77uy,146uy,33uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(197uy,27uy,125uy); C3b(233uy,163uy,201uy); C3b(253uy,224uy,239uy); C3b(247uy,247uy,247uy) C3b(230uy,245uy,208uy); C3b(161uy,215uy,106uy); C3b(77uy,146uy,33uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(197uy,27uy,125uy); C3b(222uy,119uy,174uy); C3b(241uy,182uy,218uy); C3b(253uy,224uy,239uy) C3b(230uy,245uy,208uy); C3b(184uy,225uy,134uy); C3b(127uy,188uy,65uy); C3b(77uy,146uy,33uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(197uy,27uy,125uy); C3b(222uy,119uy,174uy); C3b(241uy,182uy,218uy); C3b(253uy,224uy,239uy) C3b(247uy,247uy,247uy); C3b(230uy,245uy,208uy); C3b(184uy,225uy,134uy); C3b(127uy,188uy,65uy) C3b(77uy,146uy,33uy) |] } 10, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(142uy,1uy,82uy); C3b(197uy,27uy,125uy); C3b(222uy,119uy,174uy); C3b(241uy,182uy,218uy) C3b(253uy,224uy,239uy); C3b(230uy,245uy,208uy); C3b(184uy,225uy,134uy); C3b(127uy,188uy,65uy) C3b(77uy,146uy,33uy); C3b(39uy,100uy,25uy) |] } 11, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(142uy,1uy,82uy); C3b(197uy,27uy,125uy); C3b(222uy,119uy,174uy); C3b(241uy,182uy,218uy) C3b(253uy,224uy,239uy); C3b(247uy,247uy,247uy); C3b(230uy,245uy,208uy); C3b(184uy,225uy,134uy) C3b(127uy,188uy,65uy); C3b(77uy,146uy,33uy); C3b(39uy,100uy,25uy) |] } ] } let PRGn = { Name = Sym.ofString "PRGn" Type = SchemeType.Diverging Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(175uy,141uy,195uy); C3b(247uy,247uy,247uy); C3b(127uy,191uy,123uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(123uy,50uy,148uy); C3b(194uy,165uy,207uy); C3b(166uy,219uy,160uy); C3b(0uy,136uy,55uy) |] } 5, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print Colors = [| C3b(123uy,50uy,148uy); C3b(194uy,165uy,207uy); C3b(247uy,247uy,247uy); C3b(166uy,219uy,160uy) C3b(0uy,136uy,55uy) |] } 6, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print Colors = [| C3b(118uy,42uy,131uy); C3b(175uy,141uy,195uy); C3b(231uy,212uy,232uy); C3b(217uy,240uy,211uy) C3b(127uy,191uy,123uy); C3b(27uy,120uy,55uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(118uy,42uy,131uy); C3b(175uy,141uy,195uy); C3b(231uy,212uy,232uy); C3b(247uy,247uy,247uy) C3b(217uy,240uy,211uy); C3b(127uy,191uy,123uy); C3b(27uy,120uy,55uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(118uy,42uy,131uy); C3b(153uy,112uy,171uy); C3b(194uy,165uy,207uy); C3b(231uy,212uy,232uy) C3b(217uy,240uy,211uy); C3b(166uy,219uy,160uy); C3b(90uy,174uy,97uy); C3b(27uy,120uy,55uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(118uy,42uy,131uy); C3b(153uy,112uy,171uy); C3b(194uy,165uy,207uy); C3b(231uy,212uy,232uy) C3b(247uy,247uy,247uy); C3b(217uy,240uy,211uy); C3b(166uy,219uy,160uy); C3b(90uy,174uy,97uy) C3b(27uy,120uy,55uy) |] } 10, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(64uy,0uy,75uy); C3b(118uy,42uy,131uy); C3b(153uy,112uy,171uy); C3b(194uy,165uy,207uy) C3b(231uy,212uy,232uy); C3b(217uy,240uy,211uy); C3b(166uy,219uy,160uy); C3b(90uy,174uy,97uy) C3b(27uy,120uy,55uy); C3b(0uy,68uy,27uy) |] } 11, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(64uy,0uy,75uy); C3b(118uy,42uy,131uy); C3b(153uy,112uy,171uy); C3b(194uy,165uy,207uy) C3b(231uy,212uy,232uy); C3b(247uy,247uy,247uy); C3b(217uy,240uy,211uy); C3b(166uy,219uy,160uy) C3b(90uy,174uy,97uy); C3b(27uy,120uy,55uy); C3b(0uy,68uy,27uy) |] } ] } let RdYlBu = { Name = Sym.ofString "RdYlBu" Type = SchemeType.Diverging Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(252uy,141uy,89uy); C3b(255uy,255uy,191uy); C3b(145uy,191uy,219uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(215uy,25uy,28uy); C3b(253uy,174uy,97uy); C3b(171uy,217uy,233uy); C3b(44uy,123uy,182uy) |] } 5, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(215uy,25uy,28uy); C3b(253uy,174uy,97uy); C3b(255uy,255uy,191uy); C3b(171uy,217uy,233uy) C3b(44uy,123uy,182uy) |] } 6, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print Colors = [| C3b(215uy,48uy,39uy); C3b(252uy,141uy,89uy); C3b(254uy,224uy,144uy); C3b(224uy,243uy,248uy) C3b(145uy,191uy,219uy); C3b(69uy,117uy,180uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(215uy,48uy,39uy); C3b(252uy,141uy,89uy); C3b(254uy,224uy,144uy); C3b(255uy,255uy,191uy) C3b(224uy,243uy,248uy); C3b(145uy,191uy,219uy); C3b(69uy,117uy,180uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(215uy,48uy,39uy); C3b(244uy,109uy,67uy); C3b(253uy,174uy,97uy); C3b(254uy,224uy,144uy) C3b(224uy,243uy,248uy); C3b(171uy,217uy,233uy); C3b(116uy,173uy,209uy); C3b(69uy,117uy,180uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(215uy,48uy,39uy); C3b(244uy,109uy,67uy); C3b(253uy,174uy,97uy); C3b(254uy,224uy,144uy) C3b(255uy,255uy,191uy); C3b(224uy,243uy,248uy); C3b(171uy,217uy,233uy); C3b(116uy,173uy,209uy) C3b(69uy,117uy,180uy) |] } 10, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(165uy,0uy,38uy); C3b(215uy,48uy,39uy); C3b(244uy,109uy,67uy); C3b(253uy,174uy,97uy) C3b(254uy,224uy,144uy); C3b(224uy,243uy,248uy); C3b(171uy,217uy,233uy); C3b(116uy,173uy,209uy) C3b(69uy,117uy,180uy); C3b(49uy,54uy,149uy) |] } 11, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(165uy,0uy,38uy); C3b(215uy,48uy,39uy); C3b(244uy,109uy,67uy); C3b(253uy,174uy,97uy) C3b(254uy,224uy,144uy); C3b(255uy,255uy,191uy); C3b(224uy,243uy,248uy); C3b(171uy,217uy,233uy) C3b(116uy,173uy,209uy); C3b(69uy,117uy,180uy); C3b(49uy,54uy,149uy) |] } ] } let BrBG = { Name = Sym.ofString "BrBG" Type = SchemeType.Diverging Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(216uy,179uy,101uy); C3b(245uy,245uy,245uy); C3b(90uy,180uy,172uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(166uy,97uy,26uy); C3b(223uy,194uy,125uy); C3b(128uy,205uy,193uy); C3b(1uy,133uy,113uy) |] } 5, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(166uy,97uy,26uy); C3b(223uy,194uy,125uy); C3b(245uy,245uy,245uy); C3b(128uy,205uy,193uy) C3b(1uy,133uy,113uy) |] } 6, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(140uy,81uy,10uy); C3b(216uy,179uy,101uy); C3b(246uy,232uy,195uy); C3b(199uy,234uy,229uy) C3b(90uy,180uy,172uy); C3b(1uy,102uy,94uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(140uy,81uy,10uy); C3b(216uy,179uy,101uy); C3b(246uy,232uy,195uy); C3b(245uy,245uy,245uy) C3b(199uy,234uy,229uy); C3b(90uy,180uy,172uy); C3b(1uy,102uy,94uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(140uy,81uy,10uy); C3b(191uy,129uy,45uy); C3b(223uy,194uy,125uy); C3b(246uy,232uy,195uy) C3b(199uy,234uy,229uy); C3b(128uy,205uy,193uy); C3b(53uy,151uy,143uy); C3b(1uy,102uy,94uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(140uy,81uy,10uy); C3b(191uy,129uy,45uy); C3b(223uy,194uy,125uy); C3b(246uy,232uy,195uy) C3b(245uy,245uy,245uy); C3b(199uy,234uy,229uy); C3b(128uy,205uy,193uy); C3b(53uy,151uy,143uy) C3b(1uy,102uy,94uy) |] } 10, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(84uy,48uy,5uy); C3b(140uy,81uy,10uy); C3b(191uy,129uy,45uy); C3b(223uy,194uy,125uy) C3b(246uy,232uy,195uy); C3b(199uy,234uy,229uy); C3b(128uy,205uy,193uy); C3b(53uy,151uy,143uy) C3b(1uy,102uy,94uy); C3b(0uy,60uy,48uy) |] } 11, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(84uy,48uy,5uy); C3b(140uy,81uy,10uy); C3b(191uy,129uy,45uy); C3b(223uy,194uy,125uy) C3b(246uy,232uy,195uy); C3b(245uy,245uy,245uy); C3b(199uy,234uy,229uy); C3b(128uy,205uy,193uy) C3b(53uy,151uy,143uy); C3b(1uy,102uy,94uy); C3b(0uy,60uy,48uy) |] } ] } let RdGy = { Name = Sym.ofString "RdGy" Type = SchemeType.Diverging Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(239uy,138uy,98uy); C3b(255uy,255uy,255uy); C3b(153uy,153uy,153uy) |] } 4, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(202uy,0uy,32uy); C3b(244uy,165uy,130uy); C3b(186uy,186uy,186uy); C3b(64uy,64uy,64uy) |] } 5, { Usage = PaletteUsage.Print Colors = [| C3b(202uy,0uy,32uy); C3b(244uy,165uy,130uy); C3b(255uy,255uy,255uy); C3b(186uy,186uy,186uy) C3b(64uy,64uy,64uy) |] } 6, { Usage = PaletteUsage.None Colors = [| C3b(178uy,24uy,43uy); C3b(239uy,138uy,98uy); C3b(253uy,219uy,199uy); C3b(224uy,224uy,224uy) C3b(153uy,153uy,153uy); C3b(77uy,77uy,77uy) |] } 7, { Usage = PaletteUsage.None Colors = [| C3b(178uy,24uy,43uy); C3b(239uy,138uy,98uy); C3b(253uy,219uy,199uy); C3b(255uy,255uy,255uy) C3b(224uy,224uy,224uy); C3b(153uy,153uy,153uy); C3b(77uy,77uy,77uy) |] } 8, { Usage = PaletteUsage.None Colors = [| C3b(178uy,24uy,43uy); C3b(214uy,96uy,77uy); C3b(244uy,165uy,130uy); C3b(253uy,219uy,199uy) C3b(224uy,224uy,224uy); C3b(186uy,186uy,186uy); C3b(135uy,135uy,135uy); C3b(77uy,77uy,77uy) |] } 9, { Usage = PaletteUsage.None Colors = [| C3b(178uy,24uy,43uy); C3b(214uy,96uy,77uy); C3b(244uy,165uy,130uy); C3b(253uy,219uy,199uy) C3b(255uy,255uy,255uy); C3b(224uy,224uy,224uy); C3b(186uy,186uy,186uy); C3b(135uy,135uy,135uy) C3b(77uy,77uy,77uy) |] } 10, { Usage = PaletteUsage.None Colors = [| C3b(103uy,0uy,31uy); C3b(178uy,24uy,43uy); C3b(214uy,96uy,77uy); C3b(244uy,165uy,130uy) C3b(253uy,219uy,199uy); C3b(224uy,224uy,224uy); C3b(186uy,186uy,186uy); C3b(135uy,135uy,135uy) C3b(77uy,77uy,77uy); C3b(26uy,26uy,26uy) |] } 11, { Usage = PaletteUsage.None Colors = [| C3b(103uy,0uy,31uy); C3b(178uy,24uy,43uy); C3b(214uy,96uy,77uy); C3b(244uy,165uy,130uy) C3b(253uy,219uy,199uy); C3b(255uy,255uy,255uy); C3b(224uy,224uy,224uy); C3b(186uy,186uy,186uy) C3b(135uy,135uy,135uy); C3b(77uy,77uy,77uy); C3b(26uy,26uy,26uy) |] } ] } let PuOr = { Name = Sym.ofString "PuOr" Type = SchemeType.Diverging Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(241uy,163uy,64uy); C3b(247uy,247uy,247uy); C3b(153uy,142uy,195uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(230uy,97uy,1uy); C3b(253uy,184uy,99uy); C3b(178uy,171uy,210uy); C3b(94uy,60uy,153uy) |] } 5, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.LCD Colors = [| C3b(230uy,97uy,1uy); C3b(253uy,184uy,99uy); C3b(247uy,247uy,247uy); C3b(178uy,171uy,210uy) C3b(94uy,60uy,153uy) |] } 6, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.LCD Colors = [| C3b(179uy,88uy,6uy); C3b(241uy,163uy,64uy); C3b(254uy,224uy,182uy); C3b(216uy,218uy,235uy) C3b(153uy,142uy,195uy); C3b(84uy,39uy,136uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(179uy,88uy,6uy); C3b(241uy,163uy,64uy); C3b(254uy,224uy,182uy); C3b(247uy,247uy,247uy) C3b(216uy,218uy,235uy); C3b(153uy,142uy,195uy); C3b(84uy,39uy,136uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(179uy,88uy,6uy); C3b(224uy,130uy,20uy); C3b(253uy,184uy,99uy); C3b(254uy,224uy,182uy) C3b(216uy,218uy,235uy); C3b(178uy,171uy,210uy); C3b(128uy,115uy,172uy); C3b(84uy,39uy,136uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(179uy,88uy,6uy); C3b(224uy,130uy,20uy); C3b(253uy,184uy,99uy); C3b(254uy,224uy,182uy) C3b(247uy,247uy,247uy); C3b(216uy,218uy,235uy); C3b(178uy,171uy,210uy); C3b(128uy,115uy,172uy) C3b(84uy,39uy,136uy) |] } 10, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(127uy,59uy,8uy); C3b(179uy,88uy,6uy); C3b(224uy,130uy,20uy); C3b(253uy,184uy,99uy) C3b(254uy,224uy,182uy); C3b(216uy,218uy,235uy); C3b(178uy,171uy,210uy); C3b(128uy,115uy,172uy) C3b(84uy,39uy,136uy); C3b(45uy,0uy,75uy) |] } 11, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(127uy,59uy,8uy); C3b(179uy,88uy,6uy); C3b(224uy,130uy,20uy); C3b(253uy,184uy,99uy) C3b(254uy,224uy,182uy); C3b(247uy,247uy,247uy); C3b(216uy,218uy,235uy); C3b(178uy,171uy,210uy) C3b(128uy,115uy,172uy); C3b(84uy,39uy,136uy); C3b(45uy,0uy,75uy) |] } ] } /// Qualitative schemes do not imply magnitude differences between legend classes, and hues are used to /// create the primary visual differences between classes. Qualitative schemes are best suited to representing nominal or categorical data. module Qualitative = let Set2 = { Name = Sym.ofString "Set2" Type = SchemeType.Qualitative Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(102uy,194uy,165uy); C3b(252uy,141uy,98uy); C3b(141uy,160uy,203uy) |] } 4, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(102uy,194uy,165uy); C3b(252uy,141uy,98uy); C3b(141uy,160uy,203uy); C3b(231uy,138uy,195uy) |] } 5, { Usage = PaletteUsage.Print Colors = [| C3b(102uy,194uy,165uy); C3b(252uy,141uy,98uy); C3b(141uy,160uy,203uy); C3b(231uy,138uy,195uy) C3b(166uy,216uy,84uy) |] } 6, { Usage = PaletteUsage.None Colors = [| C3b(102uy,194uy,165uy); C3b(252uy,141uy,98uy); C3b(141uy,160uy,203uy); C3b(231uy,138uy,195uy) C3b(166uy,216uy,84uy); C3b(255uy,217uy,47uy) |] } 7, { Usage = PaletteUsage.None Colors = [| C3b(102uy,194uy,165uy); C3b(252uy,141uy,98uy); C3b(141uy,160uy,203uy); C3b(231uy,138uy,195uy) C3b(166uy,216uy,84uy); C3b(255uy,217uy,47uy); C3b(229uy,196uy,148uy) |] } 8, { Usage = PaletteUsage.None Colors = [| C3b(102uy,194uy,165uy); C3b(252uy,141uy,98uy); C3b(141uy,160uy,203uy); C3b(231uy,138uy,195uy) C3b(166uy,216uy,84uy); C3b(255uy,217uy,47uy); C3b(229uy,196uy,148uy); C3b(179uy,179uy,179uy) |] } ] } let Accent = { Name = Sym.ofString "Accent" Type = SchemeType.Qualitative Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(127uy,201uy,127uy); C3b(190uy,174uy,212uy); C3b(253uy,192uy,134uy) |] } 4, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(127uy,201uy,127uy); C3b(190uy,174uy,212uy); C3b(253uy,192uy,134uy); C3b(255uy,255uy,153uy) |] } 5, { Usage = PaletteUsage.LCD Colors = [| C3b(127uy,201uy,127uy); C3b(190uy,174uy,212uy); C3b(253uy,192uy,134uy); C3b(255uy,255uy,153uy) C3b(56uy,108uy,176uy) |] } 6, { Usage = PaletteUsage.None Colors = [| C3b(127uy,201uy,127uy); C3b(190uy,174uy,212uy); C3b(253uy,192uy,134uy); C3b(255uy,255uy,153uy) C3b(56uy,108uy,176uy); C3b(240uy,2uy,127uy) |] } 7, { Usage = PaletteUsage.None Colors = [| C3b(127uy,201uy,127uy); C3b(190uy,174uy,212uy); C3b(253uy,192uy,134uy); C3b(255uy,255uy,153uy) C3b(56uy,108uy,176uy); C3b(240uy,2uy,127uy); C3b(191uy,91uy,23uy) |] } 8, { Usage = PaletteUsage.None Colors = [| C3b(127uy,201uy,127uy); C3b(190uy,174uy,212uy); C3b(253uy,192uy,134uy); C3b(255uy,255uy,153uy) C3b(56uy,108uy,176uy); C3b(240uy,2uy,127uy); C3b(191uy,91uy,23uy); C3b(102uy,102uy,102uy) |] } ] } let Set1 = { Name = Sym.ofString "Set1" Type = SchemeType.Qualitative Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(228uy,26uy,28uy); C3b(55uy,126uy,184uy); C3b(77uy,175uy,74uy) |] } 4, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(228uy,26uy,28uy); C3b(55uy,126uy,184uy); C3b(77uy,175uy,74uy); C3b(152uy,78uy,163uy) |] } 5, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(228uy,26uy,28uy); C3b(55uy,126uy,184uy); C3b(77uy,175uy,74uy); C3b(152uy,78uy,163uy) C3b(255uy,127uy,0uy) |] } 6, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(228uy,26uy,28uy); C3b(55uy,126uy,184uy); C3b(77uy,175uy,74uy); C3b(152uy,78uy,163uy) C3b(255uy,127uy,0uy); C3b(255uy,255uy,51uy) |] } 7, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(228uy,26uy,28uy); C3b(55uy,126uy,184uy); C3b(77uy,175uy,74uy); C3b(152uy,78uy,163uy) C3b(255uy,127uy,0uy); C3b(255uy,255uy,51uy); C3b(166uy,86uy,40uy) |] } 8, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(228uy,26uy,28uy); C3b(55uy,126uy,184uy); C3b(77uy,175uy,74uy); C3b(152uy,78uy,163uy) C3b(255uy,127uy,0uy); C3b(255uy,255uy,51uy); C3b(166uy,86uy,40uy); C3b(247uy,129uy,191uy) |] } 9, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(228uy,26uy,28uy); C3b(55uy,126uy,184uy); C3b(77uy,175uy,74uy); C3b(152uy,78uy,163uy) C3b(255uy,127uy,0uy); C3b(255uy,255uy,51uy); C3b(166uy,86uy,40uy); C3b(247uy,129uy,191uy) C3b(153uy,153uy,153uy) |] } ] } let Set3 = { Name = Sym.ofString "Set3" Type = SchemeType.Qualitative Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(141uy,211uy,199uy); C3b(255uy,255uy,179uy); C3b(190uy,186uy,218uy) |] } 4, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(141uy,211uy,199uy); C3b(255uy,255uy,179uy); C3b(190uy,186uy,218uy); C3b(251uy,128uy,114uy) |] } 5, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(141uy,211uy,199uy); C3b(255uy,255uy,179uy); C3b(190uy,186uy,218uy); C3b(251uy,128uy,114uy) C3b(128uy,177uy,211uy) |] } 6, { Usage = PaletteUsage.Print Colors = [| C3b(141uy,211uy,199uy); C3b(255uy,255uy,179uy); C3b(190uy,186uy,218uy); C3b(251uy,128uy,114uy) C3b(128uy,177uy,211uy); C3b(253uy,180uy,98uy) |] } 7, { Usage = PaletteUsage.Print Colors = [| C3b(141uy,211uy,199uy); C3b(255uy,255uy,179uy); C3b(190uy,186uy,218uy); C3b(251uy,128uy,114uy) C3b(128uy,177uy,211uy); C3b(253uy,180uy,98uy); C3b(179uy,222uy,105uy) |] } 8, { Usage = PaletteUsage.Print Colors = [| C3b(141uy,211uy,199uy); C3b(255uy,255uy,179uy); C3b(190uy,186uy,218uy); C3b(251uy,128uy,114uy) C3b(128uy,177uy,211uy); C3b(253uy,180uy,98uy); C3b(179uy,222uy,105uy); C3b(252uy,205uy,229uy) |] } 9, { Usage = PaletteUsage.None Colors = [| C3b(141uy,211uy,199uy); C3b(255uy,255uy,179uy); C3b(190uy,186uy,218uy); C3b(251uy,128uy,114uy) C3b(128uy,177uy,211uy); C3b(253uy,180uy,98uy); C3b(179uy,222uy,105uy); C3b(252uy,205uy,229uy) C3b(217uy,217uy,217uy) |] } 10, { Usage = PaletteUsage.None Colors = [| C3b(141uy,211uy,199uy); C3b(255uy,255uy,179uy); C3b(190uy,186uy,218uy); C3b(251uy,128uy,114uy) C3b(128uy,177uy,211uy); C3b(253uy,180uy,98uy); C3b(179uy,222uy,105uy); C3b(252uy,205uy,229uy) C3b(217uy,217uy,217uy); C3b(188uy,128uy,189uy) |] } 11, { Usage = PaletteUsage.None Colors = [| C3b(141uy,211uy,199uy); C3b(255uy,255uy,179uy); C3b(190uy,186uy,218uy); C3b(251uy,128uy,114uy) C3b(128uy,177uy,211uy); C3b(253uy,180uy,98uy); C3b(179uy,222uy,105uy); C3b(252uy,205uy,229uy) C3b(217uy,217uy,217uy); C3b(188uy,128uy,189uy); C3b(204uy,235uy,197uy) |] } 12, { Usage = PaletteUsage.None Colors = [| C3b(141uy,211uy,199uy); C3b(255uy,255uy,179uy); C3b(190uy,186uy,218uy); C3b(251uy,128uy,114uy) C3b(128uy,177uy,211uy); C3b(253uy,180uy,98uy); C3b(179uy,222uy,105uy); C3b(252uy,205uy,229uy) C3b(217uy,217uy,217uy); C3b(188uy,128uy,189uy); C3b(204uy,235uy,197uy); C3b(255uy,237uy,111uy) |] } ] } let Dark2 = { Name = Sym.ofString "Dark2" Type = SchemeType.Qualitative Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(27uy,158uy,119uy); C3b(217uy,95uy,2uy); C3b(117uy,112uy,179uy) |] } 4, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(27uy,158uy,119uy); C3b(217uy,95uy,2uy); C3b(117uy,112uy,179uy); C3b(231uy,41uy,138uy) |] } 5, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(27uy,158uy,119uy); C3b(217uy,95uy,2uy); C3b(117uy,112uy,179uy); C3b(231uy,41uy,138uy) C3b(102uy,166uy,30uy) |] } 6, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(27uy,158uy,119uy); C3b(217uy,95uy,2uy); C3b(117uy,112uy,179uy); C3b(231uy,41uy,138uy) C3b(102uy,166uy,30uy); C3b(230uy,171uy,2uy) |] } 7, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(27uy,158uy,119uy); C3b(217uy,95uy,2uy); C3b(117uy,112uy,179uy); C3b(231uy,41uy,138uy) C3b(102uy,166uy,30uy); C3b(230uy,171uy,2uy); C3b(166uy,118uy,29uy) |] } 8, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(27uy,158uy,119uy); C3b(217uy,95uy,2uy); C3b(117uy,112uy,179uy); C3b(231uy,41uy,138uy) C3b(102uy,166uy,30uy); C3b(230uy,171uy,2uy); C3b(166uy,118uy,29uy); C3b(102uy,102uy,102uy) |] } ] } let Paired = { Name = Sym.ofString "Paired" Type = SchemeType.Qualitative Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(166uy,206uy,227uy); C3b(31uy,120uy,180uy); C3b(178uy,223uy,138uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(166uy,206uy,227uy); C3b(31uy,120uy,180uy); C3b(178uy,223uy,138uy); C3b(51uy,160uy,44uy) |] } 5, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(166uy,206uy,227uy); C3b(31uy,120uy,180uy); C3b(178uy,223uy,138uy); C3b(51uy,160uy,44uy) C3b(251uy,154uy,153uy) |] } 6, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(166uy,206uy,227uy); C3b(31uy,120uy,180uy); C3b(178uy,223uy,138uy); C3b(51uy,160uy,44uy) C3b(251uy,154uy,153uy); C3b(227uy,26uy,28uy) |] } 7, { Usage = PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(166uy,206uy,227uy); C3b(31uy,120uy,180uy); C3b(178uy,223uy,138uy); C3b(51uy,160uy,44uy) C3b(251uy,154uy,153uy); C3b(227uy,26uy,28uy); C3b(253uy,191uy,111uy) |] } 8, { Usage = PaletteUsage.LCD Colors = [| C3b(166uy,206uy,227uy); C3b(31uy,120uy,180uy); C3b(178uy,223uy,138uy); C3b(51uy,160uy,44uy) C3b(251uy,154uy,153uy); C3b(227uy,26uy,28uy); C3b(253uy,191uy,111uy); C3b(255uy,127uy,0uy) |] } 9, { Usage = PaletteUsage.LCD Colors = [| C3b(166uy,206uy,227uy); C3b(31uy,120uy,180uy); C3b(178uy,223uy,138uy); C3b(51uy,160uy,44uy) C3b(251uy,154uy,153uy); C3b(227uy,26uy,28uy); C3b(253uy,191uy,111uy); C3b(255uy,127uy,0uy) C3b(202uy,178uy,214uy) |] } 10, { Usage = PaletteUsage.LCD Colors = [| C3b(166uy,206uy,227uy); C3b(31uy,120uy,180uy); C3b(178uy,223uy,138uy); C3b(51uy,160uy,44uy) C3b(251uy,154uy,153uy); C3b(227uy,26uy,28uy); C3b(253uy,191uy,111uy); C3b(255uy,127uy,0uy) C3b(202uy,178uy,214uy); C3b(106uy,61uy,154uy) |] } 11, { Usage = PaletteUsage.None Colors = [| C3b(166uy,206uy,227uy); C3b(31uy,120uy,180uy); C3b(178uy,223uy,138uy); C3b(51uy,160uy,44uy) C3b(251uy,154uy,153uy); C3b(227uy,26uy,28uy); C3b(253uy,191uy,111uy); C3b(255uy,127uy,0uy) C3b(202uy,178uy,214uy); C3b(106uy,61uy,154uy); C3b(255uy,255uy,153uy) |] } 12, { Usage = PaletteUsage.None Colors = [| C3b(166uy,206uy,227uy); C3b(31uy,120uy,180uy); C3b(178uy,223uy,138uy); C3b(51uy,160uy,44uy) C3b(251uy,154uy,153uy); C3b(227uy,26uy,28uy); C3b(253uy,191uy,111uy); C3b(255uy,127uy,0uy) C3b(202uy,178uy,214uy); C3b(106uy,61uy,154uy); C3b(255uy,255uy,153uy); C3b(177uy,89uy,40uy) |] } ] } let Pastel2 = { Name = Sym.ofString "Pastel2" Type = SchemeType.Qualitative Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.None Colors = [| C3b(179uy,226uy,205uy); C3b(253uy,205uy,172uy); C3b(203uy,213uy,232uy) |] } 4, { Usage = PaletteUsage.None Colors = [| C3b(179uy,226uy,205uy); C3b(253uy,205uy,172uy); C3b(203uy,213uy,232uy); C3b(244uy,202uy,228uy) |] } 5, { Usage = PaletteUsage.None Colors = [| C3b(179uy,226uy,205uy); C3b(253uy,205uy,172uy); C3b(203uy,213uy,232uy); C3b(244uy,202uy,228uy) C3b(230uy,245uy,201uy) |] } 6, { Usage = PaletteUsage.None Colors = [| C3b(179uy,226uy,205uy); C3b(253uy,205uy,172uy); C3b(203uy,213uy,232uy); C3b(244uy,202uy,228uy) C3b(230uy,245uy,201uy); C3b(255uy,242uy,174uy) |] } 7, { Usage = PaletteUsage.None Colors = [| C3b(179uy,226uy,205uy); C3b(253uy,205uy,172uy); C3b(203uy,213uy,232uy); C3b(244uy,202uy,228uy) C3b(230uy,245uy,201uy); C3b(255uy,242uy,174uy); C3b(241uy,226uy,204uy) |] } 8, { Usage = PaletteUsage.None Colors = [| C3b(179uy,226uy,205uy); C3b(253uy,205uy,172uy); C3b(203uy,213uy,232uy); C3b(244uy,202uy,228uy) C3b(230uy,245uy,201uy); C3b(255uy,242uy,174uy); C3b(241uy,226uy,204uy); C3b(204uy,204uy,204uy) |] } ] } let Pastel1 = { Name = Sym.ofString "Pastel1" Type = SchemeType.Qualitative Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.None Colors = [| C3b(251uy,180uy,174uy); C3b(179uy,205uy,227uy); C3b(204uy,235uy,197uy) |] } 4, { Usage = PaletteUsage.None Colors = [| C3b(251uy,180uy,174uy); C3b(179uy,205uy,227uy); C3b(204uy,235uy,197uy); C3b(222uy,203uy,228uy) |] } 5, { Usage = PaletteUsage.None Colors = [| C3b(251uy,180uy,174uy); C3b(179uy,205uy,227uy); C3b(204uy,235uy,197uy); C3b(222uy,203uy,228uy) C3b(254uy,217uy,166uy) |] } 6, { Usage = PaletteUsage.None Colors = [| C3b(251uy,180uy,174uy); C3b(179uy,205uy,227uy); C3b(204uy,235uy,197uy); C3b(222uy,203uy,228uy) C3b(254uy,217uy,166uy); C3b(255uy,255uy,204uy) |] } 7, { Usage = PaletteUsage.None Colors = [| C3b(251uy,180uy,174uy); C3b(179uy,205uy,227uy); C3b(204uy,235uy,197uy); C3b(222uy,203uy,228uy) C3b(254uy,217uy,166uy); C3b(255uy,255uy,204uy); C3b(229uy,216uy,189uy) |] } 8, { Usage = PaletteUsage.None Colors = [| C3b(251uy,180uy,174uy); C3b(179uy,205uy,227uy); C3b(204uy,235uy,197uy); C3b(222uy,203uy,228uy) C3b(254uy,217uy,166uy); C3b(255uy,255uy,204uy); C3b(229uy,216uy,189uy); C3b(253uy,218uy,236uy) |] } 9, { Usage = PaletteUsage.None Colors = [| C3b(251uy,180uy,174uy); C3b(179uy,205uy,227uy); C3b(204uy,235uy,197uy); C3b(222uy,203uy,228uy) C3b(254uy,217uy,166uy); C3b(255uy,255uy,204uy); C3b(229uy,216uy,189uy); C3b(253uy,218uy,236uy) C3b(242uy,242uy,242uy) |] } ] } /// Sequential schemes are suited to ordered data that progress from low to high. /// Lightness steps dominate the look of these schemes, with light colors for low data values to dark colors for high data values. module Sequential = let OrRd = { Name = Sym.ofString "OrRd" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(254uy,232uy,200uy); C3b(253uy,187uy,132uy); C3b(227uy,74uy,51uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(254uy,240uy,217uy); C3b(253uy,204uy,138uy); C3b(252uy,141uy,89uy); C3b(215uy,48uy,31uy) |] } 5, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.LCD Colors = [| C3b(254uy,240uy,217uy); C3b(253uy,204uy,138uy); C3b(252uy,141uy,89uy); C3b(227uy,74uy,51uy) C3b(179uy,0uy,0uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(254uy,240uy,217uy); C3b(253uy,212uy,158uy); C3b(253uy,187uy,132uy); C3b(252uy,141uy,89uy) C3b(227uy,74uy,51uy); C3b(179uy,0uy,0uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(254uy,240uy,217uy); C3b(253uy,212uy,158uy); C3b(253uy,187uy,132uy); C3b(252uy,141uy,89uy) C3b(239uy,101uy,72uy); C3b(215uy,48uy,31uy); C3b(153uy,0uy,0uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,247uy,236uy); C3b(254uy,232uy,200uy); C3b(253uy,212uy,158uy); C3b(253uy,187uy,132uy) C3b(252uy,141uy,89uy); C3b(239uy,101uy,72uy); C3b(215uy,48uy,31uy); C3b(153uy,0uy,0uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,247uy,236uy); C3b(254uy,232uy,200uy); C3b(253uy,212uy,158uy); C3b(253uy,187uy,132uy) C3b(252uy,141uy,89uy); C3b(239uy,101uy,72uy); C3b(215uy,48uy,31uy); C3b(179uy,0uy,0uy) C3b(127uy,0uy,0uy) |] } ] } let PuBu = { Name = Sym.ofString "PuBu" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(236uy,231uy,242uy); C3b(166uy,189uy,219uy); C3b(43uy,140uy,190uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.LCD Colors = [| C3b(241uy,238uy,246uy); C3b(189uy,201uy,225uy); C3b(116uy,169uy,207uy); C3b(5uy,112uy,176uy) |] } 5, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(241uy,238uy,246uy); C3b(189uy,201uy,225uy); C3b(116uy,169uy,207uy); C3b(43uy,140uy,190uy) C3b(4uy,90uy,141uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(241uy,238uy,246uy); C3b(208uy,209uy,230uy); C3b(166uy,189uy,219uy); C3b(116uy,169uy,207uy) C3b(43uy,140uy,190uy); C3b(4uy,90uy,141uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(241uy,238uy,246uy); C3b(208uy,209uy,230uy); C3b(166uy,189uy,219uy); C3b(116uy,169uy,207uy) C3b(54uy,144uy,192uy); C3b(5uy,112uy,176uy); C3b(3uy,78uy,123uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,247uy,251uy); C3b(236uy,231uy,242uy); C3b(208uy,209uy,230uy); C3b(166uy,189uy,219uy) C3b(116uy,169uy,207uy); C3b(54uy,144uy,192uy); C3b(5uy,112uy,176uy); C3b(3uy,78uy,123uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,247uy,251uy); C3b(236uy,231uy,242uy); C3b(208uy,209uy,230uy); C3b(166uy,189uy,219uy) C3b(116uy,169uy,207uy); C3b(54uy,144uy,192uy); C3b(5uy,112uy,176uy); C3b(4uy,90uy,141uy) C3b(2uy,56uy,88uy) |] } ] } let BuPu = { Name = Sym.ofString "BuPu" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(224uy,236uy,244uy); C3b(158uy,188uy,218uy); C3b(136uy,86uy,167uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(237uy,248uy,251uy); C3b(179uy,205uy,227uy); C3b(140uy,150uy,198uy); C3b(136uy,65uy,157uy) |] } 5, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.LCD Colors = [| C3b(237uy,248uy,251uy); C3b(179uy,205uy,227uy); C3b(140uy,150uy,198uy); C3b(136uy,86uy,167uy) C3b(129uy,15uy,124uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(237uy,248uy,251uy); C3b(191uy,211uy,230uy); C3b(158uy,188uy,218uy); C3b(140uy,150uy,198uy) C3b(136uy,86uy,167uy); C3b(129uy,15uy,124uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(237uy,248uy,251uy); C3b(191uy,211uy,230uy); C3b(158uy,188uy,218uy); C3b(140uy,150uy,198uy) C3b(140uy,107uy,177uy); C3b(136uy,65uy,157uy); C3b(110uy,1uy,107uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(247uy,252uy,253uy); C3b(224uy,236uy,244uy); C3b(191uy,211uy,230uy); C3b(158uy,188uy,218uy) C3b(140uy,150uy,198uy); C3b(140uy,107uy,177uy); C3b(136uy,65uy,157uy); C3b(110uy,1uy,107uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(247uy,252uy,253uy); C3b(224uy,236uy,244uy); C3b(191uy,211uy,230uy); C3b(158uy,188uy,218uy) C3b(140uy,150uy,198uy); C3b(140uy,107uy,177uy); C3b(136uy,65uy,157uy); C3b(129uy,15uy,124uy) C3b(77uy,0uy,75uy) |] } ] } let Oranges = { Name = Sym.ofString "Oranges" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(254uy,230uy,206uy); C3b(253uy,174uy,107uy); C3b(230uy,85uy,13uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.LCD Colors = [| C3b(254uy,237uy,222uy); C3b(253uy,190uy,133uy); C3b(253uy,141uy,60uy); C3b(217uy,71uy,1uy) |] } 5, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.LCD Colors = [| C3b(254uy,237uy,222uy); C3b(253uy,190uy,133uy); C3b(253uy,141uy,60uy); C3b(230uy,85uy,13uy) C3b(166uy,54uy,3uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(254uy,237uy,222uy); C3b(253uy,208uy,162uy); C3b(253uy,174uy,107uy); C3b(253uy,141uy,60uy) C3b(230uy,85uy,13uy); C3b(166uy,54uy,3uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(254uy,237uy,222uy); C3b(253uy,208uy,162uy); C3b(253uy,174uy,107uy); C3b(253uy,141uy,60uy) C3b(241uy,105uy,19uy); C3b(217uy,72uy,1uy); C3b(140uy,45uy,4uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,245uy,235uy); C3b(254uy,230uy,206uy); C3b(253uy,208uy,162uy); C3b(253uy,174uy,107uy) C3b(253uy,141uy,60uy); C3b(241uy,105uy,19uy); C3b(217uy,72uy,1uy); C3b(140uy,45uy,4uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,245uy,235uy); C3b(254uy,230uy,206uy); C3b(253uy,208uy,162uy); C3b(253uy,174uy,107uy) C3b(253uy,141uy,60uy); C3b(241uy,105uy,19uy); C3b(217uy,72uy,1uy); C3b(166uy,54uy,3uy) C3b(127uy,39uy,4uy) |] } ] } let BuGn = { Name = Sym.ofString "BuGn" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(229uy,245uy,249uy); C3b(153uy,216uy,201uy); C3b(44uy,162uy,95uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print Colors = [| C3b(237uy,248uy,251uy); C3b(178uy,226uy,226uy); C3b(102uy,194uy,164uy); C3b(35uy,139uy,69uy) |] } 5, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(237uy,248uy,251uy); C3b(178uy,226uy,226uy); C3b(102uy,194uy,164uy); C3b(44uy,162uy,95uy) C3b(0uy,109uy,44uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(237uy,248uy,251uy); C3b(204uy,236uy,230uy); C3b(153uy,216uy,201uy); C3b(102uy,194uy,164uy) C3b(44uy,162uy,95uy); C3b(0uy,109uy,44uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(237uy,248uy,251uy); C3b(204uy,236uy,230uy); C3b(153uy,216uy,201uy); C3b(102uy,194uy,164uy) C3b(65uy,174uy,118uy); C3b(35uy,139uy,69uy); C3b(0uy,88uy,36uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(247uy,252uy,253uy); C3b(229uy,245uy,249uy); C3b(204uy,236uy,230uy); C3b(153uy,216uy,201uy) C3b(102uy,194uy,164uy); C3b(65uy,174uy,118uy); C3b(35uy,139uy,69uy); C3b(0uy,88uy,36uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(247uy,252uy,253uy); C3b(229uy,245uy,249uy); C3b(204uy,236uy,230uy); C3b(153uy,216uy,201uy) C3b(102uy,194uy,164uy); C3b(65uy,174uy,118uy); C3b(35uy,139uy,69uy); C3b(0uy,109uy,44uy) C3b(0uy,68uy,27uy) |] } ] } let YlOrBr = { Name = Sym.ofString "YlOrBr" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(255uy,247uy,188uy); C3b(254uy,196uy,79uy); C3b(217uy,95uy,14uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print Colors = [| C3b(255uy,255uy,212uy); C3b(254uy,217uy,142uy); C3b(254uy,153uy,41uy); C3b(204uy,76uy,2uy) |] } 5, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,212uy); C3b(254uy,217uy,142uy); C3b(254uy,153uy,41uy); C3b(217uy,95uy,14uy) C3b(153uy,52uy,4uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,212uy); C3b(254uy,227uy,145uy); C3b(254uy,196uy,79uy); C3b(254uy,153uy,41uy) C3b(217uy,95uy,14uy); C3b(153uy,52uy,4uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,212uy); C3b(254uy,227uy,145uy); C3b(254uy,196uy,79uy); C3b(254uy,153uy,41uy) C3b(236uy,112uy,20uy); C3b(204uy,76uy,2uy); C3b(140uy,45uy,4uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,229uy); C3b(255uy,247uy,188uy); C3b(254uy,227uy,145uy); C3b(254uy,196uy,79uy) C3b(254uy,153uy,41uy); C3b(236uy,112uy,20uy); C3b(204uy,76uy,2uy); C3b(140uy,45uy,4uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,229uy); C3b(255uy,247uy,188uy); C3b(254uy,227uy,145uy); C3b(254uy,196uy,79uy) C3b(254uy,153uy,41uy); C3b(236uy,112uy,20uy); C3b(204uy,76uy,2uy); C3b(153uy,52uy,4uy) C3b(102uy,37uy,6uy) |] } ] } let YlGn = { Name = Sym.ofString "YlGn" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(247uy,252uy,185uy); C3b(173uy,221uy,142uy); C3b(49uy,163uy,84uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(255uy,255uy,204uy); C3b(194uy,230uy,153uy); C3b(120uy,198uy,121uy); C3b(35uy,132uy,67uy) |] } 5, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(255uy,255uy,204uy); C3b(194uy,230uy,153uy); C3b(120uy,198uy,121uy); C3b(49uy,163uy,84uy) C3b(0uy,104uy,55uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,204uy); C3b(217uy,240uy,163uy); C3b(173uy,221uy,142uy); C3b(120uy,198uy,121uy) C3b(49uy,163uy,84uy); C3b(0uy,104uy,55uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,204uy); C3b(217uy,240uy,163uy); C3b(173uy,221uy,142uy); C3b(120uy,198uy,121uy) C3b(65uy,171uy,93uy); C3b(35uy,132uy,67uy); C3b(0uy,90uy,50uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,229uy); C3b(247uy,252uy,185uy); C3b(217uy,240uy,163uy); C3b(173uy,221uy,142uy) C3b(120uy,198uy,121uy); C3b(65uy,171uy,93uy); C3b(35uy,132uy,67uy); C3b(0uy,90uy,50uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,229uy); C3b(247uy,252uy,185uy); C3b(217uy,240uy,163uy); C3b(173uy,221uy,142uy) C3b(120uy,198uy,121uy); C3b(65uy,171uy,93uy); C3b(35uy,132uy,67uy); C3b(0uy,104uy,55uy) C3b(0uy,69uy,41uy) |] } ] } let Reds = { Name = Sym.ofString "Reds" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(254uy,224uy,210uy); C3b(252uy,146uy,114uy); C3b(222uy,45uy,38uy) |] } 4, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(254uy,229uy,217uy); C3b(252uy,174uy,145uy); C3b(251uy,106uy,74uy); C3b(203uy,24uy,29uy) |] } 5, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(254uy,229uy,217uy); C3b(252uy,174uy,145uy); C3b(251uy,106uy,74uy); C3b(222uy,45uy,38uy) C3b(165uy,15uy,21uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(254uy,229uy,217uy); C3b(252uy,187uy,161uy); C3b(252uy,146uy,114uy); C3b(251uy,106uy,74uy) C3b(222uy,45uy,38uy); C3b(165uy,15uy,21uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(254uy,229uy,217uy); C3b(252uy,187uy,161uy); C3b(252uy,146uy,114uy); C3b(251uy,106uy,74uy) C3b(239uy,59uy,44uy); C3b(203uy,24uy,29uy); C3b(153uy,0uy,13uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,245uy,240uy); C3b(254uy,224uy,210uy); C3b(252uy,187uy,161uy); C3b(252uy,146uy,114uy) C3b(251uy,106uy,74uy); C3b(239uy,59uy,44uy); C3b(203uy,24uy,29uy); C3b(153uy,0uy,13uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,245uy,240uy); C3b(254uy,224uy,210uy); C3b(252uy,187uy,161uy); C3b(252uy,146uy,114uy) C3b(251uy,106uy,74uy); C3b(239uy,59uy,44uy); C3b(203uy,24uy,29uy); C3b(165uy,15uy,21uy) C3b(103uy,0uy,13uy) |] } ] } let RdPu = { Name = Sym.ofString "RdPu" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(253uy,224uy,221uy); C3b(250uy,159uy,181uy); C3b(197uy,27uy,138uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(254uy,235uy,226uy); C3b(251uy,180uy,185uy); C3b(247uy,104uy,161uy); C3b(174uy,1uy,126uy) |] } 5, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(254uy,235uy,226uy); C3b(251uy,180uy,185uy); C3b(247uy,104uy,161uy); C3b(197uy,27uy,138uy) C3b(122uy,1uy,119uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(254uy,235uy,226uy); C3b(252uy,197uy,192uy); C3b(250uy,159uy,181uy); C3b(247uy,104uy,161uy) C3b(197uy,27uy,138uy); C3b(122uy,1uy,119uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(254uy,235uy,226uy); C3b(252uy,197uy,192uy); C3b(250uy,159uy,181uy); C3b(247uy,104uy,161uy) C3b(221uy,52uy,151uy); C3b(174uy,1uy,126uy); C3b(122uy,1uy,119uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,247uy,243uy); C3b(253uy,224uy,221uy); C3b(252uy,197uy,192uy); C3b(250uy,159uy,181uy) C3b(247uy,104uy,161uy); C3b(221uy,52uy,151uy); C3b(174uy,1uy,126uy); C3b(122uy,1uy,119uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,247uy,243uy); C3b(253uy,224uy,221uy); C3b(252uy,197uy,192uy); C3b(250uy,159uy,181uy) C3b(247uy,104uy,161uy); C3b(221uy,52uy,151uy); C3b(174uy,1uy,126uy); C3b(122uy,1uy,119uy) C3b(73uy,0uy,106uy) |] } ] } let Greens = { Name = Sym.ofString "Greens" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(229uy,245uy,224uy); C3b(161uy,217uy,155uy); C3b(49uy,163uy,84uy) |] } 4, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(237uy,248uy,233uy); C3b(186uy,228uy,179uy); C3b(116uy,196uy,118uy); C3b(35uy,139uy,69uy) |] } 5, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(237uy,248uy,233uy); C3b(186uy,228uy,179uy); C3b(116uy,196uy,118uy); C3b(49uy,163uy,84uy) C3b(0uy,109uy,44uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(237uy,248uy,233uy); C3b(199uy,233uy,192uy); C3b(161uy,217uy,155uy); C3b(116uy,196uy,118uy) C3b(49uy,163uy,84uy); C3b(0uy,109uy,44uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(237uy,248uy,233uy); C3b(199uy,233uy,192uy); C3b(161uy,217uy,155uy); C3b(116uy,196uy,118uy) C3b(65uy,171uy,93uy); C3b(35uy,139uy,69uy); C3b(0uy,90uy,50uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(247uy,252uy,245uy); C3b(229uy,245uy,224uy); C3b(199uy,233uy,192uy); C3b(161uy,217uy,155uy) C3b(116uy,196uy,118uy); C3b(65uy,171uy,93uy); C3b(35uy,139uy,69uy); C3b(0uy,90uy,50uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(247uy,252uy,245uy); C3b(229uy,245uy,224uy); C3b(199uy,233uy,192uy); C3b(161uy,217uy,155uy) C3b(116uy,196uy,118uy); C3b(65uy,171uy,93uy); C3b(35uy,139uy,69uy); C3b(0uy,109uy,44uy) C3b(0uy,68uy,27uy) |] } ] } let YlGnBu = { Name = Sym.ofString "YlGnBu" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(237uy,248uy,177uy); C3b(127uy,205uy,187uy); C3b(44uy,127uy,184uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(255uy,255uy,204uy); C3b(161uy,218uy,180uy); C3b(65uy,182uy,196uy); C3b(34uy,94uy,168uy) |] } 5, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print Colors = [| C3b(255uy,255uy,204uy); C3b(161uy,218uy,180uy); C3b(65uy,182uy,196uy); C3b(44uy,127uy,184uy) C3b(37uy,52uy,148uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,204uy); C3b(199uy,233uy,180uy); C3b(127uy,205uy,187uy); C3b(65uy,182uy,196uy) C3b(44uy,127uy,184uy); C3b(37uy,52uy,148uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,204uy); C3b(199uy,233uy,180uy); C3b(127uy,205uy,187uy); C3b(65uy,182uy,196uy) C3b(29uy,145uy,192uy); C3b(34uy,94uy,168uy); C3b(12uy,44uy,132uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,217uy); C3b(237uy,248uy,177uy); C3b(199uy,233uy,180uy); C3b(127uy,205uy,187uy) C3b(65uy,182uy,196uy); C3b(29uy,145uy,192uy); C3b(34uy,94uy,168uy); C3b(12uy,44uy,132uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,217uy); C3b(237uy,248uy,177uy); C3b(199uy,233uy,180uy); C3b(127uy,205uy,187uy) C3b(65uy,182uy,196uy); C3b(29uy,145uy,192uy); C3b(34uy,94uy,168uy); C3b(37uy,52uy,148uy) C3b(8uy,29uy,88uy) |] } ] } let Purples = { Name = Sym.ofString "Purples" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(239uy,237uy,245uy); C3b(188uy,189uy,220uy); C3b(117uy,107uy,177uy) |] } 4, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(242uy,240uy,247uy); C3b(203uy,201uy,226uy); C3b(158uy,154uy,200uy); C3b(106uy,81uy,163uy) |] } 5, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(242uy,240uy,247uy); C3b(203uy,201uy,226uy); C3b(158uy,154uy,200uy); C3b(117uy,107uy,177uy) C3b(84uy,39uy,143uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(242uy,240uy,247uy); C3b(218uy,218uy,235uy); C3b(188uy,189uy,220uy); C3b(158uy,154uy,200uy) C3b(117uy,107uy,177uy); C3b(84uy,39uy,143uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(242uy,240uy,247uy); C3b(218uy,218uy,235uy); C3b(188uy,189uy,220uy); C3b(158uy,154uy,200uy) C3b(128uy,125uy,186uy); C3b(106uy,81uy,163uy); C3b(74uy,20uy,134uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(252uy,251uy,253uy); C3b(239uy,237uy,245uy); C3b(218uy,218uy,235uy); C3b(188uy,189uy,220uy) C3b(158uy,154uy,200uy); C3b(128uy,125uy,186uy); C3b(106uy,81uy,163uy); C3b(74uy,20uy,134uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(252uy,251uy,253uy); C3b(239uy,237uy,245uy); C3b(218uy,218uy,235uy); C3b(188uy,189uy,220uy) C3b(158uy,154uy,200uy); C3b(128uy,125uy,186uy); C3b(106uy,81uy,163uy); C3b(84uy,39uy,143uy) C3b(63uy,0uy,125uy) |] } ] } let GnBu = { Name = Sym.ofString "GnBu" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(224uy,243uy,219uy); C3b(168uy,221uy,181uy); C3b(67uy,162uy,202uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(240uy,249uy,232uy); C3b(186uy,228uy,188uy); C3b(123uy,204uy,196uy); C3b(43uy,140uy,190uy) |] } 5, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print Colors = [| C3b(240uy,249uy,232uy); C3b(186uy,228uy,188uy); C3b(123uy,204uy,196uy); C3b(67uy,162uy,202uy) C3b(8uy,104uy,172uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(240uy,249uy,232uy); C3b(204uy,235uy,197uy); C3b(168uy,221uy,181uy); C3b(123uy,204uy,196uy) C3b(67uy,162uy,202uy); C3b(8uy,104uy,172uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(240uy,249uy,232uy); C3b(204uy,235uy,197uy); C3b(168uy,221uy,181uy); C3b(123uy,204uy,196uy) C3b(78uy,179uy,211uy); C3b(43uy,140uy,190uy); C3b(8uy,88uy,158uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(247uy,252uy,240uy); C3b(224uy,243uy,219uy); C3b(204uy,235uy,197uy); C3b(168uy,221uy,181uy) C3b(123uy,204uy,196uy); C3b(78uy,179uy,211uy); C3b(43uy,140uy,190uy); C3b(8uy,88uy,158uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(247uy,252uy,240uy); C3b(224uy,243uy,219uy); C3b(204uy,235uy,197uy); C3b(168uy,221uy,181uy) C3b(123uy,204uy,196uy); C3b(78uy,179uy,211uy); C3b(43uy,140uy,190uy); C3b(8uy,104uy,172uy) C3b(8uy,64uy,129uy) |] } ] } let Greys = { Name = Sym.ofString "Greys" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(240uy,240uy,240uy); C3b(189uy,189uy,189uy); C3b(99uy,99uy,99uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print Colors = [| C3b(247uy,247uy,247uy); C3b(204uy,204uy,204uy); C3b(150uy,150uy,150uy); C3b(82uy,82uy,82uy) |] } 5, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(247uy,247uy,247uy); C3b(204uy,204uy,204uy); C3b(150uy,150uy,150uy); C3b(99uy,99uy,99uy) C3b(37uy,37uy,37uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(247uy,247uy,247uy); C3b(217uy,217uy,217uy); C3b(189uy,189uy,189uy); C3b(150uy,150uy,150uy) C3b(99uy,99uy,99uy); C3b(37uy,37uy,37uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(247uy,247uy,247uy); C3b(217uy,217uy,217uy); C3b(189uy,189uy,189uy); C3b(150uy,150uy,150uy) C3b(115uy,115uy,115uy); C3b(82uy,82uy,82uy); C3b(37uy,37uy,37uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,255uy); C3b(240uy,240uy,240uy); C3b(217uy,217uy,217uy); C3b(189uy,189uy,189uy) C3b(150uy,150uy,150uy); C3b(115uy,115uy,115uy); C3b(82uy,82uy,82uy); C3b(37uy,37uy,37uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,255uy); C3b(240uy,240uy,240uy); C3b(217uy,217uy,217uy); C3b(189uy,189uy,189uy) C3b(150uy,150uy,150uy); C3b(115uy,115uy,115uy); C3b(82uy,82uy,82uy); C3b(37uy,37uy,37uy) C3b(0uy,0uy,0uy) |] } ] } let YlOrRd = { Name = Sym.ofString "YlOrRd" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(255uy,237uy,160uy); C3b(254uy,178uy,76uy); C3b(240uy,59uy,32uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print Colors = [| C3b(255uy,255uy,178uy); C3b(254uy,204uy,92uy); C3b(253uy,141uy,60uy); C3b(227uy,26uy,28uy) |] } 5, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,178uy); C3b(254uy,204uy,92uy); C3b(253uy,141uy,60uy); C3b(240uy,59uy,32uy) C3b(189uy,0uy,38uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,178uy); C3b(254uy,217uy,118uy); C3b(254uy,178uy,76uy); C3b(253uy,141uy,60uy) C3b(240uy,59uy,32uy); C3b(189uy,0uy,38uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,178uy); C3b(254uy,217uy,118uy); C3b(254uy,178uy,76uy); C3b(253uy,141uy,60uy) C3b(252uy,78uy,42uy); C3b(227uy,26uy,28uy); C3b(177uy,0uy,38uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,204uy); C3b(255uy,237uy,160uy); C3b(254uy,217uy,118uy); C3b(254uy,178uy,76uy) C3b(253uy,141uy,60uy); C3b(252uy,78uy,42uy); C3b(227uy,26uy,28uy); C3b(177uy,0uy,38uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,255uy,204uy); C3b(255uy,237uy,160uy); C3b(254uy,217uy,118uy); C3b(254uy,178uy,76uy) C3b(253uy,141uy,60uy); C3b(252uy,78uy,42uy); C3b(227uy,26uy,28uy); C3b(189uy,0uy,38uy) C3b(128uy,0uy,38uy) |] } ] } let PuRd = { Name = Sym.ofString "PuRd" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(231uy,225uy,239uy); C3b(201uy,148uy,199uy); C3b(221uy,28uy,119uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(241uy,238uy,246uy); C3b(215uy,181uy,216uy); C3b(223uy,101uy,176uy); C3b(206uy,18uy,86uy) |] } 5, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD Colors = [| C3b(241uy,238uy,246uy); C3b(215uy,181uy,216uy); C3b(223uy,101uy,176uy); C3b(221uy,28uy,119uy) C3b(152uy,0uy,67uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(241uy,238uy,246uy); C3b(212uy,185uy,218uy); C3b(201uy,148uy,199uy); C3b(223uy,101uy,176uy) C3b(221uy,28uy,119uy); C3b(152uy,0uy,67uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(241uy,238uy,246uy); C3b(212uy,185uy,218uy); C3b(201uy,148uy,199uy); C3b(223uy,101uy,176uy) C3b(231uy,41uy,138uy); C3b(206uy,18uy,86uy); C3b(145uy,0uy,63uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(247uy,244uy,249uy); C3b(231uy,225uy,239uy); C3b(212uy,185uy,218uy); C3b(201uy,148uy,199uy) C3b(223uy,101uy,176uy); C3b(231uy,41uy,138uy); C3b(206uy,18uy,86uy); C3b(145uy,0uy,63uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(247uy,244uy,249uy); C3b(231uy,225uy,239uy); C3b(212uy,185uy,218uy); C3b(201uy,148uy,199uy) C3b(223uy,101uy,176uy); C3b(231uy,41uy,138uy); C3b(206uy,18uy,86uy); C3b(152uy,0uy,67uy) C3b(103uy,0uy,31uy) |] } ] } let Blues = { Name = Sym.ofString "Blues" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(222uy,235uy,247uy); C3b(158uy,202uy,225uy); C3b(49uy,130uy,189uy) |] } 4, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(239uy,243uy,255uy); C3b(189uy,215uy,231uy); C3b(107uy,174uy,214uy); C3b(33uy,113uy,181uy) |] } 5, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(239uy,243uy,255uy); C3b(189uy,215uy,231uy); C3b(107uy,174uy,214uy); C3b(49uy,130uy,189uy) C3b(8uy,81uy,156uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(239uy,243uy,255uy); C3b(198uy,219uy,239uy); C3b(158uy,202uy,225uy); C3b(107uy,174uy,214uy) C3b(49uy,130uy,189uy); C3b(8uy,81uy,156uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(239uy,243uy,255uy); C3b(198uy,219uy,239uy); C3b(158uy,202uy,225uy); C3b(107uy,174uy,214uy) C3b(66uy,146uy,198uy); C3b(33uy,113uy,181uy); C3b(8uy,69uy,148uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(247uy,251uy,255uy); C3b(222uy,235uy,247uy); C3b(198uy,219uy,239uy); C3b(158uy,202uy,225uy) C3b(107uy,174uy,214uy); C3b(66uy,146uy,198uy); C3b(33uy,113uy,181uy); C3b(8uy,69uy,148uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(247uy,251uy,255uy); C3b(222uy,235uy,247uy); C3b(198uy,219uy,239uy); C3b(158uy,202uy,225uy) C3b(107uy,174uy,214uy); C3b(66uy,146uy,198uy); C3b(33uy,113uy,181uy); C3b(8uy,81uy,156uy) C3b(8uy,48uy,107uy) |] } ] } let PuBuGn = { Name = Sym.ofString "PuBuGn" Type = SchemeType.Sequential Palettes = MapExt.ofList [ 3, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.Print ||| PaletteUsage.LCD ||| PaletteUsage.PhotoCopy Colors = [| C3b(236uy,226uy,240uy); C3b(166uy,189uy,219uy); C3b(28uy,144uy,153uy) |] } 4, { Usage = PaletteUsage.ColorBlind ||| PaletteUsage.LCD Colors = [| C3b(246uy,239uy,247uy); C3b(189uy,201uy,225uy); C3b(103uy,169uy,207uy); C3b(2uy,129uy,138uy) |] } 5, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(246uy,239uy,247uy); C3b(189uy,201uy,225uy); C3b(103uy,169uy,207uy); C3b(28uy,144uy,153uy) C3b(1uy,108uy,89uy) |] } 6, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(246uy,239uy,247uy); C3b(208uy,209uy,230uy); C3b(166uy,189uy,219uy); C3b(103uy,169uy,207uy) C3b(28uy,144uy,153uy); C3b(1uy,108uy,89uy) |] } 7, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(246uy,239uy,247uy); C3b(208uy,209uy,230uy); C3b(166uy,189uy,219uy); C3b(103uy,169uy,207uy) C3b(54uy,144uy,192uy); C3b(2uy,129uy,138uy); C3b(1uy,100uy,80uy) |] } 8, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,247uy,251uy); C3b(236uy,226uy,240uy); C3b(208uy,209uy,230uy); C3b(166uy,189uy,219uy) C3b(103uy,169uy,207uy); C3b(54uy,144uy,192uy); C3b(2uy,129uy,138uy); C3b(1uy,100uy,80uy) |] } 9, { Usage = PaletteUsage.ColorBlind Colors = [| C3b(255uy,247uy,251uy); C3b(236uy,226uy,240uy); C3b(208uy,209uy,230uy); C3b(166uy,189uy,219uy) C3b(103uy,169uy,207uy); C3b(54uy,144uy,192uy); C3b(2uy,129uy,138uy); C3b(1uy,108uy,89uy) C3b(1uy,70uy,54uy) |] } ] } /// Array of all available color schemes. let All = [| Diverging.Spectral; Diverging.RdYlGn; Diverging.RdBu; Diverging.PiYG; Diverging.PRGn; Diverging.RdYlBu Diverging.BrBG; Diverging.RdGy; Diverging.PuOr; Qualitative.Set2; Qualitative.Accent; Qualitative.Set1 Qualitative.Set3; Qualitative.Dark2; Qualitative.Paired; Qualitative.Pastel2; Qualitative.Pastel1; Sequential.OrRd Sequential.PuBu; Sequential.BuPu; Sequential.Oranges; Sequential.BuGn; Sequential.YlOrBr; Sequential.YlGn Sequential.Reds; Sequential.RdPu; Sequential.Greens; Sequential.YlGnBu; Sequential.Purples; Sequential.GnBu Sequential.Greys; Sequential.YlOrRd; Sequential.PuRd; Sequential.Blues; Sequential.PuBuGn |] ================================================ FILE: src/Aardvark.Base.FSharp/Color/ColorBrewerSchemes.fsx ================================================ #r "../../../bin/Debug/netstandard2.0/Aardvark.Base.dll" #r "../../../bin/Debug/netstandard2.0/Aardvark.Base.FSharp.dll" #r "../../../bin/Debug/net6.0/FSharp.Data.Adaptive.dll" #r "System.Net.Http.dll" open Aardvark.Base open System open System.IO open System.Text open System.Text.RegularExpressions open System.Net.Http fsi.ShowDeclarationValues <- false let source = let ws = Regex(@"\s+", RegexOptions.Compiled) use client = new HttpClient() use task = client.GetStringAsync "https://raw.githubusercontent.com/axismaps/colorbrewer/master/colorbrewer_schemes.js" task.Wait() task.Result |> String.getLines |> Array.map (fun str -> ws.Replace(str, "")) module Regex = let Scheme = Regex( @"^(?[A-Za-z0-9]+):\{" + @"(?(?:[0-9]:\[.+?\],?)+)" + @"'properties':\{(?.+)\}\},?$", RegexOptions.Multiline ); let Palette = Regex(@"(?[0-9]+):\[(?[0-9'rgb\(\),]+)\]", RegexOptions.Compiled); let Color = Regex(@"'(?rgb\([0-9]{1,3},[0-9]{1,3},[0-9]{1,3}\))'", RegexOptions.Compiled) let RGB = Regex(@"^rgb\((?[0-9]{1,3}),(?[0-9]{1,3}),(?[0-9]{1,3})\)$", RegexOptions.Compiled) let Property = Regex(@"'(?[a-zA-Z]+)':(?:'(?[a-zA-Z]+)'|\[(?[0-9,]+)\])", RegexOptions.Compiled); type Severity = | Warning = 0 | Error = 1 let messages = ResizeArray() let log severity fmt = Printf.kprintf (fun str -> messages.Add (severity, str)) fmt let schemes = source |> Array.choose (fun str -> let m = Regex.Scheme.Match str if m.Success then let schemeName = m.Groups.["Name"].Value try let properties = Regex.Property.Matches m.Groups.["Properties"].Value |> Seq.map (fun p -> let value = if p.Groups.["Value"].Success then p.Groups.["Value"].Value else p.Groups.["PerPaletteValue"].Value p.Groups.["Key"].Value, value ) |> Map.ofSeq let typ = match properties.["type"] with | "div" -> ColorBrewer.SchemeType.Diverging | "qual" -> ColorBrewer.SchemeType.Qualitative | "seq" -> ColorBrewer.SchemeType.Sequential | t -> failwithf "Unknown scheme type '%s'" t let colors = Regex.Palette.Matches m.Groups.["Palettes"].Value |> Seq.map (fun p -> let size = Int32.Parse p.Groups.["Size"].Value let colors = Regex.Color.Matches p.Groups.["Colors"].Value |> Seq.map (fun m -> let m = Regex.RGB.Match m.Groups.["Color"].Value let r = m.Groups.["R"].Value let g = m.Groups.["G"].Value let b = m.Groups.["B"].Value $"C3b({r}uy,{g}uy,{b}uy)" ) |> Array.ofSeq if colors.Length <> size then failwithf "Size mismatch (expected %d but got %d)" size colors.Length colors ) |> Array.ofSeq let getFlags (propertyName : string) = let values = properties.[propertyName] |> String.split "," |> Array.map (fun str -> Int32.Parse str = 1 ) if values.Length >= colors.Length then values elif values.Length = 1 then Array.replicate colors.Length values.[0] else let missing = Array.replicate (colors.Length - values.Length) false log Severity.Warning "Property '%s' in scheme '%s' has %d entries but expected %d." propertyName schemeName values.Length colors.Length Array.concat [values; missing] let blind = getFlags "blind" let print = getFlags "print" let copy = getFlags "copy" let screen = getFlags "screen" let palettes = colors |> Array.mapi (fun i c -> let mutable usage = Set.empty if blind.[i] then usage <- usage |> Set.add ColorBrewer.PaletteUsage.ColorBlind if print.[i] then usage <- usage |> Set.add ColorBrewer.PaletteUsage.Print if copy.[i] then usage <- usage |> Set.add ColorBrewer.PaletteUsage.PhotoCopy if screen.[i] then usage <- usage |> Set.add ColorBrewer.PaletteUsage.LCD c.Length, {| Colors = c; Usage = usage |} ) |> Map.ofArray Some {| Name = schemeName; Type = typ; Palettes = palettes |} with e -> log Severity.Error "Failed to parse scheme %s: %s" schemeName e.Message None else None ) printfn "Found %d schemes" schemes.Length let writeToFile() = let builder = StringBuilder() let writeln indent fmt = Printf.kprintf (fun str -> builder.AppendLine(str |> String.indent indent) |> ignore) fmt let schemeTypeComments = Map.ofList [ ColorBrewer.SchemeType.Diverging, "/// Diverging schemes put equal emphasis on mid-range critical values and extremes at both ends of the data range.\n/// The critical class or break in the middle of the legend is emphasized with light colors and low and high extremes are\n/// emphasized with dark colors that have contrasting hues." ColorBrewer.SchemeType.Qualitative, "/// Qualitative schemes do not imply magnitude differences between legend classes, and hues are used to\n/// create the primary visual differences between classes. Qualitative schemes are best suited to representing nominal or categorical data." ColorBrewer.SchemeType.Sequential, "/// Sequential schemes are suited to ordered data that progress from low to high.\n/// Lightness steps dominate the look of these schemes, with light colors for low data values to dark colors for high data values." ] writeln 0 "namespace Aardvark.Base" writeln 0 "" writeln 0 "[]" writeln 0 "module ColorBrewerSchemes =" writeln 1 "open ColorBrewer" writeln 0 "" writeln 1 "/// Brewer color schemes designed for choropleth map visualizations." writeln 1 "module ColorBrewer =" writeln 0 "" writeln 2 "module Scheme =" writeln 0 "" let grouped = schemes |> Array.groupBy (fun s -> s.Type) for (typ, schemes) in grouped do for c in schemeTypeComments.[typ] |> String.getLines do writeln 3 "%s" c writeln 3 "module %A =" typ writeln 0 "" for s in schemes do writeln 4 "let %s =" s.Name writeln 5 "{" writeln 6 "Name = Sym.ofString \"%s\"" s.Name writeln 6 "Type = SchemeType.%A" s.Type writeln 6 "Palettes =" writeln 7 "MapExt.ofList [" for (KeyValue(n, p)) in s.Palettes do let usage = if Set.isEmpty p.Usage then "PaletteUsage.None" else p.Usage |> Seq.map (fun u -> $"PaletteUsage.{u}") |> String.concat " ||| " let colors = Array.chunkBySize 4 p.Colors |> Array.map (String.concat "; ") colors.[0] <- $"Colors = [| {colors.[0]}" colors.[colors.Length - 1] <- $"{colors.[colors.Length - 1]} |]" writeln 8 "%d, {" n writeln 9 "Usage = %s" usage writeln 9 "%s" colors.[0] for i = 1 to colors.Length - 1 do writeln 12 "%s" colors.[i] writeln 8 "}" writeln 0 "" writeln 7 "]" writeln 5 "}" writeln 0 "" writeln 3 "/// Array of all available color schemes." writeln 3 "let All =" writeln 4 "[|" let all = grouped |> Array.collect (fun (typ, schemes) -> schemes |> Array.map (fun s -> $"{typ}.{s.Name}") ) |> Array.chunkBySize 6 |> Array.map (String.concat "; ") for schemes in all do writeln 5 "%s" schemes writeln 4 "|]" let file = Path.Combine(__SOURCE_DIRECTORY__, "ColorBrewerSchemes.fs") File.writeAllText file (builder.ToString()) for s in schemes do printfn "%s" s.Name printfn "%A" s.Palettes for (s, e) in messages do printfn "[%A] %s" s e writeToFile() ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Geometry/Boundable.fs ================================================ namespace Aardvark.Base.Geometry open System open System.Runtime.CompilerServices open Aardvark.Base type RayHit<'r> = struct val mutable public T : float val mutable public Value : 'r new(t, value) = { T = t; Value = value } end [] module RayHit = let inline create (t : float) (value : 'r) = RayHit(t, value) let inline t (hit : RayHit<'r>) = hit.T let inline value (hit : RayHit<'r>) = hit.Value let map (f : 'a -> 'b) (hit : RayHit<'a>) = RayHit(hit.T, f hit.Value) type RayPart = struct val mutable public Ray : FastRay3d val mutable public TMin : float val mutable public TMax : float [] static member Intersects(x : RayPart, tri : Triangle3d) = let ray = x.Ray.Ray let mutable t = 0.0 if tri.Intersects(ray, x.TMin, x.TMax, &t) then Some t else None [] static member IntersectsV(x : RayPart, tri : Triangle3d) = let ray = x.Ray.Ray let mutable t = 0.0 if tri.Intersects(ray, x.TMin, x.TMax, &t) then ValueSome t else ValueNone [] static member Intersects(x : RayPart, box : Box3d) = let ray = x.Ray let mutable tmin = x.TMin let mutable tmax = x.TMax if ray.Intersects(box, &tmin, &tmax) then Some tmin else None [] static member IntersectsV(x : RayPart, box : Box3d) = let ray = x.Ray let mutable tmin = x.TMin let mutable tmax = x.TMax if ray.Intersects(box, &tmin, &tmax) then ValueSome tmin else ValueNone [] static member Intersects(x : RayPart, sphere : Sphere3d) = let ray = x.Ray.Ray // | (o + t * d - c) |^2 = r^2 // let x = o - c // | (x + t * d) |^2 = r^2 // = r^2 // + + + = r^2 // t^2*() + t*(2*) + ( - r^2) = 0 let dp = ray.Origin - sphere.Center let d = ray.Direction let a = d.LengthSquared let b = 2.0 * Vec.dot d dp let c = dp.LengthSquared - sphere.RadiusSquared let s = b*b - 4.0*a*c if s < 0.0 then None else let s = sqrt s let t1 = (-b + s) / (2.0 * a) let t2 = (-b - s) / (2.0 * a) let t1v = t1 >= x.TMin && t1 <= x.TMax let t2v = t2 >= x.TMin && t2 <= x.TMax if t1v && t2v then Some (min t1 t2) elif t1v then Some t1 elif t2v then Some t2 else None [] static member IntersectsV(x : RayPart, sphere : Sphere3d) = let ray = x.Ray.Ray // | (o + t * d - c) |^2 = r^2 // let x = o - c // | (x + t * d) |^2 = r^2 // = r^2 // + + + = r^2 // t^2*() + t*(2*) + ( - r^2) = 0 let dp = ray.Origin - sphere.Center let d = ray.Direction let a = d.LengthSquared let b = 2.0 * Vec.dot d dp let c = dp.LengthSquared - sphere.RadiusSquared let s = b*b - 4.0*a*c if s < 0.0 then ValueNone else let s = sqrt s let t1 = (-b + s) / (2.0 * a) let t2 = (-b - s) / (2.0 * a) let t1v = t1 >= x.TMin && t1 <= x.TMax let t2v = t2 >= x.TMin && t2 <= x.TMax if t1v && t2v then ValueSome (min t1 t2) elif t1v then ValueSome t1 elif t2v then ValueSome t2 else ValueNone [] static member Intersects(x : RayPart, cylinder : Cylinder3d) = let ray = x.Ray.Ray let tmin = x.TMin let tmax = x.TMax // taken from http://mrl.nyu.edu/~dzorin/rend05/lecture2.pdf let v = ray.Direction let va = cylinder.P1 - cylinder.P0 let la = Vec.length va let va = va / la let dp = ray.Origin - cylinder.P0 let r2 = cylinder.Radius * cylinder.Radius let v' = v - (Vec.dot v va * va) let dp' = dp - (Vec.dot dp va) * va let a = v' |> Vec.lengthSquared let b = 2.0 * (Vec.dot v' dp') let c = Vec.lengthSquared dp' - r2 let s = b*b - 4.0*a*c if s < 0.0 then None else let s = sqrt s let t1 = (-b + s) / (2.0 * a) let t2 = (-b - s) / (2.0 * a) let p0 = Plane3d(va, cylinder.P0) let p1 = Plane3d(va, cylinder.P1) let inline isValid (t : float) = let pt = ray.GetPointOnRay t t >= tmin && t <= tmax && p0.Height pt >= 0.0 && p1.Height pt <= 0.0 let t1 = if isValid t1 then ValueSome t1 else ValueNone let t2 = if isValid t2 then ValueSome t2 else ValueNone let t3 = let mutable t = 0.0 let mutable pt = V3d.Zero if ray.Intersects(p0, &t, &pt) then let d = Vec.lengthSquared (pt - cylinder.P0) if d <= r2 then ValueSome t else ValueNone else ValueNone let t4 = let mutable t = 0.0 let mutable pt = V3d.Zero if ray.Intersects(p1, &t, &pt) then let d = Vec.lengthSquared (pt - cylinder.P1) if d <= r2 then ValueSome t else ValueNone else ValueNone let hits = Array.chooseV id [|t1;t2;t3;t4|] if hits.Length > 0 then hits |> Array.min |> Some else None [] static member IntersectsV(x : RayPart, cylinder : Cylinder3d) = let ray = x.Ray.Ray let tmin = x.TMin let tmax = x.TMax // taken from http://mrl.nyu.edu/~dzorin/rend05/lecture2.pdf let v = ray.Direction let va = cylinder.P1 - cylinder.P0 let la = Vec.length va let va = va / la let dp = ray.Origin - cylinder.P0 let r2 = cylinder.Radius * cylinder.Radius let v' = v - (Vec.dot v va * va) let dp' = dp - (Vec.dot dp va) * va let a = v' |> Vec.lengthSquared let b = 2.0 * (Vec.dot v' dp') let c = Vec.lengthSquared dp' - r2 let s = b*b - 4.0*a*c if s < 0.0 then ValueNone else let s = sqrt s let t1 = (-b + s) / (2.0 * a) let t2 = (-b - s) / (2.0 * a) let p0 = Plane3d(va, cylinder.P0) let p1 = Plane3d(va, cylinder.P1) let inline isValid (t : float) = let pt = ray.GetPointOnRay t t >= tmin && t <= tmax && p0.Height pt >= 0.0 && p1.Height pt <= 0.0 let t1 = if isValid t1 then ValueSome t1 else ValueNone let t2 = if isValid t2 then ValueSome t2 else ValueNone let t3 = let mutable t = 0.0 let mutable pt = V3d.Zero if ray.Intersects(p0, &t, &pt) then let d = Vec.lengthSquared (pt - cylinder.P0) if d <= r2 then ValueSome t else ValueNone else ValueNone let t4 = let mutable t = 0.0 let mutable pt = V3d.Zero if ray.Intersects(p1, &t, &pt) then let d = Vec.lengthSquared (pt - cylinder.P1) if d <= r2 then ValueSome t else ValueNone else ValueNone let hits = Array.chooseV id [|t1;t2;t3;t4|] if hits.Length > 0 then hits |> Array.min |> ValueSome else ValueNone new(ray, min, max) = { Ray = ray; TMin = min; TMax = max } new(ray) = { Ray = ray; TMin = 0.0; TMax = Double.PositiveInfinity } end [] module RayPart = let inline ray (part : RayPart) = part.Ray let inline tmin (part : RayPart) = part.TMin let inline tmax (part : RayPart) = part.TMax let inline ofRay (ray : FastRay3d) = RayPart(ray) let inline create (ray : FastRay3d) (tmin : float) (tmax : float) = RayPart(ray, tmin, tmax) let inline intersect (part : RayPart) a = let inline call (d : ^d) (a : ^a) = ((^d or ^a) : (static member Intersects : ^d * ^a -> float option) (d, a)) call part a let inline intersectV (part : RayPart) a = let inline call (d : ^d) (a : ^a) = ((^d or ^a) : (static member IntersectsV : ^d * ^a -> float voption) (d, a)) call part a [] type PlaneSide = | None = 0x0 | Above = 0x1 | Below = 0x2 | Both = 0x3 [] type Spatial<'a>() = abstract member ComputeBounds : seq<'a> -> Box3d abstract member PlaneSide : Plane3d * 'a -> PlaneSide module Spatial = let private side (pt : V3d) (plane : Plane3d) = let h = plane.Height pt if h > 0.0 then PlaneSide.Above elif h < 0.0 then PlaneSide.Below else PlaneSide.Both let triangle = { new Spatial() with member x.ComputeBounds tris = tris |> Seq.collect (fun t -> [t.P0; t.P1; t.P2]) |> Box3d member x.PlaneSide(plane, tri) = side tri.P0 plane ||| side tri.P1 plane ||| side tri.P2 plane } let box = { new Spatial() with member x.ComputeBounds boxes = Box3d boxes member x.PlaneSide(plane, box) = let hmin = plane.Height box.Min let hmax = plane.Height box.Max if hmin > 0.0 && hmax > 0.0 then PlaneSide.Above elif hmin < 0.0 && hmax < 0.0 then PlaneSide.Below else PlaneSide.Both } let point = { new Spatial() with member x.ComputeBounds pts = pts |> Box3d member x.PlaneSide(plane, pt) = side pt plane } type IRayIntersectable<'a> = abstract member Intersect : tryIntersect : (RayPart -> 'a -> RayHit<'r> option) * part : RayPart -> RayHit<'r> option type ICullable<'a> = abstract member Cull : hull : FastHull3d -> list<'a> [] type GeometryExtensions private() = static let toPlane (v : V4d) = Plane3d(-v.XYZ, v.W) static let toHull3d (viewProj : Trafo3d) = let r0 = viewProj.Forward.R0 let r1 = viewProj.Forward.R1 let r2 = viewProj.Forward.R2 let r3 = viewProj.Forward.R3 Hull3d [| r3 + r0 |> toPlane // left r3 - r0 |> toPlane // right r3 + r1 |> toPlane // bottom r3 - r1 |> toPlane // top r3 + r2 |> toPlane // near r3 - r2 |> toPlane // far |] [] static member inline Intersect(this : IRayIntersectable<_>, part : RayPart) = let intersect (part : RayPart) (value : 'a) = match RayPart.intersect part value with | Some t -> Some (RayHit(t, value)) | None -> None this.Intersect(intersect, part) [] static member CullFrustum(this : ICullable<'a>, viewProj : Trafo3d) = let hull = toHull3d viewProj this.Cull(FastHull3d hull) ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Geometry/Bvh.fs ================================================ namespace Aardvark.Base.Geometry open Aardvark.Base [] type BvhNode = | Leaf of id : int | Node of lBox : Box3d * rBox : Box3d * left : BvhNode * right : BvhNode [] module BvhNode = open Aardvark.Base.Sorting [] let private splitPenalty = 1.0 type private BvhSplit = { leftCount : int rightCount : int sortedIndexArray : int[] leftBox : Box3d rightBox : Box3d } let private cost (lBox : Box3d) (rBox : Box3d) (lWeight : float) (rWeight : float) (invBoxArea : float) = let cBox = Box.Intersection(lBox, rBox) let cSize = V3d( (if cBox.Max.X > cBox.Min.X then cBox.Max.X - cBox.Min.X else 0.0), (if cBox.Max.Y > cBox.Min.Y then cBox.Max.Y - cBox.Min.Y else 0.0), (if cBox.Max.Z > cBox.Min.Z then cBox.Max.Z - cBox.Min.Z else 0.0) ) let leftP = lBox.SurfaceArea * invBoxArea let rightP = rBox.SurfaceArea * invBoxArea let commonP = 2.0 * (cSize.X * cSize.Y + cSize.X * cSize.Z + cSize.Y * cSize.Z) * invBoxArea (leftP + (commonP * splitPenalty)) * (1.0 + lWeight) + (rightP + (commonP * splitPenalty)) * (1.0 + rWeight) let private calculateSplit (indexArray : int[]) (start : int) (count : int) (box : Box3d) (boxes : Box3d[]) = let mutable bestLeft = 0 let mutable bestCost = System.Double.PositiveInfinity let mutable bestLeftBox = Box3d.Invalid let mutable bestRightBox = Box3d.Invalid let mutable bestDim = -1 let invBoxArea = 1.0 / box.SurfaceArea let iaa = Array.init 3 (fun _ -> Array.sub indexArray start count) for d in 0 .. 2 do let ia = iaa.[d] ia.PermutationQuickSortAscending(boxes, fun ba i -> ba.[int i].Center.[d]) let bbLeftArray = ia.ScanLeft(Box3d.Invalid, fun b i -> Box3d(b, boxes.[i])) let bbRightArray = ia.ScanRight((fun i b -> Box3d(boxes.[i], b)), Box3d.Invalid) for s in 1 .. count - 1 do let lBox = bbLeftArray.[s-1] let rBox = bbRightArray.[s] let lWeight = float s let rWeight = float (count - s) let cost = cost lBox rBox lWeight rWeight invBoxArea if cost < bestCost then bestCost <- cost bestDim <- d bestLeft <- s bestLeftBox <- lBox bestRightBox <- rBox { leftCount = bestLeft rightCount = count - bestLeft sortedIndexArray = iaa.[bestDim] leftBox = bestLeftBox rightBox = bestRightBox } let rec build (boxes : Box3d[]) (indices : int[]) (start : int) (count : int) (box : Box3d) = if count = 1 then BvhNode.Leaf(indices.[start]) else let split = calculateSplit indices start count box boxes let left = build boxes split.sortedIndexArray 0 split.leftCount split.leftBox let right = build boxes split.sortedIndexArray split.leftCount split.rightCount split.rightBox BvhNode.Node(split.leftBox, split.rightBox, left, right) let rec intersect (tryIntersect : RayPart -> 'a -> RayHit<'r> option) (data : 'a[]) (part : RayPart) (node : BvhNode) = match node with | BvhNode.Leaf id -> tryIntersect part data.[id] | BvhNode.Node(lBox, rBox, left, right) -> let inline intersect part node = intersect tryIntersect data part node let mutable lpart = part let mutable rpart = part let il = lpart.Ray.Intersects(lBox, &lpart.TMin, &lpart.TMax) let ir = lpart.Ray.Intersects(rBox, &rpart.TMin, &rpart.TMax) match il, ir with | false, false -> None | true, false -> intersect lpart left | false, true -> intersect rpart right | true, true -> if lpart.TMin < rpart.TMin then match intersect lpart left with | Some hit -> if hit.T > rpart.TMin then rpart.TMax <- hit.T match intersect rpart right with | Some hit -> Some hit | None -> Some hit else Some hit | None -> intersect rpart right else match intersect rpart right with | Some hit -> if hit.T > lpart.TMin then lpart.TMax <- hit.T match intersect lpart left with | Some hit -> Some hit | None -> Some hit else Some hit | None -> intersect lpart left let rec intersectV (tryIntersect : RayPart -> 'a -> RayHit<'r> voption) (data : 'a[]) (part : RayPart) (node : BvhNode) = match node with | BvhNode.Leaf id -> tryIntersect part data.[id] | BvhNode.Node(lBox, rBox, left, right) -> let inline intersect part node = intersectV tryIntersect data part node let mutable lpart = part let mutable rpart = part let il = lpart.Ray.Intersects(lBox, &lpart.TMin, &lpart.TMax) let ir = lpart.Ray.Intersects(rBox, &rpart.TMin, &rpart.TMax) match il, ir with | false, false -> ValueNone | true, false -> intersect lpart left | false, true -> intersect rpart right | true, true -> if lpart.TMin < rpart.TMin then match intersect lpart left with | ValueSome hit -> if hit.T > rpart.TMin then rpart.TMax <- hit.T match intersect rpart right with | ValueSome hit -> ValueSome hit | ValueNone -> ValueSome hit else ValueSome hit | ValueNone -> intersect rpart right else match intersect rpart right with | ValueSome hit -> if hit.T > lpart.TMin then lpart.TMax <- hit.T match intersect lpart left with | ValueSome hit -> ValueSome hit | ValueNone -> ValueSome hit else ValueSome hit | ValueNone -> intersect lpart left module Seq = open System.Collections.Generic let rec private mergeSortedAux (cmp : 'a -> 'a -> int) (cl : 'a voption) (cr : 'a voption) (l : IEnumerator<'a>) (r : IEnumerator<'a>) = seq { let cl = match cl with | ValueSome c -> ValueSome c | ValueNone -> if l.MoveNext() then ValueSome l.Current else ValueNone let cr = match cr with | ValueSome c -> ValueSome c | ValueNone -> if r.MoveNext() then ValueSome r.Current else ValueNone match cl, cr with | ValueNone, ValueNone -> () | ValueSome cl, ValueNone -> yield cl yield! mergeSortedAux cmp ValueNone ValueNone l r | ValueNone, ValueSome cr -> yield cr yield! mergeSortedAux cmp ValueNone ValueNone l r | ValueSome vl, ValueSome vr -> let c = cmp vl vr if c < 0 then yield vl yield! mergeSortedAux cmp ValueNone cr l r else yield vr yield! mergeSortedAux cmp cl ValueNone l r } let mergeSorted (cmp : 'a -> 'a -> int) (l : seq<'a>) (r : seq<'a>) = seq { use le = l.GetEnumerator() use re = r.GetEnumerator() yield! mergeSortedAux cmp ValueNone ValueNone le re } let rec intersections (tryIntersect : RayPart -> 'a -> RayHit<'r> option) (data : 'a[]) (part : RayPart) (node : BvhNode) = match node with | BvhNode.Leaf id -> match tryIntersect part data.[id] with | Some h -> Seq.singleton h | None -> Seq.empty | BvhNode.Node(lBox, rBox, left, right) -> let mutable lpart = part let mutable rpart = part let il = lpart.Ray.Intersects(lBox, &lpart.TMin, &lpart.TMax) let ir = lpart.Ray.Intersects(rBox, &rpart.TMin, &rpart.TMax) match il, ir with | false, false -> Seq.empty | true, false -> intersections tryIntersect data lpart left | false, true -> intersections tryIntersect data rpart right | true, true -> seq { if lpart.TMax <= rpart.TMin then // l strictly before r yield! intersections tryIntersect data lpart left yield! intersections tryIntersect data rpart right elif rpart.TMax <= lpart.TMin then // r strictly before l then yield! intersections tryIntersect data rpart right yield! intersections tryIntersect data lpart left else let li = intersections tryIntersect data lpart left let ri = intersections tryIntersect data rpart right yield! Seq.mergeSorted (fun (lh : RayHit<_>) (rh : RayHit<_>) -> compare lh.T rh.T) li ri } let rec intersectionsV (tryIntersect : RayPart -> 'a -> RayHit<'r> voption) (data : 'a[]) (part : RayPart) (node : BvhNode) = match node with | BvhNode.Leaf id -> match tryIntersect part data.[id] with | ValueSome h -> Seq.singleton h | ValueNone -> Seq.empty | BvhNode.Node(lBox, rBox, left, right) -> let mutable lpart = part let mutable rpart = part let il = lpart.Ray.Intersects(lBox, &lpart.TMin, &lpart.TMax) let ir = lpart.Ray.Intersects(rBox, &rpart.TMin, &rpart.TMax) match il, ir with | false, false -> Seq.empty | true, false -> intersectionsV tryIntersect data lpart left | false, true -> intersectionsV tryIntersect data rpart right | true, true -> seq { if lpart.TMax <= rpart.TMin then // l strictly before r yield! intersectionsV tryIntersect data lpart left yield! intersectionsV tryIntersect data rpart right elif rpart.TMax <= lpart.TMin then // r strictly before l then yield! intersectionsV tryIntersect data rpart right yield! intersectionsV tryIntersect data lpart left else let li = intersectionsV tryIntersect data lpart left let ri = intersectionsV tryIntersect data rpart right yield! Seq.mergeSorted (fun (lh : RayHit<_>) (rh : RayHit<_>) -> compare lh.T rh.T) li ri } let cull (hull : FastHull3d) (node : BvhNode) = let rec cullAcc (hull : FastHull3d) (res : System.Collections.Generic.List) (node : BvhNode) = match node with | BvhNode.Leaf id -> res.Add id | BvhNode.Node(lBox, rBox, left, right) -> if hull.Intersects(lBox) then cullAcc hull res left if hull.Intersects(rBox) then cullAcc hull res right let res = System.Collections.Generic.List() cullAcc hull res node res |> CSharpList.toList type BvhTree<'a>(data : 'a[], bounds : Box3d, root : BvhNode option) = member x.Data = data member x.Root = root member x.Bounds = bounds member x.Intersect (tryIntersect : RayPart -> 'a -> RayHit<'r> option, part : RayPart) = match root with | Some root -> let mutable part = part if part.Ray.Intersects(bounds, &part.TMin, &part.TMax) then BvhNode.intersect tryIntersect data part root else None | None -> None member x.IntersectV (tryIntersect : RayPart -> 'a -> RayHit<'r> voption, part : RayPart) = match root with | Some root -> let mutable part = part if part.Ray.Intersects(bounds, &part.TMin, &part.TMax) then BvhNode.intersectV tryIntersect data part root else ValueNone | None -> ValueNone member x.Intersections (tryIntersect : RayPart -> 'a -> RayHit<'r> option, part : RayPart) = match root with | Some root -> let mutable part = part if part.Ray.Intersects(bounds, &part.TMin, &part.TMax) then BvhNode.intersections tryIntersect data part root else Seq.empty | None -> Seq.empty member x.IntersectionsV (tryIntersect : RayPart -> 'a -> RayHit<'r> voption, part : RayPart) = match root with | Some root -> let mutable part = part if part.Ray.Intersects(bounds, &part.TMin, &part.TMax) then BvhNode.intersectionsV tryIntersect data part root else Seq.empty | None -> Seq.empty member x.Cull (hull : FastHull3d) = match root with | Some root -> if hull.Intersects(bounds) then BvhNode.cull hull root |> List.map (Array.get data) else [] | None -> [] interface IRayIntersectable<'a> with member x.Intersect(tryIntersect, ray) = x.Intersect(tryIntersect, ray) interface ICullable<'a> with member x.Cull hull = x.Cull hull new(data : array) = let data = data |> Array.chooseV (fun struct (k, b) -> if b.IsValid then let nb = Box3d.FromCenterAndSize(b.Center, b.Size + V3d(1E-8, 1E-8, 1E-8)) ValueSome <| struct (k, nb) else ValueNone ) if data.Length > 0 then let struct (data, boxes) = data |> Array.unzipV let bounds = Box3d(boxes) let root = BvhNode.build boxes (Array.init boxes.Length id) 0 boxes.Length bounds BvhTree<'a>(data, bounds, Some root) else BvhTree<'a>([||], Box3d.Invalid, None) new(data : array<'a * Box3d>) = let data = data |> Array.chooseV (fun (k, b) -> if b.IsValid then let nb = Box3d.FromCenterAndSize(b.Center, b.Size + V3d(1E-8, 1E-8, 1E-8)) ValueSome <| struct (k, nb) else ValueNone ) if data.Length > 0 then let struct (data, boxes) = data |> Array.unzipV let bounds = Box3d(boxes) let root = BvhNode.build boxes (Array.init boxes.Length id) 0 boxes.Length bounds BvhTree<'a>(data, bounds, Some root) else BvhTree<'a>([||], Box3d.Invalid, None) new(getBounds : 'a -> Box3d, data : 'a[]) = let boxes = data |> Array.map(fun d -> struct (d, getBounds d)) BvhTree<'a>(boxes) [] module BvhTree = let inline ofArray (data : array<'a * Box3d>) = BvhTree(data) let inline ofArrayV (data : array) = BvhTree(data) let inline create (bounds : 'a -> Box3d) (data : array<'a>) = BvhTree(bounds, data) let inline data (tree : BvhTree<'a>) = tree.Data let inline root (tree : BvhTree<'a>) = tree.Root let inline bounds (tree : BvhTree<'a>) = tree.Bounds let inline intersect (tryIntersect : RayPart -> 'a -> RayHit<'r> option) (part : RayPart) (tree : BvhTree<'a>) = tree.Intersect(tryIntersect, part) let inline intersectV (tryIntersect : RayPart -> 'a -> RayHit<'r> voption) (part : RayPart) (tree : BvhTree<'a>) = tree.IntersectV(tryIntersect, part) let inline cull (hull : FastHull3d) (tree : BvhTree<'a>) = tree.Cull(hull) let inline cullFrustum (viewProj : Trafo3d) (tree : BvhTree<'a>) = tree.CullFrustum(viewProj) ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Geometry/KdTree.fs ================================================ namespace Aardvark.Base.Geometry open Aardvark.Base type KdBuildInfo = struct val mutable public MaxCount : int val mutable public Splits : int static member Default = KdBuildInfo(50, 3) static member High = KdBuildInfo(50, 5) new(cnt, splits) = { MaxCount = cnt; Splits = splits } end [] type KdNode = | Empty | Leaf of int[] | Node of Plane3d * KdNode * KdNode [] module KdNode = type private Split = struct val mutable public LeftCount : int val mutable public RightCount : int val mutable public BothCount : int val mutable public Plane : Plane3d val mutable public Cost : float end let private count (spatial : Spatial<'a>) (plane : Plane3d) (indices : int[]) (data : 'a[]) = let mutable left = 0 let mutable right = 0 let mutable both = 0 for i in indices do let side = spatial.PlaneSide(plane, data.[i]) if side &&& PlaneSide.Both = PlaneSide.Both then inc &both elif side &&& PlaneSide.Above = PlaneSide.Above then inc &right elif side &&& PlaneSide.Below = PlaneSide.Below then inc &left (left, both, right) let private cost (parent : Box3d) (lBox : Box3d) (rBox : Box3d) (left : int) (both : int) (right : int) = let sl = lBox.SurfaceArea let sr = rBox.SurfaceArea let sp = parent.SurfaceArea sl * (float left + 2.0 * float both) + sr * (float right + 2.0 * float both) let rec build (spatial : Spatial<'a>) (info : KdBuildInfo) (data : 'a[]) (bounds : Box3d) (indices : int[]) = if indices.Length = 0 then KdNode.Empty elif indices.Length < info.MaxCount then KdNode.Leaf indices else let mutable best = Split(Cost = System.Double.PositiveInfinity) let size = bounds.Size for d in 0 .. 2 do let mutable n = V3d.Zero n.[d] <- 1.0 let s = size.[d] / float (info.Splits + 1) let mutable o = bounds.Min.[d] + s let mutable lBox = bounds let mutable rBox = bounds for _ in 1 .. info.Splits do let p = Plane3d(n, o) lBox.Max.[d] <- o rBox.Min.[d] <- o let l,b,r = count spatial p indices data let cost = cost bounds lBox rBox l b r if cost < best.Cost then best.LeftCount <- l best.BothCount <- b best.RightCount <- r best.Cost <- cost best.Plane <- p o <- o + s if best.BothCount = indices.Length then KdNode.Leaf indices else let mutable lBox = bounds let mutable rBox = bounds lBox.Max.[best.Plane.Normal.MajorDim] <- best.Plane.Distance rBox.Min.[best.Plane.Normal.MajorDim] <- best.Plane.Distance let l = Array.zeroCreate (best.LeftCount + best.BothCount) let r = Array.zeroCreate (best.RightCount + best.BothCount) let mutable li = 0 let mutable ri = 0 for i in indices do let side = spatial.PlaneSide(best.Plane, data.[i]) if (side &&& PlaneSide.Below) <> PlaneSide.None then l.[li] <- i inc &li if (side &&& PlaneSide.Above) <> PlaneSide.None then r.[ri] <- i inc &ri let left = build spatial info data lBox l let right = build spatial info data rBox r KdNode.Node(best.Plane, left, right) let rec intersect (tryIntersect : RayPart -> 'a -> RayHit<'r> option) (data : 'a[]) (part : RayPart) (node : KdNode) = if part.TMax < part.TMin then None else match node with | KdNode.Empty -> None | KdNode.Leaf indices -> let hits = indices |> Array.choose (Array.get data >> tryIntersect part) |> Array.toList match hits with | [] -> None | hits -> hits |> List.minBy _.T |> Some | KdNode.Node(plane, l, r) -> let inline intersect p n = intersect tryIntersect data p n let mutable t = 0.0 let mutable p = V3d.Zero let dir = Vec.dot part.Ray.Ray.Direction plane.Normal part.Ray.Ray.Intersects(plane, &t, &p) |> ignore if dir > 0.0 then if t >= part.TMin && t <= part.TMax then match intersect (RayPart(part.Ray, part.TMin, t)) l with | Some hit -> Some hit | None -> intersect (RayPart(part.Ray, t, part.TMax)) r elif t < part.TMin then intersect part r else (* t > part.TMax *) intersect part l elif dir < 0.0 then if t >= part.TMin && t <= part.TMax then match intersect (RayPart(part.Ray, part.TMin, t)) r with | Some hit -> Some hit | None -> intersect (RayPart(part.Ray, t, part.TMax)) l elif t < part.TMin then intersect part l else (* t > part.TMax *) intersect part r else let h = plane.Height part.Ray.Ray.Origin if h > 0.0 then intersect part r else intersect part l let rec intersectV (tryIntersect : RayPart -> 'a -> RayHit<'r> voption) (data : 'a[]) (part : RayPart) (node : KdNode) = if part.TMax < part.TMin then ValueNone else match node with | KdNode.Empty -> ValueNone | KdNode.Leaf indices -> let hits = indices |> Array.chooseV (Array.get data >> tryIntersect part) |> Array.toList match hits with | [] -> ValueNone | hits -> hits |> List.minBy _.T |> ValueSome | KdNode.Node(plane, l, r) -> let inline intersect p n = intersectV tryIntersect data p n let mutable t = 0.0 let mutable p = V3d.Zero let dir = Vec.dot part.Ray.Ray.Direction plane.Normal part.Ray.Ray.Intersects(plane, &t, &p) |> ignore if dir > 0.0 then if t >= part.TMin && t <= part.TMax then match intersect (RayPart(part.Ray, part.TMin, t)) l with | ValueSome hit -> ValueSome hit | _ -> intersect (RayPart(part.Ray, t, part.TMax)) r elif t < part.TMin then intersect part r else (* t > part.TMax *) intersect part l elif dir < 0.0 then if t >= part.TMin && t <= part.TMax then match intersect (RayPart(part.Ray, part.TMin, t)) r with | ValueSome hit -> ValueSome hit | _ -> intersect (RayPart(part.Ray, t, part.TMax)) l elif t < part.TMin then intersect part l else (* t > part.TMax *) intersect part r else let h = plane.Height part.Ray.Ray.Origin if h > 0.0 then intersect part r else intersect part l type KdTree<'a>(data : 'a[], root : KdNode, bounds : Box3d) = member x.Bounds = bounds member x.Data = data member x.Root = root member x.Intersect(tryIntersect : RayPart -> 'a -> RayHit<'r> option, ray : RayPart) : RayHit<'r> option = let mutable ray = ray if ray.Ray.Intersects(bounds, &ray.TMin, &ray.TMax) then KdNode.intersect tryIntersect data ray root else None member x.IntersectV(tryIntersect : RayPart -> 'a -> RayHit<'r> voption, ray : RayPart) : RayHit<'r> voption = let mutable ray = ray if ray.Ray.Intersects(bounds, &ray.TMin, &ray.TMax) then KdNode.intersectV tryIntersect data ray root else ValueNone interface IRayIntersectable<'a> with member x.Intersect(tryIntersect, ray) = x.Intersect(tryIntersect, ray) new(spatial : Spatial<'a>, info : KdBuildInfo, data : 'a[]) = let bounds = spatial.ComputeBounds (data :> seq<_>) let root = KdNode.build spatial info data bounds (Array.init data.Length id) KdTree(data, root, bounds) new(spatial : Spatial<'a>, data : 'a[]) = KdTree(spatial, KdBuildInfo.Default, data) [] module KdTree = let inline bounds (tree : KdTree<'a>) = tree.Bounds let inline root (tree : KdTree<'a>) = tree.Root let inline data (tree : KdTree<'a>) = tree.Data let inline build (spatial : Spatial<'a>) (info : KdBuildInfo) (data : 'a[]) = KdTree(spatial, info, data) let inline intersect (tryIntersect : RayPart -> 'a -> RayHit<'r> option) (ray : RayPart) (tree : KdTree<'a>) = tree.Intersect(tryIntersect, ray) let inline intersectV (tryIntersect : RayPart -> 'a -> RayHit<'r> voption) (ray : RayPart) (tree : KdTree<'a>) = tree.IntersectV(tryIntersect, ray) ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Immutable/FingerTree.fs ================================================ #if COMPILED namespace Aardvark.Base #else #I @"..\..\bin\Release" #r "Aardvark.Base.dll" open Aardvark.Base #endif open System open System.Collections open System.Collections.Generic /// Measure represents a monoidal measure for the given type 'a /// where 'm has to fulfill monoid laws: /// 1) identity element: a <*> mempty = mempty <*> a = a /// 2) associativity: (a <*> b) <> c = a <*> (b <*> c) type Measure<'a, 'm> = { quantify : 'a -> 'm mappend : 'm -> 'm -> 'm mempty : 'm } [] module private MeasureHelpers = let inline ( +. ) (a : Measure<'a, 'm> -> 'm) (b : Measure<'a, 'm> -> 'm) : Measure<'a, 'm> -> 'm = fun m -> m.mappend (a m) (b m) let inline q (a : 'a) = fun (m : Measure<'a, 'm>) -> m.quantify a let inline cq (m : 'm) = fun (_ : Measure<'a, 'm>) -> m module FingerTreeImplementation = type Affix<'a> = | One of 'a | Two of 'a * 'a | Three of 'a * 'a * 'a | Four of 'a * 'a * 'a * 'a type Node<'a, 'm> = | Node2 of 'm * 'a * 'a | Node3 of 'm * 'a * 'a * 'a with member inline x.Measure = match x with | Node2(m,_,_) -> m | Node3(m,_,_,_) -> m type FingerTreeNode<'a, 'm> = | Empty | Single of 'a | Deep of m : 'm * prefix : Affix<'a> * deeper : FingerTreeNode, 'm> * suffix : Affix<'a> type FingerTreeView<'a, 'm> = | Nil | Cons of 'a * FingerTreeNode<'a, 'm> type FingerTreeSplit<'a, 'm> = { left : FingerTreeNode<'a, 'm>; value : 'a; right : FingerTreeNode<'a, 'm> } type OptionalFingerTreeSplit<'a, 'm> = | Left | Right | Inside of FingerTreeSplit<'a, 'm> module Affix = let inline one a = One(a) let inline two a b = Two(a,b) let inline three a b c = Three(a,b,c) let inline four a b c d = Four(a,b,c,d) let quanitfy (m : Measure<'a, 'm>) (a : Affix<'a>) = match a with | One(a) -> m |> (q a) | Two(a,b) -> m |> (q a) +. (q b) | Three(a,b,c) -> m |> (q a) +. (q b) +. (q c) | Four(a,b,c,d) -> m |> (q a) +. (q b) +. (q c) +. (q d) let prepend (value : 'a) (a : Affix<'a>) = match a with | One(a) -> Two(value, a) | Two(a,b) -> Three(value, a, b) | Three(a,b,c) -> Four(value, a, b, c) | _ -> failwith "affix can only hold 1 to 4 elements" let append (value : 'a) (a : Affix<'a>) = match a with | One(a) -> Two(a, value) | Two(a,b) -> Three(a,b,value) | Three(a,b,c) -> Four(a,b,c,value) | _ -> failwith "affix can only hold 1 to 4 elements" let toNode (m : Measure<'a, 'm>) (a : Affix<'a>) = match a with | Two(a,b) -> Node2(m |> (q a) +. (q b), a, b) | Three(a,b,c) -> Node3(m |> (q a) +. (q b) +. (q c), a, b, c) | _ -> failwith "node can only hold 2 or 3 elements" let ofNode (n : Node<'a, 'm>) = match n with | Node2(_,a,b) -> Two(a,b) | Node3(_,a,b,c) -> Three(a,b,c) let toListFw (a : Affix<'a>) = match a with | One(a) -> [a] | Two(a,b) -> [a;b] | Three(a,b,c) -> [a;b;c] | Four(a,b,c,d) -> [a;b;c;d] let toListBw (a : Affix<'a>) = match a with | One(a) -> [a] | Two(a,b) -> [b;a] | Three(a,b,c) -> [c;b;a] | Four(a,b,c,d) -> [d;c;b;a] let ofList (l : list<'a>) = match l with | [a] -> One(a) | [a;b] -> Two(a,b) | [a;b;c] -> Three(a,b,c) | [a;b;c;d] -> Four(a,b,c,d) | _ -> failwith "affix can only hold 1 to 4 elements" let first (a : Affix<'a>) = match a with | One(a) -> a | Two(a,_) -> a | Three(a,_,_) -> a | Four(a,_,_,_) -> a let last (a : Affix<'a>) = match a with | One(a) -> a | Two(_,a) -> a | Three(_,_,a) -> a | Four(_,_,_,a) -> a let takeFirst (a : Affix<'a>) = match a with | Two(a,b) -> a, One(b) | Three(a,b,c) -> a, Two(b,c) | Four(a,b,c,d) -> a, Three(b,c,d) | _ -> failwith "affix can only hold 1 to 4 elements" let takeLast(a : Affix<'a>) = match a with | Two(a,b) -> b, One(a) | Three(a,b,c) -> c, Two(a,b) | Four(a,b,c,d) -> d, Three(a,b,c) | _ -> failwith "affix can only hold 1 to 4 elements" let split (m : Measure<'a, 'm>) (pred : 'm -> bool) (start : 'm) (affix : Affix<'a>) = match affix with | One(a) -> let s = m.mappend start (m.quantify a) if pred s then None, Some a, None else Some affix, None, None | Two(a,b) -> let s = m.mappend start (m.quantify a) if pred s then None, Some a, Some (One b) else let s = m.mappend s (m.quantify b) if pred s then Some (One a), Some b, None else Some affix, None, None | Three(a,b,c) -> let s = m.mappend start (m.quantify a) if pred s then None, Some a, Some (Two(b,c)) else let s = m.mappend s (m.quantify b) if pred s then Some (One a), Some b, Some (One c) else let s = m.mappend s (m.quantify c) if pred s then Some (Two(a,b)), Some c, None else Some affix, None, None | Four(a,b,c,d) -> let s = m.mappend start (m.quantify a) if pred s then None, Some a, Some (Three(b,c,d)) else let s = m.mappend s (m.quantify b) if pred s then Some (One a), Some b, Some (Two(c,d)) else let s = m.mappend s (m.quantify c) if pred s then Some (Two(a,b)), Some c, Some (One d) else let s = m.mappend s (m.quantify d) if pred s then Some (Three(a,b,c)), Some d, None else Some affix, None, None module Node = let inline two (m : Measure<'a, 'm>) (a : 'a) (b : 'a) = Node2(m |> (q a) +. (q b), a, b) let inline three (m : Measure<'a, 'm>) (a : 'a) (b : 'a) (c : 'a) = Node3(m |> (q a) +. (q b) +. (q c), a, b, c) let inline quantify (n : Node<'a, 'm>) = match n with | Node2(m,_,_) -> m | Node3(m,_,_,_) -> m let inline toAffix (n : Node<'a, 'm>) = Affix.ofNode n let inline ofAffix (m : Measure<'a, 'm>) (a : Affix<'a>) = Affix.toNode m a let toListFw (n : Node<'a, 'm>) = match n with | Node2(_,a,b) -> [a;b] | Node3(_,a,b,c) -> [a;b;c] let toListBw (n : Node<'a, 'm>) = match n with | Node2(_,a,b) -> [b;a] | Node3(_,a,b,c) -> [c;b;a] let ofList (m : Measure<'a, 'm>) (l : list<'a>) = match l with | [a;b] -> Node2(m |> (q a) +. (q b), a, b) | [a;b;c] -> Node3(m |> (q a) +. (q b) +. (q c), a, b, c) | _ -> failwith "node can only hold 2 or 3 elements" let rec manyOfList (m : Measure<'a, 'm>) (l : list<'a>) = match l with | [] | [_] -> failwith "node can only hold 2 or 3 elements" | [a;b] -> [two m a b] | [a;b;c] -> [three m a b c] | a::b::rest -> (two m a b) :: manyOfList m rest let nodesOf (m : Measure<'a, 'm>) (l : Affix<'a>) (r : Affix<'a>) = match l, r with | One(a), One(b) -> [ two m a b ] | Two(a,b), One(c) | One(a), Two(b,c) -> [ three m a b c ] | One(a), Three(b,c,d) | Two(a,b), Two(c,d) | Three(a,b,c), One(d) -> [ two m a b; two m c d ] | One(a), Four(b,c,d,e) | Two(a,b), Three(c,d,e) | Three(a,b,c), Two(d,e) | Four(a,b,c,d), One(e) -> [ two m a b; three m c d e ] | Two(a,b), Four(c,d,e,f) | Three(a,b,c), Three(d,e,f) | Four(a,b,c,d), Two(e,f) -> [ three m a b c; three m d e f ] | Three(a,b,c), Four(d,e,f,g) | Four(a,b,c,d), Three(e,f,g) -> [ two m a b; three m c d e; two m f g ] | Four(a,b,c,d), Four(e,f,g,h) -> [ two m a b; three m c d e; three m f g h ] module Measure = type private NodeMeasureFun<'a, 'm>() = static let measureFun = fun (n : Node<'a, 'm>) -> n.Measure static member MeasureFun = measureFun let node (m : Measure<'a, 'm>) = { quantify = NodeMeasureFun<'a, 'm>.MeasureFun mempty = m.mempty mappend = m.mappend } module FingerTreeNode = [] module private ListExtensions = let rec extractLast (l : list<'a>) = match l with | [a] -> a, [] | a::rest -> let (last, l) = extractLast rest last, a :: l | [] -> failwith "empty list" let (|Snoc|) (l : list<'a>) = Snoc(l |> extractLast) let quanitfy (m : Measure<'a, 'm>) (node : FingerTreeNode<'a, 'm>) = match node with | Empty -> m.mempty | Single v -> m.quantify v | Deep(m,_,_,_) -> m let rec prepend<'a, 'm> (m : Measure<'a, 'm>) (value : 'a) (node : FingerTreeNode<'a, 'm>) : FingerTreeNode<'a, 'm> = match node with | Empty -> Single value | Single y -> Deep( m |> (q y) +. (q value), Affix.one value, Empty, Affix.one y ) | Deep(ann, Four(a,b,c,d), deeper, suffix) -> Deep( m |> (cq ann) +. (q value), Affix.two value a, prepend (Measure.node m) (Node.three m b c d) deeper, suffix ) | Deep(ann, prefix, deeper, suffix) -> Deep( m |> (cq ann) +. (q value), Affix.prepend value prefix, deeper, suffix ) let rec append<'a, 'm> (m : Measure<'a, 'm>) (value : 'a) (node : FingerTreeNode<'a, 'm>) : FingerTreeNode<'a, 'm> = match node with | Empty -> Single value | Single y -> Deep( m |> (q y) +. (q value), Affix.one y, Empty, Affix.one value ) | Deep(ann, prefix, deeper, Four(a,b,c,d)) -> Deep( m |> (cq ann) +. (q value), prefix, append (Measure.node m) (Node.three m a b c) deeper, Affix.two d value ) | Deep(ann, prefix, deeper, suffix) -> Deep( m |> (cq ann) +. (q value), prefix, deeper, Affix.append value suffix ) let ofAffix (m : Measure<'a, 'm>) (a : Affix<'a>) = match a with | One(a) -> Single a | Two(a,b) -> Deep( m |> (q a) +. (q b), Affix.one a, Empty, Affix.one b ) | Three(a,b,c) -> Deep( m |> (q a) +. (q b) +. (q c), Affix.one a, Empty, Affix.two b c ) | Four(a,b,c,d) -> Deep( m |> (q a) +. (q b) +. (q c) +. (q d), Affix.two a b, Empty, Affix.two c d ) let inline ofOptAffix (m : Measure<'a, 'm>) (o : Option>) = match o with | None -> Empty | Some a -> ofAffix m a let rec viewl<'a, 'm> (m : Measure<'a, 'm>) (node : FingerTreeNode<'a, 'm>) : FingerTreeView<'a, 'm> = match node with | Empty -> Nil | Single v -> Cons(v, Empty) | Deep(_, One(a), deeper, suffix) -> match viewl (Measure.node m) deeper with | Nil -> Cons(a, ofAffix m suffix) | Cons(n, rest) -> let pref = Affix.ofNode n let mPref = Affix.quanitfy m pref let mSuff = Affix.quanitfy m suffix let mDeeper = quanitfy (Measure.node m) rest let tail = Deep( m.mappend (m.mappend mPref mDeeper) mSuff, pref, rest, suffix ) Cons(a, tail) | Deep(_,prefix, deeper, suffix) -> let (a, pref) = Affix.takeFirst prefix let mPref = Affix.quanitfy m pref let mSuff = Affix.quanitfy m suffix let mDeeper = quanitfy (Measure.node m) deeper let tail = Deep( m.mappend (m.mappend mPref mDeeper) mSuff, pref, deeper, suffix ) Cons(a, tail) let rec viewr<'a, 'm> (m : Measure<'a, 'm>) (node : FingerTreeNode<'a, 'm>) : FingerTreeView<'a, 'm> = match node with | Empty -> Nil | Single v -> Cons(v, Empty) | Deep(_, prefix, deeper, One(a)) -> match viewr (Measure.node m) deeper with | Nil -> Cons(a, ofAffix m prefix) | Cons(n, rest) -> let suff = Affix.ofNode n let mPref = Affix.quanitfy m prefix let mSuff = Affix.quanitfy m suff let mDeeper = quanitfy (Measure.node m) rest let tail = Deep( m.mappend (m.mappend mPref mDeeper) mSuff, prefix, rest, suff ) Cons(a, tail) | Deep(_,prefix, deeper, suffix) -> let (a, suff) = Affix.takeLast suffix let mPref = Affix.quanitfy m prefix let mSuff = Affix.quanitfy m suff let mDeeper = quanitfy (Measure.node m) deeper let tail = Deep( m.mappend (m.mappend mPref mDeeper) mSuff, prefix, deeper, suff ) Cons(a, tail) let tail (m : Measure<'a,'m>) (node : FingerTreeNode<'a, 'm>) = match viewl m node with | Cons(_,rest) -> rest | _ -> failwith "empty sequence" let init (m : Measure<'a,'m>) (node : FingerTreeNode<'a, 'm>) = match viewr m node with | Cons(_,rest) -> rest | _ -> failwith "empty sequence" let firstOpt (n : FingerTreeNode<'a, 'm>) = match n with | Empty -> None | Single v -> Some v | Deep(_,p,_,_) -> Affix.first p |> Some let lastOpt (n : FingerTreeNode<'a, 'm>) = match n with | Empty -> None | Single v -> Some v | Deep(_,_,_,s) -> Affix.last s |> Some let total (m : Measure<'a, 'm>) (n : FingerTreeNode<'a, 'm>) = match n with | Empty -> m.mempty | Single v -> m.quantify v | Deep(m,_,_,_) -> m let rec deep<'a, 'm> (m : Measure<'a, 'm>) (prefix : Option>) (deeper : FingerTreeNode, 'm>) (suffix : Option>) = match prefix, suffix with | None, None -> match viewl (Measure.node m) deeper with | Cons(n, rest) -> deep m (Some (Affix.ofNode n)) rest None | Nil -> Empty | None, Some s -> match viewl (Measure.node m) deeper with | Cons(n, rest) -> deep m (Some (Affix.ofNode n)) rest suffix | Nil -> ofAffix m s | Some p, None -> match viewr (Measure.node m) deeper with | Cons(n, rest) -> deep m prefix rest (Some (Affix.ofNode n)) | Nil -> ofAffix m p | Some p, Some s -> let mPref = Affix.quanitfy m p let mSuff = Affix.quanitfy m s let mDeeper = quanitfy (Measure.node m) deeper Deep( m.mappend (m.mappend mPref mDeeper) mSuff, p, deeper, s ) let rec split<'a, 'm> (m : Measure<'a, 'm>) (pred : 'm -> bool) (start : 'm) (node : FingerTreeNode<'a, 'm>) : FingerTreeSplit<'a, 'm> = match node with | Empty -> failwith "inconsistent measures in FingerTree" | Single v -> let s = m.mappend start (m.quantify v) if pred s then { left = Empty; value = v; right = Empty} else failwith "inconsistent measures in FingerTree" | Deep(total, prefix, deeper, suffix) -> let current = start let s = m.mappend current (Affix.quanitfy m prefix) if pred s then // inside prefix match Affix.split m pred current prefix with | l, Some s, r -> { left = ofOptAffix m l; value = s; right = deep m r deeper (Some suffix) } | _ -> failwith "inconsistent measures in FingerTree" else let current = s let s = m.mappend current (quanitfy (Measure.node m) deeper) if pred s then // inside deeper let inner = split (Measure.node m) pred current deeper let start = m.mappend current (quanitfy (Measure.node m) inner.left) match Affix.split m pred start (Affix.ofNode inner.value) with | ls, Some s, rp -> { left = deep m (Some prefix) inner.left ls value = s right = deep m rp inner.right (Some suffix) } | _ -> failwith "inconsistent measures in FingerTree" else let current = s let s = m.mappend current (Affix.quanitfy m suffix) if pred s then match Affix.split m pred current suffix with | l, Some s, r -> { left = deep m (Some prefix) deeper l; value = s; right = ofOptAffix m r } | _ -> failwith "inconsistent measures in FingerTree" else failwith "inconsistent measures in FingerTree" let splitFirstRight<'a, 'm> (m : Measure<'a, 'm>) (pred : 'm -> bool) (start : 'm) (node : FingerTreeNode<'a, 'm>) : FingerTreeNode<'a, 'm> * FingerTreeNode<'a, 'm> = match node with | Empty -> (Empty, Empty) | Single v -> let s = m.mappend start (m.quantify v) if pred s then (Empty, Single v) else (Single v, Empty) | Deep(_,prefix,deeper,suffix) -> let current = start let s = m.mappend current (Affix.quanitfy m prefix) if pred s then // inside prefix match Affix.split m pred current prefix with | l, Some s, r -> let r = match r with | Some r -> Affix.prepend s r | None -> One(s) (ofOptAffix m l, deep m (Some r) deeper (Some suffix)) | _ -> failwith "inconsistent measures in FingerTree" else let current = s let s = m.mappend current (quanitfy (Measure.node m) deeper) if pred s then // inside deeper let inner = split (Measure.node m) pred current deeper let start = m.mappend current (quanitfy (Measure.node m) inner.left) match Affix.split m pred start (Affix.ofNode inner.value) with | ls, Some s, rp -> let rp = match rp with | Some r -> Affix.prepend s r | None -> One(s) (deep m (Some prefix) inner.left ls, deep m (Some rp) inner.right (Some suffix)) | _ -> failwith "inconsistent measures in FingerTree" else let current = s let s = m.mappend current (Affix.quanitfy m suffix) if pred s then match Affix.split m pred current suffix with | l, Some s, r -> let r = match r with | Some r -> Affix.prepend s r | None -> One(s) (deep m (Some prefix) deeper l, ofAffix m r) | _ -> failwith "inconsistent measures in FingerTree" else (node, Empty) let trySplit<'a, 'm> (m : Measure<'a, 'm>) (pred : 'm -> bool) (node : FingerTreeNode<'a, 'm>) : OptionalFingerTreeSplit<'a, 'm> = if pred m.mempty then Left elif not (pred (quanitfy m node)) then Right else split m pred m.mempty node |> Inside let rec concatWithMiddle<'a, 'm> (m : Measure<'a, 'm>) (l : FingerTreeNode<'a, 'm>) (mid : list<'a>) (r : FingerTreeNode<'a, 'm>) : FingerTreeNode<'a, 'm> = match l, mid, r with | Empty, [], r -> r | Empty, (x::xs), r -> prepend m x (concatWithMiddle m Empty xs r) | Single y, xs, r -> prepend m y (concatWithMiddle m Empty xs r) | l, [], Empty -> l | l, Snoc(x,xs), Empty -> append m x (concatWithMiddle m l xs Empty) | l, xs, Single y -> append m y (concatWithMiddle m l xs Empty) | Deep(lm, lp, ld, ls), mid, Deep(rm,rp,rd,rs) -> let mid' = Node.manyOfList m (Affix.toListFw ls @ mid @ Affix.toListFw rp) let deeper' = concatWithMiddle (Measure.node m) ld mid' rd let mPref = Affix.quanitfy m lp let mSuff = Affix.quanitfy m rs let mDeeper = quanitfy (Measure.node m) deeper' Deep( m.mappend (m.mappend mPref mDeeper) mSuff, lp, deeper', rs ) let rec toSeqFw<'a, 'm> (n : FingerTreeNode<'a, 'm>) : seq<'a> = match n with | Empty -> Seq.empty | Single v -> Seq.singleton v | Deep(_,prefix, deeper, suffix) -> seq { yield! Affix.toListFw prefix for n in toSeqFw deeper do yield! Node.toListFw n yield! Affix.toListFw suffix } let rec toSeqBw<'a, 'm> (n : FingerTreeNode<'a, 'm>) : seq<'a> = match n with | Empty -> Seq.empty | Single v -> Seq.singleton v | Deep(_,prefix, deeper, suffix) -> seq { yield! Affix.toListBw suffix for n in toSeqBw deeper do yield! Node.toListBw n yield! Affix.toListBw suffix } let getEnumeratorFw<'a, 'm> (n : FingerTreeNode<'a, 'm>) = let s = toSeqFw n s.GetEnumerator() let getEnumeratorBw<'a, 'm> (n : FingerTreeNode<'a, 'm>) = let s = toSeqBw n s.GetEnumerator() open FingerTreeImplementation type private ArrMeasureImpl<'a>() = static let instance = { quantify = fun (a : 'a) -> 1 mempty = 0 mappend = (+) } static member Instance = instance [] type arr<'a> = private { root : FingerTreeNode<'a, int> } with member private x.AsString = if x.Length > 20 then x.root |> FingerTreeNode.toSeqFw |> Seq.take 20 |> Seq.map (sprintf "%A") |> String.concat "; " |> sprintf "arr [%s; ...]" else x.root |> FingerTreeNode.toSeqFw |> Seq.map (sprintf "%A") |> String.concat "; " |> sprintf "arr [%s]" member x.Length = x.root |> FingerTreeNode.quanitfy ArrMeasureImpl<'a>.Instance member x.Item with get (i : int) = if i < 0 || i >= x.Length then raise <| IndexOutOfRangeException() let split = x.root |> FingerTreeNode.split ArrMeasureImpl<'a>.Instance (fun id -> id > i) 0 split.value interface IEnumerable with member x.GetEnumerator() = FingerTreeImplementation.FingerTreeNode.getEnumeratorFw x.root :> IEnumerator interface IEnumerable<'a> with member x.GetEnumerator() = FingerTreeImplementation.FingerTreeNode.getEnumeratorFw x.root [] module Arr = let private mm<'a> = ArrMeasureImpl<'a>.Instance let private outOfRange() = raise <| IndexOutOfRangeException() let empty<'a> : arr<'a> = { root = Empty } let ofSeq (s : seq<'a>) = let mutable res = Empty for e in s do res <- FingerTreeNode.append mm e res { root = res } let inline ofList (l : list<'a>) = ofSeq l let inline ofArray (l : 'a[]) = ofSeq l let toSeq (a : arr<'a>) = a.root |> FingerTreeNode.toSeqFw let inline toList (a : arr<'a>) = a |> toSeq |> Seq.toList let inline toArray (a : arr<'a>) = a |> toSeq |> Seq.toArray let length (a : arr<'a>) = a.root |> FingerTreeNode.quanitfy mm let get (i : int) (a : arr<'a>) = match FingerTreeNode.trySplit mm (fun id -> id > i) a.root with | Inside res -> res.value | _ -> outOfRange() let set (i : int) (value : 'a) (a : arr<'a>) = match FingerTreeNode.trySplit mm (fun id -> id > i) a.root with | Inside res -> { root = FingerTreeNode.concatWithMiddle mm res.left [value] res.right } | _ -> outOfRange() let splitAt (i : int) (a : arr<'a>) = if i = 0 then empty, a else match FingerTreeNode.trySplit mm (fun id -> id > i) a.root with | Inside res -> { root = res.left }, { root = FingerTreeNode.prepend mm res.value res.right } | _ -> outOfRange() let concatWithMiddle (l : arr<'a>) (m : list<'a>) (r : arr<'a>) = { root = FingerTreeNode.concatWithMiddle mm l.root m r.root } let viewl (a : arr<'a>) = match FingerTreeNode.viewl mm a.root with | Cons(a, rest) -> Some(a, { root = rest }) | Nil -> None let viewr (a : arr<'a>) = match FingerTreeNode.viewr mm a.root with | Cons(a, rest) -> Some(a, { root = rest }) | Nil -> None let prepend (value : 'a) (a : arr<'a>) = { root = FingerTreeNode.prepend mm value a.root } let append (value : 'a) (a : arr<'a>) = { root = FingerTreeNode.append mm value a.root } type private SortedMeasureImpl<'a when 'a : comparison>() = static let cmp = Comparer>.Default static let vcmp = Comparer<'a>.Default static let instance = { quantify = Some mempty = None mappend = fun a b -> if cmp.Compare(a,b) > 0 then a else b } static member Instance = instance static member ValueComparer = vcmp [] type SortedList<'a> = private { root : FingerTreeNode<'a, Option<'a>> } with member private x.AsString = x.root |> FingerTreeNode.toSeqFw |> Seq.map (sprintf "%A") |> String.concat "; " |> sprintf "sorted [%s]" interface IEnumerable with member x.GetEnumerator() = FingerTreeImplementation.FingerTreeNode.getEnumeratorFw x.root :> IEnumerator interface IEnumerable<'a> with member x.GetEnumerator() = FingerTreeImplementation.FingerTreeNode.getEnumeratorFw x.root module SortedList = let private mm<'a when 'a : comparison> = SortedMeasureImpl<'a>.Instance let private cmp<'a when 'a : comparison> = SortedMeasureImpl<'a>.ValueComparer let empty<'a> : SortedList<'a> = { root = Empty } let add (v : 'a) (l : SortedList<'a>) = let ov = Some v match FingerTreeNode.trySplit mm (fun i -> i >= ov) l.root with | Left -> { root = FingerTreeNode.prepend mm v l.root } | Right -> { root = FingerTreeNode.append mm v l.root } | Inside split -> if cmp.Compare(v, split.value) = 0 then l else { root = FingerTreeNode.concatWithMiddle mm split.left [v; split.value] split.right} let remove (v : 'a) (l : SortedList<'a>) = let ov = Some v match FingerTreeNode.trySplit mm (fun i -> i >= ov) l.root with | Left -> { root = FingerTreeNode.prepend mm v l.root } | Right -> { root = FingerTreeNode.append mm v l.root } | Inside split -> if cmp.Compare(v, split.value) = 0 then { root = FingerTreeNode.concatWithMiddle mm split.left [] split.right} else l let ofSeq (s : seq<'a>) = let mutable res = empty for e in s do res <- add e res res let inline ofList (l : list<'a>) = ofSeq l let inline ofArray (l : 'a[]) = ofSeq l let toSeq (a : SortedList<'a>) = a.root |> FingerTreeNode.toSeqFw let inline toList (a : SortedList<'a>) = a |> toSeq |> Seq.toList let inline toArray (a : SortedList<'a>) = a |> toSeq |> Seq.toArray let maxOpt (l : SortedList<'a>) = l.root |> FingerTreeNode.lastOpt let minOpt (l : SortedList<'a>) = l.root |> FingerTreeNode.firstOpt let inline max l = (maxOpt l).Value let inline min l = (minOpt l).Value let viewl (a : SortedList<'a>) = match FingerTreeNode.viewl mm a.root with | Cons(a, rest) -> Some(a, { root = rest }) | Nil -> None let viewr (a : SortedList<'a>) = match FingerTreeNode.viewr mm a.root with | Cons(a, rest) -> Some(a, { root = rest }) | Nil -> None module FingerTreeBenchmarks = open System.Diagnostics open System.IO let testPerf (f : unit -> 'a) = let sw = Stopwatch() // warmup for i in 0..100 do f() |> ignore // determine an appropriate iteration count let mutable iterations = 0UL let mutable results = List<'a>(2000) sw.Restart() while sw.Elapsed.TotalMilliseconds < 500.0 do f() |> results.Add iterations <- iterations + 1UL if iterations % 1000UL = 0UL then sw.Stop() results <- List<'a>(2000) System.GC.Collect(3) System.GC.WaitForFullGCComplete() |> ignore System.GC.Collect(3) System.GC.WaitForFullGCApproach() |> ignore sw.Start() // may have produced lots of garbage System.GC.Collect(3) System.GC.WaitForFullGCComplete() |> ignore System.GC.Collect(3) System.GC.WaitForFullGCApproach() |> ignore let sw = Stopwatch() // measure real performance let mutable results = List<'a>(2000) sw.Start() for i in 1UL..iterations do let r = f() results.Add r if i % 1000UL = 0UL then sw.Stop() results <- List<'a>(2000) System.GC.Collect(3) System.GC.WaitForFullGCComplete() |> ignore System.GC.Collect(3) System.GC.WaitForFullGCApproach() |> ignore sw.Start() sw.Stop() let timePerF = sw.Elapsed.TotalMilliseconds / float iterations 1000.0 * timePerF let runTest (filename : string) (create : int -> 'a) (op : int -> 'a -> 'b) (sizes : list) = File.WriteAllLines(filename, ["size;time"]) printfn "determinig nop-overhead" let nopInstance = create (List.head sizes) testPerf(fun () -> nopInstance) |> ignore // warmup let tNop = testPerf(fun () -> nopInstance) printfn "nop: %fµs" tNop for size in sizes do System.GC.Collect() System.GC.Collect(3) System.GC.WaitForFullGCComplete() |> ignore let instance = create size let t = testPerf(fun () -> op size instance) let t = t - tNop printfn "%d: %fµs" size t File.AppendAllLines(filename, [sprintf "%d;%f" size t]) let run() = // runTest @"C:\Users\schorsch\desktop\SortedListAdd.csv" // (fun s -> SortedList.ofList ([1..s]) ) // (fun s a -> SortedList.add 1 a) // [0..10..2000] runTest @"C:\Users\schorsch\desktop\SortedListBuild.csv" (fun s -> [1..s] ) (fun s a -> a |> List.fold (fun s a -> SortedList.add a s) SortedList.empty) [0..10..2000] runTest @"C:\Users\schorsch\desktop\FSharpSetBuild.csv" (fun s -> [1..s] ) (fun s a -> a |> List.fold (fun s a -> Set.add a s) Set.empty) [0..10..2000] ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Immutable/Graph.fs ================================================ namespace Aardvark.Base [] type Tree<'a> = | Empty | Node of int * list<'a * Tree<'a>> [] module Tree = let isEmpty (t : Tree<'a>) = match t with | Tree.Empty -> true | _ -> false let rec map (mapping : 'a -> 'b) (t : Tree<'a>) = match t with | Tree.Empty -> Tree.Empty | Tree.Node(ni, children) -> Tree.Node(ni, children |> List.map (fun (e,c) -> mapping e, map mapping c)) let rec filter (predicate : 'a -> bool) (t : Tree<'a>) = match t with | Tree.Empty -> Tree.Empty | Tree.Node(ni, children) -> let newChildren = children |> List.choose (fun (e,c) -> if predicate e then let c = filter predicate c Some (e,c) else None ) Tree.Node(ni, newChildren) let rec foldEdges (folder : 's -> 'a -> 's) (seed : 's) (t : Tree<'a>) = match t with | Tree.Empty -> seed | Tree.Node(_, edges) -> edges |> List.fold (fun s (e,c) -> c |> foldEdges folder (folder s e)) seed let rec foldNodes (folder : 's -> int -> 's) (seed : 's) (t : Tree<'a>) = match t with | Tree.Empty -> seed | Tree.Node(id, edges) -> match edges with | [] -> folder seed id | edges -> edges |> List.fold (fun s (e,c) -> c |> foldNodes folder s) (folder seed id) let count (t : Tree<'a>) = foldNodes (fun c _ -> c + 1) 0 t let inline weight (t : Tree<'a>) = foldEdges (+) LanguagePrimitives.GenericZero t type UndirectedGraph<'e> = { nodes : Set adjacency : MapExt> } [] module UndirectedGraph = open Aardvark.Base.Sorting open System.Collections.Generic type private UnionNode(id : int) as this = let mutable parent = this let mutable rank = 1 member x.Parent with get() = parent and set p = parent <- p member x.Rank with get() = rank and set r = rank <- r member x.Id = id type private UnionFind() = let nodes = Dict() let node (id : int) = nodes.GetOrCreate(id, fun id -> UnionNode(id)) let rec rep (n : UnionNode) = if n.Parent = n then n else let r = rep n.Parent n.Parent <- r r member x.Add(li : int, ri : int) = let ln = node li let rn = node ri let lr = rep ln let rr = rep rn if lr = rr then false else if lr.Rank < rr.Rank then lr.Parent <- rr true elif rr.Rank < lr.Rank then rr.Parent <- lr.Parent true else rr.Parent <- lr.Parent lr.Rank <- lr.Rank + 1 true let ofNodes (nodes : Set) (getEdge : int -> int -> Option<'e>) = let mutable adjacency = MapExt.empty let add (li : int) (ri : int) (e : 'e) = adjacency <- MapExt.alter li (function Some o -> MapExt.add ri e o |> Some | None -> MapExt.ofList [ri, e] |> Some ) adjacency adjacency <- MapExt.alter ri (function Some o -> MapExt.add li e o |> Some | None -> MapExt.ofList [li, e] |> Some ) adjacency let nodeArr = Set.toArray nodes for i in 0 .. nodeArr.Length - 1 do let li = nodeArr.[i] for j in i + 1 .. nodeArr.Length - 1 do let ri = nodeArr.[j] match getEdge li ri with | Some e -> add li ri e | None -> () { nodes = nodes adjacency = adjacency } let ofEdges (edges : seq) = let mutable nodes = Set.empty let mutable adjacency = MapExt.empty let add (li : int) (ri : int) (e : 'e) = adjacency <- MapExt.alter li (function Some o -> MapExt.add ri e o |> Some | None -> MapExt.ofList [ri, e] |> Some ) adjacency adjacency <- MapExt.alter ri (function Some o -> MapExt.add li e o |> Some | None -> MapExt.ofList [li, e] |> Some ) adjacency for (li, ri, e) in edges do nodes <- Set.add li (Set.add ri nodes) add li ri e { nodes = nodes adjacency = adjacency } let inline toNodes (g : UndirectedGraph<'e>) = g.nodes let toEdges (g : UndirectedGraph<'e>) = g.adjacency |> MapExt.toSeq |> Seq.collect (fun (li,a) -> let _, _, r = a |> MapExt.split li r |> MapExt.toSeq |> Seq.map (fun (ri, e) -> (li, ri, e)) ) |> Seq.toList let spanningTree (g : UndirectedGraph<'e>) = if Set.isEmpty g.nodes then Tree.Empty else let root = Seq.head g.nodes let rec traverse (edgeCount : ref) (visited : HashSet) (n : int) = if visited.Add n then let neighbours = MapExt.tryFind n g.adjacency |> Option.defaultValue MapExt.empty let children = neighbours |> MapExt.toList |> List.choose (fun (ri, e) -> match traverse edgeCount visited ri with | Some r -> edgeCount := !edgeCount + 1 Some (e, r) | None -> None ) Tree.Node(n, children) |> Some else None let cnt = ref 0 match traverse cnt (HashSet()) root with | Some t -> assert (!cnt = Set.count g.nodes - 1) t | None -> Tree.Empty let minimumSpanningTree (cmp : 'e -> 'e -> int) (g : UndirectedGraph<'e>) = let edges = g |> toEdges |> List.toArray edges.TimSort(fun (_,_,l) (_,_,r) -> cmp l r) let uf = UnionFind() let finalEdges = List() for (li, ri, e) in edges do if uf.Add(li, ri) then finalEdges.Add(li, ri, e) finalEdges |> ofEdges |> spanningTree let maximumSpanningTree (cmp : 'e -> 'e -> int) (g : UndirectedGraph<'e>) = minimumSpanningTree (fun l r -> cmp r l) g ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Immutable/MapExt.fs ================================================ // THIS IS A MODIFIED VERSION OF F#'s Map<'Key, 'Value> !!!! // THE ORIGINAL CAN BE FOUND AT https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/map.fs // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // THIS IS A MODIFIED VERSION OF F#'s Map<'Key, 'Value> !!!! // THE ORIGINAL CAN BE FOUND AT https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/map.fs // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. namespace Aardvark.Base open System open System.Collections open System.Collections.Generic open System.Diagnostics open Microsoft.FSharp.Core open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators open FSharp.Data.Adaptive open MBrace.FsPickler open MBrace.FsPickler.Combinators module internal MapExtImplementation = [] [] type MapTree<'Key,'Value> = | MapEmpty | MapOne of 'Key * 'Value | MapNode of 'Key * 'Value * MapTree<'Key,'Value> * MapTree<'Key,'Value> * int * int // REVIEW: performance rumour has it that the data held in MapNode and MapOne should be // exactly one cache line. It is currently ~7 and 4 words respectively. type MapExtReference<'v> = | NonExisting of index : int | Existing of index : int * value : 'v type internal EnumeratorEnumerable<'T>(get : unit -> IEnumerator<'T>) = interface System.Collections.IEnumerable with member x.GetEnumerator() = get() :> System.Collections.IEnumerator interface IEnumerable<'T> with member x.GetEnumerator() = get() [] module MapTree = let empty = MapEmpty let height = function | MapEmpty -> 0 | MapOne _ -> 1 | MapNode(_,_,_,_,h,_) -> h let size = function | MapEmpty -> 0 | MapOne _ -> 1 | MapNode(_,_,_,_,_,s) -> s let isEmpty m = match m with | MapEmpty -> true | _ -> false let mk l k v r = match l,r with | MapEmpty,MapEmpty -> MapOne(k,v) | _ -> let hl = height l let hr = height r let m = if hl < hr then hr else hl let res = MapNode(k,v,l,r,m+1, 1 + size l + size r) res let rec rebalance t1 k v t2 = let t1h = height t1 let t2h = height t2 if t2h > t1h + 2 then (* right is heavier than left *) match t2 with | MapNode(t2k,t2v,t2l,t2r,_,_) -> (* one of the nodes must have height > height t1 + 1 *) if height t2l > t1h + 1 then (* balance left: combination *) match t2l with | MapNode(t2lk,t2lv,t2ll,t2lr,_,_) -> mk (mk t1 k v t2ll) t2lk t2lv (rebalance t2lr t2k t2v t2r) | _ -> failwith "rebalance" else (* rotate left *) mk (mk t1 k v t2l) t2k t2v t2r | _ -> failwith "rebalance" else if t1h > t2h + 2 then (* left is heavier than right *) match t1 with | MapNode(t1k,t1v,t1l,t1r,_,_) -> (* one of the nodes must have height > height t2 + 1 *) if height t1r > t2h + 1 then (* balance right: combination *) match t1r with | MapNode(t1rk,t1rv,t1rl,t1rr,_,_) -> mk (rebalance t1l t1k t1v t1rl) t1rk t1rv (mk t1rr k v t2) | _ -> failwith "rebalance" else mk t1l t1k t1v (mk t1r k v t2) | _ -> failwith "rebalance" else mk t1 k v t2 let rec add (comparer: IComparer<'Value>) k v m = match m with | MapEmpty -> MapOne(k,v) | MapOne(k2,_) -> let c = comparer.Compare(k,k2) if c < 0 then MapNode (k,v,MapEmpty,m,2, 2) elif c = 0 then MapOne(k,v) else MapNode (k,v,m,MapEmpty,2, 2) | MapNode(k2,v2,l,r,h,s) -> let c = comparer.Compare(k,k2) if c < 0 then rebalance (add comparer k v l) k2 v2 r elif c = 0 then MapNode(k,v,l,r,h,s) else rebalance l k2 v2 (add comparer k v r) let rec find (comparer: IComparer<'Value>) k m = match m with | MapEmpty -> raise (KeyNotFoundException()) | MapOne(k2,v2) -> let c = comparer.Compare(k,k2) if c = 0 then v2 else raise (KeyNotFoundException()) | MapNode(k2,v2,l,r,_,_) -> let c = comparer.Compare(k,k2) if c < 0 then find comparer k l elif c = 0 then v2 else find comparer k r let rec tryFind (comparer: IComparer<'Value>) k m = match m with | MapEmpty -> None | MapOne(k2,v2) -> let c = comparer.Compare(k,k2) if c = 0 then Some v2 else None | MapNode(k2,v2,l,r,_,_) -> let c = comparer.Compare(k,k2) if c < 0 then tryFind comparer k l elif c = 0 then Some v2 else tryFind comparer k r let rec tryFindV (comparer: IComparer<'Value>) k m = match m with | MapEmpty -> ValueNone | MapOne(k2,v2) -> let c = comparer.Compare(k,k2) if c = 0 then ValueSome v2 else ValueNone | MapNode(k2,v2,l,r,_,_) -> let c = comparer.Compare(k,k2) if c < 0 then tryFindV comparer k l elif c = 0 then ValueSome v2 else tryFindV comparer k r let partition1 (comparer: IComparer<'Value>) (f:OptimizedClosures.FSharpFunc<_,_,_>) k v (acc1,acc2) = if f.Invoke(k, v) then (add comparer k v acc1,acc2) else (acc1,add comparer k v acc2) let rec partitionAux (comparer: IComparer<'Value>) (f:OptimizedClosures.FSharpFunc<_,_,_>) s acc = match s with | MapEmpty -> acc | MapOne(k,v) -> partition1 comparer f k v acc | MapNode(k,v,l,r,_,_) -> let acc = partitionAux comparer f r acc let acc = partition1 comparer f k v acc partitionAux comparer f l acc let partition (comparer: IComparer<'Value>) f s = partitionAux comparer (OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)) s (empty,empty) let filter1 (comparer: IComparer<'Value>) (f:OptimizedClosures.FSharpFunc<_,_,_>) k v acc = if f.Invoke(k, v) then add comparer k v acc else acc let rec filterAux (comparer: IComparer<'Value>) (f:OptimizedClosures.FSharpFunc<_,_,_>) s acc = match s with | MapEmpty -> acc | MapOne(k,v) -> filter1 comparer f k v acc | MapNode(k,v,l,r,_,_) -> let acc = filterAux comparer f l acc let acc = filter1 comparer f k v acc filterAux comparer f r acc let filter (comparer: IComparer<'Value>) f s = filterAux comparer (OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)) s empty let rec spliceOutSuccessor m = match m with | MapEmpty -> failwith "internal error: MapExt.spliceOutSuccessor" | MapOne(k2,v2) -> k2,v2,MapEmpty | MapNode(k2,v2,l,r,_,_) -> match l with | MapEmpty -> k2,v2,r | _ -> let k3,v3,l' = spliceOutSuccessor l in k3,v3,rebalance l' k2 v2 r let rec remove (comparer: IComparer<'Value>) k m = match m with | MapEmpty -> empty | MapOne(k2,_) -> let c = comparer.Compare(k,k2) if c = 0 then MapEmpty else m | MapNode(k2,v2,l,r,_,_) -> let c = comparer.Compare(k,k2) if c < 0 then rebalance (remove comparer k l) k2 v2 r elif c = 0 then match l with | MapEmpty -> r | _ -> match r with | MapEmpty -> l | _ -> let sk,sv,r' = spliceOutSuccessor r rebalance l sk sv r' else rebalance l k2 v2 (remove comparer k r) let rec tryRemove (comparer: IComparer<'Value>) k m = match m with | MapEmpty -> None | MapOne(k2,v) -> let c = comparer.Compare(k,k2) if c = 0 then Some (v, MapEmpty) else None | MapNode(k2,v2,l,r,_,_) -> let c = comparer.Compare(k,k2) if c < 0 then match tryRemove comparer k l with | Some (v,l) -> Some (v, rebalance l k2 v2 r) | None -> None elif c = 0 then match l with | MapEmpty -> Some(v2, r) | _ -> match r with | MapEmpty -> Some(v2, l) | _ -> let sk,sv,r' = spliceOutSuccessor r Some(v2, rebalance l sk sv r') else match tryRemove comparer k r with | Some (v,r) -> Some (v, rebalance l k2 v2 r) | None -> None let rec tryRemoveV (comparer: IComparer<'Value>) k m = match m with | MapEmpty -> ValueNone | MapOne(k2,v) -> let c = comparer.Compare(k,k2) if c = 0 then ValueSome (struct(v, MapEmpty)) else ValueNone | MapNode(k2,v2,l,r,_,_) -> let c = comparer.Compare(k,k2) if c < 0 then match tryRemoveV comparer k l with | ValueSome (v,l) -> ValueSome (struct (v, rebalance l k2 v2 r)) | ValueNone -> ValueNone elif c = 0 then match l with | MapEmpty -> ValueSome(struct(v2, r)) | _ -> match r with | MapEmpty -> ValueSome(struct(v2, l)) | _ -> let sk,sv,r' = spliceOutSuccessor r ValueSome(struct(v2, rebalance l sk sv r')) else match tryRemoveV comparer k r with | ValueSome (v,r) -> ValueSome (struct(v, rebalance l k2 v2 r)) | ValueNone -> ValueNone let rec tryRemoveMin cmp m = match m with | MapEmpty -> None | MapOne(k2,v) -> Some (k2, v, MapEmpty) | MapNode(k2,v2,l,r,_,_) -> match tryRemoveMin cmp l with | Some (k,v,rest) -> match rest with | MapEmpty -> Some (k, v, add cmp k2 v2 r) | _ -> Some (k, v, rebalance rest k2 v2 r) | None -> Some(k2, v2, r) let rec tryRemoveMax cmp m = match m with | MapEmpty -> None | MapOne(k2,v) -> Some (k2, v, MapEmpty) | MapNode(k2,v2,l,r,_,_) -> match tryRemoveMax cmp r with | Some (k,v,rest) -> match rest with | MapEmpty -> Some (k, v, add cmp k2 v2 l) | _ -> Some (k, v, rebalance l k2 v2 rest) | None -> Some(k2, v2, l) let rec tryMinKeyV n = match n with | MapEmpty -> ValueNone | MapOne(k,_) -> ValueSome k | MapNode(k, _, l, _, _, _) -> match tryMinKeyV l with | ValueSome m -> ValueSome m | ValueNone -> ValueSome k let rec tryMaxKeyV n = match n with | MapEmpty -> ValueNone | MapOne(k,_) -> ValueSome k | MapNode(k, _, _, r, _, _) -> match tryMaxKeyV r with | ValueSome m -> ValueSome m | ValueNone -> ValueSome k let rec tryRemoveMinV cmp next m = match m with | MapEmpty -> ValueNone | MapOne(k2,v) -> ValueSome (struct (k2, v, next, MapEmpty)) | MapNode(k2,v2,l,r,_,_) -> match tryRemoveMinV cmp (ValueSome k2) l with | ValueSome (k,v,next,rest) -> match rest with | MapEmpty -> ValueSome (struct(k, v, next, add cmp k2 v2 r)) | _ -> ValueSome (struct(k, v, next, rebalance rest k2 v2 r)) | ValueNone -> let next = tryMinKeyV r ValueSome(struct(k2, v2, next, r)) let rec tryRemoveMaxV cmp prev m = match m with | MapEmpty -> ValueNone | MapOne(k2,v) -> ValueSome (struct(k2, v, prev, MapEmpty)) | MapNode(k2,v2,l,r,_,_) -> match tryRemoveMaxV cmp (ValueSome k2) r with | ValueSome (struct(k, v, prev, rest)) -> match rest with | MapEmpty -> ValueSome (struct(k, v, prev, add cmp k2 v2 l)) | _ -> ValueSome (struct(k, v, prev, rebalance l k2 v2 rest)) | ValueNone -> let prev = tryMaxKeyV l ValueSome(k2, v2, prev, l) let rec alter (comparer : IComparer<'Value>) k f m = match m with | MapEmpty -> match f None with | Some v -> MapOne(k,v) | None -> MapEmpty | MapOne(k2, v2) -> let c = comparer.Compare(k,k2) if c = 0 then match f (Some v2) with | Some v3 -> MapOne(k2, v3) | None -> MapEmpty else match f None with | None -> MapOne(k2, v2) | Some v3 -> if c > 0 then MapNode (k2,v2,MapEmpty,MapOne(k, v3),2, 2) else MapNode(k2, v2, MapOne(k, v3), MapEmpty, 2, 2) | MapNode(k2, v2, l, r, h, cnt) -> let c = comparer.Compare(k, k2) if c = 0 then match f (Some v2) with | Some v3 -> MapNode(k2, v3, l, r, h, cnt) | None -> match l with | MapEmpty -> r | _ -> match r with | MapEmpty -> l | _ -> let sk,sv,r' = spliceOutSuccessor r rebalance l sk sv r' elif c > 0 then rebalance l k2 v2 (alter comparer k f r) else rebalance (alter comparer k f l) k2 v2 r let rec join left k v right = let lh = height left let rh = height right if lh > rh + 2 then match left with | MapNode(k2,v2,l,r,_,_) -> // the join-result can at most be one level higher than r // therefore rebalance is sufficient here rebalance l k2 v2 (join r k v right) | _ -> failwith "join" elif rh > lh + 2 then match right with | MapNode(k2,v2,l,r,_,_) -> // the join-result can at most be one level higher than l // therefore rebalance is sufficient here rebalance (join left k v l) k2 v2 r | _ -> failwith "join" else mk left k v right let inline merge l r = match r with | MapEmpty -> l | _ -> match l with | MapEmpty -> r | _ -> let (k,v,r) = spliceOutSuccessor r join l k v r let inline joinV left k v right = match v with | ValueSome v -> join left k v right | ValueNone -> merge left right let rec range (comparer : IComparer<'Value>) lk rk m = match m with | _ when comparer.Compare(lk, rk) > 0 -> MapEmpty | MapEmpty -> MapEmpty | MapOne(k, _) as n -> if comparer.Compare(lk, k) <= 0 && comparer.Compare(k, rk) <= 0 then n else MapEmpty | MapNode(k, v, l, r, _, _) -> let cl = comparer.Compare(lk, k) if cl = 0 then if comparer.Compare(k, rk) = 0 then MapOne(k, v) else join MapEmpty k v (range comparer lk rk r) elif cl < 0 then let cr = comparer.Compare(k, rk) if cr = 0 then join (range comparer lk rk l) k v MapEmpty elif cr < 0 then join (range comparer lk rk l) k v (range comparer lk rk r) else range comparer lk rk l else range comparer lk rk r let rec split (comparer: IComparer<'Value>) k m = match m with | MapEmpty -> MapEmpty, None, MapEmpty | MapOne(k2,v2) -> let c = comparer.Compare(k, k2) if c < 0 then MapEmpty, None, MapOne(k2,v2) elif c = 0 then MapEmpty, Some(v2), MapEmpty else MapOne(k2,v2), None, MapEmpty | MapNode(k2,v2,l,r,_,_) -> let c = comparer.Compare(k, k2) if c > 0 then let rl, res, rr = split comparer k r join l k2 v2 rl, res, rr elif c = 0 then l, Some(v2), r else let ll, res, lr = split comparer k l ll, res, join lr k2 v2 r let rec tryMinAux acc m = match m with | MapEmpty -> acc | MapOne(k,v) -> Some (k,v) | MapNode(k,v,l,_,_,_) -> tryMinAux (Some (k,v)) l let rec tryMin m = tryMinAux None m let rec tryMinVAux acc m = match m with | MapEmpty -> acc | MapOne(k,v) -> ValueSome (struct(k,v)) | MapNode(k,v,l,_,_,_) -> tryMinVAux (ValueSome (struct(k,v))) l let rec tryMinV m = tryMinVAux ValueNone m let rec tryMaxAux acc m = match m with | MapEmpty -> acc | MapOne(k,v) -> Some (k,v) | MapNode(k,v,_,r,_,_) -> tryMaxAux (Some (k,v)) r let rec tryMax m = tryMaxAux None m let rec tryMaxVAux acc m = match m with | MapEmpty -> acc | MapOne(k,v) -> ValueSome (struct(k,v)) | MapNode(k,v,_,r,_,_) -> tryMaxVAux (ValueSome (struct(k,v))) r let rec tryMaxV m = tryMaxVAux ValueNone m let rec splitV (comparer: IComparer<'Value>) k m = match m with | MapEmpty -> struct (MapEmpty, ValueNone, ValueNone, ValueNone, MapEmpty) | MapOne(k2,v2) -> let c = comparer.Compare(k, k2) if c < 0 then struct (MapEmpty, ValueNone, ValueNone, ValueSome k2, MapOne(k2,v2)) elif c = 0 then struct (MapEmpty, ValueNone, ValueSome(v2), ValueNone, MapEmpty) else struct (MapOne(k2,v2), ValueSome k2, ValueNone, ValueNone, MapEmpty) | MapNode(k2,v2,l,r,_,_) -> let c = comparer.Compare(k, k2) if c > 0 then let struct (rl, lmax, res, rmin, rr) = splitV comparer k r struct (join l k2 v2 rl, lmax, res, rmin, rr) elif c = 0 then let lmax = tryMaxV l |> ValueOption.map (fun struct(k,_) -> k) let rmin = tryMinV r |> ValueOption.map (fun struct(k,_) -> k) struct (l, lmax, ValueSome(v2), rmin, r) else let struct (ll, lmax, res, rmin, lr) = splitV comparer k l struct (ll, lmax, res, rmin, join lr k2 v2 r) let rec getReference (comparer: IComparer<'Value>) (current : int) k m = match m with | MapEmpty -> NonExisting current | MapOne(key,v) -> let c = comparer.Compare(k, key) if c > 0 then NonExisting (current + 1) elif c < 0 then NonExisting current else Existing(current, v) | MapNode(key,v,l,r,_,s) -> let c = comparer.Compare(k, key) if c > 0 then getReference comparer (current + size l + 1) k r elif c < 0 then getReference comparer current k l else Existing(current+size l, v) let rec union (comparer: IComparer<'Key>) l r = match struct (l, r) with | struct (MapEmpty, r) -> r | struct (l, MapEmpty) -> l | struct (MapOne(lk, _lv), MapOne(rk, rv)) -> if Object.ReferenceEquals(l, r) then r else let c = comparer.Compare(lk, rk) if c = 0 then r elif c > 0 then mk MapEmpty rk rv l else mk l rk rv MapEmpty | struct (MapOne(lk, _), MapNode(rk, rv, rl, rr, rh, rc)) -> let c = comparer.Compare(lk, rk) if c = 0 then r elif c < 0 then join (union comparer l rl) rk rv rr else join rl rk rv (union comparer l rr) | struct (MapNode(lk, lv, ll, lr, lh, lc), MapOne(rk, rv)) -> let c = comparer.Compare(lk, rk) if c = 0 then MapNode(lk, rv, ll, lr, lh, lc) elif c < 0 then join ll lk lv (union comparer lr r) else join (union comparer ll r) lk lv lr | struct (MapNode(lk, lv, ll, lr, lh, lc), MapNode(rk, rv, rl, rr, rh, rc)) -> if Object.ReferenceEquals(l, r) then r else let c = comparer.Compare(lk, rk) if c = 0 then let l = union comparer ll rl let r = union comparer lr rr join l rk rv r elif lh > rh then let struct (rl, _lmax, rv, _rmin, rr) = splitV comparer lk r let key = lk let l = union comparer ll rl let r = union comparer lr rr match rv with | ValueSome rv -> join l key rv r | ValueNone -> join l key lv r else let struct (ll, _lmax, _, _rmin, lr) = splitV comparer rk l let key = rk let l = union comparer ll rl let r = union comparer lr rr join l key rv r let rec unionWithOpt (comparer: IComparer<'Value>) (f : OptimizedClosures.FSharpFunc<_,_,_>) l r = match struct (l, r) with | struct (MapEmpty, r) -> r | struct (l, MapEmpty) -> l | struct (MapOne(lk, lv), MapOne(rk, rv)) -> let c = comparer.Compare(lk, rk) if c = 0 then MapOne(rk, f.Invoke(lv, rv)) elif c > 0 then mk MapEmpty rk rv l else mk l rk rv MapEmpty | struct (MapOne(lk, lv), MapNode(rk, rv, rl, rr, rh, rc)) -> let c = comparer.Compare(lk, rk) if c = 0 then MapNode(rk, f.Invoke(lv, rv), rl, rr, rh, rc) elif c < 0 then join (unionWithOpt comparer f l rl) rk rv rr else join rl rk rv (unionWithOpt comparer f l rr) | struct (MapNode(lk, lv, ll, lr, lh, lc), MapOne(rk, rv)) -> let c = comparer.Compare(lk, rk) if c = 0 then MapNode(lk, f.Invoke(lv, rv), ll, lr, lh, lc) elif c < 0 then join ll lk lv (unionWithOpt comparer f lr r) else join (unionWithOpt comparer f ll r) lk lv lr | struct (MapNode(lk, lv, ll, lr, lh, lc), MapNode(rk, rv, rl, rr, rh, rc)) -> let c = comparer.Compare(lk, rk) if c = 0 then let l = unionWithOpt comparer f ll rl let r = unionWithOpt comparer f lr rr join l rk (f.Invoke(lv, rv)) r elif lh > rh then let struct (rl, _lmax, rv, _rmin, rr) = splitV comparer lk r let key = lk let l = unionWithOpt comparer f ll rl let r = unionWithOpt comparer f lr rr match rv with | ValueSome rv -> join l key (f.Invoke(lv, rv)) r | ValueNone -> join l key lv r else let struct (ll, _lmax, lv, _rmin, lr) = splitV comparer rk l let key = rk let l = unionWithOpt comparer f ll rl let r = unionWithOpt comparer f lr rr match lv with | ValueSome lv -> join l key (f.Invoke(lv, rv)) r | ValueNone -> join l key rv r let unionWith(comparer: IComparer<'Value>) f l r = unionWithOpt comparer (OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)) l r let rec stupidHeight m = match m with | MapEmpty -> 0 | MapOne _ -> 1 | MapNode(_,_,l,r,_,_) -> max (stupidHeight l) (stupidHeight r) + 1 let rec stupidCount m = match m with | MapEmpty -> 0 | MapOne _ -> 1 | MapNode(_,_,l,r,_,_) -> 1 + stupidCount l + stupidCount r let rec validateAux (comparer: IComparer<'Value>) (min : option<_>) (max : option<_>) m = match m with | MapNode(k,v,l,r,h,c) -> let lh = height l let rh = height r if Option.isSome min && comparer.Compare(k, min.Value) <= 0 then failwith "invalid order" if Option.isSome max && comparer.Compare(k, max.Value) >= 0 then failwith "invalid order" if stupidCount m <> c then failwith "invalid count" if stupidHeight l <> lh then failwith "invalid height" if stupidHeight r <> rh then failwith "invalid height" if abs (lh - rh) > 2 then failwith "imbalanced" validateAux comparer min (Some k) l validateAux comparer (Some k) max r | MapOne(k,v) -> if Option.isSome min && comparer.Compare(k, min.Value) <= 0 then failwith "invalid order" if Option.isSome max && comparer.Compare(k, max.Value) >= 0 then failwith "invalid order" | MapEmpty -> () let validate (comparer: IComparer<'Value>) m = validateAux comparer None None m let rec mem (comparer: IComparer<'Value>) k m = match m with | MapEmpty -> false | MapOne(k2,_) -> (comparer.Compare(k,k2) = 0) | MapNode(k2,_,l,r,_,_) -> let c = comparer.Compare(k,k2) if c < 0 then mem comparer k l else (c = 0 || mem comparer k r) let rec iterOpt (f:OptimizedClosures.FSharpFunc<_,_,_>) m = match m with | MapEmpty -> () | MapOne(k2,v2) -> f.Invoke(k2, v2) | MapNode(k2,v2,l,r,_,_) -> iterOpt f l; f.Invoke(k2, v2); iterOpt f r let iter f m = iterOpt (OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)) m let rec tryPickOpt (f:OptimizedClosures.FSharpFunc<_,_,_>) m = match m with | MapEmpty -> None | MapOne(k2,v2) -> f.Invoke(k2, v2) | MapNode(k2,v2,l,r,_,_) -> match tryPickOpt f l with | Some _ as res -> res | None -> match f.Invoke(k2, v2) with | Some _ as res -> res | None -> tryPickOpt f r let tryPick f m = tryPickOpt (OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)) m let rec tryPickOptBack (f:OptimizedClosures.FSharpFunc<_,_,_>) m = match m with | MapEmpty -> None | MapOne(k2,v2) -> f.Invoke(k2, v2) | MapNode(k2,v2,l,r,_,_) -> match tryPickOptBack f r with | Some _ as res -> res | None -> match f.Invoke(k2, v2) with | Some _ as res -> res | None -> tryPickOptBack f l let tryPickBack f m = tryPickOptBack (OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)) m let rec existsOpt (f:OptimizedClosures.FSharpFunc<_,_,_>) m = match m with | MapEmpty -> false | MapOne(k2,v2) -> f.Invoke(k2, v2) | MapNode(k2,v2,l,r,_,_) -> existsOpt f l || f.Invoke(k2, v2) || existsOpt f r let exists f m = existsOpt (OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)) m let rec forallOpt (f:OptimizedClosures.FSharpFunc<_,_,_>) m = match m with | MapEmpty -> true | MapOne(k2,v2) -> f.Invoke(k2, v2) | MapNode(k2,v2,l,r,_,_) -> forallOpt f l && f.Invoke(k2, v2) && forallOpt f r let forall f m = forallOpt (OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)) m let rec map f m = match m with | MapEmpty -> empty | MapOne(k,v) -> MapOne(k,f v) | MapNode(k,v,l,r,h,c) -> let l2 = map f l let v2 = f v let r2 = map f r MapNode(k,v2,l2, r2,h,c) let rec mapiOpt (f:OptimizedClosures.FSharpFunc<_,_,_>) m = match m with | MapEmpty -> empty | MapOne(k,v) -> MapOne(k, f.Invoke(k, v)) | MapNode(k,v,l,r,h,c) -> let l2 = mapiOpt f l let v2 = f.Invoke(k, v) let r2 = mapiOpt f r MapNode(k,v2, l2, r2,h,c) let mapi f m = mapiOpt (OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)) m let rec mapiMonotonicAux (f:OptimizedClosures.FSharpFunc<_,_,_>) m = match m with | MapEmpty -> empty | MapOne(k,v) -> let (k2, v2) = f.Invoke(k, v) MapOne(k2, v2) | MapNode(k,v,l,r,h,c) -> let l2 = mapiMonotonicAux f l let k2, v2 = f.Invoke(k, v) let r2 = mapiMonotonicAux f r MapNode(k2,v2, l2, r2,h,c) let mapiMonotonic f m = mapiMonotonicAux (OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)) m let rec chooseiMonotonicAux (f:OptimizedClosures.FSharpFunc<_,_,_>) m = match m with | MapEmpty -> empty | MapOne(k,v) -> match f.Invoke(k, v) with | Some (k2, v2) -> MapOne(k2, v2) | None -> MapEmpty | MapNode(k,v,l,r,h,c) -> let l2 = chooseiMonotonicAux f l let self = f.Invoke(k, v) let r2 = chooseiMonotonicAux f r match self with | Some (k2, v2) -> join l2 k2 v2 r2 | None -> match l2 with | MapEmpty -> r2 | _ -> match r2 with | MapEmpty -> l2 | _ -> let k,v,r2 = spliceOutSuccessor r2 join l2 k v r2 let chooseiMonotonic f m = chooseiMonotonicAux (OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)) m let rec chooseiOpt (f:OptimizedClosures.FSharpFunc<'Key,'T1,option<'T2>>) m = match m with | MapEmpty -> empty | MapOne(k,v) -> match f.Invoke(k,v) with | Some v -> MapOne(k,v) | None -> MapEmpty | MapNode(k,v,l,r,h,c) -> let l' = chooseiOpt f l let s' = f.Invoke(k,v) let r' = chooseiOpt f r match s' with | None -> merge l' r' | Some v -> join l' k v r' let choosei f m = chooseiOpt (OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)) m let rec chooseiOptV (f:OptimizedClosures.FSharpFunc<'Key,'T1,voption<'T2>>) m = match m with | MapEmpty -> empty | MapOne(k,v) -> match f.Invoke(k,v) with | ValueSome v -> MapOne(k,v) | ValueNone -> MapEmpty | MapNode(k,v,l,r,h,c) -> let l' = chooseiOptV f l let s' = f.Invoke(k,v) let r' = chooseiOptV f r match s' with | ValueNone -> merge l' r' | ValueSome v -> join l' k v r' let rec chooseiOptV2 (f:OptimizedClosures.FSharpFunc<'Key,'T1,struct (voption<'T2> * voption<'T3>)>) m = match m with | MapEmpty -> struct(MapEmpty, MapEmpty) | MapOne(k,v) -> let struct (a, b) = f.Invoke(k,v) let a = match a with | ValueSome v -> MapOne(k,v) | ValueNone -> MapEmpty let b = match b with | ValueSome v -> MapOne(k,v) | ValueNone -> MapEmpty struct (a, b) | MapNode(k,v,l,r,h,c) -> let struct(la', lb') = chooseiOptV2 f l let struct (sa', sb') = f.Invoke(k,v) let struct (ra', rb') = chooseiOptV2 f r let a = joinV la' k sa' ra' let b = joinV lb' k sb' rb' struct (a, b) let rec neighboursAux (comparer: IComparer<'Value>) k l r m = match m with | MapEmpty -> l, None, r | MapOne(k2,v2) -> let c = comparer.Compare(k, k2) if c > 0 then Some(k2,v2), None, r elif c = 0 then l, Some(k2,v2), r else l, None, Some(k2,v2) | MapNode(k2,v2,l2,r2,_,_) -> let c = comparer.Compare(k, k2) if c > 0 then let l = Some(k2, v2) neighboursAux comparer k l r r2 elif c = 0 then let l = match tryMax l2 with | None -> l | l -> l let r = match tryMin r2 with | None -> r | r -> r l,Some(k2, v2),r else let r = Some(k2, v2) neighboursAux comparer k l r l2 let neighbours (comparer: IComparer<'Value>) k m = neighboursAux comparer k None None m let rec neighboursiAux idx l r m = match m with | MapEmpty -> l, None, r | MapOne(k2,v2) -> if idx > 0 then Some(k2,v2), None, r elif idx = 0 then l, Some(k2,v2), r else l, None, Some(k2,v2) | MapNode(k2,v2,l2,r2,_,cnt) -> if idx < 0 then None, None, tryMin m elif idx >= cnt then tryMax m, None, None else let lc = size l2 if idx < lc then let r = Some(k2, v2) neighboursiAux idx l r l2 elif idx = lc then let l = match tryMax l2 with | None -> l | l -> l let r = match tryMin r2 with | None -> r | r -> r l, Some(k2, v2), r else let l = Some(k2, v2) neighboursiAux (idx-lc-1) l r r2 let neighboursi idx m = neighboursiAux idx None None m let rec neighboursVAux (comparer: IComparer<'Value>) k l r m = match m with | MapEmpty -> struct(l, ValueNone, r) | MapOne(k2,v2) -> let c = comparer.Compare(k, k2) if c > 0 then struct(ValueSome(struct(k2,v2)), ValueNone, r) elif c = 0 then struct(l, ValueSome(struct(k2,v2)), r) else struct(l, ValueNone, ValueSome(struct(k2,v2))) | MapNode(k2,v2,l2,r2,_,_) -> let c = comparer.Compare(k, k2) if c > 0 then let l = ValueSome(struct(k2, v2)) neighboursVAux comparer k l r r2 elif c = 0 then let l = match tryMaxV l2 with | ValueNone -> l | l -> l let r = match tryMinV r2 with | ValueNone -> r | r -> r struct(l,ValueSome(struct(k2, v2)),r) else let r = ValueSome(struct(k2, v2)) neighboursVAux comparer k l r l2 let neighboursV (comparer: IComparer<'Value>) k m = neighboursVAux comparer k ValueNone ValueNone m let rec neighboursViAux idx l r m = match m with | MapEmpty -> struct(l, ValueNone, r) | MapOne(k2,v2) -> if idx > 0 then struct(ValueSome(struct(k2,v2)), ValueNone, r) elif idx = 0 then struct(l, ValueSome(struct(k2,v2)), r) else struct(l, ValueNone, ValueSome(struct(k2,v2))) | MapNode(k2,v2,l2,r2,_,cnt) -> if idx < 0 then struct(ValueNone, ValueNone, tryMinV m) elif idx >= cnt then struct(tryMaxV m, ValueNone, ValueNone) else let lc = size l2 if idx < lc then let r = ValueSome(struct(k2, v2)) neighboursViAux idx l r l2 elif idx = lc then let l = match tryMaxV l2 with | ValueNone -> l | l -> l let r = match tryMinV r2 with | ValueNone -> r | r -> r struct(l, ValueSome(struct(k2, v2)), r) else let l = ValueSome(struct(k2, v2)) neighboursViAux (idx-lc-1) l r r2 let neighboursVi idx m = neighboursViAux idx ValueNone ValueNone m let rec tryAt i m = match m with | MapEmpty -> None | MapOne(k,v) -> if i = 0 then Some (k,v) else None | MapNode(k,v,l,r,_,c) -> if i < 0 || i >= c then None else let ls = size l if i = ls then Some (k,v) elif i < ls then tryAt i l else tryAt (i - ls - 1) r let rec tryAtV i m = match m with | MapEmpty -> ValueNone | MapOne(k,v) -> if i = 0 then ValueSome (struct(k,v)) else ValueNone | MapNode(k,v,l,r,_,c) -> if i < 0 || i >= c then ValueNone else let ls = size l if i = ls then ValueSome (struct(k,v)) elif i < ls then tryAtV i l else tryAtV (i - ls - 1) r let rec private tryGetIndexAux (comparer: IComparer<'Key>) (i : int) (key : 'Key) (m : MapTree<'Key, 'Value>) = match m with | MapEmpty -> None | MapOne(k,_value) -> if comparer.Compare(key, k) = 0 then Some i else None | MapNode(k,_value,left,right,_,_) -> let cmp = comparer.Compare(key, k) if cmp > 0 then tryGetIndexAux comparer (i + size left + 1) key right elif cmp < 0 then tryGetIndexAux comparer i key left else Some (i + size left) let tryGetIndex (comparer: IComparer<'Key>) (key : 'Key) (m : MapTree<'Key, 'Value>) = tryGetIndexAux comparer 0 key m let rec private tryGetIndexVAux (comparer: IComparer<'Key>) (i : int) (key : 'Key) (m : MapTree<'Key, 'Value>) = match m with | MapEmpty -> ValueNone | MapOne(k,_value) -> if comparer.Compare(key, k) = 0 then ValueSome i else ValueNone | MapNode(k,_value,left,right,_,_) -> let cmp = comparer.Compare(key, k) if cmp > 0 then tryGetIndexVAux comparer (i + size left + 1) key right elif cmp < 0 then tryGetIndexVAux comparer i key left else ValueSome (i + size left) let tryGetIndexV (comparer: IComparer<'Key>) (key : 'Key) (m : MapTree<'Key, 'Value>) = tryGetIndexVAux comparer 0 key m let rec map2 (comparer: IComparer<'Value>) f l r = match l, r with | MapEmpty, r -> mapi (fun i rv -> f i None (Some rv)) r | l, MapEmpty -> mapi (fun i lv -> f i (Some lv) None) l | MapOne(k,v), r -> let mutable found = false let res = r |> mapi (fun i rv -> if i = k then found <- true f i (Some v) (Some rv) else f i None (Some rv) ) if found then res else res |> add comparer k (f k (Some v) None) | l, MapOne(k,v) -> let mutable found = false let res = l |> mapi (fun i lv -> if i = k then found <- true f i (Some lv) (Some v) else f i None (Some v) ) if found then res else res |> add comparer k (f k None (Some v)) | MapNode(k,v,ll,lr,_,_),r -> let rs, self, rg = split comparer k r let v = match self with | Some rv -> f k (Some v) (Some rv) | None -> f k (Some v) None join (map2 comparer f ll rs) k v (map2 comparer f lr rg) let rec map2VOpt (comparer: IComparer<'Key>) (f : OptimizedClosures.FSharpFunc<'Key, voption<'T1>, voption<'T2>, 'T3>) (lo : OptimizedClosures.FSharpFunc<'Key, 'T1, 'T3>) (ro : OptimizedClosures.FSharpFunc<'Key, 'T2, 'T3>) l r = match l, r with | MapEmpty, r -> mapiOpt ro r | l, MapEmpty -> mapiOpt lo l | MapOne(lk, lv), MapOne(rk, rv) -> let c = comparer.Compare(lk, rk) if c = 0 then MapOne(lk, f.Invoke(lk, ValueSome lv, ValueSome rv)) else let l = MapOne(lk, f.Invoke(lk, ValueSome lv, ValueNone)) let r = MapOne(rk, f.Invoke(rk, ValueNone, ValueSome rv)) if c < 0 then merge l r else merge r l | MapNode(lk, lv, ll, lr, lh, lc), MapOne(rk, rv) -> let c = comparer.Compare(lk, rk) if c = 0 then let ll = mapiOpt lo ll let lr = mapiOpt lo lr let v = f.Invoke(lk, ValueSome lv, ValueSome rv) join ll lk v lr elif c > 0 then join (map2VOpt comparer f lo ro ll r) lk (lo.Invoke(lk, lv)) (mapiOpt lo lr) else join (mapiOpt lo ll) lk (lo.Invoke(lk, lv)) (map2VOpt comparer f lo ro lr r) | MapOne(lk, lv), MapNode(rk, rv, rl, rr, rh, rc) -> let c = comparer.Compare(lk, rk) if c = 0 then let rl = mapiOpt ro rl let rr = mapiOpt ro rr let v = f.Invoke(rk, ValueSome lv, ValueSome rv) join rl rk v rr elif c > 0 then join (mapiOpt ro rl) rk (ro.Invoke(rk, rv)) (map2VOpt comparer f lo ro l rr) else join (map2VOpt comparer f lo ro l rl) rk (ro.Invoke(rk, rv)) (mapiOpt ro rr) | MapNode(lk, lv, ll, lr, lh, lc), MapNode(rk, rv, rl, rr, rh, rc) -> let c = comparer.Compare(lk, rk) if c = 0 then join (map2VOpt comparer f lo ro ll rl) lk (f.Invoke(lk, ValueSome lv, ValueSome rv)) (map2VOpt comparer f lo ro lr rr) elif lh > rh then let struct (rl, _lmax, rv, _rmin, rr) = splitV comparer lk r join (map2VOpt comparer f lo ro ll rl) lk (f.Invoke(lk, ValueSome lv, rv)) (map2VOpt comparer f lo ro lr rr) else let struct (ll, _lmax, lv, _rmin, lr) = splitV comparer rk l join (map2VOpt comparer f lo ro ll rl) rk (f.Invoke(rk, lv, ValueSome rv)) (map2VOpt comparer f lo ro lr rr) let map2V (comparer: IComparer<'Key>) (mapping : 'Key -> voption<'T1> -> voption<'T2> -> 'T3) l r = let mapping = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt mapping let lo = OptimizedClosures.FSharpFunc<_,_,_>.Adapt (fun k l -> mapping.Invoke(k, ValueSome l, ValueNone)) let ro = OptimizedClosures.FSharpFunc<_,_,_>.Adapt (fun k r -> mapping.Invoke(k, ValueNone, ValueSome r)) map2VOpt comparer mapping lo ro l r let rec choose2VOpt (comparer: IComparer<'Key>) (f : OptimizedClosures.FSharpFunc<'Key, voption<'T1>, voption<'T2>, voption<'T3>>) (lo : OptimizedClosures.FSharpFunc<'Key, 'T1, voption<'T3>>) (ro : OptimizedClosures.FSharpFunc<'Key, 'T2, voption<'T3>>) l r = match l, r with | MapEmpty, r -> chooseiOptV ro r | l, MapEmpty -> chooseiOptV lo l | MapOne(lk, lv), MapOne(rk, rv) -> let c = comparer.Compare(lk, rk) if c = 0 then match f.Invoke(lk, ValueSome lv, ValueSome rv) with | ValueSome r -> MapOne(lk, r) | ValueNone -> MapEmpty else let l = match f.Invoke(lk, ValueSome lv, ValueNone) with | ValueSome r -> MapOne(lk, r) | ValueNone -> MapEmpty let r = match f.Invoke(rk, ValueNone, ValueSome rv) with | ValueSome r -> MapOne(rk, r) | ValueNone -> MapEmpty if c < 0 then merge l r else merge r l | MapNode(lk, lv, ll, lr, lh, lc), MapOne(rk, rv) -> let c = comparer.Compare(lk, rk) if c = 0 then let ll = chooseiOptV lo ll let lr = chooseiOptV lo lr match f.Invoke(lk, ValueSome lv, ValueSome rv) with | ValueSome v -> join ll lk v lr | ValueNone -> merge ll lr elif c > 0 then joinV (choose2VOpt comparer f lo ro ll r) lk (lo.Invoke(lk, lv)) (chooseiOptV lo lr) else joinV (chooseiOptV lo ll) lk (lo.Invoke(lk, lv)) (choose2VOpt comparer f lo ro lr r) | MapOne(lk, lv), MapNode(rk, rv, rl, rr, rh, rc) -> let c = comparer.Compare(lk, rk) if c = 0 then let rl = chooseiOptV ro rl let rr = chooseiOptV ro rr match f.Invoke(rk, ValueSome lv, ValueSome rv) with | ValueSome v -> join rl rk v rr | ValueNone -> merge rl rr elif c > 0 then joinV (chooseiOptV ro rl) rk (ro.Invoke(rk, rv)) (choose2VOpt comparer f lo ro l rr) else joinV (choose2VOpt comparer f lo ro l rl) rk (ro.Invoke(rk, rv)) (chooseiOptV ro rr) | MapNode(lk, lv, ll, lr, lh, lc), MapNode(rk, rv, rl, rr, rh, rc) -> let c = comparer.Compare(lk, rk) if c = 0 then joinV (choose2VOpt comparer f lo ro ll rl) lk (f.Invoke(lk, ValueSome lv, ValueSome rv)) (choose2VOpt comparer f lo ro lr rr) elif lh > rh then let struct (rl, _lmax, rv, _rmin, rr) = splitV comparer lk r joinV (choose2VOpt comparer f lo ro ll rl) lk (f.Invoke(lk, ValueSome lv, rv)) (choose2VOpt comparer f lo ro lr rr) else let struct (ll, _lmax, lv, _rmin, lr) = splitV comparer rk l joinV (choose2VOpt comparer f lo ro ll rl) rk (f.Invoke(rk, lv, ValueSome rv)) (choose2VOpt comparer f lo ro lr rr) let choose2V (comparer: IComparer<'Key>) (mapping : 'Key -> voption<'T1> -> voption<'T2> -> voption<'T3>) l r = let mapping = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt mapping let lo = OptimizedClosures.FSharpFunc<_,_,_>.Adapt (fun k l -> mapping.Invoke(k, ValueSome l, ValueNone)) let ro = OptimizedClosures.FSharpFunc<_,_,_>.Adapt (fun k r -> mapping.Invoke(k, ValueNone, ValueSome r)) choose2VOpt comparer mapping lo ro l r let rec applyDelta (comparer : IComparer<'Key>) (apply : OptimizedClosures.FSharpFunc<'Key, voption<'Value>, 'Delta, struct (voption<'Value> * voption<'DeltaOut>)>) (onlyDelta : OptimizedClosures.FSharpFunc<'Key, 'Delta, struct (voption<'Value> * voption<'DeltaOut>)>) (l : MapTree<'Key, 'Value>) (r : MapTree<'Key, 'Delta>) = match struct(l, r) with | struct (value, MapEmpty) -> struct (value, MapEmpty) | struct (MapEmpty, r) -> chooseiOptV2 onlyDelta r | struct (MapOne(lk, lv), MapOne(rk, rv)) -> let c = comparer.Compare(lk, rk) if c = 0 then let struct (s, d) = apply.Invoke(lk, ValueSome lv, rv) let s = match s with | ValueSome v -> MapOne(lk, v) | ValueNone -> MapEmpty let d = match d with | ValueSome v -> MapOne(rk, v) | ValueNone -> MapEmpty struct(s, d) else let struct (s, d) = onlyDelta.Invoke(rk, rv) let d = match d with | ValueSome v -> MapOne(rk, v) | ValueNone -> MapEmpty match s with | ValueSome s -> //let state = merge (MapOne(lk, lv)) (MapOne(rk, s)) let state = if c > 0 then MapNode(rk, s, MapEmpty, MapOne(lk, lv), 2, 2) else MapNode(lk, lv, MapEmpty, MapOne(rk, s), 2, 2) struct(state, d) | ValueNone -> struct (l, d) | struct (MapOne(lk, lv), MapNode(rk, rv, rl, rr, rh, rc)) -> let c = comparer.Compare(lk, rk) //match tryRemove comparer lk r with //| Some (rv, r) -> // let struct (s, d) = chooseiOptV2 onlyDelta r // let struct (sv, dv) = apply.Invoke(lk, ValueSome lv, rv) // let s = match sv with | ValueNone -> s | ValueSome v -> add comparer lk v s // let d = match dv with | ValueNone -> d | ValueSome v -> add comparer lk v d // struct (s, d) //| None -> // let struct (s, d) = chooseiOptV2 onlyDelta r // struct(add comparer lk lv s, d) if c = 0 then let struct (s, d) = apply.Invoke(rk, ValueSome lv, rv) let struct (rls, rld) = chooseiOptV2 onlyDelta rl let struct (rrs, rrd) = chooseiOptV2 onlyDelta rr let s = joinV rls rk s rrs let d = joinV rld rk d rrd struct (s, d) elif c < 0 then let struct (s, d) = onlyDelta.Invoke(rk, rv) let struct (rls, rld) = applyDelta comparer apply onlyDelta l rl let struct (rrs, rrd) = chooseiOptV2 onlyDelta rr let s = joinV rls rk s rrs let d = joinV rld rk d rrd struct (s, d) else let struct (s, d) = onlyDelta.Invoke(rk, rv) let struct (rls, rld) = chooseiOptV2 onlyDelta rl let struct (rrs, rrd) = applyDelta comparer apply onlyDelta l rr let s = joinV rls rk s rrs let d = joinV rld rk d rrd struct (s, d) | struct(MapNode(lk, lv, ll, lr, _, _), MapOne(rk, rv)) -> //match tryRemove comparer rk l with //| Some (lv, l) -> // let struct (s, d) = apply.Invoke(rk, ValueSome lv, rv) // let s = match s with | ValueSome s -> (add comparer rk s l) | ValueNone -> l // let d = match d with | ValueSome v -> MapOne(rk, v) | ValueNone -> MapEmpty // struct (s, d) //| None -> // let struct (s, d) = apply.Invoke(rk, ValueNone, rv) // let s = match s with | ValueSome s -> (add comparer rk s l) | ValueNone -> l // let d = match d with | ValueSome v -> MapOne(rk, v) | ValueNone -> MapEmpty // struct (s, d) let c = comparer.Compare(lk, rk) if c = 0 then let struct (s, d) = apply.Invoke(lk, ValueSome lv, rv) let s = joinV ll lk s lr let d = match d with | ValueSome v -> MapOne(lk, v) | ValueNone -> MapEmpty struct (s, d) elif c < 0 then // delta in right let struct (lr, d) = applyDelta comparer apply onlyDelta lr r let s = join ll lk lv lr struct (s, d) else // delta in left let struct (ll, d) = applyDelta comparer apply onlyDelta ll r let s = join ll lk lv lr struct (s, d) | struct(MapNode(lk, lv, ll, lr, lh, _), MapNode(rk, rv, rl, rr, rh, _)) -> let c = comparer.Compare(lk, rk) if c = 0 then let struct (s, d) = apply.Invoke(lk, ValueSome lv, rv) let struct (ls, ld) = applyDelta comparer apply onlyDelta ll rl let struct (rs, rd) = applyDelta comparer apply onlyDelta lr rr let s = joinV ls lk s rs let d = joinV ld lk d rd struct (s, d) elif lh > rh then let struct (rl, _lmax, rv, _rmin, rr) = splitV comparer lk r let key = lk let rk = () let lk = () match rv with | ValueSome rv -> let struct (s, d) = apply.Invoke(key, ValueSome lv, rv) let struct (ls, ld) = applyDelta comparer apply onlyDelta ll rl let struct (rs, rd) = applyDelta comparer apply onlyDelta lr rr let s = joinV ls key s rs let d = joinV ld key d rd struct (s, d) | ValueNone -> let struct (ls, ld) = applyDelta comparer apply onlyDelta ll rl let struct (rs, rd) = applyDelta comparer apply onlyDelta lr rr let s = join ls key lv rs let d = merge ld rd struct (s, d) else let struct (ll, _lmax, lv, _rmin, lr) = splitV comparer rk l let key = rk let rk = () let lk = () match lv with | ValueSome lv -> let struct (s, d) = apply.Invoke(key, ValueSome lv, rv) let struct (ls, ld) = applyDelta comparer apply onlyDelta ll rl let struct (rs, rd) = applyDelta comparer apply onlyDelta lr rr let s = joinV ls key s rs let d = joinV ld key d rd struct (s, d) | ValueNone -> let struct (s, d) = onlyDelta.Invoke(key, rv) let struct (ls, ld) = applyDelta comparer apply onlyDelta ll rl let struct (rs, rd) = applyDelta comparer apply onlyDelta lr rr let s = joinV ls key s rs let d = joinV ld key d rd struct (s, d) //| _ -> // let mutable state = l // let set = System.Collections.Generic.HashSet<_>() // let delta = // r |> choosei (fun i op -> // if not (set.Add i) then failwith "superbad" // let l = match tryFind comparer i l with | Some l -> ValueSome l | None -> ValueNone // let struct (s, d) = apply.Invoke(i, l, op) // match s with // | ValueSome s -> state <- add comparer i s state // | ValueNone -> state <- remove comparer i state // match d with // | ValueSome d -> Some d // | ValueNone -> None // ) // struct(state, delta) let rec computeDelta (comparer: IComparer<'Key>) (set : OptimizedClosures.FSharpFunc<'Key, 'Value, 'OP>) (update : OptimizedClosures.FSharpFunc<'Key, 'Value, 'Value, voption<'OP>>) (remove : OptimizedClosures.FSharpFunc<'Key, 'Value, 'OP>) (l : MapTree<'Key, 'Value>) (r : MapTree<'Key, 'Value>) = match struct (l, r) with | struct (MapEmpty, MapEmpty) -> MapEmpty | struct (MapEmpty, r) -> mapiOpt set r | struct (l, MapEmpty) -> mapiOpt remove l | struct (MapOne(lk, lv), MapOne(rk, rv)) -> if Object.ReferenceEquals(l, r) then MapEmpty else let c = comparer.Compare(lk, rk) if c = 0 then match update.Invoke(lk, lv, rv) with | ValueSome r -> MapOne(lk, r) | ValueNone -> MapEmpty elif c < 0 then MapNode(lk, remove.Invoke(lk, lv), MapEmpty, MapOne(rk, set.Invoke(rk, rv)), 2, 2) else MapNode(lk, remove.Invoke(lk, lv), MapOne(rk, set.Invoke(rk, rv)), MapEmpty, 2, 2) | struct (MapOne(lk, lv), MapNode(nk, nv, nl, nr, _, _)) -> let c = comparer.Compare(lk, nk) if c = 0 then let ll = mapiOpt set nl let rr = mapiOpt set nr match update.Invoke(lk, lv, nv) with | ValueSome op -> join ll lk op rr | ValueNone -> merge ll rr elif c > 0 then let rr = computeDelta comparer set update remove l nr join (mapiOpt set nl) nk (set.Invoke(nk, nv)) rr else let ll = computeDelta comparer set update remove l nl join ll nk (set.Invoke(nk, nv)) (mapiOpt set nr) | struct(MapNode(nk, nv, nl, nr, _, _), MapOne(rk, rv)) -> let c = comparer.Compare(rk, nk) if c = 0 then let ll = mapiOpt remove nl let rr = mapiOpt remove nr match update.Invoke(rk, nv, rv) with | ValueSome op -> join ll nk op rr | ValueNone -> merge ll rr elif c > 0 then let rr = computeDelta comparer set update remove nr r join (mapiOpt remove nl) nk (remove.Invoke(nk, nv)) rr else let ll = computeDelta comparer set update remove nl r join ll nk (remove.Invoke(nk, nv)) (mapiOpt remove nr) | struct(MapNode(lka, lva, lla, lra, lha, _), MapNode(rka, rva, rla, rra, rha, _rc)) -> if Object.ReferenceEquals(l, r) then MapEmpty else let c = comparer.Compare(lka, rka) if c = 0 then let l = computeDelta comparer set update remove lla rla let r = computeDelta comparer set update remove lra rra match update.Invoke(lka, lva, rva) with | ValueSome op -> join l lka op r | ValueNone -> merge l r elif rha < lha then let struct (rl, _lmax, rv, _rmin, rr) = splitV comparer lka r let l = computeDelta comparer set update remove lla rl let r = computeDelta comparer set update remove lra rr match rv with | ValueSome rv -> match update.Invoke(lka, lva, rv) with | ValueSome op -> join l lka op r | ValueNone -> merge l r | ValueNone -> let k = lka let v = remove.Invoke(lka, lva) join l k v r else let struct (ll, _lmax, lv, _rmin, lr) = splitV comparer rka l let l = computeDelta comparer set update remove ll rla let r = computeDelta comparer set update remove lr rra match lv with | ValueSome lv -> match update.Invoke(rka, lv, rva) with | ValueSome op -> join l rka op r | ValueNone -> merge l r | ValueNone -> let k = rka let v = set.Invoke(rka, rva) join l k v r let rec intersectWithAux (f:OptimizedClosures.FSharpFunc<'Key,'T1,'T2>) (comparer: IComparer<'k>) (l : MapTree<'k, 'Key>) (r : MapTree<'k, 'T1>) : MapTree<'k, 'T2> = match l with | MapEmpty -> MapEmpty | MapOne(k,lv) -> match tryFind comparer k r with | Some rv -> MapOne(k, f.Invoke(lv, rv)) | None -> MapEmpty | MapNode(k,v,l1,r1,_,_) -> let a, s, b = split comparer k r match s with | Some s -> let v = f.Invoke(v,s) rebalance (intersectWithAux f comparer l1 a) k v (intersectWithAux f comparer r1 b) | None -> let l = intersectWithAux f comparer l1 a let r = intersectWithAux f comparer r1 b match l with | MapEmpty -> r | _ -> match r with | MapEmpty -> l | _ -> let k,v,r' = spliceOutSuccessor r rebalance l k v r' let intersectWith (f : 'Key -> 'T1 -> 'T2) (comparer : IComparer<'k>) (l : MapTree<'k, 'Key>) (r : MapTree<'k, 'T1>) = let lc = size l let rc = size r if lc <= rc then intersectWithAux (OptimizedClosures.FSharpFunc<_,_,_>.Adapt f) comparer l r else intersectWithAux (OptimizedClosures.FSharpFunc<_,_,_>.Adapt(fun a b -> f b a)) comparer r l let rec foldBackOpt (f:OptimizedClosures.FSharpFunc<_,_,_,_>) m x = match m with | MapEmpty -> x | MapOne(k,v) -> f.Invoke(k,v,x) | MapNode(k,v,l,r,_,_) -> let x = foldBackOpt f r x let x = f.Invoke(k,v,x) foldBackOpt f l x let foldBack f m x = foldBackOpt (OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f)) m x let rec foldOpt (f:OptimizedClosures.FSharpFunc<_,_,_,_>) x m = match m with | MapEmpty -> x | MapOne(k,v) -> f.Invoke(x,k,v) | MapNode(k,v,l,r,_,_) -> let x = foldOpt f x l let x = f.Invoke(x,k,v) foldOpt f x r let fold f x m = foldOpt (OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f)) x m let foldSectionOpt (comparer: IComparer<'Value>) lo hi (f:OptimizedClosures.FSharpFunc<_,_,_,_>) m x = let rec foldFromTo (f:OptimizedClosures.FSharpFunc<_,_,_,_>) m x = match m with | MapEmpty -> x | MapOne(k,v) -> let cLoKey = comparer.Compare(lo,k) let cKeyHi = comparer.Compare(k,hi) let x = if cLoKey <= 0 && cKeyHi <= 0 then f.Invoke(k, v, x) else x x | MapNode(k,v,l,r,_,_) -> let cLoKey = comparer.Compare(lo,k) let cKeyHi = comparer.Compare(k,hi) let x = if cLoKey < 0 then foldFromTo f l x else x let x = if cLoKey <= 0 && cKeyHi <= 0 then f.Invoke(k, v, x) else x let x = if cKeyHi < 0 then foldFromTo f r x else x x if comparer.Compare(lo,hi) = 1 then x else foldFromTo f m x let foldSection (comparer: IComparer<'Value>) lo hi f m x = foldSectionOpt comparer lo hi (OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f)) m x let toList m = let rec loop m acc = match m with | MapEmpty -> acc | MapOne(k,v) -> (k,v)::acc | MapNode(k,v,l,r,_,_) -> loop l ((k,v)::loop r acc) loop m [] let toListV m = let rec loop m acc = match m with | MapEmpty -> acc | MapOne(k,v) -> struct(k,v)::acc | MapNode(k,v,l,r,_,_) -> loop l (struct(k,v)::loop r acc) loop m [] let rec private copyTo (array : array<'k * 'v>) (index : ref) m = match m with | MapEmpty -> () | MapOne(k,v) -> array.[!index] <- (k, v) index := !index + 1 | MapNode(k, v, l, r, _, _) -> copyTo array index l array.[!index] <- (k, v) index := !index + 1 copyTo array index r let rec private copyToV (array : array) (index : ref) m = match m with | MapEmpty -> () | MapOne(k,v) -> array.[!index] <- struct(k, v) index := !index + 1 | MapNode(k, v, l, r, _, _) -> copyToV array index l array.[!index] <- struct(k, v) index := !index + 1 copyToV array index r let rec private copyValuesTo (array : array<'v>) (index : ref) m = match m with | MapEmpty -> () | MapOne(k,v) -> array.[!index] <- v index := !index + 1 | MapNode(k, v, l, r, _, _) -> copyValuesTo array index l array.[!index] <- v index := !index + 1 copyValuesTo array index r let toArrayV m = let cnt = size m let arr = Array.zeroCreate cnt let index = ref 0 copyToV arr index m arr let toArray m = let cnt = size m let arr = Array.zeroCreate cnt let index = ref 0 copyTo arr index m arr let valueList m = let rec loop m acc = match m with | MapEmpty -> acc | MapOne(k,v) -> v::acc | MapNode(k,v,l,r,_,_) -> loop l (v::loop r acc) loop m [] let valueArray m = let cnt = size m let arr = Array.zeroCreate cnt let index = ref 0 copyValuesTo arr index m arr let ofList comparer l = List.fold (fun acc (k,v) -> add comparer k v acc) empty l let ofListV comparer l = List.fold (fun acc (struct (k,v)) -> add comparer k v acc) empty l let rec mkFromEnumerator comparer acc (e : IEnumerator<_>) = if e.MoveNext() then let (x,y) = e.Current mkFromEnumerator comparer (add comparer x y acc) e else acc let rec mkFromEnumeratorV comparer acc (e : IEnumerator<_>) = if e.MoveNext() then let struct (x,y) = e.Current mkFromEnumeratorV comparer (add comparer x y acc) e else acc let ofArray comparer (arr : array<_>) = let mutable res = empty for (x,y) in arr do res <- add comparer x y res res let ofArrayV comparer (arr : array<_>) = let mutable res = empty for struct (x,y) in arr do res <- add comparer x y res res let ofSeq comparer (c : seq<'Key * 'T>) = match c with | :? array<'Key * 'T> as xs -> ofArray comparer xs | :? list<'Key * 'T> as xs -> ofList comparer xs | _ -> use ie = c.GetEnumerator() mkFromEnumerator comparer empty ie let ofSeqV comparer (c : seq) = match c with | :? array as xs -> ofArrayV comparer xs | :? list as xs -> ofListV comparer xs | _ -> use ie = c.GetEnumerator() mkFromEnumeratorV comparer empty ie let copyToArray s (arr: _[]) i = let j = ref i s |> iter (fun x y -> arr.[!j] <- KeyValuePair(x,y); j := !j + 1) /// Imperative left-to-right iterators. [] type MapIterator<'Key,'Value when 'Key : comparison > = { /// invariant: always collapseLHS result mutable stack: MapTree<'Key,'Value> list; /// true when MoveNext has been called mutable started : bool } // collapseLHS: // a) Always returns either [] or a list starting with MapOne. // b) The "fringe" of the set stack is unchanged. let rec collapseLHS stack = match stack with | [] -> [] | MapEmpty :: rest -> collapseLHS rest | MapOne _ :: _ -> stack | (MapNode(k,v,l,r,_,_)) :: rest -> collapseLHS (l :: MapOne (k,v) :: r :: rest) let mkIterator s = { stack = collapseLHS [s]; started = false } let notStarted() = raise (InvalidOperationException("enumeration not started")) let alreadyFinished() = raise (InvalidOperationException("enumeration finished")) let current i = if i.started then match i.stack with | MapOne (k,v) :: _ -> new KeyValuePair<_,_>(k,v) | [] -> alreadyFinished() | _ -> failwith "Please report error: MapExt iterator, unexpected stack for current" else notStarted() let rec moveNext i = if i.started then match i.stack with | MapOne _ :: rest -> i.stack <- collapseLHS rest not i.stack.IsEmpty | [] -> false | _ -> failwith "Please report error: MapExt iterator, unexpected stack for moveNext" else i.started <- true (* The first call to MoveNext "starts" the enumeration. *) not i.stack.IsEmpty let mkIEnumerator s = let i = ref (mkIterator s) { new IEnumerator<_> with member __.Current = current !i interface System.Collections.IEnumerator with member __.Current = box (current !i) member __.MoveNext() = moveNext !i member __.Reset() = i := mkIterator s interface System.IDisposable with member __.Dispose() = ()} type MapTreeEnumerator<'k, 'v when 'k : comparison>(m : MapTree<'k, 'v>) = let mutable stack = [m] let mutable current = Unchecked.defaultof<'k * 'v> let rec move () = match stack with | [] -> false | MapEmpty :: rest -> stack <- rest move() | MapOne(key,value) :: rest -> stack <- rest current <- (key, value) true | MapNode(k,v,l,r,_,_) :: rest -> stack <- l :: (MapOne(k,v)) :: r :: rest move() interface System.Collections.IEnumerator with member x.MoveNext() = move() member x.Reset() = stack <- [m] current <- Unchecked.defaultof<'k * 'v> member x.Current = current :> obj interface IEnumerator<'k * 'v> with member x.Dispose() = stack <- [] current <- Unchecked.defaultof<'k * 'v> member x.Current = current type MapTreeBackwardEnumerator<'k, 'v when 'k : comparison>(m : MapTree<'k, 'v>) = let mutable stack = [m] let mutable current = Unchecked.defaultof<'k * 'v> let rec move () = match stack with | [] -> false | MapEmpty :: rest -> stack <- rest move() | MapOne(key,value) :: rest -> stack <- rest current <- (key, value) true | MapNode(k,v,l,r,_,_) :: rest -> stack <- r :: (MapOne(k,v)) :: l :: rest move() interface System.Collections.IEnumerator with member x.MoveNext() = move() member x.Reset() = stack <- [m] current <- Unchecked.defaultof<'k * 'v> member x.Current = current :> obj interface IEnumerator<'k * 'v> with member x.Dispose() = stack <- [] current <- Unchecked.defaultof<'k * 'v> member x.Current = current type ValueMapTreeEnumerator<'k, 'v when 'k : comparison>(m : MapTree<'k, 'v>) = let mutable stack = [m] let mutable current = Unchecked.defaultof let rec move () = match stack with | [] -> false | MapEmpty :: rest -> stack <- rest move() | MapOne(key,value) :: rest -> stack <- rest current <- struct(key, value) true | MapNode(k,v,l,r,_,_) :: rest -> stack <- l :: (MapOne(k,v)) :: r :: rest move() interface System.Collections.IEnumerator with member x.MoveNext() = move() member x.Reset() = stack <- [m] current <- Unchecked.defaultof<_> member x.Current = current :> obj interface IEnumerator with member x.Dispose() = stack <- [] current <- Unchecked.defaultof<_> member x.Current = current type ValueMapTreeBackwardEnumerator<'k, 'v when 'k : comparison>(m : MapTree<'k, 'v>) = let mutable stack = [m] let mutable current = Unchecked.defaultof let rec move () = match stack with | [] -> false | MapEmpty :: rest -> stack <- rest move() | MapOne(key,value) :: rest -> stack <- rest current <- struct(key, value) true | MapNode(k,v,l,r,_,_) :: rest -> stack <- r :: (MapOne(k,v)) :: l :: rest move() interface System.Collections.IEnumerator with member x.MoveNext() = move() member x.Reset() = stack <- [m] current <- Unchecked.defaultof<_> member x.Current = current :> obj interface IEnumerator with member x.Dispose() = stack <- [] current <- Unchecked.defaultof<_> member x.Current = current open MapExtImplementation [>)>] [] [] [] type MapExt<[]'Key,[]'Value when 'Key : comparison > internal(comparer: IComparer<'Key>, tree: MapTree<'Key,'Value>) = static let defaultComparer = LanguagePrimitives.FastGenericComparer<'Key> // We use .NET generics per-instantiation static fields to avoid allocating a new object for each empty // set (it is just a lookup into a .NET table of type-instantiation-indexed static fields). static let empty = new MapExt<'Key,'Value>(defaultComparer, MapTree<_,_>.MapEmpty) static member private CreatePickler (r : IPicklerResolver) = let pInt = r.Resolve() let pKey = r.Resolve<'Key>() let pValue = r.Resolve<'Value>() let pArray = Pickler.array (Pickler.pair pKey pValue) let read (rs : ReadState) = let _cnt = pInt.Read rs "count" let arr = pArray.Read rs "items" MapExt<'Key, 'Value>(defaultComparer, MapTree.ofArray defaultComparer arr) let write (ws : WriteState) (m : MapExt<'Key, 'Value>) = pInt.Write ws "count" m.Count pArray.Write ws "items" (m.ToArray()) let clone (cs : CloneState) (m : MapExt<'Key, 'Value>) = m.MapMonotonic (fun k v -> pKey.Clone cs k, pValue.Clone cs v) let accept (vs : VisitState) (m : MapExt<'Key, 'Value>) = for kv in m do pKey.Accept vs kv.Key; pValue.Accept vs kv.Value Pickler.FromPrimitives(read, write, clone, accept) static member Empty : MapExt<'Key,'Value> = empty static member Create(ie : IEnumerable<_>) : MapExt<'Key,'Value> = let comparer = LanguagePrimitives.FastGenericComparer<'Key> new MapExt<_,_>(comparer,MapTree.ofSeq comparer ie) static member CreateV(ie : IEnumerable<_>) : MapExt<'Key,'Value> = let comparer = LanguagePrimitives.FastGenericComparer<'Key> new MapExt<_,_>(comparer,MapTree.ofSeqV comparer ie) static member Create() : MapExt<'Key,'Value> = empty new(ie : seq<_>) = let comparer = LanguagePrimitives.FastGenericComparer<'Key> new MapExt<_,_>(comparer,MapTree.ofSeq comparer ie) [] member internal m.Comparer = comparer //[] member internal m.Tree = tree member m.Add(k,v) : MapExt<'Key,'Value> = new MapExt<'Key,'Value>(comparer,MapTree.add comparer k v tree) [] member m.IsEmpty = MapTree.isEmpty tree member m.Item with get(k : 'Key) = MapTree.find comparer k tree member x.Keys = let mutable s = Set.empty for (KeyValue(k,_)) in x do s <- s.Add k s member x.Values = x |> Seq.map (fun (KeyValue(_,v)) -> v) member x.TryAt i = MapTree.tryAt i tree member x.TryAtV i = MapTree.tryAtV i tree member x.Neighbours k = MapTree.neighbours comparer k tree member x.NeighboursAt i = MapTree.neighboursi i tree member x.NeighboursV k = MapTree.neighboursV comparer k tree member x.NeighboursAtV i = MapTree.neighboursVi i tree member x.TryGetIndex k = MapTree.tryGetIndex comparer k tree member x.TryGetIndexV k = MapTree.tryGetIndexV comparer k tree member m.TryPick(f) = MapTree.tryPick f tree member m.TryPickBack(f) = MapTree.tryPickBack f tree member m.Exists(f) = MapTree.exists f tree member m.Filter(f) : MapExt<'Key,'Value> = new MapExt<'Key,'Value>(comparer ,MapTree.filter comparer f tree) member m.ForAll(f) = MapTree.forall f tree member m.Fold f acc = MapTree.foldBack f tree acc member m.FoldSection (lo:'Key) (hi:'Key) f (acc:'z) = MapTree.foldSection comparer lo hi f tree acc member m.Iterate f = MapTree.iter f tree member m.MapRange f = new MapExt<'Key,'T2>(comparer,MapTree.map f tree) member m.Map f = new MapExt<'Key,'T2>(comparer,MapTree.mapi f tree) member m.MapMonotonic<'Key2, 'Value2 when 'Key2 : comparison> (f : 'Key -> 'Value -> 'Key2 * 'Value2) : MapExt<'Key2,'Value2> = new MapExt<'Key2,'Value2>(LanguagePrimitives.FastGenericComparer<'Key2>, MapTree.mapiMonotonic f tree) member m.ChooseMonotonic<'Key2, 'Value2 when 'Key2 : comparison> (f : 'Key -> 'Value -> option<'Key2 * 'Value2>) : MapExt<'Key2,'Value2> = new MapExt<'Key2,'Value2>(LanguagePrimitives.FastGenericComparer<'Key2>, MapTree.chooseiMonotonic f tree) member internal x.GetReference key = MapTree.getReference comparer 0 key tree member x.TryIndexOf key = match MapTree.getReference comparer 0 key tree with | Existing(i,_) -> Some i | _ -> None member x.TryRemoveMin() = match MapTree.tryRemoveMin comparer tree with | Some (k,v,t) -> Some(k,v, MapExt(comparer, t)) | None -> None member x.TryRemoveMax() = match MapTree.tryRemoveMax comparer tree with | Some (k,v,t) -> Some(k,v, MapExt(comparer, t)) | None -> None member x.TryRemoveMinV() = match MapTree.tryRemoveMinV comparer ValueNone tree with | ValueSome (struct(k,v,n,t)) -> ValueSome(struct(k, v, n, MapExt(comparer, t))) | ValueNone -> ValueNone member x.TryRemoveMaxV() = match MapTree.tryRemoveMaxV comparer ValueNone tree with | ValueSome (struct(k,v,p,t)) -> ValueSome(struct(k, v, p, MapExt(comparer, t))) | ValueNone -> ValueNone member m.Map2(other:MapExt<'Key,'Value2>, f) = let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt f let mapping k l r = f.Invoke(k, ValueOption.toOption l, ValueOption.toOption r) new MapExt<'Key,'Result>(comparer, MapTree.map2V comparer mapping tree other.Tree) member m.Map2V(other:MapExt<'Key,'Value2>, f) = new MapExt<'Key,'Result>(comparer, MapTree.map2V comparer f tree other.Tree) member m.Choose2(other:MapExt<'Key,'Value2>, f) = let inline v o = match o with | Some v -> ValueSome v | None -> ValueNone let inline o o = match o with | ValueSome v -> Some v | ValueNone -> None let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt f let mapping k l r = f.Invoke(k, o l, o r) |> v new MapExt<'Key,'Result>(comparer, MapTree.choose2V comparer mapping tree other.Tree) member m.Choose2V(other:MapExt<'Key,'Value2>, f) = new MapExt<'Key,'Result>(comparer, MapTree.choose2V comparer f tree other.Tree) member m.ComputeDelta(other:MapExt<'Key,'Value>, add, update, remove) = let add = OptimizedClosures.FSharpFunc<_,_,_>.Adapt add let update = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt update let remove = OptimizedClosures.FSharpFunc<_,_,_>.Adapt remove new MapExt<'Key,_>(comparer, MapTree.computeDelta comparer add update remove tree other.Tree) member m.ApplyDelta(other:MapExt<'Key,'Delta>, apply) = let apply = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt apply let onlyDelta = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(fun k d -> apply.Invoke(k, ValueNone, d)) let struct (s, d) = MapTree.applyDelta comparer apply onlyDelta tree other.Tree new MapExt<'Key,_>(comparer, s), new MapExt<'Key,_>(comparer, d) member m.Choose(f) = new MapExt<'Key, 'Value2>(comparer, MapTree.choosei f tree) member m.Alter(k, f) = new MapExt<'Key, 'Value>(comparer, MapTree.alter comparer k f tree) member m.Partition(f) : MapExt<'Key,'Value> * MapExt<'Key,'Value> = let r1,r2 = MapTree.partition comparer f tree in new MapExt<'Key,'Value>(comparer,r1), new MapExt<'Key,'Value>(comparer,r2) member m.Count = MapTree.size tree member x.TryMin = MapTree.tryMin tree member x.TryMax = MapTree.tryMax tree member x.TryMinKey = MapTree.tryMin tree |> Option.map fst member x.TryMaxKey = MapTree.tryMax tree |> Option.map fst member x.TryMinKeyV = MapTree.tryMinV tree |> ValueOption.map (fun struct(k,_) -> k) member x.TryMaxKeyV = MapTree.tryMaxV tree |> ValueOption.map (fun struct(k,_) -> k) member x.TryMinValue = MapTree.tryMin tree |> Option.map snd member x.TryMaxValue = MapTree.tryMax tree |> Option.map snd member x.TryMinValueV = MapTree.tryMinV tree |> ValueOption.map (fun struct(_,v) -> v) member x.TryMaxValueV = MapTree.tryMaxV tree |> ValueOption.map (fun struct(_,v) -> v) member x.Range(min, max) = MapExt<'Key, 'Value>(comparer, MapTree.range comparer min max tree) member x.Split (k) = let l, self, r = MapTree.split comparer k tree MapExt<'Key, 'Value>(comparer, l), self, MapExt<'Key, 'Value>(comparer, r) member x.SplitV (k) = let struct(l, lmax, self, rmin, r) = MapTree.splitV comparer k tree struct(MapExt<'Key, 'Value>(comparer, l), lmax, self, rmin, MapExt<'Key, 'Value>(comparer, r)) member x.UnionWith (other : MapExt<_,_>, resolve) = if x.IsEmpty then other elif other.IsEmpty then x else new MapExt<'Key, 'Value>(comparer, MapTree.unionWith comparer resolve tree other.Tree) member x.Union(other : MapExt<_,_>) = new MapExt<'Key, 'Value>(comparer, MapTree.union comparer tree other.Tree) member x.IntersectWith(other : MapExt<_,_>, resolve) = if x.IsEmpty || other.IsEmpty then MapExt<_,_>.Empty else new MapExt<'Key, _>(comparer, MapTree.intersectWith resolve comparer tree other.Tree) member x.Intersect(other : MapExt<_,_>) = if x.IsEmpty || other.IsEmpty then MapExt<_,_>.Empty else new MapExt<'Key, _>(comparer, MapTree.intersectWith (fun l r -> (l,r)) comparer tree other.Tree) member x.Validate() = MapTree.validate comparer tree member m.ContainsKey(k) = MapTree.mem comparer k tree member m.Remove(k) : MapExt<'Key,'Value> = new MapExt<'Key,'Value>(comparer,MapTree.remove comparer k tree) member m.TryRemove(k) : option<'Value * MapExt<'Key,'Value>> = match MapTree.tryRemove comparer k tree with | Some (v, t) -> Some(v, new MapExt<'Key,'Value>(comparer, t)) | None -> None member m.TryRemoveV(k) : voption)> = match MapTree.tryRemoveV comparer k tree with | ValueSome struct (v, t) -> ValueSome(struct(v, new MapExt<'Key,'Value>(comparer, t))) | ValueNone -> ValueNone member m.TryFind(k) = MapTree.tryFind comparer k tree member m.TryFindV(k) = MapTree.tryFindV comparer k tree member m.ToList() = MapTree.toList tree member m.ToArray() = MapTree.toArray tree member x.ToListV() = MapTree.toListV tree member x.ToArrayV() = MapTree.toArrayV tree member x.ToValueList() = MapTree.valueList tree member x.ToValueArray() = MapTree.valueArray tree static member ofList(l) : MapExt<'Key,'Value> = let comparer = LanguagePrimitives.FastGenericComparer<'Key> new MapExt<_,_>(comparer,MapTree.ofList comparer l) static member ofListV(l) : MapExt<'Key,'Value> = let comparer = LanguagePrimitives.FastGenericComparer<'Key> new MapExt<_,_>(comparer,MapTree.ofListV comparer l) member this.ComputeHashCode() = let combineHash x y = (x <<< 1) + y + 631 let mutable res = 0 for (KeyValue(x,y)) in this do res <- combineHash res (hash x) res <- combineHash res (Unchecked.hash y) abs res override this.Equals(that) = if System.Object.ReferenceEquals(this, that) then true else match that with | :? MapExt<'Key,'Value> as that -> use e1 = (this :> seq<_>).GetEnumerator() use e2 = (that :> seq<_>).GetEnumerator() let rec loop () = let m1 = e1.MoveNext() let m2 = e2.MoveNext() (m1 = m2) && (not m1 || let e1c, e2c = e1.Current, e2.Current in ((e1c.Key = e2c.Key) && (Unchecked.equals e1c.Value e2c.Value) && loop())) loop() | _ -> false override this.GetHashCode() = this.ComputeHashCode() member x.GetForwardEnumerator() = new MapTree.MapTreeEnumerator<'Key, 'Value>(tree) :> IEnumerator<_> member x.GetBackwardEnumerator() = new MapTree.MapTreeBackwardEnumerator<'Key, 'Value>(tree) :> IEnumerator<_> member x.GetForwardEnumeratorV() = new MapTree.ValueMapTreeEnumerator<'Key, 'Value>(tree) :> IEnumerator<_> member x.GetBackwardEnumeratorV() = new MapTree.ValueMapTreeBackwardEnumerator<'Key, 'Value>(tree) :> IEnumerator<_> interface IEnumerable> with member __.GetEnumerator() = MapTree.mkIEnumerator tree interface System.Collections.IEnumerable with member __.GetEnumerator() = (MapTree.mkIEnumerator tree :> System.Collections.IEnumerator) interface IDictionary<'Key, 'Value> with member m.Item with get x = m.[x] and set _ _ = raise (NotSupportedException("MapExt cannot be mutated.")) member m.Keys = KeyCollection(m) :> ICollection<'Key> member m.Values = ValueCollection(m) :> ICollection<'Value> member m.Add(_, _) = raise (NotSupportedException("MapExt cannot be mutated.")) member m.ContainsKey k = m.ContainsKey k member m.TryGetValue(k, r) = match m.TryFindV(k) with ValueSome v -> r <- v; true | _ -> false member m.Remove(_) = raise (NotSupportedException("MapExt cannot be mutated.")) interface ICollection> with member _.Add(_) = raise (NotSupportedException("MapExt cannot be mutated.")); member _.Clear() = raise (NotSupportedException("MapExt cannot be mutated.")); member _.Remove(_) = raise (NotSupportedException("MapExt cannot be mutated.")); member s.Contains(x) = s.ContainsKey(x.Key) && DefaultEquality.equals s.[x.Key] x.Value member _.CopyTo(arr,i) = MapTree.copyToArray tree arr i member s.IsReadOnly = true member s.Count = s.Count interface IReadOnlyCollection> with member m.Count = m.Count interface IReadOnlyDictionary<'Key, 'Value> with member m.Item with get key = m.[key] member m.Keys = KeyCollection(m) :> IEnumerable<'Key> member m.TryGetValue(key, value: byref<'Value>) = match m.TryFindV(key) with ValueSome r -> value <- r; true | _ -> false member m.Values = ValueCollection(m) :> IEnumerable<'Value> member m.ContainsKey key = m.ContainsKey key interface System.IComparable with member m.CompareTo(obj: obj) = match obj with | :? MapExt<'Key,'Value> as m2-> Seq.compareWith (fun (kvp1 : KeyValuePair<_,_>) (kvp2 : KeyValuePair<_,_>)-> let c = comparer.Compare(kvp1.Key,kvp2.Key) in if c <> 0 then c else Unchecked.compare kvp1.Value kvp2.Value) m m2 | _ -> invalidArg "obj" ("SR.GetString(SR.notComparable)") override x.ToString() = let suffix = if x.Count > 4 then "; ..." else "" let content = Seq.truncate 4 x |> Seq.map (fun (KeyValue t) -> sprintf "%A" t) |> String.concat "; " "map [" + content + suffix + "]" member private x.AsString = x.ToString() and [] internal MapDebugView<'Key,'Value when 'Key : comparison>(v: MapExt<'Key,'Value>) = [] member x.Items = v |> Seq.truncate 10000 |> Seq.toArray and internal KeyCollection<'Key,'Value when 'Key : comparison>(parent: MapExt<'Key,'Value>) = interface ICollection<'Key> with member _.Add(_) = raise (NotSupportedException("MapExt cannot be mutated.")) member _.Clear() = raise (NotSupportedException("MapExt cannot be mutated.")) member _.Remove(_) = raise (NotSupportedException("MapExt cannot be mutated.")) member _.Contains x = parent.ContainsKey x member _.CopyTo(arr, index) = if isNull arr then nullArg "arr" if index < 0 then invalidArg "index" "index must be positive" if index + parent.Count > arr.Length then invalidArg "index" "array is smaller than index plus the number of items to copy" let mutable i = index for item in parent do arr.[i] <- item.Key i <- i + 1 member _.IsReadOnly = true member _.Count = parent.Count interface IEnumerable<'Key> with member _.GetEnumerator() = (seq { for item in parent do item.Key }) .GetEnumerator() interface IEnumerable with member _.GetEnumerator() = (seq { for item in parent do item.Key }) .GetEnumerator() :> IEnumerator and internal ValueCollection<'Key, 'Value when 'Key: comparison>(parent: MapExt<'Key, 'Value>) = interface ICollection<'Value> with member _.Add(_) = raise (NotSupportedException("MapExt cannot be mutated.")) member _.Clear() = raise (NotSupportedException("MapExt cannot be mutated.")) member _.Remove(_) = raise (NotSupportedException("MapExt cannot be mutated.")) member _.Contains x = parent.Exists(fun _ value -> Unchecked.equals value x) member _.CopyTo(arr, index) = if isNull arr then nullArg "arr" if index < 0 then invalidArg "index" "index must be positive" if index + parent.Count > arr.Length then invalidArg "index" "array is smaller than index plus the number of items to copy" let mutable i = index for item in parent do arr.[i] <- item.Value i <- i + 1 member _.IsReadOnly = true member _.Count = parent.Count interface IEnumerable<'Value> with member _.GetEnumerator() = (seq { for item in parent do item.Value }) .GetEnumerator() interface IEnumerable with member _.GetEnumerator() = (seq { for item in parent do item.Value }) .GetEnumerator() :> IEnumerator [] [] module MapExt = [] let isEmpty (m:MapExt<_,_>) = m.IsEmpty [] let keys (m:MapExt<_,_>) = m.Keys [] let values (m:MapExt<_,_>) = m.Values [] let add k v (m:MapExt<_,_>) = m.Add(k,v) [] let find k (m:MapExt<_,_>) = m.[k] [] let tryFind k (m:MapExt<_,_>) = m.TryFind(k) [] let tryFindV k (m:MapExt<_,_>) = m.TryFindV(k) [] let remove k (m:MapExt<_,_>) = m.Remove(k) [] let tryRemove k (m:MapExt<_,_>) = m.TryRemove(k) [] let tryRemoveV k (m:MapExt<_,_>) = m.TryRemoveV(k) [] let tryRemoveMin (m:MapExt<_,_>) = m.TryRemoveMin() [] let tryRemoveMax (m:MapExt<_,_>) = m.TryRemoveMax() [] let tryRemoveMinV (m:MapExt<_,_>) = m.TryRemoveMinV() [] let tryRemoveMaxV (m:MapExt<_,_>) = m.TryRemoveMaxV() [] let containsKey k (m:MapExt<_,_>) = m.ContainsKey(k) [] let iter f (m:MapExt<_,_>) = m.Iterate(f) [] let tryPick f (m:MapExt<_,_>) = m.TryPick(f) [] let tryPickBack f (m:MapExt<_,_>) = m.TryPickBack(f) [] let pick f (m:MapExt<_,_>) = match tryPick f m with None -> raise (KeyNotFoundException()) | Some res -> res [] let exists f (m:MapExt<_,_>) = m.Exists(f) [] let filter f (m:MapExt<_,_>) = m.Filter(f) [] let partition f (m:MapExt<_,_>) = m.Partition(f) [] let forall f (m:MapExt<_,_>) = m.ForAll(f) [] let mapRange f (m:MapExt<_,_>) = m.MapRange(f) [] let map f (m:MapExt<_,_>) = m.Map(f) [] let fold<'Key,'T,'State when 'Key : comparison> f (z:'State) (m:MapExt<'Key,'T>) = MapTree.fold f z m.Tree [] let foldBack<'Key,'T,'State when 'Key : comparison> f (m:MapExt<'Key,'T>) (z:'State) = MapTree.foldBack f m.Tree z [] let toSeq (m:MapExt<_,_>) = m |> Seq.map (fun kvp -> kvp.Key, kvp.Value) [] let toSeqV (m:MapExt<_,_>) = m |> Seq.map (fun kvp -> struct(kvp.Key, kvp.Value)) [] let toValueSeq (m:MapExt<_,_>) = m |> Seq.map (fun kvp -> kvp.Value) [] let toSeqBack (m : MapExt<_,_>) = new EnumeratorEnumerable<_>(m.GetBackwardEnumerator) :> seq<_> [] let toSeqBackV (m : MapExt<_,_>) = new EnumeratorEnumerable<_>(m.GetBackwardEnumeratorV) :> seq<_> [] let findKey f (m : MapExt<_,_>) = m |> toSeq |> Seq.pick (fun (k,v) -> if f k v then Some(k) else None) [] let tryFindKey f (m : MapExt<_,_>) = m |> toSeq |> Seq.tryPick (fun (k,v) -> if f k v then Some(k) else None) [] let ofList (l: ('Key * 'Value) list) = MapExt<_,_>.ofList(l) [] let ofListV (l: (struct ('Key * 'Value)) list) = MapExt<_,_>.ofListV(l) [] let ofSeq l = MapExt<_,_>.Create(l) [] let ofSeqV l = MapExt<_,_>.CreateV(l) [] let singleton k v = MapExt<_,_>(LanguagePrimitives.FastGenericComparer<_>,MapOne(k,v)) [] let ofArray (array: ('Key * 'Value) array) = let comparer = LanguagePrimitives.FastGenericComparer<'Key> new MapExt<_,_>(comparer,MapTree.ofArray comparer array) [] let ofArrayV (array: (struct ('Key * 'Value)) array) = let comparer = LanguagePrimitives.FastGenericComparer<'Key> new MapExt<_,_>(comparer,MapTree.ofArrayV comparer array) [] let toList (m:MapExt<_,_>) = m.ToList() [] let toArray (m:MapExt<_,_>) = m.ToArray() [] let toListV (m:MapExt<_,_>) = m.ToListV() [] let toArrayV (m:MapExt<_,_>) = m.ToArrayV() [] let toValueList (m:MapExt<_,_>) = m.ToValueList() [] let toValueArray (m:MapExt<_,_>) = m.ToValueArray() [] let empty<'Key,'Value when 'Key : comparison> = MapExt<'Key,'Value>.Empty [] let count (m:MapExt<_,_>) = m.Count [] let tryMin (m:MapExt<_,_>) = m.TryMinKey [] let tryMinV (m:MapExt<_,_>) = m.TryMinKeyV [] let min (m:MapExt<_,_>) = match m.TryMinKey with | Some min -> min | None -> raise <| ArgumentException("The input sequence was empty.") [] let tryMax (m:MapExt<_,_>) = m.TryMaxKey [] let tryMaxV (m:MapExt<_,_>) = m.TryMaxKeyV [] let max (m:MapExt<_,_>) = match m.TryMaxKey with | Some min -> min | None -> raise <| ArgumentException("The input sequence was empty.") [] let tryItem i (m:MapExt<_,_>) = m.TryAt i [] let tryItemV i (m:MapExt<_,_>) = m.TryAtV i [] let item i (m:MapExt<_,_>) = match m.TryAt i with | Some t -> t | None -> raise <| IndexOutOfRangeException() [] let alter k f (m:MapExt<_,_>) = m.Alter(k, f) [] let mapMonotonic f (m:MapExt<_,_>) = m.MapMonotonic(f) [] let chooseMonotonic f (m:MapExt<_,_>) = m.ChooseMonotonic(f) [] let range min max (m:MapExt<_,_>) = m.Range(min, max) [] let split k (m:MapExt<_,_>) = m.Split k [] let splitV k (m:MapExt<_,_>) = m.SplitV k [] let tryIndexOf i (m:MapExt<_,_>) = m.TryIndexOf i [] let internal reference i (m:MapExt<_,_>) = m.GetReference i [] let union (l:MapExt<_,_>) r = l.Union r [] let unionWith f (l:MapExt<_,_>) r = l.UnionWith (r, f) [] let intersectWith f (l:MapExt<_,_>) r = l.IntersectWith (r, f) [] let intersect (l:MapExt<_,_>) r = l.Intersect r [] let map2 f (l:MapExt<_,_>) r = l.Map2 (r, f) [] let map2V f (l:MapExt<_,_>) r = l.Map2V (r, f) [] let choose f (l:MapExt<_,_>) = l.Choose (f) [] let choose2 f (l:MapExt<_,_>) r = l.Choose2 (r, f) [] let choose2V f (l:MapExt<_,_>) r = l.Choose2V (r, f) [] let neighbours k (m:MapExt<_,_>) = m.Neighbours k [] let neighboursAt i (m:MapExt<_,_>) = m.NeighboursAt i [] let neighboursV k (m:MapExt<_,_>) = m.NeighboursV k [] let neighboursAtV i (m:MapExt<_,_>) = m.NeighboursAtV i [] let tryGetIndex k (m:MapExt<_,_>) = m.TryGetIndex k [] let tryGetIndexV k (m:MapExt<_,_>) = m.TryGetIndexV k ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Immutable/RangeSet_auto.fs ================================================ namespace Aardvark.Base open System open System.Collections open System.Collections.Generic open Aardvark.Base type internal HalfRangeKind = | Left = 0 | Right = 1 module private RangeSetUtils = let inline inc (value : 'T) = let res = value + LanguagePrimitives.GenericOne<'T> if res = Constant<'T>.ParseableMinValue then struct (Constant<'T>.ParseableMaxValue, true) else struct (res, false) module MapExt = let inline splitAt (key : 'K) (map : MapExt<'K, 'V>) = let struct (l, _, _, _, r) = MapExt.splitV key map struct (l, r) let inline tryMinValue (map : MapExt<'K, 'V>) = MapExt.tryMinV map |> ValueOption.map (fun mk -> map.[mk]) let inline tryMaxValue (map : MapExt<'K, 'V>) = MapExt.tryMaxV map |> ValueOption.map (fun mk -> map.[mk]) let inline maxValue (map : MapExt<'K, 'V>) = map.[MapExt.max map] open RangeSetUtils /// Set of ranges where overlapping and neighboring ranges are coalesced. /// Note that ranges describe closed intervals. [] type RangeSet1i internal (store : MapExt) = static let empty = RangeSet1i(MapExt.empty) /// Empty range set. static member Empty = empty member inline private x.Store = store // We cannot directly describe a range that ends at Int32.MaxValue since the right half-range is inserted // at max + 1. In that case the right-half range will be missing and the total count is odd. member inline private x.HasMaxValue = store.Count % 2 = 1 /// Returns the minimum value in the range set or Int32.MaxValue if the range is empty. member x.Min = match store.TryMinKeyV with | ValueSome min -> min | _ -> Int32.MaxValue /// Returns the maximum value in the range set or Int32.MinValue if the range is empty. member x.Max = if x.HasMaxValue then Int32.MaxValue else match store.TryMaxKeyV with | ValueSome max -> max - 1 | _ -> Int32.MinValue /// Returns the total range spanned by the range set, i.e. [min, max]. member inline x.Range = Range1i(x.Min, x.Max) /// Adds the given range to the set. member x.Add(r : Range1i) = if r.Max < r.Min then x else let min = r.Min let struct (max, overflow) = inc r.Max let struct (lm, inner) = MapExt.splitAt min store let rm = if overflow then MapExt.empty else sndv <| MapExt.splitAt max inner let before = MapExt.tryMaxValue lm let after = MapExt.tryMinValue rm // If the set contained Int32.MaxValue or we have overflown, we must not add an explicit right half-range. // Int32.MaxValue is stored implicitly. let fixRightBoundary = if x.HasMaxValue || overflow then id else MapExt.add max HalfRangeKind.Right let newStore = match before, after with | ValueNone, ValueNone -> MapExt.ofListV [ struct (min, HalfRangeKind.Left) ] |> fixRightBoundary | ValueSome HalfRangeKind.Right, ValueNone -> lm |> MapExt.add min HalfRangeKind.Left |> fixRightBoundary | ValueSome HalfRangeKind.Left, ValueNone -> lm |> fixRightBoundary | ValueNone, ValueSome HalfRangeKind.Left -> rm |> MapExt.add min HalfRangeKind.Left |> MapExt.add max HalfRangeKind.Right | ValueNone, ValueSome HalfRangeKind.Right -> rm |> MapExt.add min HalfRangeKind.Left | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Left -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Left); struct (max, HalfRangeKind.Right) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Left -> let self = MapExt.ofListV [ struct (max, HalfRangeKind.Right) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Right -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Left) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Right -> MapExt.union lm rm | _ -> failwithf "impossible" assert (newStore.Count % 2 = 0 || MapExt.maxValue newStore = HalfRangeKind.Left) RangeSet1i(newStore) /// Removes the given range from the set. member x.Remove(r : Range1i) = if r.Max < r.Min then x else let min = r.Min let struct (max, overflow) = inc r.Max let struct (lm, inner) = MapExt.splitAt min store let rm = if overflow then MapExt.empty else sndv <| MapExt.splitAt max inner let before = MapExt.tryMaxValue lm let after = MapExt.tryMinValue rm // If the set contained Int32.MaxValue and we have not overflown, there is still a range [max, Int32.MaxValue] let fixRightBoundary = if x.HasMaxValue && not overflow then MapExt.add max HalfRangeKind.Left else id let newStore = match before, after with | ValueNone, ValueNone -> MapExt.empty |> fixRightBoundary | ValueSome HalfRangeKind.Right, ValueNone -> lm |> fixRightBoundary | ValueSome HalfRangeKind.Left, ValueNone -> lm |> MapExt.add min HalfRangeKind.Right |> fixRightBoundary | ValueNone, ValueSome HalfRangeKind.Left -> rm | ValueNone, ValueSome HalfRangeKind.Right -> rm |> MapExt.add max HalfRangeKind.Left | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Left -> MapExt.union lm rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Left -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Right) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Right -> let self = MapExt.ofListV [ struct (max, HalfRangeKind.Left) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Right -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Right); struct (max, HalfRangeKind.Left) ] MapExt.union (MapExt.union lm self) rm | _ -> failwithf "impossible" assert (newStore.Count % 2 = 0 || MapExt.maxValue newStore = HalfRangeKind.Left) RangeSet1i(newStore) /// Returns the union of the set with the given set. member inline x.Union(other : RangeSet1i) = let mutable res = x for r in other do res <- res.Add r res /// Returns the intersection of the set with the given range. member x.Intersect(r : Range1i) = if r.Max < r.Min then empty else let min = r.Min let struct (max, overflow) = inc r.Max let inner = store |> MapExt.splitAt min |> sndv |> if not overflow then MapExt.splitAt max >> fstv else id let newStore = inner |> if x.Contains r.Min then MapExt.add min HalfRangeKind.Left else id |> if x.Contains r.Max && not overflow then MapExt.add max HalfRangeKind.Right else id assert (newStore.Count % 2 = 0 || MapExt.maxValue newStore = HalfRangeKind.Left) RangeSet1i(newStore) member private x.TryFindLeftBoundary(v : int32) = let struct (l, s, _) = MapExt.neighboursV v store match s with | ValueSome (i, k) -> if k = HalfRangeKind.Left then ValueSome i else ValueNone | _ -> match l with | ValueSome (i, HalfRangeKind.Left) -> ValueSome i | _ -> ValueNone /// Returns whether the given value is contained in the range set. member x.Contains(v : int32) = x.TryFindLeftBoundary v |> ValueOption.isSome /// Returns whether the given range is contained in the set. member x.Contains(r : Range1i) = if r.Max < r.Min then false elif r.Min = r.Max then x.Contains r.Min else match x.TryFindLeftBoundary r.Min, x.TryFindLeftBoundary r.Max with | ValueSome l, ValueSome r -> l = r | _ -> false /// Returns the number of disjoint ranges in the set. member x.Count = (store.Count + 1) / 2 /// Returns whether the set is empty. member inline x.IsEmpty = x.Count = 0 /// Builds an array from the range set. member x.ToArray() = let arr = Array.zeroCreate x.Count let rec write (i : int) (l : struct (int32 * HalfRangeKind) list) = match l with | struct (l, _) :: struct (r, _) :: rest -> arr.[i] <- Range1i(l, r - 1) write (i + 1) rest | [struct (l, HalfRangeKind.Left)] when i = x.Count - 1 -> arr.[i] <- Range1i(l, Int32.MaxValue) | [_] -> failwith "bad RangeSet" | [] -> () store |> MapExt.toListV |> write 0 arr /// Builds a list from the range set. member x.ToList() = let rec build (accum : Range1i list) (l : struct (int32 * HalfRangeKind) list) = match l with | struct (l, _) :: struct (r, _) :: rest -> build (Range1i(l, r - 1) :: accum) rest | [struct (l, HalfRangeKind.Left)] -> build (Range1i(l, Int32.MaxValue) :: accum) [] | [_] -> failwith "bad RangeSet" | [] -> List.rev accum store |> MapExt.toListV |> build [] /// Views the range set as a sequence. member x.ToSeq() = x :> seq<_> member inline private x.Equals(other : RangeSet1i) = store = other.Store override x.Equals(other : obj) = match other with | :? RangeSet1i as o -> x.Equals o | _ -> false override x.GetHashCode() = store.GetHashCode() member private x.AsString = x.ToString() override x.ToString() = let content = x |> Seq.map (fun r -> $"[{r.Min}, {r.Max}]" ) |> String.concat "; " $"ranges [{content}]" member x.GetEnumerator() = new RangeSetEnumerator1i((store :> seq<_>).GetEnumerator()) interface IEquatable with member x.Equals(other) = x.Equals(other) interface IEnumerable with member x.GetEnumerator() = new RangeSetEnumerator1i((store :> seq<_>).GetEnumerator()) :> _ interface IEnumerable with member x.GetEnumerator() = new RangeSetEnumerator1i((store :> seq<_>).GetEnumerator()) :> _ // TODO: MapExt should use a struct enumerator and return it directly. // That way we could get rid of allocations. and RangeSetEnumerator1i = struct val private Inner : IEnumerator> val mutable private Left : KeyValuePair val mutable private Right : KeyValuePair internal new (inner : IEnumerator>) = { Inner = inner Left = Unchecked.defaultof<_> Right = Unchecked.defaultof<_> } member x.MoveNext() = if x.Inner.MoveNext() then x.Left <- x.Inner.Current if x.Inner.MoveNext() then x.Right <- x.Inner.Current true else if x.Left.Value = HalfRangeKind.Left then x.Right <- KeyValuePair(Int32.MinValue, HalfRangeKind.Right) // MaxValue + 1 true else failwithf "bad RangeSet" else false member x.Reset() = x.Inner.Reset() x.Left <- Unchecked.defaultof<_> x.Right <- Unchecked.defaultof<_> member x.Current = assert (x.Left.Value = HalfRangeKind.Left && x.Right.Value = HalfRangeKind.Right) Range1i(x.Left.Key, x.Right.Key - 1) member x.Dispose() = x.Inner.Dispose() x.Left <- Unchecked.defaultof<_> x.Right <- Unchecked.defaultof<_> interface IEnumerator with member x.MoveNext() = x.MoveNext() member x.Current = x.Current :> obj member x.Reset() = x.Reset() interface IEnumerator with member x.Dispose() = x.Dispose() member x.Current = x.Current end [] module RangeSet1i = /// Empty range set. let empty = RangeSet1i.Empty /// Returns the minimum value in the range set or Int32.MaxValue if the range is empty. let inline min (set : RangeSet1i) = set.Min /// Returns the maximum value in the range set or Int32.MinValue if the range is empty. let inline max (set : RangeSet1i) = set.Max /// Returns the total range spanned by the range set, i.e. [min, max]. let inline range (set : RangeSet1i) = set.Range let inline private getHalfRanges (r : Range1i) = [ struct (r.Min, HalfRangeKind.Left) if r.Max < Int32.MaxValue then struct (r.Max + 1, HalfRangeKind.Right) ] let inline private ofRange (r : Range1i) = RangeSet1i(MapExt.ofListV <| getHalfRanges r) let private ofRanges (ranges : seq) = let halves = ranges |> Seq.toList |> List.collect getHalfRanges |> List.sortBy fstv let mutable level = 0 let result = ResizeArray() for (struct (i, k) as h) in halves do if k = HalfRangeKind.Left then if level = 0 then result.Add h level <- level + 1 else level <- level - 1 if level = 0 then result.Add h RangeSet1i(MapExt.ofSeqV result) /// Builds a range set of the given list of ranges. let ofList (ranges : Range1i list) = match ranges with | [] -> empty | [r] -> ofRange r | _ -> ofRanges ranges /// Builds a range set of the given array of ranges. let ofArray (ranges : Range1i[]) = if ranges.Length = 0 then empty elif ranges.Length = 1 then ofRange ranges.[0] else ofRanges ranges /// Builds a range set of the given sequence of ranges. let inline ofSeq (ranges : seq) = ofList <| Seq.toList ranges /// Adds the given range to the set. let inline add (range : Range1i) (set : RangeSet1i) = set.Add range /// Removes the given range from the set. let inline remove (range : Range1i) (set : RangeSet1i) = set.Remove range /// Returns the union of two sets. let inline union (l : RangeSet1i) (r : RangeSet1i) = l.Union r /// Returns the intersection of the set with the given range. let inline intersect (range : Range1i) (set : RangeSet1i) = set.Intersect range /// Returns whether the given value is contained in the range set. let inline contains (value : int32) (set : RangeSet1i) = set.Contains value /// Returns whether the given range is contained in the set. let inline containsRange (range : Range1i) (set : RangeSet1i) = set.Contains range /// Returns the number of disjoint ranges in the set. let inline count (set : RangeSet1i) = set.Count /// Returns whether the set is empty. let inline isEmpty (set : RangeSet1i) = set.IsEmpty /// Views the range set as a sequence. let inline toSeq (set : RangeSet1i) = set :> seq<_> /// Builds a list from the range set. let inline toList (set : RangeSet1i) = set.ToList() /// Builds an array from the range set. let inline toArray (set : RangeSet1i) = set.ToArray() /// Set of ranges where overlapping and neighboring ranges are coalesced. /// Note that ranges describe closed intervals. [] type RangeSet1ui internal (store : MapExt) = static let empty = RangeSet1ui(MapExt.empty) /// Empty range set. static member Empty = empty member inline private x.Store = store // We cannot directly describe a range that ends at UInt32.MaxValue since the right half-range is inserted // at max + 1. In that case the right-half range will be missing and the total count is odd. member inline private x.HasMaxValue = store.Count % 2 = 1 /// Returns the minimum value in the range set or UInt32.MaxValue if the range is empty. member x.Min = match store.TryMinKeyV with | ValueSome min -> min | _ -> UInt32.MaxValue /// Returns the maximum value in the range set or UInt32.MinValue if the range is empty. member x.Max = if x.HasMaxValue then UInt32.MaxValue else match store.TryMaxKeyV with | ValueSome max -> max - 1u | _ -> UInt32.MinValue /// Returns the total range spanned by the range set, i.e. [min, max]. member inline x.Range = Range1ui(x.Min, x.Max) /// Adds the given range to the set. member x.Add(r : Range1ui) = if r.Max < r.Min then x else let min = r.Min let struct (max, overflow) = inc r.Max let struct (lm, inner) = MapExt.splitAt min store let rm = if overflow then MapExt.empty else sndv <| MapExt.splitAt max inner let before = MapExt.tryMaxValue lm let after = MapExt.tryMinValue rm // If the set contained UInt32.MaxValue or we have overflown, we must not add an explicit right half-range. // UInt32.MaxValue is stored implicitly. let fixRightBoundary = if x.HasMaxValue || overflow then id else MapExt.add max HalfRangeKind.Right let newStore = match before, after with | ValueNone, ValueNone -> MapExt.ofListV [ struct (min, HalfRangeKind.Left) ] |> fixRightBoundary | ValueSome HalfRangeKind.Right, ValueNone -> lm |> MapExt.add min HalfRangeKind.Left |> fixRightBoundary | ValueSome HalfRangeKind.Left, ValueNone -> lm |> fixRightBoundary | ValueNone, ValueSome HalfRangeKind.Left -> rm |> MapExt.add min HalfRangeKind.Left |> MapExt.add max HalfRangeKind.Right | ValueNone, ValueSome HalfRangeKind.Right -> rm |> MapExt.add min HalfRangeKind.Left | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Left -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Left); struct (max, HalfRangeKind.Right) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Left -> let self = MapExt.ofListV [ struct (max, HalfRangeKind.Right) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Right -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Left) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Right -> MapExt.union lm rm | _ -> failwithf "impossible" assert (newStore.Count % 2 = 0 || MapExt.maxValue newStore = HalfRangeKind.Left) RangeSet1ui(newStore) /// Removes the given range from the set. member x.Remove(r : Range1ui) = if r.Max < r.Min then x else let min = r.Min let struct (max, overflow) = inc r.Max let struct (lm, inner) = MapExt.splitAt min store let rm = if overflow then MapExt.empty else sndv <| MapExt.splitAt max inner let before = MapExt.tryMaxValue lm let after = MapExt.tryMinValue rm // If the set contained UInt32.MaxValue and we have not overflown, there is still a range [max, UInt32.MaxValue] let fixRightBoundary = if x.HasMaxValue && not overflow then MapExt.add max HalfRangeKind.Left else id let newStore = match before, after with | ValueNone, ValueNone -> MapExt.empty |> fixRightBoundary | ValueSome HalfRangeKind.Right, ValueNone -> lm |> fixRightBoundary | ValueSome HalfRangeKind.Left, ValueNone -> lm |> MapExt.add min HalfRangeKind.Right |> fixRightBoundary | ValueNone, ValueSome HalfRangeKind.Left -> rm | ValueNone, ValueSome HalfRangeKind.Right -> rm |> MapExt.add max HalfRangeKind.Left | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Left -> MapExt.union lm rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Left -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Right) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Right -> let self = MapExt.ofListV [ struct (max, HalfRangeKind.Left) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Right -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Right); struct (max, HalfRangeKind.Left) ] MapExt.union (MapExt.union lm self) rm | _ -> failwithf "impossible" assert (newStore.Count % 2 = 0 || MapExt.maxValue newStore = HalfRangeKind.Left) RangeSet1ui(newStore) /// Returns the union of the set with the given set. member inline x.Union(other : RangeSet1ui) = let mutable res = x for r in other do res <- res.Add r res /// Returns the intersection of the set with the given range. member x.Intersect(r : Range1ui) = if r.Max < r.Min then empty else let min = r.Min let struct (max, overflow) = inc r.Max let inner = store |> MapExt.splitAt min |> sndv |> if not overflow then MapExt.splitAt max >> fstv else id let newStore = inner |> if x.Contains r.Min then MapExt.add min HalfRangeKind.Left else id |> if x.Contains r.Max && not overflow then MapExt.add max HalfRangeKind.Right else id assert (newStore.Count % 2 = 0 || MapExt.maxValue newStore = HalfRangeKind.Left) RangeSet1ui(newStore) member private x.TryFindLeftBoundary(v : uint32) = let struct (l, s, _) = MapExt.neighboursV v store match s with | ValueSome (i, k) -> if k = HalfRangeKind.Left then ValueSome i else ValueNone | _ -> match l with | ValueSome (i, HalfRangeKind.Left) -> ValueSome i | _ -> ValueNone /// Returns whether the given value is contained in the range set. member x.Contains(v : uint32) = x.TryFindLeftBoundary v |> ValueOption.isSome /// Returns whether the given range is contained in the set. member x.Contains(r : Range1ui) = if r.Max < r.Min then false elif r.Min = r.Max then x.Contains r.Min else match x.TryFindLeftBoundary r.Min, x.TryFindLeftBoundary r.Max with | ValueSome l, ValueSome r -> l = r | _ -> false /// Returns the number of disjoint ranges in the set. member x.Count = (store.Count + 1) / 2 /// Returns whether the set is empty. member inline x.IsEmpty = x.Count = 0 /// Builds an array from the range set. member x.ToArray() = let arr = Array.zeroCreate x.Count let rec write (i : int) (l : struct (uint32 * HalfRangeKind) list) = match l with | struct (l, _) :: struct (r, _) :: rest -> arr.[i] <- Range1ui(l, r - 1u) write (i + 1) rest | [struct (l, HalfRangeKind.Left)] when i = x.Count - 1 -> arr.[i] <- Range1ui(l, UInt32.MaxValue) | [_] -> failwith "bad RangeSet" | [] -> () store |> MapExt.toListV |> write 0 arr /// Builds a list from the range set. member x.ToList() = let rec build (accum : Range1ui list) (l : struct (uint32 * HalfRangeKind) list) = match l with | struct (l, _) :: struct (r, _) :: rest -> build (Range1ui(l, r - 1u) :: accum) rest | [struct (l, HalfRangeKind.Left)] -> build (Range1ui(l, UInt32.MaxValue) :: accum) [] | [_] -> failwith "bad RangeSet" | [] -> List.rev accum store |> MapExt.toListV |> build [] /// Views the range set as a sequence. member x.ToSeq() = x :> seq<_> member inline private x.Equals(other : RangeSet1ui) = store = other.Store override x.Equals(other : obj) = match other with | :? RangeSet1ui as o -> x.Equals o | _ -> false override x.GetHashCode() = store.GetHashCode() member private x.AsString = x.ToString() override x.ToString() = let content = x |> Seq.map (fun r -> $"[{r.Min}, {r.Max}]" ) |> String.concat "; " $"ranges [{content}]" member x.GetEnumerator() = new RangeSetEnumerator1ui((store :> seq<_>).GetEnumerator()) interface IEquatable with member x.Equals(other) = x.Equals(other) interface IEnumerable with member x.GetEnumerator() = new RangeSetEnumerator1ui((store :> seq<_>).GetEnumerator()) :> _ interface IEnumerable with member x.GetEnumerator() = new RangeSetEnumerator1ui((store :> seq<_>).GetEnumerator()) :> _ // TODO: MapExt should use a struct enumerator and return it directly. // That way we could get rid of allocations. and RangeSetEnumerator1ui = struct val private Inner : IEnumerator> val mutable private Left : KeyValuePair val mutable private Right : KeyValuePair internal new (inner : IEnumerator>) = { Inner = inner Left = Unchecked.defaultof<_> Right = Unchecked.defaultof<_> } member x.MoveNext() = if x.Inner.MoveNext() then x.Left <- x.Inner.Current if x.Inner.MoveNext() then x.Right <- x.Inner.Current true else if x.Left.Value = HalfRangeKind.Left then x.Right <- KeyValuePair(UInt32.MinValue, HalfRangeKind.Right) // MaxValue + 1 true else failwithf "bad RangeSet" else false member x.Reset() = x.Inner.Reset() x.Left <- Unchecked.defaultof<_> x.Right <- Unchecked.defaultof<_> member x.Current = assert (x.Left.Value = HalfRangeKind.Left && x.Right.Value = HalfRangeKind.Right) Range1ui(x.Left.Key, x.Right.Key - 1u) member x.Dispose() = x.Inner.Dispose() x.Left <- Unchecked.defaultof<_> x.Right <- Unchecked.defaultof<_> interface IEnumerator with member x.MoveNext() = x.MoveNext() member x.Current = x.Current :> obj member x.Reset() = x.Reset() interface IEnumerator with member x.Dispose() = x.Dispose() member x.Current = x.Current end [] module RangeSet1ui = /// Empty range set. let empty = RangeSet1ui.Empty /// Returns the minimum value in the range set or UInt32.MaxValue if the range is empty. let inline min (set : RangeSet1ui) = set.Min /// Returns the maximum value in the range set or UInt32.MinValue if the range is empty. let inline max (set : RangeSet1ui) = set.Max /// Returns the total range spanned by the range set, i.e. [min, max]. let inline range (set : RangeSet1ui) = set.Range let inline private getHalfRanges (r : Range1ui) = [ struct (r.Min, HalfRangeKind.Left) if r.Max < UInt32.MaxValue then struct (r.Max + 1u, HalfRangeKind.Right) ] let inline private ofRange (r : Range1ui) = RangeSet1ui(MapExt.ofListV <| getHalfRanges r) let private ofRanges (ranges : seq) = let halves = ranges |> Seq.toList |> List.collect getHalfRanges |> List.sortBy fstv let mutable level = 0 let result = ResizeArray() for (struct (i, k) as h) in halves do if k = HalfRangeKind.Left then if level = 0 then result.Add h level <- level + 1 else level <- level - 1 if level = 0 then result.Add h RangeSet1ui(MapExt.ofSeqV result) /// Builds a range set of the given list of ranges. let ofList (ranges : Range1ui list) = match ranges with | [] -> empty | [r] -> ofRange r | _ -> ofRanges ranges /// Builds a range set of the given array of ranges. let ofArray (ranges : Range1ui[]) = if ranges.Length = 0 then empty elif ranges.Length = 1 then ofRange ranges.[0] else ofRanges ranges /// Builds a range set of the given sequence of ranges. let inline ofSeq (ranges : seq) = ofList <| Seq.toList ranges /// Adds the given range to the set. let inline add (range : Range1ui) (set : RangeSet1ui) = set.Add range /// Removes the given range from the set. let inline remove (range : Range1ui) (set : RangeSet1ui) = set.Remove range /// Returns the union of two sets. let inline union (l : RangeSet1ui) (r : RangeSet1ui) = l.Union r /// Returns the intersection of the set with the given range. let inline intersect (range : Range1ui) (set : RangeSet1ui) = set.Intersect range /// Returns whether the given value is contained in the range set. let inline contains (value : uint32) (set : RangeSet1ui) = set.Contains value /// Returns whether the given range is contained in the set. let inline containsRange (range : Range1ui) (set : RangeSet1ui) = set.Contains range /// Returns the number of disjoint ranges in the set. let inline count (set : RangeSet1ui) = set.Count /// Returns whether the set is empty. let inline isEmpty (set : RangeSet1ui) = set.IsEmpty /// Views the range set as a sequence. let inline toSeq (set : RangeSet1ui) = set :> seq<_> /// Builds a list from the range set. let inline toList (set : RangeSet1ui) = set.ToList() /// Builds an array from the range set. let inline toArray (set : RangeSet1ui) = set.ToArray() /// Set of ranges where overlapping and neighboring ranges are coalesced. /// Note that ranges describe closed intervals. [] type RangeSet1l internal (store : MapExt) = static let empty = RangeSet1l(MapExt.empty) /// Empty range set. static member Empty = empty member inline private x.Store = store // We cannot directly describe a range that ends at Int64.MaxValue since the right half-range is inserted // at max + 1. In that case the right-half range will be missing and the total count is odd. member inline private x.HasMaxValue = store.Count % 2 = 1 /// Returns the minimum value in the range set or Int64.MaxValue if the range is empty. member x.Min = match store.TryMinKeyV with | ValueSome min -> min | _ -> Int64.MaxValue /// Returns the maximum value in the range set or Int64.MinValue if the range is empty. member x.Max = if x.HasMaxValue then Int64.MaxValue else match store.TryMaxKeyV with | ValueSome max -> max - 1L | _ -> Int64.MinValue /// Returns the total range spanned by the range set, i.e. [min, max]. member inline x.Range = Range1l(x.Min, x.Max) /// Adds the given range to the set. member x.Add(r : Range1l) = if r.Max < r.Min then x else let min = r.Min let struct (max, overflow) = inc r.Max let struct (lm, inner) = MapExt.splitAt min store let rm = if overflow then MapExt.empty else sndv <| MapExt.splitAt max inner let before = MapExt.tryMaxValue lm let after = MapExt.tryMinValue rm // If the set contained Int64.MaxValue or we have overflown, we must not add an explicit right half-range. // Int64.MaxValue is stored implicitly. let fixRightBoundary = if x.HasMaxValue || overflow then id else MapExt.add max HalfRangeKind.Right let newStore = match before, after with | ValueNone, ValueNone -> MapExt.ofListV [ struct (min, HalfRangeKind.Left) ] |> fixRightBoundary | ValueSome HalfRangeKind.Right, ValueNone -> lm |> MapExt.add min HalfRangeKind.Left |> fixRightBoundary | ValueSome HalfRangeKind.Left, ValueNone -> lm |> fixRightBoundary | ValueNone, ValueSome HalfRangeKind.Left -> rm |> MapExt.add min HalfRangeKind.Left |> MapExt.add max HalfRangeKind.Right | ValueNone, ValueSome HalfRangeKind.Right -> rm |> MapExt.add min HalfRangeKind.Left | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Left -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Left); struct (max, HalfRangeKind.Right) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Left -> let self = MapExt.ofListV [ struct (max, HalfRangeKind.Right) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Right -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Left) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Right -> MapExt.union lm rm | _ -> failwithf "impossible" assert (newStore.Count % 2 = 0 || MapExt.maxValue newStore = HalfRangeKind.Left) RangeSet1l(newStore) /// Removes the given range from the set. member x.Remove(r : Range1l) = if r.Max < r.Min then x else let min = r.Min let struct (max, overflow) = inc r.Max let struct (lm, inner) = MapExt.splitAt min store let rm = if overflow then MapExt.empty else sndv <| MapExt.splitAt max inner let before = MapExt.tryMaxValue lm let after = MapExt.tryMinValue rm // If the set contained Int64.MaxValue and we have not overflown, there is still a range [max, Int64.MaxValue] let fixRightBoundary = if x.HasMaxValue && not overflow then MapExt.add max HalfRangeKind.Left else id let newStore = match before, after with | ValueNone, ValueNone -> MapExt.empty |> fixRightBoundary | ValueSome HalfRangeKind.Right, ValueNone -> lm |> fixRightBoundary | ValueSome HalfRangeKind.Left, ValueNone -> lm |> MapExt.add min HalfRangeKind.Right |> fixRightBoundary | ValueNone, ValueSome HalfRangeKind.Left -> rm | ValueNone, ValueSome HalfRangeKind.Right -> rm |> MapExt.add max HalfRangeKind.Left | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Left -> MapExt.union lm rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Left -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Right) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Right -> let self = MapExt.ofListV [ struct (max, HalfRangeKind.Left) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Right -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Right); struct (max, HalfRangeKind.Left) ] MapExt.union (MapExt.union lm self) rm | _ -> failwithf "impossible" assert (newStore.Count % 2 = 0 || MapExt.maxValue newStore = HalfRangeKind.Left) RangeSet1l(newStore) /// Returns the union of the set with the given set. member inline x.Union(other : RangeSet1l) = let mutable res = x for r in other do res <- res.Add r res /// Returns the intersection of the set with the given range. member x.Intersect(r : Range1l) = if r.Max < r.Min then empty else let min = r.Min let struct (max, overflow) = inc r.Max let inner = store |> MapExt.splitAt min |> sndv |> if not overflow then MapExt.splitAt max >> fstv else id let newStore = inner |> if x.Contains r.Min then MapExt.add min HalfRangeKind.Left else id |> if x.Contains r.Max && not overflow then MapExt.add max HalfRangeKind.Right else id assert (newStore.Count % 2 = 0 || MapExt.maxValue newStore = HalfRangeKind.Left) RangeSet1l(newStore) member private x.TryFindLeftBoundary(v : int64) = let struct (l, s, _) = MapExt.neighboursV v store match s with | ValueSome (i, k) -> if k = HalfRangeKind.Left then ValueSome i else ValueNone | _ -> match l with | ValueSome (i, HalfRangeKind.Left) -> ValueSome i | _ -> ValueNone /// Returns whether the given value is contained in the range set. member x.Contains(v : int64) = x.TryFindLeftBoundary v |> ValueOption.isSome /// Returns whether the given range is contained in the set. member x.Contains(r : Range1l) = if r.Max < r.Min then false elif r.Min = r.Max then x.Contains r.Min else match x.TryFindLeftBoundary r.Min, x.TryFindLeftBoundary r.Max with | ValueSome l, ValueSome r -> l = r | _ -> false /// Returns the number of disjoint ranges in the set. member x.Count = (store.Count + 1) / 2 /// Returns whether the set is empty. member inline x.IsEmpty = x.Count = 0 /// Builds an array from the range set. member x.ToArray() = let arr = Array.zeroCreate x.Count let rec write (i : int) (l : struct (int64 * HalfRangeKind) list) = match l with | struct (l, _) :: struct (r, _) :: rest -> arr.[i] <- Range1l(l, r - 1L) write (i + 1) rest | [struct (l, HalfRangeKind.Left)] when i = x.Count - 1 -> arr.[i] <- Range1l(l, Int64.MaxValue) | [_] -> failwith "bad RangeSet" | [] -> () store |> MapExt.toListV |> write 0 arr /// Builds a list from the range set. member x.ToList() = let rec build (accum : Range1l list) (l : struct (int64 * HalfRangeKind) list) = match l with | struct (l, _) :: struct (r, _) :: rest -> build (Range1l(l, r - 1L) :: accum) rest | [struct (l, HalfRangeKind.Left)] -> build (Range1l(l, Int64.MaxValue) :: accum) [] | [_] -> failwith "bad RangeSet" | [] -> List.rev accum store |> MapExt.toListV |> build [] /// Views the range set as a sequence. member x.ToSeq() = x :> seq<_> member inline private x.Equals(other : RangeSet1l) = store = other.Store override x.Equals(other : obj) = match other with | :? RangeSet1l as o -> x.Equals o | _ -> false override x.GetHashCode() = store.GetHashCode() member private x.AsString = x.ToString() override x.ToString() = let content = x |> Seq.map (fun r -> $"[{r.Min}, {r.Max}]" ) |> String.concat "; " $"ranges [{content}]" member x.GetEnumerator() = new RangeSetEnumerator1l((store :> seq<_>).GetEnumerator()) interface IEquatable with member x.Equals(other) = x.Equals(other) interface IEnumerable with member x.GetEnumerator() = new RangeSetEnumerator1l((store :> seq<_>).GetEnumerator()) :> _ interface IEnumerable with member x.GetEnumerator() = new RangeSetEnumerator1l((store :> seq<_>).GetEnumerator()) :> _ // TODO: MapExt should use a struct enumerator and return it directly. // That way we could get rid of allocations. and RangeSetEnumerator1l = struct val private Inner : IEnumerator> val mutable private Left : KeyValuePair val mutable private Right : KeyValuePair internal new (inner : IEnumerator>) = { Inner = inner Left = Unchecked.defaultof<_> Right = Unchecked.defaultof<_> } member x.MoveNext() = if x.Inner.MoveNext() then x.Left <- x.Inner.Current if x.Inner.MoveNext() then x.Right <- x.Inner.Current true else if x.Left.Value = HalfRangeKind.Left then x.Right <- KeyValuePair(Int64.MinValue, HalfRangeKind.Right) // MaxValue + 1 true else failwithf "bad RangeSet" else false member x.Reset() = x.Inner.Reset() x.Left <- Unchecked.defaultof<_> x.Right <- Unchecked.defaultof<_> member x.Current = assert (x.Left.Value = HalfRangeKind.Left && x.Right.Value = HalfRangeKind.Right) Range1l(x.Left.Key, x.Right.Key - 1L) member x.Dispose() = x.Inner.Dispose() x.Left <- Unchecked.defaultof<_> x.Right <- Unchecked.defaultof<_> interface IEnumerator with member x.MoveNext() = x.MoveNext() member x.Current = x.Current :> obj member x.Reset() = x.Reset() interface IEnumerator with member x.Dispose() = x.Dispose() member x.Current = x.Current end [] module RangeSet1l = /// Empty range set. let empty = RangeSet1l.Empty /// Returns the minimum value in the range set or Int64.MaxValue if the range is empty. let inline min (set : RangeSet1l) = set.Min /// Returns the maximum value in the range set or Int64.MinValue if the range is empty. let inline max (set : RangeSet1l) = set.Max /// Returns the total range spanned by the range set, i.e. [min, max]. let inline range (set : RangeSet1l) = set.Range let inline private getHalfRanges (r : Range1l) = [ struct (r.Min, HalfRangeKind.Left) if r.Max < Int64.MaxValue then struct (r.Max + 1L, HalfRangeKind.Right) ] let inline private ofRange (r : Range1l) = RangeSet1l(MapExt.ofListV <| getHalfRanges r) let private ofRanges (ranges : seq) = let halves = ranges |> Seq.toList |> List.collect getHalfRanges |> List.sortBy fstv let mutable level = 0 let result = ResizeArray() for (struct (i, k) as h) in halves do if k = HalfRangeKind.Left then if level = 0 then result.Add h level <- level + 1 else level <- level - 1 if level = 0 then result.Add h RangeSet1l(MapExt.ofSeqV result) /// Builds a range set of the given list of ranges. let ofList (ranges : Range1l list) = match ranges with | [] -> empty | [r] -> ofRange r | _ -> ofRanges ranges /// Builds a range set of the given array of ranges. let ofArray (ranges : Range1l[]) = if ranges.Length = 0 then empty elif ranges.Length = 1 then ofRange ranges.[0] else ofRanges ranges /// Builds a range set of the given sequence of ranges. let inline ofSeq (ranges : seq) = ofList <| Seq.toList ranges /// Adds the given range to the set. let inline add (range : Range1l) (set : RangeSet1l) = set.Add range /// Removes the given range from the set. let inline remove (range : Range1l) (set : RangeSet1l) = set.Remove range /// Returns the union of two sets. let inline union (l : RangeSet1l) (r : RangeSet1l) = l.Union r /// Returns the intersection of the set with the given range. let inline intersect (range : Range1l) (set : RangeSet1l) = set.Intersect range /// Returns whether the given value is contained in the range set. let inline contains (value : int64) (set : RangeSet1l) = set.Contains value /// Returns whether the given range is contained in the set. let inline containsRange (range : Range1l) (set : RangeSet1l) = set.Contains range /// Returns the number of disjoint ranges in the set. let inline count (set : RangeSet1l) = set.Count /// Returns whether the set is empty. let inline isEmpty (set : RangeSet1l) = set.IsEmpty /// Views the range set as a sequence. let inline toSeq (set : RangeSet1l) = set :> seq<_> /// Builds a list from the range set. let inline toList (set : RangeSet1l) = set.ToList() /// Builds an array from the range set. let inline toArray (set : RangeSet1l) = set.ToArray() /// Set of ranges where overlapping and neighboring ranges are coalesced. /// Note that ranges describe closed intervals. [] type RangeSet1ul internal (store : MapExt) = static let empty = RangeSet1ul(MapExt.empty) /// Empty range set. static member Empty = empty member inline private x.Store = store // We cannot directly describe a range that ends at UInt64.MaxValue since the right half-range is inserted // at max + 1. In that case the right-half range will be missing and the total count is odd. member inline private x.HasMaxValue = store.Count % 2 = 1 /// Returns the minimum value in the range set or UInt64.MaxValue if the range is empty. member x.Min = match store.TryMinKeyV with | ValueSome min -> min | _ -> UInt64.MaxValue /// Returns the maximum value in the range set or UInt64.MinValue if the range is empty. member x.Max = if x.HasMaxValue then UInt64.MaxValue else match store.TryMaxKeyV with | ValueSome max -> max - 1UL | _ -> UInt64.MinValue /// Returns the total range spanned by the range set, i.e. [min, max]. member inline x.Range = Range1ul(x.Min, x.Max) /// Adds the given range to the set. member x.Add(r : Range1ul) = if r.Max < r.Min then x else let min = r.Min let struct (max, overflow) = inc r.Max let struct (lm, inner) = MapExt.splitAt min store let rm = if overflow then MapExt.empty else sndv <| MapExt.splitAt max inner let before = MapExt.tryMaxValue lm let after = MapExt.tryMinValue rm // If the set contained UInt64.MaxValue or we have overflown, we must not add an explicit right half-range. // UInt64.MaxValue is stored implicitly. let fixRightBoundary = if x.HasMaxValue || overflow then id else MapExt.add max HalfRangeKind.Right let newStore = match before, after with | ValueNone, ValueNone -> MapExt.ofListV [ struct (min, HalfRangeKind.Left) ] |> fixRightBoundary | ValueSome HalfRangeKind.Right, ValueNone -> lm |> MapExt.add min HalfRangeKind.Left |> fixRightBoundary | ValueSome HalfRangeKind.Left, ValueNone -> lm |> fixRightBoundary | ValueNone, ValueSome HalfRangeKind.Left -> rm |> MapExt.add min HalfRangeKind.Left |> MapExt.add max HalfRangeKind.Right | ValueNone, ValueSome HalfRangeKind.Right -> rm |> MapExt.add min HalfRangeKind.Left | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Left -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Left); struct (max, HalfRangeKind.Right) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Left -> let self = MapExt.ofListV [ struct (max, HalfRangeKind.Right) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Right -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Left) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Right -> MapExt.union lm rm | _ -> failwithf "impossible" assert (newStore.Count % 2 = 0 || MapExt.maxValue newStore = HalfRangeKind.Left) RangeSet1ul(newStore) /// Removes the given range from the set. member x.Remove(r : Range1ul) = if r.Max < r.Min then x else let min = r.Min let struct (max, overflow) = inc r.Max let struct (lm, inner) = MapExt.splitAt min store let rm = if overflow then MapExt.empty else sndv <| MapExt.splitAt max inner let before = MapExt.tryMaxValue lm let after = MapExt.tryMinValue rm // If the set contained UInt64.MaxValue and we have not overflown, there is still a range [max, UInt64.MaxValue] let fixRightBoundary = if x.HasMaxValue && not overflow then MapExt.add max HalfRangeKind.Left else id let newStore = match before, after with | ValueNone, ValueNone -> MapExt.empty |> fixRightBoundary | ValueSome HalfRangeKind.Right, ValueNone -> lm |> fixRightBoundary | ValueSome HalfRangeKind.Left, ValueNone -> lm |> MapExt.add min HalfRangeKind.Right |> fixRightBoundary | ValueNone, ValueSome HalfRangeKind.Left -> rm | ValueNone, ValueSome HalfRangeKind.Right -> rm |> MapExt.add max HalfRangeKind.Left | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Left -> MapExt.union lm rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Left -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Right) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Right -> let self = MapExt.ofListV [ struct (max, HalfRangeKind.Left) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Right -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Right); struct (max, HalfRangeKind.Left) ] MapExt.union (MapExt.union lm self) rm | _ -> failwithf "impossible" assert (newStore.Count % 2 = 0 || MapExt.maxValue newStore = HalfRangeKind.Left) RangeSet1ul(newStore) /// Returns the union of the set with the given set. member inline x.Union(other : RangeSet1ul) = let mutable res = x for r in other do res <- res.Add r res /// Returns the intersection of the set with the given range. member x.Intersect(r : Range1ul) = if r.Max < r.Min then empty else let min = r.Min let struct (max, overflow) = inc r.Max let inner = store |> MapExt.splitAt min |> sndv |> if not overflow then MapExt.splitAt max >> fstv else id let newStore = inner |> if x.Contains r.Min then MapExt.add min HalfRangeKind.Left else id |> if x.Contains r.Max && not overflow then MapExt.add max HalfRangeKind.Right else id assert (newStore.Count % 2 = 0 || MapExt.maxValue newStore = HalfRangeKind.Left) RangeSet1ul(newStore) member private x.TryFindLeftBoundary(v : uint64) = let struct (l, s, _) = MapExt.neighboursV v store match s with | ValueSome (i, k) -> if k = HalfRangeKind.Left then ValueSome i else ValueNone | _ -> match l with | ValueSome (i, HalfRangeKind.Left) -> ValueSome i | _ -> ValueNone /// Returns whether the given value is contained in the range set. member x.Contains(v : uint64) = x.TryFindLeftBoundary v |> ValueOption.isSome /// Returns whether the given range is contained in the set. member x.Contains(r : Range1ul) = if r.Max < r.Min then false elif r.Min = r.Max then x.Contains r.Min else match x.TryFindLeftBoundary r.Min, x.TryFindLeftBoundary r.Max with | ValueSome l, ValueSome r -> l = r | _ -> false /// Returns the number of disjoint ranges in the set. member x.Count = (store.Count + 1) / 2 /// Returns whether the set is empty. member inline x.IsEmpty = x.Count = 0 /// Builds an array from the range set. member x.ToArray() = let arr = Array.zeroCreate x.Count let rec write (i : int) (l : struct (uint64 * HalfRangeKind) list) = match l with | struct (l, _) :: struct (r, _) :: rest -> arr.[i] <- Range1ul(l, r - 1UL) write (i + 1) rest | [struct (l, HalfRangeKind.Left)] when i = x.Count - 1 -> arr.[i] <- Range1ul(l, UInt64.MaxValue) | [_] -> failwith "bad RangeSet" | [] -> () store |> MapExt.toListV |> write 0 arr /// Builds a list from the range set. member x.ToList() = let rec build (accum : Range1ul list) (l : struct (uint64 * HalfRangeKind) list) = match l with | struct (l, _) :: struct (r, _) :: rest -> build (Range1ul(l, r - 1UL) :: accum) rest | [struct (l, HalfRangeKind.Left)] -> build (Range1ul(l, UInt64.MaxValue) :: accum) [] | [_] -> failwith "bad RangeSet" | [] -> List.rev accum store |> MapExt.toListV |> build [] /// Views the range set as a sequence. member x.ToSeq() = x :> seq<_> member inline private x.Equals(other : RangeSet1ul) = store = other.Store override x.Equals(other : obj) = match other with | :? RangeSet1ul as o -> x.Equals o | _ -> false override x.GetHashCode() = store.GetHashCode() member private x.AsString = x.ToString() override x.ToString() = let content = x |> Seq.map (fun r -> $"[{r.Min}, {r.Max}]" ) |> String.concat "; " $"ranges [{content}]" member x.GetEnumerator() = new RangeSetEnumerator1ul((store :> seq<_>).GetEnumerator()) interface IEquatable with member x.Equals(other) = x.Equals(other) interface IEnumerable with member x.GetEnumerator() = new RangeSetEnumerator1ul((store :> seq<_>).GetEnumerator()) :> _ interface IEnumerable with member x.GetEnumerator() = new RangeSetEnumerator1ul((store :> seq<_>).GetEnumerator()) :> _ // TODO: MapExt should use a struct enumerator and return it directly. // That way we could get rid of allocations. and RangeSetEnumerator1ul = struct val private Inner : IEnumerator> val mutable private Left : KeyValuePair val mutable private Right : KeyValuePair internal new (inner : IEnumerator>) = { Inner = inner Left = Unchecked.defaultof<_> Right = Unchecked.defaultof<_> } member x.MoveNext() = if x.Inner.MoveNext() then x.Left <- x.Inner.Current if x.Inner.MoveNext() then x.Right <- x.Inner.Current true else if x.Left.Value = HalfRangeKind.Left then x.Right <- KeyValuePair(UInt64.MinValue, HalfRangeKind.Right) // MaxValue + 1 true else failwithf "bad RangeSet" else false member x.Reset() = x.Inner.Reset() x.Left <- Unchecked.defaultof<_> x.Right <- Unchecked.defaultof<_> member x.Current = assert (x.Left.Value = HalfRangeKind.Left && x.Right.Value = HalfRangeKind.Right) Range1ul(x.Left.Key, x.Right.Key - 1UL) member x.Dispose() = x.Inner.Dispose() x.Left <- Unchecked.defaultof<_> x.Right <- Unchecked.defaultof<_> interface IEnumerator with member x.MoveNext() = x.MoveNext() member x.Current = x.Current :> obj member x.Reset() = x.Reset() interface IEnumerator with member x.Dispose() = x.Dispose() member x.Current = x.Current end [] module RangeSet1ul = /// Empty range set. let empty = RangeSet1ul.Empty /// Returns the minimum value in the range set or UInt64.MaxValue if the range is empty. let inline min (set : RangeSet1ul) = set.Min /// Returns the maximum value in the range set or UInt64.MinValue if the range is empty. let inline max (set : RangeSet1ul) = set.Max /// Returns the total range spanned by the range set, i.e. [min, max]. let inline range (set : RangeSet1ul) = set.Range let inline private getHalfRanges (r : Range1ul) = [ struct (r.Min, HalfRangeKind.Left) if r.Max < UInt64.MaxValue then struct (r.Max + 1UL, HalfRangeKind.Right) ] let inline private ofRange (r : Range1ul) = RangeSet1ul(MapExt.ofListV <| getHalfRanges r) let private ofRanges (ranges : seq) = let halves = ranges |> Seq.toList |> List.collect getHalfRanges |> List.sortBy fstv let mutable level = 0 let result = ResizeArray() for (struct (i, k) as h) in halves do if k = HalfRangeKind.Left then if level = 0 then result.Add h level <- level + 1 else level <- level - 1 if level = 0 then result.Add h RangeSet1ul(MapExt.ofSeqV result) /// Builds a range set of the given list of ranges. let ofList (ranges : Range1ul list) = match ranges with | [] -> empty | [r] -> ofRange r | _ -> ofRanges ranges /// Builds a range set of the given array of ranges. let ofArray (ranges : Range1ul[]) = if ranges.Length = 0 then empty elif ranges.Length = 1 then ofRange ranges.[0] else ofRanges ranges /// Builds a range set of the given sequence of ranges. let inline ofSeq (ranges : seq) = ofList <| Seq.toList ranges /// Adds the given range to the set. let inline add (range : Range1ul) (set : RangeSet1ul) = set.Add range /// Removes the given range from the set. let inline remove (range : Range1ul) (set : RangeSet1ul) = set.Remove range /// Returns the union of two sets. let inline union (l : RangeSet1ul) (r : RangeSet1ul) = l.Union r /// Returns the intersection of the set with the given range. let inline intersect (range : Range1ul) (set : RangeSet1ul) = set.Intersect range /// Returns whether the given value is contained in the range set. let inline contains (value : uint64) (set : RangeSet1ul) = set.Contains value /// Returns whether the given range is contained in the set. let inline containsRange (range : Range1ul) (set : RangeSet1ul) = set.Contains range /// Returns the number of disjoint ranges in the set. let inline count (set : RangeSet1ul) = set.Count /// Returns whether the set is empty. let inline isEmpty (set : RangeSet1ul) = set.IsEmpty /// Views the range set as a sequence. let inline toSeq (set : RangeSet1ul) = set :> seq<_> /// Builds a list from the range set. let inline toList (set : RangeSet1ul) = set.ToList() /// Builds an array from the range set. let inline toArray (set : RangeSet1ul) = set.ToArray() ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Immutable/RangeSet_template.fs ================================================ namespace Aardvark.Base open System open System.Collections open System.Collections.Generic open Aardvark.Base type internal HalfRangeKind = | Left = 0 | Right = 1 module private RangeSetUtils = let inline inc (value : 'T) = let res = value + LanguagePrimitives.GenericOne<'T> if res = Constant<'T>.ParseableMinValue then struct (Constant<'T>.ParseableMaxValue, true) else struct (res, false) module MapExt = let inline splitAt (key : 'K) (map : MapExt<'K, 'V>) = let struct (l, _, _, _, r) = MapExt.splitV key map struct (l, r) let inline tryMinValue (map : MapExt<'K, 'V>) = MapExt.tryMinV map |> ValueOption.map (fun mk -> map.[mk]) let inline tryMaxValue (map : MapExt<'K, 'V>) = MapExt.tryMaxV map |> ValueOption.map (fun mk -> map.[mk]) let inline maxValue (map : MapExt<'K, 'V>) = map.[MapExt.max map] open RangeSetUtils //# var ltypes = new[] { "int32", "uint32", "int64", "uint64" }; //# var sltypes = new[] { "Int32", "UInt32", "Int64", "UInt64" }; //# var suffixes = new[] { "i", "ui", "l", "ul" }; //# var literalSuffixes = new[] { "", "u", "L", "UL" }; //# //# for (int i = 0; i < ltypes.Length; i++) { //# var ltype = ltypes[i]; //# var suffix = suffixes[i]; //# var range = "Range1" + suffix; //# var rangeset = "RangeSet1" + suffix; //# var enumerator = "RangeSetEnumerator1" + suffix; //# var one = "1" + literalSuffixes[i]; //# var minvalue = sltypes[i] + ".MinValue"; //# var maxvalue = sltypes[i] + ".MaxValue"; /// Set of ranges where overlapping and neighboring ranges are coalesced. /// Note that ranges describe closed intervals. [] type __rangeset__ internal (store : MapExt<__ltype__, HalfRangeKind>) = static let empty = __rangeset__(MapExt.empty) /// Empty range set. static member Empty = empty member inline private x.Store = store // We cannot directly describe a range that ends at __maxvalue__ since the right half-range is inserted // at max + 1. In that case the right-half range will be missing and the total count is odd. member inline private x.HasMaxValue = store.Count % 2 = 1 /// Returns the minimum value in the range set or __maxvalue__ if the range is empty. member x.Min = match store.TryMinKeyV with | ValueSome min -> min | _ -> __maxvalue__ /// Returns the maximum value in the range set or __minvalue__ if the range is empty. member x.Max = if x.HasMaxValue then __maxvalue__ else match store.TryMaxKeyV with | ValueSome max -> max - __one__ | _ -> __minvalue__ /// Returns the total range spanned by the range set, i.e. [min, max]. member inline x.Range = __range__(x.Min, x.Max) /// Adds the given range to the set. member x.Add(r : __range__) = if r.Max < r.Min then x else let min = r.Min let struct (max, overflow) = inc r.Max let struct (lm, inner) = MapExt.splitAt min store let rm = if overflow then MapExt.empty else sndv <| MapExt.splitAt max inner let before = MapExt.tryMaxValue lm let after = MapExt.tryMinValue rm // If the set contained __maxvalue__ or we have overflown, we must not add an explicit right half-range. // __maxvalue__ is stored implicitly. let fixRightBoundary = if x.HasMaxValue || overflow then id else MapExt.add max HalfRangeKind.Right let newStore = match before, after with | ValueNone, ValueNone -> MapExt.ofListV [ struct (min, HalfRangeKind.Left) ] |> fixRightBoundary | ValueSome HalfRangeKind.Right, ValueNone -> lm |> MapExt.add min HalfRangeKind.Left |> fixRightBoundary | ValueSome HalfRangeKind.Left, ValueNone -> lm |> fixRightBoundary | ValueNone, ValueSome HalfRangeKind.Left -> rm |> MapExt.add min HalfRangeKind.Left |> MapExt.add max HalfRangeKind.Right | ValueNone, ValueSome HalfRangeKind.Right -> rm |> MapExt.add min HalfRangeKind.Left | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Left -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Left); struct (max, HalfRangeKind.Right) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Left -> let self = MapExt.ofListV [ struct (max, HalfRangeKind.Right) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Right -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Left) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Right -> MapExt.union lm rm | _ -> failwithf "impossible" assert (newStore.Count % 2 = 0 || MapExt.maxValue newStore = HalfRangeKind.Left) __rangeset__(newStore) /// Removes the given range from the set. member x.Remove(r : __range__) = if r.Max < r.Min then x else let min = r.Min let struct (max, overflow) = inc r.Max let struct (lm, inner) = MapExt.splitAt min store let rm = if overflow then MapExt.empty else sndv <| MapExt.splitAt max inner let before = MapExt.tryMaxValue lm let after = MapExt.tryMinValue rm // If the set contained __maxvalue__ and we have not overflown, there is still a range [max, __maxvalue__] let fixRightBoundary = if x.HasMaxValue && not overflow then MapExt.add max HalfRangeKind.Left else id let newStore = match before, after with | ValueNone, ValueNone -> MapExt.empty |> fixRightBoundary | ValueSome HalfRangeKind.Right, ValueNone -> lm |> fixRightBoundary | ValueSome HalfRangeKind.Left, ValueNone -> lm |> MapExt.add min HalfRangeKind.Right |> fixRightBoundary | ValueNone, ValueSome HalfRangeKind.Left -> rm | ValueNone, ValueSome HalfRangeKind.Right -> rm |> MapExt.add max HalfRangeKind.Left | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Left -> MapExt.union lm rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Left -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Right) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Right, ValueSome HalfRangeKind.Right -> let self = MapExt.ofListV [ struct (max, HalfRangeKind.Left) ] MapExt.union (MapExt.union lm self) rm | ValueSome HalfRangeKind.Left, ValueSome HalfRangeKind.Right -> let self = MapExt.ofListV [ struct (min, HalfRangeKind.Right); struct (max, HalfRangeKind.Left) ] MapExt.union (MapExt.union lm self) rm | _ -> failwithf "impossible" assert (newStore.Count % 2 = 0 || MapExt.maxValue newStore = HalfRangeKind.Left) __rangeset__(newStore) /// Returns the union of the set with the given set. member inline x.Union(other : __rangeset__) = let mutable res = x for r in other do res <- res.Add r res /// Returns the intersection of the set with the given range. member x.Intersect(r : __range__) = if r.Max < r.Min then empty else let min = r.Min let struct (max, overflow) = inc r.Max let inner = store |> MapExt.splitAt min |> sndv |> if not overflow then MapExt.splitAt max >> fstv else id let newStore = inner |> if x.Contains r.Min then MapExt.add min HalfRangeKind.Left else id |> if x.Contains r.Max && not overflow then MapExt.add max HalfRangeKind.Right else id assert (newStore.Count % 2 = 0 || MapExt.maxValue newStore = HalfRangeKind.Left) __rangeset__(newStore) member private x.TryFindLeftBoundary(v : __ltype__) = let struct (l, s, _) = MapExt.neighboursV v store match s with | ValueSome (i, k) -> if k = HalfRangeKind.Left then ValueSome i else ValueNone | _ -> match l with | ValueSome (i, HalfRangeKind.Left) -> ValueSome i | _ -> ValueNone /// Returns whether the given value is contained in the range set. member x.Contains(v : __ltype__) = x.TryFindLeftBoundary v |> ValueOption.isSome /// Returns whether the given range is contained in the set. member x.Contains(r : __range__) = if r.Max < r.Min then false elif r.Min = r.Max then x.Contains r.Min else match x.TryFindLeftBoundary r.Min, x.TryFindLeftBoundary r.Max with | ValueSome l, ValueSome r -> l = r | _ -> false /// Returns the number of disjoint ranges in the set. member x.Count = (store.Count + 1) / 2 /// Returns whether the set is empty. member inline x.IsEmpty = x.Count = 0 /// Builds an array from the range set. member x.ToArray() = let arr = Array.zeroCreate x.Count let rec write (i : int) (l : struct (__ltype__ * HalfRangeKind) list) = match l with | struct (l, _) :: struct (r, _) :: rest -> arr.[i] <- __range__(l, r - __one__) write (i + 1) rest | [struct (l, HalfRangeKind.Left)] when i = x.Count - 1 -> arr.[i] <- __range__(l, __maxvalue__) | [_] -> failwith "bad RangeSet" | [] -> () store |> MapExt.toListV |> write 0 arr /// Builds a list from the range set. member x.ToList() = let rec build (accum : __range__ list) (l : struct (__ltype__ * HalfRangeKind) list) = match l with | struct (l, _) :: struct (r, _) :: rest -> build (__range__(l, r - __one__) :: accum) rest | [struct (l, HalfRangeKind.Left)] -> build (__range__(l, __maxvalue__) :: accum) [] | [_] -> failwith "bad RangeSet" | [] -> List.rev accum store |> MapExt.toListV |> build [] /// Views the range set as a sequence. member x.ToSeq() = x :> seq<_> member inline private x.Equals(other : __rangeset__) = store = other.Store override x.Equals(other : obj) = match other with | :? __rangeset__ as o -> x.Equals o | _ -> false override x.GetHashCode() = store.GetHashCode() member private x.AsString = x.ToString() override x.ToString() = let content = x |> Seq.map (fun r -> $"[{r.Min}, {r.Max}]" ) |> String.concat "; " $"ranges [{content}]" member x.GetEnumerator() = new __enumerator__((store :> seq<_>).GetEnumerator()) interface IEquatable<__rangeset__> with member x.Equals(other) = x.Equals(other) interface IEnumerable with member x.GetEnumerator() = new __enumerator__((store :> seq<_>).GetEnumerator()) :> _ interface IEnumerable<__range__> with member x.GetEnumerator() = new __enumerator__((store :> seq<_>).GetEnumerator()) :> _ // TODO: MapExt should use a struct enumerator and return it directly. // That way we could get rid of allocations. and __enumerator__ = struct val private Inner : IEnumerator> val mutable private Left : KeyValuePair<__ltype__, HalfRangeKind> val mutable private Right : KeyValuePair<__ltype__, HalfRangeKind> internal new (inner : IEnumerator>) = { Inner = inner Left = Unchecked.defaultof<_> Right = Unchecked.defaultof<_> } member x.MoveNext() = if x.Inner.MoveNext() then x.Left <- x.Inner.Current if x.Inner.MoveNext() then x.Right <- x.Inner.Current true else if x.Left.Value = HalfRangeKind.Left then x.Right <- KeyValuePair(__minvalue__, HalfRangeKind.Right) // MaxValue + 1 true else failwithf "bad RangeSet" else false member x.Reset() = x.Inner.Reset() x.Left <- Unchecked.defaultof<_> x.Right <- Unchecked.defaultof<_> member x.Current = assert (x.Left.Value = HalfRangeKind.Left && x.Right.Value = HalfRangeKind.Right) __range__(x.Left.Key, x.Right.Key - __one__) member x.Dispose() = x.Inner.Dispose() x.Left <- Unchecked.defaultof<_> x.Right <- Unchecked.defaultof<_> interface IEnumerator with member x.MoveNext() = x.MoveNext() member x.Current = x.Current :> obj member x.Reset() = x.Reset() interface IEnumerator<__range__> with member x.Dispose() = x.Dispose() member x.Current = x.Current end [] module __rangeset__ = /// Empty range set. let empty = __rangeset__.Empty /// Returns the minimum value in the range set or __maxvalue__ if the range is empty. let inline min (set : __rangeset__) = set.Min /// Returns the maximum value in the range set or __minvalue__ if the range is empty. let inline max (set : __rangeset__) = set.Max /// Returns the total range spanned by the range set, i.e. [min, max]. let inline range (set : __rangeset__) = set.Range let inline private getHalfRanges (r : __range__) = [ struct (r.Min, HalfRangeKind.Left) if r.Max < __maxvalue__ then struct (r.Max + __one__, HalfRangeKind.Right) ] let inline private ofRange (r : __range__) = __rangeset__(MapExt.ofListV <| getHalfRanges r) let private ofRanges (ranges : seq<__range__>) = let halves = ranges |> Seq.toList |> List.collect getHalfRanges |> List.sortBy fstv let mutable level = 0 let result = ResizeArray() for (struct (i, k) as h) in halves do if k = HalfRangeKind.Left then if level = 0 then result.Add h level <- level + 1 else level <- level - 1 if level = 0 then result.Add h __rangeset__(MapExt.ofSeqV result) /// Builds a range set of the given list of ranges. let ofList (ranges : __range__ list) = match ranges with | [] -> empty | [r] -> ofRange r | _ -> ofRanges ranges /// Builds a range set of the given array of ranges. let ofArray (ranges : __range__[]) = if ranges.Length = 0 then empty elif ranges.Length = 1 then ofRange ranges.[0] else ofRanges ranges /// Builds a range set of the given sequence of ranges. let inline ofSeq (ranges : seq<__range__>) = ofList <| Seq.toList ranges /// Adds the given range to the set. let inline add (range : __range__) (set : __rangeset__) = set.Add range /// Removes the given range from the set. let inline remove (range : __range__) (set : __rangeset__) = set.Remove range /// Returns the union of two sets. let inline union (l : __rangeset__) (r : __rangeset__) = l.Union r /// Returns the intersection of the set with the given range. let inline intersect (range : __range__) (set : __rangeset__) = set.Intersect range /// Returns whether the given value is contained in the range set. let inline contains (value : __ltype__) (set : __rangeset__) = set.Contains value /// Returns whether the given range is contained in the set. let inline containsRange (range : __range__) (set : __rangeset__) = set.Contains range /// Returns the number of disjoint ranges in the set. let inline count (set : __rangeset__) = set.Count /// Returns whether the set is empty. let inline isEmpty (set : __rangeset__) = set.IsEmpty /// Views the range set as a sequence. let inline toSeq (set : __rangeset__) = set :> seq<_> /// Builds a list from the range set. let inline toList (set : __rangeset__) = set.ToList() /// Builds an array from the range set. let inline toArray (set : __rangeset__) = set.ToArray() //# } ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Immutable/SetDelta.fs ================================================ namespace Aardvark.Base [] type SetOperation<'a>(value : 'a, cnt : int) = member x.Value = value member x.Count = cnt member x.Inverse = SetOperation(value, -cnt) override x.ToString() = if cnt = 1 then sprintf "Add(%A)" value elif cnt = -1 then sprintf "Rem(%A)" value elif cnt > 0 then sprintf "Add%d(%A)" cnt value elif cnt < 0 then sprintf "Rem%d(%A)" -cnt value else "Nop" [] module SetOperation = let inline create (cnt : int) (v : 'a) = SetOperation(v, cnt) let inline add (v : 'a) = SetOperation(v, 1) let inline rem (v : 'a) = SetOperation(v, -1) let inline inverse (d : SetOperation<'a>) = d.Inverse let map (f : 'a -> 'b) (d : SetOperation<'a>) = SetOperation<'b>(f d.Value, d.Count) [] module SetDeltaExtensions = let inline Add(v : 'a) = SetOperation(v, 1) let inline Rem(v : 'a) = SetOperation(v, -1) type SetOperation<'a> with static member inline Add v = SetOperation(v, 1) static member inline Rem v = SetOperation(v, -1) let inline (|Add|Rem|) (d : SetOperation<'a>) = if d.Count > 0 then Add(d.Count, d.Value) else Rem(-d.Count, d.Value) ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Mutable/AVL.fs ================================================ #if INTERACTIVE #r "..\\..\\..\\Bin\\Release\\Aardvark.Base.dll" #r "..\\..\\..\\Bin\\Release\\Aardvark.Base.FSharp.dll" #else namespace Aardvark.Base #endif open Aardvark.Base [] module AVL = [] [] type Node<'a> = class val mutable public Value : 'a val mutable public Left : Node<'a> val mutable public Right : Node<'a> val mutable public height : int new(value : 'a) = { Value = value; Left = null; Right = null; height = -1 } new(value : 'a, l : Node<'a>, r : Node<'a>) = { Value = value; Left = l; Right = r; height = -1 } member x.Height = if x.height < 0 then let l = if not (isNull x.Left) then x.Left.Height else 0 let r = if not (isNull x.Right) then x.Right.Height else 0 x.height <- 1 + Fun.Max(l,r) x.height member x.Balance = let l = if not (isNull x.Left) then x.Left.Height else 0 let r = if not (isNull x.Right) then x.Right.Height else 0 l - r member x.AsString = if not (isNull x.Left) || not (isNull x.Right) then let l = if not (isNull x.Left) then x.Left.AsString else "Nil" let r = if not (isNull x.Right) then x.Right.AsString else "Nil" sprintf "Node(%A, %s, %s)" x.Value l r else sprintf "Leaf(%A)" x.Value end [] type Tree<'a> = class val mutable public Root : Node<'a> val public cmp : 'a -> 'a -> int new(cmp) = { cmp = cmp; Root = null } member x.AsString = if not (isNull x.Root) then x.Root.AsString else "Nil" end let private (|Nil|Node|) (n : Node<'a>) = if isNull n then Nil else Node(n.Value) let private rebalance (n : byref>) = let b = if not (isNull n) then n.Balance else 0 if b = 2 then let l = n.Left if l.Balance >= 0 then //left-left let ll = l.Left n <- Node(l.Value, ll, Node(n.Value, l.Right, n.Right)) elif l.Balance = -1 then //left-right let lr = l.Right n <- Node(lr.Value, Node(l.Value, l.Left, lr.Left), Node(n.Value, lr.Right, n.Right)) elif b = -2 then let r = n.Right if r.Balance <= 0 then //right-right let rr = r.Right n <- Node(r.Value, Node(n.Value, n.Left, r.Left), rr) elif r.Balance = 1 then //right-left let rl = r.Left n <- Node(rl.Value, Node(n.Value, n.Left, rl.Left), Node(r.Value, rl.Right, r.Right)) let rec private ninsert' (cmp : 'a -> 'a -> int) (n : byref>) (value : 'a) = match n with | Node(v) -> let c = cmp v value if c = 0 then false elif c > 0 then if ninsert' cmp &n.Left value then n.height <- -1 rebalance &n true else false else if ninsert' cmp &n.Right value then n.height <- -1 rebalance &n true else false | Nil -> n <- Node(value) true let rec private ninsertNeighbourhood' (prev : Option<'a>) (next : Option<'a>) (cmp : 'a -> 'a -> int) (n : byref>) (value : 'a) (f : Option<'a> -> Option<'a> -> unit) = match n with | Node(v) -> let c = cmp v value if c = 0 then false elif c > 0 then if ninsertNeighbourhood' prev (Some v) cmp &n.Left value f then n.height <- -1 rebalance &n true else false else if ninsertNeighbourhood' (Some v) next cmp &n.Right value f then n.height <- -1 rebalance &n true else false | Nil -> n <- Node(value) f prev next true let rec private ninsertOrUpdateNeighbourhood' (prev : Option<'a>) (next : Option<'a>) (cmp : 'a -> 'a -> int) (n : byref>) (value : 'a) (f : Option<'a> -> Option<'a> -> Option<'a> -> unit) = match n with | Node(v) -> let c = cmp v value if c = 0 then f prev (Some v) next false elif c > 0 then if ninsertOrUpdateNeighbourhood' prev (Some v) cmp &n.Left value f then n.height <- -1 rebalance &n true else false else if ninsertOrUpdateNeighbourhood' (Some v) next cmp &n.Right value f then n.height <- -1 rebalance &n true else false | Nil -> f prev None next n <- Node(value) true let rec private nextractLeftmost' (n : byref>) = match n with | Nil -> None | _ -> if isNull n.Left then let v = n.Value n <- n.Right Some v else let r = nextractLeftmost' &n.Left if r.IsSome then n.height <- -1 rebalance &n r let rec private nextractRightmost' (n : byref>) = match n with | Nil -> None | _ -> if isNull n.Right then let v = n.Value n <- n.Left Some v else let r = nextractRightmost' &n.Right if r.IsSome then n.height <- -1 rebalance &n r let rec private nremove' (n : byref>) (valueCmp : 'a -> int) = match n with | Nil -> false | Node(v) -> let c = valueCmp v if c = 0 then match n.Left, n.Right with | Nil,r -> n <- r true | l,Nil -> n <- l true | _ -> match nextractLeftmost' &n.Right with | Some v -> n <- Node(v, n.Left, n.Right) rebalance &n true | None -> match nextractRightmost' &n.Left with | Some v -> n <- Node(v, n.Left, n.Right) rebalance &n true | None -> failwith "not possible" elif c < 0 then if nremove' &n.Left valueCmp then n.height <- -1 rebalance &n true else false else if nremove' &n.Right valueCmp then n.height <- -1 rebalance &n true else false let rec private ntoSeq' (n : Node<'a>) : seq<'a> = seq { match n with | Node(v) -> yield! n.Left |> ntoSeq' yield v yield! n.Right |> ntoSeq' | _ -> () } let rec private nextractMinimalWhere' (condition : 'a -> bool) (n : byref>) = match n with | Nil -> None | Node(v) -> let c = condition v if c then if isNull n.Left then let v = n.Value n <- n.Right Some v else let r = nextractMinimalWhere' condition &n.Left if r.IsSome then n.height <- -1 rebalance &n r else let v = n.Value if isNull n.Right then n <- n.Left else match nextractLeftmost' &n.Right with | Some v -> n <- Node(v, n.Left, n.Right) rebalance &n | None -> match nextractRightmost' &n.Left with | Some v -> n <- Node(v, n.Left, n.Right) rebalance &n | None -> failwith "not possible" Some v else if isNull n.Right then None else let r = nextractMinimalWhere' condition &n.Right if r.IsSome then n.height <- -1 rebalance &n r let rec private nfindMinimalWhere' (condition : 'a -> bool) (n : Node<'a>) = match n with | Nil -> None | Node(v) -> let c = condition v if c then if isNull n.Left then Some n.Value else let r = nfindMinimalWhere' condition n.Left if r.IsSome then r else Some n.Value else if isNull n.Right then None else nfindMinimalWhere' condition n.Right let rec private nfindMaximalWhere' (condition : 'a -> bool) (n : Node<'a>) = match n with | Nil -> None | Node(v) -> let c = condition v if c then if isNull n.Right then Some n.Value else let r = nfindMaximalWhere' condition n.Right if r.IsSome then r else Some n.Value else if isNull n.Left then None else nfindMaximalWhere' condition n.Left let rec private nextractMaximalWhere' (condition : 'a -> bool) (n : byref>) = match n with | Nil -> None | Node(v) -> let c = condition v if c then if isNull n.Right then let v = n.Value n <- n.Left Some v else let r = nextractMaximalWhere' condition &n.Right if r.IsSome then n.height <- -1 rebalance &n r else let v = n.Value if isNull n.Left then n <- n.Right else match nextractLeftmost' &n.Right with | Some v -> n <- Node(v, n.Left, n.Right) rebalance &n | None -> match nextractRightmost' &n.Left with | Some v -> n <- Node(v, n.Left, n.Right) rebalance &n | None -> failwith "not possible" Some v else if isNull n.Left then None else let r = nextractMaximalWhere' condition &n.Left if r.IsSome then n.height <- -1 rebalance &n r let rec private nfind' (cmp : 'a -> int) (n : Node<'a>) = match n with | Nil -> None | Node(v) -> let c = cmp v if c = 0 then Some v elif c < 0 then nfind' cmp n.Left else nfind' cmp n.Right let private nprint' (n : Node<'a>) = if isNull n then printfn "Nil" else let h = n.Height + 1 let data = System.Collections.Generic.Dictionary[]>() let set (x : int) (y : int) (v : 'a) = match data.TryGetValue x with | (true, arr) -> arr.[y] <- Some v | _ -> let arr = Array.create h None arr.[y] <- Some v data.[x] <- arr let rec dump (l : int) (x : int) (n : Node<'a>) = match n with | Node _ -> if not (isNull n.Left) || not (isNull n.Right) then set x l n.Value dump (l + 1) (x - (1 <<< (1 + h - l))) n.Left dump (l + 1) (x + (1 <<< (1 + h - l))) n.Right else set x l n.Value | Nil -> () dump 0 0 n let nonEmpty = data |> Seq.sortBy (fun (KeyValue(k,v)) -> k) |> Seq.map (fun (KeyValue(_,v)) -> v) |> Seq.toArray let maxLength = ref 0 let strings = nonEmpty |> Array.map (fun a -> a |> Array.map (fun o -> match o with | None -> None | Some v -> let str = sprintf " %A " v if str.Length > !maxLength then maxLength := str.Length Some str )) let padToLength (s : string) = if s.Length < !maxLength then s + System.String(' ', !maxLength - s.Length) else s let strings = strings |> Array.map (fun a -> a |> Array.map (fun o -> match o with | Some s -> padToLength s | None -> System.String(' ', !maxLength) )) for y in 0..h-1 do for x in 0..strings.Length-1 do printf "%s" strings.[x].[y] printf "\r\n" /// /// creates a new empty AVL-Tree using the given comparison function /// note that the given function must define a total order and may only /// return {-1,0,1}. Futhermore cmp(a,b) = 0 must be equivalent to a = b. /// let custom cmp = Tree(cmp) /// /// creates a new empty AVL-Tree using the default comparison function /// let empty<'a when 'a : comparison> = Tree(compare<'a>) /// /// inserts a new value into the tree and returns true if the value was /// not already present in the tree. /// Runtime: O(log(N)) /// let insert (t : Tree<'a>) (value : 'a) = ninsert' t.cmp &t.Root value let insertNeighbourhood (t : Tree<'a>) (value : 'a) (f : Option<'a> -> Option<'a> -> unit) = ninsertNeighbourhood' None None t.cmp &t.Root value f let insertOrUpdateNeighbourhood (t : Tree<'a>) (value : 'a) (f : Option<'a> -> Option<'a> -> Option<'a> -> unit) = ninsertOrUpdateNeighbourhood' None None t.cmp &t.Root value f /// /// inserts a new value into the tree if not already present. /// Runtime: O(log(N)) /// let insert' (t : Tree<'a>) (value : 'a) = ninsert' t.cmp &t.Root value |> ignore /// /// removes a value from the tree and returns true if the value was found. /// Runtime: O(log(N)) /// let remove (t : Tree<'a>) (value : 'a) = nremove' &t.Root (fun v -> t.cmp value v) /// /// removes a value from the tree if present. /// Runtime: O(log(N)) /// let remove' (t : Tree<'a>) (value : 'a) = nremove' &t.Root (fun v -> t.cmp value v) |> ignore /// /// removes a value using a partially applied comparison function. /// the given function must perform comparison like: compare(myValue, treeValue). /// returns true if the element was found and false otherwise /// Runtime: O(log(N)) /// let removeCmp (t : Tree<'a>) (cmpValue : 'a -> int) = nremove' &t.Root cmpValue /// /// creates a sequence containing all the elements in the tree. /// the sequence is ascendingly sorted with respect to the given comparison function. /// Runtime: O(1) [Note that traversing the entire sequence is of course in O(N)] /// let toSeq (t : Tree<'a>) = ntoSeq' t.Root /// /// creates a list containing all the elements in the tree. /// the list is ascendingly sorted with respect to the given comparison function. /// Runtime: O(N) /// let toList (t : Tree<'a>) = t.Root |> ntoSeq' |> Seq.toList /// /// finds and removes the minimal value from the tree for which the given condition holds. /// it is assumed that this condition is transitive with respect to the given comparison function. /// returns the (optional) value found in the tree. /// Example: extractMinimalWhere (fun v -> v > 10) gives the minimal value in the tree being greater than 10. /// Runtime: O(log(N)) /// let extractMinimalWhere (condition : 'a -> bool) (t : Tree<'a>) = nextractMinimalWhere' condition &t.Root /// /// finds and removes the maximum value from the tree for which the given condition holds. /// it is assumed that this condition is transitive with respect to the given comparison function. /// returns the (optional) value found in the tree. /// Example: extractMaximalWhere (fun v -> v > 10) gives the maximal value in the tree being greater than 10. /// Runtime: O(log(N)) /// let extractMaximalWhere (condition : 'a -> bool) (t : Tree<'a>) = nextractMaximalWhere' condition &t.Root let findMinimalWhere (condition : 'a -> bool) (t : Tree<'a>) = nfindMinimalWhere' condition t.Root let findMaximalWhere (condition : 'a -> bool) (t : Tree<'a>) = nfindMaximalWhere' condition t.Root /// /// finds a value using a partially applied comparison function. /// the given function must perform comparison like: compare(myValue, treeValue). /// returns the (optional) value found /// Runtime: O(log(N)) /// let find (cmp : 'a -> int) (t : Tree<'a>) = nfind' cmp t.Root let get (element : 'a) (tree : Tree<'a>) = nfind' (fun e -> tree.cmp element e) tree.Root /// /// prints the tree to the console for debugging purposes. /// let print (t : Tree<'a>) = if isNull t.Root then printfn "Nil" else nprint' t.Root /// /// runs a randomized series of additions / removals on a tree and /// validates its correctness, completeness, order and internal cache-values. /// let runTests() = let elements = Array.init 10000 (fun i -> i) let elements = System.Collections.Generic.List(elements) let used = System.Collections.Generic.List() let tree = custom (fun (a : int) (b : int) -> a.CompareTo b) let checkCorrectness() = let l = toList tree let correct = l |> Seq.fold (fun a b -> a && used.Contains b) true if not correct then printfn "ERROR: removed elements are still in the tree" let checkCompleteness() = let l = System.Collections.Generic.HashSet(tree |> toList) let correct = used |> Seq.fold (fun a b -> a && l.Contains b) true if not correct then printfn "ERROR: elements are missing in the tree" let checkSorting() = let list = System.Collections.Generic.List(tree |> toList) let mutable error = false for i in 1..list.Count-1 do let l = list.[i-1] let r = list.[i] if l > r then error <- true if error then printfn "ERROR: elements are not ascending" let checkBalanceAndHeightCaches() = let rec h (n : Node) = match n with | Nil -> 0 | Node _ -> let l = if not (isNull n.Left) then h n.Left else 0 let r = if not (isNull n.Right) then h n.Right else 0 1 + Fun.Max(l,r) let rec balanceAndHeightValid(n : Node) = if not (isNull n) then let mine = h n let cache = n.Height if mine <> cache then false else let b = (h n.Left) - (h n.Right) let cache = n.Balance if b <> cache || b >= 2 then false else true else true if not <| balanceAndHeightValid tree.Root then printfn "ERROR: invalid balance or height cache" let checkFind() = for u in used do match tree |> find (fun b -> compare u b) with | Some v -> () | None -> printfn "ERROR: find could not find element: %d" u for e in elements do match tree |> find (fun b -> compare e b) with | Some v -> printfn "ERROR: found element not in tree: %d" e | None -> () let mutable iter = 0 let mutable maxCount = 0 let r = System.Random() let mutable removeCount = 0 let mutable extractMinimalWhereCount = 0 let mutable extractMaximalWhereCount = 0 let mutable insertCount = 0 for i in 0..10000 do let u = r.NextDouble() if u < 0.5 && used.Count > 0 && iter > 500 then let id = r.Next(used.Count) let element = used.[id] used.RemoveAt id elements.Add element let r = r.NextDouble() if r < 0.3333 then if (extractMinimalWhere (fun e -> e >= element) tree).IsNone then printfn "ERROR: extractMinimalWhere returned false although the element was present" extractMinimalWhereCount <- extractMinimalWhereCount + 1 elif r < 0.6666 then if (extractMaximalWhere (fun e -> e <= element) tree).IsNone then printfn "ERROR: extractMaximalWhere returned false although the element was present" extractMaximalWhereCount <- extractMaximalWhereCount + 1 else if not <| remove tree element then printfn "ERROR: remove returned false although the element was present" removeCount <- removeCount + 1 else let id = r.Next(elements.Count) let element = elements.[id] elements.RemoveAt id used.Add element if not <| insert tree element then printfn "ERROR: insert returned false although the element was not present" maxCount <- Fun.Max(maxCount, used.Count) insertCount <- insertCount + 1 iter <- iter + 1 checkCorrectness() checkCompleteness() checkSorting() checkBalanceAndHeightCaches() checkFind() printfn "tree contained up to %d elements" maxCount printfn " insert: %d" insertCount printfn " remove: %d" removeCount printfn " extractMinimalWhere: %d" extractMinimalWhereCount printfn " extractMaximalWhere: %d" extractMaximalWhereCount printfn " current-count: %d (expected %d)" (tree |> toList).Length (insertCount - removeCount - extractMaximalWhereCount - extractMinimalWhereCount) printfn "test finished" let test() = let t = empty insert t 5 |> ignore insert t 6 |> ignore insert t 7 |> ignore insert t 8 |> ignore insert t 9 |> ignore insert t 10 |> ignore printfn "%s" t.AsString print t let test = extractMinimalWhere (fun v -> v > 5) t let test2 = extractMaximalWhere (fun v -> v < 10) t printfn "minimal > 5 = %A" test printfn "maximal < 10 = %A" test2 remove t 10 |> ignore printfn "%s" t.Root.AsString module BucketAVL = open System.Collections.Generic [] type private LinkedListNode<'a> = class val mutable public Value : 'a val mutable public Next : LinkedListNode<'a> val mutable public Prev : LinkedListNode<'a> new(value : 'a) = { Value = value; Next = null; Prev = null } end type private Bucket<'a when 'a : equality>() = let mutable representative : Option<'a> = None let mutable root : Option> = None let references = Dictionary<'a, LinkedListNode<'a>>() let mutable next : Option> = None let mutable prev : Option> = None member x.AsSeq = match root with | Some r -> seq { yield r.Value let current = ref r.Next while !current <> r do yield current.Value.Value current := current.Value.Next } | None -> Seq.empty member x.Next with get() = next and set v = next <- v member x.Prev with get() = prev and set v = prev <- v member x.Value = representative.Value member x.Add(value : 'a) = if references.ContainsKey value then false else representative <- Some value let node = LinkedListNode(value) references.Add(value, node) match root with | Some r -> let last = r.Prev node.Prev <- last node.Next <- r last.Next <- node r.Prev <- node | None -> node.Prev <- node node.Next <- node root <- Some node true member x.Remove(value : 'a) = match references.TryGetValue value with | (true, r) -> if r = root.Value then if r.Next = r then root <- None else root <- Some r.Next r.Prev.Next <- r.Next r.Next.Prev <- r.Prev references.Remove value |> ignore //if the representative is removed change it to some other one //if the bucket gets empty maintain the representative since //it is needed for the tree-removal. (the bucket will be removed anyways) if value = representative.Value && references.Count > 0 then representative <- Some root.Value.Value true | _ -> false member x.FirstElement = root.Value.Value member x.LastElement = let last : LinkedListNode<'a> = root.Value.Prev last.Value member x.Count = references.Count type BucketTree<'a when 'a : equality> = private { cmp : 'a -> 'a -> int; tree : AVL.Tree> } let custom cmp = { cmp = cmp; tree = AVL.custom (fun (l : Bucket<'a>) (r : Bucket<'a>) -> cmp l.Value r.Value) } let insert (t : BucketTree<'a>) (value : 'a) = match AVL.find (fun (o : Bucket<'a>) -> t.cmp value o.Value) t.tree with | Some b -> b.Add value | None -> let b = Bucket<'a>() b.Add value |> ignore AVL.insertNeighbourhood t.tree b (fun prev next -> b.Prev <- prev b.Next <- next match next with Some n -> n.Prev <- Some b | _ -> () match prev with Some p -> p.Next <- Some b | _ -> () ) let insertNeighbourhood (t : BucketTree<'a>) (value : 'a) (f : Option<'a> -> Option<'a> -> unit) = match t.tree |> AVL.find (fun o -> t.cmp value o.Value) with | Some b -> let last = Some b.LastElement let next = match b.Next with | Some b -> Some b.FirstElement | _ -> None if b.Add value then f last next true else false | _ -> let b = Bucket<'a>() b.Add value |> ignore AVL.insertNeighbourhood t.tree b (fun prev next -> b.Prev <- prev b.Next <- next match next with Some n -> n.Prev <- Some b | _ -> () match prev with Some p -> p.Next <- Some b | _ -> () let prev = match prev with | Some p -> Some p.LastElement | None -> None let next = match next with | Some n -> Some n.FirstElement | None -> None f prev next ) let remove (t : BucketTree<'a>) (value : 'a) = match AVL.find (fun (o : Bucket<'a>) -> t.cmp value o.Value) t.tree with | Some b -> if b.Remove value then if b.Count = 0 then if AVL.remove t.tree b then match b.Prev with | Some p -> p.Next <- b.Next | _ -> () match b.Next with | Some n -> n.Prev <- b.Prev | _ -> () true else false else true else false | None -> false // // let extractMinimalWhere (condition : 'a -> bool) (t : BucketTree<'a>) = // match t.tree |> AVL.findMinimalWhere (fun b -> condition b.Value) with // | Some b -> // let some = b.Value // b.Remove some |> ignore // if b.Count = 0 then // AVL.remove t.tree b |> ignore // Some some // | None -> None // // let extractMaximalWhere (condition : 'a -> bool) (t : BucketTree<'a>) = // match t.tree |> AVL.findMaximalWhere (fun b -> condition b.Value) with // | Some b -> // let some = b.Value // b.Remove some |> ignore // if b.Count = 0 then // AVL.remove t.tree b |> ignore // Some some // | None -> None let toSeq (t : BucketTree<'a>) = t.tree |> AVL.toSeq |> Seq.collect (fun b -> b.AsSeq) let toList (t : BucketTree<'a>) = t |> toSeq |> Seq.toList let toArray (t : BucketTree<'a>) = t |> toSeq |> Seq.toArray let runTests() = let t = custom (fun l r -> compare (l % 10) (r % 10)) let numbers = Array.init 1000 id for n in numbers do if not <| insertNeighbourhood t n (fun l r -> ()) then printfn "ERROR: insert of %A failed" n let content = toArray t if content.Length <> numbers.Length then printfn "elements missing" ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Mutable/ConcurrentHashQueue.fs ================================================ namespace Aardvark.Base open System.Threading open System.Runtime.InteropServices [] type private HashQueueNode<'a> = class val mutable public Value : 'a val mutable public Next : HashQueueNode<'a> val mutable public Prev : HashQueueNode<'a> new(v,p,n) = { Value = v; Prev = p; Next = n } end type ConcurrentHashQueue<'a when 'a : equality>() = let lockObj = obj() let nodes = Dict<'a, HashQueueNode<'a>>() let mutable first = null let mutable last = null let detach (node : HashQueueNode<'a>) = if isNull node.Prev then first <- node.Next else node.Prev.Next <- node.Next if isNull node.Next then last <- node.Prev else node.Next.Prev <- node.Prev member x.Count = lock lockObj (fun () -> nodes.Count) member x.Enqueue(value : 'a) = lock lockObj (fun () -> let node,added = match nodes.TryGetValue value with | (true, node) -> detach node node.Prev <- last node.Next <- null node, false | _ -> let node = HashQueueNode(value, last, null) nodes.[value] <- node node, true if isNull last then first <- node else last.Next <- node last <- node added ) member x.Dequeue() = lock lockObj (fun () -> if isNull first then failwith "HashQueue empty" else let value = first.Value first <- first.Next first.Prev <- null nodes.Remove value |> ignore value ) member x.TryDequeue([] result : byref<'a>) = try Monitor.Enter lockObj if isNull first then false else let value = first.Value detach first nodes.Remove value |> ignore result <- value true finally Monitor.Exit lockObj member x.Remove(value : 'a) = lock lockObj (fun () -> match nodes.TryRemove value with | (true, node) -> detach node node.Value <- Unchecked.defaultof<_> node.Prev <- null node.Next <- null true | _ -> false ) member x.Clear() = lock lockObj (fun () -> nodes.Clear() first <- null last <- null ) [] module ConcurrentHashQueue = let inline empty<'a when 'a : equality> = ConcurrentHashQueue<'a>() let inline enqueue (v : 'a) (q : ConcurrentHashQueue<'a>) = q.Enqueue v let inline tryDequeue (q : ConcurrentHashQueue<'a>) = match q.TryDequeue() with | (true, v) -> Some v | _ -> None let inline dequeue (q : ConcurrentHashQueue<'a>) = q.Dequeue() let inline count (q : ConcurrentHashQueue<'a>) = q.Count let inline clear (q : ConcurrentHashQueue<'a>) = q.Clear() ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Mutable/FixedSizeArray.fs ================================================ namespace Aardvark.Base [] module Arrays = open System open System.Collections.Generic [] type Arr<'d, 'a when 'd :> INatural>(elements : seq<'a>) = static let size = typeSize<'d> let data = Array.zeroCreate size do let elements = elements |> Seq.toArray let l = min elements.Length size for i in 0..l-1 do data.[i] <- elements.[i] member x.Data = data member x.Item with get i = data.[i] and set i v = data.[i] <- v member x.Length = size member x.AsString = sprintf "%A" data new() = Arr [] interface IEnumerable<'a> with member x.GetEnumerator() : System.Collections.Generic.IEnumerator<'a> = (data |> Array.toSeq).GetEnumerator() member x.GetEnumerator() : System.Collections.IEnumerator = data.GetEnumerator() [] type FixedList<'d, 'a when 'd :> INatural> = { storage : Arr<'d, 'a>; mutable Count : int } with member x.Item with get i = x.storage.[i] and set i v = x.storage.[i] <- v member x.Add(value : 'a) = x.storage.[x.Count] <- value x.Count <- x.Count + 1 member x.RemoveAt(index : int) = for i in index+1..x.Count-1 do x.storage.[i-1] <- x.storage.[i] x.Count <- x.Count - 1 // // let z<'a> = Arr([||]) // // let (|&) (a : Arr<'d, 'a>) (v : 'a) : Arr, 'a> = // let data = a.Data // let inner = Array.concat [data; [|v|]] // Arr, 'a>(inner) // // let (~~) (v : 'a) : Arr, 'a> = // Arr [v] [] module Arr = let inline map ([] f : 'a -> 'b) (a : Arr<'d, 'a>) : Arr<'d, 'b> = let result = Array.zeroCreate a.Length for i in 0..a.Length-1 do result.[i] <- f a.[i] Arr<'d,'b>(result) let inline fold (f : 's -> 'a -> 's) (seed : 's) (a : Arr<'d, 'a>) : 's = let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt f let mutable result = seed for i in 0..a.Length-1 do result <- f.Invoke(result, a.[i]) result let inline foldBack (f : 'a -> 's -> 's) (seed : 's) (a : Arr<'d, 'a>) : 's = let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt f let mutable result = seed for i in 1..a.Length do let i = a.Length-i result <- f.Invoke(a.[i], result) result let inline sumBy ([] f : 'a -> 'b) (arr : Arr<'d, 'a>)= fold (fun s v -> s + (f v)) LanguagePrimitives.GenericZero arr let inline sum (arr : Arr<'d, 'a>)= fold (+) LanguagePrimitives.GenericZero arr let ofList (l : list<'a>) : Arr<'d, 'a> = Arr(l) let ofSeq (l : seq<'a>) : Arr<'d, 'a> = Arr(l) [] module ArrList = let empty<'d, 'a when 'd :> INatural> : FixedList<'d, 'a> = { storage = Arr<'d, 'a>(); Count = 0 } let inline map ([] f : 'a -> 'b) (l : FixedList<'d, 'a>) : FixedList<'d, 'b> = let result = Arr<'d, 'b>() for i in 0..l.Count-1 do result.[i] <- f l.storage.[i] { storage =result; Count = l.Count } let inline choose ([] f : 'a -> Option<'b>) (l : FixedList<'d, 'a>) : FixedList<'d, 'b> = let result = Arr<'d, 'b>() let mutable count = 0 for i in 0..l.Count-1 do match f l.[i] with | Some v -> result.[count] <- v count <- count + 1 | None -> () { storage = result; Count = count } let inline fold (acc : 'a -> 'b -> 'a) (seed : 'a) (l : FixedList<'d, 'b>) : 'a = let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt acc let mutable result = seed for i in 0..l.Count-1 do result <- f.Invoke(result, l.storage.[i]) result let inline foldBack (acc : 'b -> 'a -> 'a) (seed : 'a) (l : FixedList<'d, 'b>) : 'a = let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt acc let mutable result = seed for i in 1..l.Count do result <- f.Invoke(l.storage.[i - l.Count], result) result let inline sumBy ([] f : 'a -> 'b) (l : FixedList<'d, 'a>) : 'b = let mutable result = LanguagePrimitives.GenericZero for i in 0..l.Count-1 do result <- result + f l.storage.[i] result let inline sum (l : FixedList<'d, 'a>) : 'a = let mutable result = LanguagePrimitives.GenericZero for i in 0..l.Count-1 do result <- result + l.storage.[i] result let inline filter ([] condition : 'a -> bool) (l : FixedList<'d, 'a>) : FixedList<'d, 'a> = let result = Arr<'d, 'a>() let mutable count = 0 for i in 0..l.Count-1 do if condition l.[i] then result.[count] <- l.storage.[i] count <- count + 1 { storage = result; Count = count } let ofArr (a : Arr<'d, 'a>) = { storage = a; Count = a.Length } module List = let toFixed<'d, 'a when 'd :> INatural> (l : list<'a>) = Arr<'d, 'a>(l) module Seq = let toFixed<'d, 'a when 'd :> INatural> (l : seq<'a>) = Arr<'d, 'a>(l) module Array = let toFixed<'d, 'a when 'd :> INatural> (l : seq<'a>) = Arr<'d, 'a>(l) [] let (|FixedArrayType|_|) (t : Type) = if t.IsGenericType && t.GetGenericTypeDefinition() = typedefof> then let targs = t.GetGenericArguments() ValueSome (getSize targs.[0], targs.[1]) else ValueNone [] let (|FixedArray|_|) (o : obj) = let t = o.GetType() match t with | FixedArrayType(_,content) -> let store = t.GetProperty("Data").GetValue(o) |> unbox let result = Array.create store.Length null for i in 0..store.Length-1 do result.[i] <- store.GetValue(i) ValueSome (content, result) | _ -> ValueNone ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Mutable/OrderMaintenance.fs ================================================ namespace Aardvark.Base open System open System.Collections.Generic [] type IDeletableComparable = inherit IComparable abstract member IsDeleted : bool [] type ISortKey = inherit IDeletableComparable abstract member Clock : IOrder and IOrder = abstract member Count : int abstract member Root : ISortKey module Order = // let toSeq (c : IOrder) = // let rec toSeq (t : ISortKey) = // seq { // yield t // if t.Next <> c.Root then // yield! toSeq t // } // // toSeq c.Root.Next // // let toArray (c : IOrder) = // let mutable current = c.Root.Next // let arr = Array.zeroCreate (c.Count-1) // for i in 0..c.Count-2 do // arr.[i] <- current // current <- current.Next // arr // let toList (c : IOrder) = // c |> toArray |> Array.toList let inline count (c : IOrder) = c.Count let inline root (c : IOrder) = c.Root module SimpleOrder = [] type SortKey = class val mutable public Clock : Order val mutable public Tag : uint64 val mutable public Next : SortKey val mutable public Prev : SortKey member x.Time = x.Tag - x.Clock.Root.Tag member x.CompareTo (o : SortKey) = if isNull o.Next || isNull x.Next then failwith "cannot compare deleted times" if o.Clock <> x.Clock then failwith "cannot compare times from different clocks" compare x.Time o.Time interface IComparable with member x.CompareTo o = match o with | :? SortKey as o -> x.CompareTo(o) | _ -> failwithf "cannot compare time with %A" o interface IComparable with member x.CompareTo o = match o with | :? SortKey as o -> x.CompareTo o | _ -> failwithf "cannot compare time with %A" o override x.GetHashCode() = System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(x) override x.Equals o = System.Object.ReferenceEquals(x,o) interface ISortKey with member x.Clock = x.Clock :> IOrder member x.IsDeleted = isNull x.Next //member x.Next = x.Next :> ISortKey new(c) = { Clock = c; Tag = 0UL; Next = null; Prev = null } end and Order = class val mutable public Root : SortKey val mutable public Count : int member x.After (t : SortKey) = if t.Clock <> x then failwith "cannot insert after a different clock's time" let distance (a : SortKey) (b : SortKey) = if a = b then System.UInt64.MaxValue else b.Tag - a.Tag let mutable dn = distance t t.Next // if the distance to the next time is 1 (no room) // relabel all times s.t. the new one can be inserted if dn = 1UL then // find a range s.t. distance(range) >= 1 + |range|^2 let mutable current = t.Next let mutable j = 1UL while distance t current < 1UL + j * j do current <- current.Next j <- j + 1UL // distribute all times in the range equally spaced let step = (distance t current) / j current <- t.Next let mutable currentTime = t.Tag + step for k in 1UL..(j-1UL) do current.Tag <- currentTime current <- current.Next currentTime <- currentTime + step // store the distance to the next time dn <- step // insert the new time with distance (dn / 2) after // the given one (there has to be enough room now) let res = SortKey(x) res.Tag <- t.Tag + dn / 2UL res.Next <- t.Next res.Prev <- t t.Next.Prev <- res t.Next <- res res member x.Before (t : SortKey) = if t = x.Root then failwith "cannot insert before root-time" x.After t.Prev member x.Delete (t : SortKey) = if not (isNull t.Next) then if t.Clock <> x then failwith "cannot delete time from different clock" t.Prev.Next <- t.Next t.Next.Prev <- t.Prev t.Next <- null t.Prev <- null t.Tag <- 0UL t.Clock <- Unchecked.defaultof<_> member x.Clear() = let r = SortKey(x) x.Root <- r r.Next <- r r.Prev <- r x.Count <- 1 interface IOrder with member x.Root = x.Root :> ISortKey member x.Count = x.Count static member New() = let c = Order() let r = SortKey(c) c.Root <- r r.Next <- r r.Prev <- r c private new() = { Root = null; Count = 1 } end let create() = Order.New() module SkipOrder = let private random = Random() let randomHeight() = 1 - random.NextDouble().Log2Int() [] type SortKey = class val mutable public Clock : Order val mutable public Tag : uint64 val mutable public NextArray : SortKeyLink[] val mutable public PrevArray : SortKeyLink[] val mutable public IsDeleted : bool member x.Time = x.Tag - x.Clock.Root.Tag member x.Height = x.NextArray.Length member x.Next = if not (isNull x.NextArray) then x.NextArray.[0].Target else null member x.Prev = if not (isNull x.PrevArray) then x.PrevArray.[0].Target else null member x.CompareTo (o : SortKey) = if o.IsDeleted || x.IsDeleted then failwith "cannot compare deleted times" if o.Clock <> x.Clock then failwith "cannot compare times from different clocks" compare x.Time o.Time interface IComparable with member x.CompareTo o = match o with | :? SortKey as o -> x.CompareTo(o) | _ -> failwithf "cannot compare time with %A" o interface IComparable with member x.CompareTo o = match o with | :? SortKey as o -> x.CompareTo o | _ -> failwithf "cannot compare time with %A" o override x.GetHashCode() = System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(x) override x.Equals o = System.Object.ReferenceEquals(x,o) interface ISortKey with member x.Clock = x.Clock :> IOrder member x.IsDeleted = x.IsDeleted //member x.Next = x.Next :> ISortKey new(c, h) = { Clock = c; Tag = 0UL; NextArray = Array.zeroCreate h; PrevArray = Array.zeroCreate h; IsDeleted = false } end and SortKeyLink = struct val mutable public Width : int val mutable public Target : SortKey new(w,t) = { Width = w; Target = t } end and Order = class val mutable public Root : SortKey val mutable public Count : int member x.After (t : SortKey) = if t.Clock <> x then failwith "cannot insert after a different clock's time" let distance (a : SortKey) (b : SortKey) = if a = b then System.UInt64.MaxValue else b.Tag - a.Tag let mutable dn = distance t t.Next // if the distance to the next time is 1 (no room) // relabel all times s.t. the new one can be inserted if dn = 1UL then // find a range s.t. distance(range) >= 1 + |range|^2 let mutable current = t.NextArray.[0].Target let mutable j = 1UL while distance t current < 1UL + j * j do current <- current.Next j <- j + 1UL // distribute all times in the range equally spaced let step = (distance t current) / j current <- t.NextArray.[0].Target let mutable currentTime = t.Tag + step for k in 1UL..(j-1UL) do current.Tag <- currentTime current <- current.NextArray.[0].Target currentTime <- currentTime + step // store the distance to the next time dn <- step // insert the new time with distance (dn / 2) after // the given one (there has to be enough room now) let h = randomHeight() let res = SortKey(x, h) res.Tag <- t.Tag + dn / 2UL // since the predecessor might be "smaller" than // the new node we need to search the remaining links // by going backward in the list let mutable current = t let mutable distance = 1 let resize (h : int) = let n = x.Root if h > n.Height then let additional = Array.create (h - n.Height) (SortKeyLink(x.Count,n)) n.NextArray <- Array.append n.NextArray additional n.PrevArray <- Array.append n.PrevArray additional let back (n : SortKey) = let link = n.PrevArray.[n.PrevArray.Length - 1] (link.Width, link.Target) let tup (l : SortKeyLink) = (l.Width, l.Target) for i in 0..h-1 do // go backwards until a node with sufficient height is found // or until we've reached the representant while i >= current.Height && current <> x.Root do let (d,l) = back current current <- l distance <- distance + d // if the found node is not sufficiently high it must // be the representant and therefore it has to be resized if i >= current.Height then resize h // current must now be sufficiently high let (d,n) = tup current.NextArray.[i] current.NextArray.[i] <- SortKeyLink(distance, res) res.PrevArray.[i] <- SortKeyLink(distance, current) res.NextArray.[i] <- SortKeyLink(1 + d - distance, n) n.PrevArray.[i] <- SortKeyLink(1 + d - distance, res) // since the predecessor and the new node might be // smaller than the total height we need to increment // the width of all pointers "passing" the new node (above) let mutable current = t for i in h..x.Root.Height-1 do while i >= current.Height && current <> x.Root do let (d,l) = back current current <- l let (d,n) = tup current.NextArray.[i] current.NextArray.[i] <- SortKeyLink(d + 1, n) n.PrevArray.[i] <- SortKeyLink(d + 1, current) // finally increment the count and return the node x.Count <- x.Count + 1 res member x.Before (t : SortKey) = if t = x.Root then failwith "cannot insert before root-time" x.After t.Prev member x.Delete (t : SortKey) = if not (isNull t.NextArray) then if t.Clock <> x then failwith "cannot delete time from different clock" let tup (l : SortKeyLink) = (l.Width, l.Target) for l in 0..t.Height-1 do let (dp, p) = tup t.PrevArray.[l] let (dn, n) = tup t.NextArray.[l] n.PrevArray.[l] <- SortKeyLink(dp + dn - 1, p) p.NextArray.[l] <- SortKeyLink(dp + dn - 1, n) let mutable current = t let mutable distance = 1 for i in t.Height..x.Root.Height-1 do let back (n : SortKey) = let l = n.PrevArray.[n.PrevArray.Length - 1] (l.Width, l.Target) // go backwards until a node with sufficient height is found // or until we've reached the representant while i >= current.Height && current <> x.Root do let (d,l) = back current current <- l distance <- distance + d let (dn, n) = tup current.NextArray.[i] current.NextArray.[i] <- SortKeyLink(dn - 1, n) n.PrevArray.[i] <- SortKeyLink(dn - 1, current) // every level (except for 0) on which rep.NextArray.[level] = rep // is useless and is therefore removed let rep = x.Root let mutable repHeight = rep.Height while repHeight > 1 && rep.NextArray.[repHeight - 1].Target = rep do repHeight <- repHeight - 1 if repHeight < rep.Height then rep.NextArray <- Array.sub rep.NextArray 0 repHeight rep.PrevArray <- Array.sub rep.PrevArray 0 repHeight x.Count <- x.Count - 1 t.IsDeleted <- true // t.NextArray <- null // t.PrevArray <- null // t.Tag <- 0UL // t.Clock <- Unchecked.defaultof<_> member x.Clear() = let r = SortKey(x, 1) x.Root <- r r.NextArray.[0] <- SortKeyLink(1,r) r.PrevArray.[0] <- SortKeyLink(1,r) x.Count <- 1 /// gets the n-th time after this one /// NOTE that this only works on representant-nodes member x.TryAt (index : int) = let rec search (index : int) (level : int) (t : SortKey) : Option = if level < 0 then if index = 0 then Some t else None else let link = t.NextArray.[level] if index < link.Width then search index (level - 1) t else search (index - link.Width) level link.Target if index >= 0 && index < x.Count then search index (x.Root.Height - 1) x.Root else None member x.TryGetIndex (t : SortKey) = if t.Clock <> x || t.IsDeleted then -1 else let mutable index = 0 let mutable current = t while current <> x.Root do let link = t.PrevArray.[t.PrevArray.Length - 1] index <- index + link.Width current <- link.Target index member x.Item with get (index : int) = match x.TryAt index with | Some t -> t | None -> raise <| IndexOutOfRangeException() interface IOrder with member x.Root = x.Root :> ISortKey member x.Count = x.Count static member New() = let c = Order() let r = SortKey(c, 1) c.Root <- r r.NextArray.[0] <- SortKeyLink(1,r) r.PrevArray.[0] <- SortKeyLink(1,r) c private new() = { Root = null; Count = 1 } end let create() = Order.New() module DerivedOrder = let private random = Random() let randomHeight() = 1 - random.NextDouble().Log2Int() type private DeletedImpl<'a>() = static let isDeleted = if typeof.IsAssignableFrom(typeof<'a>) then fun (a : 'a) -> let t = unbox a if not (isNull t) then t.IsDeleted else false else fun (a : 'a) -> false static member IsDeleted = isDeleted [] type SortKey<'a> = class val mutable public Clock : Order<'a> val mutable public Tag : uint64 val mutable public Item : 'a val mutable public NextArray : SortKeyLink<'a>[] val mutable public PrevArray : SortKeyLink<'a>[] val mutable public IsDeleted : bool member x.Time = x.Tag - x.Clock.Root.Tag member x.Height = x.NextArray.Length member x.Next = if not (isNull x.NextArray) then x.NextArray.[0].Target else null member x.Prev = if not (isNull x.PrevArray) then x.PrevArray.[0].Target else null member x.CompareTo (o : SortKey<'a>) = if o.IsDeleted || x.IsDeleted then failwith "cannot compare deleted times" if o.Clock <> x.Clock then failwith "cannot compare times from different clocks" compare x.Time o.Time interface IComparable with member x.CompareTo o = match o with | :? SortKey<'a> as o -> x.CompareTo(o) | _ -> failwithf "cannot compare time with %A" o interface IComparable with member x.CompareTo o = match o with | :? SortKey<'a> as o -> x.CompareTo o | _ -> failwithf "cannot compare time with %A" o override x.GetHashCode() = System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(x) override x.Equals o = System.Object.ReferenceEquals(x,o) interface ISortKey with member x.Clock = x.Clock :> IOrder member x.IsDeleted = x.IsDeleted //member x.Next = x.Next :> ISortKey new(c, h) = { Clock = c; Tag = 0UL; NextArray = Array.zeroCreate h; PrevArray = Array.zeroCreate h; Item = Unchecked.defaultof<_>; IsDeleted = false } end and SortKeyLink<'a> = struct val mutable public Width : int val mutable public Target : SortKey<'a> new(w,t) = { Width = w; Target = t } end and Order<'a> = class val mutable public Root : SortKey<'a> val mutable public Count : int val mutable public Comparer : IComparer<'a> member x.IsDeleted (item : 'a) = DeletedImpl<'a>.IsDeleted item member private x.After (t : SortKey<'a>) = if t.Clock <> x then failwith "cannot insert after a different clock's time" let distance (a : SortKey<'a>) (b : SortKey<'a>) = if a = b then System.UInt64.MaxValue else b.Tag - a.Tag let mutable dn = distance t t.Next // if the distance to the next time is 1 (no room) // relabel all times s.t. the new one can be inserted if dn = 1UL then // find a range s.t. distance(range) >= 1 + |range|^2 let mutable current = t.NextArray.[0].Target let mutable j = 1UL while distance t current < 1UL + j * j do current <- current.Next j <- j + 1UL // distribute all times in the range equally spaced let step = (distance t current) / j current <- t.NextArray.[0].Target let mutable currentTime = t.Tag + step for k in 1UL..(j-1UL) do current.Tag <- currentTime current <- current.NextArray.[0].Target currentTime <- currentTime + step // store the distance to the next time dn <- step // insert the new time with distance (dn / 2) after // the given one (there has to be enough room now) let h = randomHeight() let res = SortKey(x, h) res.Tag <- t.Tag + dn / 2UL // since the predecessor might be "smaller" than // the new node we need to search the remaining links // by going backward in the list let mutable current = t let mutable distance = 1 let resize (h : int) = let n = x.Root if h > n.Height then let additional = Array.create (h - n.Height) (SortKeyLink(x.Count,n)) n.NextArray <- Array.append n.NextArray additional n.PrevArray <- Array.append n.PrevArray additional let back (n : SortKey<'a>) = let link = n.PrevArray.[n.PrevArray.Length - 1] (link.Width, link.Target) let tup (l : SortKeyLink<'a>) = (l.Width, l.Target) for i in 0..h-1 do // go backwards until a node with sufficient height is found // or until we've reached the representant while i >= current.Height && current <> x.Root do let (d,l) = back current current <- l distance <- distance + d // if the found node is not sufficiently high it must // be the representant and therefore it has to be resized if i >= current.Height then resize h // current must now be sufficiently high let (d,n) = tup current.NextArray.[i] current.NextArray.[i] <- SortKeyLink(distance, res) res.PrevArray.[i] <- SortKeyLink(distance, current) res.NextArray.[i] <- SortKeyLink(1 + d - distance, n) n.PrevArray.[i] <- SortKeyLink(1 + d - distance, res) // since the predecessor and the new node might be // smaller than the total height we need to increment // the width of all pointers "passing" the new node (above) let mutable current = t for i in h..x.Root.Height-1 do while i >= current.Height && current <> x.Root do let (d,l) = back current current <- l let (d,n) = tup current.NextArray.[i] current.NextArray.[i] <- SortKeyLink(d + 1, n) n.PrevArray.[i] <- SortKeyLink(d + 1, current) // finally increment the count and return the node x.Count <- x.Count + 1 res member x.Get(value : 'a) : SortKey<'a> = if x.IsDeleted value then failwith "cannot get time for deleted input-value" let rec findPrevAcc (acc : array<_>) (index : int) (level : int) (v : 'a) (n : SortKey<'a>) = if level < 0 then (index, acc) else let link = n.NextArray.[level] if link.Target = x.Root then acc.[level] <- SortKeyLink(index, n) findPrevAcc acc index (level - 1) v n else if x.IsDeleted link.Target.Item then x.Delete link.Target findPrevAcc acc index (min (x.Root.Height-1) level) v n else if link.Target <> x.Root && x.Comparer.Compare(v, link.Target.Item) > 0 then let t = n.NextArray.[level].Target let level = min level (t.NextArray.Length-1) findPrevAcc acc (index + link.Width) level v t else acc.[level] <- SortKeyLink(index, n) findPrevAcc acc index (level - 1) v n let ptr = Array.zeroCreate x.Root.Height let (index, prev) = findPrevAcc ptr 0 (x.Root.Height-1) value x.Root let next = prev.[0].Target if next <> x.Root && x.Comparer.Compare(next.Item, value) = 0 then prev.[0].Target else let tn = x.After prev.[0].Target tn.Item <- value tn member x.Delete (t : SortKey<'a>) = if t = x.Root then failwith "tried to delete root" if t.IsDeleted |> not then if t.Clock <> x then failwith "cannot delete time from different clock" let tup (l : SortKeyLink<'a>) = (l.Width, l.Target) for l in 0..t.Height-1 do let (dp, p) = tup t.PrevArray.[l] let (dn, n) = tup t.NextArray.[l] n.PrevArray.[l] <- SortKeyLink(dp + dn - 1, p) p.NextArray.[l] <- SortKeyLink(dp + dn - 1, n) let mutable current = t let mutable distance = 1 for i in t.Height..x.Root.Height-1 do let back (n : SortKey<'a>) = let l = n.PrevArray.[n.PrevArray.Length - 1] (l.Width, l.Target) // go backwards until a node with sufficient height is found // or until we've reached the representant while current.Height <= i && current <> x.Root do let (d,l) = back current current <- l distance <- distance + d let (dn, n) = tup current.NextArray.[i] current.NextArray.[i] <- SortKeyLink(dn - 1, n) n.PrevArray.[i] <- SortKeyLink(dn - 1, current) // every level (except for 0) on which rep.NextArray.[level] = rep // is useless and is therefore removed let rep = x.Root let mutable repHeight = rep.Height while repHeight > 1 && rep.NextArray.[repHeight - 1].Target = rep do repHeight <- repHeight - 1 if repHeight < rep.Height then rep.NextArray <- Array.sub rep.NextArray 0 repHeight rep.PrevArray <- Array.sub rep.PrevArray 0 repHeight x.Count <- x.Count - 1 t.IsDeleted <- true // t.NextArray <- null // t.PrevArray <- null // t.Tag <- 0UL // t.Clock <- Unchecked.defaultof<_> member x.Clear() = let r = SortKey(x, 1) x.Root <- r r.NextArray.[0] <- SortKeyLink(1,r) r.PrevArray.[0] <- SortKeyLink(1,r) x.Count <- 1 /// gets the n-th time after this one /// NOTE that this only works on representant-nodes member x.TryAt (index : int) = let rec search (index : int) (level : int) (t : SortKey<'a>) : Option> = if level < 0 then if index = 0 then Some t else None else let link = t.NextArray.[level] if index < link.Width then search index (level - 1) t else search (index - link.Width) level link.Target if index >= 0 && index < x.Count then search index (x.Root.Height - 1) x.Root else None member x.Item with get (index : int) = match x.TryAt index with | Some t -> t | None -> raise <| IndexOutOfRangeException() interface IOrder with member x.Root = x.Root :> ISortKey member x.Count = x.Count static member New(cmp) = let c = Order<'a>(cmp) let r = SortKey(c, 1) c.Root <- r r.NextArray.[0] <- SortKeyLink(1,r) r.PrevArray.[0] <- SortKeyLink(1,r) c private new(cmp) = { Root = null; Count = 1; Comparer = cmp } end let create(cmp) = Order.New(cmp) type IReal = inherit IComparable abstract member InsertAfter : unit -> IReal module RealNumber = open System.Threading [] module private Implementation = type MonitorList() = let acquired = HashSet() member x.Add(o : obj) = if acquired.Add o then Monitor.Enter o member x.Dispose() = for a in acquired do Monitor.Exit a interface IDisposable with member x.Dispose() = x.Dispose() [] type SortKey = class val mutable public RefCount : int val mutable public Root : SortKey val mutable public Tag : uint64 val mutable public Next : SortKey val mutable public Prev : SortKey member x.Time = x.Tag - x.Root.Tag static member private CompareInternal(l : SortKey, r : SortKey) = match Monitor.TryEnter(l), Monitor.TryEnter(r) with | true, true -> let res = compare l.Time r.Time Monitor.Exit l Monitor.Exit r res | false, true -> Monitor.Exit r SortKey.CompareInternal(l, r) | true, false -> Monitor.Exit l SortKey.CompareInternal(l, r) | false, false -> SortKey.CompareInternal(l, r) member x.CompareTo (o : SortKey) = if isNull o.Root || isNull x.Root then failwith "cannot compare deleted times" if o.Root != x.Root then failwith "cannot compare times from different clocks" SortKey.CompareInternal(x, o) member t.InsertAfter() = use l = new MonitorList() l.Add t l.Add t.Next let distance (a : SortKey) (b : SortKey) = if a = b then System.UInt64.MaxValue else b.Tag - a.Tag let mutable dn = distance t t.Next // if the distance to the next time is 1 (no room) // relabel all times s.t. the new one can be inserted if dn = 1UL then // find a range s.t. distance(range) >= 1 + |range|^2 let mutable current = t.Next let mutable j = 1UL while distance t current < 1UL + j * j do l.Add current.Next current <- current.Next j <- j + 1UL // distribute all times in the range equally spaced let step = (distance t current) / j current <- t.Next let mutable currentTime = t.Tag + step for k in 1UL..(j-1UL) do current.Tag <- currentTime current <- current.Next currentTime <- currentTime + step // store the distance to the next time dn <- step // insert the new time with distance (dn / 2) after // the given one (there has to be enough room now) let res = SortKey(t.Root, Prev = t, Next = t.Next, Tag = t.Tag + dn / 2UL) t.Next.Prev <- res t.Next <- res res member x.AddRef() = Interlocked.Increment(&x.RefCount) |> ignore member x.Delete() = if Interlocked.Decrement(&x.RefCount) = 0 then lock x (fun () -> x.Prev.Next <- x.Next x.Next.Prev <- x.Prev // x.Next <- null // x.Prev <- null x.Root <- null ) interface IComparable with member x.CompareTo o = match o with | :? SortKey as o -> x.CompareTo o | _ -> failwithf "cannot compare time with %A" o interface IComparable with member x.CompareTo o = match o with | :? SortKey as o -> x.CompareTo o | _ -> failwithf "cannot compare time with %A" o override x.GetHashCode() = System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(x) override x.Equals o = System.Object.ReferenceEquals(x,o) new(c) = { RefCount = 0; Root = c; Tag = 0UL; Next = null; Prev = null } end type GCKey(k : SortKey) = do k.AddRef() override x.Finalize() = k.Delete() member x.Key = k member x.InsertAfter() = GCKey(k.InsertAfter()) :> IReal interface IReal with member x.InsertAfter() = GCKey(k.InsertAfter()) :> IReal member x.CompareTo o = match o with | :? GCKey as o -> compare k o.Key | :? SortKey as o -> compare k o | _ -> failwith "cannot compare" override x.ToString() = let value = float k.Time / float UInt64.MaxValue value.ToString(System.Globalization.CultureInfo.InvariantCulture) + "r" override x.GetHashCode() = k.GetHashCode() override x.Equals o = match o with | :? GCKey as o -> k = o.Key | _ -> false let zero = let root = SortKey(null) root.Root <- root root.Next <- root root.Prev <- root GCKey(root) :> IReal let after (k : IReal) = k.InsertAfter() let between (l : IReal) (r : IReal) = let l = unbox l let r = unbox r if l >= r then failwith "[GCKey] negative range given" use locks = new MonitorList() locks.Add l locks.Add r if l.Key.Next == r.Key then l.InsertAfter() elif l.Key.Next < r.Key then GCKey(l.Key.Next) :> IReal else failwith "[GCKey] illformed range given" [] type private SortKeyTuple = struct val mutable public K0 : ISortKey val mutable public K1 : ISortKey interface IComparable with member x.CompareTo o = match o with | :? SortKeyTuple as o -> let c = compare x.K0 o.K0 if c <> 0 then c else compare x.K1 o.K1 | _ -> failwith "uncomparable" override x.GetHashCode() = HashCode.Combine(x.K0.GetHashCode(), x.K1.GetHashCode()) override x.Equals o = match o with | :? SortKeyTuple as o -> x.K0 = o.K0 && x.K1 = o.K1 | _ -> false interface IDeletableComparable with member x.IsDeleted = (not (isNull x.K0) && x.K0.IsDeleted) || (not (isNull x.K1) && x.K1.IsDeleted) new(k0, k1) = { K0 = k0; K1 = k1 } end type OrderMaintenance<'a when 'a : equality>(comparer : IComparer<'a>) = let derived = DerivedOrder.create(comparer) let nodes = Dictionary<'a, DerivedOrder.SortKey<'a>>() member x.Count = derived.Count member x.Order = derived :> IOrder member x.Root = derived.Root :> ISortKey member x.Clear() = derived.Clear() nodes.Clear() member x.Invoke(t : 'a) = let res = derived.Get t nodes.[t] <- res res :> ISortKey member x.TryGet(t : 'a) = match nodes.TryGetValue t with | (true,v) -> Some (v :> ISortKey) | _ -> None member x.Revoke(t : 'a) = match nodes.TryGetValue t with | (true, d) -> derived.Delete d d :> ISortKey | _ -> failwith "cannot delete unknown time" new() = OrderMaintenance(Comparer<'a>.Default) new(cmp : 'a -> 'a -> int) = OrderMaintenance { new IComparer<'a> with member x.Compare(l,r) = cmp l r } type OrderMapping() = inherit OrderMaintenance() type NestedOrderMapping() = let derived = DerivedOrder.create(Comparer.Default) let nodes = Dictionary>() member x.Order = derived :> IOrder member x.Count = derived.Count member x.Root = derived.Root :> ISortKey member x.Clear() = derived.Clear() nodes.Clear() member x.Invoke(outer : ISortKey, inner : ISortKey) = let tup = SortKeyTuple(outer,inner) let res = derived.Get tup nodes.[tup] <- res res :> ISortKey member inline private x.Revoke(tup : SortKeyTuple) = match nodes.TryGetValue tup with | (true, d) -> derived.Delete d d :> ISortKey | _ -> failwith "cannot delete unknown time" member x.Revoke(outer : ISortKey, inner : ISortKey) = let tup = SortKeyTuple(outer,inner) x.Revoke(tup) member x.RevokeAll(outer : ISortKey) = let all = nodes.Keys |> Seq.filter (fun tup -> tup.K0 = outer) |> Seq.toList all |> List.map x.Revoke ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Mutable/OrderMaintenanceTrie.fs ================================================ namespace Aardvark.Base open Aardvark.Base open System.Collections.Generic open FSharp.Data.Adaptive #nowarn "1336" [] type TrieReference<'k, 'a> = abstract member Key : list<'k> abstract member Prev : voption> abstract member Next : voption> abstract member Value : 'a with get, set [] module OrderMaintenanceTrieImplementation = [] type Linked<'s when 's :> Linked<'s> and 's : null> = abstract member Prev : 's with get, set abstract member Next : 's with get, set [] type IOrderedDict<'k, 'v when 'v :> Linked<'v> and 'v : null> = abstract member Keys : seq<'k> abstract member TryRemove : key : 'k -> voption<'v> abstract member TryGet : key : 'k -> voption<'v> abstract member GetOrCreate : key : 'k * create : ('k -> 'v -> 'v -> 'v) -> 'v abstract member First : 'v abstract member Last : 'v [] type UnorderedDict<'k, 'v when 'v :> Linked<'v> and 'v : null>() = let mutable first : 'v = null let mutable last : 'v = null let store = Dict<'k, 'v>() member x.GetOrCreate(key : 'k, create : 'k -> 'v -> 'v -> 'v) = store.GetOrCreate(key, fun k -> let n = create k last null if isNull last then first <- n else last.Next <- n last <- n n ) member x.TryRemove(key : 'k) = match store.TryRemove key with | (true, node) -> if isNull node.Prev then first <- node.Next else node.Prev.Next <- node.Next if isNull node.Next then last <- node.Prev else node.Next.Prev <- node.Prev node.Prev <- null node.Next <- null ValueSome node | _ -> ValueNone member x.TryGet(key : 'k) = match store.TryGetValue key with | (true, node) -> ValueSome node | _ -> ValueNone interface IOrderedDict<'k, 'v> with member x.Keys = store.Keys member x.First = first member x.Last = last member x.GetOrCreate(key, create) = x.GetOrCreate(key, create) member x.TryRemove(key) = x.TryRemove(key) member x.TryGet(key) = x.TryGet(key) [] type OrderedDict<'k, 'v when 'v :> Linked<'v> and 'v : null>(cmp : IComparer<'k>) = let mutable first : 'v = null let mutable last : 'v = null static let vo (o : Optional) = if o.HasValue then let struct(_, v) = o.Value v else null let store = SortedSetExt { new IComparer with member x.Compare((struct(lk,_)), (struct(rk, _))) = cmp.Compare(lk, rk) } member x.GetOrCreate(key : 'k, create : 'k -> 'v -> 'v -> 'v) = let l, s, r = store.FindNeighbours(struct (key, null)) if s.HasValue then let struct(_,v) = s.Value v else let l = vo l let r = vo r let node = create key l r store.Add(struct(key, node)) |> ignore if isNull l then first <- node else l.Next <- node if isNull r then last <- node else r.Prev <- node node member x.TryRemove(key : 'k) = let _, s, _ = store.FindNeighbours(struct (key, null)) if s.HasValue then let struct (_, node) = s.Value store.Remove(struct (key, node)) |> ignore let l = node.Prev let r = node.Next if isNull l then first <- r else l.Next <- r if isNull r then last <- l else r.Prev <- l node.Prev <- null node.Next <- null ValueSome node else ValueNone member x.TryGet(key : 'k) = let _, s, _ = store.FindNeighbours(struct (key, null)) if s.HasValue then let struct (_, node) = s.Value ValueSome node else ValueNone interface IOrderedDict<'k, 'v> with member x.Keys = store |> Seq.map (fun struct (k,_) -> k) member x.First = first member x.Last = last member x.GetOrCreate(key, create) = x.GetOrCreate(key, create) member x.TryRemove(key) = x.TryRemove(key) member x.TryGet(key) = x.TryGet(key) module OrderedDict = let ofComparer (cmp : option>) = match cmp with | None -> UnorderedDict<'k, 'v>() :> IOrderedDict<_,_> | Some cmp -> OrderedDict<'k, 'v>(cmp) :> IOrderedDict<_,_> [] type OrderMaintenanceTrieNode<'k, 'a> = val mutable public GetComparer : int -> option> val mutable public Level : int val mutable public Path : list<'k> val mutable public ChildrenDict : IOrderedDict<'k, OrderMaintenanceTrieNode<'k, 'a>> val mutable public Value : ValueOption<'a> val mutable public Parent : OrderMaintenanceTrieNode<'k, 'a> val mutable public Prev : OrderMaintenanceTrieNode<'k, 'a> val mutable public Next : OrderMaintenanceTrieNode<'k, 'a> member private x.AfterLast() = if isNull x.Next then if isNull x.Parent then ValueNone else x.Parent.AfterLast() else x.Next.First interface Linked> with member x.Prev with get() = x.Prev and set p = x.Prev <- p member x.Next with get() = x.Next and set p = x.Next <- p interface TrieReference<'k, 'a> with member x.Key = List.rev x.Path member x.Prev = if isNull x.Prev then if isNull x.Parent then ValueNone elif ValueOption.isSome x.Parent.Value then ValueSome (x.Parent :> TrieReference<_,_>) else (x.Parent :> TrieReference<_,_>).Prev else x.Prev.Last member x.Next = if isNull x.ChildrenDict || isNull x.ChildrenDict.First then if isNull x.Next then if isNull x.Parent then ValueNone else x.Parent.AfterLast() else x.Next.First else x.ChildrenDict.First.First member x.Value with get() = match x.Value with | ValueSome v -> v | _ -> failwith "bad" and set v = x.Value <- ValueSome v member x.Last : voption> = if isNull x.ChildrenDict || isNull x.ChildrenDict.Last then match x.Value with | ValueSome _ -> ValueSome (x :> TrieReference<_,_>) | ValueNone -> if isNull x.Prev then ValueNone else x.Prev.Last else x.ChildrenDict.Last.Last member x.First : voption> = match x.Value with | ValueSome _ -> ValueSome (x :> TrieReference<_,_>) | ValueNone -> if isNull x.ChildrenDict || isNull x.ChildrenDict.First then if isNull x.Next then ValueNone else x.Next.First else x.ChildrenDict.First.First member x.IsEmpty = ValueOption.isNone x.Value && (isNull x.ChildrenDict || isNull x.ChildrenDict.First) member x.TryRemove(k : list<'k>) = match k with | [] -> match x.Value with | ValueSome _ -> let r = x :> TrieReference<_,_> let p = r.Prev let n = r.Next x.Value <- ValueNone ValueSome (p, n) | ValueNone -> ValueNone | h :: t -> if isNull x.ChildrenDict then ValueNone else match x.ChildrenDict.TryGet h with | ValueSome c -> match c.TryRemove t with | ValueSome (prev,next) -> if c.IsEmpty then x.ChildrenDict.TryRemove h |> ignore ValueSome(prev,next) | _ -> ValueNone | _ -> ValueNone member x.Add(k : list<'k>, value : 'a) = match k with | [] -> x.Value <- ValueSome value x :> TrieReference<_,_> | h :: t -> let children = if isNull x.ChildrenDict then let d = OrderedDict.ofComparer (x.GetComparer (x.Level + 1)) x.ChildrenDict <- d d else x.ChildrenDict let node = children.GetOrCreate(h, fun k l r -> let n = OrderMaintenanceTrieNode<'k, 'a>(x.GetComparer, x.Level + 1, k :: x.Path) n.Prev <- l n.Next <- r n.Parent <- x n ) node.Add(t, value) member x.AddOrUpdate(k : list<'k>, create : voption<'a> -> 'a) = match k with | [] -> x.Value <- ValueSome (create x.Value) x :> TrieReference<_,_> | h :: t -> let children = if isNull x.ChildrenDict then let d = OrderedDict.ofComparer (x.GetComparer (x.Level + 1)) x.ChildrenDict <- d d else x.ChildrenDict let node = children.GetOrCreate(h, fun k l r -> let n = OrderMaintenanceTrieNode<'k, 'a>(x.GetComparer, x.Level + 1, k :: x.Path) n.Prev <- l n.Next <- r n.Parent <- x n ) node.AddOrUpdate(t, create) member x.Alter(k : list<'k>, update : voption<'a> -> voption<'a>) = match k with | [] -> x.Value <- update x.Value match x.Value with | ValueSome _ -> ValueSome (x :> TrieReference<_,_>) | _ -> ValueNone | h :: t -> if isNull x.ChildrenDict then match update ValueNone with | ValueNone -> ValueNone | ValueSome v -> x.Add(h :: t, v) |> ValueSome else match x.ChildrenDict.TryGet h with | ValueSome c -> let res = c.Alter(t, update) match res with | ValueNone -> if c.IsEmpty then x.ChildrenDict.TryRemove h |> ignore | _ -> () res | ValueNone -> match update ValueNone with | ValueNone -> ValueNone | ValueSome v -> x.Add(h :: t, v) |> ValueSome member x.Iter (action : list<'k> -> 'a -> unit) = match x.Value with | ValueSome v -> action (List.rev x.Path) v | ValueNone -> () if not (isNull x.ChildrenDict) then let mutable c = x.ChildrenDict.First while not (isNull c) do c.Iter action c <- c.Next member x.TryGetValue (key : list<'k>) = match key with | [] -> x.Value | h :: t -> if isNull x.ChildrenDict then ValueNone else match x.ChildrenDict.TryGet(h) with | ValueSome c -> c.TryGetValue t | ValueNone -> ValueNone member x.TryGetReference(key : list<'k>) = match key with | [] -> match x.Value with | ValueSome _ -> ValueSome (x :> TrieReference<_,_>) | ValueNone -> ValueNone | h :: t -> if isNull x.ChildrenDict then ValueNone else match x.ChildrenDict.TryGet(h) with | ValueSome c -> c.TryGetReference t | ValueNone -> ValueNone member x.ContainsKey (key : list<'k>) = match key with | [] -> ValueOption.isSome x.Value | h :: t -> if isNull x.ChildrenDict then false else match x.ChildrenDict.TryGet(h) with | ValueSome c -> c.ContainsKey t | ValueNone -> false new(getComparer : int -> option>, l : int, ks : list<'k>) = { GetComparer = getComparer; Level = l Path = ks ChildrenDict = null //OrderedDict.ofComparer (getComparer (l + 1)) Value = ValueNone Parent = null Prev = null; Next = null } type TrieReferenceForwardEnumerator<'k, 'v>(initial : unit -> voption>) = let mutable initial = initial let mutable started = false let mutable current : TrieReference<'k, 'v> = null member x.MoveNext() = if not started then started <- true match initial() with | ValueSome initial -> current <- initial true | ValueNone -> false elif not (isNull current) then match current.Next with | ValueSome n -> current <- n true | ValueNone -> current <- null false else false member x.Reset() = started <- false current <- null member x.Dispose() = started <- false current <- null initial <- fun _ -> ValueNone member x.Current = current.Key, current.Value interface System.Collections.IEnumerator with member x.MoveNext() = x.MoveNext() member x.Reset() = x.Reset() member x.Current = x.Current :> obj interface IEnumerator * 'v> with member x.Dispose() = x.Dispose() member x.Current = x.Current open OrderMaintenanceTrieImplementation type OrderMaintenanceTrie<'k, 'a>(getComparer : int -> option>) = let comparerCache = IntDict>>() let getCachedComparer level = comparerCache.GetOrCreate(level, System.Func<_,_>(getComparer)) let mutable root = OrderMaintenanceTrieNode<'k, 'a>(getCachedComparer, -1, []) member x.IsEmpty = root.IsEmpty member x.Set (key : list<'k>, value : 'a) = root.Add(key, value) member x.Iter (action : list<'k> -> 'a -> unit) = root.Iter(action) member x.TryRemove(key : list<'k>) = root.TryRemove key member x.AddOrUpdate(key : list<'k>, create : voption<'a> -> 'a) = root.AddOrUpdate(key, create) member x.Alter(key : list<'k>, update : voption<'a> -> voption<'a>) = root.Alter(key, update) member x.TryGetValue (key : list<'k>) = root.TryGetValue key member x.TryGetReference(key : list<'k>) = root.TryGetReference key member x.ContainsKey (key : list<'k>) = root.ContainsKey key member x.Clear() = root <- OrderMaintenanceTrieNode<'k, 'a>(getCachedComparer, 0, []) member x.Root = root member x.First = root.First member x.Last = root.Last interface System.Collections.IEnumerable with member x.GetEnumerator() = new TrieReferenceForwardEnumerator<_,_>(fun () -> x.First) :> _ interface IEnumerable * 'a> with member x.GetEnumerator() = new TrieReferenceForwardEnumerator<_,_>(fun () -> x.First) :> _ new() = OrderMaintenanceTrie(fun _ -> None) new(cmp : IComparer<'k>) = let res = Some cmp OrderMaintenanceTrie(fun _ -> res) ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Mutable/ReferenceCountingSet.fs ================================================ namespace Aardvark.Base open System.Collections open System.Collections.Generic open System.Threading open FSharp.Data.Adaptive /// /// represents a set of elements having a reference count. /// this means that an element is contained when it has been /// added at least once more than removed. /// type ReferenceCountingSet<'a>(initial : seq<'a>) = let mutable nullCount = 0 let mutable version = 0 let mutable store = Dictionary)>(1) let hasChanged() = Interlocked.Increment &version |> ignore let toCollection (s : seq<'a>) = match s with | :? ICollection<'a> as s -> s | _ -> System.Collections.Generic.HashSet s :> ICollection<_> let compareSeq (other : seq<'a>) = let distinctOther = toCollection other let mutable both = 0 let mutable onlyMe = 0 for (o,_) in store.Values do if distinctOther.Contains o then both <- both + 1 else onlyMe <- onlyMe + 1 let onlyOther = distinctOther.Count - both (both, onlyMe, onlyOther) let add (v : 'a) = if isNull (v :> obj) then nullCount <- nullCount + 1 nullCount = 1 else match store.TryGetValue v with | (true, (_,r)) -> r := !r + 1 false | _ -> let r = struct(v, ref 1) store.[v] <- r hasChanged() true let remove (v : 'a) = if isNull (v :> obj) then nullCount <- nullCount - 1 nullCount = 0 else match store.TryGetValue v with | (true, (_,r)) -> r := !r - 1 if !r = 0 then hasChanged() store.Remove v else false | _ -> false do for e in initial do add e |> ignore member private x.Version = version member private x.Store = store member private x.NullCount = nullCount member internal x.SetTo(other : ReferenceCountingSet<'a>) = nullCount <- other.NullCount version <- other.Version store <- Dictionary(other.Store.Count) for (KeyValue(k,(v,r))) in other.Store do store.[k] <- (v, ref !r) member internal x.Apply(deltas : list>) = match deltas with | [] -> [] | [v] -> match v with | Add(_,v) -> if x.Add v then [Add v] else [] | Rem(_,v) -> if x.Remove v then [Rem v] else [] | _ -> let mutable originalNullRefs = nullCount let touched = Dictionary>() for d in deltas do match d with | Add(_,v) -> let o = v :> obj if isNull o then nullCount <- nullCount + 1 else match store.TryGetValue o with | (true, (_,r)) -> r := !r + 1 | _ -> let r = ref 1 touched.[o] <- (v, false, r) store.[o] <- (v, r) | Rem(_, v) -> let o = v :> obj if isNull o then nullCount <- nullCount - 1 else match store.TryGetValue o with | (true, (_,r)) -> r := !r - 1 if !r = 0 && not (touched.ContainsKey o) then touched.[o] <- (v, true, r) | _ -> let r = ref -1 touched.[o] <- (v, false, r) store.[o] <- (v, r) () let valueDeltas = touched.Values |> Seq.choose (fun (value, wasContained, refCount) -> let r = !refCount if r > 0 then if wasContained then None else Some (Add value) else store.Remove value |> ignore if wasContained then Some (Rem value) else None ) |> Seq.toList let result = if nullCount = 0 && originalNullRefs > 0 then (Rem Unchecked.defaultof<_>)::valueDeltas elif nullCount > 0 && originalNullRefs = 0 then (Add Unchecked.defaultof<_>)::valueDeltas else valueDeltas if not (List.isEmpty result) then hasChanged() result /// /// adds an element to the ReferenceCountingSet and returns /// true if the element was not contained in the set before /// this operation. /// member x.Add (v : 'a) = add v /// /// removes an element from the ReferenceCountingSet and returns /// true if the element is no longer contained after the operation. /// member x.Remove(v : 'a) = remove v /// /// checks if the set contains a specific element /// member x.Contains (v : 'a) = if isNull (v :> obj) then nullCount > 0 else store.ContainsKey v /// /// clears the entire set /// member x.Clear() = if x.Count <> 0 then nullCount <- 0 store.Clear() hasChanged() /// /// returns the number of (distinct) elements contained in /// the set. /// member x.Count = (if nullCount > 0 then 1 else 0) + store.Count /// /// gets the current reference count for the given element /// member x.GetReferenceCount(v) = if isNull (v :> obj) then nullCount else match store.TryGetValue (v :> obj) with | (true, (_,c)) -> !c | _ -> 0 /// /// Remove items in other from this set. Modifies this set. /// member x.ExceptWith (items : seq<'a>) = for o in items do x.Remove o |> ignore /// /// Take the union of this set with other. Modifies this set. /// member x.UnionWith (other : seq<'a>) = for o in other do x.Add o |> ignore /// /// Takes the intersection of this set with other. Modifies this set. /// member x.IntersectWith (other : seq<'a>) = let other = toCollection other for (v,_) in store.Values do if not <| other.Contains v then x.Remove v |> ignore /// /// Takes symmetric difference (XOR) with other and this set. Modifies this set. /// member x.SymmetricExceptWith (other : seq<'a>) = for o in other do if not <| x.Remove o then x.Add o |> ignore /// /// determines if the set is a subset of the given sequence /// member x.IsSubsetOf (other : seq<'a>) = match compareSeq other with | (_, 0, _) -> true | _ -> false /// /// determines if the set is a superset of the given sequence /// member x.IsSupersetOf (other : seq<'a>) = match compareSeq other with | (_, _, 0) -> true | _ -> false /// /// determines if the set is a proper subset of the given sequence /// member x.IsProperSubsetOf (other : seq<'a>) = match compareSeq other with | (_, 0, o) -> o > 0 | _ -> false /// /// determines if the set is a proper superset of the given sequence /// member x.IsProperSupersetOf (other : seq<'a>) = match compareSeq other with | (_, m, 0) -> m > 0 | _ -> false /// /// determines if the set and the given sequence overlap /// member x.Overlaps (other : seq<'a>) = let (b,_,_) = compareSeq other b > 0 /// /// determines if the set is equal (set) to the given sequence /// member x.SetEquals (other : seq<'a>) = match compareSeq other with | (_,0,0) -> true | _ -> false new() = ReferenceCountingSet Seq.empty interface ICollection<'a> with member x.Add v = x.Add v |> ignore member x.Remove v = x.Remove v member x.Clear() = x.Clear() member x.Count = x.Count member x.CopyTo(arr, index) = let mutable i = index if nullCount > 0 then arr.[i] <- Unchecked.defaultof<_> i <- i + 1 for e in x do arr.[i] <- e i <- i + 1 member x.IsReadOnly = false member x.Contains v = store.ContainsKey v interface ISet<'a> with member x.Add item = x.Add item member x.ExceptWith other = x.ExceptWith other member x.IntersectWith other = x.IntersectWith other member x.UnionWith other = x.UnionWith other member x.SymmetricExceptWith other = x.SymmetricExceptWith other member x.IsProperSubsetOf other = x.IsProperSubsetOf other member x.IsProperSupersetOf other = x.IsProperSupersetOf other member x.IsSubsetOf other = x.IsSubsetOf other member x.IsSupersetOf other = x.IsSupersetOf other member x.Overlaps other = x.Overlaps other member x.SetEquals other = x.SetEquals other member x.GetEnumerator() = new ReferenceCountingSetEnumerator<'a>(nullCount > 0, store) interface IEnumerable with member x.GetEnumerator() = new ReferenceCountingSetEnumerator<'a>(nullCount > 0, store) :> IEnumerator interface IEnumerable<'a> with member x.GetEnumerator() = new ReferenceCountingSetEnumerator<'a>(nullCount > 0, store) :> IEnumerator<'a> // define an Enumerator enumerating all (distinct) elements in the set and ReferenceCountingSetEnumerator<'a> = struct val mutable private containsNull : bool val mutable private emitNull : bool val mutable private currentIsNull : bool val mutable private e : Dictionary)>.Enumerator member x.Current = if x.currentIsNull then Unchecked.defaultof<_> else x.e.Current.Value |> fstv member x.MoveNext() = if x.emitNull then x.emitNull <- false x.currentIsNull <- true true else x.currentIsNull <- false x.e.MoveNext() interface IEnumerator with member x.MoveNext() = x.MoveNext() member x.Reset() = x.emitNull <- x.containsNull (x.e :> IEnumerator).Reset() member x.Current = x.Current :> obj interface IEnumerator<'a> with member x.Current = x.Current member x.Dispose() = x.e.Dispose() internal new(containsNull : bool, store : Dictionary)>) = { containsNull = containsNull emitNull = containsNull currentIsNull = false e = store.GetEnumerator() } end ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Mutable/SkipList.fs ================================================ namespace Aardvark.Base open System open System.Collections open System.Collections.Generic [] type private Node<'a>(value : 'a, height : int) = let mutable height = height let mutable next : Link<'a>[] = Array.zeroCreate height member x.Height = height member x.Next = next member x.Value = value member x.Resize(h : int) = if h < height then failwith "cannot shrink node" else let newNext = Array.zeroCreate h for i in 0..height-1 do newNext.[i] <- next.[i] next <- newNext and private Link<'a> = struct val mutable public Target : Node<'a> val mutable public Width : int new(target, w) = { Target = target; Width = w } end type SkipList<'a>(cmp : 'a -> 'a -> int) = let mutable root : Link<'a>[] = Array.zeroCreate 0 let mutable count = 0 static let random = Random() static let resize (height : int) (root : byref[]>) = if height > root.Length then let newRoot = Array.zeroCreate height for i in 0..root.Length-1 do newRoot.[i] <- root.[i] root <- newRoot static let randomHeight() = let mutable height = 1 while random.NextDouble() < 0.5 do height <- height + 1 height static let newNode (v : 'a) = Node(v, randomHeight()) static let rec findPrev (acc : list<_>) (cmp : 'a -> 'a -> int) (index : int) (level : int) (v : 'a) (n : Node<'a>) (links : Link<'a>[]) = if level < 0 then (index, acc) else let link = links.[level] let vCmp = if isNull link.Target then -1 else cmp v link.Target.Value if vCmp <= 0 then findPrev ((index, n)::acc) cmp index (level - 1) v n links else let t = links.[level].Target findPrev acc cmp (index + link.Width) level v t t.Next static let rec findPrevIndex (acc : list<_>) (currentIndex : int) (level : int) (id : int) (n : Node<'a>) (links : Link<'a>[]) = if level < 0 then (currentIndex, acc) else let link = links.[level] let vCmp = if isNull link.Target then -1 else compare id (currentIndex + link.Width)//link.Target.Value if vCmp <= 0 then findPrevIndex ((currentIndex, n)::acc) currentIndex (level - 1) id n links else let t = links.[level].Target findPrevIndex acc (currentIndex + link.Width) level id t t.Next let print (l : SkipList<'a>) = let rec cnt (n : Node<'a>) = if isNull n then 1 else 1 + cnt n.Next.[0].Target let rec dist (l : Node<'a>) (r : Node<'a>) = if l = r then 0 else 1 + dist (l.Next.[0].Target) r let h = root.Length let w = cnt root.[0].Target let arr = Array2D.create (w + 2) (h + 2) " " for y in 0..h-1 do let mutable current = root.[y].Target let mutable x = root.[y].Width while not (isNull current) do arr.[x,y] <- sprintf "%A" current.Value let next = current.Next.[y].Target x <- x + dist current next current <- next for y in 1..h do for x in 0..w-1 do printf "%s " arr.[x,h - y] printfn "" let removePtr (prev : list>) (n : Node<'a>) = let mutable level = 0 for (id,p) in prev do let prevNext = if not (isNull p) then p.Next else root let leftLink = prevNext.[level] if level < n.Height then let rightLink = n.Next.[level] prevNext.[level] <- Link(rightLink.Target, leftLink.Width + rightLink.Width - 1) else prevNext.[level] <- Link(leftLink.Target, leftLink.Width - 1) level <- level + 1 count <- count - 1 let toSeq() = let rec toSeq (n : Node<'a>) = if isNull n then Seq.empty else seq { yield n.Value yield! toSeq n.Next.[0].Target } if root.Length > 0 then toSeq root.[0].Target else Seq.empty member x.Add (v : 'a) = if root.Length <> 0 then // create a new node with random height let n = newNode v // resize the root if necessary resize n.Height &root let height = root.Length let (index, prev) = findPrev [] cmp 0 (height - 1) v null root let (_,p) = prev |> List.head let on = if isNull p then root.[0].Target else p.Next.[0].Target if not (isNull on) && cmp on.Value v = 0 then false else let fi = index + 1 let mutable level = 0 for (id,p) in prev do let prevNext = if not (isNull p) then p.Next else root let l = prevNext.[level] if level < n.Height then let ti = id + l.Width let si = id //ti - si prevNext.[level] <- Link(n, fi - si) n.Next.[level] <- Link(l.Target, 1 + ti - fi) else prevNext.[level] <- Link(l.Target, l.Width + 1) level <- level + 1 count <- count + 1 true else // create a new node with random height let n = newNode v // resize the root if necessary resize n.Height &root for i in 0..n.Height-1 do root.[i] <- Link(n, 1) count <- count + 1 true member x.Remove (v : 'a) = if root.Length <> 0 then let height = root.Length let (index, prev) = findPrev [] cmp 0 (height - 1) v null root let (_,p) = prev |> List.head let n = if isNull p then root.[0].Target else p.Next.[0].Target if not (isNull n) && cmp n.Value v = 0 then removePtr prev n true else false else false member x.Clear() = count <- 0 root <- Array.zeroCreate 0 member x.RemoveAt (index : int) = if root.Length <> 0 then let height = root.Length let (_, prev) = findPrevIndex [] 0 (height - 1) (index + 1) null root let (_,p) = prev |> List.head let n = if isNull p then root.[0].Target else p.Next.[0].Target if not (isNull n) then removePtr prev n true else false else false member x.TryAt(index : int) = if root.Length = 0 then None else let height = root.Length let (_,ptr) = findPrevIndex [] 0 (height - 1) (index + 1) null root let (id,n) = ptr |> List.head let link = if isNull n then root.[0] else n.Next.[0] if not (isNull link.Target) && link.Width + id = index + 1 then Some link.Target.Value else None member x.Contains (v : 'a) (l : SkipList<'a>) = if root.Length <> 0 then let height = root.Length let (index, prev) = findPrev [] cmp 0 (height - 1) v null root let (_,p) = prev |> List.head let n = if isNull p then root.[0].Target else p.Next.[0].Target if not (isNull n) && cmp n.Value v = 0 then true else false else false member x.Item with get (index : int) = match x.TryAt index with | Some v -> v | None -> raise <| IndexOutOfRangeException() member x.Count = count interface IEnumerable with member x.GetEnumerator() = toSeq().GetEnumerator() :> IEnumerator interface IEnumerable<'a> with member x.GetEnumerator() = toSeq().GetEnumerator() [] module SkipList = let empty<'a when 'a : comparison> : SkipList<'a> = SkipList<'a>(compare) let custom (cmp : 'a -> 'a -> int) = SkipList<'a>(cmp) let count (s : SkipList<'a>) = s.Count let add (v : 'a) (l : SkipList<'a>) = l.Add v let remove (v : 'a) (l : SkipList<'a>) = l.Remove v let removeAt (index : int) (l : SkipList<'a>) = l.RemoveAt index let clear (l : SkipList<'a>) = l.Clear() let at (index : int) (l : SkipList<'a>) = l.TryAt index let contains (v : 'a) (l : SkipList<'a>) = l.Contains v let ofSeq (s : seq<'a>) = let l = empty for e in s do add e l |> ignore l let ofList (l : list<'a>) = ofSeq l let ofArray (a : 'a[]) = ofSeq a let toSeq (s : SkipList<'a>) = s :> seq<_> let toList (s : SkipList<'a>) = s |> Seq.toList let toArray (s : SkipList<'a>) = s |> Seq.toArray ================================================ FILE: src/Aardvark.Base.FSharp/Datastructures/Mutable/StableSet.fs ================================================ namespace Aardvark.Base open System.Collections open System.Collections.Generic open System.Runtime.InteropServices open System.Runtime.CompilerServices [] type private Linked<'a> = class val mutable public Value : 'a val mutable public Prev : Linked<'a> val mutable public Next : Linked<'a> new (v, p, n) = { Value = v; Prev = p; Next = n } new (v) = { Value = v; Prev = null; Next = null } end type private LinkedEnumerator<'a>(l : Linked<'a>) = let mutable current = null interface IEnumerator with member x.MoveNext() = if isNull current then current <- l else current <- current.Next not (isNull current) member x.Current = current.Value :> obj member x.Reset() = current <- null interface IEnumerator<'a> with member x.Current = current.Value member x.Dispose() = current <- null [] type StableSet<'a>() = let content = Dict.empty<'a, Linked<'a>> let mutable first : Linked<'a> = null let mutable last : Linked<'a> = null member x.Count = content.Count member x.First = if isNull first then None else Some first.Value member x.Last = if isNull last then None else Some last.Value member x.Contains(v : 'a) = content.ContainsKey v member x.Clear() = content.Clear() first <- null last <- null member x.Add(v : 'a) = let n = Linked(v, last, null) if not (content.ContainsKey v) then content.[v] <- n if isNull last then first <- n else last.Next <- n last <- n true else false member x.Remove(v : 'a) = match content.TryRemove v with | (true, n) -> if isNull n.Prev then first <- n.Next else n.Prev.Next <- n.Next if isNull n.Next then last <- n.Prev else n.Next.Prev <- n.Prev n.Prev <- null n.Next <- null true | _ -> false member x.UnionWith (s : seq<'a>) = s |> Seq.iter (x.Add >> ignore) member x.ExeptWith (s : seq<'a>) = s |> Seq.iter (x.Remove >> ignore) member x.TryGetPrev(v : 'a) = match content.TryGetValue v with | (true, n) -> if isNull n.Prev then None else Some n.Prev.Value | _ -> None member x.TryGetNext(v : 'a) = match content.TryGetValue v with | (true, n) -> if isNull n.Next then None else Some n.Next.Value | _ -> None member x.AddWithPrev (f : Option<'a> -> 'a) = let left = if isNull last then None else Some last.Value let v = f left if x.Add v then Some v else None interface IEnumerable with member x.GetEnumerator() = new LinkedEnumerator<'a>(first) :> IEnumerator interface IEnumerable<'a> with member x.GetEnumerator() = new LinkedEnumerator<'a>(first) :> IEnumerator<'a> [] type StableDict<'k, 'v>() = let content = Dict.empty<'k, Linked<'k * 'v>> let mutable first : Linked<'k * 'v> = null let mutable last : Linked<'k * 'v> = null member x.Count = content.Count member x.First = if isNull first then None else Some first.Value member x.Last = if isNull last then None else Some last.Value member x.ContainsKey(v : 'k) = content.ContainsKey v member x.TryGetValue(k : 'k, [] value : byref<'v>) = match content.TryGetValue k with | (true, l) -> value <- snd l.Value true | _ -> false member x.TryAdd(k : 'k, value : 'v) = let n = Linked((k,value), last, null) if content.TryAdd(k, n) then if isNull last then first <- n else last.Next <- n last <- n true else false member x.TryRemove(k : 'k, [] value : byref<'v>) = match content.TryRemove k with | (true, n) -> if isNull n.Prev then first <- n.Next else n.Prev.Next <- n.Next if isNull n.Next then last <- n.Prev else n.Next.Prev <- n.Prev value <- snd n.Value true | _ -> false member x.GetOrAdd(k : 'k, f : 'k -> 'v) = let isNew = ref false let node = content.GetOrCreate(k, fun k -> isNew := true Linked((k, f k), last, null) ) if !isNew then if isNull last then first <- node else last.Next <- node last <- node node.Value |> snd member x.Remove(k : 'k) = match content.TryRemove k with | (true, n) -> if isNull n.Prev then first <- n.Next else n.Prev.Next <- n.Next if isNull n.Next then last <- n.Prev else n.Next.Prev <- n.Prev true | _ -> false member x.TryGetPrev(v : 'k) = match content.TryGetValue v with | (true, n) -> if isNull n.Prev then None else Some n.Prev.Value | _ -> None member x.TryGetNext(v : 'k) = match content.TryGetValue v with | (true, n) -> if isNull n.Next then None else Some n.Next.Value | _ -> None interface IEnumerable with member x.GetEnumerator() = new LinkedEnumerator<'k * 'v>(first) :> IEnumerator interface IEnumerable<'k * 'v> with member x.GetEnumerator() = new LinkedEnumerator<'k * 'v>(first) :> IEnumerator<'k * 'v> ================================================ FILE: src/Aardvark.Base.FSharp/Math/AverageWindow.fs ================================================ namespace Aardvark.Base /// Represents a moving average window of a sequence. /// It builds the average of the last N inserted values. type AverageWindow(maxCount : int) = let values = Array.zeroCreate maxCount let mutable index = 0 let mutable count = 0 let mutable sum = 0.0 /// Insert a new value to the sequence and returns the average of the last N values. member x.Insert(v : float) = let newSum = if count < maxCount then count <- count + 1 sum + v else sum + v - values.[index] sum <- newSum values.[index] <- v index <- (index + 1) % maxCount x.Value /// The number of currently inserted values. member x.Count = count /// Returns the average of the last N inserted values. member x.Value = if count = 0 then 0.0 else sum / float count /// Resets the average window. member x.Reset() = index <- 0 count <- 0 sum <- 0.0 ================================================ FILE: src/Aardvark.Base.FSharp/Math/Converters.fs ================================================ namespace Aardvark.Base #nowarn "77" // Statically resolved, generic converters [] module Converters = module Identity = type Converter() = static member inline op_Explicit (x : ^a) : ^a = x let inline private conv< ^z, ^a, ^b when (^z or ^a or ^b) : (static member op_Explicit : ^a -> ^b) > (a : ^a) : ^b = ((^z or ^a or ^b) : (static member op_Explicit : ^a -> ^b) (a)) [] module Vector = let inline v2d (v : ^a) = conv< Identity.Converter, ^a, V2d > v let inline v2f (v : ^a) = conv< Identity.Converter, ^a, V2f > v let inline v2i (v : ^a) = conv< Identity.Converter, ^a, V2i > v let inline v2ui (v : ^a) = conv< Identity.Converter, ^a, V2ui > v let inline v2l (v : ^a) = conv< Identity.Converter, ^a, V2l > v let inline v3d (v : ^a) = conv< Identity.Converter, ^a, V3d > v let inline v3f (v : ^a) = conv< Identity.Converter, ^a, V3f > v let inline v3i (v : ^a) = conv< Identity.Converter, ^a, V3i > v let inline v3ui (v : ^a) = conv< Identity.Converter, ^a, V3ui > v let inline v3l (v : ^a) = conv< Identity.Converter, ^a, V3l > v let inline v4d (v : ^a) = conv< Identity.Converter, ^a, V4d > v let inline v4f (v : ^a) = conv< Identity.Converter, ^a, V4f > v let inline v4i (v : ^a) = conv< Identity.Converter, ^a, V4i > v let inline v4ui (v : ^a) = conv< Identity.Converter, ^a, V4ui > v let inline v4l (v : ^a) = conv< Identity.Converter, ^a, V4l > v module private CompilerTests = let working() = let a : V3d = v3d V2i.IO let a : V3d = v3d V3f.IOI let a : V3d = v3d V3d.IOI let a : V3d = v3d V4l.IOII let a : V3d = v3d [| 0l; 1l; 2l |] let a : V3d = v3d C3ui.BlueViolet let a : V4d = v4d C3ui.BlueViolet let a : V3d = v3d C4f.BlueViolet let a : V3ui = v3ui C4b.White () [] module Color = let inline c3b (v : ^a) = conv< Identity.Converter, ^a, C3b > v let inline c3us (v : ^a) = conv< Identity.Converter, ^a, C3us > v let inline c3ui (v : ^a) = conv< Identity.Converter, ^a, C3ui > v let inline c3f (v : ^a) = conv< Identity.Converter, ^a, C3f > v let inline c3d (v : ^a) = conv< Identity.Converter, ^a, C3d > v let inline c4b (v : ^a) = conv< Identity.Converter, ^a, C4b > v let inline c4us (v : ^a) = conv< Identity.Converter, ^a, C4us > v let inline c4ui (v : ^a) = conv< Identity.Converter, ^a, C4ui > v let inline c4f (v : ^a) = conv< Identity.Converter, ^a, C4f > v let inline c4d (v : ^a) = conv< Identity.Converter, ^a, C4d > v let working() = let a : C3d = c3d V3f.IOI let a : C3d = c3d V4d.IOII let a : C3ui = c3ui [| 0us; 1us; 2us |] let a : C3d = c3d C3ui.BlueViolet let a : C4d = c4d C3ui.BlueViolet () [] module Matrix = let inline m22d (v : ^a) = conv< Identity.Converter, ^a, M22d > v let inline m23d (v : ^a) = conv< Identity.Converter, ^a, M23d > v let inline m33d (v : ^a) = conv< Identity.Converter, ^a, M33d > v let inline m34d (v : ^a) = conv< Identity.Converter, ^a, M34d > v let inline m44d (v : ^a) = conv< Identity.Converter, ^a, M44d > v let inline m22f (v : ^a) = conv< Identity.Converter, ^a, M22f > v let inline m23f (v : ^a) = conv< Identity.Converter, ^a, M23f > v let inline m33f (v : ^a) = conv< Identity.Converter, ^a, M33f > v let inline m34f (v : ^a) = conv< Identity.Converter, ^a, M34f > v let inline m44f (v : ^a) = conv< Identity.Converter, ^a, M44f > v let inline m22i (v : ^a) = conv< Identity.Converter, ^a, M22i > v let inline m23i (v : ^a) = conv< Identity.Converter, ^a, M23i > v let inline m33i (v : ^a) = conv< Identity.Converter, ^a, M33i > v let inline m34i (v : ^a) = conv< Identity.Converter, ^a, M34i > v let inline m44i (v : ^a) = conv< Identity.Converter, ^a, M44i > v let inline m22l (v : ^a) = conv< Identity.Converter, ^a, M22l > v let inline m23l (v : ^a) = conv< Identity.Converter, ^a, M23l > v let inline m33l (v : ^a) = conv< Identity.Converter, ^a, M33l > v let inline m34l (v : ^a) = conv< Identity.Converter, ^a, M34l > v let inline m44l (v : ^a) = conv< Identity.Converter, ^a, M44l > v module private CompilerTests = let working() = let a : M33d = m33d M23i.Zero let a : M33d = m33d M33f.Zero let a : M33d = m33d M33d.Zero let a : M33d = m33d M34l.Zero let a : M22d = m22d [| 0l; 1l; 2l; 3l |] let a : M22d = m22d <| Array2D.create 2 2 2.0f () ================================================ FILE: src/Aardvark.Base.FSharp/Math/Math.fs ================================================ namespace Aardvark.Base open System /// Provides generic math functions that work for both scalars and vectors (element-wise). /// Functions already provided by the F# core library are only redefined if necessary /// (e.g. different signature) [] module FSharpMath = module Helpers = // Some of these SRTP member methods have odd names to avoid clashes with // methods added in .NET 7 (e.g. Double.Log2). If we use those standard names in our helper types we // get build errors due to ambiguities when targeting .NET 7+. [] type Log2() = static member inline LogBinary(x: int8) : float = Fun.Log2 x static member inline LogBinary(x: int16) : float = Fun.Log2 x static member inline LogBinary(x: int32) : float = Fun.Log2 x static member inline LogBinary(x: int64) : float = Fun.Log2 x static member inline LogBinary(x: uint8) : float = Fun.Log2 x static member inline LogBinary(x: uint16) : float = Fun.Log2 x static member inline LogBinary(x: uint32) : float = Fun.Log2 x static member inline LogBinary(x: uint64) : float = Fun.Log2 x static member inline LogBinary(x: float) : float = Fun.Log2 x static member inline LogBinary(x: float32) : float32 = Fun.Log2 x [] type Acosh() = static member inline Acoshb(x: float) : float = Fun.Acosh x static member inline Acoshb(x: float32) : float32 = Fun.Acosh x [] type Asinh() = static member inline Asinhb(x: float) : float = Fun.Asinh x static member inline Asinhb(x: float32) : float32 = Fun.Asinh x [] type Atanh() = static member inline Atanhb(x: float) : float = Fun.Atanh x static member inline Atanhb(x: float32) : float32 = Fun.Atanh x [] type Cbrt() = static member inline CubeRoot(x: int8) : float = Fun.Cbrt x static member inline CubeRoot(x: int16) : float = Fun.Cbrt x static member inline CubeRoot(x: int32) : float = Fun.Cbrt x static member inline CubeRoot(x: int64) : float = Fun.Cbrt x static member inline CubeRoot(x: uint8) : float = Fun.Cbrt x static member inline CubeRoot(x: uint16) : float = Fun.Cbrt x static member inline CubeRoot(x: uint32) : float = Fun.Cbrt x static member inline CubeRoot(x: uint64) : float = Fun.Cbrt x static member inline CubeRoot(x: float) : float = Fun.Cbrt x static member inline CubeRoot(x: float32) : float32 = Fun.Cbrt x [] type Lerp() = static member inline LinearInterp(t: float, a: int8, b: int8) : int8 = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float32, a: int8, b: int8) : int8 = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float, a: uint8, b: uint8) : uint8 = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float32, a: uint8, b: uint8) : uint8 = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float, a: int16, b: int16) : int16 = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float32, a: int16, b: int16) : int16 = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float, a: uint16, b: uint16) : uint16 = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float32, a: uint16, b: uint16) : uint16 = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float, a: int32, b: int32) : int32 = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float32, a: int32, b: int32) : int32 = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float, a: uint32, b: uint32) : uint32 = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float32, a: uint32, b: uint32) : uint32 = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float, a: int64, b: int64) : int64 = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float32, a: int64, b: int64) : int64 = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float, a: uint64, b: uint64) : uint64 = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float32, a: uint64, b: uint64) : uint64 = Fun.Lerp(t, a, b) static member inline LinearInterp(t: decimal, a: decimal, b: decimal) : decimal = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float, a: float, b: float) : float = Fun.Lerp(t, a, b) static member inline LinearInterp(t: float32, a: float32, b: float32) : float32 = Fun.Lerp(t, a, b) [] type CopySign() = static member inline CopySgn(value: float, sign: float) : float = Fun.CopySign(value, sign) static member inline CopySgn(value: float32, sign: float32) : float32 = Fun.CopySign(value, sign) [] type Comparison() = static member inline Min< ^T when ^T : comparison>(a : ^T, b : ^T) = Operators.min a b static member inline Min(a : float, b : V2d) = V2d.Min(b, a) static member inline Min(a : float, b : V3d) = V3d.Min(b, a) static member inline Min(a : float, b : V4d) = V4d.Min(b, a) static member inline Min(a : float32, b : V2f) = V2f.Min(b, a) static member inline Min(a : float32, b : V3f) = V3f.Min(b, a) static member inline Min(a : float32, b : V4f) = V4f.Min(b, a) static member inline Min(a : int, b : V2i) = V2i.Min(b, a) static member inline Min(a : int, b : V3i) = V3i.Min(b, a) static member inline Min(a : int, b : V4i) = V4i.Min(b, a) static member inline Min(a : uint, b : V2ui) = V2ui.Min(b, a) static member inline Min(a : uint, b : V3ui) = V3ui.Min(b, a) static member inline Min(a : uint, b : V4ui) = V4ui.Min(b, a) static member inline Min(a : int64, b : V2l) = V2l.Min(b, a) static member inline Min(a : int64, b : V3l) = V3l.Min(b, a) static member inline Min(a : int64, b : V4l) = V4l.Min(b, a) static member inline Max< ^T when ^T : comparison>(a : ^T, b : ^T) = Operators.max a b static member inline Max(a : float, b : V2d) = V2d.Max(b, a) static member inline Max(a : float, b : V3d) = V3d.Max(b, a) static member inline Max(a : float, b : V4d) = V4d.Max(b, a) static member inline Max(a : float32, b : V2f) = V2f.Max(b, a) static member inline Max(a : float32, b : V3f) = V3f.Max(b, a) static member inline Max(a : float32, b : V4f) = V4f.Max(b, a) static member inline Max(a : int, b : V2i) = V2i.Max(b, a) static member inline Max(a : int, b : V3i) = V3i.Max(b, a) static member inline Max(a : int, b : V4i) = V4i.Max(b, a) static member inline Max(a : uint, b : V2ui) = V2ui.Max(b, a) static member inline Max(a : uint, b : V3ui) = V3ui.Max(b, a) static member inline Max(a : uint, b : V4ui) = V4ui.Max(b, a) static member inline Max(a : int64, b : V2l) = V2l.Max(b, a) static member inline Max(a : int64, b : V3l) = V3l.Max(b, a) static member inline Max(a : int64, b : V4l) = V4l.Max(b, a) [] type Saturate() = static member inline Saturate(x : sbyte) = x |> max 0y |> min 1y static member inline Saturate(x : int16) = x |> max 0s |> min 1s static member inline Saturate(x : int32) = x |> max 0 |> min 1 static member inline Saturate(x : int64) = x |> max 0L |> min 1L static member inline Saturate(x : byte) = x |> max 0uy |> min 1uy static member inline Saturate(x : uint16) = x |> max 0us |> min 1us static member inline Saturate(x : uint32) = x |> max 0u |> min 1u static member inline Saturate(x : uint64) = x |> max 0UL |> min 1UL static member inline Saturate(x : nativeint) = x |> max 0n |> min 1n static member inline Saturate(x : float) = x |> max 0.0 |> min 1.0 static member inline Saturate(x : float16) = x |> max float16.Zero |> min float16.One static member inline Saturate(x : float32) = x |> max 0.0f |> min 1.0f static member inline Saturate(x : decimal) = x |> max 0m |> min 1m [] type Infinity() = static member inline IsNaN< ^T when ^T : (member IsNaN : bool)> (x : ^T) : bool = (^T : (member IsNaN : bool) x) static member inline IsInfinity< ^T when ^T : (member IsInfinity : bool)> (x : ^T) : bool = (^T : (member IsInfinity : bool) x) static member inline IsPositiveInfinity< ^T when ^T : (member IsPositiveInfinity : bool)> (x : ^T) : bool = (^T : (member IsPositiveInfinity : bool) x) static member inline IsNegativeInfinity< ^T when ^T : (member IsNegativeInfinity : bool)> (x : ^T) : bool = (^T : (member IsNegativeInfinity : bool) x) [] type InfinityS() = static member inline IsNaN< ^T when ^T : (static member IsNaN : ^T -> bool)> (x : ^T) : bool = (^T : (static member IsNaN : ^T -> bool) x) static member inline IsInfinity< ^T when ^T : (static member IsInfinity : ^T -> bool)> (x : ^T) : bool = (^T : (static member IsInfinity : ^T -> bool) x) static member inline IsPositiveInfinity< ^T when ^T : (static member IsPositiveInfinity : ^T -> bool)> (x : ^T) : bool = (^T : (static member IsPositiveInfinity : ^T -> bool) x) static member inline IsNegativeInfinity< ^T when ^T : (static member IsNegativeInfinity : ^T -> bool)> (x : ^T) : bool = (^T : (static member IsNegativeInfinity : ^T -> bool) x) [] module private Aux = let inline signumAux (_ : ^Z) (x : ^T) = ((^Z or ^T) : (static member Signum : ^T -> ^T) x) let inline signumiAux (_ : ^Z) (x : ^T) = ((^Z or ^T) : (static member Signumi : ^T -> ^U) x) // Making the power functions more general with ^T -> ^U -> ^V // generally works but requires manual type annotations in some cases // It's not worth the hassle so we restrict them to ^T -> ^U -> ^T // Also using the default pow / Pow() doesn't work with code quotations // for some reason. let inline powAux (_ : ^Z) (x : ^T) (y : ^U) = ((^Z or ^T or ^U) : (static member Power : ^T * ^U -> ^T) (x, y)) let inline pownAux (_ : ^Z) (x : ^T) (y : ^U) = ((^Z or ^T or ^U) : (static member Pown : ^T * ^U -> ^T) (x, y)) let inline exp2Aux (_ : ^Z) (x : ^T) = ((^Z or ^T) : (static member PowerOfTwo : ^T -> ^T) (x)) let inline log2Aux (_ : ^Z) (x : ^T) = ((^Z or ^T) : (static member LogBinary : ^T -> ^T) x) let inline log2intAux (_ : ^Z) (x : ^T) = ((^Z or ^T) : (static member Log2Int : ^T -> ^U) x) let inline asinhAux (_ : ^Z) (x : ^T) = ((^Z or ^T) : (static member Asinhb : ^T -> ^T) x) let inline acoshAux (_ : ^Z) (x : ^T) = ((^Z or ^T) : (static member Acoshb : ^T -> ^T) x) let inline atanhAux (_ : ^Z) (x : ^T) = ((^Z or ^T) : (static member Atanhb : ^T -> ^T) x) let inline cbrtAux (_ : ^Z) (x : ^T) = ((^Z or ^T) : (static member CubeRoot : ^T -> ^T) x) // See comment for powAux let inline minAux (_ : ^Z) (x : ^T) (y : ^U) = ((^Z or ^T or ^U) : (static member Min : ^T * ^U -> ^U) (x, y)) let inline maxAux (_ : ^Z) (x : ^T) (y : ^U) = ((^Z or ^T or ^U) : (static member Max : ^T * ^U -> ^U) (x, y)) // Simply using min and max directly will resolve to the comparison overload for some reason. // Therefore we need to do it the dumb (incomplete) way. E.g. won't work for Version. let inline saturateAux (_ : ^Z) (x : ^T) = ((^Z or ^T) : (static member Saturate : ^T -> ^T) (x)) let inline lerpAux (_ : ^Z) (x : ^T) (y : ^T) (t : ^U) = ((^Z or ^T or ^U) : (static member LinearInterp : ^U * ^T * ^T -> ^T) (t, x, y)) let inline invLerpAux (_ : ^Z) (a : ^T) (b : ^T) (y : ^T) = ((^Z or ^T or ^U) : (static member InvLerp : ^T * ^T * ^T -> ^U) (y, a, b)) let inline stepAux (_ : ^Z) (edge : ^T) (x : ^U) = ((^Z or ^T or ^U) : (static member Step : ^U * ^T -> ^U) (x, edge)) let inline linearstepAux (_ : ^Z) (edge0 : ^T) (edge1 : ^T) (x : ^U) = ((^Z or ^T or ^U) : (static member Linearstep : ^U * ^T * ^T -> ^U) (x, edge0, edge1)) let inline smoothstepAux (_ : ^Z) (edge0 : ^T) (edge1 : ^T) (x : ^U) = ((^Z or ^T or ^U) : (static member Smoothstep : ^U * ^T * ^T -> ^U) (x, edge0, edge1)) // See comment for powAux let inline copysignAux (_ : ^Z) (value : ^T) (sign : ^U) = ((^Z or ^T or ^U) : (static member CopySgn : ^T * ^U -> ^T) (value, sign)) let inline degreesAux (_ : ^Z) (radians : ^T) = ((^Z or ^T) : (static member DegreesFromRadians : ^T -> ^T) radians) let inline radiansAux (_ : ^Z) (degrees : ^T) = ((^Z or ^T) : (static member RadiansFromDegrees : ^T -> ^T) degrees) let inline maddAux (_ : ^Z) (x : ^T) (y : ^U) (z : ^T) = ((^Z or ^T or ^U) : (static member MultiplyAdd : ^T * ^U * ^T -> ^T) (x, y, z)) let inline isNanAux (_ : ^Z) (_ : ^Y) (x : ^T) = ((^Z or ^Y or ^T) : (static member IsNaN : ^T -> bool) x) let inline isInfAux (_ : ^Z) (_ : ^Y) (x : ^T) = ((^Z or ^Y or ^T) : (static member IsInfinity : ^T -> bool) x) let inline isPosInfAux (_ : ^Z) (_ : ^Y) (x : ^T) = ((^Z or ^Y or ^T) : (static member IsPositiveInfinity : ^T -> bool) x) let inline isNegInfAux (_ : ^Z) (_ : ^Y) (x : ^T) = ((^Z or ^Y or ^T) : (static member IsNegativeInfinity : ^T -> bool) x) let inline approximateEqualsAux (_: ^Z) (epsilon: ^U) (x: ^T) (y: ^T) = ((^Z or ^T) : (static member ApproximateEquals : ^T * ^T * ^U -> bool) (x, y, epsilon)) /// Resolves to the zero value for any scalar or vector type. [] let inline zero< ^T when ^T : (static member Zero : ^T) > : ^T = LanguagePrimitives.GenericZero /// Resolves to the one value for any scalar or vector type. [] let inline one< ^T when ^T : (static member One : ^T) > : ^T = LanguagePrimitives.GenericOne /// Returns -1 if x is less than zero, 0 if x is equal to zero, and 1 if /// x is greater than zero. The result has the same type as the input. let inline signum x = signumAux Unchecked.defaultof x /// Returns -1 if x is less than zero, 0 if x is equal to zero, and 1 if /// x is greater than zero. let inline signumi x = signumiAux Unchecked.defaultof x /// Returns x raised to the power of y (must be float or double). // F# variant does not support integers! let inline pow x y = powAux Unchecked.defaultof x y /// Returns x raised to the power of y. // F# variant does not support integers! let inline ( ** ) x y = pow x y /// Returns x raised to the integer power of y (must not be negative). // F# variant has signature a' -> int -> 'a, which does not permit for example V2f -> V2i -> V2f let inline pown x y = pownAux Unchecked.defaultof x y /// Returns 2 raised to the power of x (must be float, double, or uint64). let inline exp2 x = exp2Aux Unchecked.defaultof x /// Returns the base 2 logarithm of x. let inline log2 x = log2Aux Unchecked.defaultof x /// Returns the base 2 logarithm of x rounded to the next integer towards negative infinity. let inline log2int x = log2intAux Unchecked.defaultof x /// Returns the inverse hyperbolic sine of x. let inline asinh x = asinhAux Unchecked.defaultof x /// Returns the inverse hyperbolic cosine of x. let inline acosh x = acoshAux Unchecked.defaultof x /// Returns the inverse hyperbolic tangent of x. let inline atanh x = atanhAux Unchecked.defaultof x /// Returns x^2 let inline sqr x = x * x /// Returns the cubic root of x. let inline cbrt x = cbrtAux Unchecked.defaultof x /// Returns the smaller of x and y. let inline min x y = minAux Unchecked.defaultof x y /// Returns the larger of x and y. let inline max x y = maxAux Unchecked.defaultof x y /// Clamps x to the interval [a, b]. let inline clamp a b x = x |> max a |> min b /// Clamps x to the interval [0, 1]. let inline saturate (x : ^T) = saturateAux Unchecked.defaultof x /// Linearly interpolates between x and y. let inline lerp x y t = lerpAux Unchecked.defaultof x y t /// Inverse linear interpolation. Computes t of y = a * (1 - t) + b * t. let inline invLerp a b y = invLerpAux Unchecked.defaultof a b y /// Returns 0 if x < edge, and 1 otherwise. let inline step (edge : ^T) (x : ^U) = stepAux Unchecked.defaultof edge x /// Inverse linear interpolation. Clamped to [0, 1]. let inline linearstep (edge0 : ^T) (edge1 : ^T) (x : ^U) : ^U = linearstepAux Unchecked.defaultof edge0 edge1 x /// Performs smooth Hermite interpolation between 0 and 1 when edge0 < x < edge1. let inline smoothstep (edge0 : ^T) (edge1 : ^T) (x : ^U) = smoothstepAux Unchecked.defaultof edge0 edge1 x /// Returns a value with the magnitude of the first argument and the sign of the second argument. let inline copysign (value : ^T) (sign : ^U) = copysignAux Unchecked.defaultof value sign /// Converts an angle given in radians to degrees. let inline degrees (radians : ^T) = degreesAux Unchecked.defaultof radians /// Converts an angle given in degrees to radians. let inline radians (degrees : ^T) = radiansAux Unchecked.defaultof degrees /// Returns (x * y) + z let inline madd (x : ^T) (y : ^U) (z : ^T) = maddAux Unchecked.defaultof x y z /// Returns whether x is NaN. let inline isNaN (x : ^T) = isNanAux Unchecked.defaultof Unchecked.defaultof x /// Returns whether x is infinity (positive or negative). let inline isInfinity (x : ^T) = isInfAux Unchecked.defaultof Unchecked.defaultof x /// Returns whether x is positive infinity. let inline isPositiveInfinity (x : ^T) = isPosInfAux Unchecked.defaultof Unchecked.defaultof x /// Returns whether x is negative infinity. let inline isNegativeInfinity (x : ^T) = isNegInfAux Unchecked.defaultof Unchecked.defaultof x /// Returns whether x is finite (i.e. not NaN and not infinity). let inline isFinite (x : ^T) = (x |> isInfinity |> not) && (x |> isNaN |> not) /// Returns whether the distance between x and y is not more than epsilon. let inline approximateEquals epsilon x y = approximateEqualsAux Unchecked.defaultof epsilon x y [] module ``Math compiler tests 😀😁`` = type MyCustomNumericTypeExtensionTestTypeForInternalTesting() = static member IsNaN(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = false static member Power(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting, e : float) = h static member Pown(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting, e : int) = h static member (*)(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting, e : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = h static member (*)(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting, e : int) = h static member (+)(h : int, e : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = e static member (+)(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting, e : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = h static member (-)(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting, e : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = h static member (/)(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting, e : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = h static member Signum(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = h static member Signumi(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = 0 static member CubeRoot(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = h static member Log(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = h static member LogBinary(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = h static member Log2Int(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = 0 static member Acoshb(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = h static member Asinhb(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = h static member Atanhb(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = h static member Sqrt(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = h static member inline MultiplyAdd(a : MyCustomNumericTypeExtensionTestTypeForInternalTesting, b : int, c : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = a static member DegreesFromRadians(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = h static member RadiansFromDegrees(h : MyCustomNumericTypeExtensionTestTypeForInternalTesting) = h let fsharpCoreWorking() = let absWorking() = let a : V2i = abs V2i.One let a : V3f = abs V3f.One () let acosWorking() = let a : V2f = acos V2f.One let a : V3d = acos V3d.One let a : ComplexD = acos ComplexD.One () let asinWorking() = let a : V2f = asin V2f.One let a : V3d = asin V3d.One let a : ComplexD = asin ComplexD.One () let atanWorking() = let a : V2f = atan V2f.One let a : V3d = atan V3d.One let a : ComplexD = atan ComplexD.One () let atan2Working() = let a : V2f = atan2 V2f.One V2f.Zero let a : V3d = atan2 V3d.One V3d.Zero () let ceilWorking() = let a : V2f = ceil V2f.One let a : V3d = ceil V3d.One () let expWorking() = let a : V2f = exp V2f.One let a : V3d = exp V3d.One let a : ComplexD = exp ComplexD.One () let floorWorking() = let a : V2f = floor V2f.One let a : V3d = floor V3d.One () let truncateWorking() = let a : V2f = truncate V2f.One let a : V3d = truncate V3d.One () let roundWorking() = let a : V2f = round V2f.One let a : V3d = round V3d.One () let logWorking() = let a : V2f = log V2f.One let a : V3d = log V3d.One let a : ComplexD = log ComplexD.One () let log10Working() = let a : V2f = log10 V2f.One let a : V3d = log10 V3d.One let a : ComplexD = log10 ComplexD.One () let sqrtWorking() = let a : V2f = sqrt V2f.One let a : V3d = sqrt V3d.One let a : ComplexD = sqrt ComplexD.One () let cosWorking() = let a : V2f = cos V2f.One let a : V3d = cos V3d.One let a : ComplexD = cos ComplexD.One () let coshWorking() = let a : V2f = cosh V2f.One let a : V3d = cosh V3d.One let a : ComplexD = cosh ComplexD.One () let sinWorking() = let a : V2f = sin V2f.One let a : V3d = sin V3d.One let a : ComplexD = sin ComplexD.One () let sinhWorking() = let a : V2f = sinh V2f.One let a : V3d = sinh V3d.One let a : ComplexD = sinh ComplexD.One () let tanWorking() = let a : V2f = tan V2f.One let a : V3d = tan V3d.One let a : ComplexD = tan ComplexD.One () let tanhWorking() = let a : V2f = tanh V2f.One let a : V3d = tanh V3d.One let a : ComplexD = tanh ComplexD.One () let listAverageWorking() = let a : V2f = List.average [V2f.One; V2f.Zero] let a : C4us = List.average [C4us.Black; C4us.White] let a : M34d = List.average [M34d.Zero; M34d.Zero] let a : ComplexD = List.average [ComplexD.One; ComplexD.Zero] () () let zeroWorking() = let a : int = zero let a : float = zero let a : float16 = zero let a : V2d = zero let a : ComplexD = zero () let oneWorking() = let a : int = one let a : float = one let a : float16 = one let a : V2d = one let a : ComplexD = one () let inline indirectSignum (x : ^T) = signum x let signumWorking() = let a : float = signum 1.0 let b : int = signum 1 let s : V2d = signum V2d.II let a : decimal = signum 1.0m let a : MyCustomNumericTypeExtensionTestTypeForInternalTesting = signum (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) let a : MyCustomNumericTypeExtensionTestTypeForInternalTesting = indirectSignum (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) () let signumIntWorking() = let a : int = signumi 1.0 let b : int = signumi 1 let s : V2i = signumi V2d.II let a : int = signumi (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) () let inline indirectPown (x : ^T) (y : int) = pown x y let pownWorking() = let a = pown (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) 6 let a = indirectPown (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) 6 let a : float = pown 1.0 2 let a : int = pown 1 2 let a : uint16 = pown 1us 2 let a : uint16 = pown 1us 2us let a : int64 = pown 1L 2 let a : int64 = pown 1L 2L let a = 2.0 * (pown V3d.III V3i.III) let a = 2.0 * (indirectPown V3d.III 6) let a : V2f = pown V2f.One 1 let a : V2f = pown V2f.One V2i.One let a : V2i = pown V2i.One 1 let a : V2i = pown V2i.One V2i.One let a : V2l = pown V2l.One 1 let a : V2l = pown V2l.One 1L let a : V2l = pown V2l.One V2i.One let a : V2l = pown V2l.One V2l.One () let inline indirectExp2 (x : ^T) = exp2 x let exp2Working() = let a : float = exp2 1.0 let a : float32 = exp2 1.0f let a : uint64 = exp2 1UL let a = 2.0 * (exp2 V3d.III) let a = 2.0 * (indirectExp2 V3d.III) let a : V2f = exp2 V2f.One let a : V2d = exp2 V2d.One () let inline indirectPow (x : ^T) (y : ^U) = pow x y let powWorking() = let a : float = pow 1.0 2.0 let a : float = indirectPow 1.0 2.0 let a : float32 = pow 1.0f 2.0f let a : float32 = indirectPow 1.0f 2.0f let a = log (2.0 + 8.0 * (pow V3d.III V3d.III)) let a = log (2.0 + 8.0 * (indirectPow V3d.III V3d.III)) let a = pow (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) 12. // This doesn't work if we just extend the built-in pow function // by adding Pow() members to the vector types... let a : V2d -> float -> V2d = pow let a : V2d -> float -> V2d = indirectPow let a : V2d -> float -> V2d = ( ** ) let a : V2d = pow V2d.II V2d.II let a : V2d = pow V2d.II 1.0 let a : ComplexD = pow ComplexD.One ComplexD.One let a : ComplexD = pow ComplexD.One 1.0 () let powOpWorking() = let a : float = 1.0 ** 2.0 let a : float32 = 1.0f ** 2.0f let a = MyCustomNumericTypeExtensionTestTypeForInternalTesting() ** 12.0 let a : V2d = V2d.II ** V2d.II let a : V2d = V2d.II ** 1.0 let a : ComplexD = ComplexD.One ** ComplexD.One let a : ComplexD = ComplexD.One ** 1.0 () let inline indirectLog2 (x : ^T) : ^T = log2 x let log2Working() = let a : float = log2 10.0 let a : V2d = log2 V2d.II let a : ComplexD = log2 ComplexD.One let a : MyCustomNumericTypeExtensionTestTypeForInternalTesting = log2 (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) let a : MyCustomNumericTypeExtensionTestTypeForInternalTesting = indirectLog2 (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) () let inline indirectLog2int (x : ^T) = log2int x let log2intWorking() = let a : int = log2int 10.0 let a : V2i = log2int V2d.II let a : int = log2int (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) let a : int = indirectLog2int (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) () let acoshWorking() = let a : float = acosh 1.0 let a : float32 = acosh 1.0f let a : V2f = acosh V2f.One let a : V3d = acosh V3d.One let a : ComplexD = acosh ComplexD.One let a : MyCustomNumericTypeExtensionTestTypeForInternalTesting = acosh (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) () let asinhWorking() = let a : float = asinh 1.0 let a : float32 = asinh 1.0f let a : V2f = asinh V2f.One let a : V3d = asinh V3d.One let a : ComplexD = asinh ComplexD.One let a : MyCustomNumericTypeExtensionTestTypeForInternalTesting = asinh (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) () let atanhWorking() = let a : float = atanh 1.0 let a : float32 = atanh 1.0f let a : V2f = atanh V2f.One let a : V3d = atanh V3d.One let a : ComplexD = atanh ComplexD.One let a : MyCustomNumericTypeExtensionTestTypeForInternalTesting = atanh (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) () let cbrtWorking() = let a : float = cbrt 10.0 let a : V2d = cbrt V2d.II let a : ComplexD = cbrt ComplexD.One let a : MyCustomNumericTypeExtensionTestTypeForInternalTesting = cbrt (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) () let sqrWorking() = let a : byte = sqr 4uy let a : float = sqr 10.0 let a : V2d = sqr V2d.II let a : V2i = sqr V2i.II let a : ComplexD = sqr ComplexD.One () let clampWorking() = let a : int = clamp 1 2 3 let a : float16 = clamp (float16 1) (float16 2) (float16 3) let a : Version = clamp (Version(1,2,3)) (Version(3,2,3)) (Version(4,5,6)) let a : V2d = clamp V2d.Zero V2d.One V2d.Half let a : V3f = clamp 0.5f 1.5f V3f.Zero let a = exp ((V3f.Zero |> clamp 0.5f V3f.One) * 0.5f) () let inline indirectMin x y = min x y let minWorking() = let a : V2d = min V2d.II V2d.OO let a : V2d = min 0.0 V2d.II let a : V2ui = min 0u V2ui.II let a = (V2d.II |> min 1.0) * 2.0 - 0.5 let a = (V2d.II |> indirectMin 1.0) * 2.0 - 0.5 let a : float = min 1.0 2.0 let a : float16 = min (float16 1.0) (float16 2.0) let a : uint32 = min 1u 2u let a : nativeint = min 1n 2n let a : Version = min (Version(1,2,3)) (Version(3,2,3)) () let maxWorking() = let a : V2d = max V2d.II V2d.OO let a : V2d = max 0.0 V2d.II let a : V2ui = max 0u V2ui.II let a : float = max 1.0 2.0 let a : float16 = max (float16 1.0) (float16 2.0) let a : uint32 = max 1u 2u let a : nativeint = max 1n 2n let a : Version = max (Version(1,2,3)) (Version(3,2,3)) () let inline indirectSaturate (x : ^T) = saturate x let saturateWorking() = let a : int = saturate 3 let a : int = indirectSaturate 3 let a : float = saturate 3.0 let a : float16 = saturate (float16 3.0) let a : uint32 = saturate 3u let a : nativeint = saturate 3n let a : V2d = saturate V2d.One let a : V2d = indirectSaturate V2d.One let a : V4i = saturate V4i.One () let lerpWorking() = let a : int = lerp 1 10 0.5 let a : int = lerp 1 10 0.5f let a : float = lerp 1.0 10.0 0.5 let a : float32 = lerp 1.0f 10.0f 0.5f let a : V2i = lerp V2i.Zero V2i.One 0.5 let a : V4i = lerp V4i.Zero V4i.One V4d.Half let a : V2i = lerp V2i.Zero V2i.One 0.5f let a : V4i = lerp V4i.Zero V4i.One V4f.Half let a : C4b = lerp C4b.Black C4b.Black 0.5f let a : C4b = lerp C4b.Black C4b.Black V4f.Half let a : C4b = lerp C4b.Black C4b.Black V4d.Half () let invLerpWorking() = let a : float = 1 |> invLerp 1 10 let a : float = 1.0 |> invLerp 1.0 10.0 let a : float32 = 1.0f |> invLerp 1.0f 10.0f let a : V2d = V2i.Zero |> invLerp V2i.Zero V2i.One let a : V4d = V4i.Zero |> invLerp V4i.Zero V4i.One let a : V2f = V2f.Zero |> invLerp V2f.Zero V2f.One let a : V4f = V4f.Zero |> invLerp V4f.Zero V4f.One let a : V2d = V2d.Zero |> invLerp V2d.Zero V2d.One let a : V4d = V4d.Zero |> invLerp V4d.Zero V4d.One () let stepWorking() = let a : float = step 0.0 1.0 let a : float32 = step 0.0f 0.5f let a : uint8 = step 32uy 64uy let a : int8 = step 32y 64y let a : int16 = step 32s 64s let a : uint16 = step 32us 64us let a : int32 = step 32 64 let a : int64 = step 32L 64L let a : decimal = step 32m 64m let a : V2i = step 0 V2i.One let a : V2l = step 0L V2l.One let a : V2f = step 0.0f V2f.Half let a : V4d = step V4d.Zero V4d.Half () let linearstepWorking() = let a : float = linearstep 0.0 1.0 0.5 let a : float32 = linearstep 0.0f 1.0f 0.5f let a : V2f = linearstep 0.0f 1.0f V2f.Half let a : V4d = linearstep V4d.Zero V4d.One V4d.Half () let smoothstepWorking() = let a : float = smoothstep 0.0 1.0 0.5 let a : float32 = smoothstep 0.0f 1.0f 0.5f let a : V2f = smoothstep 0.0f 1.0f V2f.Half let a : V4d = smoothstep V4d.Zero V4d.One V4d.Half () let copysignWorking() = let a : float = copysign 0.0 1.0 let a : float32 = copysign 0.0f 10.0f let a : V3d = copysign V3d.Zero V3d.One let a : V3d = copysign V3d.Zero -1.0 let a = exp (2.0 * (copysign V3d.Zero -1.0)) () let conversionWorking() = let a : float = degrees 0.0 let a : float32 = radians 0.0f let a : V3d = degrees V3d.Zero let a : V4f = radians V4f.Zero let a : MyCustomNumericTypeExtensionTestTypeForInternalTesting = radians (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) let a : MyCustomNumericTypeExtensionTestTypeForInternalTesting = degrees (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) () let inline indirectMultiplyAdd (x : ^T) (y : ^U) (z : ^T) = madd x y z let multiplyAddWorking() = let a : float = madd 0.0 1.0 2.0 let a : float32 = madd 0.0f 1.0f 2.0f let a : V3d = madd V3d.Zero 1.0 V3d.Zero let a : V3d = indirectMultiplyAdd V3d.Zero 1.0 V3d.Zero let a : V3d = madd V3d.Zero V3d.Zero V3d.Zero let a : MyCustomNumericTypeExtensionTestTypeForInternalTesting = madd (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) 1 (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) let a : MyCustomNumericTypeExtensionTestTypeForInternalTesting = indirectMultiplyAdd (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) 1 (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) () let inline indirectIsNaN (x : ^T) = isNaN x let specialFloatingPointValuesWorking() = let a : bool = isNaN 0.0 let a : bool = isNaN (float16 0.0) let a : bool = indirectIsNaN 0.0 let a : bool = indirectIsNaN (float16 0.0) let a : bool = isNaN 0.0f let a : bool = isNaN ComplexD.Zero let a : bool = isNaN V3d.Zero let a : bool = isNaN C3d.Black let a : bool = isNaN M44d.Identity let a : bool = isNaN (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) let a : bool = indirectIsNaN (MyCustomNumericTypeExtensionTestTypeForInternalTesting()) let a : bool = isFinite 0.0 let a : bool = isFinite 0.0f let a : bool = isFinite (float16 0.0f) let a : bool = isFinite ComplexD.Zero let a : bool = isFinite V3d.Zero let a : bool = isFinite C3d.Black let a : bool = isFinite M44d.Identity let a : bool = isInfinity 0.0 let a : bool = isInfinity 0.0f let a : bool = isInfinity (float16 0.0f) let a : bool = isInfinity ComplexD.Zero let a : bool = isInfinity V3d.Zero let a : bool = isInfinity C3d.Black let a : bool = isInfinity M44d.Identity let a : bool = isPositiveInfinity 0.0 let a : bool = isPositiveInfinity 0.0f let a : bool = isPositiveInfinity (float16 0.0f) let a : bool = isPositiveInfinity ComplexD.Zero let a : bool = isPositiveInfinity C3d.Black let a : bool = isPositiveInfinity V3d.Zero let a : bool = isPositiveInfinity M33d.Zero let a : bool = isNegativeInfinity 0.0 let a : bool = isNegativeInfinity 0.0f let a : bool = isNegativeInfinity (float16 0.0f) let a : bool = isNegativeInfinity ComplexD.Zero let a : bool = isNegativeInfinity C3d.Black let a : bool = isNegativeInfinity V3d.Zero let a : bool = isNegativeInfinity M33d.Zero () let approximateEqualsWorking() = let a : bool = approximateEquals 2 42 43 let a : bool = approximateEquals 1.0 42.0 43.0 let a : bool = approximateEquals 1 V2i.Zero V2i.One let a : bool = approximateEquals 1 M44i.Zero M44i.Identity let a : bool = approximateEquals 1.0 ComplexD.Zero ComplexD.One () ================================================ FILE: src/Aardvark.Base.FSharp/Math/Matrix.fs ================================================ namespace Aardvark.Base [] module Mat = [] module private Aux = let inline transposeAux (_ : ^z) (m : ^Matrix) = ((^z or ^Matrix) : (static member Transposed : ^Matrix -> ^Matrix') m) let inline determinantAux (_ : ^z) (m : ^Matrix) = ((^z or ^Matrix) : (static member Determinant : ^Matrix -> ^Scalar) m) let inline inverseAux (_ : ^z) (m : ^Matrix) = ((^z or ^Matrix) : (static member Inverse : ^Matrix -> ^Matrix) m) let inline transformAux (_ : ^z) (m : ^Matrix) (v : ^Vector) = ((^z or ^Matrix or ^Vector) : (static member Transform : ^Matrix * ^Vector -> ^Vector') (m, v)) let inline transformDirAux (_ : ^z) (m : ^Matrix) (v : ^Vector) = ((^z or ^Matrix or ^Vector) : (static member TransformDir : ^Matrix * ^Vector -> ^Vector) (m, v)) let inline transformPosAux (_ : ^z) (m : ^Matrix) (v : ^Vector) = ((^z or ^Matrix or ^Vector) : (static member TransformPos : ^Matrix * ^Vector -> ^Vector) (m, v)) let inline transformPosProjAux (_ : ^z) (m : ^Matrix) (v : ^Vector) = ((^z or ^Matrix or ^Vector) : (static member TransformPosProj : ^Matrix * ^Vector -> ^Vector) (m, v)) let inline anyEqualAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AnyEqual : ^a * ^b -> bool) (a, b)) let inline anyDifferentAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AnyDifferent : ^a * ^b -> bool) (a, b)) let inline anySmallerAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AnySmaller : ^a * ^b -> bool) (a, b)) let inline anyGreaterAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AnyGreater : ^a * ^b -> bool) (a, b)) let inline anySmallerOrEqualAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AnySmallerOrEqual : ^a * ^b -> bool) (a, b)) let inline anyGreaterOrEqualAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AnyGreaterOrEqual : ^a * ^b -> bool) (a, b)) let inline allEqualAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AllEqual : ^a * ^b -> bool) (a, b)) let inline allDifferentAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AllDifferent : ^a * ^b -> bool) (a, b)) let inline allSmallerAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AllSmaller : ^a * ^b -> bool) (a, b)) let inline allGreaterAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AllGreater : ^a * ^b -> bool) (a, b)) let inline allSmallerOrEqualAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AllSmallerOrEqual : ^a * ^b -> bool) (a, b)) let inline allGreaterOrEqualAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AllGreaterOrEqual : ^a * ^b -> bool) (a, b)) /// Returns the transpose of a matrix. let inline transpose (m : ^Matrix) : ^Matrix' = transposeAux Unchecked.defaultof m /// Returns the determinant of a matrix. let inline det (m : ^Matrix) : ^Scalar = determinantAux Unchecked.defaultof m /// Returns the inverse of a matrix. let inline inverse (m : ^Matrix) : ^Matrix = inverseAux Unchecked.defaultof m /// Transforms a vector by a matrix. let inline transform (m : ^Matrix) (v : ^Vector) : ^Vector' = transformAux Unchecked.defaultof m v /// Transforms a point vector by a matrix (the last element of the vector is presumed 1) let inline transformPos (m : ^Matrix) (v : ^Vector) : ^Vector = transformPosAux Unchecked.defaultof m v /// Transforms a direction vector by a matrix (the last element of the vector is presumed 0) let inline transformDir (m : ^Matrix) (v : ^Vector) : ^Vector = transformDirAux Unchecked.defaultof m v /// Transforms a point vector by a matrix (the last element of the vector is presumed 1). /// Projective transform is performed. Perspective Division is performed. let inline transformPosProj (m : ^Matrix) (v : ^Vector) : ^Vector = transformPosProjAux Unchecked.defaultof m v /// Returns if a = b for any component. One or both of a and b have to be a matrix. let inline anyEqual a b = anyEqualAux Unchecked.defaultof a b /// Returns if a <> b for any component. One or both of a and b have to be a matrix. let inline anyDifferent a b = anyDifferentAux Unchecked.defaultof a b /// Returns if a = b for all components. One or both of a and b have to be a matrix. let inline allEqual a b = allEqualAux Unchecked.defaultof a b /// Returns if a <> b for all components. One or both of a and b have to be a matrix. let inline allDifferent a b = allDifferentAux Unchecked.defaultof a b /// Returns if a < b for any component. One or both of a and b have to be a matrix. let inline anySmaller a b = anySmallerAux Unchecked.defaultof a b /// Returns if a > b for any component. One or both of a and b have to be a matrix. let inline anyGreater a b = anyGreaterAux Unchecked.defaultof a b /// Returns if a < b for all components. One or both of a and b have to be a matrix. let inline allSmaller a b = allSmallerAux Unchecked.defaultof a b /// Returns if a > b for all components. One or both of a and b have to be a matrix. let inline allGreater a b = allGreaterAux Unchecked.defaultof a b /// Returns if a <= b for any component. One or both of a and b have to be a matrix. let inline anySmallerOrEqual a b = anySmallerOrEqualAux Unchecked.defaultof a b /// Returns if a >= b for any component. One or both of a and b have to be a matrix. let inline anyGreaterOrEqual a b = anyGreaterOrEqualAux Unchecked.defaultof a b /// Returns if a <= b for all components. One or both of a and b have to be a matrix. let inline allSmallerOrEqual a b = allSmallerOrEqualAux Unchecked.defaultof a b /// Returns if a >= b for all components. One or both of a and b have to be a matrix. let inline allGreaterOrEqual a b = allGreaterOrEqualAux Unchecked.defaultof a b module private CompilerTests = let working () = let a = (transpose M33d.Identity) * 0.5 let a = (det M22l.Identity) * 5L let a = inverse M22f.Identity let a : V4d = transform M44d.Identity V4d.Zero let a : V3d = transform M34d.Zero V4d.Zero let a = (transform M34d.Zero V4d.Zero) * 0.5 let a = log (0.5 * (transform M22d.Identity V2d.Zero)) let a : V3d = transformPos M44d.Identity V3d.Zero let a : V3d = transformPos M34d.Zero V3d.Zero let a = (transformPos M34d.Zero V3d.Zero) * 0.5 let a = log (0.5 * (transformPos M33d.Identity V2d.Zero)) let a : V3d = transformDir M44d.Identity V3d.Zero let a : V3d = transformDir M34d.Zero V3d.Zero let a = (transformDir M34d.Zero V3d.Zero) * 0.5 let a = log (0.5 * (transformDir M33d.Identity V2d.Zero)) let a : V3d = transformPosProj M44d.Identity V3d.Zero let a = log (0.5 * (transformPosProj M33d.Identity V2d.Zero)) () let comparisonsWorking () = let a : bool = anyEqual M34i.Zero M34i.Zero let a : bool = anyEqual M34i.Zero 0 let a : bool = anyEqual 1 M34i.Zero let a : bool = anyDifferent M34i.Zero M34i.Zero let a : bool = anyDifferent M34i.Zero 0 let a : bool = anyDifferent 1 M34i.Zero let a : bool = anySmaller M34i.Zero M34i.Zero let a : bool = anySmaller M34i.Zero 0 let a : bool = anySmaller 1 M34i.Zero let a : bool = anyGreater M34i.Zero M34i.Zero let a : bool = anyGreater M34i.Zero 0 let a : bool = anyGreater 1 M34i.Zero let a : bool = anySmallerOrEqual M34i.Zero M34i.Zero let a : bool = anySmallerOrEqual M34i.Zero 0 let a : bool = anySmallerOrEqual 1 M34i.Zero let a : bool = anyGreaterOrEqual M34i.Zero M34i.Zero let a : bool = anyGreaterOrEqual M34i.Zero 0 let a : bool = anyGreaterOrEqual 1 M34i.Zero let a : bool = allEqual M34i.Zero M34i.Zero let a : bool = allEqual M34i.Zero 0 let a : bool = allEqual 1 M34i.Zero let a : bool = allDifferent M34i.Zero M34i.Zero let a : bool = allDifferent M34i.Zero 0 let a : bool = allDifferent 1 M34i.Zero let a : bool = allSmaller M34i.Zero M34i.Zero let a : bool = allSmaller M34i.Zero 0 let a : bool = allSmaller 1 M34i.Zero let a : bool = allGreater M34i.Zero M34i.Zero let a : bool = allGreater M34i.Zero 0 let a : bool = allGreater 1 M34i.Zero let a : bool = allSmallerOrEqual M34i.Zero M34i.Zero let a : bool = allSmallerOrEqual M34i.Zero 0 let a : bool = allSmallerOrEqual 1 M34i.Zero let a : bool = allGreaterOrEqual M34i.Zero M34i.Zero let a : bool = allGreaterOrEqual M34i.Zero 0 let a : bool = allGreaterOrEqual 1 M34i.Zero () [] module Trafo = let inline private inverseAux (_ : ^z) (t : ^Trafo) = ((^z or ^Trafo) : (static member Inverse : ^Trafo -> ^Trafo) t) let inline private forwardAux (_ : ^z) (t : ^Trafo) = ((^z or ^Trafo) : (static member Forward : ^Trafo -> ^Matrix) t) let inline private backwardAux (_ : ^z) (t : ^Trafo) = ((^z or ^Trafo) : (static member Backward : ^Trafo -> ^Matrix) t) /// Returns the inverse of a transformation. let inline inverse (t : ^Trafo) : ^Trafo = t |> inverseAux Unchecked.defaultof /// Returns the forward matrix of a transformation. let inline forward (t : ^Trafo) : ^Matrix = t |> forwardAux Unchecked.defaultof /// Returns the backward matrix of a transformation. let inline backward (t : ^Trafo) : ^Matrix = t |> backwardAux Unchecked.defaultof module private CompilerTests = let working () = let a : Trafo3d = inverse Trafo3d.Identity let a = V3d.Zero |> Mat.transformPos (Trafo3d.Identity |> inverse |> forward) let a : M44d = forward Trafo3d.Identity let a : M33f = forward Trafo2f.Identity let a = (forward Trafo3d.Identity) * 5.0 let a = V3d.Zero |> Mat.transformPos (Trafo3d.Identity |> forward) let a : M44d = backward Trafo3d.Identity let a : M33f = backward Trafo2f.Identity let a = (backward Trafo3d.Identity) * 5.0 let a = V3d.Zero |> Mat.transformPos (Trafo3d.Identity |> backward) () ================================================ FILE: src/Aardvark.Base.FSharp/Math/SVDM33f.fs ================================================ namespace Aardvark.Base // Fast 3x3 float matrix SVD // Source: McAdams, Aleka, et al. "Computing the singular value decomposition of 3× 3 matrices with minimal branching and elementary floating point operations." University of Wisconsin Madison (2011). // Implementation on: // https://github.com/ericjang/svd3/blob/master/svd3.h // by https://github.com/ericjang [] module M33f = let gamma = 5.828427124f let cstar = 0.923879532f let sstar = 0.3826834323f let epsilon = float32 1E-6 let inline invSqrt x = 1.0f / (sqrt x) let inline quatToM33 (qV : V4f) = let w = qV.W let x = qV.X let y = qV.Y let z = qV.Z let qxx = x*x let qyy = y*y let qzz = z*z let qxz = x*z let qxy = x*y let qyz = y*z let qwx = w*x let qwy = w*y let qwz = w*z M33f( 1.0f - 2.0f * (qyy + qzz), 2.0f * (qxy - qwz), 2.0f * (qxz + qwy), 2.0f * (qxy + qwz), 1.0f - 2.0f * (qxx + qzz), 2.0f * (qyz - qwx), 2.0f * (qxz - qwy), 2.0f * (qyz + qwx), 1.0f - 2.0f * (qxx + qyy) ) let inline givens m11 m12 m22 = let ch = 2.0f * (m11 - m22) let sh = m12 let b = gamma*sh*sh < ch*ch let w = invSqrt(ch*ch + sh*sh) let och = if b then w*ch else cstar let osh = if b then w*sh else sstar och, osh let inline diagonal m11 m21 m22 m31 m32 m33 = M33f(m11, m21, m31, m21, m22, m32, m31, m32, m33) let inline conjugate (x : int) (y : int) (z : int) (m : M33f) (qV : V4f) = let (ch,sh) = givens m.M00 m.M10 m.M11 let scale = ch*ch + sh*sh let a = (ch*ch-sh*sh)/scale let b = (2.0f*sh*ch)/scale let m11 = a*(a*m.M00+b*m.M10) + b*(a*m.M10 + b*m.M11) let m21 = a*(-b*m.M00+a*m.M10) + b*(-b*m.M10 + a*m.M11) let m22 = -b*(-b*m.M00+a*m.M10) + a*(-b*m.M10 + a*m.M11) let m31 = a*m.M20 + b*m.M21 let m32 = -b*m.M20 + a*m.M21 let m33 = m.M22 let tmp = V3f(qV.X*sh, qV.Y*sh, qV.Z*sh) let shScaled = qV.W * sh let q1 = qV.X * ch let q2 = qV.Y * ch let q3 = qV.Z * ch let q4 = qV.W * ch let q = [|q1; q2; q3; q4|] q.[z] <- q.[z] + shScaled q.[3] <- q.[3] - tmp.[z] q.[x] <- q.[x] + tmp.[y] q.[y] <- q.[y] - tmp.[x] let ma = diagonal m22 m32 m33 m21 m31 m11 let va = V4f(q.[0], q.[1], q.[2], q.[3]) ma,va let inline diagonalizeSymmetric (m : M33f) = let mutable m = m let mutable qV = V4f(0, 0, 0, 1) let doIt (mm,mqV) = m <- mm qV <- mqV for _ in 0..4 do doIt (conjugate 0 1 2 m qV) doIt (conjugate 1 2 0 m qV) doIt (conjugate 2 0 1 m qV) m,qV let inline swap c x y = if c then (y,-x) else (x,y) let inline fswap c x y = if c then (y,x) else (x,y) let inline decomposeAndSort (m : M33f) (q : M33f) = let rho1 = m.C0.LengthSquared let rho2 = m.C1.LengthSquared let rho3 = m.C2.LengthSquared let c = rho1 < rho2 let (m11,m12) = swap c m.M00 m.M01 let (m21,m22) = swap c m.M10 m.M11 let (m31,m32) = swap c m.M20 m.M21 let (q11,q12) = swap c q.M00 q.M01 let (q21,q22) = swap c q.M10 q.M11 let (q31,q32) = swap c q.M20 q.M21 let (rho1,rho2) = fswap c rho1 rho2 let c = rho1 < rho3 let (m11,m13) = swap c m11 m.M02 let (m21,m23) = swap c m21 m.M12 let (m31,m33) = swap c m31 m.M22 let (q11,q13) = swap c q11 q.M02 let (q21,q23) = swap c q21 q.M12 let (q31,q33) = swap c q31 q.M22 let (rho1,rho3) = fswap c rho1 rho3 let c = rho2 < rho3 let (m12,m13) = swap c m12 m13 let (m22,m23) = swap c m22 m23 let (m32,m33) = swap c m32 m33 let (q12,q13) = swap c q12 q13 let (q22,q23) = swap c q22 q23 let (q32,q33) = swap c q32 q33 let M = M33f(m11,m12,m13,m21,m22,m23,m31,m32,m33) let V = M33f(q11,q12,q13,q21,q22,q23,q31,q32,q33) M,V let inline QRgivens p a = let rho = sqrt(p*p + a*a) let ch = (abs p) + max rho epsilon let sh = if rho > epsilon then a else 0.0f let (sh,ch) = fswap (p<0.0f) sh ch let w = invSqrt(ch*ch + sh*sh) let ch = w * ch let sh = w * sh ch,sh let inline QRdecompose (m : M33f) = let (ch1,sh1) = QRgivens m.M00 m.M10 let a = 1.0f - 2.0f * sh1 * sh1 let b = 2.0f * ch1 * sh1 let r11 = a * m.M00 + b * m.M10 let r12 = a * m.M01 + b * m.M11 let r13 = a * m.M02 + b * m.M12 let r21 = -b* m.M00 + a * m.M10 let r22 = -b* m.M01 + a * m.M11 let r23 = -b* m.M02 + a * m.M12 let r31 = m.M20 let r32 = m.M21 let r33 = m.M22 let (ch2,sh2) = QRgivens r11 r31 let a = 1.0f - 2.0f * sh2 * sh2 let b = 2.0f * ch2 * sh2 let b11 = a * r11 + b * r31 let b12 = a * r12 + b * r32 let b13 = a * r13 + b * r33 let b21 = r21 let b22 = r22 let b23 = r23 let b31 = -b* r11 + a * r31 let b32 = -b* r12 + a * r32 let b33 = -b* r13 + a * r33 let (ch3,sh3) = QRgivens b22 b32 let a = 1.0f - 2.0f * sh3 * sh3 let b = 2.0f * ch3 * sh3 let r11 = b11 let r12 = b12 let r13 = b13 let r21 = a * b21 + b * b31 let r22 = a * b22 + b * b32 let r23 = a * b23 + b * b33 let r31 = -b* b21 + a * b31 let r32 = -b* b22 + a * b32 let r33 = -b* b23 + a * b33 let sh1s = sh1*sh1 let sh2s = sh2*sh2 let sh3s = sh3*sh3 let q11 = (-1.0f + 2.0f * sh1s) * (-1.0f + 2.0f * sh2s) let q12 = 4.0f * ch2 * ch3 * (-1.0f + 2.0f * sh1s) * sh2 * sh3 + 2.0f * ch1 * sh1 * (-1.0f + 2.0f * sh3s) let q13 = 4.0f * ch1 * ch3 * sh1 * sh3 - 2.0f * ch2 * (-1.0f + 2.0f * sh1s) * sh2 * (-1.0f + 2.0f * sh3s) let q21 = 2.0f * ch1 * sh1 * (1.0f - 2.0f * sh2s) let q22 = -8.0f * ch1 * ch2 * ch3 * sh1 * sh2 * sh3 + (-1.0f + 2.0f * sh1s) * (-1.0f + 2.0f * sh3s) let q23 = -2.0f * ch3 * sh3 + 4.0f * sh1 * (ch3 * sh1 * sh3 + ch1 * ch2 * sh2 * (-1.0f + 2.0f * sh3s)) let q31 = 2.0f * ch2 * sh2 let q32 = 2.0f * ch3 * (1.0f - 2.0f * sh2s) * sh3 let q33 = (-1.0f + 2.0f * sh2s) * (-1.0f + 2.0f * sh3s) let Q = M33f(q11,q12,q13,q21,q22,q23,q31,q32,q33) let R = M33f(r11,r12,r13,r21,r22,r23,r31,r32,r33) (Q,R) let inline svd (m : M33f) = let norm = m.Transposed * m let (_, qV) = diagonalizeSymmetric norm let quat = quatToM33 qV let B = m * quat let (M,V) = decomposeAndSort B quat let (U,S) = QRdecompose M (U,S,V) ================================================ FILE: src/Aardvark.Base.FSharp/Math/Vectors.fs ================================================ namespace Aardvark.Base [] module Vec = [] module private Aux = let inline dotAux (_ : ^z) (a : ^a) (b : ^a) = ((^z or ^a) : (static member Dot : ^a * ^a -> ^b) (a, b)) let inline crossAux (_ : ^z) (a : ^a) (b : ^a) = ((^z or ^a) : (static member Cross : ^a * ^a -> ^a) (a, b)) let inline distanceAux (_ : ^z) (a : ^a) (b : ^a) = ((^z or ^a) : (static member Distance : ^a * ^a -> ^b) (a, b)) let inline distanceSquaredAux (_ : ^z) (a : ^a) (b : ^a) = ((^z or ^a) : (static member DistanceSquared : ^a * ^a -> ^b) (a, b)) let inline reflectAux (_ : ^z) (n : ^a) (v : ^a) = ((^z or ^a) : (static member Reflect : ^a * ^a -> ^a) (v, n)) let inline refractAux (_ : ^z) (eta : ^b) (n : ^a) (v : ^a) = ((^z or ^a) : (static member Refract : ^a * ^a * ^b -> ^a) (v, n, eta)) let inline anyEqualAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AnyEqual : ^a * ^b -> bool) (a, b)) let inline anyDifferentAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AnyDifferent : ^a * ^b -> bool) (a, b)) let inline anySmallerAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AnySmaller : ^a * ^b -> bool) (a, b)) let inline anyGreaterAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AnyGreater : ^a * ^b -> bool) (a, b)) let inline anySmallerOrEqualAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AnySmallerOrEqual : ^a * ^b -> bool) (a, b)) let inline anyGreaterOrEqualAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AnyGreaterOrEqual : ^a * ^b -> bool) (a, b)) let inline allEqualAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AllEqual : ^a * ^b -> bool) (a, b)) let inline allDifferentAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AllDifferent : ^a * ^b -> bool) (a, b)) let inline allSmallerAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AllSmaller : ^a * ^b -> bool) (a, b)) let inline allGreaterAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AllGreater : ^a * ^b -> bool) (a, b)) let inline allSmallerOrEqualAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AllSmallerOrEqual : ^a * ^b -> bool) (a, b)) let inline allGreaterOrEqualAux (_ : ^z) (a : ^a) (b : ^b) = ((^z or ^a or ^b) : (static member AllGreaterOrEqual : ^a * ^b -> bool) (a, b)) /// Computes the dot product of two vectors a and b. let inline dot a b = dotAux Unchecked.defaultof a b /// Computes the cross product of two 3D vectors a and b. let inline cross a b = crossAux Unchecked.defaultof a b /// Computes the distance between a and b let inline distance a b = distanceAux Unchecked.defaultof a b /// Computes the squared distance between a and b let inline distanceSquared a b = distanceSquaredAux Unchecked.defaultof a b /// Computes the length of the vector v. let inline length< ^a, ^b when ^a : (member Length : ^b )> (v : ^a) = (^a : (member Length : ^b ) (v)) /// Computes the squared length of the vector v. let inline lengthSquared< ^a, ^b when ^a : (member LengthSquared : ^b )> (v : ^a) = (^a : (member LengthSquared : ^b ) (v)) /// Returns the vector v with unit length. let inline normalize< ^a, ^b when ^a : (member Normalized : ^b )> (v : ^a) = (^a : (member Normalized : ^b ) v) /// Returns the reflection direction of v for the normal n (should be normalized). let inline reflect n v = reflectAux Unchecked.defaultof n v /// Returns the refraction direction of v for the normal n and ratio of refraction indices eta. /// v and n should be normalized. let inline refract eta n v = refractAux Unchecked.defaultof eta n v /// Returns the x-component of the vector v. let inline x< ^a, ^b when ^a : (member P_X : ^b)> (v : ^a) = (^a : (member P_X : ^b) v) /// Returns the y-component of the vector v. let inline y< ^a, ^b when ^a : (member P_Y : ^b)> (v : ^a) = (^a : (member P_Y : ^b) v) /// Returns the z-component of the vector v. let inline z< ^a, ^b when ^a : (member P_Z : ^b)> (v : ^a) = (^a : (member P_Z : ^b) v) /// Returns the w-component of the vector v. let inline w< ^a, ^b when ^a : (member P_W : ^b)> (v : ^a) = (^a : (member P_W : ^b) v) /// Returns the xy-components of the vector v. let inline xy< ^a, ^b when ^a : (member XY : ^b)> (v : ^a) = (^a : (member XY : ^b) v) /// Returns the yz-components of the vector v. let inline yz< ^a, ^b when ^a : (member YZ : ^b)> (v : ^a) = (^a : (member YZ : ^b) v) /// Returns the zw-components of the vector v. let inline zw< ^a, ^b when ^a : (member ZW : ^b)> (v : ^a) = (^a : (member ZW : ^b) v) /// Returns the xyz-components of the vector v. let inline xyz< ^a, ^b when ^a : (member XYZ : ^b)> (v : ^a) = (^a : (member XYZ : ^b) v) /// Returns the yzw-components of the vector v. let inline yzw< ^a, ^b when ^a : (member YZW : ^b)> (v : ^a) = (^a : (member YZW : ^b) v) /// Returns if a = b for any component. One or both of a and b have to be a vector. let inline anyEqual a b = anyEqualAux Unchecked.defaultof a b /// Returns if a <> b for any component. One or both of a and b have to be a vector. let inline anyDifferent a b = anyDifferentAux Unchecked.defaultof a b /// Returns if a = b for all components. One or both of a and b have to be a vector. let inline allEqual a b = allEqualAux Unchecked.defaultof a b /// Returns if a <> b for all components. One or both of a and b have to be a vector. let inline allDifferent a b = allDifferentAux Unchecked.defaultof a b /// Returns if a < b for any component. One or both of a and b have to be a vector. let inline anySmaller a b = anySmallerAux Unchecked.defaultof a b /// Returns if a > b for any component. One or both of a and b have to be a vector. let inline anyGreater a b = anyGreaterAux Unchecked.defaultof a b /// Returns if a < b for all components. One or both of a and b have to be a vector. let inline allSmaller a b = allSmallerAux Unchecked.defaultof a b /// Returns if a > b for all components. One or both of a and b have to be a vector. let inline allGreater a b = allGreaterAux Unchecked.defaultof a b /// Returns if a <= b for any component. One or both of a and b have to be a vector. let inline anySmallerOrEqual a b = anySmallerOrEqualAux Unchecked.defaultof a b /// Returns if a >= b for any component. One or both of a and b have to be a vector. let inline anyGreaterOrEqual a b = anyGreaterOrEqualAux Unchecked.defaultof a b /// Returns if a <= b for all components. One or both of a and b have to be a vector. let inline allSmallerOrEqual a b = allSmallerOrEqualAux Unchecked.defaultof a b /// Returns if a >= b for all components. One or both of a and b have to be a vector. let inline allGreaterOrEqual a b = allGreaterOrEqualAux Unchecked.defaultof a b module private CompilerTests = let dotWorking () = let a : float = dot V3d.One V3d.Zero let a : int = dot V3i.One V3i.Zero () let crossWorking () = let a : V3d = cross V3d.One V3d.Zero let a : V3i = cross V3i.One V3i.Zero () let distanceWorking () = let a : float = distance V3d.One V3d.Zero let a : float32 = distance V3f.One V3f.Zero let a : float = distance V3i.One V3i.Zero () let distanceSquaredWorking () = let a : float = distanceSquared V3d.One V3d.Zero let a : float32 = distanceSquared V3f.One V3f.Zero let a : int = distanceSquared V3i.One V3i.Zero () let lengthWorking () = let a : float32 = length V3f.One let a : float = length V3d.One let a : float = length V3i.One () let lengthSquaredWorking () = let a : float32 = lengthSquared V3f.One let a : float = lengthSquared V3d.One let a : int = lengthSquared V3i.One () let normalizeWorking () = let a : V3f = normalize V3f.One let a : V3d = normalize V3d.One let a : V3d = normalize V3i.One () let reflectWorking () = let a : V3f = reflect V3f.One V3f.Zero let a : V3d = reflect V3d.One V3d.Zero () let refractWorking () = let a : V3f = refract 0.0f V3f.One V3f.Zero let a : V3d = refract 0.0 V3d.One V3d.Zero () let swizzlesWorking () = let a : float = x V3d.One let a : float = y V3d.One let a : float = z V3d.One let a : float = w V4d.One let a : V2d = xy V3d.One let a : V2d = yz V3d.One let a : V2d = zw V4d.One let a : V3d = xyz V4d.One let a : V3d = yzw V4d.One () let comparisonsWorking () = let a : bool = anyEqual V3i.One V3i.Zero let a : bool = anyEqual V3i.One 0 let a : bool = anyEqual 1 V3i.Zero let a : bool = anyDifferent V3i.One V3i.Zero let a : bool = anyDifferent V3i.One 0 let a : bool = anyDifferent 1 V3i.Zero let a : bool = anySmaller V3i.One V3i.Zero let a : bool = anySmaller V3i.One 0 let a : bool = anySmaller 1 V3i.Zero let a : bool = anyGreater V3i.One V3i.Zero let a : bool = anyGreater V3i.One 0 let a : bool = anyGreater 1 V3i.Zero let a : bool = anySmallerOrEqual V3i.One V3i.Zero let a : bool = anySmallerOrEqual V3i.One 0 let a : bool = anySmallerOrEqual 1 V3i.Zero let a : bool = anyGreaterOrEqual V3i.One V3i.Zero let a : bool = anyGreaterOrEqual V3i.One 0 let a : bool = anyGreaterOrEqual 1 V3i.Zero let a : bool = allEqual V3i.One V3i.Zero let a : bool = allEqual V3i.One 0 let a : bool = allEqual 1 V3i.Zero let a : bool = allDifferent V3i.One V3i.Zero let a : bool = allDifferent V3i.One 0 let a : bool = allDifferent 1 V3i.Zero let a : bool = allSmaller V3i.One V3i.Zero let a : bool = allSmaller V3i.One 0 let a : bool = allSmaller 1 V3i.Zero let a : bool = allGreater V3i.One V3i.Zero let a : bool = allGreater V3i.One 0 let a : bool = allGreater 1 V3i.Zero let a : bool = allSmallerOrEqual V3i.One V3i.Zero let a : bool = allSmallerOrEqual V3i.One 0 let a : bool = allSmallerOrEqual 1 V3i.Zero let a : bool = allGreaterOrEqual V3i.One V3i.Zero let a : bool = allGreaterOrEqual V3i.One 0 let a : bool = allGreaterOrEqual 1 V3i.Zero () ================================================ FILE: src/Aardvark.Base.FSharp/Native/BlobStore.fs ================================================ namespace Aardvark.Base.Native open Aardvark.Base open System type IBlobFile = abstract member Name : Guid abstract member Exists : bool abstract member Size : int64 abstract member Read : unit -> byte[] abstract member Write : byte[] -> unit abstract member Delete : unit -> unit abstract member CopyTo : IBlobFile -> unit type IBlobStore = inherit IDisposable abstract member Memory : Mem abstract member Create : unit -> IBlobFile abstract member Get : Guid -> IBlobFile ================================================ FILE: src/Aardvark.Base.FSharp/Native/FileTable.fs ================================================ namespace Aardvark.Base.Native #nowarn "9" open System open System.Runtime.InteropServices open System.Collections.Generic open Aardvark.Base [] type Entry = struct val mutable public Key : Guid val mutable public Offset : int64 val mutable public Size : int64 val mutable public HashCode : int val mutable public Next : int override x.ToString() = sprintf "{ Key = %A; Offset = %d; Size = %d }" x.Key x.Offset x.Size new(k : Guid, o : int64, s : int64, h : int, n : int) = { Key = k; Offset = o; Size = s; HashCode = h; Next = n } end [] type private DictHeader = struct [] val mutable public Magic : int64 [] val mutable public CapacityIndex : int [] val mutable public Capacity : int [] val mutable public FreeList : int [] val mutable public Count : int [] val mutable public FreeCount : int end [] module private ``DictHeader Extensions`` = let inline (==) (a : Guid) (b : Guid) = a.Equals(b) let inline private read<'a when 'a : unmanaged> (ptr : ptr) : 'a = ptr.Read<'a>() let inline private write<'a when 'a : unmanaged> (v : 'a) (ptr : ptr) : unit = ptr.Write<'a>(v) let inline (!!) (ptr : ptr<'a>) = ptr.Value let inline (!=) (ptr : ptr<'a>) (v : 'a) = ptr.Value <- v type ptr with member x.Magic with inline get() = x |> read and inline set m = x |> write m member x.CapacityIndex with inline get() = (8n + x) |> read and inline set m = (8n + x) |> write m member x.Capacity with inline get() = (12n + x) |> read and inline set m = (12n + x) |> write m member x.FreeList with inline get() = (16n + x) |> read and inline set m = (16n + x) |> write m member x.Count with inline get() = (24n + x) |> read and inline set m = (24n + x) |> write m member x.FreeCount with inline get() = (28n + x) |> read and inline set m = (28n + x) |> write m member x.Key with inline get() = x |> read and inline set m = x |> write m member x.Offset with inline get() = (16n + x) |> read and inline set m = (16n + x) |> write m member x.Size with inline get() = (24n + x) |> read and inline set m = (24n + x) |> write m member x.HashCode with inline get() = (32n + x) |> read and inline set m = (32n + x) |> write m member x.Next with inline get() = (36n + x) |> read and inline set m = (36n + x) |> write m let inline (.+) (ptr : ptr<'a>) (i : int) : ptr<'a> = ptr + i type private DictStore = { size : int64 pointer : Memory header : ptr entries : ptr buckets : ptr } [] module private DictStore = let private magic = 0x4a3214b10905af7aL let private se = sizeof |> int64 let private si = sizeof |> int64 let private sh = sizeof |> int64 let primeSizes = [| (* prime no. prime *) (* 2 3 + 1 = 2^2 *) (* 4 *) 7 // + 1 = 2^3, minimal size (* 6 *) 13 // + 3 = 2^4 (* 11 *) 31 // + 1 = 2^5 (* 18 *) 61 // + 3 = 2^6 (* 31 *) 127 // + 1 = 2^7 (* 54 *) 251 // + 5 = 2^8 (* 97 *) 509 // + 3 = 2^9 (* 172 *) 1021 // + 3 = 2^10 (* 309 *) 2039 // + 9 = 2^11 (* 564 *) 4093 // + 3 = 2^12 (* 1028 *) 8191 // + 1 = 2^13 (* 1900 *) 16381 // + 3 = 2^14 (* 3512 *) 32749 // + 19 = 2^15 (* 6542 *) 65521 // + 15 = 2^16 (* 12251 *) 131071 // + 1 = 2^17 (* 23000 *) 262139 // + 5 = 2^18 (* 43390 *) 524287 // + 1 = 2^19 (* 82025 *) 1048573 // + 3 = 2^20 (* 155611 *) 2097143 // + 9 = 2^21 (* 295947 *) 4194301 // + 3 = 2^22 (* 564163 *) 8388593 // + 15 = 2^23 (* 1077871 *) 16777213 // + 3 = 2^24 (* 2063689 *) 33554393 // + 39 = 2^25 (* 3957809 *) 67108859 // + 5 = 2^26 (* 7603553 *) 134217689 // + 39 = 2^27 (* 14630843 *) 268435399 // + 57 = 2^28 (* 28192750 *) 536870909 // + 3 = 2^29 (* 54400028 *) 1073741789 // + 35 = 2^30 (* 105097565 *) 2147483647 // + 1 = 2^31 |] let empty = { size = 0L pointer = Unchecked.defaultof<_> header = ptr<_>.Null entries = ptr<_>.Null buckets = ptr<_>.Null } let private isDict (ptr : ptr) = ptr.Read() = magic let create (mem : Memory) (capacityIndex : int) = let capacity = primeSizes.[capacityIndex] // create a new dictionary let size = sh + int64 capacity * (se + si) mem.Clear size let pHeader = Ptr.cast mem let pEntries = Ptr.cast (mem + sh) let pBuckets = Ptr.cast (mem + sh + (int64 capacity * se)) pHeader != DictHeader( Magic = magic, CapacityIndex = capacityIndex, Capacity = capacity, FreeList = -1, Count = 0, FreeCount = 0 ) { size = size pointer = mem header = pHeader entries = pEntries buckets = pBuckets } let getOrCreate (mem : Memory) (capacityIndex : int) = if mem.Size >= 8L && isDict mem then // read the dictionary let size = mem.Size let mapName = Guid.NewGuid() |> string let pHeader = Ptr.cast mem let header : DictHeader = !!pHeader let pEntries = Ptr.cast (mem + nativeint sh) let pBuckets = Ptr.cast (mem + nativeint sh + nativeint (int64 header.Capacity * se)) { size = size pointer = mem header = pHeader entries = pEntries buckets = pBuckets } else create mem capacityIndex let realloc (store : DictStore) (capacityIndex : int) = let capacity = primeSizes.[capacityIndex] let size = sh + int64 capacity * (se + si) store.pointer.Realloc(size) let pHeader = Ptr.cast store.pointer let pEntries = Ptr.cast (store.pointer + sh) let pBuckets = Ptr.cast (store.pointer + sh + (int64 capacity * se)) Marshal.Set(pBuckets.Pointer, 0, unativeint (sizeof * capacity)) pHeader.CapacityIndex <- capacityIndex pHeader.Capacity <- capacity { size = size pointer = store.pointer header = pHeader entries = pEntries buckets = pBuckets } let release (s : DictStore) = s.pointer.Dispose() type FileTable(mem : Memory) = static let initialExp = 10 let mutable store = DictStore.getOrCreate mem (initialExp - 3) let mutable header = store.header member private x.Grow () : unit = // TODO: backup!!!! let oldHeader = !!header let newCapacityIndex = 1 + oldHeader.CapacityIndex let count = oldHeader.Count store <- DictStore.realloc store newCapacityIndex header <- store.header let cap = header.Capacity let mutable pEntry = store.entries for i in 0 .. count-1 do if not (pEntry.Key == Guid.Empty) then let bucket = pEntry.HashCode % cap pEntry.Next <- store.buckets.[bucket] - 1 store.buckets.[bucket] <- i + 1 pEntry <- pEntry .+ 1 // TODO: remove backup () member private x.FindEntry(key : Guid, hashCode : int) = let index = hashCode % header.Capacity let id = store.buckets.[index] - 1 if id < 0 then -1 else let mutable pEntry = store.entries .+ id if pEntry.HashCode = hashCode && pEntry.Key == key then id else let next = pEntry.Next if next >= 0 then let rec search (id : int) (pEntry : ptr) = if pEntry.HashCode = hashCode && pEntry.Key == key then id else let next = pEntry.Next if next >= 0 then search next (store.entries .+ pEntry.Next) else -1 search next (store.entries .+ next) else -1 member private x.FindEntry(key : Guid) = let hashCode = key.GetHashCode() &&& 0x7FFFFFFF x.FindEntry(key, hashCode) member private x.Set(key : Guid, offset : int64, size : int64) = let hashCode = key.GetHashCode() &&& 0x7FFFFFFF let mutable index = hashCode % header.Capacity let id = x.FindEntry(key, hashCode) if id >= 0 then let p = store.entries .+ id p.Offset <- offset p.Size <- size else let freeCount = header.FreeCount let entryId = if freeCount > 0 then let newBucket = header.FreeList header.FreeList <- (store.entries .+ newBucket).Next header.FreeCount <- freeCount - 1 newBucket else let count = header.Count if count = header.Capacity then x.Grow() index <- hashCode % header.Capacity header.Count <- count + 1 count let pEntry = store.entries .+ entryId let pBucket = store.buckets .+ index pEntry.Key <- key pEntry.Offset <- offset pEntry.Size <- size pEntry.HashCode <- hashCode pEntry.Next <- !!pBucket - 1 pBucket != 1 + entryId member private x.Get(key : Guid) = let id = x.FindEntry(key) if id < 0 then failwithf "key not found: %A" key else let p = store.entries .+ id (p.Offset, p.Size) member x.Remove(key : Guid) = let hashCode = key.GetHashCode() &&& 0x7FFFFFFF let index = hashCode % header.Capacity let id = store.buckets.[index] - 1 if id < 0 then false else let pEntry = store.entries .+ id let mutable entryId = -1 if pEntry.HashCode = hashCode && pEntry.Key == key then store.buckets.[index] <- pEntry.Next + 1 entryId <- id else let next = pEntry.Next if next >= 0 then let rec search (pLast : ptr) (id : int) (pEntry : ptr) = if pEntry.HashCode = hashCode && pEntry.Key == key then pLast.Next <- pEntry.Next entryId <- id else let next = pEntry.Next if next >= 0 then search pEntry next (store.entries .+ pEntry.Next) search pEntry next (store.entries .+ next) if entryId >= 0 then let pEntry = store.entries .+ entryId let nextFree = if header.FreeCount > 0 then header.FreeList else -1 pEntry != Entry(Guid.Empty, 0L, 0L, -1, nextFree) header.FreeList <- entryId header.FreeCount <- header.FreeCount + 1 true else false member x.TryGetValue(key : Guid, [] value : byref) = let id = x.FindEntry(key) if id < 0 then false else let p = store.entries .+ id value <- (p.Offset, p.Size) true member x.Count = header.Count - header.FreeCount member x.Item with get (key : Guid) = x.Get key and set (key : Guid) (offset : int64, size : int64) = x.Set(key, offset, size) member x.GetOrAdd(key : Guid, f : Guid -> int64 * int64) = let hashCode = key.GetHashCode() &&& 0x7FFFFFFF let mutable index = hashCode % header.Capacity let id = x.FindEntry(key, hashCode) if id >= 0 then let p = store.entries .+ id (p.Offset, p.Size) else let offset, size = f key let freeCount = header.FreeCount let entryId = if freeCount > 0 then let newBucket = header.FreeList header.FreeList <- (store.entries .+ newBucket).Next header.FreeCount <- freeCount - 1 newBucket else let count = header.Count if count = header.Capacity then x.Grow() index <- hashCode % header.Capacity header.Count <- count + 1 count let pEntry = store.entries .+ entryId let pBucket = store.buckets .+ index pEntry.Key <- key pEntry.Offset <- offset pEntry.Size <- size pEntry.HashCode <- hashCode pEntry.Next <- !!pBucket - 1 pBucket != 1 + entryId (offset, size) member x.ContainsKey (key : Guid) = let id = x.FindEntry(key) id >= 0 member x.Dispose() = DictStore.release store store <- DictStore.empty interface IDisposable with member x.Dispose() = x.Dispose() interface System.Collections.IEnumerable with member x.GetEnumerator() = new FileDictEnumerator(store) :> _ interface System.Collections.Generic.IEnumerable with member x.GetEnumerator() = new FileDictEnumerator(store) :> _ and private FileDictEnumerator(store : DictStore) = static let nullPtr : ptr = ptr<_>.Null let cnt = store.header.Count let mutable i = -1 let mutable ptr = store.entries .+ -1 member x.MoveNext() = i <- i + 1 ptr <- ptr .+ 1 while i < cnt && (store.entries .+ i).HashCode < 0 do i <- i + 1 ptr <- ptr .+ 1 i < cnt member x.Current : Entry = !!ptr member x.Reset() = i <- -1 ptr <- store.entries .+ -1 interface System.Collections.IEnumerator with member x.Current = x.Current :> obj member x.MoveNext() = x.MoveNext() member x.Reset() = x.Reset() interface IEnumerator with member x.Current = x.Current member x.Dispose() = () ================================================ FILE: src/Aardvark.Base.FSharp/Native/Manager.fs ================================================ namespace Aardvark.Base.Native open System open System.Threading open System.Runtime.CompilerServices open Aardvark.Base type MemoryManager(store : Memory) as this = let mutable capacity = store.Size let mutable allocated = 0L let free = FreeList() let mutable first : Block = null let mutable last : Block = null do if store.Size <> 0L then let b = Block(this, 0L, store.Size) free.Insert(b.Size, b) first <- b last <- b let mutable pointer = new ReaderWriterLockSlim() member x.ReadEntries(entries : array<'a * int64 * int64>, newBlock : 'a -> Block -> unit) = lock x (fun () -> if entries.Length > 0 then let (_,lo,ls) = entries.[entries.Length-1] let maxUsed = lo + ls x.Resize(false, maxUsed + 1L) free.Clear() let mutable current = first let mutable offset = first.Size for (name, off, size) in entries do if off <> offset then let between = Block(x, offset, off - offset, Prev = current, Next = null, IsFree = true) free.Insert(between.Size, between) offset <- off current <- between let b = Block(x, off, size, Prev = current, Next = null, IsFree = false) current.Next <- b offset <- offset + size allocated <- allocated + size newBlock name b current <- b let off = current.Offset + current.Size if off < capacity then let between = Block(x, off, capacity - off, Prev = current, Next = null, IsFree = true) free.Insert(between.Size, between) last <- between else last <- current ) member x.FillRate = float allocated / float capacity member x.Allocated = allocated member x.Capacity = capacity member x.Compact() = lock x (fun () -> let mutable offset = 0L let mutable prev = null let mutable current = first free.Clear() while not (isNull current) do if not current.IsFree then let pSource = store + current.Offset let pTarget = store + offset let temp = Array.zeroCreate (int current.Size) pSource.Read(temp, 0L, temp.LongLength) //mem.Read(store.Value, current.Offset, temp, 0L, temp.LongLength) current.Offset <- offset current.Prev <- prev if isNull prev then first <- current else prev.Next <- current pTarget.Write(temp, 0L, temp.LongLength) offset <- offset + current.Size prev <- current current <- current.Next let off = current.Offset + current.Size if off < capacity then let between = Block(x, off, capacity - off, Prev = current, Next = null, IsFree = true) free.Insert(between.Size, between) last <- between else last <- current x.Resize(true, off) ) member private x.Swap(l : Block, r : Block) = let l,r = if l.Offset < r.Offset then l,r else r,l Fun.Swap(&l.Offset, &r.Offset) Fun.Swap(&l.Size, &r.Size) if l.IsFree || r.IsFree then failwith "[MemoryManager] cannot swap free blocks" if l.Next = r then if isNull l.Prev then first <- r r.Prev <- null else r.Prev <- l.Prev if isNull r.Next then last <- l l.Next <- null else l.Next <- r.Next r.Next <- l l.Prev <- r else Fun.Swap(&l.Next, &r.Next) Fun.Swap(&l.Prev, &r.Prev) if isNull l.Next then last <- l else l.Next.Prev <- l if isNull l.Prev then first <- l else l.Prev.Next <- l if isNull r.Next then last <- r else r.Next.Prev <- r if isNull r.Prev then first <- r else r.Prev.Next <- r member private x.Resize (hard : bool, minCapacity : int64) = lock x (fun () -> let c = if hard then minCapacity else Fun.NextPowerOfTwo (max 1024L minCapacity) if c <> capacity then ReaderWriterLock.write pointer (fun () -> store.Realloc(c) if c > capacity then let newBlock = Block(x, capacity, c - capacity, Prev = last, Next = null, IsFree = false) if not (isNull last) then last.Next <- newBlock allocated <- allocated + newBlock.Size x.Free newBlock else if last.IsFree && last.Offset <= c then free.Remove(last.Size, last) |> ignore last.Size <- c - last.Offset free.Insert(last.Size, last) else Log.warn "cannot shrink" capacity <- c ) ) member x.Free (b : Block) = lock b (fun () -> if not b.IsFree then lock x (fun () -> let prev = b.Prev let next = b.Next if isNull prev then first <- b elif prev.IsFree then free.Remove(prev.Size, prev) |> ignore b.Offset <- prev.Offset b.Size <- b.Size + prev.Size b.Prev <- prev.Prev if isNull b.Prev then first <- b else b.Prev.Next <- b if isNull next then last <- b elif next.IsFree then free.Remove(next.Size, next) |> ignore b.Size <- b.Size + next.Size b.Next <- next.Next if isNull b.Next then last <- b else b.Next.Prev <- b allocated <- allocated - b.Size free.Insert(b.Size, b) b.IsFree <- true ) ) member x.Alloc (size : int64) = lock x (fun () -> match free.TryGetGreaterOrEqualV(size) with | ValueSome b -> b.IsFree <- false if b.Size > size then let n = Block(x, b.Offset + size, b.Size - size, Prev = b, Next = b.Next, IsFree = false) if isNull n.Next then last <- n else n.Next.Prev <- n b.Next <- n b.Size <- size x.Free n allocated <- allocated + size b | ValueNone -> x.Resize(false, capacity + size) x.Alloc(size) ) member x.Realloc (b : Block, newSize : int64) = lock b (fun () -> lock x (fun () -> if b.Size <> newSize then let n = x.Alloc(newSize) x.Swap(b, n) x.Free(n) // let mutable missing = newSize - b.Size // if missing > 0L then // let next = b.Next // if not (isNull next) && next.IsFree && next.Size >= missing then // free.Remove(next.Size, next) |> ignore // next.Offset <- next.Offset + missing // next.Size <- next.Size - missing // free.Insert(next.Size, next) // allocated <- allocated + missing // // b.Size <- newSize // else // let n = x.Alloc(newSize) // x.Swap(b, n) // x.Free(n) // // // elif missing < 0L then // let rest = Block(x, b.Offset + newSize, b.Size + missing, Prev = b, Next = b.Next, IsFree = false) // // if isNull rest.Next then last <- rest // else rest.Next.Prev <- rest // b.Next <- rest // // b.Size <- newSize // // else // () ) ) member x.Write (b : Block, data : byte[]) = lock b (fun () -> if b.IsFree then failwith "out of range" let ptr = store + b.Offset ReaderWriterLock.read pointer (fun () -> ptr.Write(data, 0L, data.LongLength) ) ) member x.Read (b : Block, data : byte[]) = lock b (fun () -> if b.IsFree then failwith "out of range" let ptr = store + b.Offset ReaderWriterLock.read pointer (fun () -> ptr.Read(data, 0L, data.LongLength) ) ) member x.Dispose() = lock x (fun () -> store.Free() capacity <- 0L free.Clear() first <- null last <- null pointer.Dispose() ) interface IDisposable with member x.Dispose() = x.Dispose() and [] Block = class val mutable public Memory : MemoryManager val mutable public Offset : int64 val mutable public Size : int64 val mutable public Next : Block val mutable public Prev : Block val mutable public IsFree : bool //member x.Write(source : nativeint, size : int64) = x.Memory.Write(x, source, size) new(mem, off, size) = { Memory = mem; Offset = off; Size = size; Prev = null; Next = null; IsFree = true } end [] type BlockExtensions private() = [] static member Realloc(this : Block, size : int64) = this.Memory.Realloc(this, size) [] static member Read(this : Block, target : byte[]) = this.Memory.Read(this, target) [] static member Write(this : Block, source : byte[]) = this.Memory.Write(this, source) [] static member Read(this : Block) = let target : byte[] = Array.zeroCreate (int this.Size) this.Memory.Read(this, target) target ================================================ FILE: src/Aardvark.Base.FSharp/Native/Memory.fs ================================================ namespace Aardvark.Base.Native open System open System.Threading open System.IO open System.IO.MemoryMappedFiles open System.Runtime.InteropServices open Aardvark.Base module OldImpl = [] type Memory() = abstract member Alloc : int64 -> sizedptr abstract member Free : sizedptr -> unit abstract member Realloc : sizedptr * int64 -> unit [] module Memory = type private Ptr = class inherit sizedptr val mutable public Value : nativeint val mutable public PointerSize : int64 override x.Pointer = x.Value override x.IsValid = x.Value <> 0n override x.Size = x.PointerSize new(v, s) = { Value = v; PointerSize = s} end type private FilePtr = class inherit sizedptr val mutable public FileSize : int64 val mutable public Path : Option val mutable public MapName : string val mutable public File : MemoryMappedFile val mutable public Accessor : MemoryMappedViewAccessor val mutable public Value : nativeint override x.Pointer = x.Value override x.IsValid = x.Value <> 0n override x.Size = x.FileSize new(size, path, name, file, acc, value) = { FileSize = size; Path = path; MapName = name; File = file; Accessor = acc; Value = value } end type private ManagedPtr = class inherit sizedptr val mutable public Array : byte[] val mutable public Handle : GCHandle val mutable public Value : nativeint override x.Pointer = x.Value override x.IsValid = x.Value <> 0n override x.Size = if isNull x.Array then 0L else x.Array.LongLength new(arr, handle, value) = { Array = arr; Handle = handle; Value = value } end type private ViewPointer = class inherit sizedptr val mutable public Base : ptr val mutable public Offset : nativeint val mutable public PointerSize : int64 override x.IsValid = x.Base.IsValid override x.Pointer = x.Base.Pointer + x.Offset override x.Size = x.PointerSize new(ptr, o, s) = { Base = ptr; Offset = o; PointerSize = s } end let managed = { new Memory() with member x.Alloc(size) = let arr = Array.zeroCreate (int size) let gc = GCHandle.Alloc(arr, GCHandleType.Pinned) let v = gc.AddrOfPinnedObject() ManagedPtr(arr, gc, v) :> _ member x.Free(ptr) = let ptr = unbox ptr ptr.Handle.Free() ptr.Array <- null ptr.Handle <- Unchecked.defaultof<_> ptr.Value <- 0n member x.Realloc(ptr, size) = let ptr = unbox ptr ptr.Handle.Free() Array.Resize(&ptr.Array, int size) let gc = GCHandle.Alloc(ptr.Array, GCHandleType.Pinned) let v = gc.AddrOfPinnedObject() ptr.Handle <- gc ptr.Value <- v } let hglobal = { new Memory() with member x.Alloc(size) = Ptr(Marshal.AllocHGlobal(nativeint size), size) :> _ member x.Free(ptr) = let ptr = unbox ptr Marshal.FreeHGlobal ptr.Value ptr.Value <- 0n member x.Realloc(ptr, size) = let ptr = unbox ptr ptr.Value <- Marshal.ReAllocHGlobal(ptr.Value, nativeint size) } let cotask = { new Memory() with member x.Alloc(size) = Ptr(Marshal.AllocCoTaskMem(int size), size) :> _ member x.Free(ptr) = let ptr = unbox ptr Marshal.FreeCoTaskMem ptr.Value ptr.Value <- 0n member x.Realloc(ptr, size) = let ptr = unbox ptr ptr.Value <- Marshal.ReAllocCoTaskMem(ptr.Value, int size) } let newFile (path : string) = { new Memory() with member x.Alloc(size) = let mapName = Guid.NewGuid() |> string let file = MemoryMappedFile.CreateFromFile(path, FileMode.Create, mapName, size, MemoryMappedFileAccess.ReadWrite) let acc = file.CreateViewAccessor() let ptr = acc.SafeMemoryMappedViewHandle.DangerousGetHandle() FilePtr(size, Some path, mapName, file, acc, ptr) :> _ member x.Free(ptr) = let ptr = unbox ptr ptr.Accessor.Dispose() ptr.File.Dispose() ptr.FileSize <- 0L ptr.Path <- None ptr.MapName <- null ptr.File <- null ptr.Accessor <- null ptr.Value <- 0n member x.Realloc(ptr, size) = let ptr = unbox ptr ptr.Accessor.Dispose() ptr.File.Dispose() let file = MemoryMappedFile.CreateFromFile(ptr.Path.Value, FileMode.Open, ptr.MapName, size, MemoryMappedFileAccess.ReadWrite) let acc = file.CreateViewAccessor() let value = acc.SafeMemoryMappedViewHandle.DangerousGetHandle() ptr.FileSize <- size ptr.File <- file ptr.Accessor <- acc ptr.Value <- value } let ofFile (path : string) = let ptr = if File.Exists path then let size = FileInfo(path).Length let mapName = Guid.NewGuid() |> string let file = MemoryMappedFile.CreateFromFile(path, FileMode.Open, mapName, size, MemoryMappedFileAccess.ReadWrite) let acc = file.CreateViewAccessor() let value = acc.SafeMemoryMappedViewHandle.DangerousGetHandle() FilePtr(size, Some path, mapName, file, acc, value) :> sizedptr else sizedptr.Null let heap = newFile path ptr, heap let split (mem : Memory) = let real = mem.Alloc(8L) let leftSizePtr = Ptr.cast real let leftSize = leftSizePtr.Value let mutable total = 0L let leftPtr = ViewPointer(real, 8n, leftSize) let rightPtr = ViewPointer(real, 8n + nativeint leftSize, real.Size - leftSize) let mutable live = 0 let left = { new Memory() with member x.Realloc(old : sizedptr, size : int64) = if size <> leftPtr.PointerSize then let rightShift = size - leftPtr.PointerSize leftPtr.PointerSize <- size leftSizePtr.Value <- size // if the overall size changed realloc the underlying store let newTotal = size + rightPtr.PointerSize if total <> newTotal then mem.Realloc(real, 8L + newTotal) total <- newTotal // move the right-block if rightPtr.PointerSize > 0L then let newRight = rightPtr + rightShift Marshal.Move(rightPtr.Pointer, newRight.Pointer, rightPtr.PointerSize) rightPtr.Offset <- nativeint leftPtr.PointerSize member x.Alloc s = Interlocked.Increment(&live) |> ignore x.Realloc(sizedptr.Null, s) leftPtr :> sizedptr member x.Free(ptr) = if Interlocked.Decrement(&live) = 0 then mem.Free(real) } let right = { new Memory() with member x.Realloc(old : sizedptr, size : int64) = if size <> rightPtr.PointerSize then rightPtr.PointerSize <- size // if the overall size changed realloc the underlying store let newTotal = leftPtr.PointerSize + size if total <> newTotal then mem.Realloc(real, 8L + newTotal) total <- newTotal member x.Alloc s = Interlocked.Increment(&live) |> ignore x.Realloc(sizedptr.Null, s) rightPtr :> _ member x.Free(ptr) = if Interlocked.Decrement(&live) = 0 then mem.Free(real) } left, right [] module NewImpl = [] type Memory() = inherit sizedptr() abstract member Clear : int64 -> unit abstract member Realloc : int64 -> unit abstract member Free : unit -> unit member private x.Dispose(disposing : bool) = if x.IsValid then if disposing then GC.SuppressFinalize x x.Free() member x.Dispose() = x.Dispose(true) override x.Finalize() = x.Dispose(false) interface IDisposable with member x.Dispose() = x.Dispose(true) [] module Memory = type HGlobalMemory(size : int64) = inherit Memory() let mutable size = size let mutable ptr = Marshal.AllocHGlobal (nativeint size) override x.IsValid = ptr <> 0n override x.Pointer = ptr override x.Size = size override x.Realloc (newSize : int64) = if newSize <> size then ptr <- Marshal.ReAllocHGlobal(ptr, nativeint newSize) size <- newSize override x.Clear(newSize : int64) = Marshal.FreeHGlobal(ptr) ptr <- Marshal.AllocHGlobal (nativeint newSize) Marshal.Set(ptr, 0, newSize) size <- newSize override x.Free() = let p = Interlocked.Exchange(&ptr, 0n) if p <> 0n then size <- 0L Marshal.FreeHGlobal p type CoTaskMemory(size : int64) = inherit Memory() let mutable size = size let mutable ptr = Marshal.AllocCoTaskMem (int size) override x.IsValid = ptr <> 0n override x.Pointer = ptr override x.Size = size override x.Realloc (newSize : int64) = if newSize <> size then ptr <- Marshal.ReAllocCoTaskMem(ptr, int newSize) size <- newSize override x.Clear(newSize : int64) = Marshal.FreeCoTaskMem(ptr) ptr <- Marshal.AllocCoTaskMem (int newSize) size <- newSize override x.Free() = let p = Interlocked.Exchange(&ptr, 0n) if p <> 0n then size <- 0L Marshal.FreeCoTaskMem p type FileOperation = | Open of string | Create of string * int64 type MappedFileMemory(file : FileOperation) = inherit Memory() let mapName = Guid.NewGuid() |> string let mutable fileName, file, size = match file with | Open(fileName) -> if File.Exists fileName then let info = FileInfo(fileName) let file = MemoryMappedFile.CreateFromFile(fileName, FileMode.Open, mapName, info.Length, MemoryMappedFileAccess.ReadWrite) fileName, file, info.Length else let file = MemoryMappedFile.CreateFromFile(fileName, FileMode.Create, mapName, 4096L, MemoryMappedFileAccess.ReadWrite) fileName, file, 4096L | Create(fileName, capacity) -> let file = MemoryMappedFile.CreateFromFile(fileName, FileMode.Create, mapName, capacity, MemoryMappedFileAccess.ReadWrite) fileName, file, capacity let mutable accessor = file.CreateViewAccessor() let mutable ptr = accessor.SafeMemoryMappedViewHandle.DangerousGetHandle() override x.IsValid = not (isNull file) override x.Pointer = ptr override x.Size = size override x.Realloc (newSize : int64) = if newSize <> size then accessor.Dispose() file.Dispose() file <- MemoryMappedFile.CreateFromFile(fileName, FileMode.Open, mapName, newSize, MemoryMappedFileAccess.ReadWrite) accessor <- file.CreateViewAccessor() ptr <- accessor.SafeMemoryMappedViewHandle.DangerousGetHandle() size <- newSize override x.Clear (newSize : int64) = accessor.Dispose() file.Dispose() file <- MemoryMappedFile.CreateFromFile(fileName, FileMode.Create, mapName, newSize, MemoryMappedFileAccess.ReadWrite) accessor <- file.CreateViewAccessor() ptr <- accessor.SafeMemoryMappedViewHandle.DangerousGetHandle() size <- newSize override x.Free() = let f = Interlocked.Exchange(&file, null) if not (isNull f) then accessor.Dispose() f.Dispose() fileName <- null file <- null size <- 0L accessor <- null ptr <- 0n let hglobal (size : int64) = new HGlobalMemory(size) :> Memory let cotask (size : int64) = new CoTaskMemory(size) :> Memory let mapped (file : string) = new MappedFileMemory(Open file) :> Memory type private ViewPointer = class inherit sizedptr val mutable public Base : ptr val mutable public Offset : nativeint val mutable public PointerSize : int64 override x.IsValid = x.Base.IsValid override x.Pointer = x.Base.Pointer + x.Offset override x.Size = x.PointerSize new(ptr, o, s) = { Base = ptr; Offset = o; PointerSize = s } end let split (mem : Memory) = let leftSizePtr = Ptr.cast mem let mutable leftSize = if mem.Size < 8L then mem.Clear 8L 0L else leftSizePtr.Value let mutable rightSize = mem.Size - leftSize - 8L let mutable live = 2 let left = { new Memory() with override x.IsValid = mem.IsValid override x.Pointer = mem.Pointer + 8n override x.Size = leftSize override x.Realloc (newSize : int64) = if newSize > leftSize then // realloc the underlying memory mem.Realloc (8L + newSize + rightSize) // move the right memory let rightShift = newSize - leftSize let rightStart = mem.Pointer + 8n + nativeint leftSize Marshal.Move(rightStart, rightStart + nativeint rightShift, rightSize) // set the new left-memory to 0 Marshal.Set(rightStart, 0, rightShift) // store the new leftSize leftSizePtr.Value <- newSize leftSize <- newSize elif newSize < leftSize then // move the right memory let rightShift = newSize - leftSize let rightStart = mem.Pointer + 8n + nativeint leftSize Marshal.Move(rightStart, rightStart + nativeint rightShift, rightSize) // realloc the underlying memory mem.Realloc (8L + newSize + rightSize) // store the new leftSize leftSizePtr.Value <- newSize leftSize <- newSize override x.Clear (newSize : int64) = if newSize > leftSize then // realloc the underlying memory mem.Realloc (8L + newSize + rightSize) // move the right memory let rightShift = newSize - leftSize let rightStart = mem.Pointer + 8n + nativeint leftSize Marshal.Move(rightStart, rightStart + nativeint rightShift, rightSize) // set the left-memory to 0 Marshal.Set(mem.Pointer + 8n, 0, newSize) // store the new leftSize leftSizePtr.Value <- newSize leftSize <- newSize elif newSize < leftSize then // move the right memory let rightShift = newSize - leftSize let rightStart = mem.Pointer + 8n + nativeint leftSize Marshal.Move(rightStart, rightStart + nativeint rightShift, rightSize) // realloc the underlying memory mem.Realloc (8L + newSize + rightSize) // set the left-memory to 0 Marshal.Set(mem.Pointer + 8n, 0, newSize) // store the new leftSize leftSizePtr.Value <- newSize leftSize <- newSize else Marshal.Set(mem.Pointer + 8n, 0, leftSize) override x.Free() = if Interlocked.Decrement(&live) = 0 then mem.Free() } let right = { new Memory() with override x.IsValid = mem.IsValid override x.Pointer = mem.Pointer + 8n + nativeint leftSize override x.Size = rightSize override x.Realloc (newSize : int64) = if newSize > rightSize then // realloc the underlying memory mem.Realloc (8L + leftSize + newSize) // store the new leftSize rightSize <- newSize elif newSize < leftSize then // realloc the leftSize memory mem.Realloc (8L + leftSize + newSize) // store the new leftSize rightSize <- newSize override x.Clear (newSize : int64) = x.Realloc(newSize) Marshal.Set(mem.Pointer + 8n + nativeint leftSize, 0, newSize) override x.Free() = if Interlocked.Decrement(&live) = 0 then mem.Free() } left, right ================================================ FILE: src/Aardvark.Base.FSharp/Native/Pointer.fs ================================================ namespace Aardvark.Base.Native #nowarn "9" open System.Runtime.InteropServices open Microsoft.FSharp.NativeInterop open Aardvark.Base [] type ptr() = static let nullptr = { new ptr() with member x.Pointer = 0n member x.IsValid = false } abstract member Pointer : nativeint abstract member IsValid : bool abstract member RealPointer : ptr default x.RealPointer = x member inline x.Read<'a when 'a : unmanaged>() = NativePtr.read (NativePtr.ofNativeInt<'a> x.Pointer) member inline x.Write<'a when 'a : unmanaged>(value : 'a) = NativePtr.write (NativePtr.ofNativeInt<'a> x.Pointer) value member inline x.Get<'a when 'a : unmanaged>(index : int) = NativePtr.get (NativePtr.ofNativeInt<'a> x.Pointer) index member inline x.Set<'a when 'a : unmanaged>(index : int, value : 'a) = NativePtr.set (NativePtr.ofNativeInt<'a> x.Pointer) index value member x.Write(source : byte[], offset : int64, length : int64) = let gc = GCHandle.Alloc(source, GCHandleType.Pinned) try let src = gc.AddrOfPinnedObject() Marshal.Copy(src + nativeint offset, x.Pointer, length) finally gc.Free() member x.Read(target : byte[], offset : int64, length : int64) = let gc = GCHandle.Alloc(target, GCHandleType.Pinned) try let src = gc.AddrOfPinnedObject() Marshal.Copy(x.Pointer, src + nativeint offset, length) finally gc.Free() member inline x.CopyTo(target : nativeint, length : int64) = Marshal.Copy(x.Pointer, target, length) member inline x.CopyTo(target : ptr, length : int64) = Marshal.Copy(x.Pointer, target.Pointer, length) member x.CopyTo(target : byte[], offset : int64, length : int64) = let gc = GCHandle.Alloc(target, GCHandleType.Pinned) try let src = gc.AddrOfPinnedObject() Marshal.Copy(x.Pointer, src + nativeint offset, length) finally gc.Free() member inline x.CopyFrom(source : nativeint, length : int64) = Marshal.Copy(source, x.Pointer, length) member inline x.CopyFrom(source : ptr, length : int64) = Marshal.Copy(source.Pointer, x.Pointer, length) member x.CopyFrom(source : byte[], offset : int64, length : int64) = let gc = GCHandle.Alloc(source, GCHandleType.Pinned) try let src = gc.AddrOfPinnedObject() Marshal.Copy(src + nativeint offset, x.Pointer, length) finally gc.Free() member x.ToByteArray (length : int64) = let arr : byte[] = Array.zeroCreate (int length) x.CopyTo(arr, 0L, length) arr override x.ToString() = sprintf "ptr 0x%X" x.Pointer override x.GetHashCode() = if x.IsValid then x.Pointer.GetHashCode() else 0 override x.Equals o = match o with | :? ptr as o -> match x.IsValid, o.IsValid with | true, true -> x.Pointer = o.Pointer | false, false -> true | _ -> false | _ -> false static member Zero = nullptr static member Null = nullptr static member (+) (p : ptr, offset : nativeint) = match p with | :? ViewPointer as vp -> let o = vp.Offset + offset if o = 0n then vp.Source else ViewPointer(vp.Source, o) :> ptr | _ -> ViewPointer(p, offset) :> ptr static member inline (-) (p : ptr, offset : nativeint) = p + (-offset) static member inline (+) (p : ptr, offset : 'a) = p + nativeint offset static member inline (-) (p : ptr, offset : 'a) = p + nativeint -offset static member inline (+) (offset : nativeint, p : ptr) = p + offset static member inline (+) (offset : 'a, p : ptr) = p + nativeint offset static member inline op_Equality (ptr : ptr, v : nativeint) = ptr.Pointer = v and private ViewPointer(p : ptr, offset : nativeint) = inherit ptr() member x.Source = p member x.Offset = offset override x.IsValid = p.IsValid override x.Pointer = p.Pointer + offset type ptr<'a when 'a : unmanaged>(p : ptr) = inherit ptr() static let nullptr = ptr<'a>(ptr.Null) static let sa = sizeof<'a> static let sa64 = int64 sa override x.Pointer = p.Pointer override x.RealPointer = p override x.IsValid = p.IsValid static member Zero = nullptr static member Null = nullptr member x.Item with get (i : int) : 'a = NativePtr.get (NativePtr.ofNativeInt p.Pointer) i and set (i : int) (value : 'a) = NativePtr.set (NativePtr.ofNativeInt p.Pointer) i value member x.Value with get() : 'a = NativePtr.read (NativePtr.ofNativeInt p.Pointer) and set (v : 'a) = NativePtr.write (NativePtr.ofNativeInt p.Pointer) v member x.CopyTo(target : nativeint, count : int64) = Marshal.Copy(x.Pointer, target, sa64 * count) member x.CopyTo(target : ptr, count : int64) = Marshal.Copy(x.Pointer, target.Pointer, sa64 * count) member x.CopyTo(target : ptr<'a>, count : int64) = Marshal.Copy(x.Pointer, target.Pointer, sa64 * count) member x.CopyTo(target : 'a[], offset : int64, count : int64) = let gc = GCHandle.Alloc(target, GCHandleType.Pinned) try let src = gc.AddrOfPinnedObject() Marshal.Copy(x.Pointer, src + nativeint offset * nativeint sa, count * sa64) finally gc.Free() member x.CopyFrom(source : nativeint, count : int64) = Marshal.Copy(source, x.Pointer, sa64 * count) member x.CopyFrom(source : ptr, count : int64) = Marshal.Copy(source.Pointer, x.Pointer, sa64 * count) member x.CopyFrom(source : ptr<'a>, count : int64) = Marshal.Copy(source.Pointer, x.Pointer, sa64 * count) member x.CopyFrom(source : 'a[], offset : int64, count : int64) = let gc = GCHandle.Alloc(source, GCHandleType.Pinned) try let src = gc.AddrOfPinnedObject() Marshal.Copy(src + nativeint offset * nativeint sa, x.Pointer, count * sa64) finally gc.Free() member x.ToArray(count : int) = let target : 'a[] = Array.zeroCreate count x.CopyTo(target, 0L, int64 count) target static member (+) (l : ptr<'a>, index : int) = ptr<'a>(l.RealPointer + sa * index) static member (-) (l : ptr<'a>, index : int) = ptr<'a>(l.RealPointer - sa * index) static member (+) (l : ptr<'a>, index : int64) = ptr<'a>(l.RealPointer + sa64 * index) static member (-) (l : ptr<'a>, index : int64) = ptr<'a>(l.RealPointer - sa64 * index) [] type sizedptr() = inherit ptr() static let nullptr = { new sizedptr() with member x.Pointer = 0n member x.IsValid = false member x.Size = 0L } static member Null = nullptr static member Zero = nullptr abstract member Size : int64 [] module Ptr = let zero = ptr.Zero let inline isValid (p : ptr) = p.IsValid let inline isNull (p : ptr) = not p.IsValid let inline cast<'a when 'a : unmanaged> (p : ptr) : ptr<'a> = ptr<'a>(p.RealPointer) let inline get (i : int) (p : ptr<'a>) = p.[i] let inline set (i : int) (value : 'a) (p : ptr<'a>) = p.[i] <- value let inline read (p : ptr<'a>) = p.Value let inline write (value : 'a) (p : ptr<'a>) = p.Value <- value let inline toByteArray (length : int64) (ptr : ptr) = ptr.ToByteArray(length) let inline toArray (length : int) (ptr : ptr<'a>) = ptr.ToArray(length) ================================================ FILE: src/Aardvark.Base.FSharp/Native/Store.fs ================================================ namespace Aardvark.Base.Native #nowarn "9" open System open System.Diagnostics open System.Runtime.InteropServices open Aardvark.Base open Microsoft.FSharp.NativeInterop open System.Threading open System.IO module FileManagerTypes = let inline (++) (ptr : nativeptr<'a>) (v : 'a) = NativePtr.add ptr (int v) let inline (!!) (ptr : nativeptr<'a>) = NativePtr.read ptr let inline (<--) (ptr : nativeptr<'a>) c = NativePtr.write ptr c let magic = Guid("CFD123CA-17BC-437A-9EFC-6EECE27188FF") [] let Red = 0 [] let Black = 1 [] type Block = struct [] val mutable public Offset : int64 [] val mutable public Size : int64 [] val mutable public IsFree : int [] val mutable public Prev : int [] val mutable public Next : int [] val mutable public Chunk : int static member Invalid = Block(Offset = -1L, Size = -1L, IsFree = -1, Prev = -1, Next = -1, Chunk = -1) override x.ToString() = sprintf "{ Offset = %d; Size = %d; IsFree = %A; Prev = %d; Next = %d; Chunk = %d }" x.Offset x.Size (x.IsFree <> 0) x.Prev x.Next x.Chunk end [] type DictEntry = struct [] val mutable public Key : Guid // 16 [] val mutable public HashCode : int // 20 [] val mutable public Next : int // 24 [] val mutable public Block : int // 28 static member Invalid = DictEntry(Key = Guid.Empty, HashCode = -1, Next = -1, Block = -1) end [] type Node = struct [] val mutable public Offset : int64 [] val mutable public Size : int64 [] val mutable public Entry : int [] val mutable public Left : int [] val mutable public Right : int [] val mutable public Color : int static member Invalid = Node(Offset = -1L, Size = -1L, Entry = -1, Left = -1, Right = -1, Color = -1) end [] type Header = struct val mutable public Magic : Guid // 16 val mutable public MFirst : int // 20 val mutable public MLast : int // 24 val mutable public MBlubb : int64 // 32 val mutable public NRoot : int // 36 val mutable public NCount : int // 40 val mutable public NFreeList : int // 44 val mutable public NFreeCount : int // 48 val mutable public ECount : int // 52 val mutable public EFreeList : int // 56 val mutable public EFreeCount : int // 60 val mutable public DCapacity : int // 64 val mutable public DCapacityId : int // 68 val mutable public BCount : int // 72 val mutable public BFreeList : int // 76 val mutable public BFreeCount : int // 80 val mutable public BCapacity : int // 84 val mutable public Chunks : int // 88 end type blockptr = struct val mutable public ptr : nativeint member inline x.Offset = NativePtr.ofNativeInt x.ptr member inline x.Size = NativePtr.ofNativeInt (8n + x.ptr) member inline x.IsFree = NativePtr.ofNativeInt (16n + x.ptr) member inline x.Prev = NativePtr.ofNativeInt (20n + x.ptr) member inline x.Next = NativePtr.ofNativeInt (24n + x.ptr) member inline x.Chunk = NativePtr.ofNativeInt (28n + x.ptr) member x.Value with inline get() = NativePtr.read (NativePtr.ofNativeInt x.ptr) and inline set v = NativePtr.write (NativePtr.ofNativeInt x.ptr) v static member inline (+) (ptr : blockptr, index : int) = blockptr(ptr.ptr + nativeint (sizeof * index)) static member Null = blockptr(0n) new(p) = { ptr = p } end type dentryptr = struct val mutable public ptr : nativeint member inline x.Key = (x.ptr) |> NativePtr.ofNativeInt member inline x.HashCode = (x.ptr + 16n) |> NativePtr.ofNativeInt member inline x.Next = (x.ptr + 20n) |> NativePtr.ofNativeInt member inline x.Block = (x.ptr + 24n) |> NativePtr.ofNativeInt member x.Value with inline get() = NativePtr.read (NativePtr.ofNativeInt x.ptr) and inline set v = NativePtr.write (NativePtr.ofNativeInt x.ptr) v static member inline (+) (ptr : dentryptr, index : int) = dentryptr(ptr.ptr + nativeint (sizeof * index)) static member Null = dentryptr(0n) new(p) = { ptr = p } end type nodeptr = struct val mutable public ptr : nativeint member inline x.Offset = NativePtr.ofNativeInt (x.ptr) member inline x.Size = NativePtr.ofNativeInt (8n + x.ptr) member inline x.Entry = NativePtr.ofNativeInt (16n + x.ptr) member inline x.Left = NativePtr.ofNativeInt (20n + x.ptr) member inline x.Right = NativePtr.ofNativeInt (24n + x.ptr) member inline x.Color = NativePtr.ofNativeInt (28n + x.ptr) member x.Value with inline get() = NativePtr.read (NativePtr.ofNativeInt x.ptr) and inline set n = NativePtr.write (NativePtr.ofNativeInt x.ptr) n static member inline (+) (ptr : nodeptr, index : int) = nodeptr(ptr.ptr + nativeint (sizeof * index)) static member Null = nodeptr(0n) new(p) = { ptr = p } end type headerptr = struct val mutable public ptr : nativeint member inline x.Magic = NativePtr.ofNativeInt (0n + x.ptr) member inline x.MFirst = NativePtr.ofNativeInt (16n + x.ptr) member inline x.MLast = NativePtr.ofNativeInt (20n + x.ptr) member inline x.NRoot = NativePtr.ofNativeInt (32n + x.ptr) member inline x.NCount = NativePtr.ofNativeInt (36n + x.ptr) member inline x.NFreeList = NativePtr.ofNativeInt (40n + x.ptr) member inline x.NFreeCount = NativePtr.ofNativeInt (44n + x.ptr) member inline x.ECount = NativePtr.ofNativeInt (48n + x.ptr) member inline x.EFreeList = NativePtr.ofNativeInt (52n + x.ptr) member inline x.EFreeCount = NativePtr.ofNativeInt (56n + x.ptr) member inline x.DCapacity = NativePtr.ofNativeInt (60n + x.ptr) member inline x.DCapacityId = NativePtr.ofNativeInt (64n + x.ptr) member inline x.BCount = NativePtr.ofNativeInt (68n + x.ptr) member inline x.BFreeList = NativePtr.ofNativeInt (72n + x.ptr) member inline x.BFreeCount = NativePtr.ofNativeInt (76n + x.ptr) member inline x.BCapacity = NativePtr.ofNativeInt (80n + x.ptr) member inline x.Chunks = NativePtr.ofNativeInt (84n + x.ptr) member inline x.Value = NativePtr.read (NativePtr.ofNativeInt
x.ptr) static member inline (+) (ptr : headerptr, index : int) = nodeptr(ptr.ptr + nativeint (sizeof
* index)) static member Null = headerptr(0n) new(p) = { ptr = p } end [] type VirtualNode(ptr : nodeptr, index : int) = member x.Index = index override x.GetHashCode() = index override x.Equals o = match o with | :? VirtualNode as o -> index = o.Index | _ -> false interface IComparable with member x.CompareTo o = match o with | :? VirtualNode as o -> let c = compare x.Size o.Size if c = 0 then let c = compare x.Offset o.Offset if c = 0 then compare x.Entry o.Entry else c else c | _ -> failwith "uncomparable" member x.Equals (o : VirtualNode) = if isNull o then false else index = o.Index member x.Color with get() = !!ptr.Color and set v = ptr.Color <-- v member x.Offset with get() = !!ptr.Offset and set v = ptr.Offset <-- v member x.Size with get() = !!ptr.Size and set v = ptr.Size <-- v member x.Entry with get() = !!ptr.Entry and set v = ptr.Entry <-- v member x.Left with get() = let id = !!ptr.Left if id < 0 then null else VirtualNode(ptr + (id - x.Index), id) and set (l : VirtualNode) = if isNull l then ptr.Left <-- -1 else ptr.Left <-- l.Index member x.Right with get() = let id = !!ptr.Right if id < 0 then null else VirtualNode(ptr + (id - x.Index), id) and set (l : VirtualNode) = if isNull l then ptr.Right <-- -1 else ptr.Right <-- l.Index module Tree = [] module private Tools = type TreeRotation = | Left | Right | RightLeft | LeftRight let inline isRed (n : VirtualNode) = not (isNull n) && n.Color = Red let inline isBlack (n : VirtualNode) = not (isNull n) && n.Color = Black let inline isNullOrBlack (n : VirtualNode) = isNull n || n.Color = Black let inline is4Node (n : VirtualNode) = isRed n.Left && isRed n.Right let inline is2Node (n : VirtualNode) = assert (not (isNull n)) isBlack n && isNullOrBlack n.Left && isNullOrBlack n.Right let split4Node (n : VirtualNode) = n.Color <- Red n.Left.Color <- Black n.Right.Color <- Black let merge2Nodes (parent : VirtualNode) (child1 : VirtualNode) (child2 : VirtualNode) = assert (isRed parent) parent.Color <- Black child1.Color <- Red child2.Color <- Red let rotateLeft (n : VirtualNode) = let x = n.Right n.Right <- x.Left x.Left <- n x let rotateRight (n : VirtualNode) : VirtualNode = let x = n.Left n.Left <- x.Right x.Right <- n x let rotateLeftRight (n : VirtualNode) = let child = n.Left let grandChild = child.Right n.Left <- grandChild.Right grandChild.Right <- n child.Right <- grandChild.Left grandChild.Left <- child grandChild let rotateRightLeft (n : VirtualNode) = let child = n.Right let grandChild = child.Left n.Right <- grandChild.Left grandChild.Left <- n child.Left <- grandChild.Right grandChild.Right <- child grandChild let replaceChildOfNodeOrRoot(root : byref, parent : VirtualNode, child : VirtualNode, newChild : VirtualNode) = if isNull parent then root <- newChild else if parent.Left = child then parent.Left <- newChild else parent.Right <- newChild let replaceNode(root : byref, match_ : VirtualNode, parentOfMatch : VirtualNode, successor : VirtualNode, parentOfSuccessor : VirtualNode) = let mutable successor = successor if successor = match_ then assert (isNull match_.Right) successor <- match_.Left else assert ( not (isNull parentOfSuccessor) && isNull successor.Left) assert ((isNull successor.Right && successor.Color = Red) || (successor.Right.Color = Red && successor.Color = Black)) if not (isNull successor.Right) then successor.Right.Color <- Black if parentOfSuccessor <> match_ then parentOfSuccessor.Left <- successor.Right successor.Right <- match_.Right successor.Left <- match_.Left if not (isNull successor) then successor.Color <- match_.Color replaceChildOfNodeOrRoot(&root, parentOfMatch, match_, successor) let sibling (n : VirtualNode) (p : VirtualNode) = if n = p.Left then p.Right else p.Left let insertionBalance(root : byref, current : VirtualNode, parent : byref, grandParent : VirtualNode, greatGrandParent : VirtualNode) = assert (not (isNull grandParent)) let parentIsOnRight = grandParent.Right = parent let currentIsOnRight = parent.Right = current let mutable newChildOfGreatGrandParent = null if parentIsOnRight = currentIsOnRight then newChildOfGreatGrandParent <- if currentIsOnRight then rotateLeft grandParent else rotateRight grandParent else newChildOfGreatGrandParent <- if currentIsOnRight then rotateLeftRight grandParent else rotateRightLeft grandParent parent <- greatGrandParent grandParent.Color <- Red newChildOfGreatGrandParent.Color <- Black replaceChildOfNodeOrRoot(&root, greatGrandParent, grandParent, newChildOfGreatGrandParent) let rotationNeeded (parent : VirtualNode) (current : VirtualNode) (sibling : VirtualNode) = assert (isRed sibling.Left || isRed sibling.Right) if isRed sibling.Left then if parent.Left = current then TreeRotation.RightLeft else TreeRotation.Right else if parent.Left = current then TreeRotation.Left else TreeRotation.LeftRight let insert (node : VirtualNode) (root : byref) = node.Color <- Red if isNull root then node.Color <- Black root <- node true else let mutable current : VirtualNode = root let mutable parent : VirtualNode = null let mutable grandParent : VirtualNode = null let mutable greatGrandParent : VirtualNode = null let mutable order = 0 let mutable found = false while not (found || isNull current) do order <- compare node current if order = 0 then root.Color <- Black found <- true else if is4Node current then split4Node current if isRed parent then insertionBalance(&root, current, &parent, grandParent, greatGrandParent) greatGrandParent <- grandParent grandParent <- parent parent <- current current <- if order < 0 then current.Left else current.Right () if found then false else assert (not (isNull parent)) if order > 0 then parent.Right <- node else parent.Left <- node if isRed parent then insertionBalance(&root, node, &parent, grandParent, greatGrandParent) root.Color <- Black true let remove (node : VirtualNode) (root : byref) = if isNull root then false else let mutable current : VirtualNode = root let mutable parent : VirtualNode = null let mutable grandParent : VirtualNode = null let mutable match_ : VirtualNode = null let mutable parentOfMatch : VirtualNode = null let mutable foundMatch = false while not (isNull current) do if is2Node current then if isNull parent then current.Color <- Red else let mutable sibling = sibling current parent if isRed sibling then assert(parent.Color <> Red) if parent.Right = sibling then rotateLeft parent |> ignore else rotateRight parent |> ignore parent.Color <- Red sibling.Color <- Black replaceChildOfNodeOrRoot(&root, grandParent, parent, sibling) grandParent <- sibling if parent = match_ then parentOfMatch <- sibling sibling <- if parent.Left = current then parent.Right else parent.Left assert (not (isNull sibling) || sibling.Color <> Red) if is2Node sibling then merge2Nodes parent current sibling else let rotation = rotationNeeded parent current sibling let mutable newGrandParent = null match rotation with | TreeRotation.Right -> assert (parent.Left = sibling && sibling.Left.Color = Red) sibling.Left.Color <- Black newGrandParent <- rotateRight parent | TreeRotation.Left -> assert (parent.Right = sibling && sibling.Right.Color = Red) sibling.Right.Color <- Black newGrandParent <- rotateLeft parent | TreeRotation.RightLeft -> assert (parent.Right = sibling && sibling.Left.Color = Red) newGrandParent <- rotateRightLeft parent | TreeRotation.LeftRight -> assert (parent.Left = sibling && sibling.Right.Color = Red) newGrandParent <- rotateLeftRight parent newGrandParent.Color <- parent.Color parent.Color <- Black current.Color <- Red replaceChildOfNodeOrRoot(&root, grandParent, parent, newGrandParent) if parent = match_ then parentOfMatch <- newGrandParent grandParent <- newGrandParent let order = if foundMatch then -1 else compare node current if order = 0 then foundMatch <- true match_ <- current parentOfMatch <- parent grandParent <- parent parent <- current current <- if order < 0 then current.Left else current.Right if not (isNull match_) then replaceNode(&root, match_, parentOfMatch, parent, grandParent) if not (isNull root) then root.Color <- Black foundMatch let removeKey (offset : int64) (size : int64) (root : byref) = if isNull root then null else let mutable current : VirtualNode = root let mutable parent : VirtualNode = null let mutable grandParent : VirtualNode = null let mutable match_ : VirtualNode = null let mutable parentOfMatch : VirtualNode = null let mutable foundMatch = false while not (isNull current) do if is2Node current then if isNull parent then current.Color <- Red else let mutable sibling = sibling current parent if isRed sibling then assert(parent.Color <> Red) if parent.Right = sibling then rotateLeft parent |> ignore else rotateRight parent |> ignore parent.Color <- Red sibling.Color <- Black replaceChildOfNodeOrRoot(&root, grandParent, parent, sibling) grandParent <- sibling if parent = match_ then parentOfMatch <- sibling sibling <- if parent.Left = current then parent.Right else parent.Left assert (not (isNull sibling) || sibling.Color <> Red) if is2Node sibling then merge2Nodes parent current sibling else let rotation = rotationNeeded parent current sibling let mutable newGrandParent = null match rotation with | TreeRotation.Right -> assert (parent.Left = sibling && sibling.Left.Color = Red) sibling.Left.Color <- Black newGrandParent <- rotateRight parent | TreeRotation.Left -> assert (parent.Right = sibling && sibling.Right.Color = Red) sibling.Right.Color <- Black newGrandParent <- rotateLeft parent | TreeRotation.RightLeft -> assert (parent.Right = sibling && sibling.Left.Color = Red) newGrandParent <- rotateRightLeft parent | TreeRotation.LeftRight -> assert (parent.Left = sibling && sibling.Right.Color = Red) newGrandParent <- rotateLeftRight parent newGrandParent.Color <- parent.Color parent.Color <- Black current.Color <- Red replaceChildOfNodeOrRoot(&root, grandParent, parent, newGrandParent) if parent = match_ then parentOfMatch <- newGrandParent grandParent <- newGrandParent let order = if foundMatch then -1 else let c = compare size current.Size if c = 0 then compare offset current.Offset else c if order = 0 then foundMatch <- true match_ <- current parentOfMatch <- parent grandParent <- parent parent <- current current <- if order < 0 then current.Left else current.Right if not (isNull match_) then replaceNode(&root, match_, parentOfMatch, parent, grandParent) if not (isNull root) then root.Color <- Black if not foundMatch then null else match_ let findSmallestGreater (size : int64) (root : VirtualNode) = if isNull root then null else let mutable best = null let mutable current = root while not (isNull current) do let cmp = compare size current.Size if cmp = 0 then best <- current current <- null elif cmp > 0 then current <- current.Right else best <- current current <- current.Left best let removeSmallestGreater (size : int64) (root : byref) = let n = findSmallestGreater size root if isNull n then null else let res = remove n &root assert res n let primeSizes = [| (* prime no. prime *) (* 2 3 + 1 = 2^2 *) (* 4 *) 7 // + 1 = 2^3, minimal size (* 6 *) 13 // + 3 = 2^4 (* 11 *) 31 // + 1 = 2^5 (* 18 *) 61 // + 3 = 2^6 (* 31 *) 127 // + 1 = 2^7 (* 54 *) 251 // + 5 = 2^8 (* 97 *) 509 // + 3 = 2^9 (* 172 *) 1021 // + 3 = 2^10 (* 309 *) 2039 // + 9 = 2^11 (* 564 *) 4093 // + 3 = 2^12 (* 1028 *) 8191 // + 1 = 2^13 (* 1900 *) 16381 // + 3 = 2^14 (* 3512 *) 32749 // + 19 = 2^15 (* 6542 *) 65521 // + 15 = 2^16 (* 12251 *) 131071 // + 1 = 2^17 (* 23000 *) 262139 // + 5 = 2^18 (* 43390 *) 524287 // + 1 = 2^19 (* 82025 *) 1048573 // + 3 = 2^20 (* 155611 *) 2097143 // + 9 = 2^21 (* 295947 *) 4194301 // + 3 = 2^22 (* 564163 *) 8388593 // + 15 = 2^23 (* 1077871 *) 16777213 // + 3 = 2^24 (* 2063689 *) 33554393 // + 39 = 2^25 (* 3957809 *) 67108859 // + 5 = 2^26 (* 7603553 *) 134217689 // + 39 = 2^27 (* 14630843 *) 268435399 // + 57 = 2^28 (* 28192750 *) 536870909 // + 3 = 2^29 (* 54400028 *) 1073741789 // + 35 = 2^30 (* 105097565 *) 2147483647 // + 1 = 2^31 |] [] type FileHandle = class val mutable internal EntryId : int val mutable internal Length : int64 val public Id : Guid member x.Size = x.Length member x.Exists = x.EntryId >= 0 internal new(id : Guid, eid : int, length : int64) = { Id = id; EntryId = eid; Length = length } end type BlockHandle = struct val mutable internal BlockId : int internal new(bid : int) = { BlockId = bid } end type FileManagerStatistics = { growManagerTime : MicroTime growDictTime : MicroTime growDataTime : MicroTime rehashTime : MicroTime reallocTime : MicroTime allocCount : int64 freeCount : int64 fileCount : int blockCount : int } open FileManagerTypes type FileManager(mem : Memory, getChunk : int -> Memory) = static let initialCapacityId = 7 static let initialMemoryCapacity = 1L <<< 20 static let chunkSize = 2L <<< 30 static let isStore (m : Memory) = if m.Size >= int64 sizeof
then let ptr = m.Pointer |> headerptr magic.Equals !!ptr.Magic else false static let headerSize = int64 sizeof
static let managerSize (bCapacity : int) = let nCapacity = if bCapacity > 0 then bCapacity + 1 else 0 int64 sizeof * int64 nCapacity + int64 sizeof * int64 bCapacity static let dictSize (dCapacity : int) = int64 (sizeof + sizeof) * int64 dCapacity let mutable mem = mem let chunks = System.Collections.Generic.List() let mutable header = headerptr.Null let mutable nodes = nodeptr.Null let mutable blocks = blockptr.Null let mutable entries = dentryptr.Null let mutable buckets = NativePtr.zero let growManagerTime = Stopwatch() let growDictTime = Stopwatch() let growDataTime = Stopwatch() let rehashTime = Stopwatch() let reallocTime = Stopwatch() let mutable allocCount = 0L let mutable freeCount = 0L let handleCache = Dict() let nCapacity() = let cap = !!header.BCapacity if cap > 0 then cap + 1 else 0 let bCapacity() = !!header.BCapacity let dCapacity() = !!header.DCapacity let setPointers() = let ptr = mem.Pointer header <- ptr |> headerptr let ptr = ptr + nativeint headerSize let nCapacity = nCapacity() let bCapacity = bCapacity() let dCapacity = dCapacity() nodes <- ptr |> nodeptr let ptr = ptr + (nativeint sizeof * nativeint nCapacity) blocks <- ptr |> blockptr let ptr = ptr + (nativeint sizeof * nativeint bCapacity) entries <- ptr |> dentryptr let ptr = ptr + (nativeint sizeof * nativeint dCapacity) buckets <- NativePtr.ofNativeInt ptr let ptr = ptr + (nativeint sizeof * nativeint dCapacity) () let rec growManager() = growManagerTime.Start() let oldBCapacity = !!header.BCapacity let newBCapacity = 2 * oldBCapacity let oldNCapacity = if oldBCapacity = 0 then 0 else oldBCapacity + 1 let newNCapacity = if newBCapacity = 0 then 0 else newBCapacity + 1 let dictSize = dictSize !!header.DCapacity let newTotalSize = headerSize + managerSize newBCapacity + dictSize let oldTotalSize = headerSize + managerSize oldBCapacity + dictSize header.BCapacity <-- newBCapacity mem.Realloc(newTotalSize) let newPtr = mem.Pointer + nativeint newTotalSize let oldPtr = mem.Pointer + nativeint oldTotalSize // move the dict let newPtr = newPtr - nativeint dictSize let oldPtr = oldPtr - nativeint dictSize Marshal.Move(oldPtr, newPtr, dictSize) // move the Blocks let oldSize = int64 sizeof * int64 oldBCapacity let newSize = int64 sizeof * int64 newBCapacity let newPtr = newPtr - nativeint newSize let oldPtr = oldPtr - nativeint oldSize Marshal.Move(oldPtr, newPtr, oldSize) Marshal.Set(newPtr + nativeint oldSize, -1, newSize - oldSize) // move the Nodes let oldSize = int64 sizeof * int64 oldNCapacity let newSize = int64 sizeof * int64 newNCapacity let newPtr = newPtr - nativeint newSize let oldPtr = oldPtr - nativeint oldSize Marshal.Move(oldPtr, newPtr, oldSize) Marshal.Set(newPtr + nativeint oldSize, -1, newSize - oldSize) setPointers() growManagerTime.Stop() and growDict() = growDictTime.Start() let oldDCapacityId = !!header.DCapacityId let oldDCapacity = !!header.DCapacity let newDCapacityId = 1 + oldDCapacityId let newDCapacity = primeSizes.[newDCapacityId] let oldDictSize = dictSize oldDCapacity let newDictSize = dictSize newDCapacity let managerSize = managerSize !!header.BCapacity let newTotalSize = headerSize + managerSize + newDictSize let oldTotalSize = headerSize + managerSize + oldDictSize header.DCapacityId <-- newDCapacityId header.DCapacity <-- newDCapacity reallocTime.Start() mem.Realloc(newTotalSize) reallocTime.Stop() // move the dict let newPtr = mem.Pointer + nativeint newTotalSize let oldPtr = mem.Pointer + nativeint oldTotalSize // set the buckets to 0 let newSize = int64 sizeof * int64 newDCapacity let oldSize = int64 sizeof * int64 oldDCapacity let newPtr = newPtr - nativeint newSize let oldPtr = oldPtr - nativeint oldSize Marshal.Set(newPtr, 0, newSize) // move the DictEntries let newSize = int64 sizeof * int64 newDCapacity let oldSize = int64 sizeof * int64 oldDCapacity let newPtr = newPtr - nativeint newSize let oldPtr = oldPtr - nativeint oldSize Marshal.Move(oldPtr, newPtr, oldSize) setPointers() rehashTime.Start() rehash() rehashTime.Stop() growDictTime.Stop() and growData(needed : int64) = growDataTime.Start() let chunkIndex = chunks.Count - 1 let oldLastId = !!header.MLast let _, freeBlockId = newBlock() let pFreeBlock = blocks + freeBlockId pFreeBlock.Prev <-- oldLastId pFreeBlock.Next <-- -1 pFreeBlock.IsFree <-- 0 if chunkIndex >= 0 && chunks.[chunkIndex].Size < chunkSize then let lastChunk = chunks.[chunkIndex] let oldChunkCapacity = lastChunk.Size let newChunkCapacity = 2L * oldChunkCapacity lastChunk.Realloc newChunkCapacity let offset = chunkSize * int64 chunkIndex + oldChunkCapacity // free the new block pFreeBlock.Offset <-- offset pFreeBlock.Size <-- newChunkCapacity - oldChunkCapacity pFreeBlock.Chunk <-- chunkIndex else let chunkIndex = 1 + chunkIndex let newChunk = getChunk chunkIndex let newChunkCapacity = max (1L <<< 20) (Fun.NextPowerOfTwo needed) newChunk.Clear newChunkCapacity chunks.Add newChunk let offset = chunkSize * int64 chunkIndex pFreeBlock.Offset <-- offset pFreeBlock.Size <-- newChunkCapacity pFreeBlock.Chunk <-- chunkIndex header.Chunks <-- !!header.Chunks + 1 if oldLastId < 0 then header.MFirst <-- freeBlockId else (blocks + oldLastId).Next <-- freeBlockId free freeBlockId growDataTime.Stop() and newBlock() : bool * int = if !!header.BFreeCount > 0 then let id = !!header.BFreeList assert (id >= 0) let b = blocks + id header.BFreeList <-- !!b.Next header.BFreeCount <-- !!header.BFreeCount - 1 b.Next <-- -1 false, id else let mutable resized = false let cnt = !!header.BCount if cnt >= bCapacity() then resized <- true growManager() let id = cnt header.BCount <-- cnt + 1 resized, id and deleteBlock(bid : int) = assert (bid >= 0) let n = !!header.BFreeList let mutable b = blocks + bid b.Value <- Block.Invalid b.Next <-- n header.BFreeList <-- bid header.BFreeCount <-- !!header.BFreeCount + 1 and newNode() : bool * int = if !!header.NFreeCount > 0 then let id = !!header.NFreeList assert (id >= 0) let n = nodes + id header.NFreeList <-- !!n.Left header.NFreeCount <-- !!header.NFreeCount - 1 n.Left <-- -1 false, id else let mutable resized = false let cnt = !!header.NCount if cnt >= nCapacity() then resized <- true growManager() let id = cnt header.NCount <-- cnt + 1 resized, id and deleteNode(nid : int) = assert (nid >= 0) let next = !!header.NFreeList let mutable n = nodes + nid n.Value <- Node.Invalid n.Left <-- next header.NFreeList <-- nid header.NFreeCount <-- !!header.NFreeCount + 1 and newEntry() : bool * int = if !!header.EFreeCount > 0 then let id = !!header.EFreeList assert (id >= 0) let e = entries + id header.EFreeList <-- !!e.Next header.EFreeCount <-- !!header.EFreeCount - 1 e.Next <-- -1 false, id else let mutable resized = false let cnt = !!header.ECount if cnt >= dCapacity() then resized <- true growDict() let id = cnt header.ECount <-- cnt + 1 resized, id and deleteEntry(eid : int) = assert (eid >= 0) let next = !!header.EFreeList let mutable e = entries + eid e.Value <- DictEntry.Invalid e.Next <-- next header.EFreeList <-- eid header.EFreeCount <-- !!header.EFreeCount + 1 and withTree (f : ref -> 'a) = let root = let rid = !!header.NRoot if rid < 0 then null else VirtualNode(nodes + rid, rid) let r = ref root let res = f r let root = !r if isNull root then header.NRoot <-- -1 else header.NRoot <-- root.Index res and insertFreeBlock (bid : int) = assert (bid >= 0) let pBlock = blocks + bid let size = !!pBlock.Size let offset = !!pBlock.Offset let _, nid = newNode() let pEntry = () let pNode = nodes + nid pNode.Offset <-- offset pNode.Size <-- size pNode.Left <-- -1 pNode.Right <-- -1 pNode.Entry <-- bid pNode.Color <-- Red withTree (fun root -> let nn = VirtualNode(pNode, nid) let worked = Tree.insert nn &root.contents if not worked then Log.warn "could not add to freelist: %A" (offset, size) deleteNode nid ) and removeFreeBlock (bid : int) = assert (bid >= 0) let pBlock = blocks + bid let offset = !!pBlock.Offset let size = !!pBlock.Size let toKill = withTree(fun root -> Tree.removeKey offset size &root.contents ) if not (isNull toKill) then deleteNode toKill.Index true else Log.warn "could not remove from freelist: %A" (offset, size) false and getFreeBlock (size : int64) : bool * int = let node = withTree (fun tree -> Tree.removeSmallestGreater size &tree.contents ) if isNull node then growData size let _, bid = getFreeBlock size true, bid else let bid = node.Entry assert (bid >= 0) assert (!!(blocks + bid).Size >= size) deleteNode node.Index false, bid and alloc (size : int64) = if size <= 0L then false, -1 else allocCount <- allocCount + 1L let mutable resized, bid = getFreeBlock size let mutable pBlock = blocks + bid let blockSize = !!pBlock.Size if blockSize > size then let r, rid = newBlock() if r then pBlock <- blocks + bid resized <- true let restNext = !!pBlock.Next let mutable pRestBlock = blocks + rid pRestBlock.Offset <-- !!pBlock.Offset + size pRestBlock.Size <-- blockSize - size pRestBlock.IsFree <-- 1 pRestBlock.Prev <-- bid pRestBlock.Next <-- restNext pRestBlock.Chunk <-- !!pBlock.Chunk if restNext < 0 then header.MLast <-- rid else (blocks + restNext).Prev <-- rid pBlock.Size <-- size pBlock.Next <-- rid insertFreeBlock rid pBlock.IsFree <-- 0 assert (!!pBlock.Size = size) resized, bid and free (bid : int) = if bid >= 0 then freeCount <- freeCount + 1L let pBlock = blocks + bid if !!pBlock.IsFree = 0 then let chunk = !!pBlock.Chunk let prev = !!pBlock.Prev let next = !!pBlock.Next let pPrevBlock = blocks + prev let pNextBlock = blocks + next if prev < 0 then header.MFirst <-- bid elif !!pPrevBlock.IsFree <> 0 && !!pPrevBlock.Chunk = chunk then // merge with prev removeFreeBlock prev |> ignore pBlock.Offset <-- !!pPrevBlock.Offset pBlock.Size <-- !!pPrevBlock.Size + !!pBlock.Size let pp = !!pPrevBlock.Prev pBlock.Prev <-- pp if pp < 0 then header.MFirst <-- bid else (blocks + pp).Next <-- bid deleteBlock prev if next < 0 then header.MLast <-- bid elif !!pNextBlock.IsFree <> 0 && !!pNextBlock.Chunk = chunk then // merge with next removeFreeBlock next |> ignore pBlock.Size <-- !!pBlock.Size + !!pNextBlock.Size let nn = !!pNextBlock.Next pBlock.Next <-- nn if nn < 0 then header.MLast <-- bid else (blocks + nn).Prev <-- bid deleteBlock next pBlock.IsFree <-- 1 insertFreeBlock bid and findEntry (key : Guid) (hashCode : int) = let bid = hashCode % !!header.DCapacity let pBucket = NativePtr.add buckets bid let b = !!pBucket - 1 if b < 0 then -1 else let pEntry = entries + b if !!pEntry.HashCode = hashCode && key.Equals !!pEntry.Key then b else let rec search (id : int) (pEntry : dentryptr) = if id < 0 then -1 elif !!pEntry.HashCode = hashCode && key.Equals !!pEntry.Key then id else let next = !!pEntry.Next search next (entries + next) let next = !!pEntry.Next search next (entries + next) // and removeEntry (key : Guid) (hashCode : int) = // let bid = hashCode % !!header.DCapacity // let pBucket = NativePtr.add buckets bid // // let b = !!pBucket - 1 // if b < 0 then // -1 // else // let pEntry = entries + b // if !!pEntry.HashCode = hashCode && key.Equals !!pEntry.Key then // let block = !!pEntry.Block // deleteEntry b // pBucket <-- 0 // block // else // let rec search (last : dentryptr) (id : int) (pEntry : dentryptr) = // if id < 0 then // -1 // elif !!pEntry.HashCode = hashCode && key.Equals !!pEntry.Key then // let next = !!pEntry.Next // last.Next <-- next // // let block = !!pEntry.Block // deleteEntry id // block // else // let next = !!pEntry.Next // search pEntry next (entries + next) // // let next = !!pEntry.Next // search pEntry next (entries + next) and removeEntryPtr (eid : int) = if eid >= 0 then let pRemEntry = entries + eid let hashCode = !!pRemEntry.HashCode let bid = hashCode % !!header.DCapacity let pBucket = NativePtr.add buckets bid let b = !!pBucket - 1 if b < 0 then false else let pEntry = entries + b if b = eid then let next = !!pEntry.Next deleteEntry b pBucket <-- 1 + next true else let rec search (last : dentryptr) (id : int) (pEntry : dentryptr) = if id < 0 then false elif id = eid then let next = !!pEntry.Next last.Next <-- next let block = !!pEntry.Block deleteEntry id true else let next = !!pEntry.Next search pEntry next (entries + next) let next = !!pEntry.Next search pEntry next (entries + next) else true and setEntry (key : Guid) (hashCode : int) (value : int) = let eid = findEntry key hashCode if eid >= 0 then let pEntry = entries + eid pEntry.Block <-- value eid else let _, eid = newEntry() let pEntry = entries + eid pEntry.Key <-- key pEntry.HashCode <-- hashCode pEntry.Block <-- value pEntry.Next <-- -1 let bid = hashCode % !!header.DCapacity let pBucket = NativePtr.add buckets bid let b = !!pBucket - 1 pEntry.Next <-- b pBucket <-- eid + 1 eid and rehash() = let mutable pEntry = entries let eCount = !!header.ECount let dCapacity = !!header.DCapacity for i in 0..eCount-1 do let hash = !!pEntry.HashCode if hash >= 0 then let bid = hash % dCapacity let pBucket = NativePtr.add buckets bid let b = !!pBucket - 1 pEntry.Next <-- b pBucket <-- i + 1 pEntry <- pEntry + 1 do if isStore mem then setPointers() let numChunks = !!header.Chunks for i in 0..numChunks-1 do chunks.Add(getChunk i) else let dCapacityId = initialCapacityId let dCapacity = primeSizes.[dCapacityId] let bCapacity = Fun.NextPowerOfTwo dCapacity let total = headerSize + managerSize bCapacity + dictSize dCapacity mem.Clear(total) let c0 = getChunk 0 chunks.Add c0 c0.Clear(initialMemoryCapacity) let initialHeader = Header( Magic = magic, MFirst = -1, MLast = -1, NRoot = -1, NCount = 0, NFreeList = -1, NFreeCount = 0, ECount = 0, EFreeList = -1, EFreeCount = 0, DCapacity = dCapacity, DCapacityId = dCapacityId, BCount = 0, BFreeList = -1, BFreeCount = 0, BCapacity = bCapacity, Chunks = 1 ) NativePtr.write (NativePtr.ofNativeInt mem.Pointer) initialHeader setPointers() // create the new free-block let _,bid = newBlock() let pBlock = blocks + bid pBlock.Offset <-- 0L pBlock.Size <-- initialMemoryCapacity pBlock.IsFree <-- 0 pBlock.Prev <-- -1 pBlock.Next <-- -1 pBlock.Chunk <-- 0 // store the free-block in a new entry // and ensure its correct linkage header.MFirst <-- bid header.MLast <-- bid // free the new block free bid // =================================================================================================== // Block API // =================================================================================================== member x.Alloc (size : int64) = let _,bid = alloc size BlockHandle bid member x.Free (block : BlockHandle) = free block.BlockId member x.SizeOf(block : BlockHandle) = let bid = block.BlockId if bid < 0 then 0L else let pBlock = blocks + bid !!pBlock.Size member x.Copy(src : byte[], srcOffset : int64, dst : BlockHandle, dstOffset : int64, length : int64) = if length <= 0L then () else let bid = dst.BlockId if bid < 0 then failwithf "[FileManager] cannot write %d bytes to block of size 0" length if isNull src then failwith "[FileManager] cannot read from null array" let pBlock = blocks + bid assert (!!pBlock.IsFree <> 1) let blockSize = !!pBlock.Size if length > blockSize then failwithf "[FileManager] cannot write %d bytes to block of size %d" length blockSize let chunk = !!pBlock.Chunk let memory = chunks.[chunk].Pointer - nativeint chunkSize * nativeint chunk let gc = GCHandle.Alloc(src, GCHandleType.Pinned) try let dst = memory + nativeint !!pBlock.Offset + nativeint dstOffset let src = gc.AddrOfPinnedObject() + nativeint srcOffset Marshal.Copy(src, dst, length) finally gc.Free() member x.Copy(src : BlockHandle, srcOffset : int64, dst : byte[], dstOffset : int64, length : int64) = if length <= 0L then () else let bid = src.BlockId if bid < 0 then failwithf "[FileManager] cannot read %d bytes from block of size 0" length if isNull dst then failwith "[FileManager] cannot write to null array" let pBlock = blocks + bid assert (!!pBlock.IsFree <> 1) let blockSize = !!pBlock.Size if length > blockSize then failwithf "[FileManager] cannot read %d bytes from block of size %d" length blockSize let chunk = !!pBlock.Chunk let memory = chunks.[chunk].Pointer - nativeint chunkSize * nativeint chunk let gc = GCHandle.Alloc(dst, GCHandleType.Pinned) try let dst = gc.AddrOfPinnedObject() + nativeint dstOffset let src = memory + nativeint !!pBlock.Offset + nativeint srcOffset Marshal.Copy(src, dst, length) finally gc.Free() member x.Copy(src : BlockHandle, srcOffset : int64, dst : BlockHandle, dstOffset : int64, length : int64) = if length <= 0L then () else let sid = src.BlockId let did = src.BlockId if sid < 0 then failwithf "[FileManager] cannot copy %d bytes from block of size 0" length if did < 0 then failwithf "[FileManager] cannot copy %d bytes to block of size 0" length let pSrc = blocks + sid let pDst = blocks + did assert (!!pSrc.IsFree <> 1) assert (!!pDst.IsFree <> 1) let srcSize = !!pSrc.Size let dstSize = !!pDst.Size if length > srcSize then failwithf "[FileManager] cannot copy %d bytes from block of size %d" length srcSize if length > dstSize then failwithf "[FileManager] cannot copy %d bytes to block of size %d" length dstSize let dstChunk = !!pDst.Chunk let dstMemory = chunks.[dstChunk].Pointer - nativeint chunkSize * nativeint dstChunk let srcChunk = !!pSrc.Chunk let srcMemory = chunks.[srcChunk].Pointer - nativeint chunkSize * nativeint srcChunk Marshal.Copy(srcMemory + nativeint !!pSrc.Offset + nativeint srcOffset, dstMemory + nativeint !!pDst.Offset + nativeint dstOffset, length) member x.Copy(src : BlockHandle, dst : byte[], dstOffset : int64, length : int64) = x.Copy(src, 0L, dst, dstOffset, length) member x.Copy(src : BlockHandle, srcOffset : int64, dst : byte[], length : int64) = x.Copy(src, srcOffset, dst, 0L, length) member x.Copy(src : BlockHandle, dst : byte[], length : int64) = x.Copy(src, 0L, dst, 0L, length) member x.Copy(src : BlockHandle, dst : byte[]) = x.Copy(src, 0L, dst, 0L, dst.LongLength) member x.Copy(src : byte[], dst : BlockHandle, dstOffset : int64, length : int64) = x.Copy(src, 0L, dst, dstOffset, length) member x.Copy(src : byte[], srcOffset : int64, dst : BlockHandle, length : int64) = x.Copy(src, srcOffset, dst, 0L, length) member x.Copy(src : byte[], dst : BlockHandle, length : int64) = x.Copy(src, 0L, dst, 0L, length) member x.Copy(src : byte[], dst : BlockHandle) = x.Copy(src, 0L, dst, 0L, src.LongLength) member x.Copy(src : BlockHandle, dst : BlockHandle, dstOffset : int64, length : int64) = x.Copy(src, 0L, dst, dstOffset, length) member x.Copy(src : BlockHandle, srcOffset : int64, dst : BlockHandle, length : int64) = x.Copy(src, srcOffset, dst, 0L, length) member x.Copy(src : BlockHandle, dst : BlockHandle, length : int64) = x.Copy(src, 0L, dst, 0L, length) member x.Copy(src : BlockHandle, dst : BlockHandle) = x.Copy(src, 0L, dst, 0L, x.SizeOf src) member x.Read(src : BlockHandle) = if src.BlockId >= 0 then let size = x.SizeOf src let arr = Array.zeroCreate (int size) x.Copy(src, 0L, arr, 0L, arr.LongLength) arr else [||] // =================================================================================================== // File API // =================================================================================================== member x.Exists(file : FileHandle) = file.EntryId >= 0 member x.GetCurrentBlock(file : FileHandle) = if file.EntryId < 0 then BlockHandle(-1) else let pEntry = entries + file.EntryId BlockHandle(!!pEntry.Block) member x.GetFile (key : Guid) = handleCache.GetOrCreate(key, fun key -> let hashCode = key.GetHashCode() &&& 0x7FFFFFFF let eid = findEntry key hashCode if eid < 0 then FileHandle(key, -1, 0L) else let bid = !!(entries + eid).Block |> BlockHandle let size = x.SizeOf bid FileHandle(key, eid, size) ) member x.TryGetFile (key : Guid, [] file : byref) = if handleCache.TryGetValue(key, &file) then true else let hashCode = key.GetHashCode() &&& 0x7FFFFFFF let eid = findEntry key hashCode if eid < 0 then false else let bid = !!(entries + eid).Block |> BlockHandle let size = x.SizeOf bid let res = FileHandle(key, eid, size) handleCache.[key] <- res file <- res true member x.Resize (file : FileHandle, newSize : int64) = let eid = file.EntryId if eid < 0 then if newSize > 0L then let _, bid = alloc newSize let hashCode = file.Id.GetHashCode() &&& 0x7FFFFFFF let eid = setEntry file.Id hashCode bid file.EntryId <- eid file.Length <- newSize else file.Length <- 0L else if newSize > 0L then let mutable pEntry = entries + eid let oldBlockId = !!pEntry.Block if oldBlockId >= 0 then let pBlock = blocks + oldBlockId let oldSize = !!pBlock.Size if oldSize <> newSize then free oldBlockId let resized, newBlockId = alloc newSize if resized then pEntry <- entries + eid pEntry.Block <-- newBlockId else let resized, bid = alloc newSize if resized then pEntry <- entries + eid pEntry.Block <-- bid file.Length <- newSize else let pEntry = entries + eid let bid = !!pEntry.Block if bid >= 0 then pEntry.Block <-- -1 free bid file.Length <- 0L member x.Delete(file : FileHandle) = let eid = file.EntryId if eid >= 0 then file.EntryId <- -1 handleCache.Remove file.Id |> ignore let bid = !!(entries + eid).Block let removed = removeEntryPtr eid assert removed if bid >= 0 then free bid member x.Copy(src : byte[], srcOffset : int64, dst : FileHandle, dstOffset : int64, length : int64) = x.Copy(src, srcOffset, x.GetCurrentBlock dst, dstOffset, length) member x.Copy(src : byte[], dst : FileHandle, dstOffset : int64, length : int64) = x.Copy(src, 0L, x.GetCurrentBlock dst, dstOffset, length) member x.Copy(src : byte[], srcOffset : int64, dst : FileHandle, length : int64) = x.Copy(src, srcOffset, x.GetCurrentBlock dst, 0L, length) member x.Copy(src : byte[], dst : FileHandle, length : int64) = x.Copy(src, 0L, x.GetCurrentBlock dst, 0L, length) member x.Copy(src : byte[], dst : FileHandle) = x.Copy(src, 0L, x.GetCurrentBlock dst, 0L, src.LongLength) member x.Copy(src : FileHandle, srcOffset : int64, dst : byte[], dstOffset : int64, length : int64) = x.Copy(x.GetCurrentBlock src, srcOffset, dst, dstOffset, length) member x.Copy(src : FileHandle, dst : byte[], dstOffset : int64, length : int64) = x.Copy(x.GetCurrentBlock src, 0L, dst, dstOffset, length) member x.Copy(src : FileHandle, srcOffset : int64, dst : byte[], length : int64) = x.Copy(x.GetCurrentBlock src, srcOffset, dst, 0L, length) member x.Copy(src : FileHandle, dst : byte[], length : int64) = x.Copy(x.GetCurrentBlock src, 0L, dst, 0L, length) member x.Copy(src : FileHandle, dst : byte[]) = x.Copy(x.GetCurrentBlock src, 0L, dst, 0L, dst.LongLength) member x.Read(src : FileHandle) = if src.EntryId >= 0 then let arr = Array.zeroCreate (int src.Length) x.Copy(x.GetCurrentBlock src, 0L, arr, 0L, arr.LongLength) arr else [||] member x.TotalMemory = Mem mem.Size + Mem (chunks |> Seq.sumBy (fun m -> m.Size)) member x.Entries = !!header.BCount - !!header.BFreeCount member x.Files = !!header.ECount - !!header.EFreeCount member x.Statistics = { growManagerTime = growManagerTime.MicroTime growDictTime = growDictTime.MicroTime growDataTime = growDataTime.MicroTime rehashTime = rehashTime.MicroTime reallocTime = reallocTime.MicroTime allocCount = allocCount freeCount = freeCount fileCount = !!header.ECount - !!header.EFreeCount blockCount = !!header.BCount - !!header.BFreeCount } member private x.Dispose(disposing : bool) = if header.ptr <> 0n then if disposing then GC.SuppressFinalize x mem.Dispose() chunks |> Seq.iter (fun c -> c.Dispose()) chunks.Clear() header <- headerptr.Null nodes <- nodeptr.Null blocks <- blockptr.Null entries <- dentryptr.Null buckets <- NativePtr.zero member x.Dispose() = x.Dispose(true) override x.Finalize() = x.Dispose(false) interface IDisposable with member x.Dispose() = x.Dispose(true) [] module FileManager = let directory (dir : string) = let exists = Directory.Exists dir if not exists then Directory.CreateDirectory dir |> ignore let main = Path.Combine(dir, "index.bin") |> Memory.mapped let get (i : int) = Path.Combine(dir, sprintf "store%d.bin" i) |> Memory.mapped new FileManager(main, get) let hglobal () = let main = Memory.hglobal 0L let get (i : int) = Memory.hglobal 0L new FileManager(main, get) type BlobStore(m : Memory, getChunk : int -> Memory) = let store = new FileManager(m, getChunk) let cache = System.Collections.Concurrent.ConcurrentDictionary() let rw = new ReaderWriterLockSlim() member x.Memory = ReaderWriterLock.read rw (fun () -> store.TotalMemory) member x.Get (id : Guid) = cache.GetOrAdd(id, fun id -> ReaderWriterLock.write rw (fun () -> BlobFile(rw, store, id, store.GetFile id) ) ) member x.Create() = let id = Guid.NewGuid() ReaderWriterLock.write rw (fun () -> let res = BlobFile(rw, store, id, store.GetFile id) cache.[id] <- res res ) member x.Dispose() = ReaderWriterLock.write rw (fun () -> store.Dispose() ) interface IBlobStore with member x.Memory = x.Memory member x.Get id = x.Get(id) :> IBlobFile member x.Create() = x.Create() :> IBlobFile member x.Dispose() = x.Dispose() and BlobFile(rw : ReaderWriterLockSlim, store : FileManager, id : Guid, eid : FileHandle) = let mutable eid = eid let mutable bid = store.GetCurrentBlock eid member x.Name = id member x.Exists = lock x (fun () -> eid.Exists) member x.Size = lock x (fun () -> eid.Size) member x.Read() = lock x (fun () -> ReaderWriterLock.read rw (fun () -> store.Read bid ) ) member x.Write(data : byte[]) = lock x (fun () -> if eid.Size <> data.LongLength then ReaderWriterLock.write rw (fun () -> if not eid.Exists then eid <- store.GetFile(id) store.Resize(eid, data.LongLength) bid <- store.GetCurrentBlock eid ) ReaderWriterLock.read rw (fun () -> store.Copy(data, 0L, bid, 0L, data.LongLength) ) ) member x.Delete() = lock x (fun () -> if eid.Exists then ReaderWriterLock.write rw (fun () -> store.Delete(eid) ) ) interface IBlobFile with member x.Name = x.Name member x.Exists = x.Exists member x.Size = x.Size member x.Read() = x.Read() member x.Write arr = x.Write arr member x.Delete() = x.Delete() member x.CopyTo o = o.Write (x.Read()) [] module BlobStore = let directory (dir : string) = let exists = Directory.Exists dir if not exists then Directory.CreateDirectory dir |> ignore let main = Path.Combine(dir, "index.bin") |> Memory.mapped let get (i : int) = Path.Combine(dir, sprintf "store%d.bin" i) |> Memory.mapped new BlobStore(main, get) let hglobal () = let main = Memory.hglobal 0L let get (i : int) = Memory.hglobal 0L new BlobStore(main, get) ================================================ FILE: src/Aardvark.Base.FSharp/Reflection/Formatf.fs ================================================ namespace Aardvark.Base open System open System.Text open System.Text.RegularExpressions open System.Collections.Concurrent open Aardvark.Base open Microsoft.FSharp.Reflection type StringFormat = struct val mutable public Format : string val mutable public Args : obj[] override x.ToString() = String.Format(x.Format, x.Args) new(f,a) = { Format = f; Args = a } end type StringFormat<'a, 'r> = Format<'a, unit, StringFormat, 'r> [] module Printf = module private FormatString = /// Used for width and precision to denote that user has specified '*' flag [] let StarValue = -1 /// Used for width and precision to denote that corresponding value was omitted in format string [] let NotSpecifiedValue = -2 type FormatFlags = | None = 0 | LeftJustify = 1 | PadWithZeros = 2 | PlusForPositives = 4 | SpaceForPositives = 8 let inline isDigit c = c >= '0' && c <= '9' let intFromString (s : string) pos = let rec go acc i = if isDigit s.[i] then let n = int s.[i] - int '0' go (acc * 10 + n) (i + 1) else acc, i go 0 pos let parseFlags (s : string) i : FormatFlags * int = let rec go flags i = match s.[i] with | '0' -> go (flags ||| FormatFlags.PadWithZeros) (i + 1) | '+' -> go (flags ||| FormatFlags.PlusForPositives) (i + 1) | ' ' -> go (flags ||| FormatFlags.SpaceForPositives) (i + 1) | '-' -> go (flags ||| FormatFlags.LeftJustify) (i + 1) | _ -> flags, i go FormatFlags.None i let parseWidth (s : string) i : int * int = if s.[i] = '*' then StarValue, (i + 1) elif isDigit (s.[i]) then intFromString s i else NotSpecifiedValue, i let parsePrecision (s : string) i : int * int = if s.[i] = '.' then if s.[i + 1] = '*' then StarValue, i + 2 elif isDigit (s.[i + 1]) then intFromString s (i + 1) else raise (ArgumentException("invalid precision value")) else NotSpecifiedValue, i let parseTypeChar (s : string) i : char * int = s.[i], (i + 1) let findNextFormatSpecifier (s : string) i = let rec go i (buf : Text.StringBuilder) = if i >= s.Length then s.Length, s.Length, buf.ToString() else let c = s.[i] if c = '%' then if i + 1 < s.Length then let _, i1 = parseFlags s (i + 1) let w, i2 = parseWidth s i1 let p, i3 = parsePrecision s i2 let typeChar, i4 = parseTypeChar s i3 // shortcut for the simpliest case // if typeChar is not % or it has star as width\precision - resort to long path if typeChar = '%' && not (w = StarValue || p = StarValue) then buf.Append('%') |> ignore go i4 buf else i, i4, buf.ToString() else raise (ArgumentException("Missing format specifier")) else buf.Append(c) |> ignore go (i + 1) buf go i (Text.StringBuilder()) open System.Reflection open System.Reflection.Emit type private StringFormatCache<'a, 'res> private() = static let contType = typeof 'res> static let rec getFunctionSignature (t : Type) = if t = typeof<'res> then [], t elif FSharpType.IsFunction t then let (d,i) = FSharpType.GetFunctionElements t let args, ret = getFunctionSignature i d::args, ret else [], t static let args, _ = getFunctionSignature typeof<'a> static let args : Type[] = List.toArray (contType::args) static let invokeCont = contType.GetMethod("Invoke", BindingFlags.Instance ||| BindingFlags.Public, Type.DefaultBinder, [| typeof |], null) static let formatCtor = typeof.GetConstructor [| typeof; typeof |] static let createFunction (fmt : string) : (StringFormat -> 'res) -> 'a = let meth = DynamicMethod( "StringFormat_" + fmt, typeof<'res>, args, true ) let il = meth.GetILGenerator() let arr = il.DeclareLocal(typeof) il.Emit(OpCodes.Ldc_I4, args.Length - 1) il.Emit(OpCodes.Newarr, typeof) il.Emit(OpCodes.Stloc, arr) for i in 1..args.Length-1 do let t = args.[i] il.Emit(OpCodes.Ldloc, arr) il.Emit(OpCodes.Ldc_I4, i - 1) il.Emit(OpCodes.Ldarg, i) if t.IsValueType then il.Emit(OpCodes.Box, t) il.Emit(OpCodes.Stelem_Ref) il.Emit(OpCodes.Ldarg_0) il.Emit(OpCodes.Ldstr, fmt) il.Emit(OpCodes.Ldloc, arr) il.Emit(OpCodes.Newobj, formatCtor) il.EmitCall(OpCodes.Callvirt, invokeCont, null) il.Emit(OpCodes.Ret) let del = if typeof<'res> = typeof then let funcType = typedefof>.FullName.Replace("1", string (args.Length)) |> Type.GetType let funcType = funcType.MakeGenericType args meth.CreateDelegate(funcType) else let funcType = typedefof>.FullName.Replace("1", string (args.Length + 1)) |> Type.GetType let funcType = funcType.MakeGenericType (Array.append args [|typeof<'res>|]) meth.CreateDelegate(funcType) DelegateAdapters.wrap del static let create(value : string) : (StringFormat -> 'res) -> 'a = let mutable args = [] let mutable ret = typeof<'a> let formatBuilder = StringBuilder() let mutable i = 0 let mutable c = 0 while c < value.Length do let (s,e,str) = FormatString.findNextFormatSpecifier value c formatBuilder.Append(str.Replace("{", "{{").Replace("}", "}}")) |> ignore c <- e if s < value.Length then formatBuilder.Append("{" + string i + "}") |> ignore i <- i + 1 let (d,i) = FSharpType.GetFunctionElements ret args <- d::args ret <- i let formatString = formatBuilder.ToString() createFunction formatString static let cache = ConcurrentDictionary 'res) -> 'a>() static member get (fmt : StringFormat<'a, 'res>) = cache.GetOrAdd(fmt.Value, Func(fun value -> create value)) let formatf (fmt : StringFormat<'a, StringFormat>) : 'a = StringFormatCache<'a, StringFormat>.get fmt id let kformatf (f : StringFormat -> 'res) (fmt : StringFormat<'a, 'res>) : 'a = StringFormatCache<'a, 'res>.get fmt f ================================================ FILE: src/Aardvark.Base.FSharp/Reflection/FunctionReflection.fs ================================================ #if INTERACTIVE #r "..\\..\\Bin\\Debug\\Aardvark.Base.dll" open Aardvark.Base #else namespace Aardvark.Base #endif open System.Linq.Expressions open System.Runtime.InteropServices open Microsoft.FSharp.Reflection open System.Reflection open System.Reflection.Emit open System /// /// FunctionReflection provides functions wrapping MethodInfos as F# functions efficiently. /// It also allows to create n-ary functions using an untyped implementation. /// module FunctionReflection = let rec private sequentializeTupleType (t : Type) = if FSharpType.IsTuple t then t |> FSharpType.GetTupleElements |> Seq.collect sequentializeTupleType else seq { yield t } let private tupleGet (p : ParameterExpression) (i : int) = if FSharpType.IsTuple p.Type then let name = sprintf "Item%d" (i+1) let pi = p.Type.GetProperty(name) if not (isNull pi) then Expression.Property(p, pi.GetMethod) :> Expression else failwithf "property %A was not fount for type %A" name p.Type else if i = 0 then p :> Expression else failwithf "cannot access tuple elements of type %A" p.Type let rec private getMethodSignatureInternal (t : Type) = if FSharpType.IsFunction t then let a, ret = FSharpType.GetFunctionElements t let args, ret = getMethodSignatureInternal ret if a = typeof then (args, ret) else (a::args, ret) else if t = typeof then ([],typeof) else ([],t) let rec getMethodSignature (t : Type) = if FSharpType.IsFunction t then let a, ret = FSharpType.GetFunctionElements t let args, ret = getMethodSignature ret //Here be dragons if a = typeof then (args, ret) else let a = a |> sequentializeTupleType |> Seq.toList (List.concat [a; args], ret) else if t = typeof then ([],typeof) else ([],t) let rec private buildLambda (args : list) (callArgs : list) (target : obj) (argTypes : list) (mi : MethodInfo) = match argTypes with | x::xs -> let v = Expression.Variable(x) let x = x |> sequentializeTupleType |> Seq.toList let tupleArgs = x |> List.mapi (fun i xi -> tupleGet v i) buildLambda (v::args) (List.concat [callArgs; tupleArgs]) target xs mi | [] -> let args = List.rev args let call = if isNull target then Expression.Call(mi, callArgs) else Expression.Call(Expression.Constant(target), mi, callArgs) Expression.Lambda( call, args) let private buildLambdaExpression (target : obj) (mi : MethodInfo) (funType : Type) : 'a = let (args,ret) = getMethodSignatureInternal funType //mi.GetParameters() |> Seq.map (fun p -> p.ParameterType) |> Seq.toList let lambda = buildLambda [] [] target args mi |> unbox> lambda.Compile() type FunctionBuilder = static member BuildFunction (target : obj,mi : MethodInfo) : 'a -> 'r = if typeof<'a> = typeof then if typeof<'r> = typeof then let a : Action = buildLambdaExpression target mi typeof<'a -> 'r> fun _ -> a.Invoke() |> unbox<'r> else let f : Func<'r> = buildLambdaExpression target mi typeof<'a -> 'r> fun _ -> f.Invoke() else if typeof<'r> = typeof then let a : Action<'a> = buildLambdaExpression target mi typeof<'a -> 'r> fun a0 -> a.Invoke(a0) |> unbox<'r> else let f : Func<'a, 'r> = buildLambdaExpression target mi typeof<'a -> 'r> f.Invoke static member BuildFunction (target : obj,mi : MethodInfo) : 'a -> 'b -> 'r = if typeof<'r> = typeof then let a : Action<'a, 'b> = buildLambdaExpression target mi typeof<'a -> 'b -> 'r> fun a0 a1 -> a.Invoke(a0,a1) |> unbox<'r> else let f : Func<'a, 'b, 'r> = buildLambdaExpression target mi typeof<'a -> 'b -> 'r> fun a0 a1 -> f.Invoke(a0,a1) static member BuildFunction (target : obj,mi : MethodInfo) : 'a -> 'b -> 'c -> 'r = if typeof<'r> = typeof then let a : Action<'a, 'b, 'c> = buildLambdaExpression target mi typeof<'a -> 'b -> 'c -> 'r> fun a0 a1 a2 -> a.Invoke(a0,a1,a2) |> unbox<'r> else let f : Func<'a, 'b, 'c, 'r> = buildLambdaExpression target mi typeof<'a -> 'b -> 'c -> 'r> fun a0 a1 a2 -> f.Invoke(a0,a1,a2) static member BuildFunction (target : obj,mi : MethodInfo) : 'a -> 'b -> 'c -> 'd -> 'r = if typeof<'r> = typeof then let a : Action<'a, 'b, 'c, 'd> = buildLambdaExpression target mi typeof<'a -> 'b -> 'c -> 'd -> 'r> fun a0 a1 a2 a3 -> a.Invoke(a0,a1,a2,a3) |> unbox<'r> else let f : Func<'a, 'b, 'c, 'd, 'r> = buildLambdaExpression target mi typeof<'a -> 'b -> 'c -> 'd -> 'r> fun a0 a1 a2 a3 -> f.Invoke(a0,a1,a2,a3) static member BuildFunction (target : obj,mi : MethodInfo) : 'a -> 'b -> 'c -> 'd -> 'e -> 'r = if typeof<'r> = typeof then let a : Action<'a, 'b, 'c, 'd, 'e> = buildLambdaExpression target mi typeof<'a -> 'b -> 'c -> 'd -> 'e -> 'r> fun a0 a1 a2 a3 a4 -> a.Invoke(a0,a1,a2,a3,a4) |> unbox<'r> else let f : Func<'a, 'b, 'c, 'd, 'e, 'r> = buildLambdaExpression target mi typeof<'a -> 'b -> 'c -> 'd -> 'e -> 'r> fun a0 a1 a2 a3 a4 -> f.Invoke(a0,a1,a2,a3,a4) static member BuildFunction (target : obj,mi : MethodInfo) : 'a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'r = if typeof<'r> = typeof then let a : Action<'a, 'b, 'c, 'd, 'e, 'f> = buildLambdaExpression target mi typeof<'a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'r> fun a0 a1 a2 a3 a4 a5 -> a.Invoke(a0,a1,a2,a3,a4,a5) |> unbox<'r> else let f : Func<'a, 'b, 'c, 'd, 'e, 'f, 'r> = buildLambdaExpression target mi typeof<'a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'r> fun a0 a1 a2 a3 a4 a5 -> f.Invoke(a0,a1,a2,a3,a4,a5) static member BuildFunction (target : obj,mi : MethodInfo) : 'a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'g -> 'r = if typeof<'r> = typeof then let a : Action<'a, 'b, 'c, 'd, 'e, 'f, 'g> = buildLambdaExpression target mi typeof<'a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'g -> 'r> fun a0 a1 a2 a3 a4 a5 a6 -> a.Invoke(a0,a1,a2,a3,a4,a5,a6) |> unbox<'r> else let f : Func<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'r> = buildLambdaExpression target mi typeof<'a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'g -> 'r> fun a0 a1 a2 a3 a4 a5 a6 -> f.Invoke(a0,a1,a2,a3,a4,a5,a6) static member BuildFunction (target : obj,mi : MethodInfo) : 'a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'g -> 'h -> 'r= if typeof<'r> = typeof then let a : Action<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> = buildLambdaExpression target mi typeof<'a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'g -> 'h -> 'r> fun a0 a1 a2 a3 a4 a5 a6 a7 -> a.Invoke(a0,a1,a2,a3,a4,a5,a6,a7) |> unbox<'r> else let f : Func<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'r> = buildLambdaExpression target mi typeof<'a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'g -> 'h -> 'r> fun a0 a1 a2 a3 a4 a5 a6 a7 -> f.Invoke(a0,a1,a2,a3,a4,a5,a6,a7) let private buildFunctionInternal (target : obj) (argTypes : list) (mi : MethodInfo) : 'a = let t = typeof<'a> let mutable ret = t let args = System.Collections.Generic.List() while FSharpType.IsFunction ret do let a,r = FSharpType.GetFunctionElements ret args.Add a ret <- r let ret = ret let genArgs = seq { yield! args; yield ret } |> Seq.toArray let m = typeof.GetMethods(BindingFlags.Public ||| BindingFlags.NonPublic ||| BindingFlags.Static) |> Seq.filter (fun mi -> mi.Name = "BuildFunction") |> Seq.filter (fun mi -> mi.IsGenericMethodDefinition && mi.GetGenericArguments().Length = genArgs.Length) |> Seq.tryPick(fun mi -> mi.MakeGenericMethod genArgs |> Some) match m with | Some m -> m.Invoke(null, [|target; mi :> obj|]) |> unbox<'a> | None -> failwithf "could not wrap function of with generic args: %A" genArgs let buildFunction (target : obj) (mi : MethodInfo) = buildFunctionInternal target [] mi [] let rec private makeNAryFunctionInternal (t : Type) (count : int) (f : obj[] -> obj) : int * (obj[] -> obj) = if FSharpType.IsFunction t then let index = count let (_,ret) = FSharpType.GetFunctionElements t let count,c = makeNAryFunctionInternal ret (count + 1) f (count, fun args -> FSharpValue.MakeFunction(t, fun o -> args.[index] <- o c(args)) ) else (count, fun args -> f args) [] let makeNAryFunction (f : obj[] -> obj) : 'x = let t = typeof<'x> let (count, c) = makeNAryFunctionInternal t 0 f let args = Array.create count null c args |> unbox let makeFormatFunction (f : string -> obj[] -> obj) (fmt : Printf.BuilderFormat<'r, obj>) : 'r = makeNAryFunction (fun args -> (f fmt.Value args) ) module QuotationReflectionHelpers = open Microsoft.FSharp.Quotations //extracts the (optional) top-most method call from an expression let rec tryGetMethodInfo (e : Expr) = match e with | Patterns.Call(_,mi,_) -> if mi.IsGenericMethod then mi.GetGenericMethodDefinition() |> Some else mi |> Some | ExprShape.ShapeCombination(_, args) -> args |> List.tryPick tryGetMethodInfo | ExprShape.ShapeLambda(_,b) -> tryGetMethodInfo b | _ -> None /// /// extracts the top-most method-call from an expression. /// When no method-call is found the method will raise an exception /// /// let getMethodInfo (e : Expr) = match tryGetMethodInfo e with | Some mi -> mi | None -> failwith "could not find a method-call in expression" module DelegateAdapters = type AdapterFunc = static member Convert0 (f : Func<'a>) = f.Invoke static member Convert1 (f : Func<'a, 'b>) = f.Invoke static member Convert2 (f : Func<'a, 'b, 'c>) = fun a b -> f.Invoke(a,b) static member Convert3 (f : Func<'a, 'b, 'c, 'd>) = fun a b c -> f.Invoke(a,b,c) static member Convert4 (f : Func<'a, 'b, 'c, 'd, 'e>) = fun a b c d -> f.Invoke(a,b,c,d) static member Convert5 (f : Func<'a, 'b, 'c, 'd, 'e, 'f>) = fun a b c d e -> f.Invoke(a,b,c,d,e) type AdapterAction = static member Convert0 (f : Action) = f.Invoke static member Convert1 (f : Action<'a>) = f.Invoke static member Convert2 (f : Action<'a, 'b>) = fun a b -> f.Invoke(a,b) static member Convert3 (f : Action<'a, 'b, 'c>) = fun a b c -> f.Invoke(a,b,c) static member Convert4 (f : Action<'a, 'b, 'c, 'd>) = fun a b c d -> f.Invoke(a,b,c,d) static member Convert5 (f : Action<'a, 'b, 'c, 'd, 'e>) = fun a b c d e -> f.Invoke(a,b,c,d,e) let rec getFunctionSignature (t : Type) = if FSharpType.IsFunction t then let (d,i) = FSharpType.GetFunctionElements t let args, ret = getFunctionSignature i d::args, ret else [], t let wrapUntyped (d : Delegate) : obj = let mi = d.GetMethodInfo() let args = mi.GetParameters() |> Array.map (fun p -> p.ParameterType) let ret = if mi.ReturnType = typeof then typeof else mi.ReturnType let generic, args = if mi.ReturnType = typeof then typeof.GetMethod("Convert" + string args.Length), args //Type.GetType(typedefof>.FullName.Replace("1", string args.Length)) else typeof.GetMethod("Convert" + string args.Length), Array.append args [|ret|] //Type.GetType(typedefof>.FullName.Replace("1", string args.Length)) if isNull generic then let code = args |> Seq.map (fun t -> t.Name) |> String.concat " -> " failwithf "could not get delegate adapter: %s" code let t = generic.MakeGenericMethod args t.Invoke(null, [|d|]) //Activator.CreateInstance(t, d) let wrap (d : Delegate) : 'a = match wrapUntyped d with | :? 'a as res -> res | _ -> failwithf "[DelegateAdapter] cannot convert from delegate %A to %A" (d.GetType()) typeof<'a> ================================================ FILE: src/Aardvark.Base.FSharp/Reflection/IL.fs ================================================ namespace Aardvark.Base.IL open System open System.IO open System.Threading open System.Reflection open System.Reflection.Emit open Microsoft.FSharp.Quotations open Microsoft.FSharp.Quotations.Patterns open Aardvark.Base open Aardvark.Base.FunctionReflection type JumpCondition = | Less | LessOrEqual | Greater | GreaterOrEqual | Equal | NotEqual | False | True type Constant = | Int8 of int8 | UInt8 of uint8 | Int16 of int16 | UInt16 of uint16 | Int32 of int32 | UInt32 of uint32 | Int64 of int64 | UInt64 of uint64 | Float64 of float | Float32 of float32 | NativeInt of nativeint | UNativeInt of unativeint | String of string type ValueType = | Int8 = 0 | UInt8 = 1 | Int16 = 2 | UInt16 = 3 | Int32 = 4 | UInt32 = 5 | Int64 = 6 | UInt64 = 7 | Float64 = 8 | Float32 = 9 | NativeInt = 10 | UNativeInt = 11 | Object = 12 type Label private(id : int) = static let mutable currentId = 0 member x.Id = id override x.ToString() = sprintf "Label(%d)" id override x.GetHashCode() = id.GetHashCode() override x.Equals o = match o with | :? Label as o -> id = o.Id | _ -> false interface IComparable with member x.CompareTo o = match o with | :? Label as o -> compare id o.Id | _ -> failwithf "cannot compare Label with %A" o new() = Label(Interlocked.Increment(¤tId)) type Local private(id : int, name : string, t : Type) = static let mutable currentId = 0 member x.Id = id member x.Name = name member x.Type = t override x.ToString() = if String.IsNullOrWhiteSpace name then sprintf "local%d(%A)" id t else sprintf "%s(%A)" name t override x.GetHashCode() = id.GetHashCode() override x.Equals o = match o with | :? Local as o -> id = o.Id | _ -> false interface IComparable with member x.CompareTo o = match o with | :? Local as o -> compare id o.Id | _ -> failwithf "cannot compare Local with %A" o new(name, t) = Local(Interlocked.Increment(¤tId), name, t) new(t) = Local(Interlocked.Increment(¤tId), "", t) type Instruction = | Start | Nop | Break | Dup | Pop | Ldarg of int | LdargA of int | Starg of int | Ldloc of Local | LdlocA of Local | Stloc of Local | Ldfld of FieldInfo | LdfldA of FieldInfo | Stfld of FieldInfo | LdIndirect of ValueType | StIndirect of ValueType | CpObj of Type | LdObj of Type | StObj of Type | NewObj of ConstructorInfo | InitObj of Type | CastClass of Type | IsInstance of Type | Unbox of Type | UnboxAny of Type | Box of Type | NewArr of Type | Ldlen | Ldelem of Type | LdelemA of Type | Stelem of Type | Add | Sub | Mul | Div | Rem | And | Or | Xor | Shl | Shr | Neg | Not | Conv of ValueType | ConvChecked of ValueType | RefAnyVal of Type | CkFinite | MkRefAny of Type | LdNull | LdConst of Constant | LdToken of obj | WriteLine of string | ReadOnly | Tail | Mark of Label | ConditionalJump of JumpCondition * Label | Jump of Label | Call of MethodBase | CallIndirect | Ret | Switch of Label[] | Throw | EndFinally | Leave of Label type MethodDefinition = { ArgumentTypes : Type[] ReturnType : Type Body : list } module StateMonad = type State<'s, 'a> = 's -> 's * 'a module State = let bind (f : 'a -> State<'s, 'b>) (m : State<'s, 'a>) : State<'s, 'b> = fun s -> let (s,v) = m s f v s let combine (l : State<'s, unit>) (r : State<'s, 'a>) : State<'s, 'a> = fun s -> let (s,()) = l s r s let map (f : 'a -> 'b) (m : State<'s, 'a>) : State<'s, 'b> = fun s -> let (s,v) = m s s, f v let create (v : 'a) : State<'s, 'a> = fun s -> s,v let delay (f : unit -> State<'s, 'a>) : State<'s, 'a> = fun s -> f () s let get<'s> : State<'s, 's> = fun s -> s,s let put (s : 's) : State<'s, unit> = fun _ -> s, () let modify (f : 's -> 's) : State<'s, unit> = fun s -> (f s), () type StateBuilder() = member x.Bind(m : State<'s, 'a>, f : 'a -> State<'s, 'b>) = State.bind f m member x.Return (v : 'a) : State<'s, 'a> = State.create v member x.ReturnFrom (m : State<'s, 'a>) : State<'s, 'a> = m member x.Delay (f : unit -> State<'s, 'a>) : State<'s, 'a> = State.delay f member x.Zero() : State<'s, unit> = State.create () member x.Combine(l : State<'s, unit>, r : State<'s, 'a>) = State.combine l r member x.For(elements : seq<'a>, f : 'a -> State<'s, unit>) : State<'s, unit> = fun s -> let mutable c = s for e in elements do let (s,()) = f e c c <- s c, () member x.While(guard : unit -> bool, body : State<'s, unit>) : State<'s, unit> = fun s -> let mutable c = s while guard() do let (s,()) = body c c <- s c, () let state = StateBuilder() [] module ReflectionExtensions = type BindingFlags with static member All = BindingFlags.Public ||| BindingFlags.NonPublic ||| BindingFlags.Instance module Disassembler = type Parameter = | This of Type | Parameter of string * Type type RawInstruction = class val mutable public Code : OpCode val mutable public Operand : obj override x.ToString() = if isNull x.Operand then sprintf "%A" x.Code else sprintf "%A(%A)" x.Code x.Operand new(c) = { Code = c; Operand = null } new(c, o) = { Code = c; Operand = o } end [] module private Helpers = module OpCodes = let table = typeof.GetFields() |> Array.toList |> List.map (fun f -> f.GetValue(null) |> unbox) |> List.map (fun c -> c.Value, c) |> Map.ofList let get (value : int16) = table.[value] type ILContext = { TypeArgs : Type[] MethodArgs : Type[] Module : Module } type BinaryReader with member x.ReadOpCode() = let b0 = x.ReadByte() if b0 = 0xFEuy then let b1 = x.ReadByte() let v = ((int16 b0) <<< 8) ||| (int16 b1) OpCodes.get v else let v = int16 b0 OpCodes.get v member x.ReadOperand(ctx : ILContext, o : OperandType) = match o with | OperandType.InlineNone -> null | OperandType.InlineBrTarget -> let off = x.ReadInt32() int x.BaseStream.Position + off :> obj | OperandType.InlineField -> let token = x.ReadInt32() let field = ctx.Module.ResolveField(token, ctx.TypeArgs, ctx.MethodArgs) field :> obj | OperandType.InlineI -> x.ReadInt32() :> obj | OperandType.InlineI8 -> x.ReadInt64() :> obj | OperandType.InlineMethod -> let token = x.ReadInt32() let meth = ctx.Module.ResolveMethod(token, ctx.TypeArgs, ctx.MethodArgs) meth :> obj | OperandType.InlineR -> x.ReadDouble() :> obj | OperandType.InlineSig -> let token = x.ReadInt32() let signature = ctx.Module.ResolveSignature(token) signature :> obj | OperandType.InlineString -> let token = x.ReadInt32() let string = ctx.Module.ResolveString(token) string :> obj | OperandType.InlineTok -> let token = x.ReadInt32() let v = ctx.Module.ResolveMember(token, ctx.TypeArgs, ctx.MethodArgs) v :> obj | OperandType.InlineType -> let token = x.ReadInt32() let v = ctx.Module.ResolveType(token, ctx.TypeArgs, ctx.MethodArgs) v :> obj | OperandType.InlineVar -> let id = x.ReadInt16() int id :> obj | OperandType.ShortInlineBrTarget -> let off = x.ReadSByte() |> int int x.BaseStream.Position + off :> obj | OperandType.ShortInlineI -> x.ReadSByte() :> obj | OperandType.ShortInlineR -> x.ReadSingle() :> obj | OperandType.ShortInlineVar -> let id = x.ReadByte() |> int id |> int :> obj | OperandType.InlineSwitch -> let length = x.ReadInt32() let baseOff = int x.BaseStream.Position Array.init length (fun _ -> baseOff + x.ReadInt32()) :> obj | _ -> failwithf "[IL] unsupported operand-type: %A" o member x.ReadRawInstruction(ctx : ILContext) = let code = x.ReadOpCode() let op = x.ReadOperand(ctx, code.OperandType) RawInstruction(code, op) module Patterns = [] let inline (|Nop|_|) (i : RawInstruction) = if i.Code = OpCodes.Nop then ValueSome() else ValueNone [] let inline (|Break|_|) (i : RawInstruction) = if i.Code = OpCodes.Break then ValueSome() else ValueNone [] let inline (|Dup|_|) (i : RawInstruction) = if i.Code = OpCodes.Dup then ValueSome() else ValueNone [] let inline (|Pop|_|) (i : RawInstruction) = if i.Code = OpCodes.Pop then ValueSome() else ValueNone [] let inline (|Ldarg|_|) (i : RawInstruction) = if i.Code = OpCodes.Ldarg then ValueSome(unbox i.Operand) elif i.Code = OpCodes.Ldarg_0 then ValueSome 0 elif i.Code = OpCodes.Ldarg_1 then ValueSome 1 elif i.Code = OpCodes.Ldarg_2 then ValueSome 2 elif i.Code = OpCodes.Ldarg_3 then ValueSome 3 elif i.Code = OpCodes.Ldarg_S then ValueSome(unbox i.Operand) else ValueNone [] let inline (|Starg|_|) (i : RawInstruction) = if i.Code = OpCodes.Starg_S then ValueSome(unbox i.Operand) elif i.Code = OpCodes.Starg then ValueSome(unbox i.Operand) else ValueNone [] let inline (|Ldarga|_|) (i : RawInstruction) = if i.Code = OpCodes.Ldarga then ValueSome(unbox i.Operand) elif i.Code = OpCodes.Ldarga_S then ValueSome(unbox i.Operand) else ValueNone [] let inline (|Ldloc|_|) (i : RawInstruction) = if i.Code = OpCodes.Ldloc then ValueSome (unbox i.Operand) elif i.Code = OpCodes.Ldloc_S then ValueSome (unbox i.Operand) elif i.Code = OpCodes.Ldloc_0 then ValueSome 0 elif i.Code = OpCodes.Ldloc_1 then ValueSome 1 elif i.Code = OpCodes.Ldloc_2 then ValueSome 2 elif i.Code = OpCodes.Ldloc_3 then ValueSome 3 else ValueNone [] let inline (|LdlocA|_|) (i : RawInstruction) = if i.Code = OpCodes.Ldloca then ValueSome (unbox i.Operand) elif i.Code = OpCodes.Ldloca_S then ValueSome (unbox i.Operand) else ValueNone [] let inline (|Stloc|_|) (i : RawInstruction) = if i.Code = OpCodes.Stloc then ValueSome (unbox i.Operand) elif i.Code = OpCodes.Stloc_S then ValueSome (unbox i.Operand) elif i.Code = OpCodes.Stloc_0 then ValueSome 0 elif i.Code = OpCodes.Stloc_1 then ValueSome 1 elif i.Code = OpCodes.Stloc_2 then ValueSome 2 elif i.Code = OpCodes.Stloc_3 then ValueSome 3 else ValueNone [] let inline (|Ldfld|_|) (i : RawInstruction) = if i.Code = OpCodes.Ldfld then ValueSome (unbox i.Operand) elif i.Code = OpCodes.Ldsfld then ValueSome (unbox i.Operand) else ValueNone [] let inline (|LdfldA|_|) (i : RawInstruction) = if i.Code = OpCodes.Ldflda then ValueSome (unbox i.Operand) elif i.Code = OpCodes.Ldsflda then ValueSome (unbox i.Operand) else ValueNone [] let inline (|Stfld|_|) (i : RawInstruction) = if i.Code = OpCodes.Stfld then ValueSome (unbox i.Operand) elif i.Code = OpCodes.Stsfld then ValueSome (unbox i.Operand) else ValueNone [] let inline (|LdIndirect|_|) (i : RawInstruction) = if i.Code = OpCodes.Ldind_I then ValueSome(ValueType.NativeInt) elif i.Code = OpCodes.Ldind_I1 then ValueSome(ValueType.Int8) elif i.Code = OpCodes.Ldind_U1 then ValueSome(ValueType.UInt8) elif i.Code = OpCodes.Ldind_I2 then ValueSome(ValueType.Int16) elif i.Code = OpCodes.Ldind_U2 then ValueSome(ValueType.UInt16) elif i.Code = OpCodes.Ldind_I4 then ValueSome(ValueType.Int32) elif i.Code = OpCodes.Ldind_U4 then ValueSome(ValueType.UInt32) elif i.Code = OpCodes.Ldind_I8 then ValueSome(ValueType.Int64) elif i.Code = OpCodes.Ldind_R4 then ValueSome(ValueType.Float32) elif i.Code = OpCodes.Ldind_R8 then ValueSome(ValueType.Float64) elif i.Code = OpCodes.Ldind_Ref then ValueSome(ValueType.Object) else ValueNone [] let inline (|StIndirect|_|) (i : RawInstruction) = if i.Code = OpCodes.Stind_I then ValueSome(ValueType.NativeInt) elif i.Code = OpCodes.Stind_I1 then ValueSome(ValueType.Int8) elif i.Code = OpCodes.Stind_I2 then ValueSome(ValueType.Int16) elif i.Code = OpCodes.Stind_I4 then ValueSome(ValueType.Int32) elif i.Code = OpCodes.Stind_I8 then ValueSome(ValueType.Int64) elif i.Code = OpCodes.Stind_R4 then ValueSome(ValueType.Float32) elif i.Code = OpCodes.Stind_R8 then ValueSome(ValueType.Float64) elif i.Code = OpCodes.Stind_Ref then ValueSome(ValueType.Object) else ValueNone [] let inline (|CpObj|_|) (i : RawInstruction) = if i.Code = OpCodes.Cpobj then ValueSome(unbox i.Operand) else ValueNone [] let inline (|LdObj|_|) (i : RawInstruction) = if i.Code = OpCodes.Ldobj then ValueSome(unbox i.Operand) else ValueNone [] let inline (|StObj|_|) (i : RawInstruction) = if i.Code = OpCodes.Stobj then ValueSome(unbox i.Operand) else ValueNone [] let inline (|NewObj|_|) (i : RawInstruction) = if i.Code = OpCodes.Newobj then ValueSome (unbox i.Operand) else ValueNone [] let inline (|InitObj|_|) (i : RawInstruction) = if i.Code = OpCodes.Initobj then ValueSome (unbox i.Operand) else ValueNone [] let inline (|CastClass|_|) (i : RawInstruction) = if i.Code = OpCodes.Castclass then ValueSome (unbox i.Operand) else ValueNone [] let inline (|IsInstance|_|) (i : RawInstruction) = if i.Code = OpCodes.Isinst then ValueSome (unbox i.Operand) else ValueNone [] let inline (|Unbox|_|) (i : RawInstruction) = if i.Code = OpCodes.Unbox then ValueSome (unbox i.Operand) else ValueNone [] let inline (|UnboxAny|_|) (i : RawInstruction) = if i.Code = OpCodes.Unbox_Any then ValueSome (unbox i.Operand) else ValueNone [] let inline (|Box|_|) (i : RawInstruction) = if i.Code = OpCodes.Box then ValueSome (unbox i.Operand) else ValueNone [] let inline (|NewArr|_|) (i : RawInstruction) = if i.Code = OpCodes.Newarr then ValueSome (unbox i.Operand) else ValueNone [] let inline (|Ldlen|_|) (i : RawInstruction) = if i.Code = OpCodes.Ldlen then ValueSome () else ValueNone [] let inline (|Ldelem|_|) (i : RawInstruction) = if i.Code = OpCodes.Ldelem then ValueSome(unbox i.Operand) elif i.Code = OpCodes.Ldelem_I1 then ValueSome typeof elif i.Code = OpCodes.Ldelem_U1 then ValueSome typeof elif i.Code = OpCodes.Ldelem_I2 then ValueSome typeof elif i.Code = OpCodes.Ldelem_U2 then ValueSome typeof elif i.Code = OpCodes.Ldelem_I4 then ValueSome typeof elif i.Code = OpCodes.Ldelem_U4 then ValueSome typeof elif i.Code = OpCodes.Ldelem_I8 then ValueSome typeof elif i.Code = OpCodes.Ldelem_R4 then ValueSome typeof elif i.Code = OpCodes.Ldelem_R8 then ValueSome typeof elif i.Code = OpCodes.Ldelem_I then ValueSome typeof elif i.Code = OpCodes.Ldelem_Ref then ValueSome typeof else ValueNone [] let inline (|LdelemA|_|) (i : RawInstruction) = if i.Code = OpCodes.Ldelema then ValueSome (unbox i.Operand) else ValueNone [] let inline (|Stelem|_|) (i : RawInstruction) = if i.Code = OpCodes.Stelem then ValueSome(unbox i.Operand) elif i.Code = OpCodes.Stelem_I1 then ValueSome typeof elif i.Code = OpCodes.Stelem_I2 then ValueSome typeof elif i.Code = OpCodes.Stelem_I4 then ValueSome typeof elif i.Code = OpCodes.Stelem_I8 then ValueSome typeof elif i.Code = OpCodes.Stelem_R4 then ValueSome typeof elif i.Code = OpCodes.Stelem_R8 then ValueSome typeof elif i.Code = OpCodes.Stelem_I then ValueSome typeof elif i.Code = OpCodes.Stelem_Ref then ValueSome typeof else ValueNone [] let inline (|Add|_|) (i : RawInstruction) = if i.Code = OpCodes.Add then ValueSome () elif i.Code = OpCodes.Add_Ovf then ValueSome () elif i.Code = OpCodes.Add_Ovf_Un then ValueSome () else ValueNone [] let inline (|Sub|_|) (i : RawInstruction) = if i.Code = OpCodes.Sub then ValueSome () elif i.Code = OpCodes.Sub_Ovf then ValueSome () elif i.Code = OpCodes.Sub_Ovf_Un then ValueSome () else ValueNone [] let inline (|Mul|_|) (i : RawInstruction) = if i.Code = OpCodes.Mul then ValueSome () elif i.Code = OpCodes.Mul_Ovf then ValueSome () elif i.Code = OpCodes.Mul_Ovf_Un then ValueSome () else ValueNone [] let inline (|Div|_|) (i : RawInstruction) = if i.Code = OpCodes.Div then ValueSome () elif i.Code = OpCodes.Div_Un then ValueSome () else ValueNone [] let inline (|Rem|_|) (i : RawInstruction) = if i.Code = OpCodes.Rem then ValueSome () elif i.Code = OpCodes.Rem_Un then ValueSome () else ValueNone [] let inline (|And|_|) (i : RawInstruction) = if i.Code = OpCodes.And then ValueSome () else ValueNone [] let inline (|Or|_|) (i : RawInstruction) = if i.Code = OpCodes.Or then ValueSome () else ValueNone [] let inline (|Xor|_|) (i : RawInstruction) = if i.Code = OpCodes.Xor then ValueSome () else ValueNone [] let inline (|Shl|_|) (i : RawInstruction) = if i.Code = OpCodes.Shl then ValueSome () else ValueNone [] let inline (|Shr|_|) (i : RawInstruction) = if i.Code = OpCodes.Shr then ValueSome () elif i.Code = OpCodes.Shr_Un then ValueSome () else ValueNone [] let inline (|Neg|_|) (i : RawInstruction) = if i.Code = OpCodes.Neg then ValueSome () else ValueNone [] let inline (|Not|_|) (i : RawInstruction) = if i.Code = OpCodes.Not then ValueSome () else ValueNone [] let inline (|Conv|_|) (i : RawInstruction) = if i.Code = OpCodes.Conv_I1 then ValueSome ValueType.Int8 elif i.Code = OpCodes.Conv_U1 then ValueSome ValueType.UInt8 elif i.Code = OpCodes.Conv_I2 then ValueSome ValueType.Int16 elif i.Code = OpCodes.Conv_U2 then ValueSome ValueType.UInt16 elif i.Code = OpCodes.Conv_I4 then ValueSome ValueType.Int32 elif i.Code = OpCodes.Conv_U4 then ValueSome ValueType.UInt32 elif i.Code = OpCodes.Conv_I8 then ValueSome ValueType.Int64 elif i.Code = OpCodes.Conv_U8 then ValueSome ValueType.UInt64 elif i.Code = OpCodes.Conv_R4 then ValueSome ValueType.Float32 elif i.Code = OpCodes.Conv_R8 then ValueSome ValueType.Float64 elif i.Code = OpCodes.Conv_I then ValueSome ValueType.NativeInt elif i.Code = OpCodes.Conv_U then ValueSome ValueType.UNativeInt elif i.Code = OpCodes.Conv_R_Un then ValueSome ValueType.Float32 else ValueNone [] let inline (|ConvChecked|_|) (i : RawInstruction) = if i.Code = OpCodes.Conv_Ovf_I1 then ValueSome ValueType.Int8 elif i.Code = OpCodes.Conv_Ovf_U1 then ValueSome ValueType.UInt8 elif i.Code = OpCodes.Conv_Ovf_I2 then ValueSome ValueType.Int16 elif i.Code = OpCodes.Conv_Ovf_U2 then ValueSome ValueType.UInt16 elif i.Code = OpCodes.Conv_Ovf_I4 then ValueSome ValueType.Int32 elif i.Code = OpCodes.Conv_Ovf_U4 then ValueSome ValueType.UInt32 elif i.Code = OpCodes.Conv_Ovf_I8 then ValueSome ValueType.Int64 elif i.Code = OpCodes.Conv_Ovf_U8 then ValueSome ValueType.UInt64 elif i.Code = OpCodes.Conv_Ovf_I then ValueSome ValueType.NativeInt elif i.Code = OpCodes.Conv_Ovf_U then ValueSome ValueType.UNativeInt elif i.Code = OpCodes.Conv_Ovf_I1_Un then ValueSome ValueType.Int8 elif i.Code = OpCodes.Conv_Ovf_U1_Un then ValueSome ValueType.UInt8 elif i.Code = OpCodes.Conv_Ovf_I2_Un then ValueSome ValueType.Int16 elif i.Code = OpCodes.Conv_Ovf_U2_Un then ValueSome ValueType.UInt16 elif i.Code = OpCodes.Conv_Ovf_I4_Un then ValueSome ValueType.Int32 elif i.Code = OpCodes.Conv_Ovf_U4_Un then ValueSome ValueType.UInt32 elif i.Code = OpCodes.Conv_Ovf_I8_Un then ValueSome ValueType.Int64 elif i.Code = OpCodes.Conv_Ovf_U8_Un then ValueSome ValueType.UInt64 elif i.Code = OpCodes.Conv_Ovf_I_Un then ValueSome ValueType.NativeInt elif i.Code = OpCodes.Conv_Ovf_U_Un then ValueSome ValueType.UNativeInt else ValueNone [] let inline (|RefAnyVal|_|) (i : RawInstruction) = if i.Code = OpCodes.Refanyval then ValueSome (unbox i.Operand) else ValueNone [] let inline (|CkFinite|_|) (i : RawInstruction) = if i.Code = OpCodes.Ckfinite then ValueSome () else ValueNone [] let inline (|MkRefAny|_|) (i : RawInstruction) = if i.Code = OpCodes.Mkrefany then ValueSome (unbox i.Operand) else ValueNone [] let inline (|LdNull|_|) (i : RawInstruction) = if i.Code = OpCodes.Ldnull then ValueSome () else ValueNone [] let inline (|LdConst|_|) (i : RawInstruction) = if i.Code = OpCodes.Ldc_I4 then i.Operand |> unbox |> Int32 |> ValueSome elif i.Code = OpCodes.Ldc_I4_S then i.Operand |> unbox |> int |> Int32 |> ValueSome elif i.Code = OpCodes.Ldc_I8 then i.Operand |> unbox |> Int64 |> ValueSome elif i.Code = OpCodes.Ldc_R4 then i.Operand |> unbox |> Float32 |> ValueSome elif i.Code = OpCodes.Ldc_R8 then i.Operand |> unbox |> Float64 |> ValueSome elif i.Code = OpCodes.Ldc_I4_0 then ValueSome (Int32 0) elif i.Code = OpCodes.Ldc_I4_1 then ValueSome (Int32 1) elif i.Code = OpCodes.Ldc_I4_2 then ValueSome (Int32 2) elif i.Code = OpCodes.Ldc_I4_3 then ValueSome (Int32 3) elif i.Code = OpCodes.Ldc_I4_4 then ValueSome (Int32 4) elif i.Code = OpCodes.Ldc_I4_5 then ValueSome (Int32 5) elif i.Code = OpCodes.Ldc_I4_6 then ValueSome (Int32 6) elif i.Code = OpCodes.Ldc_I4_7 then ValueSome (Int32 7) elif i.Code = OpCodes.Ldc_I4_8 then ValueSome (Int32 8) elif i.Code = OpCodes.Ldc_I4_M1 then ValueSome (Int32 -1) elif i.Code = OpCodes.Ldstr then i.Operand |> unbox |> String |> ValueSome else ValueNone [] let inline (|LdToken|_|) (i : RawInstruction) = if i.Code = OpCodes.Ldtoken then ValueSome (i.Operand) else ValueNone [] let inline (|ReadOnly|_|) (i : RawInstruction) = if i.Code = OpCodes.Readonly then ValueSome () else ValueNone [] let inline (|Tail|_|) (i : RawInstruction) = if i.Code = OpCodes.Tailcall then ValueSome () else ValueNone [] let inline (|ConditionalJump|_|) (i : RawInstruction) = if i.Code = OpCodes.Blt || i.Code = OpCodes.Blt_S || i.Code = OpCodes.Blt_Un || i.Code = OpCodes.Blt_Un_S then ValueSome (Less, unbox i.Operand) elif i.Code = OpCodes.Ble || i.Code = OpCodes.Ble_S || i.Code = OpCodes.Ble_Un || i.Code = OpCodes.Ble_Un_S then ValueSome (LessOrEqual, unbox i.Operand) elif i.Code = OpCodes.Bgt || i.Code = OpCodes.Bgt_S || i.Code = OpCodes.Bgt_Un || i.Code = OpCodes.Bgt_Un_S then ValueSome (Greater, unbox i.Operand) elif i.Code = OpCodes.Bge || i.Code = OpCodes.Bge_S || i.Code = OpCodes.Bge_Un || i.Code = OpCodes.Bge_Un_S then ValueSome (GreaterOrEqual, unbox i.Operand) elif i.Code = OpCodes.Beq || i.Code = OpCodes.Beq_S then ValueSome (Equal, unbox i.Operand) elif i.Code = OpCodes.Bne_Un || i.Code = OpCodes.Bne_Un_S then ValueSome (NotEqual, unbox i.Operand) elif i.Code = OpCodes.Brfalse || i.Code = OpCodes.Brfalse_S then ValueSome (False, unbox i.Operand) elif i.Code = OpCodes.Brtrue || i.Code = OpCodes.Brtrue_S then ValueSome (True, unbox i.Operand) else ValueNone [] let inline (|Jump|_|) (i : RawInstruction) = if i.Code = OpCodes.Br || i.Code = OpCodes.Br_S then ValueSome (unbox i.Operand) else ValueNone [] let inline (|Call|_|) (i : RawInstruction) = if i.Code = OpCodes.Call || i.Code = OpCodes.Callvirt then ValueSome (unbox i.Operand) else ValueNone [] let inline (|CallIndirect|_|) (i : RawInstruction) = if i.Code = OpCodes.Calli then ValueSome () else ValueNone [] let inline (|Ret|_|) (i : RawInstruction) = if i.Code = OpCodes.Ret then ValueSome () else ValueNone [] let inline (|Switch|_|) (i : RawInstruction) = if i.Code = OpCodes.Switch then ValueSome (unbox i.Operand) else ValueNone [] let inline (|Throw|_|) (i : RawInstruction) = if i.Code = OpCodes.Throw then ValueSome () else ValueNone [] let inline (|EndFinally|_|) (i : RawInstruction) = if i.Code = OpCodes.Endfinally then ValueSome () else ValueNone [] let inline (|Leave|_|) (i : RawInstruction) = if i.Code = OpCodes.Leave then ValueSome (unbox i.Operand) else ValueNone let read (m : MethodBase) = let body = m.GetMethodBody() if body = null then failwith "could not get method body" let locals = body.LocalVariables |> Seq.map (fun l -> l.LocalIndex, Local(l.LocalType)) |> Map.ofSeq let isInstance = not m.IsStatic let parameters = let off = if isInstance then 1 else 0 m.GetParameters() |> Seq.map (fun p -> off + p.Position, Parameter(p.Name, p.ParameterType)) |> Map.ofSeq let parameters = if isInstance then Map.add 0 (This m.DeclaringType) parameters else parameters let ctx = { TypeArgs = if m.DeclaringType.IsGenericType then m.DeclaringType.GetGenericArguments() else [||] MethodArgs = if m.IsGenericMethod then m.GetGenericArguments() else [||] Module = m.Module } use binary = new BinaryReader(new MemoryStream(body.GetILAsByteArray())) let all = System.Collections.Generic.List() while binary.BaseStream.Position < binary.BaseStream.Length do let offset = binary.BaseStream.Position |> int let i = binary.ReadRawInstruction(ctx) all.Add (offset, i) parameters, locals, all.ToArray() let disassemble (m : MethodBase) = let parameter, locals, instructions = read m let currentId = ref 0 let branchTargetIds = instructions |> Seq.collect (fun (_,i) -> if i.Code.OperandType = OperandType.InlineBrTarget || i.Code.OperandType = OperandType.ShortInlineBrTarget then [unbox i.Operand] :> seq<_> elif i.Code.OperandType = OperandType.InlineSwitch then unbox i.Operand :> seq<_> else Seq.empty ) |> Set.ofSeq |> Seq.map (fun i -> i, Label()) |> Map.ofSeq let body = seq { for (off, i) in instructions do match Map.tryFind off branchTargetIds with | Some l -> yield Mark l | _ -> () match i with | Patterns.Nop -> yield Nop | Patterns.Break -> yield Break | Patterns.Dup -> yield Dup | Patterns.Pop -> yield Pop | Patterns.Ldarg index -> yield Ldarg index | Patterns.Ldarga index -> yield LdargA index | Patterns.Starg index -> yield Starg index | Patterns.Ldloc index -> yield Ldloc locals.[index] | Patterns.LdlocA index -> yield LdlocA locals.[index] | Patterns.Stloc index -> yield Stloc locals.[index] | Patterns.Ldfld f -> yield Ldfld f | Patterns.LdfldA f -> yield LdfldA f | Patterns.Stfld f -> yield Stfld f | Patterns.LdIndirect t -> yield LdIndirect t | Patterns.StIndirect t -> yield StIndirect t | Patterns.CpObj t -> yield CpObj t | Patterns.LdObj t -> yield LdObj t | Patterns.StObj t -> yield StObj t | Patterns.NewObj c -> yield NewObj c | Patterns.InitObj t -> yield InitObj t | Patterns.CastClass t -> yield CastClass t | Patterns.IsInstance t -> yield IsInstance t | Patterns.Unbox t -> yield Unbox t | Patterns.UnboxAny t -> yield UnboxAny t | Patterns.Box t -> yield Box t | Patterns.NewArr t -> yield NewArr t | Patterns.Ldlen -> yield Ldlen | Patterns.Ldelem t -> yield Ldelem t | Patterns.LdelemA t -> yield LdelemA t | Patterns.Stelem t -> yield Stelem t | Patterns.Add -> yield Add | Patterns.Sub -> yield Sub | Patterns.Mul -> yield Mul | Patterns.Div -> yield Div | Patterns.Rem -> yield Rem | Patterns.And -> yield And | Patterns.Or -> yield Or | Patterns.Xor -> yield Xor | Patterns.Shl -> yield Shl | Patterns.Shr -> yield Shr | Patterns.Neg -> yield Neg | Patterns.Not -> yield Not | Patterns.Conv t -> yield Conv t | Patterns.ConvChecked t -> yield ConvChecked t | Patterns.RefAnyVal t -> yield RefAnyVal t | Patterns.CkFinite -> yield CkFinite | Patterns.MkRefAny t -> yield MkRefAny t | Patterns.LdNull -> yield LdNull | Patterns.LdConst c -> yield LdConst c | Patterns.LdToken t -> yield LdToken t | Patterns.ReadOnly -> yield ReadOnly | Patterns.Tail -> yield Tail | Patterns.Jump target -> yield Jump(branchTargetIds.[target]) | Patterns.Call mi -> yield Call mi | Patterns.CallIndirect -> yield CallIndirect | Patterns.Ret -> yield Ret | Patterns.Throw -> yield Throw | Patterns.EndFinally -> yield EndFinally | Patterns.Leave t -> yield Leave(branchTargetIds.[t]) | Patterns.Switch targets -> yield Switch(targets |> Array.map (fun t -> branchTargetIds.[t])) | Patterns.ConditionalJump(condition, target) -> yield ConditionalJump(condition, branchTargetIds.[target]) | _ -> failwithf "unknown instruction: %A" i } let body = Start :: (Seq.toList body) let returnType = match m with | :? MethodInfo as mi -> mi.ReturnType | :? ConstructorInfo -> typeof | _ -> failwithf "unknown method type: %A" m let arguments = m.GetParameters() |> Array.map (fun p -> p.ParameterType) let arguments = if m.IsStatic then arguments else Array.append [|m.DeclaringType|] arguments { ArgumentTypes = arguments ReturnType = returnType Body = body } module Assembler = open StateMonad type State = { generator : ILGenerator labels : Map locals : Map stack : list } [] module private Helpers = open Microsoft.FSharp.Reflection open StateMonad let (|ValueType|_|) (t : Type) = if t = typeof then Some ValueType.Object elif t = typeof then Some ValueType.Int8 elif t = typeof then Some ValueType.UInt8 elif t = typeof then Some ValueType.Int16 elif t = typeof then Some ValueType.UInt16 elif t = typeof then Some ValueType.Int32 elif t = typeof then Some ValueType.UInt32 elif t = typeof then Some ValueType.Int64 elif t = typeof then Some ValueType.UInt64 elif t = typeof then Some ValueType.NativeInt elif t = typeof then Some ValueType.UNativeInt elif t = typeof then Some ValueType.Float64 elif t = typeof then Some ValueType.Float64 else None let (|Type|) (t : ValueType) = match t with | ValueType.Int8 -> typeof | ValueType.UInt8 -> typeof | ValueType.Int16 -> typeof | ValueType.UInt16 -> typeof | ValueType.Int32 -> typeof | ValueType.UInt32 -> typeof | ValueType.Int64 -> typeof | ValueType.UInt64 -> typeof | ValueType.NativeInt -> typeof | ValueType.UNativeInt -> typeof | ValueType.Float32 -> typeof | ValueType.Float64 -> typeof | _ -> typeof type Asm<'a> = State type Asm() = static member Push (t : Type) : Asm = fun s -> { s with stack = t::s.stack }, () static member Push (Type t) : Asm = fun s -> { s with stack = t::s.stack }, () static member Pop : Asm = fun s -> match s.stack with | t::stack -> { s with stack = stack }, t | _ -> s, typeof static member Peek : Asm = fun s -> match s.stack with | t::_ -> s, t | _ -> s, typeof static member PopN (n : int) : Asm> = fun s -> let rec pop (n : int) (s : list) = if n <= 0 then [], s else match s with | h::t -> let args, rest = pop (n - 1) t (h::args), rest | _ -> let args = List.init n (fun _ -> typeof) args, [] let res, stack = pop n s.stack { s with stack = stack }, res static member fail fmt = failwithf fmt static member GetLocal (l : Local) : Asm = fun s -> match Map.tryFind l s.locals with | Some l -> s,l | None -> let res = s.generator.DeclareLocal(l.Type) let s = { s with locals = Map.add l res s.locals } s, res static member GetLabel (l : Label) : Asm = fun s -> match Map.tryFind l s.labels with | Some l -> s,l | None -> let res = s.generator.DefineLabel() let s = { s with labels = Map.add l res s.labels } s, res static member Mark(l : Label) = state { let! l = Asm.GetLabel l do! (fun s -> s, s.generator.MarkLabel(l)) } static member Emit(c : OpCode) : Asm = fun s -> s, s.generator.Emit(c) static member WriteLine (str : string) : Asm = fun s -> s, s.generator.EmitWriteLine str static member Emit(c : OpCode, arg : obj) : Asm = fun s -> match arg with | null -> s.generator.Emit(c) | :? uint8 as o -> s.generator.Emit(c, o) | :? float as o -> s.generator.Emit(c, o) | :? int16 as o -> s.generator.Emit(c, o) | :? int as o -> s.generator.Emit(c, o) | :? int64 as o -> s.generator.Emit(c, o) | :? ConstructorInfo as o -> s.generator.Emit(c, o) | :? FieldInfo as o -> s.generator.Emit(c, o) | :? MethodInfo as o -> s.generator.Emit(c, o) | :? int8 as o -> s.generator.Emit(c, o) | :? float32 as o -> s.generator.Emit(c, o) | :? string as o -> s.generator.Emit(c, o) | :? Type as o -> s.generator.Emit(c, o) | :? SignatureHelper as o -> s.generator.Emit(c, o) | :? Emit.Label as o -> s.generator.Emit(c, o) | :? array as o -> s.generator.Emit(c, o) | :? LocalBuilder as o -> s.generator.Emit(c, o) | operand -> failwithf "[IL] unsupported operand: %A" operand s, () let private assembleInstruction (i : Instruction) = state { match i with | Start -> () | Nop -> do! Asm.Emit(OpCodes.Nop) | Break -> do! Asm.Emit(OpCodes.Break) | Dup -> let! t = Asm.Peek do! Asm.Push t do! Asm.Emit(OpCodes.Dup) | Pop -> let! _ = Asm.Pop do! Asm.Emit(OpCodes.Pop) | WriteLine str -> do! Asm.WriteLine str | Ldarg a -> match a with | 0 -> do! Asm.Emit(OpCodes.Ldarg_0) | 1 -> do! Asm.Emit(OpCodes.Ldarg_1) | 2 -> do! Asm.Emit(OpCodes.Ldarg_2) | 3 -> do! Asm.Emit(OpCodes.Ldarg_3) | p when p < 256 -> do! Asm.Emit(OpCodes.Ldarg_S, uint8 p :> obj) | p -> do! Asm.Emit(OpCodes.Ldarg, p :> obj) //do! Asm.Push a.ArgumentType | LdargA a -> if a > 255 then do! Asm.Emit(OpCodes.Ldarga, a :> obj) else do! Asm.Emit(OpCodes.Ldarga_S, uint8 a) //do! Asm.Push (a.ArgumentType.MakeByRefType()) | Starg a -> let! t = Asm.Pop if a > 255 then do! Asm.Emit(OpCodes.Starg, a :> obj) else do! Asm.Emit(OpCodes.Starg_S, uint8 a) | Ldloc l -> let! l = Asm.GetLocal l do! Asm.Emit(OpCodes.Ldloc, l) do! Asm.Push l.LocalType | LdlocA l -> let! l = Asm.GetLocal l do! Asm.Emit(OpCodes.Ldloca, l) do! Asm.Push (l.LocalType.MakeByRefType()) | Stloc l -> let! l = Asm.GetLocal l let! t = Asm.Pop do! Asm.Emit(OpCodes.Stloc, l) | Ldfld f -> if f.IsStatic then do! Asm.Emit(OpCodes.Ldsfld, f) else do! Asm.Emit(OpCodes.Ldfld, f) do! Asm.Push f.FieldType | LdfldA f -> if f.IsStatic then do! Asm.Emit(OpCodes.Ldsflda, f) else do! Asm.Emit(OpCodes.Ldflda, f) do! Asm.Push (f.FieldType.MakeByRefType()) | Stfld f -> let! t = Asm.Pop if f.IsStatic then do! Asm.Emit(OpCodes.Stsfld, f) else do! Asm.Emit(OpCodes.Stfld, f) | LdIndirect t -> match t with | ValueType.Int8 -> do! Asm.Emit(OpCodes.Ldind_I1) | ValueType.UInt8 -> do! Asm.Emit(OpCodes.Ldind_U1) | ValueType.Int16 -> do! Asm.Emit(OpCodes.Ldind_I2) | ValueType.UInt16 -> do! Asm.Emit(OpCodes.Ldind_U2) | ValueType.Int32 -> do! Asm.Emit(OpCodes.Ldind_I4) | ValueType.UInt32 -> do! Asm.Emit(OpCodes.Ldind_U4) | ValueType.Int64 -> do! Asm.Emit(OpCodes.Ldind_I8) | ValueType.UInt64 -> do! Asm.fail "cannot LdIndirect uint64" | ValueType.NativeInt -> do! Asm.Emit(OpCodes.Ldind_I) | ValueType.UNativeInt -> do! Asm.fail "cannot LdIndirect unativeint" | ValueType.Float32 -> do! Asm.Emit(OpCodes.Ldind_R4) | ValueType.Float64 -> do! Asm.Emit(OpCodes.Ldind_R8) | _ -> do! Asm.Emit(OpCodes.Ldind_Ref) do! Asm.Push t | StIndirect t -> let! vt = Asm.Pop match t with | ValueType.Int8 -> do! Asm.Emit(OpCodes.Stind_I1) | ValueType.UInt8 -> do! Asm.Emit(OpCodes.Stind_I1) | ValueType.Int16 -> do! Asm.Emit(OpCodes.Stind_I2) | ValueType.UInt16 -> do! Asm.Emit(OpCodes.Stind_I2) | ValueType.Int32 -> do! Asm.Emit(OpCodes.Stind_I4) | ValueType.UInt32 -> do! Asm.Emit(OpCodes.Stind_I4) | ValueType.Int64 -> do! Asm.Emit(OpCodes.Stind_I8) | ValueType.UInt64 -> do! Asm.Emit(OpCodes.Stind_I8) | ValueType.NativeInt -> do! Asm.Emit(OpCodes.Stind_I) | ValueType.UNativeInt -> do! Asm.Emit(OpCodes.Stind_I) | ValueType.Float32 -> do! Asm.Emit(OpCodes.Stind_R4) | ValueType.Float64 -> do! Asm.Emit(OpCodes.Stind_R8) | _ -> do! Asm.Emit(OpCodes.Stind_Ref) | CpObj t -> do! Asm.Emit(OpCodes.Cpobj, t) do! Asm.Push t | LdObj t -> do! Asm.Emit(OpCodes.Ldobj, t) do! Asm.Push t | StObj t -> let! rt = Asm.Pop do! Asm.Emit(OpCodes.Stobj, t) | NewObj c -> let! args = Asm.PopN (c.GetParameters().Length) do! Asm.Emit(OpCodes.Newobj, c) do! Asm.Push c.DeclaringType | InitObj t -> do! Asm.Emit(OpCodes.Initobj, t) | CastClass t -> let! tr = Asm.Pop do! Asm.Emit(OpCodes.Castclass, t) do! Asm.Push t | IsInstance t -> let! tr = Asm.Pop do! Asm.Emit(OpCodes.Isinst, t) do! Asm.Push t | Unbox t -> let! ot = Asm.Pop do! Asm.Emit(OpCodes.Unbox, t) do! Asm.Push t | UnboxAny t -> let! _ = Asm.Pop do! Asm.Emit(OpCodes.Unbox_Any, t) do! Asm.Push t | Box t -> let! tr = Asm.Pop do! Asm.Emit(OpCodes.Box, t) do! Asm.Push typeof | NewArr t -> let! tl = Asm.Pop do! Asm.Emit(OpCodes.Newarr, t) do! Asm.Push (t.MakeArrayType()) | Ldlen -> let! tarr = Asm.Pop do! Asm.Emit(OpCodes.Ldlen) do! Asm.Push typeof // Stack maintained up to this point | Ldelem t -> match t with | ValueType vt -> match vt with | ValueType.Int8 -> do! Asm.Emit(OpCodes.Ldelem_I1) | ValueType.UInt8 -> do! Asm.Emit(OpCodes.Ldelem_U1) | ValueType.Int16 -> do! Asm.Emit(OpCodes.Ldelem_I2) | ValueType.UInt16 -> do! Asm.Emit(OpCodes.Ldelem_U2) | ValueType.Int32 -> do! Asm.Emit(OpCodes.Ldelem_I4) | ValueType.UInt32 -> do! Asm.Emit(OpCodes.Ldelem_U4) | ValueType.Int64 -> do! Asm.Emit(OpCodes.Ldelem_I8) | ValueType.UInt64 -> do! Asm.fail "cannot load uint64 array element" | ValueType.NativeInt -> do! Asm.Emit(OpCodes.Ldelem_I) | ValueType.UNativeInt -> do! Asm.fail "cannot load unativeint array element" | ValueType.Float32 -> do! Asm.Emit(OpCodes.Ldelem_R4) | ValueType.Float64 -> do! Asm.Emit(OpCodes.Ldelem_R8) | _ -> do! Asm.Emit(OpCodes.Ldelem_Ref) | t -> do! Asm.Emit(OpCodes.Ldelem, t) | LdelemA t -> do! Asm.Emit(OpCodes.Ldelema, t) | Stelem t -> match t with | ValueType vt -> match vt with | ValueType.Int8 -> do! Asm.Emit(OpCodes.Stelem_I1) | ValueType.UInt8 -> do! Asm.Emit(OpCodes.Stelem_I1) | ValueType.Int16 -> do! Asm.Emit(OpCodes.Stelem_I2) | ValueType.UInt16 -> do! Asm.Emit(OpCodes.Stelem_I2) | ValueType.Int32 -> do! Asm.Emit(OpCodes.Stelem_I4) | ValueType.UInt32 -> do! Asm.Emit(OpCodes.Stelem_I4) | ValueType.Int64 -> do! Asm.Emit(OpCodes.Stelem_I8) | ValueType.UInt64 -> do! Asm.Emit(OpCodes.Stelem_I8) | ValueType.NativeInt -> do! Asm.Emit(OpCodes.Stelem_I) | ValueType.UNativeInt -> do! Asm.Emit(OpCodes.Stelem_I) | ValueType.Float32 -> do! Asm.Emit(OpCodes.Stelem_R4) | ValueType.Float64 -> do! Asm.Emit(OpCodes.Stelem_R8) | _ -> do! Asm.Emit(OpCodes.Stelem_Ref) | t -> do! Asm.Emit(OpCodes.Stelem, t) | Add -> do! Asm.Emit(OpCodes.Add) | Sub -> do! Asm.Emit(OpCodes.Sub) | Mul -> do! Asm.Emit(OpCodes.Mul) | Div -> do! Asm.Emit(OpCodes.Div) | Rem -> do! Asm.Emit(OpCodes.Rem) | And -> do! Asm.Emit(OpCodes.And) | Or -> do! Asm.Emit(OpCodes.Or) | Xor -> do! Asm.Emit(OpCodes.Xor) | Shl -> do! Asm.Emit(OpCodes.Shl) | Shr -> do! Asm.Emit(OpCodes.Shr) | Neg -> do! Asm.Emit(OpCodes.Neg) | Not -> do! Asm.Emit(OpCodes.Not) | Conv t -> match t with | ValueType.Int8 -> do! Asm.Emit(OpCodes.Conv_Ovf_I1) | ValueType.UInt8 -> do! Asm.Emit(OpCodes.Conv_Ovf_U1) | ValueType.Int16 -> do! Asm.Emit(OpCodes.Conv_Ovf_I2) | ValueType.UInt16 -> do! Asm.Emit(OpCodes.Conv_Ovf_U2) | ValueType.Int32 -> do! Asm.Emit(OpCodes.Conv_Ovf_I4) | ValueType.UInt32 -> do! Asm.Emit(OpCodes.Conv_Ovf_U4) | ValueType.Int64 -> do! Asm.Emit(OpCodes.Conv_Ovf_I8) | ValueType.UInt64 -> do! Asm.Emit(OpCodes.Conv_Ovf_U8) | ValueType.NativeInt -> do! Asm.Emit(OpCodes.Conv_Ovf_I) | ValueType.UNativeInt -> do! Asm.Emit(OpCodes.Conv_Ovf_U) | ValueType.Float32 -> do! Asm.Emit(OpCodes.Conv_R4) | ValueType.Float64 -> do! Asm.Emit(OpCodes.Conv_R8) | _ -> do! Asm.fail "cannot convert to obj" | ConvChecked t -> match t with | ValueType.Int8 -> do! Asm.Emit(OpCodes.Conv_Ovf_I1) | ValueType.UInt8 -> do! Asm.Emit(OpCodes.Conv_Ovf_U1) | ValueType.Int16 -> do! Asm.Emit(OpCodes.Conv_Ovf_I2) | ValueType.UInt16 -> do! Asm.Emit(OpCodes.Conv_Ovf_U2) | ValueType.Int32 -> do! Asm.Emit(OpCodes.Conv_Ovf_I4) | ValueType.UInt32 -> do! Asm.Emit(OpCodes.Conv_Ovf_U4) | ValueType.Int64 -> do! Asm.Emit(OpCodes.Conv_Ovf_I8) | ValueType.UInt64 -> do! Asm.Emit(OpCodes.Conv_Ovf_U8) | ValueType.NativeInt -> do! Asm.Emit(OpCodes.Conv_Ovf_I) | ValueType.UNativeInt -> do! Asm.Emit(OpCodes.Conv_Ovf_U) | ValueType.Float32 -> do! Asm.Emit(OpCodes.Conv_R4) | ValueType.Float64 -> do! Asm.Emit(OpCodes.Conv_R8) | _ -> do! Asm.fail "cannot convert to obj" | LdNull -> do! Asm.Emit(OpCodes.Ldnull) | LdConst c -> match c with | Int8 i -> do! Asm.Emit(OpCodes.Ldc_I4, int i) do! Asm.Emit(OpCodes.Conv_I1) | UInt8 i -> do! Asm.Emit(OpCodes.Ldc_I4, int i) do! Asm.Emit(OpCodes.Conv_U1) | Int16 i -> do! Asm.Emit(OpCodes.Ldc_I4, int i) do! Asm.Emit(OpCodes.Conv_I2) | UInt16 i -> do! Asm.Emit(OpCodes.Ldc_I4, int i) do! Asm.Emit(OpCodes.Conv_U2) | Int32 i -> do! Asm.Emit(OpCodes.Ldc_I4, int i) | UInt32 i -> do! Asm.Emit(OpCodes.Ldc_I4, int i) | Int64 i -> do! Asm.Emit(OpCodes.Ldc_I8, i) | UInt64 i -> do! Asm.Emit(OpCodes.Ldc_I8, i) | Float32 f -> do! Asm.Emit(OpCodes.Ldc_R4, f) | Float64 f -> do! Asm.Emit(OpCodes.Ldc_R8, f) | NativeInt i -> do! Asm.Emit(OpCodes.Ldc_I8, int64 i) do! Asm.Emit(OpCodes.Conv_I) | UNativeInt i -> do! Asm.Emit(OpCodes.Ldc_I8, int64 i) do! Asm.Emit(OpCodes.Conv_I) | String str -> do! Asm.Emit(OpCodes.Ldstr, str) | LdToken t -> do! Asm.Emit(OpCodes.Ldtoken, t) | ReadOnly -> do! Asm.Emit(OpCodes.Readonly) | Tail -> do! Asm.Emit(OpCodes.Tailcall) | Mark l -> do! Asm.Mark l | ConditionalJump(c, l) -> let! l = Asm.GetLabel l match c with | Less -> do! Asm.Emit(OpCodes.Blt, l) | LessOrEqual -> do! Asm.Emit(OpCodes.Ble, l) | Greater -> do! Asm.Emit(OpCodes.Bgt, l) | GreaterOrEqual -> do! Asm.Emit(OpCodes.Bge, l) | Equal -> do! Asm.Emit(OpCodes.Beq, l) | NotEqual -> do! Asm.Emit(OpCodes.Bne_Un, l) | True -> do! Asm.Emit(OpCodes.Brtrue, l) | False -> do! Asm.Emit(OpCodes.Brfalse, l) | Jump l -> let! l = Asm.GetLabel l do! Asm.Emit(OpCodes.Br, l) | Call mi -> if mi.IsVirtual then do! Asm.Emit(OpCodes.Callvirt, mi) else do! Asm.Emit(OpCodes.Call, mi) | CallIndirect -> do! Asm.Emit(OpCodes.Calli) | Ret -> do! Asm.Emit(OpCodes.Ret) | Switch labels -> let arr = Array.zeroCreate labels.Length for i in 0..labels.Length-1 do let! l = Asm.GetLabel(labels.[i]) arr.[i] <- l do! Asm.Emit(OpCodes.Switch, arr) | Throw -> do! Asm.Emit(OpCodes.Throw) | EndFinally -> do! Asm.Emit(OpCodes.Endfinally) | Leave l -> let! l = Asm.GetLabel l do! Asm.Emit(OpCodes.Leave, l) | CkFinite -> do! Asm.Emit(OpCodes.Ckfinite) | MkRefAny t -> do! Asm.Emit(OpCodes.Mkrefany, t) | RefAnyVal t -> do! Asm.Emit(OpCodes.Refanyval, t) } let private assembleBody (m : seq) = state { for i in m do do! assembleInstruction i } let assembleTo (il : ILGenerator) (m : seq) = assembleBody m { generator = il labels = Map.empty locals = Map.empty stack = [] } |> ignore let assembleTo' (state : State) (m : seq) = assembleBody m state |> ignore let assembleDelegateInternal (tdel : Type) (m : list) : Delegate = let invoke = tdel.GetMethod("Invoke") let args = invoke.GetParameters() |> Array.map (fun p -> p.ParameterType) let owner = if args.Length > 0 then let a0 = args.[0] if a0.IsInterface then typeof else a0 else typeof let meth = DynamicMethod( Guid.NewGuid() |> string, invoke.ReturnType, args, owner, true ) let state = { generator = meth.GetILGenerator() labels = Map.empty locals = Map.empty stack = [] } let endState,_ = assembleBody m state meth.CreateDelegate(tdel) let assembleDelegate (m : MethodDefinition) : Delegate = let delegateType = if m.ReturnType = typeof then if m.ArgumentTypes.Length = 0 then typeof else let funcType = typedefof>.FullName.Replace("1", string (m.ArgumentTypes.Length)) |> Type.GetType let funcType = funcType.MakeGenericType m.ArgumentTypes funcType else let funcType = typedefof>.FullName.Replace("1", string (m.ArgumentTypes.Length + 1)) |> Type.GetType let funcType = funcType.MakeGenericType (Array.append m.ArgumentTypes [|m.ReturnType|]) funcType assembleDelegateInternal delegateType m.Body let assembleDefinition (m : MethodDefinition) : 'a = let d = assembleDelegate m DelegateAdapters.wrap d let assemble (body : seq) : 'a = let args, ret = DelegateAdapters.getFunctionSignature typeof<'a> assembleDefinition { ArgumentTypes = List.toArray args ReturnType = if ret = typeof then typeof else ret Body = Seq.toList body } [] module Frontend = open StateMonad type ConcList<'a> = private | Empty | List of list<'a> | Single of 'a | Concat of list> module ConcList = let empty = Empty let single v = Single v let ofList l = match l with | [] -> Empty | l -> List l let ofSeq (s : #seq<'a>) : ConcList<'a> = match s :> seq<'a> with | :? list<'a> as l -> List l | _ -> s |> Seq.toList |> List let ofArray a = a |> Array.toList |> List let rec toSeq (c : ConcList<'a>) = let res = System.Collections.Generic.List<'a>() let rec recurse (c : ConcList<'a>) = match c with | Empty -> () | Single v -> res.Add v | List l -> res.AddRange l | Concat ls -> for l in ls do recurse l recurse c res :> seq<_> let rec toList (c : ConcList<'a>) = let l = toSeq c |> unbox> l |> CSharpList.toList let rec toArray (c : ConcList<'a>) = let l = toSeq c |> unbox> l.ToArray() let append (l : ConcList<'a>) (r : ConcList<'a>) = match l, r with | Empty, r -> r | l, Empty -> l | l, r -> Concat [l;r] let concat (l : #seq>) = let l = l |> Seq.toList Concat l let cons (a : 'a) (l : ConcList<'a>) = Concat [Single a; l] let snoc (l : ConcList<'a>) (a : 'a) = Concat [l; Single a] type CodeGenState = { instructions : ConcList } type CodeGen<'a> = State type CodeGen = static member concat (l : list>) = fun s -> let mutable c = s for e in l do let (s,()) = e c c <- s c, () static member run(c : CodeGen) = let (s,()) = c { instructions = ConcList.empty } s.instructions |> ConcList.toList static member emit (i : ConcList) : CodeGen = fun s -> { s with instructions = ConcList.append s.instructions i }, () static member emit (i : Instruction) : CodeGen = fun s -> { s with instructions = ConcList.snoc s.instructions i }, () static member emit (i : #seq) : CodeGen = fun s -> { s with instructions = ConcList.append s.instructions (ConcList.ofSeq i) }, () type CodeGenBuilder() = member x.Bind(i : Instruction, f : unit -> CodeGen<'b>) = state.Bind(CodeGen.emit (ConcList.single i), f) member x.Bind(i : #seq, f : unit -> CodeGen<'b>) = state.Bind(CodeGen.emit (ConcList.ofSeq i), f) member x.Bind(m : CodeGen<'a>, f : 'a -> CodeGen<'b>) = state.Bind(m,f) member x.Return (v : 'a) : CodeGen<'a> = state.Return v member x.ReturnFrom (c : CodeGen<'a>) = state.ReturnFrom c member x.Zero() : CodeGen = state.Zero() member x.Delay(f : unit -> CodeGen<'a>) = state.Delay f member x.Combine(l : CodeGen, r : CodeGen<'a>) = state.Combine(l,r) member x.For(elements : seq<'a>, f : 'a -> CodeGen) = state.For(elements, f) member x.While(guard, body : CodeGen) = state.While(guard, body) type ExecutableBuilder() = inherit CodeGenBuilder() member x.Run(c : CodeGen) = let code = c |> CodeGen.run Assembler.assemble code let codegen = CodeGenBuilder() let cil = ExecutableBuilder() [] module private Helpers = let rec tryGetMethodInfo (e : Expr) = match e with | Patterns.Call(_,mi,_) -> Some mi | ExprShape.ShapeCombination(_, args) -> args |> List.tryPick tryGetMethodInfo | ExprShape.ShapeLambda(_,b) -> tryGetMethodInfo b | _ -> None let getMethodInfo (e : Expr) = match tryGetMethodInfo e with | Some mi -> mi | None -> failwithf "[IL] could not get MethodInfo from: %A" e let rec tryGetFieldInfo (e : Expr) = match e with | FieldGet(_,fi) -> Some fi | ExprShape.ShapeCombination(_, args) -> args |> List.tryPick tryGetFieldInfo | ExprShape.ShapeLambda(_,b) -> tryGetFieldInfo b | _ -> None let getFieldInfo (e : Expr) = match tryGetFieldInfo e with | Some fi -> fi | None -> failwithf "[IL] could not get FieldInfo from: %A" e let rec tryGetConstructorInfo (e : Expr) = match e with | NewObject(ctor,_) -> Some ctor | ExprShape.ShapeCombination(_, args) -> args |> List.tryPick tryGetConstructorInfo | ExprShape.ShapeLambda(_,b) -> tryGetConstructorInfo b | _ -> None let getConstructorInfo (e : Expr) = match tryGetConstructorInfo e with | Some fi -> fi | None -> failwithf "[IL] could not get ConstructorInfo from: %A" e type IL private() = static let stringFormat = typeof.GetMethod("Format", [| typeof; typeof |]) static let printString = typeof.GetMethod("WriteLine", [| typeof; typeof |]) /// nop static member nop = Nop |> CodeGen.emit // break static member break_ = Break |> CodeGen.emit /// duplicates the top-most value on the stack static member dup = Dup |> CodeGen.emit /// pops the top-most value from the stack static member pop = Pop |> CodeGen.emit /// loads the argument with the given index onto the stack static member ldarg (i : int) = i |> Ldarg |> CodeGen.emit /// loads the address of the argument with the given index onto the stack static member ldarga (i : int) = i |> LdargA |> CodeGen.emit /// stores the top-most value in the argument with the given index static member starg (i : int) = i |> Starg |> CodeGen.emit /// loads the local variable onto the stack static member ldloc (l : Local) = l |> Ldloc |> CodeGen.emit /// load the address of the local variable onto the stack static member ldloca (l : Local) = l |> LdlocA |> CodeGen.emit /// stores the top-most value in the local variable static member stloc (l : Local) = l |> Stloc |> CodeGen.emit /// loads the value of the field onto the stack static member ldfld (f : FieldInfo) = if isNull f then failwith "[IL] cannot load null field" f |> Ldfld |> CodeGen.emit /// loads the address of the field onto the stack static member ldflda (f : FieldInfo) = if isNull f then failwith "[IL] cannot load null field" f |> LdfldA |> CodeGen.emit /// stores the top-most value in the field static member stfld (f : FieldInfo) = if isNull f then failwith "[IL] cannot store null field" f |> Stfld |> CodeGen.emit /// loads the value of the field onto the stack static member ldfld (e : Expr) = e |> getFieldInfo |> IL.ldfld /// loads the address of the field onto the stack static member ldflda (e : Expr) = e |> getFieldInfo |> IL.ldflda /// stores the top-most value in the field static member stfld (e : Expr) = e |> getFieldInfo |> IL.stfld /// stores the top-most value in a ref on the stack static member stind (t : ValueType) = t |> StIndirect |> CodeGen.emit /// loads the value from a ref on the stack static member ldind (t : ValueType) = t |> LdIndirect |> CodeGen.emit /// TODO static member cpobj (t : Type) = t |> CpObj |> CodeGen.emit /// loads the object (with the given type) from the pointer currently on the stack static member ldobj (t : Type) = t |> LdObj |> CodeGen.emit /// stores the top-most value (with the given type) in a ptr on the stack static member stobj (t : Type) = t |> LdObj |> CodeGen.emit /// creates a new object by calling the given Constructor static member newobj (ctor : ConstructorInfo) = ctor |> NewObj |> CodeGen.emit /// creates a new uninitialized object static member initobj (t : Type) = t |> InitObj |> CodeGen.emit /// creates a new object by calling the given Constructor static member newobj (e : Expr) = e |> getConstructorInfo |> IL.newobj /// casts the top-most value to the given class static member castclass (t : Type) = t |> CastClass |> CodeGen.emit /// checks if the top-most value is an instance of the given type static member isinst (t : Type) = t |> IsInstance |> CodeGen.emit /// unboxes the top-most value (with the given type) to its unboxed representation static member unbox (t : Type) = t |> Unbox |> CodeGen.emit /// unboxes the top-most value to the given type static member unboxAny (t : Type) = t |> UnboxAny |> CodeGen.emit /// boxes the top-most value (with the given type) to an object static member box (t : Type) = t |> Box |> CodeGen.emit /// creates a new array using the given element-type and the length on the stack static member newarr (t : Type) = t |> NewArr |> CodeGen.emit /// loads the length of the array currently on the stack static member ldlen = Ldlen |> CodeGen.emit /// loads an element (with the given type) from the array on the stack static member ldelem (t : Type) = t |> Ldelem |> CodeGen.emit /// stores the element (with the given type) to the array on the stack static member stelem (t : Type) = t |> Ldelem |> CodeGen.emit static member add = Add |> CodeGen.emit static member sub = Sub |> CodeGen.emit static member mul = Mul |> CodeGen.emit static member div = Div |> CodeGen.emit static member rem = Rem |> CodeGen.emit static member bitand = And |> CodeGen.emit static member bitor = Or |> CodeGen.emit static member bifxor = Xor |> CodeGen.emit static member neg = Neg |> CodeGen.emit static member not = Not |> CodeGen.emit /// converts the top-most value to the given type static member conv (t : ValueType) = t |> Conv |> CodeGen.emit /// converts the top-most value to the given type (checked) static member convChecked (t : ValueType) = t |> ConvChecked |> CodeGen.emit /// loads null onto the stack static member ldnull = LdNull |> CodeGen.emit /// loads the given Constant onto the stack static member ldconst(c : Constant) = LdConst c |> CodeGen.emit /// loads the given int8 constant onto the stack static member ldconst(i : int8) = LdConst(Int8 i) |> CodeGen.emit /// loads the given uint8 constant onto the stack static member ldconst(i : uint8) = LdConst(UInt8 i) |> CodeGen.emit /// loads the given int16 constant onto the stack static member ldconst(i : int16) = LdConst(Int16 i) |> CodeGen.emit /// loads the given uint16 constant onto the stack static member ldconst(i : uint16) = LdConst(UInt16 i) |> CodeGen.emit /// loads the given int constant onto the stack static member ldconst(i : int32) = LdConst(Int32 i) |> CodeGen.emit /// loads the given uint32 constant onto the stack static member ldconst(i : uint32) = LdConst(UInt32 i) |> CodeGen.emit /// loads the given int64 constant onto the stack static member ldconst(i : int64) = LdConst(Int64 i) |> CodeGen.emit /// loads the given uint64 constant onto the stack static member ldconst(i : uint64) = LdConst(UInt64 i) |> CodeGen.emit /// loads the given nativeint constant onto the stack static member ldconst(i : nativeint) = LdConst(NativeInt i) |> CodeGen.emit /// loads the given unativeint constant onto the stack static member ldconst(i : unativeint) = LdConst(UNativeInt i) |> CodeGen.emit /// loads the given float constant onto the stack static member ldconst(i : float32) = LdConst(Float32 i) |> CodeGen.emit /// loads the given double constant onto the stack static member ldconst(i : float) = LdConst(Float64 i) |> CodeGen.emit /// loads the given string constant onto the stack static member ldconst(i : string) = LdConst(String i) |> CodeGen.emit /// load the given object as token onto the stack static member ldtoken (t : obj) = LdToken(t) |> CodeGen.emit /// load the given type-token onto the stack static member ldtoken (t : Type) = LdToken(t) |> CodeGen.emit /// tells the JITer that the following call is a tail-call static member tail = Tail |> CodeGen.emit /// marks the current location using the given label static member mark l = l |> Mark |> CodeGen.emit /// conditionally jumps to a label static member jmp (c : JumpCondition) = fun l -> ConditionalJump(c, l) |> CodeGen.emit /// jumps to a label static member jmp (l : Label) = Jump(l) |> CodeGen.emit /// calls the given MethodInfo static member call (e : Expr) = e |> getMethodInfo :> MethodBase |> Call |> CodeGen.emit /// calls the given MethodInfo static member call (mi : MethodBase) = mi |> Call |> CodeGen.emit /// returns from the current function static member ret = Ret |> CodeGen.emit /// prints a log-line using the given local values static member println (format : string, [] args : obj[]) = let v = Local(typeof) let arr = Local(typeof) codegen { do! LdConst (Int32 args.Length) do! NewArr typeof do! Stloc arr for i in 0..args.Length-1 do do! Ldloc arr do! LdConst (Int32 i) match args.[i] with | :? Local as a -> do! Ldloc a if a.Type.IsValueType then do! Box a.Type else do! UnboxAny typeof | a -> do! LdConst (String (sprintf "%A" a)) do! UnboxAny typeof do! Stelem typeof do! LdConst (String format) do! Ldloc arr do! Call printString } /// prints a log-line using the given local values static member printfn (fmt : StringFormat<'a, CodeGen>) : 'a = kformatf (fun fmt -> IL.println(fmt.Format, fmt.Args)) fmt static member newlabel : CodeGen